diff --git a/.gitignore b/.gitignore index 201c107..6d2faec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/ user/build +toolchains/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 6439ebf..1ab3bac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ add_custom_target(iso ) add_custom_target(disk_img - COMMAND dd if=/dev/zero of=${DISK_IMG} bs=1M count=32 + COMMAND dd if=/dev/zero of=${DISK_IMG} bs=1M count=512 COMMAND mkfs.ext2 -F -L KIRKOS ${DISK_IMG} COMMAND guestfish --rw -a ${DISK_IMG} run @@ -111,6 +111,7 @@ add_custom_target(run -smp 2 -device ich9-intel-hda -device hda-duplex + -cpu qemu64,+fsgsbase ) add_custom_target(debug @@ -118,13 +119,14 @@ add_custom_target(debug COMMAND qemu-system-x86_64 -cdrom ${ISO} -hda ${DISK_IMG} - -s -S -debugcon stdio + -s -S -d int,cpu_reset -m 8G -smp 2 - -device ich9-intel-hda,id=hda - -device hda-duplex,id=codec0,bus=hda.0,cad=0 + -device ich9-intel-hda + -device hda-duplex + -cpu qemu64,+fsgsbase ) target_include_directories(KirkOS PRIVATE diff --git a/ext2_root/helloworld.elf b/ext2_root/helloworld.elf new file mode 100755 index 0000000..efa54b6 Binary files /dev/null and b/ext2_root/helloworld.elf differ diff --git a/ext2_root/log.txt b/ext2_root/log.txt new file mode 100644 index 0000000..1da85b6 --- /dev/null +++ b/ext2_root/log.txt @@ -0,0 +1,3058 @@ +readelf -h helloworld.elf +ELF Header: + Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00 + Class: ELF64 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - GNU + ABI Version: 0 + Type: EXEC (Executable file) + Machine: Advanced Micro Devices X86-64 + Version: 0x1 + Entry point address: 0x8000170 + Start of program headers: 64 (bytes into file) + Start of section headers: 2487152 (bytes into file) + Flags: 0x0 + Size of this header: 64 (bytes) + Size of program headers: 56 (bytes) + Number of program headers: 5 + Size of section headers: 64 (bytes) + Number of section headers: 26 + Section header string table index: 25 +readelf -h init.elf +ELF Header: + Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 + Class: ELF64 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: EXEC (Executable file) + Machine: Advanced Micro Devices X86-64 + Version: 0x1 + Entry point address: 0x4002cc + Start of program headers: 64 (bytes into file) + Start of section headers: 5336 (bytes into file) + Flags: 0x0 + Size of this header: 64 (bytes) + Size of program headers: 56 (bytes) + Number of program headers: 4 + Size of section headers: 64 (bytes) + Number of section headers: 9 + Section header string table index: 8 + +readelf -S init.elf +There are 9 section headers, starting at offset 0x14d8: + +Section Headers: + [Nr] Name Type Address Offset + Size EntSize Flags Link Info Align + [ 0] NULL 0000000000000000 00000000 + 0000000000000000 0000000000000000 0 0 0 + [ 1] .text PROGBITS 0000000000400000 00001000 + 00000000000002d3 0000000000000000 AX 0 0 32 + [ 2] .rodata PROGBITS 00000000004002d8 000012d8 + 000000000000006a 0000000000000001 AMS 0 0 8 + [ 3] .note.gnu.pr[...] NOTE 0000000000400348 00001348 + 0000000000000030 0000000000000000 A 0 0 8 + [ 4] .eh_frame PROGBITS 0000000000400378 00001378 + 0000000000000058 0000000000000000 A 0 0 8 + [ 5] .comment PROGBITS 0000000000000000 000013d0 + 000000000000001b 0000000000000001 MS 0 0 1 + [ 6] .symtab SYMTAB 0000000000000000 000013f0 + 0000000000000078 0000000000000018 7 2 8 + [ 7] .strtab STRTAB 0000000000000000 00001468 + 000000000000001b 0000000000000000 0 0 1 + [ 8] .shstrtab STRTAB 0000000000000000 00001483 + 000000000000004f 0000000000000000 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings), I (info), + L (link order), O (extra OS processing required), G (group), T (TLS), + C (compressed), x (unknown), o (OS specific), E (exclude), + D (mbind), l (large), p (processor specific) + +readelf -S helloworld.elf +There are 26 section headers, starting at offset 0x25f370: + +Section Headers: + [Nr] Name Type Address Offset + Size EntSize Flags Link Info Align + [ 0] NULL 0000000000000000 00000000 + 0000000000000000 0000000000000000 0 0 0 + [ 1] .init PROGBITS 0000000008000158 00000158 + 000000000000000d 0000000000000000 AX 0 0 1 + [ 2] .text PROGBITS 0000000008000170 00000170 + 000000000006bd81 0000000000000000 AX 0 0 16 + [ 3] .fini PROGBITS 000000000806bef1 0006bef1 + 0000000000000008 0000000000000000 AX 0 0 1 + [ 4] .rodata PROGBITS 000000000806bf00 0006bf00 + 000000000001723a 0000000000000000 A 0 0 32 + [ 5] .eh_frame_hdr PROGBITS 000000000808313c 0008313c + 0000000000004504 0000000000000000 A 0 0 4 + [ 6] .eh_frame PROGBITS 0000000008087640 00087640 + 0000000000011c98 0000000000000000 A 0 0 8 + [ 7] .tbss NOBITS 000000000809a2d8 000992d8 + 0000000000000094 0000000000000000 WAT 0 0 8 + [ 8] .init_array INIT_ARRAY 000000000809a2d8 000992d8 + 0000000000000028 0000000000000008 WA 0 0 8 + [ 9] .fini_array FINI_ARRAY 000000000809a300 00099300 + 0000000000000008 0000000000000008 WA 0 0 8 + [10] .ctors PROGBITS 000000000809a308 00099308 + 0000000000000010 0000000000000000 WA 0 0 8 + [11] .dtors PROGBITS 000000000809a318 00099318 + 0000000000000010 0000000000000000 WA 0 0 8 + [12] .data.rel.ro PROGBITS 000000000809a328 00099328 + 0000000000000410 0000000000000000 WA 0 0 8 + [13] .data PROGBITS 000000000809a740 00099740 + 0000000000000e48 0000000000000000 WA 0 0 32 + [14] .bss NOBITS 000000000809b5a0 0009a588 + 0000000000008338 0000000000000000 WA 0 0 32 + [15] .comment PROGBITS 0000000000000000 0009a588 + 0000000000000047 0000000000000001 MS 0 0 1 + [16] .debug_aranges PROGBITS 0000000000000000 0009a5d0 + 000000000000c660 0000000000000000 0 0 16 + [17] .debug_info PROGBITS 0000000000000000 000a6c30 + 00000000000c3004 0000000000000000 0 0 1 + [18] .debug_abbrev PROGBITS 0000000000000000 00169c34 + 0000000000013142 0000000000000000 0 0 1 + [19] .debug_line PROGBITS 0000000000000000 0017cd76 + 000000000005450a 0000000000000000 0 0 1 + [20] .debug_str PROGBITS 0000000000000000 001d1280 + 000000000004cb96 0000000000000001 MS 0 0 1 + [21] .debug_line_str PROGBITS 0000000000000000 0021de16 + 00000000000013a9 0000000000000001 MS 0 0 1 + [22] .debug_rnglists PROGBITS 0000000000000000 0021f1bf + 00000000000082e8 0000000000000000 0 0 1 + [23] .symtab SYMTAB 0000000000000000 002274a8 + 00000000000110a0 0000000000000018 24 480 8 + [24] .strtab STRTAB 0000000000000000 00238548 + 0000000000026d2b 0000000000000000 0 0 1 + [25] .shstrtab STRTAB 0000000000000000 0025f273 + 00000000000000fa 0000000000000000 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings), I (info), + L (link order), O (extra OS processing required), G (group), T (TLS), + C (compressed), x (unknown), o (OS specific), E (exclude), + R (retain), D (mbind), l (large), p (processor specific) + + +Symbol table '.symtab' contains 2908 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c + 2: 000000000809a308 0 OBJECT LOCAL DEFAULT 10 __CTOR_LIST__ + 3: 000000000809a318 0 OBJECT LOCAL DEFAULT 11 __DTOR_LIST__ + 4: 0000000008087670 0 OBJECT LOCAL DEFAULT 6 __EH_FRAME_BEGIN__ + 5: 0000000008000190 0 FUNC LOCAL DEFAULT 2 deregister_tm_clones + 6: 00000000080001c0 0 FUNC LOCAL DEFAULT 2 register_tm_clones + 7: 0000000008000200 0 FUNC LOCAL DEFAULT 2 __do_global_dtors_aux + 8: 000000000809b5a0 1 OBJECT LOCAL DEFAULT 14 completed.2 + 9: 000000000809b5a8 8 OBJECT LOCAL DEFAULT 14 dtor_idx.1 + 10: 0000000008000290 0 FUNC LOCAL DEFAULT 2 frame_dummy + 11: 000000000809b5c0 48 OBJECT LOCAL DEFAULT 14 object.0 + 12: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c + 13: 000000000809a310 0 OBJECT LOCAL DEFAULT 10 __CTOR_END__ + 14: 00000000080992d4 0 OBJECT LOCAL DEFAULT 6 __FRAME_END__ + 15: 000000000806beb0 0 FUNC LOCAL DEFAULT 2 __do_global_ctors_aux + 16: 0000000000000000 0 FILE LOCAL DEFAULT ABS helloworld.c + 17: 0000000000000000 0 FILE LOCAL DEFAULT ABS entry.cpp + 18: 0000000000000000 0 FILE LOCAL DEFAULT ABS startup.cpp + 19: 0000000000000000 0 FILE LOCAL DEFAULT ABS ensure.cpp + 20: 000000000806bf68 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 21: 000000000809a328 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 22: 0000000000000000 0 FILE LOCAL DEFAULT ABS stdlib.cpp + 23: 000000000806c220 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 24: 000000000809a330 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 25: 000000000806c238 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 26: 000000000806c23c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 27: 000000000806c240 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 28: 000000000806c244 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 29: 000000000806c248 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 30: 000000000806c24c 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 31: 000000000806c24d 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 32: 0000000000000000 8 TLS LOCAL DEFAULT 7 _ZN12_GLOBAL__N_[...] + 33: 0000000000000008 8 TLS LOCAL DEFAULT 7 _ZN12_GLOBAL__N_[...] + 34: 000000000809bff0 16 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 35: 0000000008002bab 58 FUNC LOCAL DEFAULT 2 _ZL6temperj + 36: 000000000800340c 50 FUNC LOCAL DEFAULT 2 _ZL14qsort_callb[...] + 37: 0000000008003f2e 22 FUNC LOCAL DEFAULT 2 _Z41__static_ini[...] + 38: 0000000008003f44 11 FUNC LOCAL DEFAULT 2 _GLOBAL__sub_I_s[...] + 39: 0000000000000000 0 FILE LOCAL DEFAULT ABS ctype.cpp + 40: 000000000806d9e0 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 41: 000000000809a338 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 42: 0000000000000000 0 FILE LOCAL DEFAULT ABS environment.cpp + 43: 000000000806db78 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 44: 000000000809a340 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 45: 000000000800c628 57 FUNC LOCAL DEFAULT 2 _ZN3frgL6strchrEPKci + 46: 000000000806db90 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 47: 000000000806db94 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 48: 000000000806db98 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 49: 000000000806db9c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 50: 000000000806dba0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 51: 000000000806dba4 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 52: 000000000806dba5 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 53: 000000000809c020 8 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 54: 000000000800bc54 433 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 55: 000000000809c040 32 OBJECT LOCAL DEFAULT 14 _ZZN12_GLOBAL__N[...] + 56: 000000000809c060 8 OBJECT LOCAL DEFAULT 14 _ZGVZN12_GLOBAL_[...] + 57: 000000000800be05 126 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 58: 000000000800be83 202 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 59: 000000000800bf4d 329 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 60: 000000000800c096 366 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 61: 0000000000000000 0 FILE LOCAL DEFAULT ABS errno.cpp + 62: 0000000000000000 0 FILE LOCAL DEFAULT ABS signal.cpp + 63: 000000000806f048 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 64: 000000000809a348 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 65: 0000000000000000 0 FILE LOCAL DEFAULT ABS stdio.cpp + 66: 000000000806f0d0 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 67: 000000000809a350 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 68: 000000000806f0e8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 69: 000000000806f0ec 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 70: 000000000806f0f0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 71: 000000000806f0f4 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 72: 000000000806f0f8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 73: 000000000806f0fc 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 74: 000000000806f0fd 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 75: 000000000800d96f 219 FUNC LOCAL DEFAULT 2 _ZL9store_intPvjy + 76: 000000000800de5a 98 FUNC LOCAL DEFAULT 2 _ZZ7vfscanfENUt_[...] + 77: 000000000800debc 91 FUNC LOCAL DEFAULT 2 _ZZ7vfscanfENUt_[...] + 78: 000000000800fc02 6337 FUNC LOCAL DEFAULT 2 _Z8do_scanfIZ7vf[...] + 79: 000000000800e248 20 FUNC LOCAL DEFAULT 2 _ZZ7vsscanfENUt_[...] + 80: 000000000800e25c 48 FUNC LOCAL DEFAULT 2 _ZZ7vsscanfENUt_[...] + 81: 00000000080115ba 6337 FUNC LOCAL DEFAULT 2 _Z8do_scanfIZ7vs[...] + 82: 000000000800fb0c 121 FUNC LOCAL DEFAULT 2 _ZZ8do_scanfIZ7v[...] + 83: 000000000800fb86 124 FUNC LOCAL DEFAULT 2 _ZZ8do_scanfIZ7v[...] + 84: 00000000080114c4 121 FUNC LOCAL DEFAULT 2 _ZZ8do_scanfIZ7v[...] + 85: 000000000801153e 124 FUNC LOCAL DEFAULT 2 _ZZ8do_scanfIZ7v[...] + 86: 0000000000000000 0 FILE LOCAL DEFAULT ABS string.cpp + 87: 000000000809c078 8 OBJECT LOCAL DEFAULT 14 _ZZ6strtokE5saved + 88: 0000000000000000 0 FILE LOCAL DEFAULT ABS wchar.cpp + 89: 00000000080729c0 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 90: 000000000809a358 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 91: 000000000809c080 8 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 92: 000000000809c088 8 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 93: 000000000809c090 8 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 94: 000000000809c098 8 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 95: 000000000809a760 2592 OBJECT LOCAL DEFAULT 13 _ZN12_GLOBAL__N_[...] + 96: 000000000809b180 928 OBJECT LOCAL DEFAULT 13 _ZN12_GLOBAL__N_[...] + 97: 000000000803eb74 172 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 98: 0000000000000000 0 FILE LOCAL DEFAULT ABS dso_exit.cpp + 99: 0000000008072b98 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 100: 000000000809a360 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 101: 0000000008072bb0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 102: 0000000008072bb4 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 103: 0000000008072bb8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 104: 0000000008072bbc 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 105: 0000000008072bc0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 106: 0000000008072bc4 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 107: 0000000008072bc5 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 108: 000000000809c0a0 32 OBJECT LOCAL DEFAULT 14 _ZZ12getExitQueu[...] + 109: 000000000809c0c0 8 OBJECT LOCAL DEFAULT 14 _ZGVZ12getExitQu[...] + 110: 0000000000000000 0 FILE LOCAL DEFAULT ABS tls.cpp + 111: 0000000008073e4c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 112: 0000000008073e50 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 113: 0000000008073e54 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 114: 0000000008073e58 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 115: 0000000008073e5c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 116: 0000000000000000 0 FILE LOCAL DEFAULT ABS sysdeps.cpp + 117: 0000000008073e60 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 118: 0000000008073e64 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 119: 0000000008073e68 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 120: 0000000008073e6c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 121: 0000000008073e70 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 122: 0000000000000000 0 FILE LOCAL DEFAULT ABS syscall.cpp + 123: 0000000000000000 0 FILE LOCAL DEFAULT ABS dso.c + 124: 0000000000000000 0 FILE LOCAL DEFAULT ABS guard-abi.cpp + 125: 0000000008073eb8 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 126: 000000000809a368 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 127: 0000000008073ed0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 128: 000000000803facc 77 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 129: 000000000803fb1a 26 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 130: 0000000000000000 0 FILE LOCAL DEFAULT ABS allocator.cpp + 131: 0000000008074190 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 132: 000000000809a370 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 133: 00000000080741a4 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 134: 00000000080741a8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 135: 00000000080741ac 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 136: 00000000080741b0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 137: 00000000080741b4 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 138: 00000000080741b8 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 139: 00000000080741b9 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 140: 000000000809c0e0 1 OBJECT LOCAL DEFAULT 14 _ZZ12getAllocato[...] + 141: 000000000809c0e8 8 OBJECT LOCAL DEFAULT 14 _ZGVZ12getAlloca[...] + 142: 000000000809c100 440 OBJECT LOCAL DEFAULT 14 _ZZ12getAllocato[...] + 143: 000000000809c2b8 8 OBJECT LOCAL DEFAULT 14 _ZGVZ12getAlloca[...] + 144: 000000000809c2c0 8 OBJECT LOCAL DEFAULT 14 _ZZ12getAllocato[...] + 145: 000000000809c2c8 8 OBJECT LOCAL DEFAULT 14 _ZGVZ12getAlloca[...] + 146: 0000000000000000 0 FILE LOCAL DEFAULT ABS debug.cpp + 147: 000000000807424f 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 148: 000000000809a378 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 149: 0000000000000000 0 FILE LOCAL DEFAULT ABS essential.cpp + 150: 0000000008040a93 1796 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 151: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.cpp + 152: 0000000008074268 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 153: 000000000809a380 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 154: 0000000008074280 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 155: 0000000008074284 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 156: 0000000008074288 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 157: 000000000807428c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 158: 0000000008074290 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 159: 0000000008074294 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 160: 0000000008074295 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 161: 0000000008074296 1 OBJECT LOCAL DEFAULT 4 _ZL12logEntryExit + 162: 0000000008074297 1 OBJECT LOCAL DEFAULT 4 _ZL10logStartup + 163: 0000000008074298 1 OBJECT LOCAL DEFAULT 4 _ZL10logDlCalls + 164: 000000000809c520 144 OBJECT LOCAL DEFAULT 14 _ZL8earlyTcb + 165: 000000000809c5b0 8 OBJECT LOCAL DEFAULT 14 _ZL12executableSO + 166: 0000000008041952 550 FUNC LOCAL DEFAULT 2 _ZL9parseListN3f[...] + 167: 0000000008043490 82 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 168: 0000000008043588 268 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 169: 0000000008043694 190 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 170: 00000000080434e2 165 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 171: 0000000008042b4e 125 FUNC LOCAL DEFAULT 2 _ZZ15__dlapi_rev[...] + 172: 0000000008043490 82 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 173: 00000000080434e2 165 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 174: 0000000008043752 52 FUNC LOCAL DEFAULT 2 _ZN3frg8destruct[...] + 175: 0000000008043786 391 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 176: 000000000804390d 14 FUNC LOCAL DEFAULT 2 _ZSt4moveIRZ15__[...] + 177: 000000000804391b 117 FUNC LOCAL DEFAULT 2 _ZN3frg9construc[...] + 178: 0000000008043990 26 FUNC LOCAL DEFAULT 2 _ZN3frg5tupleIJK[...] + 179: 00000000080439aa 26 FUNC LOCAL DEFAULT 2 _ZN3frg5tupleIJK[...] + 180: 00000000080439c4 14 FUNC LOCAL DEFAULT 2 _ZSt7forwardIZ15[...] + 181: 00000000080439d2 79 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 182: 0000000008043a21 14 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple13[...] + 183: 0000000008043a2f 30 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple13[...] + 184: 00000000080439d2 79 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 185: 0000000008043a4e 66 FUNC LOCAL DEFAULT 2 _ZN3frg5tupleIJK[...] + 186: 0000000008043a90 14 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple13[...] + 187: 0000000008043a4e 66 FUNC LOCAL DEFAULT 2 _ZN3frg5tupleIJK[...] + 188: 0000000008043a9e 74 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple7s[...] + 189: 0000000008043a9e 74 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple7s[...] + 190: 0000000008043ae8 27 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple7s[...] + 191: 0000000008043ae8 27 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple7s[...] + 192: 0000000000000000 0 FILE LOCAL DEFAULT ABS linker.cpp + 193: 0000000008075b98 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 194: 000000000809a388 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 195: 0000000008075bb0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 196: 0000000008075bb4 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 197: 0000000008075bb8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 198: 0000000008075bbc 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 199: 0000000008075bc0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 200: 0000000008075bc4 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 201: 0000000008075bc5 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 202: 0000000008075bdb 1 OBJECT LOCAL DEFAULT 4 _ZL7verbose + 203: 0000000008075bdc 1 OBJECT LOCAL DEFAULT 4 _ZL20stillSlight[...] + 204: 0000000008075bdd 1 OBJECT LOCAL DEFAULT 4 _ZL16logBaseAddresses + 205: 0000000008075bde 1 OBJECT LOCAL DEFAULT 4 _ZL8logRpath + 206: 0000000008075bdf 1 OBJECT LOCAL DEFAULT 4 _ZL9logLdPath + 207: 0000000008075be0 1 OBJECT LOCAL DEFAULT 4 _ZL17logSymbolVe[...] + 208: 0000000008075be1 1 OBJECT LOCAL DEFAULT 4 _ZL12eagerBinding + 209: 0000000008045178 127 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 210: 00000000080451f7 20 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 211: 000000000804586c 66 FUNC LOCAL DEFAULT 2 _ZZN16ObjectRepo[...] + 212: 00000000080458ae 756 FUNC LOCAL DEFAULT 2 _ZZN16ObjectRepo[...] + 213: 0000000008045ba2 104 FUNC LOCAL DEFAULT 2 _ZZN16ObjectRepo[...] + 214: 000000000804ad8a 131 FUNC LOCAL DEFAULT 2 _ZZ15resolveInOb[...] + 215: 000000000804ae0e 253 FUNC LOCAL DEFAULT 2 _ZZ15resolveInOb[...] + 216: 000000000804e5b4 82 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 217: 000000000804e6ac 190 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 218: 000000000804e76a 268 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 219: 000000000804e606 165 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 220: 000000000804e876 67 FUNC LOCAL DEFAULT 2 _ZN3frg9construc[...] + 221: 000000000804e5b4 82 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 222: 000000000804e606 165 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 223: 000000000804e8b9 52 FUNC LOCAL DEFAULT 2 _ZN3frg8destruct[...] + 224: 000000000804e8ee 26 FUNC LOCAL DEFAULT 2 _ZN3frg5tupleIJK[...] + 225: 000000000804e908 26 FUNC LOCAL DEFAULT 2 _ZN3frg5tupleIJK[...] + 226: 000000000804e922 391 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 227: 000000000804eaa9 14 FUNC LOCAL DEFAULT 2 _ZSt4moveIRZN6Lo[...] + 228: 000000000804eab7 117 FUNC LOCAL DEFAULT 2 _ZN3frg9construc[...] + 229: 000000000804eb2c 14 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple13[...] + 230: 000000000804eb3a 30 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple13[...] + 231: 000000000804eb58 14 FUNC LOCAL DEFAULT 2 _ZSt7forwardIZN6[...] + 232: 000000000804eb66 79 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 233: 000000000804ebb5 14 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple13[...] + 234: 000000000804eb66 79 FUNC LOCAL DEFAULT 2 _ZN3frg8hash_map[...] + 235: 000000000804ebc4 66 FUNC LOCAL DEFAULT 2 _ZN3frg5tupleIJK[...] + 236: 000000000804ebc4 66 FUNC LOCAL DEFAULT 2 _ZN3frg5tupleIJK[...] + 237: 000000000804ec06 74 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple7s[...] + 238: 000000000804ec06 74 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple7s[...] + 239: 000000000804ec50 27 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple7s[...] + 240: 000000000804ec50 27 FUNC LOCAL DEFAULT 2 _ZN3frg6_tuple7s[...] + 241: 0000000000000000 0 FILE LOCAL DEFAULT ABS floor.c + 242: 0000000008078320 8 OBJECT LOCAL DEFAULT 4 toint + 243: 0000000000000000 0 FILE LOCAL DEFAULT ABS log10.c + 244: 0000000008078340 8 OBJECT LOCAL DEFAULT 4 ivln10hi + 245: 0000000008078348 8 OBJECT LOCAL DEFAULT 4 ivln10lo + 246: 0000000008078350 8 OBJECT LOCAL DEFAULT 4 log10_2hi + 247: 0000000008078358 8 OBJECT LOCAL DEFAULT 4 log10_2lo + 248: 0000000008078360 8 OBJECT LOCAL DEFAULT 4 Lg1 + 249: 0000000008078368 8 OBJECT LOCAL DEFAULT 4 Lg2 + 250: 0000000008078370 8 OBJECT LOCAL DEFAULT 4 Lg3 + 251: 0000000008078378 8 OBJECT LOCAL DEFAULT 4 Lg4 + 252: 0000000008078380 8 OBJECT LOCAL DEFAULT 4 Lg5 + 253: 0000000008078388 8 OBJECT LOCAL DEFAULT 4 Lg6 + 254: 0000000008078390 8 OBJECT LOCAL DEFAULT 4 Lg7 + 255: 0000000000000000 0 FILE LOCAL DEFAULT ABS modf.c + 256: 0000000000000000 0 FILE LOCAL DEFAULT ABS pow.c + 257: 0000000008078420 16 OBJECT LOCAL DEFAULT 4 bp + 258: 0000000008078430 16 OBJECT LOCAL DEFAULT 4 dp_h + 259: 0000000008078440 16 OBJECT LOCAL DEFAULT 4 dp_l + 260: 0000000008078450 8 OBJECT LOCAL DEFAULT 4 two53 + 261: 0000000008078458 8 OBJECT LOCAL DEFAULT 4 huge + 262: 0000000008078460 8 OBJECT LOCAL DEFAULT 4 tiny + 263: 0000000008078468 8 OBJECT LOCAL DEFAULT 4 L1 + 264: 0000000008078470 8 OBJECT LOCAL DEFAULT 4 L2 + 265: 0000000008078478 8 OBJECT LOCAL DEFAULT 4 L3 + 266: 0000000008078480 8 OBJECT LOCAL DEFAULT 4 L4 + 267: 0000000008078488 8 OBJECT LOCAL DEFAULT 4 L5 + 268: 0000000008078490 8 OBJECT LOCAL DEFAULT 4 L6 + 269: 0000000008078498 8 OBJECT LOCAL DEFAULT 4 P1 + 270: 00000000080784a0 8 OBJECT LOCAL DEFAULT 4 P2 + 271: 00000000080784a8 8 OBJECT LOCAL DEFAULT 4 P3 + 272: 00000000080784b0 8 OBJECT LOCAL DEFAULT 4 P4 + 273: 00000000080784b8 8 OBJECT LOCAL DEFAULT 4 P5 + 274: 00000000080784c0 8 OBJECT LOCAL DEFAULT 4 lg2 + 275: 00000000080784c8 8 OBJECT LOCAL DEFAULT 4 lg2_h + 276: 00000000080784d0 8 OBJECT LOCAL DEFAULT 4 lg2_l + 277: 00000000080784d8 8 OBJECT LOCAL DEFAULT 4 ovt + 278: 00000000080784e0 8 OBJECT LOCAL DEFAULT 4 cp + 279: 00000000080784e8 8 OBJECT LOCAL DEFAULT 4 cp_h + 280: 00000000080784f0 8 OBJECT LOCAL DEFAULT 4 cp_l + 281: 00000000080784f8 8 OBJECT LOCAL DEFAULT 4 ivln2 + 282: 0000000008078500 8 OBJECT LOCAL DEFAULT 4 ivln2_h + 283: 0000000008078508 8 OBJECT LOCAL DEFAULT 4 ivln2_l + 284: 0000000000000000 0 FILE LOCAL DEFAULT ABS rint.c + 285: 0000000008078620 8 OBJECT LOCAL DEFAULT 4 toint + 286: 0000000000000000 0 FILE LOCAL DEFAULT ABS scalbn.c + 287: 0000000000000000 0 FILE LOCAL DEFAULT ABS sqrt.c + 288: 0000000008078648 8 OBJECT LOCAL DEFAULT 4 tiny + 289: 0000000000000000 0 FILE LOCAL DEFAULT ABS pthread.cpp + 290: 0000000008078660 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 291: 000000000809a390 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 292: 0000000008078678 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 293: 000000000807867c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 294: 0000000008078680 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 295: 0000000008078684 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 296: 0000000008078688 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 297: 000000000805532e 21 FUNC LOCAL DEFAULT 2 _ZN5mlibcL19tcb_[...] + 298: 0000000008055343 18 FUNC LOCAL DEFAULT 2 _ZN5mlibcL18tcb_[...] + 299: 000000000807868c 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 300: 000000000807868d 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 301: 000000000809c5c0 1 OBJECT LOCAL DEFAULT 14 _ZL11enableTrace + 302: 00000000080786c8 4 OBJECT LOCAL DEFAULT 4 _ZL14mutexRecursive + 303: 00000000080786cc 4 OBJECT LOCAL DEFAULT 4 _ZL16mutex_owner_mask + 304: 00000000080786d0 4 OBJECT LOCAL DEFAULT 4 _ZL17mutex_waite[...] + 305: 00000000080786d4 4 OBJECT LOCAL DEFAULT 4 _ZL14mutex_excl_bit + 306: 00000000080786d8 4 OBJECT LOCAL DEFAULT 4 _ZL13rc_count_mask + 307: 00000000080786dc 4 OBJECT LOCAL DEFAULT 4 _ZL14rc_waiters_bit + 308: 00000000080786e0 8 OBJECT LOCAL DEFAULT 4 _ZL17default_sta[...] + 309: 00000000080786e8 8 OBJECT LOCAL DEFAULT 4 _ZL17default_gua[...] + 310: 000000000809c5e0 24576 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 311: 00000000080a25e0 8 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 312: 0000000008057c6c 38 FUNC LOCAL DEFAULT 2 _ZN3frg5arrayIN1[...] + 313: 0000000008055cb3 271 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 314: 0000000008055dc2 144 FUNC LOCAL DEFAULT 2 _ZN5mlibc12_GLOB[...] + 315: 0000000008055dc2 144 FUNC LOCAL DEFAULT 2 _ZN5mlibc12_GLOB[...] + 316: 00000000080a25e8 1 OBJECT LOCAL DEFAULT 14 _ZN5mlibc12_GLOB[...] + 317: 0000000008078814 4 OBJECT LOCAL DEFAULT 4 _ZL12onceComplete + 318: 0000000008078818 4 OBJECT LOCAL DEFAULT 4 _ZL10onceLocked + 319: 00000000080570f6 76 FUNC LOCAL DEFAULT 2 _ZZ20pthread_bar[...] + 320: 000000000805734e 247 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 321: 0000000008057445 178 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 322: 00000000080574f7 48 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 323: 0000000008057c92 37 FUNC LOCAL DEFAULT 2 _Z41__static_ini[...] + 324: 0000000008057cb7 11 FUNC LOCAL DEFAULT 2 _GLOBAL__sub_I_p[...] + 325: 0000000000000000 0 FILE LOCAL DEFAULT ABS unistd.cpp + 326: 0000000008079ed0 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 327: 000000000809a398 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 328: 0000000008079ee8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 329: 0000000008079eec 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 330: 0000000008079ef0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 331: 0000000008079ef4 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 332: 0000000008079ef8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 333: 0000000008079efc 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 334: 0000000008079efd 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 335: 0000000008079efe 1 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 336: 0000000000000014 128 TLS LOCAL DEFAULT 7 _ZZ7ttynameE3buf + 337: 00000000080a2600 128 OBJECT LOCAL DEFAULT 14 _ZZ7getpassE8password + 338: 00000000080a2680 8 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 339: 000000000809b550 18 OBJECT LOCAL DEFAULT 13 _ZZN12_GLOBAL__N[...] + 340: 000000000805caf2 136 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 341: 000000000805cb7a 45 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 342: 00000000080a26a0 4096 OBJECT LOCAL DEFAULT 14 _ZZ12getusershel[...] + 343: 0000000000000000 0 FILE LOCAL DEFAULT ABS sys-ioctl.cpp + 344: 000000000807bc68 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 345: 000000000809a3a0 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 346: 0000000000000000 0 FILE LOCAL DEFAULT ABS charcode.cpp + 347: 000000000807bcd8 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 348: 000000000809a3a8 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 349: 00000000080a36a0 16 OBJECT LOCAL DEFAULT 14 _ZZN5mlibc16curr[...] + 350: 00000000080a36b0 8 OBJECT LOCAL DEFAULT 14 _ZGVZN5mlibc16cu[...] + 351: 00000000080a36b8 1 OBJECT LOCAL DEFAULT 14 _ZZN5mlibc22plat[...] + 352: 0000000000000000 0 FILE LOCAL DEFAULT ABS charset.cpp + 353: 000000000807be10 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 354: 000000000809a3b0 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 355: 00000000080a36b9 1 OBJECT LOCAL DEFAULT 14 _ZZN5mlibc15curr[...] + 356: 0000000000000000 0 FILE LOCAL DEFAULT ABS getopt.cpp + 357: 000000000807c400 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 358: 000000000809a3b8 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 359: 000000000809b56c 4 OBJECT LOCAL DEFAULT 13 _ZN12_GLOBAL__N_[...] + 360: 000000000805f4f6 1095 FUNC LOCAL DEFAULT 2 _ZZN12_GLOBAL__N[...] + 361: 000000000805f93e 841 FUNC LOCAL DEFAULT 2 _ZZN12_GLOBAL__N[...] + 362: 000000000805fc88 92 FUNC LOCAL DEFAULT 2 _ZZN12_GLOBAL__N[...] + 363: 000000000805fce4 93 FUNC LOCAL DEFAULT 2 _ZZN12_GLOBAL__N[...] + 364: 000000000805fd42 92 FUNC LOCAL DEFAULT 2 _ZZN12_GLOBAL__N[...] + 365: 000000000805fd9e 3078 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 366: 00000000080609a4 187 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 367: 0000000000000000 0 FILE LOCAL DEFAULT ABS global-config.cpp + 368: 00000000080616ea 71 FUNC LOCAL DEFAULT 2 _ZN5mlibcL10envE[...] + 369: 0000000008061756 22 FUNC LOCAL DEFAULT 2 _Z41__static_ini[...] + 370: 000000000806176c 11 FUNC LOCAL DEFAULT 2 _GLOBAL__sub_I_g[...] + 371: 0000000000000000 0 FILE LOCAL DEFAULT ABS inline-emitter.cpp + 372: 0000000000000000 0 FILE LOCAL DEFAULT ABS sigset.cpp + 373: 0000000008061e0a 18 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 374: 0000000008061e1c 17 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 375: 0000000000000000 0 FILE LOCAL DEFAULT ABS threads.cpp + 376: 000000000807c648 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 377: 000000000809a3c0 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 378: 000000000807c660 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 379: 000000000807c664 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 380: 000000000807c668 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 381: 000000000807c66c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 382: 000000000807c670 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 383: 000000000807c768 8 OBJECT LOCAL DEFAULT 4 _ZN5mlibcL17defa[...] + 384: 000000000807c770 8 OBJECT LOCAL DEFAULT 4 _ZN5mlibcL17defa[...] + 385: 000000000807c778 4 OBJECT LOCAL DEFAULT 4 _ZN5mlibcL14mute[...] + 386: 000000000807c77c 4 OBJECT LOCAL DEFAULT 4 _ZN5mlibcL15mute[...] + 387: 000000000807c780 4 OBJECT LOCAL DEFAULT 4 _ZN5mlibcL16mute[...] + 388: 000000000807c784 4 OBJECT LOCAL DEFAULT 4 _ZN5mlibcL17mute[...] + 389: 0000000000000000 0 FILE LOCAL DEFAULT ABS stack_protector.cpp + 390: 000000000807cd38 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 391: 000000000809a3c8 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 392: 0000000000000000 0 FILE LOCAL DEFAULT ABS cxxabi.cpp + 393: 0000000000000000 0 FILE LOCAL DEFAULT ABS options_internal[...] + 394: 00000000080632bf 0 FUNC LOCAL DEFAULT 2 __setjmp + 395: 0000000000000000 0 FILE LOCAL DEFAULT ABS assert.cpp + 396: 0000000000000000 0 FILE LOCAL DEFAULT ABS file-io.cpp + 397: 000000000807ced8 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 398: 000000000809a3d0 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 399: 000000000807cef0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 400: 000000000807cef4 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 401: 000000000807cef8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 402: 000000000807cefc 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 403: 000000000807cf00 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 404: 000000000807cf04 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 405: 000000000807cf05 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 406: 000000000807cf06 1 OBJECT LOCAL DEFAULT 4 _ZN5mlibc12_GLOB[...] + 407: 000000000807cf08 8 OBJECT LOCAL DEFAULT 4 _ZN5mlibc12_GLOB[...] + 408: 00000000080a36e0 16 OBJECT LOCAL DEFAULT 14 _ZZN5mlibc12_GLO[...] + 409: 00000000080a36f0 8 OBJECT LOCAL DEFAULT 14 _ZGVZN5mlibc12_G[...] + 410: 000000000806337c 91 FUNC LOCAL DEFAULT 2 _ZN5mlibc12_GLOB[...] + 411: 00000000080a3700 144 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 412: 00000000080a37a0 144 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 413: 00000000080a3840 144 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 414: 0000000008065046 11 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 415: 0000000008065046 11 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 416: 0000000008065052 235 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 417: 0000000008065052 235 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_[...] + 418: 00000000080a38d0 1 OBJECT LOCAL DEFAULT 14 _ZN12_GLOBAL__N_[...] + 419: 000000000806595b 240 FUNC LOCAL DEFAULT 2 _Z41__static_ini[...] + 420: 0000000008065a4b 11 FUNC LOCAL DEFAULT 2 _GLOBAL__sub_I_f[...] + 421: 0000000000000000 0 FILE LOCAL DEFAULT ABS fabs.c + 422: 0000000000000000 0 FILE LOCAL DEFAULT ABS __fpclassify.c + 423: 0000000000000000 0 FILE LOCAL DEFAULT ABS __fpclassifyf.c + 424: 0000000000000000 0 FILE LOCAL DEFAULT ABS __fpclassifyl.c + 425: 0000000000000000 0 FILE LOCAL DEFAULT ABS dirent.cpp + 426: 000000000807ebb8 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 427: 000000000809a3d8 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 428: 000000000807ebd0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 429: 000000000807ebd4 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 430: 000000000807ebd8 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 431: 000000000807ebdc 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 432: 000000000807ebe0 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 433: 000000000807ebe4 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 434: 000000000807ebe5 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 435: 0000000000000000 0 FILE LOCAL DEFAULT ABS fcntl.cpp + 436: 0000000008080020 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 437: 000000000809a3e0 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 438: 0000000000000000 0 FILE LOCAL DEFAULT ABS posix_stdio.cpp + 439: 00000000080801f0 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 440: 000000000809a3e8 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 441: 0000000008080208 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 442: 000000000808020c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 443: 0000000008080210 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 444: 0000000008080214 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 445: 0000000008080218 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 446: 000000000808021c 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 447: 000000000808021d 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 448: 0000000000000000 0 FILE LOCAL DEFAULT ABS posix_string.cpp + 449: 00000000080816a8 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 450: 000000000809a3f0 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 451: 0000000000000000 0 FILE LOCAL DEFAULT ABS strings.cpp + 452: 0000000000000000 0 FILE LOCAL DEFAULT ABS sys-stat.cpp + 453: 0000000008081ac0 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 454: 000000000809a3f8 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 455: 0000000000000000 0 FILE LOCAL DEFAULT ABS sys-time.cpp + 456: 0000000008081b90 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 457: 000000000809a400 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 458: 0000000000000000 0 FILE LOCAL DEFAULT ABS termios.cpp + 459: 0000000000000000 0 FILE LOCAL DEFAULT ABS getopt.cpp + 460: 0000000000000000 0 FILE LOCAL DEFAULT ABS strings.cpp + 461: 0000000000000000 0 FILE LOCAL DEFAULT ABS posix-file-io.cpp + 462: 0000000008081ce8 1 OBJECT LOCAL DEFAULT 4 _ZN3frgL8null_optE + 463: 000000000809a408 8 OBJECT LOCAL DEFAULT 12 _ZN3frg15_to_str[...] + 464: 0000000008081d00 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 465: 0000000008081d04 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 466: 0000000008081d08 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 467: 0000000008081d0c 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 468: 0000000008081d10 4 OBJECT LOCAL DEFAULT 4 _ZN12_GLOBAL__N_[...] + 469: 0000000008081d14 1 OBJECT LOCAL DEFAULT 4 _ZN3frg9_redblac[...] + 470: 0000000008081d15 1 OBJECT LOCAL DEFAULT 4 _ZN3frg12_GLOBAL[...] + 471: 0000000000000000 0 FILE LOCAL DEFAULT ABS + 472: 0000000008000000 0 NOTYPE LOCAL DEFAULT 1 __ehdr_start + 473: 000000000809a308 0 NOTYPE LOCAL DEFAULT 9 __fini_array_end + 474: 000000000809a300 0 NOTYPE LOCAL DEFAULT 9 __fini_array_start + 475: 000000000808313c 0 NOTYPE LOCAL DEFAULT 5 __GNU_EH_FRAME_HDR + 476: 000000000809a300 0 NOTYPE LOCAL DEFAULT 8 __init_array_end + 477: 000000000809a2d8 0 NOTYPE LOCAL DEFAULT 7 __preinit_array_end + 478: 000000000809a2d8 0 NOTYPE LOCAL DEFAULT 8 __init_array_start + 479: 000000000809a2d8 0 NOTYPE LOCAL DEFAULT 7 __preinit_array_start + 480: 00000000080686b6 45 FUNC WEAK DEFAULT 2 _ZN5mlibc17fmemo[...] + 481: 00000000080530e3 14 FUNC WEAK HIDDEN 2 _ZSt7launderIN3f[...] + 482: 00000000080524c0 117 FUNC WEAK HIDDEN 2 _ZN3frg9construc[...] + 483: 000000000802910e 45 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 484: 000000000800ed7a 41 FUNC GLOBAL DEFAULT 2 getwchar + 485: 00000000080559ab 146 FUNC GLOBAL DEFAULT 2 pthread_cleanup_pop + 486: 000000000800a2d3 349 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 487: 000000000806325e 9 FUNC GLOBAL HIDDEN 2 __stack_chk_fail[...] + 488: 0000000008063303 0 FUNC GLOBAL DEFAULT 2 longjmp + 489: 0000000008036e0a 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 490: 0000000008023599 2864 FUNC WEAK DEFAULT 2 _ZN3frg14do_prin[...] + 491: 0000000008043f54 37 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIN[...] + 492: 000000000801ba2c 476 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 493: 00000000080689e9 72 FUNC GLOBAL DEFAULT 2 stpcpy + 494: 000000000800eaca 111 FUNC GLOBAL DEFAULT 2 putchar + 495: 00000000080008d2 55 FUNC WEAK HIDDEN 2 _ZN3frg14locale_[...] + 496: 000000000800a05a 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA4[...] + 497: 0000000008006a70 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 498: 0000000008051328 84 FUNC WEAK HIDDEN 2 _ZN3frg9construc[...] + 499: 000000000806313c 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA5[...] + 500: 0000000008007702 50 FUNC WEAK HIDDEN 2 _ZN3frg11unique_[...] + 501: 00000000080508be 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 502: 0000000008022ef2 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 503: 0000000008030a54 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 504: 0000000008025584 430 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 505: 000000000803f9d9 48 FUNC GLOBAL HIDDEN 2 __do_syscall4 + 506: 0000000008051148 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 507: 0000000008051720 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIN3f[...] + 508: 0000000008000bfc 41 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 509: 000000000801d2e2 1785 FUNC WEAK DEFAULT 2 _ZN3frg15do_prin[...] + 510: 000000000803e1b9 229 FUNC GLOBAL DEFAULT 2 mbrlen + 511: 000000000801526c 42 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 512: 000000000805f3aa 187 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 513: 000000000805cd0a 146 FUNC GLOBAL DEFAULT 2 chroot + 514: 000000000803af26 83 FUNC GLOBAL DEFAULT 2 strcpy + 515: 00000000080286ca 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 516: 000000000801cf9c 681 FUNC WEAK DEFAULT 2 _ZN3frg16do_prin[...] + 517: 000000000806ba02 32 FUNC WEAK DEFAULT 2 _ZNK5mlibc18mems[...] + 518: 00000000080510be 137 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJ1[...] + 519: 0000000008051eaa 69 FUNC WEAK HIDDEN 2 _ZN3frg6formatIN[...] + 520: 0000000008000736 143 FUNC WEAK HIDDEN 2 _ZN3frg14format_[...] + 521: 0000000008056c5c 49 FUNC GLOBAL DEFAULT 2 pthread_mutex_co[...] + 522: 00000000080616d6 20 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17Globa[...] + 523: 00000000080632fa 0 FUNC GLOBAL DEFAULT 2 sigsetjmp + 524: 0000000008064154 145 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 525: 00000000080091df 29 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 526: 000000000800c5a0 62 FUNC GLOBAL DEFAULT 2 unsetenv + 527: 0000000008000956 99 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 528: 000000000805eb44 225 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 529: 0000000008017960 65 FUNC WEAK DEFAULT 2 _ZN3frg12basic_s[...] + 530: 0000000008066144 50 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 531: 00000000080664fa 47 FUNC GLOBAL DEFAULT 2 fabs + 532: 00000000080349d6 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 533: 0000000008009c77 49 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 534: 0000000008056ff5 257 FUNC GLOBAL DEFAULT 2 pthread_barrier_[...] + 535: 0000000008043ce4 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 536: 0000000008016ede 80 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 537: 0000000008061b70 100 FUNC GLOBAL DEFAULT 2 __mlibc_islessgr[...] + 538: 0000000008069415 45 FUNC GLOBAL DEFAULT 2 bcmp + 539: 000000000804ef24 18 FUNC WEAK HIDDEN 2 _ZNK13SymbolVers[...] + 540: 0000000008054fc4 873 FUNC GLOBAL DEFAULT 2 sqrt + 541: 00000000080617de 34 FUNC GLOBAL DEFAULT 2 ELF32_ST_INFO + 542: 00000000080632f5 0 FUNC GLOBAL DEFAULT 2 setjmp + 543: 0000000008052a46 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 544: 00000000080440ca 97 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 545: 0000000008030528 1110 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 546: 000000000804a2e8 70 FUNC GLOBAL HIDDEN 2 _ZN13RuntimeTlsM[...] + 547: 0000000008007f56 30 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 548: 00000000080527ee 26 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJK[...] + 549: 000000000806d9c0 32 OBJECT UNIQUE HIDDEN 4 _ZN3frg9slab_poo[...] + 550: 0000000008056bdf 53 FUNC GLOBAL DEFAULT 2 pthread_mutex_ti[...] + 551: 0000000008060f6e 49 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 552: 000000000803a92a 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 553: 0000000008053396 117 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 554: 000000000805047c 81 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 555: 000000000800d5a2 41 FUNC GLOBAL DEFAULT 2 tmpfile + 556: 000000000805e8d4 207 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 557: 00000000080268e6 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 558: 0000000008044f08 14 FUNC WEAK HIDDEN 2 _ZSt7launderI13S[...] + 559: 000000000805d9de 376 FUNC GLOBAL DEFAULT 2 ioctl + 560: 000000000805a71a 167 FUNC GLOBAL DEFAULT 2 pause + 561: 0000000008053152 61 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 562: 000000000800109e 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 563: 0000000008056e80 72 FUNC GLOBAL DEFAULT 2 pthread_cond_signal + 564: 0000000008057e02 110 FUNC WEAK DEFAULT 2 _ZN10ScopeTraceD2Ev + 565: 0000000008052ae6 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 566: 00000000080448d4 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 567: 000000000806115a 51 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 568: 0000000008060c47 54 FUNC WEAK DEFAULT 2 _ZSt26__throw_ba[...] + 569: 000000000804a701 653 FUNC GLOBAL HIDDEN 2 _Z9accessDtvP12S[...] + 570: 000000000800dfd5 53 FUNC GLOBAL DEFAULT 2 vscanf + 571: 00000000080130fc 38 FUNC WEAK DEFAULT 2 _ZN13BufferPrint[...] + 572: 0000000008051a76 81 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 573: 0000000008052b28 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA3[...] + 574: 000000000805d2f6 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 575: 000000000806ba7c 77 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIc[...] + 576: 000000000805116c 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 577: 0000000008033728 1116 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 578: 0000000008013922 50 FUNC WEAK DEFAULT 2 _ZN3frg11unique_[...] + 579: 000000000809a458 72 OBJECT WEAK DEFAULT 12 _ZTVN5mlibc20pol[...] + 580: 0000000008069694 173 FUNC GLOBAL DEFAULT 2 fstatat + 581: 000000000803b5bf 317 FUNC GLOBAL DEFAULT 2 strtok_r + 582: 0000000008052f89 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRK1[...] + 583: 0000000008029f8d 1917 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 584: 000000000801c2b2 423 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 585: 000000000805c812 97 FUNC GLOBAL DEFAULT 2 getgid + 586: 000000000803bd72 57 FUNC GLOBAL DEFAULT 2 wcstok + 587: 00000000080662bc 14 FUNC WEAK DEFAULT 2 _ZSt4moveIRPN5ml[...] + 588: 000000000801c108 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 589: 0000000008028cd2 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 590: 0000000008067957 1375 FUNC GLOBAL DEFAULT 2 popen + 591: 000000000805d8fc 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 592: 0000000008001d18 1122 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 593: 000000000805b30e 1982 FUNC GLOBAL DEFAULT 2 sysconf + 594: 000000000800d8b8 183 FUNC GLOBAL DEFAULT 2 printf + 595: 000000000809b580 8 OBJECT GLOBAL DEFAULT 13 stdout + 596: 0000000008061732 36 FUNC GLOBAL DEFAULT 2 _ZN5mlibc12Globa[...] + 597: 000000000800e152 245 FUNC GLOBAL DEFAULT 2 vsprintf + 598: 00000000080009e4 46 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 599: 000000000800090a 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 600: 000000000805d4fe 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 601: 0000000008031b9e 349 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 602: 0000000008052906 144 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 603: 0000000008026590 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 604: 000000000803b7b9 53 FUNC GLOBAL DEFAULT 2 wcstof + 605: 000000000802c53b 209 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 606: 0000000008056f29 31 FUNC GLOBAL DEFAULT 2 pthread_barriera[...] + 607: 000000000806ad2a 577 FUNC GLOBAL DEFAULT 2 _ZN5mlibc18memst[...] + 608: 000000000806a451 22 FUNC GLOBAL DEFAULT 2 cfgetospeed + 609: 0000000008006cc6 1283 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 610: 00000000080666eb 267 FUNC GLOBAL DEFAULT 2 fdopendir + 611: 0000000008051ae4 58 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 612: 000000000800ba92 50 FUNC WEAK HIDDEN 2 _ZN3frg17basic_s[...] + 613: 000000000800e541 61 FUNC GLOBAL DEFAULT 2 vswprintf + 614: 00000000080065ba 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 615: 0000000008000e3e 21 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 616: 000000000806b5ea 65 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11cooki[...] + 617: 00000000080568d6 37 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 618: 0000000008063624 1190 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 619: 000000000805a103 21 FUNC GLOBAL DEFAULT 2 getlogin + 620: 000000000800e9f1 73 FUNC GLOBAL DEFAULT 2 putc_unlocked + 621: 00000000080528e9 14 FUNC WEAK HIDDEN 2 _ZSt7forwardI12O[...] + 622: 000000000801b48a 482 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 623: 00000000080553a0 15 FUNC GLOBAL DEFAULT 2 pthread_attr_destroy + 624: 0000000008062b5e 41 FUNC GLOBAL DEFAULT 2 _ZN5mlibc24threa[...] + 625: 000000000806625c 34 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 626: 0000000008050b9e 18 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIN[...] + 627: 000000000801dfb8 457 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 628: 000000000801859c 63 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 629: 000000000800036c 144 FUNC GLOBAL DEFAULT 2 _ZN5mlibc16parse[...] + 630: 0000000008044bbe 14 FUNC WEAK HIDDEN 2 _ZSt7launderI16O[...] + 631: 000000000809c2e1 1 OBJECT GLOBAL HIDDEN 14 rtldConfig + 632: 000000000805e884 31 FUNC WEAK DEFAULT 2 _ZN5mlibc8code_s[...] + 633: 000000000805d98e 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA6[...] + 634: 00000000080529ba 26 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 635: 0000000008004302 13 FUNC WEAK DEFAULT 2 _ZN5mlibc10int_l[...] + 636: 0000000008065885 124 FUNC GLOBAL DEFAULT 2 ungetc + 637: 00000000080355fe 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 638: 0000000008051f8f 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 639: 000000000804f88e 26 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJi[...] + 640: 000000000806a7d2 54 FUNC GLOBAL DEFAULT 2 tcgetsid + 641: 0000000008044050 121 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 642: 00000000080553fe 34 FUNC GLOBAL DEFAULT 2 pthread_attr_get[...] + 643: 00000000080179a2 51 FUNC WEAK DEFAULT 2 _ZN3frg12basic_s[...] + 644: 0000000008045370 128 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 645: 000000000802a75a 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRcE[...] + 646: 00000000080003fc 202 FUNC GLOBAL DEFAULT 2 _ZN5mlibc16set_s[...] + 647: 00000000080613f8 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 648: 0000000008041b78 965 FUNC GLOBAL HIDDEN 2 interpreterMain + 649: 000000000804ece0 84 FUNC WEAK HIDDEN 2 _ZN10RelocationC[...] + 650: 0000000008055685 56 FUNC GLOBAL DEFAULT 2 pthread_create + 651: 000000000803fc1e 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 652: 00000000080286f2 259 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 653: 000000000803298e 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 654: 000000000805247e 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 655: 00000000080178ea 65 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 656: 0000000008040a3c 22 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 657: 0000000008061e2d 41 FUNC GLOBAL DEFAULT 2 sigemptyset + 658: 000000000805646d 351 FUNC GLOBAL DEFAULT 2 pthread_getspecific + 659: 00000000080579f9 214 FUNC GLOBAL DEFAULT 2 pthread_rwlock_rdlock + 660: 00000000080688a9 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRPm[...] + 661: 0000000008060f3c 49 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 662: 0000000008034270 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 663: 000000000803be86 3906 FUNC GLOBAL DEFAULT 2 strerror + 664: 00000000080581d3 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 665: 000000000806b6ba 29 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11cooki[...] + 666: 00000000080595ed 51 FUNC GLOBAL DEFAULT 2 fpathconf + 667: 000000000806bb4c 47 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIc[...] + 668: 0000000008001156 63 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 669: 000000000802e9ac 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 670: 000000000801bf5e 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 671: 0000000008052a88 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA5[...] + 672: 0000000008016b9c 63 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 673: 000000000806858d 207 FUNC WEAK DEFAULT 2 _ZN3frg9construc[...] + 674: 00000000080690df 98 FUNC GLOBAL DEFAULT 2 memrchr + 675: 0000000008068975 116 FUNC GLOBAL DEFAULT 2 strndup + 676: 000000000805c935 97 FUNC GLOBAL DEFAULT 2 geteuid + 677: 0000000008048406 531 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 678: 00000000080227ac 480 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 679: 0000000008068274 64 FUNC WEAK DEFAULT 2 _ZN10popen_fileC[...] + 680: 0000000008055355 75 FUNC GLOBAL DEFAULT 2 pthread_attr_init + 681: 000000000802146a 459 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 682: 000000000804ffce 18 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 683: 0000000008050dfc 77 FUNC WEAK HIDDEN 2 _ZN3frg6vectorI1[...] + 684: 0000000008034f16 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 685: 0000000008012fde 38 FUNC WEAK DEFAULT 2 _ZN13StreamPrint[...] + 686: 0000000008044a0e 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 687: 0000000008051b2c 30 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 688: 0000000008027c20 267 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 689: 0000000008022ef2 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 690: 0000000008041573 189 FUNC GLOBAL HIDDEN 2 memmove + 691: 000000000804f5a6 41 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 692: 0000000008064042 90 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 693: 000000000803f761 72 FUNC GLOBAL HIDDEN 2 _ZN5mlibc11sys_t[...] + 694: 000000000805d80c 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 695: 000000000805759c 125 FUNC GLOBAL DEFAULT 2 pthread_rwlock_init + 696: 000000000800cb1c 178 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 697: 00000000080085ae 446 FUNC WEAK HIDDEN 2 _ZN13FutexLockIm[...] + 698: 0000000008053144 14 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 699: 0000000008044c98 26 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 700: 0000000008067866 241 FUNC GLOBAL DEFAULT 2 pclose + 701: 00000000080556f5 387 FUNC GLOBAL DEFAULT 2 pthread_exit + 702: 000000000806834d 172 FUNC WEAK DEFAULT 2 _ZN3frg9construc[...] + 703: 0000000008019950 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA4[...] + 704: 000000000800db01 184 FUNC GLOBAL DEFAULT 2 snprintf + 705: 0000000008028910 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 706: 0000000008066090 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 707: 00000000080013ba 42 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 708: 00000000080518b4 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIN[...] + 709: 0000000008051864 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 710: 00000000080515b4 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 711: 000000000802de82 449 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 712: 00000000080067ec 258 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 713: 000000000805dc3e 63 FUNC WEAK DEFAULT 2 _ZN5mlibc20polym[...] + 714: 000000000805c078 97 FUNC GLOBAL DEFAULT 2 gettid + 715: 000000000805a673 167 FUNC GLOBAL DEFAULT 2 pathconf + 716: 0000000008050bb0 33 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIN[...] + 717: 0000000008026de1 2864 FUNC WEAK DEFAULT 2 _ZN3frg14do_prin[...] + 718: 00000000080012b1 67 FUNC WEAK DEFAULT 2 _ZN3frg6formatIj[...] + 719: 000000000805932e 163 FUNC GLOBAL DEFAULT 2 faccessat + 720: 000000000802944c 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 721: 0000000008056f76 15 FUNC GLOBAL DEFAULT 2 pthread_barriera[...] + 722: 000000000802298c 480 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 723: 00000000080091fc 74 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 724: 000000000806513d 55 FUNC GLOBAL DEFAULT 2 fileno_unlocked + 725: 00000000080441a8 26 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 726: 000000000805d462 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 727: 00000000080510a4 26 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJK[...] + 728: 00000000080a36d0 8 OBJECT GLOBAL DEFAULT 14 __stack_chk_guard + 729: 000000000804ed64 30 FUNC WEAK HIDDEN 2 _ZNK10Relocation[...] + 730: 0000000008044a31 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 731: 0000000008063303 0 FUNC GLOBAL DEFAULT 2 _longjmp + 732: 0000000008029f54 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 733: 00000000080409ae 32 FUNC WEAK HIDDEN 2 _ZN13FutexLockIm[...] + 734: 0000000008009ffb 15 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 735: 00000000080069d8 43 FUNC WEAK HIDDEN 2 _ZN3frg3maxImEER[...] + 736: 000000000803b8a4 43 FUNC GLOBAL DEFAULT 2 wcstoull + 737: 0000000008052d1a 51 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 738: 00000000080663c8 45 FUNC WEAK DEFAULT 2 _ZN5mlibc7fd_fileD1Ev + 739: 000000000804505c 255 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 740: 000000000800c8f0 119 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 741: 0000000008056d60 46 FUNC GLOBAL DEFAULT 2 pthread_condattr[...] + 742: 00000000080699e1 45 FUNC GLOBAL DEFAULT 2 mknod + 743: 0000000008067f7a 105 FUNC GLOBAL DEFAULT 2 ftello64 + 744: 000000000804f9c6 216 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 745: 0000000008043d7a 77 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIN[...] + 746: 0000000008002965 36 FUNC GLOBAL DEFAULT 2 atol + 747: 000000000805f465 13 FUNC GLOBAL DEFAULT 2 _ZN5mlibc15curre[...] + 748: 000000000806a057 47 FUNC GLOBAL DEFAULT 2 timerisset + 749: 0000000008043cd2 18 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 750: 000000000805d71c 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA7[...] + 751: 0000000008052ece 14 FUNC WEAK HIDDEN 2 _ZSt7launderIbEPT_S1_ + 752: 000000000806a978 112 FUNC GLOBAL DEFAULT 2 _ZN5mlibc8mem_fi[...] + 753: 000000000804fffa 26 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJK[...] + 754: 0000000008050b84 26 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 755: 000000000805755f 46 FUNC GLOBAL DEFAULT 2 pthread_rwlockat[...] + 756: 00000000080490dc 956 FUNC GLOBAL HIDDEN 2 _ZN12SharedObjec[...] + 757: 00000000080263b4 476 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 758: 000000000806a1c2 162 FUNC GLOBAL DEFAULT 2 timer_create + 759: 0000000008055491 53 FUNC GLOBAL DEFAULT 2 pthread_attr_getstack + 760: 000000000800e964 26 FUNC GLOBAL DEFAULT 2 getc_unlocked + 761: 00000000080615fc 41 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 762: 000000000806bb06 18 FUNC WEAK DEFAULT 2 _ZNK3frg6vectorI[...] + 763: 000000000805dc12 31 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13wide_[...] + 764: 0000000008061923 88 FUNC GLOBAL DEFAULT 2 __mlibc_islessl + 765: 000000000804520b 48 FUNC GLOBAL HIDDEN 2 _Z7trySeekil + 766: 00000000080523ec 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 767: 0000000008021eea 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 768: 0000000008061cef 100 FUNC GLOBAL DEFAULT 2 __mlibc_isgreate[...] + 769: 00000000080530f1 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRKN[...] + 770: 000000000801e348 427 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 771: 0000000008044334 99 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 772: 0000000008038198 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 773: 0000000008061444 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 774: 0000000008060fd2 84 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 775: 000000000806318c 126 FUNC GLOBAL DEFAULT 2 _ZN5mlibc14initS[...] + 776: 0000000008056cda 32 FUNC GLOBAL DEFAULT 2 pthread_condattr[...] + 777: 0000000008052da4 149 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 778: 0000000008044cb2 26 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 779: 0000000008021800 457 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 780: 000000000802e9e5 1917 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 781: 0000000008007464 452 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 782: 000000000800c204 205 FUNC GLOBAL DEFAULT 2 getenv + 783: 000000000806492c 91 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 784: 0000000008045370 128 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 785: 00000000080233f2 423 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 786: 000000000806868a 43 FUNC WEAK DEFAULT 2 _ZN5mlibc8mem_fi[...] + 787: 000000000803be11 47 FUNC GLOBAL DEFAULT 2 wcslen + 788: 000000000800b1ff 72 FUNC GLOBAL DEFAULT 2 iswcntrl + 789: 0000000008034900 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 790: 000000000800854a 100 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 791: 000000000806955a 151 FUNC GLOBAL DEFAULT 2 fchmod + 792: 000000000805a9a3 177 FUNC GLOBAL DEFAULT 2 pwrite64 + 793: 0000000008013122 60 FUNC WEAK DEFAULT 2 _ZN13BufferPrint[...] + 794: 000000000806bb18 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 795: 000000000801995e 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 796: 000000000803fcd6 69 FUNC WEAK HIDDEN 2 _ZN3frg6formatIP[...] + 797: 0000000008000f4c 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRPK[...] + 798: 000000000803f831 59 FUNC WEAK HIDDEN 2 _Z7syscallIimmEl[...] + 799: 0000000008050ff6 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 800: 000000000804ee6a 78 FUNC WEAK HIDDEN 2 _ZN13SymbolVersi[...] + 801: 0000000008027bf8 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 802: 000000000800afba 83 FUNC GLOBAL DEFAULT 2 iswpunct + 803: 0000000008004225 23 FUNC WEAK HIDDEN 2 _ZN5mlibc15get_c[...] + 804: 0000000008028b60 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 805: 000000000803419a 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 806: 0000000008053520 260 FUNC GLOBAL DEFAULT 2 floor + 807: 000000000802cf74 449 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 808: 000000000806118e 51 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 809: 0000000008002ac0 37 FUNC GLOBAL DEFAULT 2 strtold + 810: 000000000804f780 141 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 811: 000000000805c873 97 FUNC GLOBAL DEFAULT 2 getegid + 812: 000000000805d496 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 813: 000000000800ac2b 86 FUNC GLOBAL DEFAULT 2 isblank + 814: 000000000800d6e3 42 FUNC GLOBAL DEFAULT 2 setlinebuf + 815: 0000000008057e70 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 816: 00000000080611c1 14 FUNC WEAK DEFAULT 2 _ZSt7forwardISt9[...] + 817: 0000000008012f4f 84 FUNC WEAK DEFAULT 2 _ZN3frg15generic[...] + 818: 0000000008008b8a 22 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 819: 000000000802d16f 1917 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 820: 00000000080035ab 24 FUNC GLOBAL DEFAULT 2 labs + 821: 000000000803b879 43 FUNC GLOBAL DEFAULT 2 wcstoll + 822: 000000000804f266 82 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 823: 00000000080012f4 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 824: 000000000804f0f4 31 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 825: 000000000800ae6e 83 FUNC GLOBAL DEFAULT 2 iswalpha + 826: 000000000800e9c8 41 FUNC GLOBAL DEFAULT 2 gets + 827: 00000000080468a8 243 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 828: 000000000800b060 83 FUNC GLOBAL DEFAULT 2 iswblank + 829: 0000000008041f4a 32 FUNC GLOBAL DEFAULT 2 __dlapi_error + 830: 000000000806165a 40 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 831: 0000000008055a3d 154 FUNC GLOBAL DEFAULT 2 pthread_setname_np + 832: 0000000008024a6c 125 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 833: 000000000803d0ae 178 FUNC GLOBAL DEFAULT 2 memmem + 834: 000000000805d097 165 FUNC GLOBAL DEFAULT 2 getresuid + 835: 000000000800331e 238 FUNC GLOBAL DEFAULT 2 bsearch + 836: 000000000805c3bb 142 FUNC GLOBAL DEFAULT 2 usleep + 837: 000000000806b62c 112 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11cooki[...] + 838: 000000000802b8c0 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 839: 00000000080580e3 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA1[...] + 840: 0000000008028910 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 841: 000000000803f95b 14 FUNC GLOBAL HIDDEN 2 __do_syscall_ret + 842: 0000000008046a26 838 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 843: 000000000802f308 1135 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 844: 0000000008064a3c 255 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 845: 0000000008034aa6 1135 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 846: 0000000008062bda 101 FUNC GLOBAL DEFAULT 2 _ZN5mlibc16threa[...] + 847: 00000000080007c6 236 FUNC WEAK HIDDEN 2 _ZN3frg14format_[...] + 848: 000000000805c729 233 FUNC GLOBAL DEFAULT 2 execve + 849: 000000000803aa00 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 850: 0000000008069b49 204 FUNC GLOBAL DEFAULT 2 utimensat + 851: 00000000080283f4 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 852: 000000000802913c 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 853: 0000000008051954 112 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 854: 000000000800e28c 75 FUNC GLOBAL DEFAULT 2 vsscanf + 855: 000000000800cae8 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 856: 0000000008056c8d 36 FUNC GLOBAL DEFAULT 2 pthread_condattr_init + 857: 000000000809c300 144 OBJECT GLOBAL HIDDEN 14 initialRepository + 858: 000000000803f81b 22 FUNC GLOBAL HIDDEN 2 _ZN5mlibc13sys_c[...] + 859: 00000000080442a4 67 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 860: 0000000008006682 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 861: 000000000805bde3 11 FUNC GLOBAL DEFAULT 2 getpagesize + 862: 000000000805c996 97 FUNC GLOBAL DEFAULT 2 getpid + 863: 0000000008057c02 105 FUNC GLOBAL DEFAULT 2 pthread_getcpuclockid + 864: 0000000008055450 34 FUNC GLOBAL DEFAULT 2 pthread_attr_get[...] + 865: 0000000008044c6e 14 FUNC WEAK HIDDEN 2 _ZSt7launderIP12[...] + 866: 000000000801f856 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 867: 00000000080490dc 956 FUNC GLOBAL HIDDEN 2 _ZN12SharedObjec[...] + 868: 000000000800442d 1546 FUNC WEAK DEFAULT 2 _ZN5mlibc7strtof[...] + 869: 00000000080008d2 55 FUNC WEAK HIDDEN 2 _ZN3frg14locale_[...] + 870: 000000000800343e 61 FUNC GLOBAL DEFAULT 2 qsort + 871: 0000000008032a64 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 872: 000000000805dc7e 32 FUNC WEAK DEFAULT 2 _ZN5mlibc13utf8_[...] + 873: 000000000804aa34 111 FUNC GLOBAL HIDDEN 2 _ZN12ObjectSymbo[...] + 874: 000000000800139e 14 FUNC WEAK HIDDEN 2 _ZSt7launderIKiE[...] + 875: 00000000080593d1 168 FUNC GLOBAL DEFAULT 2 fchown + 876: 000000000803bca7 97 FUNC GLOBAL DEFAULT 2 wcsrchr + 877: 000000000806197b 100 FUNC GLOBAL DEFAULT 2 __mlibc_islessequal + 878: 000000000805bb2a 53 FUNC GLOBAL DEFAULT 2 truncate + 879: 00000000080665fd 139 FUNC GLOBAL DEFAULT 2 __fpclassifyl + 880: 0000000008023248 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 881: 000000000800d804 180 FUNC GLOBAL DEFAULT 2 fscanf + 882: 000000000800e761 118 FUNC GLOBAL DEFAULT 2 fgets + 883: 0000000008052f98 103 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 884: 000000000802c7ce 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 885: 0000000008000d58 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 886: 000000000800e6b3 53 FUNC GLOBAL DEFAULT 2 vwprintf + 887: 000000000800af14 83 FUNC GLOBAL DEFAULT 2 iswxdigit + 888: 0000000008001196 16 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 889: 000000000803f1e8 82 FUNC WEAK DEFAULT 2 _ZN3frg7eternalI[...] + 890: 0000000008027bf8 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 891: 0000000008056369 260 FUNC GLOBAL DEFAULT 2 pthread_key_delete + 892: 000000000804f254 18 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 893: 000000000804bdac 926 FUNC GLOBAL HIDDEN 2 _ZN6Loader11link[...] + 894: 0000000008037640 1135 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 895: 00000000080066ea 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 896: 000000000803fd1b 104 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 897: 0000000008051f3f 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 898: 0000000008016ede 80 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 899: 0000000008064396 135 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 900: 0000000008000ae2 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 901: 000000000805340b 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIKN3[...] + 902: 0000000008049498 125 FUNC GLOBAL HIDDEN 2 _ZN12SharedObjec[...] + 903: 0000000008008bf0 1519 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 904: 0000000008044f24 298 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 905: 00000000080556ec 9 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7do_exitEv + 906: 00000000080610d6 72 FUNC WEAK DEFAULT 2 _ZNR3frg8optiona[...] + 907: 000000000804f6c6 29 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 908: 0000000008006a20 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 909: 0000000008013922 50 FUNC WEAK DEFAULT 2 _ZN3frg11unique_[...] + 910: 00000000080611d0 51 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 911: 0000000008015eba 3065 FUNC WEAK DEFAULT 2 _ZN3frg13printf_[...] + 912: 000000000800e97e 26 FUNC GLOBAL DEFAULT 2 getc + 913: 0000000008050656 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 914: 000000000804498e 33 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 915: 000000000804166c 673 FUNC GLOBAL HIDDEN 2 lazyRelocate + 916: 00000000080634cc 251 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 917: 0000000008058632 143 FUNC GLOBAL DEFAULT 2 fchdir + 918: 0000000008052b36 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 919: 000000000800744c 24 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 920: 000000000805e19e 43 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 921: 000000000800431f 16 FUNC WEAK DEFAULT 2 _ZN5mlibc10int_l[...] + 922: 000000000802c60c 449 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 923: 0000000008024aea 456 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 924: 000000000804c8f6 310 FUNC GLOBAL HIDDEN 2 _ZN6Loader13_sch[...] + 925: 000000000801b102 424 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 926: 000000000804670c 412 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 927: 0000000008036eda 1122 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 928: 0000000008041197 45 FUNC GLOBAL HIDDEN 2 memcpy + 929: 000000000809c000 1 OBJECT UNIQUE DEFAULT 14 _ZZN5mlibc12glob[...] + 930: 0000000008040a72 33 FUNC GLOBAL HIDDEN 2 _ZN5mlibc9PanicS[...] + 931: 0000000008056070 290 FUNC GLOBAL DEFAULT 2 pthread_cancel + 932: 000000000804323c 473 FUNC GLOBAL DEFAULT 2 __dlapi_find_object + 933: 000000000806a120 162 FUNC GLOBAL DEFAULT 2 setitimer + 934: 00000000080512da 18 FUNC WEAK HIDDEN 2 _ZNK3frg6vectorI[...] + 935: 00000000080400bc 208 FUNC WEAK HIDDEN 2 _ZZN3frg11_fmt_b[...] + 936: 0000000008056cfa 71 FUNC GLOBAL DEFAULT 2 pthread_condattr[...] + 937: 00000000080441c2 153 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 938: 00000000080656fb 275 FUNC GLOBAL DEFAULT 2 setvbuf + 939: 000000000804ed34 17 FUNC WEAK HIDDEN 2 _ZN10Relocation6[...] + 940: 0000000008000ffd 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 941: 0000000008053419 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIP12[...] + 942: 000000000809b588 0 OBJECT GLOBAL HIDDEN 13 __TMC_END__ + 943: 000000000809a410 72 OBJECT WEAK DEFAULT 12 _ZTVN5mlibc28pol[...] + 944: 000000000804ef36 18 FUNC WEAK HIDDEN 2 _ZNK13SymbolVers[...] + 945: 00000000080513f1 88 FUNC WEAK HIDDEN 2 _ZN3frg10destruc[...] + 946: 00000000080212a2 456 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 947: 000000000801bdb2 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 948: 00000000080625b9 395 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17threa[...] + 949: 00000000080588b8 383 FUNC GLOBAL DEFAULT 2 execl + 950: 0000000008051e5a 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 951: 0000000008066eba 53 FUNC GLOBAL DEFAULT 2 seekdir + 952: 0000000008032b34 1105 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 953: 000000000800c8aa 18 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 954: 00000000080660f8 35 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 955: 0000000008012ed0 42 FUNC WEAK DEFAULT 2 _ZN5mlibc9StdioL[...] + 956: 000000000804baf4 137 FUNC GLOBAL HIDDEN 2 _ZN6LoaderC1EP5S[...] + 957: 000000000804a1ef 248 FUNC GLOBAL HIDDEN 2 _Z10doDestructP1[...] + 958: 0000000008038790 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 959: 000000000804fe86 68 FUNC WEAK HIDDEN 2 _ZNK3frg8hash_ma[...] + 960: 000000000804f0d8 27 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 961: 00000000080223ea 479 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 962: 000000000800d4fd 165 FUNC GLOBAL DEFAULT 2 renameat + 963: 000000000800f08a 137 FUNC GLOBAL DEFAULT 2 perror + 964: 000000000805688e 72 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 965: 00000000080398ce 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 966: 0000000008044d5c 18 FUNC WEAK HIDDEN 2 _ZNK3frg4hashIP1[...] + 967: 0000000008038cb6 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 968: 0000000008006974 48 FUNC WEAK DEFAULT 2 _ZN3frg14slab_al[...] + 969: 0000000008052808 58 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 970: 000000000804ab9c 22 FUNC GLOBAL HIDDEN 2 _ZN12ObjectSymbo[...] + 971: 0000000008057e02 110 FUNC WEAK DEFAULT 2 _ZN10ScopeTraceD1Ev + 972: 000000000805b108 136 FUNC GLOBAL DEFAULT 2 swab + 973: 0000000008044ba2 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIbEO[...] + 974: 00000000080042cf 19 FUNC WEAK HIDDEN 2 _ZN3frg10bitop_i[...] + 975: 0000000008066fd7 42 FUNC GLOBAL DEFAULT 2 creat + 976: 000000000805aa54 169 FUNC GLOBAL DEFAULT 2 readlink + 977: 000000000806627e 14 FUNC WEAK DEFAULT 2 _ZN3frg16intrusi[...] + 978: 000000000809a320 0 OBJECT GLOBAL HIDDEN 11 __DTOR_END__ + 979: 000000000803fa7d 79 FUNC GLOBAL HIDDEN 2 __do_syscall7 + 980: 0000000008037570 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 981: 0000000008051f81 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA1[...] + 982: 0000000008051fee 281 FUNC WEAK HIDDEN 2 _ZN3frg6vectorI1[...] + 983: 000000000805e8c4 15 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 984: 00000000080556c8 36 FUNC GLOBAL DEFAULT 2 pthread_equal + 985: 000000000804f2b8 38 FUNC WEAK HIDDEN 2 _ZN3frg5stackIP1[...] + 986: 0000000008002320 1122 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 987: 00000000080514a4 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 988: 0000000008066376 34 FUNC WEAK DEFAULT 2 _ZNK3frg5_list14[...] + 989: 000000000800eb39 266 FUNC GLOBAL DEFAULT 2 puts + 990: 000000000803f0b0 149 FUNC GLOBAL DEFAULT 2 __cxa_finalize + 991: 0000000008051292 72 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 992: 000000000805c4df 152 FUNC GLOBAL DEFAULT 2 dup2 + 993: 000000000800433c 31 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 994: 000000000804478e 128 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 995: 000000000805068a 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 996: 000000000804ed46 30 FUNC WEAK HIDDEN 2 _ZNK10Relocation[...] + 997: 000000000803f748 25 FUNC GLOBAL HIDDEN 2 _ZN5mlibc8sys_se[...] + 998: 000000000803fa41 60 FUNC GLOBAL HIDDEN 2 __do_syscall6 + 999: 000000000802ad96 449 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1000: 000000000800ad2d 86 FUNC GLOBAL DEFAULT 2 islower + 1001: 000000000803e29e 368 FUNC GLOBAL DEFAULT 2 mbrtowc + 1002: 0000000008027fce 259 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 1003: 000000000805db56 29 FUNC GLOBAL DEFAULT 2 _ZN5mlibc20polym[...] + 1004: 000000000803f969 16 FUNC GLOBAL HIDDEN 2 __do_syscall0 + 1005: 000000000803173c 1122 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1006: 0000000008026590 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1007: 0000000008051684 18 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 1008: 00000000080283f4 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1009: 000000000800c76c 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1010: 000000000806a6a1 151 FUNC GLOBAL DEFAULT 2 tcflush + 1011: 0000000008058a37 625 FUNC GLOBAL DEFAULT 2 execle + 1012: 000000000804bb7e 557 FUNC GLOBAL HIDDEN 2 _ZN6Loader13_bui[...] + 1013: 0000000008065901 90 FUNC GLOBAL DEFAULT 2 __fpurge + 1014: 00000000080503fe 73 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 1015: 000000000805c8d4 97 FUNC GLOBAL DEFAULT 2 getuid + 1016: 000000000805bdee 472 FUNC GLOBAL DEFAULT 2 getpass + 1017: 000000000800b7c9 81 FUNC GLOBAL DEFAULT 2 tolower + 1018: 000000000801e6a2 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1019: 000000000805db74 43 FUNC GLOBAL DEFAULT 2 _ZN5mlibc20polym[...] + 1020: 0000000008008804 318 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1021: 00000000080662ca 26 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 1022: 0000000008031596 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1023: 0000000008017c3a 2402 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1024: 000000000803f248 149 FUNC WEAK DEFAULT 2 _ZN3frg6vectorI1[...] + 1025: 000000000802f91e 1132 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1026: 000000000806a808 51 FUNC GLOBAL DEFAULT 2 tcsendbreak + 1027: 0000000008066c16 50 FUNC GLOBAL DEFAULT 2 rewinddir + 1028: 000000000800b159 83 FUNC GLOBAL DEFAULT 2 iswlower + 1029: 0000000008007d92 400 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 1030: 0000000008061306 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1031: 0000000008044908 77 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 1032: 000000000806123a 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1033: 0000000008002fd1 796 FUNC GLOBAL DEFAULT 2 system + 1034: 0000000008043e78 191 FUNC WEAK HIDDEN 2 _ZN3frg17basic_s[...] + 1035: 0000000008066176 17 FUNC WEAK DEFAULT 2 _ZNK3frg5_list14[...] + 1036: 000000000800f062 20 FUNC GLOBAL DEFAULT 2 feof + 1037: 000000000806a3a9 146 FUNC GLOBAL DEFAULT 2 timer_delete + 1038: 000000000802ddb1 209 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1039: 000000000800ec74 56 FUNC GLOBAL DEFAULT 2 fgetws + 1040: 00000000080068ee 41 FUNC WEAK HIDDEN 2 _ZN3frg14slab_al[...] + 1041: 000000000806b9b4 78 FUNC WEAK DEFAULT 2 _ZN5mlibc18memst[...] + 1042: 000000000803bc72 53 FUNC GLOBAL DEFAULT 2 wcspbrk + 1043: 000000000803938e 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1044: 000000000803f92e 45 FUNC WEAK HIDDEN 2 _Z7syscallImEllT_ + 1045: 000000000801f500 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1046: 0000000008004a37 1545 FUNC WEAK DEFAULT 2 _ZN5mlibc7strtof[...] + 1047: 0000000008051e9c 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIN3f[...] + 1048: 000000000803b823 43 FUNC GLOBAL DEFAULT 2 wcstol + 1049: 00000000080634cc 251 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 1050: 0000000008051fd1 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA1[...] + 1051: 0000000008051ccb 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 1052: 00000000080534c3 0 FUNC GLOBAL HIDDEN 2 __mlibcTlsdescStatic + 1053: 0000000008050c06 254 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1054: 0000000008003cd5 166 FUNC GLOBAL DEFAULT 2 malloc + 1055: 000000000800d342 286 FUNC GLOBAL DEFAULT 2 remove + 1056: 0000000008006a12 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA3[...] + 1057: 000000000805cc7b 143 FUNC GLOBAL DEFAULT 2 isatty + 1058: 000000000803945e 1135 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1059: 0000000008016eba 35 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 1060: 0000000008002fa1 48 FUNC GLOBAL DEFAULT 2 quick_exit + 1061: 000000000806a43b 22 FUNC GLOBAL DEFAULT 2 cfgetispeed + 1062: 000000000805876a 313 FUNC GLOBAL DEFAULT 2 confstr + 1063: 000000000805d4ca 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1064: 000000000800b0b3 83 FUNC GLOBAL DEFAULT 2 iswspace + 1065: 00000000080399a4 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1066: 000000000801e4f4 430 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1067: 00000000080029ed 137 FUNC GLOBAL DEFAULT 2 siglongjmp + 1068: 0000000008052a2a 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIR12[...] + 1069: 000000000804194b 7 FUNC GLOBAL HIDDEN 2 dl_debug_state + 1070: 000000000800cbdc 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1071: 0000000008001378 38 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1072: 0000000008055545 32 FUNC GLOBAL DEFAULT 2 pthread_attr_getscope + 1073: 000000000800cbce 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 1074: 00000000080517fa 92 FUNC WEAK HIDDEN 2 _ZN3frg4swapERNS[...] + 1075: 0000000008066368 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRKc[...] + 1076: 000000000806179b 31 FUNC GLOBAL DEFAULT 2 ELF64_ST_INFO + 1077: 000000000804f56c 57 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1078: 0000000008051b4a 113 FUNC WEAK HIDDEN 2 _ZNK3frg4hashINS[...] + 1079: 000000000805c332 137 FUNC GLOBAL DEFAULT 2 sleep + 1080: 0000000008052edc 82 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 1081: 000000000804523b 200 FUNC GLOBAL HIDDEN 2 _Z14tryReadExact[...] + 1082: 0000000008041f6a 40 FUNC GLOBAL DEFAULT 2 __dlapi_get_tls + 1083: 00000000080a36c0 8 OBJECT GLOBAL DEFAULT 14 optarg + 1084: 0000000008008bbe 49 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1085: 00000000080615c8 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1086: 000000000804edcc 43 FUNC WEAK HIDDEN 2 _ZN10Relocation1[...] + 1087: 0000000008062744 66 FUNC GLOBAL DEFAULT 2 _ZN5mlibc20threa[...] + 1088: 000000000803e11b 82 FUNC GLOBAL DEFAULT 2 btowc + 1089: 00000000080145e2 30 FUNC WEAK DEFAULT 2 _ZNK3frg8expecte[...] + 1090: 00000000080613d2 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1091: 000000000805088a 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1092: 000000000801f324 476 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1093: 0000000008050348 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1094: 000000000800e00a 328 FUNC GLOBAL DEFAULT 2 vsnprintf + 1095: 0000000008002b10 43 FUNC GLOBAL DEFAULT 2 strtoll + 1096: 00000000080648ca 97 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 1097: 00000000080682e4 67 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIc[...] + 1098: 0000000008065ade 42 FUNC WEAK DEFAULT 2 _ZN3frg5_list19i[...] + 1099: 0000000008037b86 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1100: 0000000008057619 114 FUNC GLOBAL DEFAULT 2 pthread_rwlock_d[...] + 1101: 00000000080583ed 349 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1102: 0000000008037c56 1132 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1103: 0000000008067eb6 82 FUNC GLOBAL DEFAULT 2 open_memstream + 1104: 0000000008013538 80 FUNC WEAK DEFAULT 2 _ZN13ResizePrint[...] + 1105: 000000000806a30c 157 FUNC GLOBAL DEFAULT 2 timer_gettime + 1106: 000000000804085e 82 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 1107: 00000000080077a6 188 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1108: 0000000008061682 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1109: 00000000080288d2 61 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1110: 000000000806abee 315 FUNC GLOBAL DEFAULT 2 _ZN5mlibc18memst[...] + 1111: 00000000080581c5 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA5[...] + 1112: 0000000008062c3f 15 FUNC GLOBAL DEFAULT 2 _ZN5mlibc19threa[...] + 1113: 000000000806a57b 143 FUNC GLOBAL DEFAULT 2 tcdrain + 1114: 0000000008055506 33 FUNC GLOBAL DEFAULT 2 pthread_attr_get[...] + 1115: 000000000805230a 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 1116: 0000000008064988 20 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 1117: 0000000008060a5f 471 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13getop[...] + 1118: 00000000080595b5 56 FUNC GLOBAL DEFAULT 2 fexecve + 1119: 000000000803baea 57 FUNC GLOBAL DEFAULT 2 wcsncmp + 1120: 00000000080043b8 31 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 1121: 0000000008066597 102 FUNC GLOBAL DEFAULT 2 __fpclassifyf + 1122: 0000000008050a2e 72 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1123: 000000000800bb4c 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1124: 0000000008008ab7 211 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 1125: 00000000080569bb 32 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 1126: 00000000080392b8 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1127: 00000000080681e8 139 FUNC WEAK DEFAULT 2 _ZN5mlibc11cooki[...] + 1128: 0000000008002b3b 43 FUNC GLOBAL DEFAULT 2 strtoul + 1129: 000000000809b520 8 OBJECT GLOBAL HIDDEN 13 __dso_handle + 1130: 000000000805d59a 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1131: 000000000800b909 60 FUNC WEAK HIDDEN 2 _ZN3frg14generic[...] + 1132: 0000000008009e52 425 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1133: 000000000801792c 51 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1134: 000000000805e170 45 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 1135: 000000000803bd3d 53 FUNC GLOBAL DEFAULT 2 wcsstr + 1136: 000000000800e635 126 FUNC GLOBAL DEFAULT 2 wscanf + 1137: 000000000800a018 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1138: 0000000008056039 55 FUNC GLOBAL DEFAULT 2 pthread_testcancel + 1139: 0000000008067538 197 FUNC GLOBAL DEFAULT 2 splice + 1140: 000000000800cc83 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1141: 0000000008066a8c 394 FUNC GLOBAL DEFAULT 2 readdir_r + 1142: 000000000806611c 40 FUNC WEAK DEFAULT 2 _ZNK3frg5_list14[...] + 1143: 000000000805e8a4 31 FUNC WEAK DEFAULT 2 _ZN5mlibc8code_s[...] + 1144: 00000000080130fc 38 FUNC WEAK DEFAULT 2 _ZN13BufferPrint[...] + 1145: 0000000008043bfa 26 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 1146: 0000000008031d66 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1147: 00000000080199eb 1785 FUNC WEAK DEFAULT 2 _ZN3frg15do_prin[...] + 1148: 00000000080580f1 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1149: 00000000080032ed 49 FUNC GLOBAL DEFAULT 2 mktemp + 1150: 000000000806409c 79 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 1151: 00000000080616d6 20 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17Globa[...] + 1152: 000000000801f6aa 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1153: 000000000800ab7f 86 FUNC GLOBAL DEFAULT 2 ispunct + 1154: 000000000800790c 376 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1155: 00000000080677b8 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA4[...] + 1156: 0000000008017bc2 63 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1157: 0000000008069e9a 154 FUNC GLOBAL DEFAULT 2 settimeofday + 1158: 0000000008065ade 42 FUNC WEAK DEFAULT 2 _ZN3frg5_list19i[...] + 1159: 0000000008040850 14 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 1160: 0000000000000010 4 TLS GLOBAL DEFAULT 7 __mlibc_errno + 1161: 0000000008051caf 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRlEONS[...] + 1162: 00000000080456b8 436 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 1163: 0000000008043b04 18 FUNC WEAK HIDDEN 2 _ZN12ObjectSymbo[...] + 1164: 000000000802af58 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1165: 000000000805dc3e 63 FUNC WEAK DEFAULT 2 _ZN5mlibc20polym[...] + 1166: 000000000805d63a 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1167: 0000000008003a1c 52 FUNC GLOBAL DEFAULT 2 wctomb + 1168: 00000000080500dc 38 FUNC WEAK HIDDEN 2 _ZN3frg5stackIP1[...] + 1169: 0000000008060ce1 100 FUNC WEAK DEFAULT 2 _ZSt24__find_uni[...] + 1170: 0000000008057ea4 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1171: 000000000806ba22 68 FUNC WEAK DEFAULT 2 _ZN5mlibc17fmemo[...] + 1172: 0000000008050d04 82 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1173: 0000000008057acf 307 FUNC GLOBAL DEFAULT 2 pthread_rwlock_unlock + 1174: 000000000802c149 356 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1175: 000000000803f4f6 57 FUNC GLOBAL HIDDEN 2 _ZN5mlibc12sys_l[...] + 1176: 0000000008013004 72 FUNC WEAK DEFAULT 2 _ZN13StreamPrint[...] + 1177: 000000000809b568 4 OBJECT GLOBAL DEFAULT 13 opterr + 1178: 0000000008017890 73 FUNC WEAK DEFAULT 2 _ZN3frg8expected[...] + 1179: 0000000008068274 64 FUNC WEAK DEFAULT 2 _ZN10popen_fileC[...] + 1180: 000000000800cc75 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA3[...] + 1181: 000000000805abae 146 FUNC GLOBAL DEFAULT 2 rmdir + 1182: 0000000008051650 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1183: 00000000080501aa 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1184: 0000000008051c3c 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1185: 00000000080368c4 1135 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1186: 0000000008009246 31 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1187: 00000000080071c9 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1188: 0000000008003ba4 55 FUNC GLOBAL DEFAULT 2 wcstombs + 1189: 0000000008000d24 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1190: 0000000008044cda 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA5[...] + 1191: 00000000080409ce 55 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1192: 000000000801a0e4 125 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1193: 0000000008013588 22 FUNC WEAK DEFAULT 2 _ZN3frg9va_structC2Ev + 1194: 000000000805d6da 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1195: 000000000801376c 259 FUNC WEAK DEFAULT 2 _ZN13FutexLockIm[...] + 1196: 0000000008061860 100 FUNC GLOBAL DEFAULT 2 __mlibc_isless + 1197: 000000000804ee58 17 FUNC WEAK HIDDEN 2 _ZN12ObjectSymbo[...] + 1198: 000000000802aa36 221 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1199: 00000000080668fa 402 FUNC GLOBAL DEFAULT 2 readdir + 1200: 000000000803e10c 15 FUNC WEAK DEFAULT 2 _ZN5mlibc5widenI[...] + 1201: 0000000008000956 99 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1202: 0000000008057f7f 91 FUNC WEAK DEFAULT 2 _ZN3frg9construc[...] + 1203: 0000000008068495 38 FUNC WEAK DEFAULT 2 _ZN5mlibc15file_[...] + 1204: 000000000804f780 141 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1205: 000000000801c459 2864 FUNC WEAK DEFAULT 2 _ZN3frg14do_prin[...] + 1206: 000000000805a2a7 169 FUNC GLOBAL DEFAULT 2 lchown + 1207: 000000000800ca38 18 FUNC WEAK DEFAULT 2 _ZNK3frg6vectorI[...] + 1208: 00000000080069a4 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1209: 00000000080509e6 72 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1210: 000000000804554e 361 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 1211: 000000000806111e 45 FUNC WEAK DEFAULT 2 _ZSt17holds_alte[...] + 1212: 00000000080361f2 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1213: 0000000008052b78 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1214: 00000000080380c2 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1215: 0000000008023248 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1216: 000000000801cf8a 18 FUNC WEAK DEFAULT 2 _ZNK3frg8optiona[...] + 1217: 000000000806ba66 21 FUNC WEAK DEFAULT 2 _ZNK5mlibc17fmem[...] + 1218: 000000000806818d 90 FUNC GLOBAL DEFAULT 2 fopencookie + 1219: 0000000008032452 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1220: 000000000800cc2c 73 FUNC WEAK DEFAULT 2 _ZN3frg6formatIN[...] + 1221: 0000000008065d52 778 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 1222: 000000000800f5d7 22 FUNC GLOBAL DEFAULT 2 clearerr_unlocked + 1223: 0000000008000eac 63 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1224: 000000000806244c 290 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11threa[...] + 1225: 0000000008061260 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1226: 000000000804f0f4 31 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 1227: 000000000800ac81 86 FUNC GLOBAL DEFAULT 2 isspace + 1228: 00000000080555a1 32 FUNC GLOBAL DEFAULT 2 pthread_attr_get[...] + 1229: 000000000800e6e8 53 FUNC GLOBAL DEFAULT 2 vwscanf + 1230: 0000000008043fd6 121 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 1231: 00000000080635f4 47 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 1232: 000000000804b98c 360 FUNC GLOBAL HIDDEN 2 _ZN5Scope13resol[...] + 1233: 0000000008051712 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIPKc[...] + 1234: 00000000080139e8 3065 FUNC WEAK DEFAULT 2 _ZN3frg13printf_[...] + 1235: 0000000008055ca3 16 FUNC GLOBAL DEFAULT 2 __mlibc_do_cancel + 1236: 0000000008001c48 208 FUNC WEAK HIDDEN 2 _ZZN3frg11_fmt_b[...] + 1237: 000000000803ce63 52 FUNC GLOBAL DEFAULT 2 mempcpy + 1238: 000000000805f472 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1239: 0000000008008ba0 30 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1240: 0000000008062b87 31 FUNC GLOBAL DEFAULT 2 _ZN5mlibc24threa[...] + 1241: 0000000008051148 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1242: 0000000008044400 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1243: 000000000800170c 219 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1244: 000000000806865c 45 FUNC WEAK DEFAULT 2 _ZN5mlibc8mem_fi[...] + 1245: 0000000008065560 411 FUNC GLOBAL DEFAULT 2 fflush + 1246: 000000000804f114 27 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJi[...] + 1247: 0000000008043c14 109 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1248: 0000000008027e64 259 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 1249: 000000000800103f 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRjE[...] + 1250: 000000000803f1e8 82 FUNC WEAK DEFAULT 2 _ZN3frg7eternalI[...] + 1251: 0000000008000fad 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1252: 000000000805d67c 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA6[...] + 1253: 000000000803733c 349 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1254: 000000000809a4a0 88 OBJECT WEAK DEFAULT 12 _ZTVN5mlibc7fd_fileE + 1255: 000000000804f80e 101 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJi[...] + 1256: 00000000080664ec 14 FUNC WEAK DEFAULT 2 _ZN3frg11composi[...] + 1257: 0000000008058004 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1258: 0000000008021d3c 430 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1259: 000000000804ef12 17 FUNC WEAK HIDDEN 2 _ZNK13SymbolVers[...] + 1260: 00000000080596af 154 FUNC GLOBAL DEFAULT 2 ftruncate + 1261: 000000000806a8da 157 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11strnc[...] + 1262: 000000000805174a 176 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1263: 0000000008052c41 82 FUNC WEAK HIDDEN 2 _ZSt4swapIN3frg1[...] + 1264: 00000000080132b2 84 FUNC WEAK DEFAULT 2 _ZN14LimitedPrin[...] + 1265: 000000000805e9a4 189 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 1266: 00000000080443cc 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1267: 0000000008006bf5 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIPvE[...] + 1268: 000000000802c807 1900 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1269: 000000000806bc8a 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1270: 000000000805691d 32 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 1271: 00000000080386ba 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1272: 0000000008012ea6 42 FUNC WEAK DEFAULT 2 _ZN5mlibc9StdioL[...] + 1273: 00000000080350bc 1132 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1274: 000000000800ce5c 33 FUNC WEAK DEFAULT 2 _ZNK3frg6vectorI[...] + 1275: 00000000080532a8 114 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJK[...] + 1276: 0000000008005e3f 957 FUNC WEAK DEFAULT 2 _ZN5mlibc15strin[...] + 1277: 0000000008003a50 340 FUNC GLOBAL DEFAULT 2 mbstowcs + 1278: 000000000805dc31 13 FUNC GLOBAL DEFAULT 2 _ZN5mlibc22platf[...] + 1279: 000000000800c37e 26 FUNC GLOBAL DEFAULT 2 putenv + 1280: 000000000809c4e0 40 OBJECT GLOBAL HIDDEN 14 globalDebugInterface + 1281: 000000000803f2f0 42 FUNC WEAK DEFAULT 2 _ZN3frg6vectorI1[...] + 1282: 000000000805c249 84 FUNC GLOBAL DEFAULT 2 lseek + 1283: 00000000080614b4 59 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1284: 000000000803b97c 57 FUNC GLOBAL DEFAULT 2 wmemcpy + 1285: 0000000008027911 681 FUNC WEAK DEFAULT 2 _ZN3frg16do_prin[...] + 1286: 000000000805d84e 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA8[...] + 1287: 000000000805331a 109 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJK[...] + 1288: 0000000008061e7f 176 FUNC GLOBAL DEFAULT 2 sigaddset + 1289: 00000000080519d2 30 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 1290: 0000000008051ac7 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRN3[...] + 1291: 0000000008018614 2402 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1292: 0000000008006761 139 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1293: 000000000806baca 18 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIc[...] + 1294: 000000000802c38a 222 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1295: 00000000080130ae 77 FUNC WEAK DEFAULT 2 _ZN13StreamPrint[...] + 1296: 000000000800c5de 74 FUNC GLOBAL DEFAULT 2 clearenv + 1297: 00000000080081de 30 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1298: 000000000806b6d8 103 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11cooki[...] + 1299: 00000000080586c1 169 FUNC GLOBAL DEFAULT 2 chown + 1300: 000000000803d1b4 28 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 1301: 0000000008031056 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1302: 000000000800e57e 57 FUNC GLOBAL DEFAULT 2 vswscanf + 1303: 000000000800157d 398 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 1304: 00000000080693e8 45 FUNC GLOBAL DEFAULT 2 strncasecmp + 1305: 000000000804ec7c 100 FUNC WEAK HIDDEN 2 _ZN10RelocationC[...] + 1306: 00000000080408d0 37 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 1307: 0000000008002f8c 21 FUNC GLOBAL DEFAULT 2 _Exit + 1308: 000000000804ec7c 100 FUNC WEAK HIDDEN 2 _ZN10RelocationC[...] + 1309: 000000000804f4e2 53 FUNC WEAK HIDDEN 2 _ZNK3frg12basic_[...] + 1310: 0000000008065b08 431 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 1311: 000000000803e9f0 388 FUNC GLOBAL DEFAULT 2 wcsnrtombs + 1312: 000000000804ef48 113 FUNC WEAK HIDDEN 2 _ZNK13SymbolVers[...] + 1313: 0000000008063f64 221 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 1314: 00000000080011a6 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1315: 0000000008069470 40 FUNC GLOBAL DEFAULT 2 bzero + 1316: 000000000805aded 151 FUNC GLOBAL DEFAULT 2 setpgid + 1317: 0000000008021224 125 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1318: 00000000080078b8 84 FUNC WEAK HIDDEN 2 _ZN3frg11unique_[...] + 1319: 000000000805589d 104 FUNC GLOBAL DEFAULT 2 pthread_detach + 1320: 000000000809c2e8 8 OBJECT GLOBAL HIDDEN 14 entryStack + 1321: 0000000008060fa0 49 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 1322: 000000000805d02d 53 FUNC GLOBAL DEFAULT 2 getdomainname + 1323: 0000000008061bd4 100 FUNC GLOBAL DEFAULT 2 __mlibc_isgreater + 1324: 000000000800d70d 67 FUNC GLOBAL DEFAULT 2 setbuffer + 1325: 00000000080002d2 83 FUNC GLOBAL DEFAULT 2 __mlibc_entry + 1326: 0000000008061822 32 FUNC GLOBAL DEFAULT 2 ELF64_R_INFO + 1327: 0000000008055905 166 FUNC GLOBAL DEFAULT 2 pthread_cleanup_push + 1328: 000000000800ce0b 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA3[...] + 1329: 000000000800c818 77 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 1330: 000000000806114b 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIcEO[...] + 1331: 000000000802af91 1900 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1332: 0000000008002d72 407 FUNC GLOBAL DEFAULT 2 abort + 1333: 00000000080503ca 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1334: 0000000008066228 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1335: 000000000806aa06 29 FUNC GLOBAL DEFAULT 2 _ZN5mlibc8mem_fi[...] + 1336: 0000000008016d7a 80 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 1337: 0000000008055630 32 FUNC GLOBAL DEFAULT 2 pthread_attr_get[...] + 1338: 0000000008053100 68 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1339: 0000000008069322 30 FUNC GLOBAL DEFAULT 2 ffsl + 1340: 000000000802841c 267 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 1341: 000000000806320a 84 FUNC GLOBAL DEFAULT 2 __stack_chk_fail + 1342: 000000000803bab5 53 FUNC GLOBAL DEFAULT 2 wcscoll + 1343: 0000000008007bca 232 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1344: 00000000080514d8 117 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1345: 000000000801d2ae 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1346: 00000000080694c0 154 FUNC GLOBAL DEFAULT 2 chmod + 1347: 000000000802acc4 209 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1348: 0000000008035cc6 1110 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1349: 000000000804b5f2 62 FUNC GLOBAL HIDDEN 2 _ZN5ScopeC2Eb + 1350: 000000000800f5a2 53 FUNC GLOBAL DEFAULT 2 ftrylockfile + 1351: 0000000008069d6d 171 FUNC GLOBAL DEFAULT 2 fstat64 + 1352: 000000000800aad3 86 FUNC GLOBAL DEFAULT 2 isxdigit + 1353: 0000000008030382 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1354: 0000000008044b10 30 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 1355: 0000000008060c36 17 FUNC WEAK DEFAULT 2 _ZSt26__throw_ba[...] + 1356: 0000000008001458 74 FUNC WEAK DEFAULT 2 _ZN3frg13format_[...] + 1357: 0000000008000158 0 FUNC GLOBAL DEFAULT 1 _init + 1358: 00000000080445f0 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1359: 0000000008016b48 84 FUNC WEAK DEFAULT 2 _ZN3frg11unique_[...] + 1360: 000000000805854a 86 FUNC GLOBAL DEFAULT 2 alarm + 1361: 0000000008006b52 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 1362: 000000000806aa24 134 FUNC GLOBAL DEFAULT 2 _ZN5mlibc18memst[...] + 1363: 0000000008051dbe 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1364: 00000000080449af 14 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 1365: 000000000804480e 197 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1366: 000000000802868c 61 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1367: 0000000008058133 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1368: 0000000008025ff4 480 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1369: 0000000008061378 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1370: 000000000804f130 72 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1371: 0000000008043caa 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1372: 000000000803fc94 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1373: 0000000008029bf2 70 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1374: 00000000080405fc 282 FUNC GLOBAL HIDDEN 2 _Z12getAllocatorv + 1375: 0000000008055472 31 FUNC GLOBAL DEFAULT 2 pthread_attr_set[...] + 1376: 0000000008034fec 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1377: 0000000008002ae5 43 FUNC GLOBAL DEFAULT 2 strtol + 1378: 000000000805825f 398 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1379: 0000000008051092 18 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1380: 000000000806625c 34 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 1381: 00000000080029ad 64 FUNC GLOBAL DEFAULT 2 __sigsetjmp + 1382: 000000000805a7c1 151 FUNC GLOBAL DEFAULT 2 pipe + 1383: 000000000805130e 26 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 1384: 0000000008044b50 82 FUNC WEAK HIDDEN 2 _ZN3frg12small_v[...] + 1385: 000000000800efae 158 FUNC GLOBAL DEFAULT 2 fsetpos + 1386: 000000000800c866 67 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 1387: 0000000008017bb0 18 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1388: 00000000080613ac 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1389: 0000000008044e02 262 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIN[...] + 1390: 000000000801ed82 482 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1391: 000000000809b620 2500 OBJECT GLOBAL DEFAULT 14 __mlibc_rand_engine + 1392: 000000000805a219 16 FUNC GLOBAL DEFAULT 2 getpgrp + 1393: 000000000803f4db 26 FUNC GLOBAL DEFAULT 2 __tls_get_addr + 1394: 0000000008038268 1105 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1395: 0000000008068ad0 61 FUNC GLOBAL DEFAULT 2 strnlen + 1396: 000000000800ce19 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1397: 0000000008051c2e 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA1[...] + 1398: 000000000803b784 53 FUNC GLOBAL DEFAULT 2 wcstod + 1399: 0000000008068830 43 FUNC WEAK DEFAULT 2 _ZN5mlibc18memst[...] + 1400: 000000000800366b 265 FUNC GLOBAL DEFAULT 2 mblen + 1401: 0000000008006ab2 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA6[...] + 1402: 0000000008052bba 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1403: 0000000008002250 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1404: 000000000800b106 83 FUNC GLOBAL DEFAULT 2 iswprint + 1405: 0000000008027e3c 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1406: 0000000008028527 356 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1407: 00000000080647f6 212 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 1408: 00000000080616b6 31 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1409: 0000000008016ab4 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1410: 000000000803f390 317 FUNC WEAK DEFAULT 2 _ZN3frg6vectorI1[...] + 1411: 0000000008052d84 32 FUNC WEAK HIDDEN 2 _ZN3frg5arrayINS[...] + 1412: 0000000008055c0d 150 FUNC GLOBAL DEFAULT 2 pthread_getschedparam + 1413: 000000000803d17c 28 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 1414: 000000000801526c 42 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1415: 000000000806a467 47 FUNC GLOBAL DEFAULT 2 cfsetispeed + 1416: 0000000008040994 26 FUNC WEAK HIDDEN 2 _ZN3frg14slab_al[...] + 1417: 0000000008000a7a 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1418: 0000000008061db2 88 FUNC GLOBAL DEFAULT 2 __mlibc_isgreate[...] + 1419: 00000000080610c8 14 FUNC WEAK DEFAULT 2 _ZNRSt8__detail9[...] + 1420: 00000000080449db 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIR13[...] + 1421: 0000000008044614 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1422: 0000000008007cb2 123 FUNC WEAK DEFAULT 2 _ZN3frg9slab_poo[...] + 1423: 00000000080408f5 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIR16[...] + 1424: 000000000804dcb2 2305 FUNC GLOBAL HIDDEN 2 _ZN6Loader23_pro[...] + 1425: 0000000008054e07 189 FUNC GLOBAL DEFAULT 2 rint + 1426: 000000000801fbaa 423 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1427: 00000000080615c8 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1428: 000000000803f23a 14 FUNC WEAK DEFAULT 2 _ZN3frg7eternalI[...] + 1429: 00000000080043d7 86 FUNC WEAK DEFAULT 2 _ZN5mlibc12globa[...] + 1430: 000000000800d460 157 FUNC GLOBAL DEFAULT 2 rename + 1431: 0000000008004399 31 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 1432: 000000000803ffe6 214 FUNC WEAK HIDDEN 2 _ZZN3frg11_fmt_b[...] + 1433: 00000000080501d2 82 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1434: 000000000800c714 17 FUNC WEAK HIDDEN 2 _ZNK3frg17basic_[...] + 1435: 000000000805d3c6 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1436: 0000000008043be0 26 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJ1[...] + 1437: 000000000805e1ea 55 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 1438: 0000000008057fda 41 FUNC WEAK DEFAULT 2 _ZN3frg5guardI13[...] + 1439: 0000000008050856 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1440: 0000000008055f13 294 FUNC GLOBAL DEFAULT 2 pthread_setcance[...] + 1441: 00000000080534c8 0 FUNC GLOBAL HIDDEN 2 __mlibcTlsdescDynamic + 1442: 00000000080019d0 209 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 1443: 000000000803e6c0 438 FUNC GLOBAL DEFAULT 2 mbsnrtowcs + 1444: 000000000803b432 112 FUNC GLOBAL DEFAULT 2 strrchr + 1445: 00000000080534f1 0 NOTYPE GLOBAL HIDDEN 2 pltRelocateStub + 1446: 000000000801b66c 480 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1447: 000000000803b8cf 66 FUNC GLOBAL DEFAULT 2 wcscpy + 1448: 0000000008022096 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1449: 0000000008002cdc 150 FUNC GLOBAL DEFAULT 2 calloc + 1450: 000000000805144a 90 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1451: 000000000801d27a 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1452: 0000000008000e3e 21 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 1453: 0000000008061594 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1454: 0000000008044d6e 119 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 1455: 0000000008000c88 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1456: 0000000008052536 72 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 1457: 0000000008032522 1132 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1458: 000000000804425c 72 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 1459: 000000000805d392 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1460: 00000000080502d0 18 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 1461: 0000000008051954 112 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 1462: 000000000800671e 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1463: 0000000008052c93 82 FUNC WEAK HIDDEN 2 _ZSt4swapImENSt9[...] + 1464: 000000000802dcde 211 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1465: 000000000806aadc 274 FUNC GLOBAL DEFAULT 2 _ZN5mlibc18memst[...] + 1466: 0000000008001aa1 209 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1467: 0000000008002a76 37 FUNC GLOBAL DEFAULT 2 strtod + 1468: 0000000008046d6c 2255 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 1469: 000000000806a9e8 29 FUNC GLOBAL DEFAULT 2 _ZN5mlibc8mem_fi[...] + 1470: 00000000080692e8 34 FUNC GLOBAL DEFAULT 2 rindex + 1471: 0000000008004020 463 FUNC WEAK DEFAULT 2 _ZN3frg7mt19937clEv + 1472: 0000000008065cb8 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1473: 0000000008058f3e 1008 FUNC GLOBAL DEFAULT 2 execvpe + 1474: 000000000804efba 17 FUNC WEAK HIDDEN 2 _ZNK13SymbolVers[...] + 1475: 000000000805094a 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1476: 00000000080613f8 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1477: 0000000008066421 71 FUNC WEAK DEFAULT 2 _ZN3frg8destruct[...] + 1478: 0000000008018f76 63 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1479: 0000000008057f2c 83 FUNC WEAK DEFAULT 2 _ZN3frg9construc[...] + 1480: 0000000008000a12 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1481: 000000000806be4c 45 FUNC WEAK DEFAULT 2 _ZN5mlibc11cooki[...] + 1482: 0000000008066326 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1483: 0000000008060fa0 49 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 1484: 0000000008056cb1 41 FUNC GLOBAL DEFAULT 2 pthread_condattr[...] + 1485: 00000000080613d2 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1486: 000000000805c19d 86 FUNC GLOBAL DEFAULT 2 write + 1487: 0000000008055565 60 FUNC GLOBAL DEFAULT 2 pthread_attr_setscope + 1488: 000000000802913c 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1489: 0000000008003f50 32 FUNC WEAK DEFAULT 2 _ZN3frg7mt19937C2Ev + 1490: 000000000803bdab 102 FUNC GLOBAL DEFAULT 2 wmemchr + 1491: 000000000800a506 208 FUNC WEAK HIDDEN 2 _ZZN3frg11_fmt_b[...] + 1492: 00000000080449ea 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1493: 0000000008061626 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1494: 0000000008013954 39 FUNC WEAK DEFAULT 2 _ZN3frg11unique_[...] + 1495: 0000000008038e5c 1116 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1496: 00000000080687f0 63 FUNC WEAK DEFAULT 2 _ZN5mlibc18memst[...] + 1497: 0000000008069141 112 FUNC GLOBAL DEFAULT 2 strerror_l + 1498: 0000000008009808 1135 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 1499: 0000000008002922 31 FUNC GLOBAL DEFAULT 2 atof + 1500: 000000000802f238 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1501: 00000000080408d0 37 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 1502: 0000000008058215 74 FUNC WEAK DEFAULT 2 _ZN3frg13format_[...] + 1503: 000000000809a740 8 OBJECT GLOBAL DEFAULT 13 environ + 1504: 000000000805331a 109 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJK[...] + 1505: 0000000008027bba 62 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1506: 000000000804085e 82 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 1507: 0000000008063267 44 FUNC GLOBAL HIDDEN 2 _ZdlPvj + 1508: 00000000080219ca 453 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1509: 0000000008068567 38 FUNC WEAK DEFAULT 2 _ZN5mlibc15file_[...] + 1510: 0000000008069d6d 171 FUNC GLOBAL DEFAULT 2 fstat + 1511: 000000000806132c 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1512: 0000000008059526 143 FUNC GLOBAL DEFAULT 2 fdatasync + 1513: 0000000008028ed8 61 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1514: 000000000800d750 180 FUNC GLOBAL DEFAULT 2 fprintf + 1515: 000000000803f86c 46 FUNC WEAK HIDDEN 2 _Z7syscallIiEllT_ + 1516: 00000000080610ab 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRNS[...] + 1517: 000000000804a32e 282 FUNC GLOBAL HIDDEN 2 _Z14initTlsObjec[...] + 1518: 000000000800e88e 103 FUNC GLOBAL DEFAULT 2 fputs_unlocked + 1519: 000000000800b00d 83 FUNC GLOBAL DEFAULT 2 iswgraph + 1520: 00000000080131c6 100 FUNC WEAK DEFAULT 2 _ZN13BufferPrint[...] + 1521: 000000000800ccc6 42 FUNC WEAK HIDDEN 2 _ZN3frg17basic_s[...] + 1522: 000000000806930a 24 FUNC GLOBAL DEFAULT 2 ffs + 1523: 0000000008040716 87 FUNC GLOBAL HIDDEN 2 _ZN16VirtualAllo[...] + 1524: 000000000800849e 172 FUNC WEAK HIDDEN 2 _ZN13FutexLockIm[...] + 1525: 00000000080662ca 26 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 1526: 0000000008050dfc 77 FUNC WEAK HIDDEN 2 _ZN3frg6vectorI1[...] + 1527: 000000000803b000 56 FUNC GLOBAL DEFAULT 2 strcat + 1528: 00000000080005f5 303 FUNC GLOBAL DEFAULT 2 __ensure_warn + 1529: 00000000080677c6 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1530: 000000000805047c 81 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1531: 000000000809a600 104 OBJECT WEAK DEFAULT 12 _ZTVN5mlibc17fme[...] + 1532: 0000000008051e4c 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA3[...] + 1533: 000000000800eda3 52 FUNC GLOBAL DEFAULT 2 putwc + 1534: 00000000080445f0 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1535: 0000000008013356 46 FUNC WEAK DEFAULT 2 _ZN13ResizePrint[...] + 1536: 000000000800d09b 78 FUNC WEAK DEFAULT 2 _ZN3frg6formatIj[...] + 1537: 0000000008060dcb 34 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1538: 0000000008044ce8 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1539: 000000000805f0b4 189 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 1540: 0000000008028f16 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1541: 0000000008028282 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1542: 0000000008002be5 53 FUNC GLOBAL DEFAULT 2 rand_r + 1543: 000000000804ee1c 59 FUNC WEAK HIDDEN 2 _ZN10Relocation8[...] + 1544: 0000000008022d48 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1545: 00000000080503fe 73 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 1546: 000000000805bd43 160 FUNC GLOBAL DEFAULT 2 unlinkat + 1547: 00000000080528f7 14 FUNC WEAK HIDDEN 2 _ZSt7forwardI13S[...] + 1548: 000000000805bb2a 53 FUNC GLOBAL DEFAULT 2 truncate64 + 1549: 000000000800dfa6 47 FUNC GLOBAL DEFAULT 2 vprintf + 1550: 000000000804194b 7 FUNC GLOBAL DEFAULT 2 _dl_debug_state + 1551: 0000000008016af6 81 FUNC WEAK DEFAULT 2 _ZN3frg11unique_[...] + 1552: 0000000008028282 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1553: 000000000805e1ca 31 FUNC WEAK DEFAULT 2 _ZN5mlibc8code_s[...] + 1554: 000000000800122d 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1555: 000000000804fe52 51 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1556: 0000000008043d60 26 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 1557: 000000000803f8f9 53 FUNC WEAK HIDDEN 2 _Z7syscallImmEllT_T0_ + 1558: 0000000008030458 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1559: 000000000806991c 37 FUNC GLOBAL DEFAULT 2 mkfifo + 1560: 0000000008043b84 47 FUNC WEAK HIDDEN 2 _ZN6LoaderD2Ev + 1561: 0000000008068327 38 FUNC WEAK DEFAULT 2 _ZN5mlibc15file_[...] + 1562: 0000000008066529 110 FUNC GLOBAL DEFAULT 2 __fpclassify + 1563: 000000000803f52f 29 FUNC GLOBAL HIDDEN 2 _ZN5mlibc14sys_l[...] + 1564: 0000000008035528 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1565: 000000000805f4b4 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1566: 0000000008056ec8 72 FUNC GLOBAL DEFAULT 2 pthread_cond_bro[...] + 1567: 0000000008052fff 101 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 1568: 00000000080566d7 367 FUNC GLOBAL DEFAULT 2 pthread_once + 1569: 0000000008028b22 62 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1570: 000000000809c2e0 1 OBJECT GLOBAL HIDDEN 14 _ZN5mlibc18tcb_a[...] + 1571: 00000000080282aa 267 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 1572: 000000000805dcc0 405 FUNC WEAK DEFAULT 2 _ZN5mlibc13utf8_[...] + 1573: 000000000801f144 480 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1574: 00000000080585a0 146 FUNC GLOBAL DEFAULT 2 chdir + 1575: 0000000008053100 68 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1576: 0000000008050396 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1577: 000000000800e445 126 FUNC GLOBAL DEFAULT 2 swprintf + 1578: 00000000080555c1 47 FUNC GLOBAL DEFAULT 2 pthread_attr_set[...] + 1579: 00000000080258de 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1580: 00000000080280d2 61 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1581: 0000000008013498 76 FUNC WEAK DEFAULT 2 _ZN13ResizePrint[...] + 1582: 00000000080612e0 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1583: 000000000806499c 159 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 1584: 0000000008067f08 114 FUNC GLOBAL DEFAULT 2 fseeko + 1585: 0000000008040800 79 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 1586: 000000000805ae99 151 FUNC GLOBAL DEFAULT 2 setregid + 1587: 0000000008018fee 2402 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1588: 000000000800cc1e 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIN3f[...] + 1589: 000000000800cb1c 178 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 1590: 0000000008067348 165 FUNC GLOBAL DEFAULT 2 posix_fadvise + 1591: 000000000804b82e 349 FUNC GLOBAL HIDDEN 2 _ZN5Scope24resol[...] + 1592: 0000000008048c0e 1139 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 1593: 00000000080539a4 299 FUNC GLOBAL DEFAULT 2 modf + 1594: 0000000008051d6e 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIN[...] + 1595: 00000000080442a4 67 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 1596: 0000000008022242 424 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1597: 000000000805037c 26 FUNC WEAK HIDDEN 2 _ZN3frg7hex_fmtI[...] + 1598: 0000000008050136 27 FUNC WEAK HIDDEN 2 _ZN3frg5stackIP1[...] + 1599: 0000000008014648 42 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1600: 000000000804258f 1470 FUNC GLOBAL DEFAULT 2 __dlapi_resolve + 1601: 00000000080652ee 156 FUNC GLOBAL DEFAULT 2 fseek + 1602: 0000000008044c2c 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1603: 000000000804f8c2 18 FUNC WEAK HIDDEN 2 _ZNK3frg12small_[...] + 1604: 0000000008016d7a 80 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 1605: 000000000805e222 336 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 1606: 0000000008028110 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1607: 0000000008027f68 61 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1608: 000000000802673a 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1609: 0000000008055b7a 147 FUNC GLOBAL DEFAULT 2 pthread_setschedparam + 1610: 000000000805cebf 52 FUNC GLOBAL DEFAULT 2 ctermid + 1611: 0000000008027fa6 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1612: 0000000008052996 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1613: 0000000008045349 39 FUNC GLOBAL HIDDEN 2 _Z7alignUpmm + 1614: 00000000080407c6 44 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 1615: 000000000800a0b8 67 FUNC WEAK HIDDEN 2 _ZN3frg6formatIi[...] + 1616: 000000000802d136 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1617: 000000000804f3d0 122 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 1618: 000000000800a0aa 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRiE[...] + 1619: 0000000008051a38 61 FUNC WEAK HIDDEN 2 _ZN3frg12small_v[...] + 1620: 000000000802af58 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1621: 000000000801f500 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1622: 000000000804f2de 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRN3frg[...] + 1623: 000000000806be3e 14 FUNC WEAK DEFAULT 2 _ZSt4moveIRcEONS[...] + 1624: 00000000080509b2 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1625: 000000000800f145 572 FUNC GLOBAL DEFAULT 2 getdelim + 1626: 000000000805242e 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 1627: 000000000805d2d4 34 FUNC WEAK DEFAULT 2 _ZN3frg17basic_s[...] + 1628: 0000000008044638 109 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1629: 000000000800854a 100 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1630: 0000000008064cca 88 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 1631: 000000000803f342 77 FUNC WEAK DEFAULT 2 _ZN3frg6vectorI1[...] + 1632: 00000000080042f2 16 FUNC WEAK DEFAULT 2 _ZN5mlibc10int_l[...] + 1633: 000000000806a496 103 FUNC GLOBAL DEFAULT 2 cfsetospeed + 1634: 00000000080690a3 60 FUNC GLOBAL DEFAULT 2 memccpy + 1635: 0000000008001b72 214 FUNC WEAK HIDDEN 2 _ZZN3frg11_fmt_b[...] + 1636: 000000000805239c 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1637: 000000000803eee4 284 FUNC WEAK DEFAULT 2 _ZN5mlibc20polym[...] + 1638: 0000000008000fef 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 1639: 000000000805161c 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1640: 00000000080641e6 298 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 1641: 000000000802abf1 211 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1642: 0000000008056f48 46 FUNC GLOBAL DEFAULT 2 pthread_barriera[...] + 1643: 000000000809a4f8 88 OBJECT WEAK DEFAULT 12 _ZTVN5mlibc13abs[...] + 1644: 000000000809b564 4 OBJECT GLOBAL DEFAULT 13 optind + 1645: 000000000803b7ee 53 FUNC GLOBAL DEFAULT 2 wcstold + 1646: 000000000804aaa4 247 FUNC GLOBAL HIDDEN 2 _ZN12ObjectSymbo[...] + 1647: 000000000802f778 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1648: 000000000805625d 268 FUNC GLOBAL DEFAULT 2 pthread_key_create + 1649: 000000000803b295 89 FUNC GLOBAL DEFAULT 2 memchr + 1650: 000000000801f6aa 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1651: 00000000080017e7 398 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1652: 0000000008050a76 270 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1653: 0000000008007f38 30 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1654: 0000000008000d8c 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1655: 000000000801b2aa 479 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1656: 0000000008017960 65 FUNC WEAK DEFAULT 2 _ZN3frg12basic_s[...] + 1657: 000000000803f7f6 15 FUNC GLOBAL HIDDEN 2 _ZN5mlibc14sys_f[...] + 1658: 000000000804412c 123 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 1659: 0000000008000eac 63 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1660: 0000000008052f7b 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRKt[...] + 1661: 0000000008051cd9 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1662: 000000000809b578 8 OBJECT GLOBAL DEFAULT 13 stdin + 1663: 000000000801315e 104 FUNC WEAK DEFAULT 2 _ZN13BufferPrint[...] + 1664: 0000000008033658 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1665: 000000000804f44a 152 FUNC WEAK HIDDEN 2 _ZN3frg17basic_s[...] + 1666: 000000000803d1d0 28 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 1667: 0000000008051582 32 FUNC WEAK HIDDEN 2 _ZNK3frg6vectorI[...] + 1668: 000000000803f7a9 77 FUNC GLOBAL HIDDEN 2 _ZN5mlibc8sys_op[...] + 1669: 000000000802a8d2 356 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1670: 0000000008067784 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1671: 000000000801bdb2 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1672: 000000000800c7a0 119 FUNC WEAK HIDDEN 2 _ZNK3frg17basic_[...] + 1673: 0000000008044398 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1674: 0000000008069ab5 148 FUNC GLOBAL DEFAULT 2 umask + 1675: 0000000008066c48 626 FUNC GLOBAL DEFAULT 2 scandir + 1676: 0000000008069f34 130 FUNC GLOBAL DEFAULT 2 timeradd + 1677: 000000000803a1c4 365 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1678: 0000000008040a52 31 FUNC GLOBAL HIDDEN 2 _ZN5mlibc8InfoSi[...] + 1679: 0000000008069340 30 FUNC GLOBAL DEFAULT 2 ffsll + 1680: 000000000803097e 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1681: 0000000008043221 27 FUNC GLOBAL DEFAULT 2 __dlapi_enter + 1682: 000000000806118e 51 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 1683: 0000000008067fe3 177 FUNC GLOBAL DEFAULT 2 dprintf + 1684: 000000000805243c 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1685: 000000000805d2a0 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1686: 00000000080027aa 188 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1687: 000000000805174a 176 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1688: 0000000008061286 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1689: 0000000008022d48 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1690: 0000000008040a3c 22 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1691: 000000000805efd2 225 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 1692: 00000000080409ae 32 FUNC WEAK HIDDEN 2 _ZN13FutexLockIm[...] + 1693: 000000000805f4a6 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA7[...] + 1694: 0000000008008942 318 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1695: 0000000008056f10 25 FUNC GLOBAL DEFAULT 2 pthread_barriera[...] + 1696: 0000000008050fb2 68 FUNC WEAK HIDDEN 2 _ZNK3frg8hash_ma[...] + 1697: 000000000800217a 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1698: 000000000805e864 31 FUNC WEAK DEFAULT 2 _ZN5mlibc8code_s[...] + 1699: 000000000809c070 8 OBJECT WEAK DEFAULT 14 __progname + 1700: 000000000806903c 103 FUNC GLOBAL DEFAULT 2 strcasestr + 1701: 0000000008000170 0 FUNC GLOBAL DEFAULT 2 _start + 1702: 000000000805137c 117 FUNC WEAK HIDDEN 2 _ZN3frg11constru[...] + 1703: 0000000008064310 133 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 1704: 0000000008069cc1 172 FUNC GLOBAL DEFAULT 2 lstat + 1705: 00000000080407f2 14 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 1706: 000000000802a768 71 FUNC WEAK DEFAULT 2 _ZN3frg6formatIc[...] + 1707: 000000000803fc86 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA4[...] + 1708: 00000000080286ca 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1709: 000000000800f076 20 FUNC GLOBAL DEFAULT 2 ferror + 1710: 000000000803b50f 176 FUNC GLOBAL DEFAULT 2 strstr + 1711: 0000000008052295 117 FUNC WEAK HIDDEN 2 _ZN3frg9construc[...] + 1712: 000000000806b14a 64 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17fmemo[...] + 1713: 000000000800bbc2 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1714: 000000000802ff30 1105 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1715: 0000000008065a56 38 FUNC WEAK DEFAULT 2 _ZN5mlibc9StdioL[...] + 1716: 0000000008007a84 81 FUNC WEAK HIDDEN 2 _ZN3frg11unique_[...] + 1717: 0000000008038860 1110 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1718: 000000000800ccf0 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRN3frg[...] + 1719: 000000000806141e 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1720: 000000000806b7a8 98 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11cooki[...] + 1721: 0000000008061b06 106 FUNC GLOBAL DEFAULT 2 __mlibc_islessgr[...] + 1722: 0000000008002b91 26 FUNC GLOBAL DEFAULT 2 rand + 1723: 00000000080502fc 75 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 1724: 000000000803fb34 113 FUNC GLOBAL HIDDEN 2 __cxa_pure_virtual + 1725: 0000000008067f7a 105 FUNC GLOBAL DEFAULT 2 ftello + 1726: 0000000008044334 99 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 1727: 0000000008007628 217 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1728: 0000000008008a80 55 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1729: 00000000080532a8 114 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJK[...] + 1730: 000000000805ad5e 143 FUNC GLOBAL DEFAULT 2 setgid + 1731: 0000000008050d56 165 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1732: 0000000008007734 39 FUNC WEAK HIDDEN 2 _ZN3frg11unique_[...] + 1733: 000000000803611c 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1734: 000000000800d0ff 226 FUNC GLOBAL DEFAULT 2 signal + 1735: 000000000801a4f6 457 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1736: 0000000008061214 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1737: 000000000805c1f3 86 FUNC GLOBAL DEFAULT 2 read + 1738: 0000000008027d2b 211 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1739: 0000000008041f9f 30 FUNC GLOBAL DEFAULT 2 __dlapi_exit + 1740: 00000000080666db 16 FUNC GLOBAL DEFAULT 2 dirfd + 1741: 0000000008044526 73 FUNC WEAK HIDDEN 2 _ZNK3frg8expecte[...] + 1742: 0000000008007d2e 100 FUNC WEAK DEFAULT 2 _ZN3frg9slab_poo[...] + 1743: 000000000809c508 8 OBJECT GLOBAL HIDDEN 14 lastError + 1744: 00000000080688fe 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIR25[...] + 1745: 00000000080446a6 232 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1746: 0000000008050186 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1747: 000000000804f74c 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1748: 000000000805bfc6 178 FUNC GLOBAL DEFAULT 2 get_current_dir_name + 1749: 0000000008000e92 26 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1750: 0000000008043c82 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1751: 000000000809c3a0 48 OBJECT GLOBAL HIDDEN 14 globalScope + 1752: 000000000801397c 42 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1753: 000000000805a8f2 177 FUNC GLOBAL DEFAULT 2 pread64 + 1754: 0000000008017b7a 18 FUNC WEAK DEFAULT 2 _ZNK3frg12basic_[...] + 1755: 0000000008044434 209 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 1756: 0000000008055420 48 FUNC GLOBAL DEFAULT 2 pthread_attr_set[...] + 1757: 000000000803fd83 400 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 1758: 00000000080225ca 482 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1759: 0000000008016c7a 255 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 1760: 000000000804f0d8 27 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 1761: 00000000080691b1 157 FUNC GLOBAL DEFAULT 2 strlcpy + 1762: 000000000805c0d9 196 FUNC GLOBAL DEFAULT 2 getentropy + 1763: 000000000800b63d 396 FUNC GLOBAL DEFAULT 2 iswctype + 1764: 000000000803b19e 37 FUNC GLOBAL DEFAULT 2 strcoll + 1765: 000000000803fc52 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1766: 0000000008064b3c 104 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 1767: 000000000800ad83 86 FUNC GLOBAL DEFAULT 2 isupper + 1768: 0000000008040970 22 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 1769: 0000000008015e90 42 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1770: 000000000801e9fa 424 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1771: 0000000008061800 18 FUNC GLOBAL DEFAULT 2 ELF64_R_SYM + 1772: 000000000803b1c3 135 FUNC GLOBAL DEFAULT 2 strncmp + 1773: 00000000080362c2 1116 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1774: 000000000801a6c0 457 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1775: 0000000008067001 139 FUNC GLOBAL DEFAULT 2 fallocate + 1776: 000000000804ed82 74 FUNC WEAK HIDDEN 2 _ZN10Relocation1[...] + 1777: 000000000802c468 211 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1778: 000000000804aa0a 42 FUNC GLOBAL HIDDEN 2 _ZN12ObjectSymbo[...] + 1779: 00000000080178ea 65 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1780: 000000000803e876 378 FUNC GLOBAL DEFAULT 2 wcsrtombs + 1781: 0000000008005040 1473 FUNC WEAK DEFAULT 2 _ZN5mlibc7strtof[...] + 1782: 000000000804fd8a 200 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1783: 0000000008066688 51 FUNC GLOBAL DEFAULT 2 alphasort + 1784: 000000000800bc04 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 1785: 0000000008002866 188 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1786: 000000000805cba7 164 FUNC GLOBAL DEFAULT 2 getusershell + 1787: 000000000801359e 461 FUNC WEAK DEFAULT 2 _ZN13FutexLockIm[...] + 1788: 0000000008008a80 55 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1789: 000000000805777d 408 FUNC GLOBAL DEFAULT 2 pthread_rwlock_wrlock + 1790: 000000000801a88a 453 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1791: 000000000805a066 157 FUNC GLOBAL DEFAULT 2 sethostname + 1792: 0000000008057540 31 FUNC GLOBAL DEFAULT 2 pthread_rwlockat[...] + 1793: 000000000804abb2 180 FUNC GLOBAL HIDDEN 2 _ZN12ObjectSymbo[...] + 1794: 000000000805d566 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1795: 0000000008066f20 51 FUNC GLOBAL DEFAULT 2 versionsort + 1796: 0000000008061560 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1797: 000000000800a00a 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA3[...] + 1798: 000000000803be40 70 FUNC GLOBAL DEFAULT 2 wmemset + 1799: 0000000008042bcb 1268 FUNC GLOBAL DEFAULT 2 __dlapi_reverse + 1800: 000000000806bb7b 43 FUNC WEAK DEFAULT 2 _ZSt3minImERKT_S2_S2_ + 1801: 000000000805ae84 21 FUNC GLOBAL DEFAULT 2 setpgrp + 1802: 00000000080347a2 349 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1803: 0000000008060f18 35 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 1804: 0000000008025732 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1805: 000000000806152c 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1806: 0000000008053acf 4920 FUNC GLOBAL DEFAULT 2 pow + 1807: 000000000806165a 40 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1808: 0000000008063293 44 FUNC GLOBAL HIDDEN 2 _ZdlPvm + 1809: 000000000802b8c0 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1810: 00000000080283b6 62 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1811: 000000000803af79 135 FUNC GLOBAL DEFAULT 2 strncpy + 1812: 000000000800437a 31 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 1813: 000000000805bca7 156 FUNC GLOBAL DEFAULT 2 unlink + 1814: 000000000805b2cf 63 FUNC GLOBAL DEFAULT 2 sync + 1815: 000000000803f9b1 40 FUNC GLOBAL HIDDEN 2 __do_syscall3 + 1816: 000000000800c398 520 FUNC GLOBAL DEFAULT 2 setenv + 1817: 00000000080408be 18 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 1818: 000000000803d1ec 1017 FUNC WEAK DEFAULT 2 _ZN5mlibc15strin[...] + 1819: 000000000800720c 406 FUNC WEAK DEFAULT 2 _ZN3frg9slab_poo[...] + 1820: 000000000800435b 31 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 1821: 000000000806aaaa 49 FUNC GLOBAL DEFAULT 2 _ZN5mlibc18memst[...] + 1822: 000000000809c070 8 OBJECT GLOBAL DEFAULT 14 program_invocati[...] + 1823: 0000000008026a90 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1824: 000000000806935e 138 FUNC GLOBAL DEFAULT 2 strcasecmp + 1825: 0000000008064d7a 72 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 1826: 000000000804feca 259 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1827: 0000000008028f16 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1828: 0000000008025048 457 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1829: 0000000008053624 896 FUNC GLOBAL DEFAULT 2 log10 + 1830: 00000000080688b7 71 FUNC WEAK DEFAULT 2 _ZN3frg8destruct[...] + 1831: 000000000804ec6c 16 FUNC WEAK HIDDEN 2 _ZNK3frg4hashIjEclEi + 1832: 0000000008052842 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1833: 000000000806bcbe 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1834: 000000000804699c 42 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 1835: 0000000008025a8a 424 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1836: 000000000800f571 49 FUNC GLOBAL DEFAULT 2 funlockfile + 1837: 00000000080134e4 84 FUNC WEAK DEFAULT 2 _ZN13ResizePrint[...] + 1838: 000000000803ec20 212 FUNC GLOBAL DEFAULT 2 wcwidth + 1839: 000000000806870f 64 FUNC WEAK DEFAULT 2 _ZN3frg8destruct[...] + 1840: 0000000008015e90 42 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1841: 000000000800ae24 74 FUNC GLOBAL DEFAULT 2 isascii + 1842: 0000000008001336 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1843: 0000000008028244 62 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1844: 0000000008003d7b 226 FUNC GLOBAL DEFAULT 2 realloc + 1845: 0000000008068750 45 FUNC WEAK DEFAULT 2 _ZN10popen_fileD1Ev + 1846: 0000000008039a74 1122 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1847: 000000000804861a 1524 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 1848: 000000000803f145 22 FUNC GLOBAL DEFAULT 2 _Z22__mlibc_do_d[...] + 1849: 000000000800b8ba 79 FUNC GLOBAL DEFAULT 2 towupper + 1850: 0000000008026c3a 423 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1851: 00000000080663c8 45 FUNC WEAK DEFAULT 2 _ZN5mlibc7fd_fileD2Ev + 1852: 000000000806b42c 446 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17fmemo[...] + 1853: 0000000008041f92 13 FUNC GLOBAL DEFAULT 2 __dlapi_get_config + 1854: 0000000008050622 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1855: 000000000805ee3a 189 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 1856: 000000000803f066 74 FUNC GLOBAL DEFAULT 2 __cxa_atexit + 1857: 0000000008062b24 58 FUNC GLOBAL DEFAULT 2 _ZN5mlibc21threa[...] + 1858: 0000000008066468 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRFv[...] + 1859: 000000000802309e 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1860: 000000000800c726 18 FUNC WEAK HIDDEN 2 _ZNK3frg17basic_[...] + 1861: 000000000800664e 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1862: 0000000008061a96 112 FUNC GLOBAL DEFAULT 2 __mlibc_islessgreater + 1863: 00000000080442e8 75 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 1864: 000000000802c7ce 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1865: 000000000801ef64 480 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1866: 0000000008051cbd 14 FUNC WEAK HIDDEN 2 _ZSt7launderIlEPT_S1_ + 1867: 00000000080501aa 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1868: 000000000800ca4a 82 FUNC WEAK HIDDEN 2 _ZSt4swapIPcENSt[...] + 1869: 00000000080019be 18 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 1870: 00000000080010ee 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 1871: 0000000008017b9e 18 FUNC WEAK HIDDEN 2 _ZNK3frg12basic_[...] + 1872: 00000000080668fa 402 FUNC GLOBAL DEFAULT 2 readdir64 + 1873: 0000000008060e8d 34 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1874: 0000000008033c5a 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1875: 000000000801304c 97 FUNC WEAK DEFAULT 2 _ZN13StreamPrint[...] + 1876: 0000000008050e4a 67 FUNC WEAK HIDDEN 2 _ZN3frg6vectorI1[...] + 1877: 0000000008040a2d 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRN3frg[...] + 1878: 0000000008007ad6 244 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 1879: 000000000800142e 42 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 1880: 0000000008056d8e 83 FUNC GLOBAL DEFAULT 2 pthread_cond_init + 1881: 0000000008029d92 449 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1882: 0000000008069442 46 FUNC GLOBAL DEFAULT 2 bcopy + 1883: 0000000008040904 108 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 1884: 000000000803eeaf 53 FUNC GLOBAL DEFAULT 2 wcsnlen + 1885: 000000000804f2b8 38 FUNC WEAK HIDDEN 2 _ZN3frg5stackIP1[...] + 1886: 000000000806be4c 45 FUNC WEAK DEFAULT 2 _ZN5mlibc11cooki[...] + 1887: 000000000803b6fc 44 FUNC GLOBAL DEFAULT 2 strtok + 1888: 0000000008038d8c 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1889: 0000000008061204 15 FUNC WEAK DEFAULT 2 _ZNKSt8__detail9[...] + 1890: 0000000008061e56 41 FUNC GLOBAL DEFAULT 2 sigfillset + 1891: 0000000008002f32 49 FUNC GLOBAL DEFAULT 2 at_quick_exit + 1892: 000000000803b0ba 114 FUNC GLOBAL DEFAULT 2 memcmp + 1893: 000000000800092e 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1894: 00000000080066b6 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 1895: 00000000080673ed 99 FUNC GLOBAL DEFAULT 2 posix_fallocate + 1896: 0000000008043caa 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1897: 0000000008061214 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1898: 000000000804f5d0 245 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1899: 000000000806bdfc 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1900: 000000000801a32a 459 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1901: 000000000804f718 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1902: 0000000008001130 38 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1903: 000000000806bba6 17 FUNC WEAK DEFAULT 2 _ZNK3frg4spanIcE[...] + 1904: 000000000804f114 27 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJi[...] + 1905: 0000000008057527 25 FUNC GLOBAL DEFAULT 2 pthread_rwlockat[...] + 1906: 000000000803a4d8 1105 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1907: 000000000806b80a 323 FUNC GLOBAL DEFAULT 2 fdopen + 1908: 0000000008003f50 32 FUNC WEAK DEFAULT 2 _ZN3frg7mt19937C1Ev + 1909: 0000000008066476 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 1910: 0000000008061378 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1911: 0000000008044506 31 FUNC WEAK HIDDEN 2 _ZNK3frg8expecte[...] + 1912: 0000000008069498 40 FUNC GLOBAL DEFAULT 2 explicit_bzero + 1913: 000000000805c577 294 FUNC GLOBAL DEFAULT 2 fork + 1914: 00000000080506be 148 FUNC WEAK HIDDEN 2 _ZN3frg6vectorI1[...] + 1915: 0000000008065a7c 52 FUNC WEAK DEFAULT 2 _ZN3frg7eternalI[...] + 1916: 000000000800dc6d 180 FUNC GLOBAL DEFAULT 2 sscanf + 1917: 000000000805037c 26 FUNC WEAK HIDDEN 2 _ZN3frg7hex_fmtI[...] + 1918: 0000000008061a3e 88 FUNC GLOBAL DEFAULT 2 __mlibc_islessequall + 1919: 0000000008058ee0 47 FUNC GLOBAL DEFAULT 2 execv + 1920: 000000000801792c 51 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 1921: 0000000008041fbd 1490 FUNC GLOBAL DEFAULT 2 __dlapi_open + 1922: 0000000008060eaf 34 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1923: 00000000080514d8 117 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1924: 000000000805116c 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1925: 0000000008069fb6 127 FUNC GLOBAL DEFAULT 2 timersub + 1926: 00000000080614f0 59 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1927: 000000000805696c 32 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 1928: 000000000800aa27 86 FUNC GLOBAL DEFAULT 2 isalpha + 1929: 0000000008069cc1 172 FUNC GLOBAL DEFAULT 2 lstat64 + 1930: 0000000008066f53 80 FUNC WEAK DEFAULT 2 _ZN3frg9construc[...] + 1931: 000000000805dc7e 32 FUNC WEAK DEFAULT 2 _ZN5mlibc13utf8_[...] + 1932: 00000000080525c0 388 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1933: 000000000803bc3d 53 FUNC GLOBAL DEFAULT 2 wcscspn + 1934: 0000000008016ae8 14 FUNC WEAK DEFAULT 2 _ZSt4moveIRiEONS[...] + 1935: 000000000803b84e 43 FUNC GLOBAL DEFAULT 2 wcstoul + 1936: 000000000806132c 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1937: 000000000805cef3 157 FUNC GLOBAL DEFAULT 2 setresuid + 1938: 000000000803b038 130 FUNC GLOBAL DEFAULT 2 strncat + 1939: 0000000008058ca8 568 FUNC GLOBAL DEFAULT 2 execlp + 1940: 0000000008006bb0 69 FUNC WEAK DEFAULT 2 _ZN3frg6formatIP[...] + 1941: 0000000008066398 48 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 1942: 0000000008052e47 82 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 1943: 000000000800a430 214 FUNC WEAK HIDDEN 2 _ZZN3frg11_fmt_b[...] + 1944: 0000000008052808 58 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1945: 00000000080261d4 480 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1946: 000000000800c9f0 33 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 1947: 000000000804fc1a 30 FUNC WEAK HIDDEN 2 _ZNK3frg8expecte[...] + 1948: 00000000080613ac 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1949: 0000000008051946 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIiEO[...] + 1950: 000000000803305c 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 1951: 0000000008027dfe 61 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1952: 000000000803bbda 99 FUNC GLOBAL DEFAULT 2 wcschr + 1953: 000000000803d160 28 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 1954: 0000000008062075 983 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13threa[...] + 1955: 0000000008049082 90 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 1956: 00000000080660c4 51 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 1957: 000000000805d062 53 FUNC GLOBAL DEFAULT 2 setdomainname + 1958: 0000000008050d04 82 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 1959: 000000000800c662 42 FUNC WEAK DEFAULT 2 _ZN3frg10escape_[...] + 1960: 0000000008060ed1 70 FUNC WEAK DEFAULT 2 _ZSt3getILm0EJmc[...] + 1961: 000000000800ee3b 126 FUNC GLOBAL DEFAULT 2 fread + 1962: 0000000008006622 43 FUNC WEAK DEFAULT 2 _ZN3frg3minImEER[...] + 1963: 000000000800092e 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1964: 0000000008062786 592 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17threa[...] + 1965: 0000000008016f2e 2402 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 1966: 0000000008050186 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1967: 0000000008017a9a 224 FUNC WEAK DEFAULT 2 _ZN3frg12basic_s[...] + 1968: 000000000805bc1c 139 FUNC GLOBAL DEFAULT 2 ttyname_r + 1969: 0000000008052906 144 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 1970: 0000000008051bbc 37 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 1971: 000000000803f991 32 FUNC GLOBAL HIDDEN 2 __do_syscall2 + 1972: 0000000008061478 59 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1973: 000000000804a0b8 311 FUNC GLOBAL HIDDEN 2 _Z12doInitialize[...] + 1974: 000000000806badc 42 FUNC WEAK DEFAULT 2 _ZN3frg4spanIcEC1EPcm + 1975: 000000000806987c 160 FUNC GLOBAL DEFAULT 2 mkdirat + 1976: 000000000800e355 126 FUNC GLOBAL DEFAULT 2 fwscanf + 1977: 000000000805d1e1 190 FUNC GLOBAL DEFAULT 2 sbrk + 1978: 000000000805a118 53 FUNC GLOBAL DEFAULT 2 getlogin_r + 1979: 000000000802c076 211 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 1980: 0000000008028110 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 1981: 0000000008016eba 35 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 1982: 0000000008066fa3 52 FUNC WEAK DEFAULT 2 _ZN3frg8destruct[...] + 1983: 000000000806890c 105 FUNC GLOBAL DEFAULT 2 strdup + 1984: 0000000008061777 18 FUNC GLOBAL DEFAULT 2 ELF64_ST_BIND + 1985: 000000000801f856 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 1986: 0000000008056d41 31 FUNC GLOBAL DEFAULT 2 pthread_condattr[...] + 1987: 00000000080504f6 169 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 1988: 0000000008062ca3 1124 FUNC GLOBAL DEFAULT 2 _ZN5mlibc21threa[...] + 1989: 0000000008002b66 43 FUNC GLOBAL DEFAULT 2 strtoull + 1990: 000000000804018c 1135 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 1991: 0000000008001156 63 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1992: 00000000080692c6 34 FUNC GLOBAL DEFAULT 2 index + 1993: 0000000008061444 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 1994: 0000000008059479 173 FUNC GLOBAL DEFAULT 2 fchownat + 1995: 000000000805b190 157 FUNC GLOBAL DEFAULT 2 symlink + 1996: 0000000008000aae 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 1997: 000000000804b630 126 FUNC GLOBAL HIDDEN 2 _ZN5Scope12appen[...] + 1998: 0000000008069e18 130 FUNC GLOBAL DEFAULT 2 gettimeofday + 1999: 00000000080367f4 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2000: 0000000008045c0a 1896 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 2001: 000000000804edf8 35 FUNC WEAK HIDDEN 2 _ZN10Relocation1[...] + 2002: 000000000801322a 54 FUNC WEAK DEFAULT 2 _ZN14LimitedPrin[...] + 2003: 0000000008007f22 22 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 2004: 00000000080651d8 146 FUNC GLOBAL DEFAULT 2 fopen + 2005: 000000000806889b 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRPP[...] + 2006: 000000000809b5a0 0 NOTYPE GLOBAL DEFAULT 14 __bss_start + 2007: 0000000008052744 117 FUNC WEAK HIDDEN 2 _ZN3frg9construc[...] + 2008: 0000000008051ca1 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA3[...] + 2009: 000000000803ba2e 57 FUNC GLOBAL DEFAULT 2 wcsncat + 2010: 0000000008000c26 46 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2011: 00000000080684bb 172 FUNC WEAK DEFAULT 2 _ZN3frg9construc[...] + 2012: 00000000080614b4 59 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2013: 000000000805af30 151 FUNC GLOBAL DEFAULT 2 setreuid + 2014: 000000000805a14d 56 FUNC GLOBAL DEFAULT 2 getopt + 2015: 0000000008043d18 72 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2016: 0000000008052884 71 FUNC WEAK HIDDEN 2 _ZN3frg6formatIt[...] + 2017: 00000000080356ce 1105 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2018: 0000000008050e4a 67 FUNC WEAK HIDDEN 2 _ZN3frg6vectorI1[...] + 2019: 000000000800edd7 48 FUNC GLOBAL DEFAULT 2 putwchar + 2020: 00000000080411c4 943 FUNC GLOBAL HIDDEN 2 memset + 2021: 0000000008060f6e 49 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 2022: 00000000080508f2 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2023: 0000000008021636 457 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2024: 0000000008052e39 14 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 2025: 00000000080002bd 21 FUNC GLOBAL DEFAULT 2 main + 2026: 0000000008060d45 100 FUNC WEAK DEFAULT 2 _ZSt24__find_uni[...] + 2027: 000000000806a4fd 126 FUNC GLOBAL DEFAULT 2 cfmakeraw + 2028: 000000000806468a 364 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 2029: 0000000008013870 178 FUNC WEAK DEFAULT 2 _ZN13FutexLockIm[...] + 2030: 000000000805d3fa 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2031: 0000000008044614 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2032: 000000000805a49c 323 FUNC GLOBAL DEFAULT 2 lockf + 2033: 0000000008061594 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2034: 0000000008028b88 267 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 2035: 000000000803f342 77 FUNC WEAK DEFAULT 2 _ZN3frg6vectorI1[...] + 2036: 000000000803bd08 53 FUNC GLOBAL DEFAULT 2 wcsspn + 2037: 0000000008014648 42 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 2038: 0000000008061026 45 FUNC WEAK DEFAULT 2 _ZSt17holds_alte[...] + 2039: 000000000805a229 126 FUNC GLOBAL DEFAULT 2 getsid + 2040: 000000000800104d 67 FUNC WEAK DEFAULT 2 _ZN3frg6formatIj[...] + 2041: 000000000806538a 148 FUNC GLOBAL DEFAULT 2 ftell + 2042: 00000000080240c9 681 FUNC WEAK DEFAULT 2 _ZN3frg16do_prin[...] + 2043: 000000000805f172 189 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 2044: 00000000080a38d4 4 OBJECT GLOBAL DEFAULT 14 __optreset + 2045: 0000000008060da9 34 FUNC WEAK DEFAULT 2 _ZSt3getIcJmcSt9[...] + 2046: 0000000008033b84 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2047: 0000000008002c1a 34 FUNC GLOBAL DEFAULT 2 srand + 2048: 000000000805d8ee 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA8[...] + 2049: 00000000080518a6 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRN3[...] + 2050: 000000000803b24a 75 FUNC GLOBAL DEFAULT 2 strxfrm + 2051: 0000000008040986 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIPN3[...] + 2052: 000000000804f922 163 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 2053: 000000000805e844 31 FUNC WEAK DEFAULT 2 _ZN5mlibc8code_s[...] + 2054: 0000000008028a43 222 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2055: 00000000080501d2 82 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2056: 000000000800929a 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2057: 000000000800e3d3 57 FUNC GLOBAL DEFAULT 2 vfwprintf + 2058: 000000000806924e 120 FUNC GLOBAL DEFAULT 2 strlcat + 2059: 000000000803e51c 420 FUNC GLOBAL DEFAULT 2 mbsrtowcs + 2060: 0000000008044d2a 49 FUNC WEAK HIDDEN 2 _ZN3frg14slab_al[...] + 2061: 0000000008000a46 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2062: 0000000008056f85 112 FUNC GLOBAL DEFAULT 2 pthread_barrier_init + 2063: 000000000803f805 22 FUNC GLOBAL HIDDEN 2 _ZN5mlibc14sys_f[...] + 2064: 0000000008043c82 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2065: 0000000008015296 3065 FUNC WEAK DEFAULT 2 _ZN3frg13printf_[...] + 2066: 000000000805319d 14 FUNC WEAK HIDDEN 2 _ZSt7launderI13R[...] + 2067: 000000000804497c 18 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 2068: 000000000800b247 1014 FUNC GLOBAL DEFAULT 2 wctype + 2069: 000000000804aa0a 42 FUNC GLOBAL HIDDEN 2 _ZN12ObjectSymbo[...] + 2070: 000000000800f04c 22 FUNC GLOBAL DEFAULT 2 clearerr + 2071: 0000000008035bf6 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2072: 000000000803f31a 26 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 2073: 0000000008064d22 88 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 2074: 0000000008009266 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2075: 000000000809b528 8 OBJECT GLOBAL DEFAULT 13 _dl_debug_addr + 2076: 00000000080073e4 104 FUNC WEAK DEFAULT 2 _ZN3frg13format_[...] + 2077: 00000000080661ad 123 FUNC WEAK DEFAULT 2 _ZN3frg9construc[...] + 2078: 0000000008000724 18 FUNC WEAK HIDDEN 2 _ZnwmPv + 2079: 000000000805102a 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2080: 00000000080408be 18 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 2081: 000000000806526a 132 FUNC GLOBAL DEFAULT 2 fclose + 2082: 00000000080554c6 64 FUNC GLOBAL DEFAULT 2 pthread_attr_setstack + 2083: 00000000080686e4 43 FUNC WEAK DEFAULT 2 _ZN5mlibc17fmemo[...] + 2084: 0000000008067638 331 FUNC GLOBAL DEFAULT 2 open64 + 2085: 0000000008051be2 76 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 2086: 000000000800e9b0 24 FUNC GLOBAL DEFAULT 2 getchar + 2087: 000000000803f735 19 FUNC GLOBAL HIDDEN 2 _ZN5mlibc12sys_v[...] + 2088: 0000000008050f7e 51 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2089: 000000000805a3ed 175 FUNC GLOBAL DEFAULT 2 linkat + 2090: 00000000080568fb 34 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 2091: 000000000805c9f7 97 FUNC GLOBAL DEFAULT 2 getppid + 2092: 000000000806492c 91 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 2093: 000000000806a738 154 FUNC GLOBAL DEFAULT 2 tcgetattr + 2094: 000000000802309e 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2095: 000000000805154e 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2096: 00000000080065ee 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2097: 000000000806628c 48 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 2098: 0000000008009738 208 FUNC WEAK HIDDEN 2 _ZZN3frg11_fmt_b[...] + 2099: 000000000805257e 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 2100: 000000000805cc6f 12 FUNC GLOBAL DEFAULT 2 endusershell + 2101: 00000000080667f6 260 FUNC GLOBAL DEFAULT 2 opendir + 2102: 0000000008057cc2 319 FUNC WEAK DEFAULT 2 _ZN10ScopeTraceC[...] + 2103: 0000000008006b02 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA7[...] + 2104: 0000000008065abe 32 FUNC WEAK DEFAULT 2 _ZN13FutexLockIm[...] + 2105: 0000000008059f01 159 FUNC GLOBAL DEFAULT 2 getgroups + 2106: 0000000008012fa3 59 FUNC WEAK DEFAULT 2 _ZN3frg14generic[...] + 2107: 0000000008001090 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA1[...] + 2108: 0000000008000dc0 125 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2109: 0000000008006ba2 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRPv[...] + 2110: 00000000080178d9 16 FUNC WEAK DEFAULT 2 _ZN3frg15indicat[...] + 2111: 000000000809c2d0 1 OBJECT GLOBAL HIDDEN 14 _ZN5mlibc10infoL[...] + 2112: 0000000008051856 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 2113: 000000000801af56 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2114: 000000000800abd5 86 FUNC GLOBAL DEFAULT 2 isgraph + 2115: 000000000805698c 47 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 2116: 00000000080515a2 18 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 2117: 000000000804a2e8 70 FUNC GLOBAL HIDDEN 2 _ZN13RuntimeTlsM[...] + 2118: 000000000809b540 8 OBJECT GLOBAL HIDDEN 13 rtsCounter + 2119: 000000000803b911 107 FUNC GLOBAL DEFAULT 2 wcsncpy + 2120: 000000000806332c 79 FUNC GLOBAL DEFAULT 2 __assert_fail + 2121: 00000000080407c6 44 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 2122: 000000000809c4a0 40 OBJECT GLOBAL HIDDEN 14 preloads + 2123: 000000000805a858 154 FUNC GLOBAL DEFAULT 2 pipe2 + 2124: 0000000008031126 1135 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2125: 000000000800ef37 119 FUNC GLOBAL DEFAULT 2 fgetpos + 2126: 000000000805d93e 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA5[...] + 2127: 000000000800ab29 86 FUNC GLOBAL DEFAULT 2 isalnum + 2128: 00000000080616b6 31 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2129: 000000000800090a 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2130: 00000000080466c2 73 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 2131: 000000000806a086 154 FUNC GLOBAL DEFAULT 2 getitimer + 2132: 0000000008052da4 149 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 2133: 0000000008044de5 14 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 2134: 000000000800d5cb 49 FUNC GLOBAL DEFAULT 2 tmpnam + 2135: 000000000804f518 84 FUNC WEAK HIDDEN 2 _ZNK3frg17basic_[...] + 2136: 000000000800e2d7 126 FUNC GLOBAL DEFAULT 2 fwprintf + 2137: 0000000008017890 73 FUNC WEAK DEFAULT 2 _ZN3frg8expected[...] + 2138: 000000000805accf 143 FUNC GLOBAL DEFAULT 2 seteuid + 2139: 000000000800acd7 86 FUNC GLOBAL DEFAULT 2 isprint + 2140: 000000000800a145 398 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 2141: 000000000805105e 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2142: 0000000008044df3 14 FUNC WEAK HIDDEN 2 _ZSt7launderI12O[...] + 2143: 00000000080179d6 196 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 2144: 00000000080615fc 41 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2145: 000000000805e73c 264 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 2146: 0000000008052a38 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA5[...] + 2147: 000000000806badc 42 FUNC WEAK DEFAULT 2 _ZN3frg4spanIcEC2EPcm + 2148: 0000000008043d7a 77 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIN[...] + 2149: 000000000800ea3a 108 FUNC GLOBAL DEFAULT 2 putc + 2150: 000000000805db9f 115 FUNC GLOBAL DEFAULT 2 _ZN5mlibc16curre[...] + 2151: 0000000008063108 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2152: 0000000008000b4a 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2153: 00000000080523de 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA1[...] + 2154: 00000000080682c8 27 FUNC WEAK DEFAULT 2 _ZN10popen_file1[...] + 2155: 00000000080553af 32 FUNC GLOBAL DEFAULT 2 pthread_attr_get[...] + 2156: 000000000804f178 70 FUNC WEAK HIDDEN 2 _ZN7LinkMapC2Ev + 2157: 0000000008043f7a 91 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 2158: 00000000080527b9 52 FUNC WEAK HIDDEN 2 _ZN3frg8destruct[...] + 2159: 000000000804ad05 132 FUNC GLOBAL HIDDEN 2 _Z7gnuHashN3frg1[...] + 2160: 0000000008006918 40 FUNC WEAK HIDDEN 2 _ZN3frg14slab_al[...] + 2161: 0000000008009ca8 425 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2162: 000000000805a5df 148 FUNC GLOBAL DEFAULT 2 nice + 2163: 00000000080008b2 31 FUNC WEAK HIDDEN 2 _ZN3frg14format_[...] + 2164: 00000000080430d8 329 FUNC GLOBAL DEFAULT 2 __dlapi_iterate_phdr + 2165: 000000000801eba2 479 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2166: 000000000809b538 8 OBJECT GLOBAL HIDDEN 13 tlsMaxAlignment + 2167: 0000000008017b8c 18 FUNC WEAK DEFAULT 2 _ZN3frg12basic_s[...] + 2168: 000000000800f659 401 FUNC GLOBAL DEFAULT 2 fread_unlocked + 2169: 000000000800775c 73 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 2170: 00000000080611d0 51 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 2171: 000000000803b12c 114 FUNC GLOBAL DEFAULT 2 strcmp + 2172: 0000000008000f5a 69 FUNC WEAK HIDDEN 2 _ZN3frg6formatIP[...] + 2173: 0000000008025e12 482 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2174: 0000000008020881 681 FUNC WEAK DEFAULT 2 _ZN3frg16do_prin[...] + 2175: 0000000008052bfc 69 FUNC WEAK HIDDEN 2 _ZN3frg6formatIm[...] + 2176: 000000000801fbaa 423 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2177: 00000000080013ac 14 FUNC WEAK HIDDEN 2 _ZSt7launderIiEPT_S1_ + 2178: 0000000008056c14 72 FUNC GLOBAL DEFAULT 2 pthread_mutex_unlock + 2179: 000000000805ea62 225 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 2180: 00000000080662e4 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2181: 000000000800a5d6 1105 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 2182: 0000000008044b50 82 FUNC WEAK HIDDEN 2 _ZN3frg12small_v[...] + 2183: 000000000805bb5f 189 FUNC GLOBAL DEFAULT 2 ttyname + 2184: 0000000008044b10 30 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 2185: 000000000805de56 794 FUNC WEAK DEFAULT 2 _ZN5mlibc13utf8_[...] + 2186: 0000000008043b16 110 FUNC WEAK HIDDEN 2 _ZN13SymbolVersi[...] + 2187: 0000000008052d6a 25 FUNC WEAK HIDDEN 2 _ZNK3frg12small_[...] + 2188: 0000000008013260 81 FUNC WEAK DEFAULT 2 _ZN14LimitedPrin[...] + 2189: 0000000008060c7d 100 FUNC WEAK DEFAULT 2 _ZSt24__find_uni[...] + 2190: 000000000805d32a 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2191: 000000000805c449 150 FUNC GLOBAL DEFAULT 2 dup + 2192: 000000000805144a 90 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2193: 0000000008034340 1122 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2194: 000000000800423c 66 FUNC WEAK HIDDEN 2 _ZN5mlibc8this_tidEv + 2195: 000000000804f096 65 FUNC WEAK HIDDEN 2 _ZNK13SymbolVers[...] + 2196: 000000000804ca2c 2701 FUNC GLOBAL HIDDEN 2 _ZN6Loader19_pro[...] + 2197: 00000000080618c4 95 FUNC GLOBAL DEFAULT 2 __mlibc_islessf + 2198: 000000000800bb80 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2199: 0000000008057142 524 FUNC GLOBAL DEFAULT 2 pthread_barrier_wait + 2200: 0000000008059749 1976 FUNC GLOBAL DEFAULT 2 getcwd + 2201: 00000000080504ce 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2202: 00000000080695f1 163 FUNC GLOBAL DEFAULT 2 fchmodat + 2203: 000000000804f178 70 FUNC WEAK HIDDEN 2 _ZN7LinkMapC1Ev + 2204: 0000000008068bdd 1119 FUNC GLOBAL DEFAULT 2 strsignal + 2205: 000000000804f874 26 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJi[...] + 2206: 000000000806aa24 134 FUNC GLOBAL DEFAULT 2 _ZN5mlibc18memst[...] + 2207: 0000000008060f3c 49 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 2208: 000000000800432f 13 FUNC WEAK DEFAULT 2 _ZN5mlibc10int_l[...] + 2209: 000000000806bef1 0 FUNC GLOBAL DEFAULT 3 _fini + 2210: 0000000008069741 161 FUNC GLOBAL DEFAULT 2 futimens + 2211: 000000000801adaa 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2212: 000000000806109d 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRSt[...] + 2213: 00000000080449bd 30 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 2214: 000000000803f31a 26 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 2215: 0000000008020b2a 1785 FUNC WEAK DEFAULT 2 _ZN3frg15do_prin[...] + 2216: 0000000008052f2e 77 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 2217: 0000000008044bea 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 2218: 000000000800bbb4 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA1[...] + 2219: 0000000008044bcc 16 FUNC WEAK HIDDEN 2 _ZN3frg15indicat[...] + 2220: 000000000804fcbf 202 FUNC WEAK HIDDEN 2 _ZN3frg9construc[...] + 2221: 0000000008044ccc 14 FUNC WEAK HIDDEN 2 _ZSt4moveIR12Obj[...] + 2222: 000000000804c698 606 FUNC GLOBAL HIDDEN 2 _ZN6Loader11init[...] + 2223: 00000000080681e8 139 FUNC WEAK DEFAULT 2 _ZN5mlibc11cooki[...] + 2224: 000000000801fa00 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2225: 000000000800e71d 68 FUNC GLOBAL DEFAULT 2 fgetc + 2226: 000000000806115a 51 FUNC WEAK DEFAULT 2 _ZNSt7variantIJm[...] + 2227: 0000000008059fc9 157 FUNC GLOBAL DEFAULT 2 gethostname + 2228: 00000000080612ac 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2229: 000000000804f266 82 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2230: 000000000803d5e5 919 FUNC WEAK DEFAULT 2 _ZN5mlibc15strin[...] + 2231: 000000000800dbb9 180 FUNC GLOBAL DEFAULT 2 sprintf + 2232: 0000000008053258 80 FUNC WEAK HIDDEN 2 _ZN3frg6formatIm[...] + 2233: 000000000801d9dc 125 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2234: 0000000008051ae4 58 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2235: 000000000801c108 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2236: 000000000804ac66 159 FUNC GLOBAL HIDDEN 2 _Z9elf64HashN3fr[...] + 2237: 000000000800f381 180 FUNC GLOBAL DEFAULT 2 asprintf + 2238: 000000000806bbb8 181 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIc[...] + 2239: 0000000008000eec 16 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2240: 0000000008000cbc 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2241: 00000000080430bf 25 FUNC GLOBAL DEFAULT 2 __dlapi_close + 2242: 0000000008061286 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2243: 0000000008045303 70 FUNC GLOBAL HIDDEN 2 _Z10closeOrDiei + 2244: 0000000008044c8a 14 FUNC WEAK HIDDEN 2 _ZSt4moveIR13Sym[...] + 2245: 000000000805d76c 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2246: 0000000008053387 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIKtE[...] + 2247: 000000000803ce06 93 FUNC GLOBAL DEFAULT 2 strerror_r + 2248: 0000000008000f9f 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA8[...] + 2249: 00000000080610ba 14 FUNC WEAK DEFAULT 2 _ZNRSt8__detail9[...] + 2250: 0000000008065a56 38 FUNC WEAK DEFAULT 2 _ZN5mlibc9StdioL[...] + 2251: 000000000806441e 619 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 2252: 0000000008002a9b 37 FUNC GLOBAL DEFAULT 2 strtof + 2253: 0000000008065ab0 14 FUNC WEAK DEFAULT 2 _ZN3frg7eternalI[...] + 2254: 0000000008002f09 41 FUNC GLOBAL DEFAULT 2 atexit + 2255: 0000000008061626 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2256: 0000000008053064 127 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2257: 0000000008061560 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2258: 000000000803fbef 46 FUNC GLOBAL HIDDEN 2 __cxa_guard_release + 2259: 000000000803b357 109 FUNC GLOBAL DEFAULT 2 strcspn + 2260: 000000000800ba92 50 FUNC WEAK HIDDEN 2 _ZN3frg17basic_s[...] + 2261: 000000000803671e 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2262: 0000000008007862 86 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2263: 0000000008058038 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2264: 000000000805758d 15 FUNC GLOBAL DEFAULT 2 pthread_rwlockat[...] + 2265: 00000000080a38d4 4 OBJECT WEAK DEFAULT 14 optreset + 2266: 000000000802e9ac 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2267: 0000000008065cec 102 FUNC WEAK DEFAULT 2 _ZN3frg5_list14i[...] + 2268: 000000000800bc12 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2269: 00000000080580a0 67 FUNC WEAK DEFAULT 2 _ZN3frg6formatIi[...] + 2270: 0000000008050d56 165 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2271: 000000000804f2ec 227 FUNC WEAK HIDDEN 2 _ZN3frg9construc[...] + 2272: 000000000802a70a 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA4[...] + 2273: 0000000008013384 275 FUNC WEAK DEFAULT 2 _ZN13ResizePrint[...] + 2274: 0000000008043f38 28 FUNC WEAK HIDDEN 2 _ZNK3frg17basic_[...] + 2275: 0000000008029c38 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2276: 000000000802fd8a 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2277: 000000000800f540 49 FUNC GLOBAL DEFAULT 2 flockfile + 2278: 00000000080664d2 26 FUNC WEAK DEFAULT 2 _ZN3frg13locate_[...] + 2279: 000000000803237c 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2280: 000000000800aec1 83 FUNC GLOBAL DEFAULT 2 iswdigit + 2281: 000000000801da5a 456 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2282: 00000000080185dc 55 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 2283: 00000000080687f0 63 FUNC WEAK DEFAULT 2 _ZN5mlibc18memst[...] + 2284: 000000000800da4a 183 FUNC GLOBAL DEFAULT 2 scanf + 2285: 0000000008012efa 85 FUNC WEAK DEFAULT 2 _ZN3frg15generic[...] + 2286: 0000000008050e8e 240 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2287: 000000000803f2de 18 FUNC WEAK DEFAULT 2 _ZNK3frg6vectorI[...] + 2288: 00000000080199a0 75 FUNC WEAK DEFAULT 2 _ZN3frg8expected[...] + 2289: 0000000008050224 171 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2290: 000000000809b570 8 OBJECT GLOBAL DEFAULT 13 stderr + 2291: 00000000080531ab 77 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 2292: 000000000800c6e0 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2293: 000000000809a6d0 104 OBJECT WEAK DEFAULT 12 _ZTVN5mlibc8mem_fileE + 2294: 000000000804a448 697 FUNC GLOBAL HIDDEN 2 _Z11allocateTcbv + 2295: 0000000008060f18 35 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 2296: 00000000080516de 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2297: 00000000080408b0 14 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 2298: 000000000802d9bf 356 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2299: 000000000801c2b2 423 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2300: 000000000806b29c 400 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17fmemo[...] + 2301: 000000000803a033 401 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2302: 0000000008013954 39 FUNC WEAK DEFAULT 2 _ZN3frg11unique_[...] + 2303: 000000000809c2d1 1 OBJECT GLOBAL HIDDEN 14 _ZN5mlibc11panic[...] + 2304: 00000000080014a2 219 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2305: 00000000080682e4 67 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIc[...] + 2306: 00000000080612ac 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2307: 0000000008054ec4 256 FUNC GLOBAL DEFAULT 2 scalbn + 2308: 000000000804efcc 201 FUNC WEAK HIDDEN 2 _ZNK13SymbolVers[...] + 2309: 000000000805c69d 140 FUNC GLOBAL DEFAULT 2 vfork + 2310: 0000000008040a06 39 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2311: 0000000008000cf0 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2312: 000000000805d94c 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2313: 000000000804fb36 227 FUNC WEAK HIDDEN 2 _ZN3frg9construc[...] + 2314: 000000000805e1ea 55 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 2315: 000000000804076e 88 FUNC GLOBAL HIDDEN 2 _ZN16VirtualAllo[...] + 2316: 0000000008068b0d 208 FUNC GLOBAL DEFAULT 2 strsep + 2317: 0000000008062c4e 85 FUNC GLOBAL DEFAULT 2 _ZN5mlibc21threa[...] + 2318: 0000000008006a62 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 2319: 0000000008013306 80 FUNC WEAK DEFAULT 2 _ZN14LimitedPrin[...] + 2320: 000000000800126f 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2321: 000000000801a162 456 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2322: 00000000080686b6 45 FUNC WEAK DEFAULT 2 _ZN5mlibc17fmemo[...] + 2323: 000000000802b6fe 449 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2324: 0000000008040970 22 FUNC WEAK HIDDEN 2 _ZN3frg15aligned[...] + 2325: 0000000008061d53 95 FUNC GLOBAL DEFAULT 2 __mlibc_isgreate[...] + 2326: 000000000805768b 242 FUNC GLOBAL DEFAULT 2 pthread_rwlock_t[...] + 2327: 00000000080268e6 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2328: 000000000806af6c 91 FUNC GLOBAL DEFAULT 2 _ZN5mlibc18memst[...] + 2329: 00000000080253d8 427 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2330: 000000000800eaa6 36 FUNC GLOBAL DEFAULT 2 putchar_unlocked + 2331: 000000000804b5f2 62 FUNC GLOBAL HIDDEN 2 _ZN5ScopeC1Eb + 2332: 0000000008057915 228 FUNC GLOBAL DEFAULT 2 pthread_rwlock_t[...] + 2333: 00000000080505a0 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2334: 0000000008003601 53 FUNC GLOBAL DEFAULT 2 ldiv + 2335: 0000000008061fe8 141 FUNC GLOBAL DEFAULT 2 sigismember + 2336: 0000000008062ba6 52 FUNC GLOBAL DEFAULT 2 _ZN5mlibc24threa[...] + 2337: 000000000802dc00 222 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2338: 000000000806b18a 274 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17fmemo[...] + 2339: 000000000804af0b 1199 FUNC GLOBAL HIDDEN 2 _Z15resolveInObj[...] + 2340: 0000000008061c38 95 FUNC GLOBAL DEFAULT 2 __mlibc_isgreaterf + 2341: 0000000008061260 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2342: 0000000008044f16 14 FUNC WEAK HIDDEN 2 _ZSt7launderIK13[...] + 2343: 000000000800ed49 49 FUNC GLOBAL DEFAULT 2 getwc + 2344: 0000000008050928 33 FUNC WEAK HIDDEN 2 _ZN3frg6vectorI1[...] + 2345: 000000000800427e 81 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2346: 0000000008059620 143 FUNC GLOBAL DEFAULT 2 fsync + 2347: 000000000803a408 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2348: 0000000008043dc8 176 FUNC WEAK HIDDEN 2 _ZNK3frg17basic_[...] + 2349: 000000000803aad0 1110 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2350: 000000000809c3e0 56 OBJECT GLOBAL HIDDEN 14 runtimeTlsMap + 2351: 0000000008013356 46 FUNC WEAK DEFAULT 2 _ZN13ResizePrint[...] + 2352: 000000000802f162 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2353: 0000000008050102 26 FUNC WEAK HIDDEN 2 _ZNK3frg5stackIP[...] + 2354: 000000000800e822 108 FUNC GLOBAL DEFAULT 2 fputc + 2355: 000000000801322a 54 FUNC WEAK DEFAULT 2 _ZN14LimitedPrin[...] + 2356: 0000000008028138 267 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 2357: 000000000803f714 33 FUNC GLOBAL HIDDEN 2 _ZN5mlibc10sys_v[...] + 2358: 000000000802d136 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2359: 0000000008068123 53 FUNC GLOBAL DEFAULT 2 fgetln + 2360: 000000000800f5ed 20 FUNC GLOBAL DEFAULT 2 feof_unlocked + 2361: 00000000080469c6 95 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 2362: 000000000801fa00 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2363: 000000000806b740 103 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11cooki[...] + 2364: 000000000806256e 75 FUNC GLOBAL DEFAULT 2 _ZN5mlibc16threa[...] + 2365: 000000000804b3ba 567 FUNC GLOBAL HIDDEN 2 _ZN5Scope12_reso[...] + 2366: 00000000080519c4 14 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 2367: 00000000080453f0 350 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 2368: 0000000008061080 29 FUNC WEAK DEFAULT 2 _ZNKSt7variantIJ[...] + 2369: 000000000802b8f9 1917 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2370: 0000000008016dca 167 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 2371: 000000000803f334 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRN3[...] + 2372: 000000000804eeb8 90 FUNC WEAK HIDDEN 2 _ZN13SymbolVersi[...] + 2373: 00000000080a36c8 4 OBJECT GLOBAL DEFAULT 14 optopt + 2374: 000000000805d5dc 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA4[...] + 2375: 000000000800e998 24 FUNC GLOBAL DEFAULT 2 getchar_unlocked + 2376: 000000000803f979 24 FUNC GLOBAL HIDDEN 2 __do_syscall1 + 2377: 000000000804f56c 57 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 2378: 0000000008017c02 55 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 2379: 00000000080009ba 41 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2380: 0000000008006b60 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2381: 000000000802e044 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2382: 0000000008000b7e 125 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2383: 000000000806b94e 102 FUNC WEAK DEFAULT 2 _ZN5mlibc8mem_fi[...] + 2384: 000000000805a8f2 177 FUNC GLOBAL DEFAULT 2 pread + 2385: 0000000008016e72 72 FUNC WEAK DEFAULT 2 _ZNK3frg8optiona[...] + 2386: 00000000080556bd 11 FUNC GLOBAL DEFAULT 2 pthread_self + 2387: 0000000008012e7c 42 FUNC WEAK DEFAULT 2 _ZN5mlibc9StdioL[...] + 2388: 000000000806be7a 43 FUNC WEAK DEFAULT 2 _ZN5mlibc11cooki[...] + 2389: 0000000008055e52 193 FUNC GLOBAL DEFAULT 2 pthread_setcanceltype + 2390: 000000000800ed15 52 FUNC GLOBAL DEFAULT 2 fwide + 2391: 000000000800b1ac 83 FUNC GLOBAL DEFAULT 2 iswupper + 2392: 00000000080004c6 303 FUNC GLOBAL DEFAULT 2 __ensure_fail + 2393: 000000000805d62c 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA6[...] + 2394: 0000000008051eef 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA3[...] + 2395: 0000000008056846 72 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 2396: 000000000809a550 88 OBJECT WEAK DEFAULT 12 _ZTV10popen_file + 2397: 0000000008043bb4 18 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 2398: 00000000080640ec 104 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 2399: 000000000800848c 17 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2400: 000000000805cf90 157 FUNC GLOBAL DEFAULT 2 setresgid + 2401: 000000000806541e 322 FUNC GLOBAL DEFAULT 2 fflush_unlocked + 2402: 0000000008028c94 62 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2403: 0000000008044a8e 130 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIN[...] + 2404: 0000000008053064 127 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2405: 000000000804f8a8 26 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 2406: 0000000008028b60 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2407: 00000000080505ee 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2408: 000000000806141e 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2409: 000000000801e182 453 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2410: 00000000080007c6 236 FUNC WEAK HIDDEN 2 _ZN3frg14format_[...] + 2411: 000000000804f3d0 122 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 2412: 0000000008050bd2 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2413: 0000000008000c54 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2414: 00000000080139a6 66 FUNC WEAK DEFAULT 2 _ZN3frgltIiiEEbR[...] + 2415: 00000000080617cc 18 FUNC GLOBAL DEFAULT 2 ELF32_ST_TYPE + 2416: 000000000801dc22 459 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2417: 000000000800ece0 53 FUNC GLOBAL DEFAULT 2 fputws + 2418: 0000000008000736 143 FUNC WEAK HIDDEN 2 _ZN3frg14format_[...] + 2419: 00000000080512ec 33 FUNC WEAK HIDDEN 2 _ZNK3frg6vectorI[...] + 2420: 00000000080445bc 18 FUNC WEAK HIDDEN 2 _ZNK3frg6vectorI[...] + 2421: 0000000008014600 71 FUNC WEAK DEFAULT 2 _ZNK3frg8expecte[...] + 2422: 000000000806afc8 385 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17fmemo[...] + 2423: 000000000804f242 18 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 2424: 000000000805e372 333 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 2425: 000000000806afc8 385 FUNC GLOBAL DEFAULT 2 _ZN5mlibc17fmemo[...] + 2426: 000000000800f7ea 584 FUNC GLOBAL DEFAULT 2 fwrite_unlocked + 2427: 000000000803bb5c 126 FUNC GLOBAL DEFAULT 2 wmemcmp + 2428: 0000000008016bdc 55 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 2429: 0000000008069c15 172 FUNC GLOBAL DEFAULT 2 stat + 2430: 0000000008052ce5 53 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 2431: 0000000008003636 53 FUNC GLOBAL DEFAULT 2 lldiv + 2432: 000000000804f8d4 26 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 2433: 0000000008044956 37 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 2434: 000000000804ece0 84 FUNC WEAK HIDDEN 2 _ZN10RelocationC[...] + 2435: 000000000803f000 102 FUNC GLOBAL DEFAULT 2 _Z12getExitQueuev + 2436: 000000000803b9b5 57 FUNC GLOBAL DEFAULT 2 wmemmove + 2437: 0000000008061053 45 FUNC WEAK DEFAULT 2 _ZSt17holds_alte[...] + 2438: 0000000008061732 36 FUNC GLOBAL DEFAULT 2 _ZN5mlibc12Globa[...] + 2439: 00000000080633d8 244 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 2440: 000000000805d72a 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2441: 0000000008052d1a 51 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 2442: 000000000800aa7d 86 FUNC GLOBAL DEFAULT 2 isdigit + 2443: 000000000803f6c1 83 FUNC GLOBAL HIDDEN 2 _ZN5mlibc13sys_a[...] + 2444: 0000000008068a31 159 FUNC GLOBAL DEFAULT 2 stpncpy + 2445: 000000000805b22d 162 FUNC GLOBAL DEFAULT 2 symlinkat + 2446: 000000000800eeb9 126 FUNC GLOBAL DEFAULT 2 fwrite + 2447: 0000000008044bdc 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA5[...] + 2448: 000000000800ce7d 542 FUNC WEAK DEFAULT 2 _ZN3frg13format_[...] + 2449: 000000000805d2d4 34 FUNC WEAK DEFAULT 2 _ZN3frg17basic_s[...] + 2450: 000000000805318f 14 FUNC WEAK HIDDEN 2 _ZSt7launderImEPT_S1_ + 2451: 0000000008006752 15 FUNC WEAK HIDDEN 2 _ZN3frg10array_s[...] + 2452: 000000000803f4cd 14 FUNC WEAK DEFAULT 2 _ZSt4moveIR11Exi[...] + 2453: 00000000080619df 95 FUNC GLOBAL DEFAULT 2 __mlibc_islessequalf + 2454: 000000000802fe60 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2455: 0000000008000efc 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA1[...] + 2456: 0000000008040800 79 FUNC WEAK HIDDEN 2 _ZN3frg7eternalI[...] + 2457: 00000000080531f8 18 FUNC WEAK HIDDEN 2 _ZNK3frg12basic_[...] + 2458: 000000000805ca58 154 FUNC GLOBAL DEFAULT 2 access + 2459: 000000000803f89a 95 FUNC WEAK HIDDEN 2 _Z7syscallIimiii[...] + 2460: 000000000809b588 0 NOTYPE GLOBAL DEFAULT 13 _edata + 2461: 000000000804eeb8 90 FUNC WEAK HIDDEN 2 _ZN13SymbolVersi[...] + 2462: 0000000008051194 82 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2463: 0000000008040904 108 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 2464: 0000000008051efd 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 2465: 000000000800c68c 83 FUNC WEAK HIDDEN 2 _ZNK3frg17basic_[...] + 2466: 000000000800347b 285 FUNC GLOBAL DEFAULT 2 qsort_r + 2467: 000000000802928a 449 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2468: 000000000803f15b 141 FUNC GLOBAL DEFAULT 2 _Z19__mlibc_do_f[...] + 2469: 0000000008065a7c 52 FUNC WEAK DEFAULT 2 _ZN3frg7eternalI[...] + 2470: 0000000008051a76 81 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 2471: 0000000008035b20 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2472: 00000000080a38d8 0 NOTYPE GLOBAL DEFAULT 14 _end + 2473: 000000000805e5d8 356 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 2474: 0000000008052d4d 14 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 2475: 0000000008006940 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2476: 000000000806bdee 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA5[...] + 2477: 0000000008033582 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2478: 0000000008051b1e 14 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 2479: 000000000803f628 52 FUNC GLOBAL HIDDEN 2 _ZN5mlibc9sys_closeEi + 2480: 0000000008005a20 1055 FUNC WEAK DEFAULT 2 _ZN5mlibc15strin[...] + 2481: 000000000804fa9e 76 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 2482: 0000000008030f80 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2483: 0000000008061789 18 FUNC GLOBAL DEFAULT 2 ELF64_ST_TYPE + 2484: 0000000008056a88 26 FUNC GLOBAL DEFAULT 2 pthread_mutex_destroy + 2485: 0000000008043415 122 FUNC GLOBAL HIDDEN 2 _Z14rtld_auxvectorv + 2486: 000000000805d85c 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2487: 0000000008044570 75 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 2488: 000000000804515b 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRN3frg[...] + 2489: 000000000803ee7a 53 FUNC GLOBAL DEFAULT 2 wcscasecmp + 2490: 000000000800df17 143 FUNC GLOBAL DEFAULT 2 vfscanf + 2491: 00000000080529d4 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRmEONS[...] + 2492: 000000000803d97c 1017 FUNC WEAK DEFAULT 2 _ZN5mlibc15strin[...] + 2493: 00000000080529e2 72 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 2494: 0000000008058175 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA4[...] + 2495: 00000000080041f0 53 FUNC WEAK HIDDEN 2 _ZN3frg14format_[...] + 2496: 0000000008069a0e 167 FUNC GLOBAL DEFAULT 2 mknodat + 2497: 00000000080502e2 26 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2498: 0000000008043b84 47 FUNC WEAK HIDDEN 2 _ZN6LoaderD1Ev + 2499: 0000000008025c32 479 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2500: 0000000008061c97 88 FUNC GLOBAL DEFAULT 2 __mlibc_isgreaterl + 2501: 000000000806580e 119 FUNC GLOBAL DEFAULT 2 rewind + 2502: 000000000805d68a 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2503: 000000000805d35e 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2504: 00000000080502fc 75 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 2505: 000000000800ca12 37 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 2506: 00000000080081fc 655 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2507: 000000000800427e 81 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2508: 000000000804504e 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRKP[...] + 2509: 000000000800d5fc 172 FUNC GLOBAL DEFAULT 2 freopen + 2510: 000000000809b530 8 OBJECT GLOBAL HIDDEN 13 libraryBase + 2511: 0000000008033d2a 1135 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2512: 000000000800f615 68 FUNC GLOBAL DEFAULT 2 fgetc_unlocked + 2513: 000000000804d4ba 2039 FUNC GLOBAL HIDDEN 2 _ZN6Loader25_pro[...] + 2514: 00000000080008b2 31 FUNC WEAK HIDDEN 2 _ZN3frg14format_[...] + 2515: 0000000008056aa2 72 FUNC GLOBAL DEFAULT 2 pthread_mutex_lock + 2516: 0000000008006a03 15 FUNC WEAK DEFAULT 2 _ZN5mlibc5widenI[...] + 2517: 000000000805bacc 54 FUNC GLOBAL DEFAULT 2 tcgetpgrp + 2518: 000000000803749a 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2519: 000000000800c866 67 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 2520: 000000000805aafd 177 FUNC GLOBAL DEFAULT 2 readlinkat + 2521: 0000000008013588 22 FUNC WEAK DEFAULT 2 _ZN3frg9va_structC1Ev + 2522: 00000000080011e8 69 FUNC WEAK DEFAULT 2 _ZN3frg6formatIP[...] + 2523: 000000000806123a 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2524: 0000000008021b90 427 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2525: 000000000800ee07 52 FUNC GLOBAL DEFAULT 2 ungetwc + 2526: 000000000802673a 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2527: 0000000008000f0a 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2528: 0000000008056e29 42 FUNC GLOBAL DEFAULT 2 pthread_cond_wait + 2529: 0000000008031e3c 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2530: 0000000008016c52 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2531: 000000000804baf4 137 FUNC GLOBAL HIDDEN 2 _ZN6LoaderC2EP5S[...] + 2532: 0000000008031cfb 107 FUNC WEAK DEFAULT 2 _ZN3frg13format_[...] + 2533: 0000000008044bb0 14 FUNC WEAK HIDDEN 2 _ZSt7launderI5Sc[...] + 2534: 000000000802a7af 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA7[...] + 2535: 000000000804fa9e 76 FUNC WEAK HIDDEN 2 _ZN3frg8expected[...] + 2536: 0000000008028cd2 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2537: 000000000800d0e9 22 FUNC GLOBAL DEFAULT 2 __errno_location + 2538: 00000000080a36cc 1 OBJECT GLOBAL DEFAULT 14 _ZN5mlibc5guardE + 2539: 000000000805a350 157 FUNC GLOBAL DEFAULT 2 link + 2540: 000000000809c2e2 1 OBJECT GLOBAL HIDDEN 14 ldShowAuxv + 2541: 0000000008045169 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIKP1[...] + 2542: 000000000803ed74 99 FUNC GLOBAL DEFAULT 2 wcsdup + 2543: 0000000008058183 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2544: 000000000804f6e4 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2545: 00000000080009e4 46 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2546: 000000000805d532 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2547: 0000000008050152 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2548: 00000000080664b8 26 FUNC WEAK DEFAULT 2 _ZN3frg3getINS_5[...] + 2549: 000000000805d6cc 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA7[...] + 2550: 0000000008052f98 103 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2551: 0000000008051696 72 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2552: 000000000802a718 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2553: 0000000008002f63 41 FUNC GLOBAL DEFAULT 2 exit + 2554: 0000000008003f70 175 FUNC WEAK DEFAULT 2 _ZN3frg7mt199374[...] + 2555: 000000000802a7ff 211 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2556: 000000000801bc08 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2557: 0000000008055527 30 FUNC GLOBAL DEFAULT 2 pthread_attr_set[...] + 2558: 000000000800a0fb 74 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 2559: 0000000008064ba4 293 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 2560: 00000000080633d8 244 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 2561: 000000000804763c 3530 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 2562: 0000000008066187 38 FUNC WEAK DEFAULT 2 _ZN5mlibc15file_[...] + 2563: 0000000008007f22 22 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 2564: 00000000080675fd 59 FUNC GLOBAL DEFAULT 2 vmsplice + 2565: 000000000805db56 29 FUNC GLOBAL DEFAULT 2 _ZN5mlibc20polym[...] + 2566: 0000000008024372 1785 FUNC WEAK DEFAULT 2 _ZN3frg15do_prin[...] + 2567: 00000000080061fc 957 FUNC WEAK DEFAULT 2 _ZN5mlibc15strin[...] + 2568: 000000000800b86b 79 FUNC GLOBAL DEFAULT 2 towlower + 2569: 000000000801aa50 427 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2570: 00000000080409ce 55 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 2571: 000000000805320a 78 FUNC WEAK HIDDEN 2 _ZN3frg6formatIj[...] + 2572: 0000000008044b2e 34 FUNC WEAK HIDDEN 2 _ZN3frg5arrayINS[...] + 2573: 000000000805f230 189 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 2574: 00000000080035c3 24 FUNC GLOBAL DEFAULT 2 llabs + 2575: 000000000803f55a 90 FUNC GLOBAL HIDDEN 2 _ZN5mlibc9sys_wr[...] + 2576: 000000000804faea 76 FUNC WEAK HIDDEN 2 _ZN3frg9construc[...] + 2577: 0000000008068750 45 FUNC WEAK DEFAULT 2 _ZN10popen_fileD2Ev + 2578: 0000000008061f2f 185 FUNC GLOBAL DEFAULT 2 sigdelset + 2579: 000000000800d6a8 59 FUNC GLOBAL DEFAULT 2 setbuf + 2580: 000000000800b946 284 FUNC WEAK DEFAULT 2 _ZN5mlibc20polym[...] + 2581: 000000000800af67 83 FUNC GLOBAL DEFAULT 2 iswalnum + 2582: 0000000008056aea 245 FUNC GLOBAL DEFAULT 2 pthread_mutex_trylock + 2583: 0000000008053396 117 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 2584: 000000000800e4c3 126 FUNC GLOBAL DEFAULT 2 swscanf + 2585: 000000000800c2d1 173 FUNC GLOBAL DEFAULT 2 _ZN5mlibc6putenvEPc + 2586: 000000000800c818 77 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 2587: 000000000805d13c 165 FUNC GLOBAL DEFAULT 2 getresgid + 2588: 000000000803ba67 78 FUNC GLOBAL DEFAULT 2 wcscmp + 2589: 0000000008032f86 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2590: 0000000008056192 203 FUNC GLOBAL DEFAULT 2 pthread_atfork + 2591: 000000000804fc38 64 FUNC WEAK HIDDEN 2 _ZN3frg8destruct[...] + 2592: 0000000008024cb2 459 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2593: 000000000803ff13 211 FUNC WEAK HIDDEN 2 _ZN3frg11_fmt_ba[...] + 2594: 0000000008039ed6 349 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2595: 000000000800c968 135 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 2596: 00000000080073a2 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2597: 000000000805e170 45 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 2598: 000000000803f54c 14 FUNC GLOBAL HIDDEN 2 _ZN5mlibc10Sysde[...] + 2599: 0000000008050448 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2600: 000000000801e84e 428 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2601: 000000000803d198 28 FUNC WEAK DEFAULT 2 _ZN5mlibc11char_[...] + 2602: 0000000008027fa6 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2603: 000000000804c14a 1357 FUNC GLOBAL HIDDEN 2 _ZN6Loader13_bui[...] + 2604: 0000000008002941 36 FUNC GLOBAL DEFAULT 2 atoi + 2605: 0000000008018fb6 55 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 2606: 000000000800add9 75 FUNC GLOBAL DEFAULT 2 iscntrl + 2607: 0000000008016c52 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2608: 0000000008014672 3065 FUNC WEAK DEFAULT 2 _ZN3frg13printf_[...] + 2609: 000000000805d5ea 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2610: 000000000800f601 20 FUNC GLOBAL DEFAULT 2 ferror_unlocked + 2611: 00000000080635c8 43 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 2612: 00000000080612e0 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2613: 00000000080511e6 171 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2614: 0000000008056de1 72 FUNC GLOBAL DEFAULT 2 pthread_cond_destroy + 2615: 0000000008044a74 26 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2616: 000000000802e7ea 449 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2617: 00000000080510be 137 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJ1[...] + 2618: 0000000008016c14 61 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2619: 0000000008029164 294 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 2620: 00000000080671b5 403 FUNC GLOBAL DEFAULT 2 openat + 2621: 00000000080445ce 33 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 2622: 0000000008052ad8 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA5[...] + 2623: 0000000008065174 100 FUNC GLOBAL DEFAULT 2 fileno + 2624: 000000000805693d 47 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 2625: 0000000008055650 53 FUNC GLOBAL DEFAULT 2 pthread_attr_set[...] + 2626: 00000000080632f5 0 FUNC GLOBAL DEFAULT 2 _setjmp + 2627: 000000000800fa32 218 FUNC GLOBAL DEFAULT 2 fgets_unlocked + 2628: 000000000803dd75 919 FUNC WEAK DEFAULT 2 _ZN5mlibc15strin[...] + 2629: 0000000008044b2e 34 FUNC WEAK HIDDEN 2 _ZN3frg5arrayINS[...] + 2630: 00000000080515e8 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2631: 000000000800ca9c 76 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 2632: 000000000805d7fe 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA8[...] + 2633: 000000000800f113 50 FUNC GLOBAL DEFAULT 2 getline + 2634: 000000000801bc08 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2635: 0000000008037ab0 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2636: 000000000805dcae 17 FUNC WEAK DEFAULT 2 _ZN5mlibc13utf8_[...] + 2637: 0000000008069941 160 FUNC GLOBAL DEFAULT 2 mkfifoat + 2638: 00000000080588a3 21 FUNC GLOBAL DEFAULT 2 _exit + 2639: 000000000803b9ee 64 FUNC GLOBAL DEFAULT 2 wcscat + 2640: 000000000802944c 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2641: 00000000080087dc 40 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 2642: 00000000080199a0 75 FUNC WEAK DEFAULT 2 _ZN3frg8expected[...] + 2643: 0000000008053152 61 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 2644: 0000000008065abe 32 FUNC WEAK DEFAULT 2 _ZN13FutexLockIm[...] + 2645: 0000000008040a06 39 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2646: 000000000806885b 64 FUNC WEAK DEFAULT 2 _ZN3frg8destruct[...] + 2647: 000000000803ce97 535 FUNC GLOBAL DEFAULT 2 strverscmp + 2648: 000000000805235a 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIN[...] + 2649: 0000000008041f3d 13 FUNC GLOBAL DEFAULT 2 __dlapi_entrystack + 2650: 000000000803b4a2 109 FUNC GLOBAL DEFAULT 2 strspn + 2651: 0000000008067501 55 FUNC GLOBAL DEFAULT 2 open_by_handle_at + 2652: 000000000803e16d 12 FUNC GLOBAL DEFAULT 2 wctob + 2653: 000000000806b69c 29 FUNC GLOBAL DEFAULT 2 _ZN5mlibc11cooki[...] + 2654: 0000000008052e99 53 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 2655: 000000000806ba7c 77 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIc[...] + 2656: 00000000080518f6 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA2[...] + 2657: 0000000008068158 53 FUNC GLOBAL DEFAULT 2 tempnam + 2658: 000000000802f84e 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2659: 000000000805cd9c 291 FUNC GLOBAL DEFAULT 2 daemon + 2660: 000000000805349a 41 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 2661: 000000000806605c 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2662: 0000000008056a35 83 FUNC GLOBAL DEFAULT 2 pthread_mutex_init + 2663: 0000000008027e3c 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2664: 000000000802ab13 222 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2665: 0000000008052a96 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 2666: 000000000805097e 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2667: 000000000802e07d 1900 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2668: 00000000080287f5 221 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2669: 000000000804fc78 71 FUNC WEAK HIDDEN 2 _ZNK3frg8expecte[...] + 2670: 0000000008043b16 110 FUNC WEAK HIDDEN 2 _ZN13SymbolVersi[...] + 2671: 000000000802903d 209 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2672: 0000000008041630 60 FUNC GLOBAL HIDDEN 2 strlen + 2673: 000000000805c29d 84 FUNC GLOBAL DEFAULT 2 lseek64 + 2674: 0000000008029c60 306 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 2675: 0000000008053428 113 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 2676: 00000000080569db 53 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 2677: 000000000806841f 118 FUNC WEAK DEFAULT 2 _ZN3frg9construc[...] + 2678: 000000000805173c 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRmE[...] + 2679: 0000000008067638 331 FUNC GLOBAL DEFAULT 2 open + 2680: 0000000008050014 199 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2681: 000000000804a98e 124 FUNC GLOBAL HIDDEN 2 _Z12tryAccessDtv[...] + 2682: 000000000809c008 8 OBJECT UNIQUE DEFAULT 14 _ZGVZN5mlibc12gl[...] + 2683: 0000000008061352 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2684: 0000000008051e00 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRbEONS[...] + 2685: 000000000800c662 42 FUNC WEAK DEFAULT 2 _ZN3frg10escape_[...] + 2686: 000000000809c068 8 OBJECT GLOBAL DEFAULT 14 program_invocati[...] + 2687: 0000000008049516 1015 FUNC GLOBAL HIDDEN 2 _ZN12SharedObjec[...] + 2688: 0000000008051194 82 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2689: 000000000800b81a 81 FUNC GLOBAL DEFAULT 2 toupper + 2690: 000000000800e5b7 126 FUNC GLOBAL DEFAULT 2 wprintf + 2691: 00000000080092ce 52 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2692: 000000000805dc9e 16 FUNC WEAK DEFAULT 2 _ZN5mlibc13utf8_[...] + 2693: 000000000805d7ae 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA6[...] + 2694: 0000000008051e32 26 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2695: 0000000008002989 36 FUNC GLOBAL DEFAULT 2 atoll + 2696: 00000000080617ba 18 FUNC GLOBAL DEFAULT 2 ELF32_ST_BIND + 2697: 000000000805ec26 531 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 2698: 00000000080505d4 26 FUNC WEAK HIDDEN 2 _ZN3frg7hex_fmtI[...] + 2699: 0000000008001976 72 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2700: 0000000008000325 71 FUNC GLOBAL DEFAULT 2 _ZN5mlibc9init_libcEv + 2701: 000000000805806c 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2702: 00000000080441c2 153 FUNC WEAK HIDDEN 2 _ZN3frg12basic_s[...] + 2703: 000000000800cdfd 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRPcEON[...] + 2704: 00000000080528cb 30 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple13[...] + 2705: 000000000806877e 43 FUNC WEAK DEFAULT 2 _ZN10popen_fileD0Ev + 2706: 00000000080013e4 74 FUNC WEAK HIDDEN 2 _ZN3frg13format_[...] + 2707: 000000000803bb23 57 FUNC GLOBAL DEFAULT 2 wcsxfrm + 2708: 0000000008068094 143 FUNC GLOBAL DEFAULT 2 vdprintf + 2709: 0000000008028e05 211 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2710: 0000000008051d1b 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIN3f[...] + 2711: 000000000805d8ac 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2712: 0000000008056a10 19 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 2713: 000000000805d7bc 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2714: 00000000080035db 38 FUNC GLOBAL DEFAULT 2 div + 2715: 000000000804f1be 131 FUNC WEAK HIDDEN 2 _ZN12SharedObjectD2Ev + 2716: 0000000008003598 19 FUNC GLOBAL DEFAULT 2 abs + 2717: 0000000008029c38 40 FUNC WEAK DEFAULT 2 _ZZN3frg7pop_arg[...] + 2718: 000000000802e044 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2719: 000000000803b2ee 105 FUNC GLOBAL DEFAULT 2 strchr + 2720: 0000000008050916 18 FUNC WEAK HIDDEN 2 _ZN3frg6vectorI1[...] + 2721: 000000000803f60e 26 FUNC GLOBAL HIDDEN 2 _ZN5mlibc8sys_exitEi + 2722: 0000000008052d5b 14 FUNC WEAK HIDDEN 2 _ZSt7launderIN3f[...] + 2723: 000000000804990d 557 FUNC GLOBAL HIDDEN 2 _Z21processLateR[...] + 2724: 000000000809a668 104 OBJECT WEAK DEFAULT 12 _ZTVN5mlibc18mem[...] + 2725: 0000000008006c04 193 FUNC WEAK HIDDEN 2 _ZN3frg9slab_poo[...] + 2726: 000000000803ecf4 128 FUNC GLOBAL DEFAULT 2 wcswidth + 2727: 0000000008052108 397 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2728: 0000000008051904 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 2729: 0000000008028f3e 255 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 2730: 000000000800e8f5 111 FUNC GLOBAL DEFAULT 2 fputs + 2731: 0000000008053428 113 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 2732: 0000000008058f0f 47 FUNC GLOBAL DEFAULT 2 execvp + 2733: 000000000804f8ee 52 FUNC WEAK HIDDEN 2 _ZN3frg12small_v[...] + 2734: 00000000080508f2 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2735: 0000000008007f74 618 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2736: 0000000008055610 32 FUNC GLOBAL DEFAULT 2 pthread_attr_set[...] + 2737: 000000000803f65c 101 FUNC GLOBAL HIDDEN 2 _ZN5mlibc17sys_a[...] + 2738: 000000000803edd7 163 FUNC GLOBAL DEFAULT 2 wcsncasecmp + 2739: 000000000802c2ad 221 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2740: 0000000008002782 40 FUNC WEAK HIDDEN 2 _ZN3frg3maxIiEER[...] + 2741: 000000000805afc7 118 FUNC GLOBAL DEFAULT 2 setsid + 2742: 000000000802a7bd 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2743: 00000000080687a9 71 FUNC WEAK DEFAULT 2 _ZN3frg8destruct[...] + 2744: 000000000805ac40 143 FUNC GLOBAL DEFAULT 2 setegid + 2745: 0000000008050752 259 FUNC WEAK HIDDEN 2 _ZN3frg8hash_map[...] + 2746: 0000000008044908 77 FUNC WEAK HIDDEN 2 _ZN3frg6vectorIP[...] + 2747: 000000000804190d 62 FUNC GLOBAL DEFAULT 2 __rtld_allocateTcb + 2748: 00000000080504ce 39 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2749: 0000000008009662 214 FUNC WEAK HIDDEN 2 _ZZN3frg11_fmt_b[...] + 2750: 0000000008064dc2 644 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7fd_fil[...] + 2751: 0000000008040994 26 FUNC WEAK HIDDEN 2 _ZN3frg14slab_al[...] + 2752: 0000000008031f0c 1135 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2753: 000000000804f80e 101 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJi[...] + 2754: 000000000802db23 221 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2755: 0000000008006ac0 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 2756: 00000000080666bb 32 FUNC GLOBAL DEFAULT 2 closedir + 2757: 000000000803f5b4 90 FUNC GLOBAL HIDDEN 2 _ZN5mlibc8sys_re[...] + 2758: 00000000080010e0 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA9[...] + 2759: 0000000008052318 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 2760: 0000000008061478 59 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2761: 000000000803fa09 56 FUNC GLOBAL HIDDEN 2 __do_syscall5 + 2762: 0000000008030b24 1116 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2763: 000000000800ec43 49 FUNC GLOBAL DEFAULT 2 fgetwc + 2764: 000000000800e40c 57 FUNC GLOBAL DEFAULT 2 vfwscanf + 2765: 0000000008000c26 46 FUNC WEAK HIDDEN 2 _ZN3frg19stack_b[...] + 2766: 000000000801d246 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2767: 0000000008028cfa 267 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 2768: 0000000008043bc6 26 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJ1[...] + 2769: 000000000806865c 45 FUNC WEAK DEFAULT 2 _ZN5mlibc8mem_fi[...] + 2770: 000000000805172e 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIP5S[...] + 2771: 0000000008000b16 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2772: 000000000806bc6e 28 FUNC WEAK DEFAULT 2 _ZNK3frg4spanIcEixEm + 2773: 0000000008009302 864 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2774: 0000000008060e0f 71 FUNC WEAK DEFAULT 2 _ZSt3getILm1EJmc[...] + 2775: 000000000809b5f0 24 OBJECT GLOBAL DEFAULT 14 _ZN5mlibc11entry[...] + 2776: 000000000805cc4b 36 FUNC GLOBAL DEFAULT 2 setusershell + 2777: 000000000800a068 66 FUNC WEAK HIDDEN 2 _ZN3frg6formatIA[...] + 2778: 0000000008061851 15 FUNC GLOBAL DEFAULT 2 ELF32_R_TYPE + 2779: 0000000008055ad7 163 FUNC GLOBAL DEFAULT 2 pthread_getname_np + 2780: 000000000809a5a8 88 OBJECT WEAK DEFAULT 12 _ZTVN5mlibc11coo[...] + 2781: 0000000008061306 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2782: 0000000008044638 109 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2783: 000000000800f435 267 FUNC GLOBAL DEFAULT 2 vasprintf + 2784: 00000000080553cf 47 FUNC GLOBAL DEFAULT 2 pthread_attr_set[...] + 2785: 00000000080505d4 26 FUNC WEAK HIDDEN 2 _ZN3frg7hex_fmtI[...] + 2786: 0000000008022b6c 476 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2787: 000000000800e7d7 75 FUNC GLOBAL DEFAULT 2 fputc_unlocked + 2788: 0000000008006b10 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2789: 000000000803b728 92 FUNC GLOBAL DEFAULT 2 strchrnul + 2790: 00000000080682b4 20 FUNC WEAK DEFAULT 2 _ZN10popen_file1[...] + 2791: 000000000801ddee 457 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2792: 000000000804478e 128 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2793: 000000000805349a 41 FUNC WEAK HIDDEN 2 _ZN3frg6_tuple7s[...] + 2794: 0000000008044c7c 14 FUNC WEAK HIDDEN 2 _ZSt4moveIRP12Sh[...] + 2795: 0000000008061842 15 FUNC GLOBAL DEFAULT 2 ELF32_R_SYM + 2796: 00000000080629d6 334 FUNC GLOBAL DEFAULT 2 _ZN5mlibc19threa[...] + 2797: 0000000008046372 847 FUNC GLOBAL HIDDEN 2 _ZN16ObjectRepos[...] + 2798: 0000000008028938 267 FUNC WEAK DEFAULT 2 _ZN3frg7pop_argI[...] + 2799: 000000000806708c 297 FUNC GLOBAL DEFAULT 2 fcntl + 2800: 0000000008000e54 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2801: 000000000800876c 111 FUNC WEAK HIDDEN 2 _ZN3frg9_redblac[...] + 2802: 0000000008060fd2 84 FUNC WEAK DEFAULT 2 _ZN3frg8optional[...] + 2803: 0000000008005601 1055 FUNC WEAK DEFAULT 2 _ZN5mlibc15strin[...] + 2804: 0000000008025212 453 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2805: 0000000008055878 37 FUNC GLOBAL DEFAULT 2 pthread_join + 2806: 000000000801397c 42 FUNC WEAK DEFAULT 2 _ZN11PrintfAgent[...] + 2807: 000000000805b03d 203 FUNC GLOBAL DEFAULT 2 setuid + 2808: 000000000805a185 148 FUNC GLOBAL DEFAULT 2 getpgid + 2809: 00000000080614f0 59 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2810: 00000000080179a2 51 FUNC WEAK DEFAULT 2 _ZN3frg12basic_s[...] + 2811: 0000000008024e7e 457 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2812: 000000000805eef8 218 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 2813: 000000000806a264 168 FUNC GLOBAL DEFAULT 2 timer_settime + 2814: 000000000805f2ee 187 FUNC GLOBAL DEFAULT 2 _ZN5mlibc7charse[...] + 2815: 0000000008061812 16 FUNC GLOBAL DEFAULT 2 ELF64_R_TYPE + 2816: 0000000008036d34 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2817: 000000000803a332 214 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2818: 0000000008059fa0 41 FUNC GLOBAL DEFAULT 2 gethostid + 2819: 000000000803166c 208 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2820: 0000000008067f08 114 FUNC GLOBAL DEFAULT 2 fseeko64 + 2821: 0000000008056e53 45 FUNC GLOBAL DEFAULT 2 pthread_cond_tim[...] + 2822: 000000000806a035 34 FUNC GLOBAL DEFAULT 2 timerclear + 2823: 0000000008002c3c 160 FUNC GLOBAL DEFAULT 2 aligned_alloc + 2824: 000000000806bd00 238 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIc[...] + 2825: 000000000806a83b 159 FUNC GLOBAL DEFAULT 2 tcsetattr + 2826: 0000000008057cc2 319 FUNC WEAK DEFAULT 2 _ZN10ScopeTraceC[...] + 2827: 0000000008049498 125 FUNC GLOBAL HIDDEN 2 _ZN12SharedObjec[...] + 2828: 000000000803fba5 74 FUNC GLOBAL HIDDEN 2 __cxa_guard_acquire + 2829: 00000000080697e2 154 FUNC GLOBAL DEFAULT 2 mkdir + 2830: 0000000008003e5d 209 FUNC GLOBAL DEFAULT 2 posix_memalign + 2831: 000000000800bac4 135 FUNC WEAK HIDDEN 2 _ZNK3frg17basic_[...] + 2832: 0000000008067450 177 FUNC GLOBAL DEFAULT 2 name_to_handle_at + 2833: 00000000080663f6 43 FUNC WEAK DEFAULT 2 _ZN5mlibc7fd_fileD0Ev + 2834: 0000000008007702 50 FUNC WEAK HIDDEN 2 _ZN3frg11unique_[...] + 2835: 000000000806314a 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2836: 00000000080233f2 423 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2837: 0000000008051e0e 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2838: 000000000802d8ec 211 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2839: 0000000008051db0 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRA3[...] + 2840: 000000000803e40e 270 FUNC GLOBAL DEFAULT 2 wcrtomb + 2841: 0000000008060ded 34 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2842: 000000000806152c 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2843: 000000000805d89e 14 FUNC WEAK DEFAULT 2 _ZSt7forwardIRA8[...] + 2844: 000000000805a9a3 177 FUNC GLOBAL DEFAULT 2 pwrite + 2845: 0000000008051d29 69 FUNC WEAK HIDDEN 2 _ZN3frg6formatIN[...] + 2846: 000000000805c2f1 65 FUNC GLOBAL DEFAULT 2 close + 2847: 000000000806b94e 102 FUNC WEAK DEFAULT 2 _ZN5mlibc8mem_fi[...] + 2848: 000000000805d99c 66 FUNC WEAK DEFAULT 2 _ZN3frg6formatIA[...] + 2849: 0000000008056a23 18 FUNC GLOBAL DEFAULT 2 pthread_mutexatt[...] + 2850: 0000000008057ed8 52 FUNC WEAK DEFAULT 2 _ZN3frg8destruct[...] + 2851: 00000000080042e2 16 FUNC WEAK DEFAULT 2 _ZN5mlibc10int_l[...] + 2852: 0000000008012fde 38 FUNC WEAK DEFAULT 2 _ZN13StreamPrint[...] + 2853: 0000000008026c3a 423 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2854: 00000000080555f0 32 FUNC GLOBAL DEFAULT 2 pthread_attr_get[...] + 2855: 000000000801bf5e 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2856: 0000000008057f0c 32 FUNC WEAK DEFAULT 2 _ZN3frg5arrayIN3[...] + 2857: 000000000800c8bc 52 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 2858: 000000000804ffe0 26 FUNC WEAK HIDDEN 2 _ZN3frg5tupleIJK[...] + 2859: 0000000008051fdf 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRtE[...] + 2860: 0000000008029f54 57 FUNC WEAK DEFAULT 2 _ZZN3frg11_fmt_b[...] + 2861: 0000000008003774 680 FUNC GLOBAL DEFAULT 2 mbtowc + 2862: 0000000008000e78 26 FUNC WEAK HIDDEN 2 _ZNK3frg8optiona[...] + 2863: 0000000008043c14 109 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2864: 0000000008066eef 49 FUNC GLOBAL DEFAULT 2 telldir + 2865: 000000000800c738 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2866: 00000000080683f9 38 FUNC WEAK DEFAULT 2 _ZN5mlibc15file_[...] + 2867: 000000000805d42e 52 FUNC WEAK DEFAULT 2 _ZN3frg19stack_b[...] + 2868: 0000000008060e56 21 FUNC WEAK DEFAULT 2 _ZNKSt7variantIJ[...] + 2869: 0000000008051ad5 14 FUNC WEAK HIDDEN 2 _ZSt7forwardIRP5[...] + 2870: 0000000008049b3a 1406 FUNC GLOBAL HIDDEN 2 _Z22processLateR[...] + 2871: 0000000008067808 94 FUNC GLOBAL DEFAULT 2 fmemopen + 2872: 000000000804ee6a 78 FUNC WEAK HIDDEN 2 _ZN13SymbolVersi[...] + 2873: 000000000805011c 26 FUNC WEAK HIDDEN 2 _ZN3frg5stackIP1[...] + 2874: 000000000800dd21 312 FUNC GLOBAL DEFAULT 2 vfprintf + 2875: 000000000800ccfe 255 FUNC WEAK DEFAULT 2 _ZN3frg6vectorIP[...] + 2876: 000000000801abfc 430 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2877: 000000000809c068 8 OBJECT WEAK DEFAULT 14 __progname_full + 2878: 000000000803b3c4 110 FUNC GLOBAL DEFAULT 2 strpbrk + 2879: 000000000805bb02 40 FUNC GLOBAL DEFAULT 2 tcsetpgrp + 2880: 00000000080565cc 267 FUNC GLOBAL DEFAULT 2 pthread_setspecific + 2881: 0000000008060e6b 34 FUNC WEAK DEFAULT 2 _ZSt3getImJmcSt9[...] + 2882: 000000000801fd51 2864 FUNC WEAK DEFAULT 2 _ZN3frg14do_prin[...] + 2883: 0000000008051c7e 35 FUNC WEAK HIDDEN 2 _ZN3frg8optional[...] + 2884: 000000000800ccc6 42 FUNC WEAK HIDDEN 2 _ZN3frg17basic_s[...] + 2885: 000000000801b84c 480 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2886: 000000000800ecac 52 FUNC GLOBAL DEFAULT 2 fputwc + 2887: 000000000800d1e1 190 FUNC GLOBAL DEFAULT 2 raise + 2888: 0000000008061352 38 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2889: 000000000805e4c0 279 FUNC WEAK DEFAULT 2 _ZN5mlibc28polym[...] + 2890: 000000000806a60a 151 FUNC GLOBAL DEFAULT 2 tcflow + 2891: 0000000008063aca 1177 FUNC GLOBAL DEFAULT 2 _ZN5mlibc13abstr[...] + 2892: 0000000008003bdb 250 FUNC GLOBAL DEFAULT 2 free + 2893: 0000000008029485 1900 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2894: 000000000809c420 104 OBJECT GLOBAL HIDDEN 14 libraryPaths + 2895: 000000000800d29f 162 FUNC GLOBAL DEFAULT 2 sigprocmask + 2896: 000000000800430f 16 FUNC WEAK DEFAULT 2 _ZN5mlibc10int_l[...] + 2897: 0000000008007734 39 FUNC WEAK HIDDEN 2 _ZN3frg11unique_[...] + 2898: 000000000804b6ae 383 FUNC GLOBAL HIDDEN 2 _ZN5Scope20resol[...] + 2899: 000000000803e179 64 FUNC GLOBAL DEFAULT 2 mbsinit + 2900: 000000000800ba62 48 FUNC WEAK DEFAULT 2 _ZN5mlibc18gener[...] + 2901: 0000000008026a90 426 FUNC WEAK DEFAULT 2 _ZZN3frg14do_pri[...] + 2902: 000000000803cdc8 62 FUNC GLOBAL DEFAULT 2 __gnu_strerror_r + 2903: 000000000803312c 1110 FUNC WEAK DEFAULT 2 _ZN3frg11_fmt_ba[...] + 2904: 0000000008061682 51 FUNC WEAK DEFAULT 2 _ZNSt8__detail9_[...] + 2905: 00000000080596af 154 FUNC GLOBAL DEFAULT 2 ftruncate64 + 2906: 00000000080519f0 72 FUNC WEAK HIDDEN 2 _ZN3frg10manual_[...] + 2907: 000000000804f1be 131 FUNC WEAK HIDDEN 2 _ZN12SharedObjectD1Ev + +readelf -s init.elf + +Symbol table '.symtab' contains 5 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS init.c + 2: 00000000004002cc 0 NOTYPE GLOBAL DEFAULT 1 _start + 3: 0000000000400040 652 FUNC GLOBAL DEFAULT 1 main + 4: 0000000000400000 43 FUNC GLOBAL DEFAULT 1 strlen diff --git a/ext2_root/usr/include/abi-bits/access.h b/ext2_root/usr/include/abi-bits/access.h new file mode 100644 index 0000000..56b3ac0 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +#endif /* _ABIBITS_ACCESS_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/auxv.h b/ext2_root/usr/include/abi-bits/auxv.h new file mode 100755 index 0000000..819b386 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/auxv.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_PLATFORM 15 +#define AT_HWCAP 16 +#define AT_CLKTCK 17 +#define AT_FPUCW 18 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_HWCAP2 26 +#define AT_HWCAP3 29 +#define AT_HWCAP4 30 +#define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 + +#endif /* _ABIBITS_AUXV_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/blkcnt_t.h b/ext2_root/usr/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..b104f7e --- /dev/null +++ b/ext2_root/usr/include/abi-bits/blkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +#include + +typedef __mlibc_int64 blkcnt_t; + +#endif /* _ABIBITS_BLKCNT_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/blksize_t.h b/ext2_root/usr/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..a65f69d --- /dev/null +++ b/ext2_root/usr/include/abi-bits/blksize_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +typedef long blksize_t; + +#endif /* _ABIBITS_BLKSIZE_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/clockid_t.h b/ext2_root/usr/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..90466dd --- /dev/null +++ b/ext2_root/usr/include/abi-bits/clockid_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef int clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/dev_t.h b/ext2_root/usr/include/abi-bits/dev_t.h new file mode 100755 index 0000000..ca2f7bd --- /dev/null +++ b/ext2_root/usr/include/abi-bits/dev_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +#include + +typedef __mlibc_uint64 dev_t; + +#endif /* _ABIBITS_DEV_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/errno.h b/ext2_root/usr/include/abi-bits/errno.h new file mode 100755 index 0000000..61bf847 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/errno.h @@ -0,0 +1,143 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EWOULDBLOCK EAGAIN +#define ENOMSG 42 +#define EIDRM 43 +#define ECHRNG 44 +#define EL2NSYNC 45 +#define EL3HLT 46 +#define EL3RST 47 +#define ELNRNG 48 +#define EUNATCH 49 +#define ENOCSI 50 +#define EL2HLT 51 +#define EBADE 52 +#define EBADR 53 +#define EXFULL 54 +#define ENOANO 55 +#define EBADRQC 56 +#define EBADSLT 57 +#define EDEADLOCK EDEADLK +#define EBFONT 59 +#define ENOSTR 60 +#define ENODATA 61 +#define ETIME 62 +#define ENOSR 63 +#define ENONET 64 +#define ENOPKG 65 +#define EREMOTE 66 +#define ENOLINK 67 +#define EADV 68 +#define ESRMNT 69 +#define ECOMM 70 +#define EPROTO 71 +#define EMULTIHOP 72 +#define EDOTDOT 73 +#define EBADMSG 74 +#define EOVERFLOW 75 +#define ENOTUNIQ 76 +#define EBADFD 77 +#define EREMCHG 78 +#define ELIBACC 79 +#define ELIBBAD 80 +#define ELIBSCN 81 +#define ELIBMAX 82 +#define ELIBEXEC 83 +#define EILSEQ 84 +#define ERESTART 85 +#define ESTRPIPE 86 +#define EUSERS 87 +#define ENOTSOCK 88 +#define EDESTADDRREQ 89 +#define EMSGSIZE 90 +#define EPROTOTYPE 91 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP 95 +#define ENOTSUP EOPNOTSUPP +#define EPFNOSUPPORT 96 +#define EAFNOSUPPORT 97 +#define EADDRINUSE 98 +#define EADDRNOTAVAIL 99 +#define ENETDOWN 100 +#define ENETUNREACH 101 +#define ENETRESET 102 +#define ECONNABORTED 103 +#define ECONNRESET 104 +#define ENOBUFS 105 +#define EISCONN 106 +#define ENOTCONN 107 +#define ESHUTDOWN 108 +#define ETOOMANYREFS 109 +#define ETIMEDOUT 110 +#define ECONNREFUSED 111 +#define EHOSTDOWN 112 +#define EHOSTUNREACH 113 +#define EALREADY 114 +#define EINPROGRESS 115 +#define ESTALE 116 +#define EUCLEAN 117 +#define ENOTNAM 118 +#define ENAVAIL 119 +#define EISNAM 120 +#define EREMOTEIO 121 +#define EDQUOT 122 +#define ENOMEDIUM 123 +#define EMEDIUMTYPE 124 +#define ECANCELED 125 +#define ENOKEY 126 +#define EKEYEXPIRED 127 +#define EKEYREVOKED 128 +#define EKEYREJECTED 129 +#define EOWNERDEAD 130 +#define ENOTRECOVERABLE 131 +#define ERFKILL 132 +#define EHWPOISON 133 + + +/* This is mlibc-specific. */ +#define EIEIO 4095 + +#endif /* _ABIBITS_ERRNO_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/fcntl.h b/ext2_root/usr/include/abi-bits/fcntl.h new file mode 100755 index 0000000..bcee906 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/fcntl.h @@ -0,0 +1,124 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +#include +#include + +#define O_PATH 010000000 + +#define O_ACCMODE (03 | O_PATH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_LARGEFILE 0100000 +#define O_NOATIME 01000000 +#define O_TMPFILE 020000000 + +#define O_EXEC O_PATH +#define O_SEARCH O_PATH + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLK64 F_SETLK +#define F_SETLKW 7 +#define F_SETLKW64 F_SETLKW + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 + +#define F_SETLEASE 1024 +#define F_GETLEASE 1025 +#define F_NOTIFY 1026 +#define F_DUPFD_CLOEXEC 1030 +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define F_SEAL_SEAL 0x0001 +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 + +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define FD_CLOEXEC 1 + +#define AT_FDCWD -100 +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 +#define AT_NO_AUTOMOUNT 0x800 +#define AT_EMPTY_PATH 0x1000 + +#if __MLIBC_LINUX_OPTION + +#define DN_ACCESS 1 +#define DN_MODIFY 2 +#define DN_CREATE 4 +#define DN_DELETE 8 +#define DN_RENAME 16 +#define DN_ATTRIB 32 +#define DN_MULTISHOT 0x80000000 + +#define AT_STATX_SYNC_AS_STAT 0x0000 +#define AT_STATX_FORCE_SYNC 0x2000 +#define AT_STATX_DONT_SYNC 0x4000 +#define AT_STATX_SYNC_TYPE 0x6000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#if defined(_GNU_SOURCE) +struct f_owner_ex { + int type; + pid_t pid; +}; +#endif /* _GNU_SOURCE */ + +#define F_OWNER_TID 0 +#define F_OWNER_PID 1 +#define F_OWNER_PGRP 2 + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 + +#endif /* _ABIBITS_FCNTL_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/fd_set.h b/ext2_root/usr/include/abi-bits/fd_set.h new file mode 100644 index 0000000..dbbcdba --- /dev/null +++ b/ext2_root/usr/include/abi-bits/fd_set.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_FD_SET_H +#define _ABIBITS_FD_SET_H + +#include + +#define FD_SETSIZE 1024 + +typedef struct __attribute__((__aligned__(__alignof__(long)))) { + __mlibc_uint8 fds_bits[128]; +} fd_set; + +#endif /* _ABIBITS_FD_SET_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/fsblkcnt_t.h b/ext2_root/usr/include/abi-bits/fsblkcnt_t.h new file mode 100644 index 0000000..ecb5ca4 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSBLKCNT_T_H +#define _ABIBITS_FSBLKCNT_T_H + +#include + +typedef __mlibc_uint64 fsblkcnt_t; + +#endif /* _ABIBITS_FSBLKCNT_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/fsfilcnt_t.h b/ext2_root/usr/include/abi-bits/fsfilcnt_t.h new file mode 100644 index 0000000..d7e3cb6 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSFILCNT_T_H +#define _ABIBITS_FSFILCNT_T_H + +#include + +typedef __mlibc_uint64 fsfilcnt_t; + +#endif /* _ABIBITS_FSFILCNT_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/gid_t.h b/ext2_root/usr/include/abi-bits/gid_t.h new file mode 100755 index 0000000..b6cf2fa --- /dev/null +++ b/ext2_root/usr/include/abi-bits/gid_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif /* _ABIBITS_GID_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/in.h b/ext2_root/usr/include/abi-bits/in.h new file mode 100644 index 0000000..5b48c31 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/in.h @@ -0,0 +1,235 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t sin_zero[8]; +}; + +#if !__MLIBC_LINUX_OPTION || (!defined(_UAPI_LINUX_IN6_H) && !defined(_UAPI_IPV6_H)) +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; +#endif /* !__MLIBC_LINUX_OPTION || (!defined(_UAPI_LINUX_IN6_H) && !defined(_UAPI_IPV6_H)) */ + +#define MCAST_INCLUDE 1 + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_req { + uint32_t gr_interface; + struct sockaddr_storage gr_group; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#define INADDR_ANY ((in_addr_t) 0x00000000) +#define INADDR_BROADCAST ((in_addr_t) 0xffffffff) +#define INADDR_NONE ((in_addr_t) 0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t) 0x7f000001) + +#define INADDR_UNSPEC_GROUP ((in_addr_t) 0xe0000000) +#define INADDR_ALLHOSTS_GROUP ((in_addr_t) 0xe0000001) +#define INADDR_ALLRTRS_GROUP ((in_addr_t) 0xe0000002) +#define INADDR_ALLSNOOPERS_GROUP ((in_addr_t) 0xe000006a) +#define INADDR_MAX_LOCAL_GROUP ((in_addr_t) 0xe00000ff) + +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + +#define IPPORT_RESERVED 1024 + +#define IPPROTO_IP 0 +#define IPPROTO_HOPOPTS 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_IGMP 2 +#define IPPROTO_IPIP 4 +#define IPPROTO_TCP 6 +#define IPPROTO_EGP 8 +#define IPPROTO_PUP 12 +#define IPPROTO_UDP 17 +#define IPPROTO_IDP 22 +#define IPPROTO_TP 29 +#define IPPROTO_DCCP 33 +#define IPPROTO_IPV6 41 +#define IPPROTO_ROUTING 43 +#define IPPROTO_FRAGMENT 44 +#define IPPROTO_RSVP 46 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_NONE 59 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_MTP 92 +#define IPPROTO_BEETPH 94 +#define IPPROTO_ENCAP 98 +#define IPPROTO_PIM 103 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_MH 135 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MPLS 137 +#define IPPROTO_RAW 255 +#define IPPROTO_MAX 256 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_HDRINCL 3 +#define IP_OPTIONS 4 +#define IP_RECVOPTS 6 +#define IP_RETOPTS 7 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_MTU 14 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define IP_UNICAST_IF 50 + +#define IPV6_2292PKTOPTIONS 6 +#define IPV6_2292HOPLIMIT 8 +#define IPV6_UNICAST_HOPS 16 +#define IPV6_MULTICAST_IF 17 +#define IPV6_MULTICAST_HOPS 18 +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_JOIN_GROUP 20 +#define IPV6_LEAVE_GROUP 21 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_MTU 24 +#define IPV6_RECVERR 25 +#define IPV6_V6ONLY 26 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 + +#define IPV6_RECVTCLASS 66 +#define IPV6_TCLASS 67 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#define IPV6_PMTUDISC_DONT 0 +#define IPV6_PMTUDISC_WANT 1 +#define IPV6_PMTUDISC_DO 2 +#define IPV6_PMTUDISC_PROBE 3 +#define IPV6_PMTUDISC_INTERFACE 4 +#define IPV6_PMTUDISC_OMIT 5 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_WANT 1 +#define IP_PMTUDISC_DO 2 +#define IP_PMTUDISC_PROBE 3 +#define IP_PMTUDISC_INTERFACE 4 +#define IP_PMTUDISC_OMIT 5 + +#define MCAST_JOIN_GROUP 42 +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#if __MLIBC_LINUX_OPTION + +#define __UAPI_DEF_IN_ADDR 0 +#define __UAPI_DEF_IN_CLASS 0 +#define __UAPI_DEF_IN_IPPROTO 0 +#define __UAPI_DEF_IN_PKTINFO 0 +#define __UAPI_DEF_IP_MREQ 0 +#define __UAPI_DEF_SOCKADDR_IN 0 + +#define __UAPI_DEF_IN6_ADDR 0 +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#define __UAPI_DEF_IN6_PKTINFO 0 +#define __UAPI_DEF_IP6_MTUINFO 0 +#define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_MREQ 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 +#define __UAPI_DEF_SOCKADDR_IN6 0 + +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABITBITS_IN_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/ino_t.h b/ext2_root/usr/include/abi-bits/ino_t.h new file mode 100755 index 0000000..b76b8b7 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/ino_t.h @@ -0,0 +1,10 @@ + +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +#include + +typedef __mlibc_uint64 ino_t; +typedef ino_t ino64_t; + +#endif /* _ABIBITS_INO_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/ipc.h b/ext2_root/usr/include/abi-bits/ipc.h new file mode 100644 index 0000000..09d3f80 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/ipc.h @@ -0,0 +1,50 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + int __ipc_perm_seq; + long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/limits.h b/ext2_root/usr/include/abi-bits/limits.h new file mode 100755 index 0000000..472b3ec --- /dev/null +++ b/ext2_root/usr/include/abi-bits/limits.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 +#define LOGIN_NAME_MAX 256 +#define HOST_NAME_MAX 64 +#define NAME_MAX 255 +#define OPEN_MAX 256 + +#endif /*_ABIBITS_LIMITS_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/mode_t.h b/ext2_root/usr/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5f6fb06 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/mode_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef unsigned int mode_t; + +#endif /* _ABIBITS_MODE_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/mqueue.h b/ext2_root/usr/include/abi-bits/mqueue.h new file mode 100644 index 0000000..18596db --- /dev/null +++ b/ext2_root/usr/include/abi-bits/mqueue.h @@ -0,0 +1,20 @@ +#ifndef _ABIBITS_MQUEUE_H +#define _ABIBITS_MQUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct mq_attr { + long mq_flags; + long mq_maxmsg; + long mq_msgsize; + long mq_curmsgs; + long __pad[4]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MQUEUE_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/msg.h b/ext2_root/usr/include/abi-bits/msg.h new file mode 100644 index 0000000..a9aa285 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/msg.h @@ -0,0 +1,44 @@ +#ifndef _ABIBITS_MSG_H +#define _ABIBITS_MSG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long msglen_t; +typedef unsigned long msgqnum_t; + +struct msqid64_ds { + struct ipc64_perm msg_perm; +#if (UINTPTR_MAX == UINT64_MAX) /* || x32 ABI */ + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; +#else + unsigned long msg_stime; + unsigned long msg_stime_high; + unsigned long msg_rtime; + unsigned long msg_rtime_high; + unsigned long msg_ctime; + unsigned long msg_ctime_high; +#endif + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; +}; + +#define msqid_ds msqid64_ds + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MSG_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/nlink_t.h b/ext2_root/usr/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..c9d4d45 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/nlink_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef unsigned long nlink_t; + +#endif /* _ABIBITS_NLINK_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/pid_t.h b/ext2_root/usr/include/abi-bits/pid_t.h new file mode 100755 index 0000000..b7e8ec7 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/pid_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif /* _ABIBITS_PID_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/poll.h b/ext2_root/usr/include/abi-bits/poll.h new file mode 100644 index 0000000..8a31198 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 +#define POLLRDNORM 0x0040 +#define POLLRDBAND 0x0080 +#define POLLWRNORM 0x0100 +#define POLLWRBAND 0x0200 +#define POLLRDHUP 0x2000 + +#endif /* _ABIBITS_POLL_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/resource.h b/ext2_root/usr/include/abi-bits/resource.h new file mode 100644 index 0000000..46f7a12 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/resource.h @@ -0,0 +1,54 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN -1 + +#define RLIMIT_CPU 0 +#define RLIMIT_FSIZE 1 +#define RLIMIT_DATA 2 +#define RLIMIT_STACK 3 +#define RLIMIT_CORE 4 +#define RLIMIT_RSS 5 +#define RLIMIT_NPROC 6 +#define RLIMIT_NOFILE 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_AS 9 +#define RLIMIT_LOCKS 10 +#define RLIMIT_SIGPENDING 11 +#define RLIMIT_MSGQUEUE 12 +#define RLIMIT_NICE 13 +#define RLIMIT_RTPRIO 14 +#define RLIMIT_RTTIME 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RESOURCE_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/riscv-hwprobe.h b/ext2_root/usr/include/abi-bits/riscv-hwprobe.h new file mode 100644 index 0000000..fc7fdee --- /dev/null +++ b/ext2_root/usr/include/abi-bits/riscv-hwprobe.h @@ -0,0 +1,107 @@ +#ifndef _ABIBITS_RISCV_HWPROBE_H +#define _ABIBITS_RISCV_HWPROBE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct riscv_hwprobe { + signed long long int key; + unsigned long long int value; +}; + +#define RISCV_HWPROBE_KEY_MVENDORID 0 +#define RISCV_HWPROBE_KEY_MARCHID 1 +#define RISCV_HWPROBE_KEY_MIMPID 2 +#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3 +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0) +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 +#define RISCV_HWPROBE_IMA_FD (1 << 0) +#define RISCV_HWPROBE_IMA_C (1 << 1) +#define RISCV_HWPROBE_IMA_V (1 << 2) +#define RISCV_HWPROBE_EXT_ZBA (1 << 3) +#define RISCV_HWPROBE_EXT_ZBB (1 << 4) +#define RISCV_HWPROBE_EXT_ZBS (1 << 5) +#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) +#define RISCV_HWPROBE_EXT_ZBC (1 << 7) +#define RISCV_HWPROBE_EXT_ZBKB (1 << 8) +#define RISCV_HWPROBE_EXT_ZBKC (1 << 9) +#define RISCV_HWPROBE_EXT_ZBKX (1 << 10) +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#define RISCV_HWPROBE_EXT_ZKNH (1 << 13) +#define RISCV_HWPROBE_EXT_ZKSED (1 << 14) +#define RISCV_HWPROBE_EXT_ZKSH (1 << 15) +#define RISCV_HWPROBE_EXT_ZKT (1 << 16) +#define RISCV_HWPROBE_EXT_ZVBB (1 << 17) +#define RISCV_HWPROBE_EXT_ZVBC (1 << 18) +#define RISCV_HWPROBE_EXT_ZVKB (1 << 19) +#define RISCV_HWPROBE_EXT_ZVKG (1 << 20) +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22) +#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23) +#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24) +#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25) +#define RISCV_HWPROBE_EXT_ZVKT (1 << 26) +#define RISCV_HWPROBE_EXT_ZFH (1 << 27) +#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) +#define RISCV_HWPROBE_EXT_ZVFH (1 << 30) +#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31) +#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) +#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) +#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) +#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) +#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36) +#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37) +#define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38) +#define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39) +#define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40) +#define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41) +#define RISCV_HWPROBE_EXT_ZIMOP (1ULL << 42) +#define RISCV_HWPROBE_EXT_ZCA (1ULL << 43) +#define RISCV_HWPROBE_EXT_ZCB (1ULL << 44) +#define RISCV_HWPROBE_EXT_ZCD (1ULL << 45) +#define RISCV_HWPROBE_EXT_ZCF (1ULL << 46) +#define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47) +#define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48) +#define RISCV_HWPROBE_EXT_SUPM (1ULL << 49) +#define RISCV_HWPROBE_EXT_ZICNTR (1ULL << 50) +#define RISCV_HWPROBE_EXT_ZIHPM (1ULL << 51) +#define RISCV_HWPROBE_EXT_ZFBFMIN (1ULL << 52) +#define RISCV_HWPROBE_EXT_ZVFBFMIN (1ULL << 53) +#define RISCV_HWPROBE_EXT_ZVFBFWMA (1ULL << 54) +#define RISCV_HWPROBE_EXT_ZICBOM (1ULL << 55) +#define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) +#define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) +#define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58) +#define RISCV_HWPROBE_KEY_CPUPERF_0 5 +#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) +#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) +#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0) +#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) +#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) +#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7 +#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8 +#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0 11 +#define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE 12 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0 13 + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RISCV_HWPROBE_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/rlim_t.h b/ext2_root/usr/include/abi-bits/rlim_t.h new file mode 100644 index 0000000..7a13862 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/rlim_t.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +#if __INTPTR_WIDTH__ == 32 +typedef unsigned long long int rlim_t; +#else +typedef unsigned long int rlim_t; +#endif + +#endif /* _ABIBITS_RLIM_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/sa_family_t.h b/ext2_root/usr/include/abi-bits/sa_family_t.h new file mode 100644 index 0000000..7775dfd --- /dev/null +++ b/ext2_root/usr/include/abi-bits/sa_family_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_SA_FAMILY_T_H +#define _ABIBITS_SA_FAMILY_T_H + +typedef unsigned short sa_family_t; + +#endif /* _ABIBITS_SA_FAMILY_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/seek-whence.h b/ext2_root/usr/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..c0a13c0 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/seek-whence.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_DATA 3 +#define SEEK_HOLE 4 + +#endif /* _ABIBITS_SEEK_WHENCE_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/sem.h b/ext2_root/usr/include/abi-bits/sem.h new file mode 100644 index 0000000..85dae90 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/sem.h @@ -0,0 +1,30 @@ +#ifndef _ABIBITS_SEM_H +#define _ABIBITS_SEM_H + +#include +#include + +#define GETPID 11 +#define GETVAL 12 +#define GETALL 13 +#define SETVAL 16 +#define SETALL 17 + +#define SEM_UNDO 0x1000 + +struct sembuf { + unsigned short int sem_num; + short int sem_op; + short int sem_flg; +}; + +struct semid_ds { + struct ipc_perm sem_perm; + time_t sem_otime; + time_t sem_ctime; + + unsigned long sem_nsems; + unsigned long __unused[2]; +}; + +#endif /* _ABIBITS_SEM_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/shm.h b/ext2_root/usr/include/abi-bits/shm.h new file mode 100755 index 0000000..5f32528 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/shm.h @@ -0,0 +1,107 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +#if defined(__i386__) || defined(__m68k__) +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + unsigned long __shm_atime_lo; + unsigned long __shm_atime_hi; + unsigned long __shm_dtime_lo; + unsigned long __shm_dtime_hi; + unsigned long __shm_ctime_lo; + unsigned long __shm_ctime_hi; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __unused[3]; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; +}; +#elif defined(__x86_64__) || defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __unused[2]; +}; +#else +#error "Missing architecture specific code." +#endif + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/sig-limits.h b/ext2_root/usr/include/abi-bits/sig-limits.h new file mode 100644 index 0000000..ab4ef8c --- /dev/null +++ b/ext2_root/usr/include/abi-bits/sig-limits.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_SIG_LIMITS_H +#define _ABIBITS_SIG_LIMITS_H + +#include + +#define NSIG_MAX 1024 + +#if defined(_DEFAULT_SOURCE) || __MLIBC_XOPEN +#define NZERO 20 +#endif /* defined(_DEFAULT_SOURCE) || __MLIBC_XOPEN */ + +#endif /*_ABIBITS_SIG_LIMITS_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/sigevent.h b/ext2_root/usr/include/abi-bits/sigevent.h new file mode 100755 index 0000000..ab836d4 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/sigevent.h @@ -0,0 +1,24 @@ +#ifndef _ABIBITS_SIGEVENT_H +#define _ABIBITS_SIGEVENT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sigevent { + union sigval sigev_value; + int sigev_notify; + int sigev_signo; + void (*sigev_notify_function)(union sigval); + struct __mlibc_threadattr *sigev_notify_attributes; + pid_t sigev_notify_thread_id; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGEVENT_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/signal.h b/ext2_root/usr/include/abi-bits/signal.h new file mode 100755 index 0000000..df8da4a --- /dev/null +++ b/ext2_root/usr/include/abi-bits/signal.h @@ -0,0 +1,647 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#include +#include +#include +#include +#include +#include + +#define POLL_IN 1 +#define POLL_OUT 2 +#define POLL_MSG 3 +#define POLL_ERR 4 +#define POLL_PRI 5 +#define POLL_HUP 6 + +/* struct taken from musl. */ + +typedef struct { + int si_signo, si_errno, si_code; + union { + char __pad[128 - 2*sizeof(int) - sizeof(long)]; + struct { + union { + struct { + pid_t si_pid; + uid_t si_uid; + } __piduid; + struct { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union { + union sigval si_value; + struct { + int si_status; + clock_t si_utime, si_stime; + } __sigchld; + } __second; + } __si_common; + struct { + void *si_addr; + short si_addr_lsb; + union { + struct { + void *si_lower; + void *si_upper; + } __addr_bnd; + unsigned si_pkey; + } __first; + } __sigfault; + struct { + long si_band; + int si_fd; + } __sigpoll; + struct { + void *si_call_addr; + int si_syscall; + unsigned si_arch; + } __sigsys; + } __si_fields; +} siginfo_t; +#define si_pid __si_fields.__si_common.__first.__piduid.si_pid +#define si_uid __si_fields.__si_common.__first.__piduid.si_uid +#define si_status __si_fields.__si_common.__second.__sigchld.si_status +#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime +#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime +#define si_value __si_fields.__si_common.__second.si_value +#define si_addr __si_fields.__sigfault.si_addr +#define si_addr_lsb __si_fields.__sigfault.si_addr_lsb +#define si_lower __si_fields.__sigfault.__first.__addr_bnd.si_lower +#define si_upper __si_fields.__sigfault.__first.__addr_bnd.si_upper +#define si_pkey __si_fields.__sigfault.__first.si_pkey +#define si_band __si_fields.__sigpoll.si_band +#define si_fd __si_fields.__sigpoll.si_fd +#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid +#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun +#define si_ptr si_value.sival_ptr +#define si_int si_value.sival_int +#define si_call_addr __si_fields.__sigsys.si_call_addr +#define si_syscall __si_fields.__sigsys.si_syscall +#define si_arch __si_fields.__sigsys.si_arch + +/* Required for sys_sigaction sysdep. */ +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +/* SA_NOMASK is an alias for SA_NODEFER */ +/* SA_ONESHOT is an alias for SA_RESETHAND */ +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +#ifdef __cplusplus +extern "C" { +#endif + +/* Argument for signal() */ +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(0)) +#define SIG_IGN ((__sighandler)(void *)(1)) + +#define SIGABRT 6 +#define SIGFPE 8 +#define SIGILL 4 +#define SIGINT 2 +#define SIGSEGV 11 +#define SIGTERM 15 +#define SIGPROF 27 +#define SIGIO 29 +#define SIGPWR 30 +#define SIGRTMIN 35 +#define SIGRTMAX 64 + +typedef struct { + unsigned long sig[1024 / (8 * sizeof(long))]; +} sigset_t; + +/* constants for sigprocmask() */ +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +#define SIGHUP 1 +#define SIGQUIT 3 +#define SIGTRAP 5 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGWINCH 28 +#define SIGPOLL 29 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS +#define SIGCANCEL 32 +#define SIGTIMER 33 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +/* constants for sigev_notify of struct sigevent */ +#define SIGEV_SIGNAL 0 +#define SIGEV_NONE 1 +#define SIGEV_THREAD 2 +#define SIGEV_THREAD_ID 4 + +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 +#define BUS_MCEERR_AR 4 +#define BUS_MCEERR_AO 5 + +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +#define NSIG 65 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +#if defined(__i386__) +#define REG_GS 0 +#define REG_FS 1 +#define REG_ES 2 +#define REG_DS 3 +#define REG_EDI 4 +#define REG_ESI 5 +#define REG_EBP 6 +#define REG_ESP 7 +#define REG_EBX 8 +#define REG_EDX 9 +#define REG_ECX 10 +#define REG_EAX 11 +#define REG_TRAPNO 12 +#define REG_ERR 13 +#define REG_EIP 14 +#define REG_CS 15 +#define REG_EFL 16 +#define REG_UESP 17 +#define REG_SS 18 +#define NGREG 19 +#elif defined(__x86_64__) +#define REG_R8 0 +#define REG_R9 1 +#define REG_R10 2 +#define REG_R11 3 +#define REG_R12 4 +#define REG_R13 5 +#define REG_R14 6 +#define REG_R15 7 +#define REG_RDI 8 +#define REG_RSI 9 +#define REG_RBP 10 +#define REG_RBX 11 +#define REG_RDX 12 +#define REG_RAX 13 +#define REG_RCX 14 +#define REG_RSP 15 +#define REG_RIP 16 +#define REG_EFL 17 +#define REG_CSGSFS 18 +#define REG_ERR 19 +#define REG_TRAPNO 20 +#define REG_OLDMASK 21 +#define REG_CR2 22 +#define NGREG 23 +#endif + +#include + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + } __sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; +}; + +#define sa_handler __sa_handler.sa_handler +#define sa_sigaction __sa_handler.sa_sigaction + +/* Taken from the linux kernel headers */ + +#if defined(__x86_64__) || defined(__i386__) + +struct _fpreg { + unsigned short significand[4]; + unsigned short exponent; +}; + +struct _fpxreg { + unsigned short significand[4]; + unsigned short exponent; + unsigned short padding[3]; +}; + +struct _xmmreg { + uint32_t element[4]; +}; + +struct _fpstate { +#if defined(__x86_64__) + uint16_t cwd; + uint16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t rdp; + uint32_t mxcsr; + uint32_t mxcr_mask; + struct _fpxreg _st[8]; + struct _xmmreg _xmm[16]; + uint32_t padding[24]; +#elif defined(__i386__) + uint32_t cw; + uint32_t sw; + uint32_t tag; + uint32_t ipoff; + uint32_t cssel; + uint32_t dataoff; + uint32_t datasel; + struct _fpreg _st[8]; + uint16_t status; + uint16_t magic; + + /* FXSR FPU */ + + uint32_t _fxsr_env[6]; + uint32_t mxscr; + uint32_t reserved; + struct _fpxreg _fxsr_st[8]; + struct _xmmreg _xmm[8]; + + uint32_t padding2[56]; +#endif +}; + +struct sigcontext { +#if defined(__x86_64__) + unsigned long r8, r9, r10, r11, r12, r13, r14, r15; + unsigned long rdi, rsi, rbp, rbx, rdx, rax, rcx, rsp, rip, eflags; + unsigned short cs, gs, fs, __pad0; + unsigned long err, trapno, oldmask, cr2; + struct _fpstate *fpstate; + unsigned long __reserved1[8]; +#elif defined(__i386__) + unsigned short gs, __gsh, fs, __fsh, es, __esh, ds, __dsh; + unsigned long edi, esi, ebp, esp, ebx, edx, ecx, eax; + unsigned long trapno, err, eip; + unsigned short cs, __csh; + unsigned long eflags, esp_at_signal; + unsigned short ss, __ssh; + struct _fpstate *fpstate; + unsigned long oldmask, cr2; +#endif +}; + +typedef struct { + unsigned long gregs[NGREG]; + struct _fpstate *fpregs; + unsigned long __reserved1[8]; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#elif defined(__riscv) && __riscv_xlen == 64 +/* Definitions from Linux kernel headers. */ + +#define NGREG 32 + +enum { + REG_PC = 0, +#define REG_PC REG_PC + REG_RA = 1, +#define REG_RA REG_RA + REG_SP = 2, +#define REG_SP REG_SP + REG_TP = 4, +#define REG_TP REG_TP + REG_S0 = 8, +#define REG_S0 REG_S0 + REG_A0 = 10 +#define REG_A0 REG_A0 +}; + +struct __riscv_f_ext_state { + uint32_t f[32]; + uint32_t fcsr; +}; + +struct __riscv_d_ext_state { + uint64_t f[32]; + uint32_t fcsr; +}; + +struct __riscv_q_ext_state { + uint64_t f[64] __attribute__((__aligned__(16))); + uint32_t fcsr; + uint32_t reserved[3]; +}; + +union __riscv_fp_state { + struct __riscv_f_ext_state f; + struct __riscv_d_ext_state d; + struct __riscv_q_ext_state q; +}; + +typedef unsigned long __riscv_mc_gp_state[NGREG]; + +typedef struct sigcontext { + __riscv_mc_gp_state gregs; + union __riscv_fp_state fpregs; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + uint8_t __unused[1024 / 8 - sizeof(sigset_t)]; +#pragma GCC diagnostic pop + mcontext_t uc_mcontext; +} ucontext_t; + +#elif defined (__aarch64__) + +#define NGREG 34 + +typedef struct sigcontext { + uint64_t fault_address; + uint64_t regs[31]; + uint64_t sp; + uint64_t pc; + uint64_t pstate; + uint8_t __reserved[4096]; +} mcontext_t; + +#define FPSIMD_MAGIC 0x46508001 +#define ESR_MAGIC 0x45535201 +#define EXTRA_MAGIC 0x45585401 +#define SVE_MAGIC 0x53564501 +struct _aarch64_ctx { + uint32_t magic; + uint32_t size; +}; +struct fpsimd_context { + struct _aarch64_ctx head; + uint32_t fpsr; + uint32_t fpcr; + __uint128_t vregs[32]; +}; +struct esr_context { + struct _aarch64_ctx head; + uint64_t esr; +}; +struct extra_context { + struct _aarch64_ctx head; + uint64_t datap; + uint32_t size; + uint32_t __reserved[3]; +}; +struct sve_context { + struct _aarch64_ctx head; + uint16_t vl; + uint16_t __reserved[3]; +}; +#define SVE_VQ_BYTES 16 +#define SVE_VQ_MIN 1 +#define SVE_VQ_MAX 512 +#define SVE_VL_MIN (SVE_VQ_MIN * SVE_VQ_BYTES) +#define SVE_VL_MAX (SVE_VQ_MAX * SVE_VQ_BYTES) +#define SVE_NUM_ZREGS 32 +#define SVE_NUM_PREGS 16 +#define sve_vl_valid(vl) \ + ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX) +#define sve_vq_from_vl(vl) ((vl) / SVE_VQ_BYTES) +#define sve_vl_from_vq(vq) ((vq) * SVE_VQ_BYTES) +#define SVE_SIG_ZREG_SIZE(vq) ((unsigned)(vq) * SVE_VQ_BYTES) +#define SVE_SIG_PREG_SIZE(vq) ((unsigned)(vq) * (SVE_VQ_BYTES / 8)) +#define SVE_SIG_FFR_SIZE(vq) SVE_SIG_PREG_SIZE(vq) +#define SVE_SIG_REGS_OFFSET \ + ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1)) \ + / SVE_VQ_BYTES * SVE_VQ_BYTES) +#define SVE_SIG_ZREGS_OFFSET SVE_SIG_REGS_OFFSET +#define SVE_SIG_ZREG_OFFSET(vq, n) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n)) +#define SVE_SIG_ZREGS_SIZE(vq) \ + (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET) +#define SVE_SIG_PREGS_OFFSET(vq) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq)) +#define SVE_SIG_PREG_OFFSET(vq, n) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n)) +#define SVE_SIG_PREGS_SIZE(vq) \ + (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq)) +#define SVE_SIG_FFR_OFFSET(vq) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq)) +#define SVE_SIG_REGS_SIZE(vq) \ + (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET) +#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq)) + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + mcontext_t uc_mcontext; +} ucontext_t; + +#elif defined (__m68k__) + +/* taken from musl */ + +#if defined(_GNU_SOURCE) || defined(__MLIBC_BUILDING_MLIBC) +enum { R_D0 = 0 }; +#define R_D0 R_D0 +enum { R_D1 = 1 }; +#define R_D1 R_D1 +enum { R_D2 = 2 }; +#define R_D2 R_D2 +enum { R_D3 = 3 }; +#define R_D3 R_D3 +enum { R_D4 = 4 }; +#define R_D4 R_D4 +enum { R_D5 = 5 }; +#define R_D5 R_D5 +enum { R_D6 = 6 }; +#define R_D6 R_D6 +enum { R_D7 = 7 }; +#define R_D7 R_D7 +enum { R_A0 = 8 }; +#define R_A0 R_A0 +enum { R_A1 = 9 }; +#define R_A1 R_A1 +enum { R_A2 = 10 }; +#define R_A2 R_A2 +enum { R_A3 = 11 }; +#define R_A3 R_A3 +enum { R_A4 = 12 }; +#define R_A4 R_A4 +enum { R_A5 = 13 }; +#define R_A5 R_A5 +enum { R_A6 = 14 }; +#define R_A6 R_A6 +enum { R_A7 = 15 }; +#define R_A7 R_A7 +enum { R_SP = 15 }; +#define R_SP R_SP +enum { R_PC = 16 }; +#define R_PC R_PC +enum { R_PS = 17 }; +#define R_PS R_PS +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(__MLIBC_BUILDING_MLIBC) + +struct sigcontext { + unsigned long sc_mask, sc_usp, sc_d0, sc_d1, sc_a0, sc_a1; + unsigned short sc_sr; + unsigned long sc_pc; + unsigned short sc_formatvec; + unsigned long sc_fpregs[6], sc_fpcntl[3]; + unsigned char sc_fpstate[216]; +}; + +typedef int greg_t, gregset_t[18]; +typedef struct { + int f_pcr, f_psr, f_fpiaddr, f_fpregs[8][3]; +} fpregset_t; + +typedef struct { + int version; + gregset_t gregs; + fpregset_t fpregs; +} mcontext_t; +#else +typedef struct { + int __version; + int __gregs[18]; + int __fpregs[27]; +} mcontext_t; +#endif + +struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + long __reserved[80]; + sigset_t uc_sigmask; +} ucontext_t; + +#elif defined(__loongarch64) +/* Taken from musl. */ + +#define NGREG 32 +#define REG_RA 1 +#define REG_SP 3 +#define REG_S0 23 +#define REG_S1 24 +#define REG_A0 4 +#define REG_S2 25 +#define REG_NARGS 8 + +typedef unsigned long greg_t, gregset_t[32]; + +struct sigcontext { + unsigned long sc_pc; + unsigned long sc_regs[32]; + unsigned sc_flags; + unsigned long sc_extcontext[1] __attribute__((__aligned__(16))); +}; + +typedef struct { + unsigned long pc; + unsigned long gregs[32]; + unsigned flags; + unsigned long extcontext[1] __attribute__((__aligned__(16))); +} mcontext_t; + +struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + long __uc_pad; + mcontext_t uc_mcontext; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGNAL_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/sigset_t.h b/ext2_root/usr/include/abi-bits/sigset_t.h new file mode 100644 index 0000000..6cf9a05 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/sigset_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SIGSET_T_H +#define _ABIBITS_SIGSET_T_H + +typedef struct { + unsigned long __sig[1024 / (8 * sizeof(long))]; +} sigset_t; + +#endif /* _ABIBITS_SIGSET_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/sigval.h b/ext2_root/usr/include/abi-bits/sigval.h new file mode 100755 index 0000000..627b624 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/sigval.h @@ -0,0 +1,17 @@ +#ifndef _ABIBITS_SIGVAL_H +#define _ABIBITS_SIGVAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +union sigval { + int sival_int; + void *sival_ptr; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGVAL_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/sockaddr_storage.h b/ext2_root/usr/include/abi-bits/sockaddr_storage.h new file mode 100644 index 0000000..576a65a --- /dev/null +++ b/ext2_root/usr/include/abi-bits/sockaddr_storage.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_SOCKADDR_STORAGE_H +#define _ABIBITS_SOCKADDR_STORAGE_H + +#include + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t) - sizeof(long)]; + long __force_alignment; +}; + +#endif /* _ABIBITS_SOCKADDR_STORAGE_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/socket.h b/ext2_root/usr/include/abi-bits/socket.h new file mode 100755 index 0000000..a1c6710 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/socket.h @@ -0,0 +1,329 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned short sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + size_t msg_iovlen; /* int in POSIX */ + void *msg_control; + size_t msg_controllen; /* socklen_t in POSIX */ + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t) - sizeof(long)]; + long __force_alignment; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + size_t cmsg_len; /* socklen_t in POSIX */ + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_CREDENTIALS 2 + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#ifndef SOCK_STREAM +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#endif + +#define SOCK_RAW 3 +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 +#define SOCK_DCCP 6 +#define SOCK_PACKET 10 + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 02000000 +#define SOCK_NONBLOCK 04000 +#endif + +#define PF_UNSPEC 0 +#define PF_LOCAL 1 +#define PF_UNIX PF_LOCAL +#define PF_FILE PF_LOCAL +#define PF_INET 2 +#define PF_AX25 3 +#define PF_IPX 4 +#define PF_APPLETALK 5 +#define PF_NETROM 6 +#define PF_BRIDGE 7 +#define PF_ATMPVC 8 +#define PF_X25 9 +#define PF_INET6 10 +#define PF_ROSE 11 +#define PF_DECnet 12 +#define PF_NETBEUI 13 +#define PF_SECURITY 14 +#define PF_KEY 15 +#define PF_NETLINK 16 +#define PF_ROUTE PF_NETLINK +#define PF_PACKET 17 +#define PF_ASH 18 +#define PF_ECONET 19 +#define PF_ATMSVC 20 +#define PF_RDS 21 +#define PF_SNA 22 +#define PF_IRDA 23 +#define PF_PPPOX 24 +#define PF_WANPIPE 25 +#define PF_LLC 26 +#define PF_IB 27 +#define PF_MPLS 28 +#define PF_CAN 29 +#define PF_TIPC 30 +#define PF_BLUETOOTH 31 +#define PF_IUCV 32 +#define PF_RXRPC 33 +#define PF_ISDN 34 +#define PF_PHONET 35 +#define PF_IEEE802154 36 +#define PF_CAIF 37 +#define PF_ALG 38 +#define PF_NFC 39 +#define PF_VSOCK 40 +#define PF_KCM 41 +#define PF_QIPCRTR 42 +#define PF_SMC 43 +#define PF_XDP 44 +#define PF_MAX 45 + +#define AF_UNSPEC PF_UNSPEC +#define AF_LOCAL PF_LOCAL +#define AF_UNIX AF_LOCAL +#define AF_FILE AF_LOCAL +#define AF_INET PF_INET +#define AF_AX25 PF_AX25 +#define AF_IPX PF_IPX +#define AF_APPLETALK PF_APPLETALK +#define AF_NETROM PF_NETROM +#define AF_BRIDGE PF_BRIDGE +#define AF_ATMPVC PF_ATMPVC +#define AF_X25 PF_X25 +#define AF_INET6 PF_INET6 +#define AF_ROSE PF_ROSE +#define AF_DECnet PF_DECnet +#define AF_NETBEUI PF_NETBEUI +#define AF_SECURITY PF_SECURITY +#define AF_KEY PF_KEY +#define AF_NETLINK PF_NETLINK +#define AF_ROUTE PF_ROUTE +#define AF_PACKET PF_PACKET +#define AF_ASH PF_ASH +#define AF_ECONET PF_ECONET +#define AF_ATMSVC PF_ATMSVC +#define AF_RDS PF_RDS +#define AF_SNA PF_SNA +#define AF_IRDA PF_IRDA +#define AF_PPPOX PF_PPPOX +#define AF_WANPIPE PF_WANPIPE +#define AF_LLC PF_LLC +#define AF_IB PF_IB +#define AF_MPLS PF_MPLS +#define AF_CAN PF_CAN +#define AF_TIPC PF_TIPC +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_IUCV PF_IUCV +#define AF_RXRPC PF_RXRPC +#define AF_ISDN PF_ISDN +#define AF_PHONET PF_PHONET +#define AF_IEEE802154 PF_IEEE802154 +#define AF_CAIF PF_CAIF +#define AF_ALG PF_ALG +#define AF_NFC PF_NFC +#define AF_VSOCK PF_VSOCK +#define AF_KCM PF_KCM +#define AF_QIPCRTR PF_QIPCRTR +#define AF_SMC PF_SMC +#define AF_XDP PF_XDP +#define AF_MAX PF_MAX + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +#define SO_REUSEPORT 15 +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_ACCEPTCONN 30 +#define SO_PEERSEC 31 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 + +#ifndef SO_RCVTIMEO +#if __LONG_MAX == 0x7fffffff +#define SO_RCVTIMEO 66 +#else +#define SO_RCVTIMEO 20 +#endif +#endif + +#ifndef SO_RCVTIMEO_OLD +#define SO_RCVTIMEO_OLD 20 +#endif + +#ifndef SO_SNDTIMEO +#if __LONG_MAX == 0x7fffffff +#define SO_SNDTIMEO 67 +#else +#define SO_SNDTIMEO 21 +#endif +#endif + +#ifndef SO_SNDTIMEO_OLD +#define SO_SNDTIMEO_OLD 21 +#endif + +#ifndef SO_TIMESTAMP +#if __LONG_MAX == 0x7fffffff +#define SO_TIMESTAMP 63 +#define SO_TIMESTAMPNS 64 +#define SO_TIMESTAMPING 65 +#else +#define SO_TIMESTAMP 29 +#define SO_TIMESTAMPNS 35 +#define SO_TIMESTAMPING 37 +#endif +#endif + +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 +#define SO_GET_FILTER SO_ATTACH_FILTER + +#define SO_PEERNAME 28 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SO_PASSSEC 34 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS +#define SO_MARK 36 +#define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 +#define SO_NOFCS 43 +#define SO_LOCK_FILTER 44 +#define SO_SELECT_ERR_QUEUE 45 +#define SO_BUSY_POLL 46 +#define SO_MAX_PACING_RATE 47 +#define SO_BPF_EXTENSIONS 48 +#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#define SO_ATTACH_REUSEPORT_CBPF 51 +#define SO_ATTACH_REUSEPORT_EBPF 52 +#define SO_CNX_ADVICE 53 +#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_MEMINFO 55 +#define SO_INCOMING_NAPI_ID 56 +#define SO_COOKIE 57 +#define SCM_TIMESTAMPING_PKTINFO 58 +#define SO_PEERGROUPS 59 +#define SO_ZEROCOPY 60 +#define SO_TXTIME 61 +#define SCM_TXTIME SO_TXTIME +#define SO_BINDTOIFINDEX 62 +#define SO_DETACH_REUSEPORT_BPF 68 + +#define SOL_SOCKET 1 + +#define SOL_IP 0 +#define SOL_IPV6 41 +#define SOL_ICMPV6 58 + +#define SOL_RAW 255 +#define SOL_DECNET 261 +#define SOL_X25 262 +#define SOL_PACKET 263 +#define SOL_ATM 264 +#define SOL_AAL 265 +#define SOL_IRDA 266 +#define SOL_NETBEUI 267 +#define SOL_LLC 268 +#define SOL_DCCP 269 +#define SOL_NETLINK 270 +#define SOL_TIPC 271 +#define SOL_RXRPC 272 +#define SOL_PPPOL2TP 273 +#define SOL_BLUETOOTH 274 +#define SOL_PNPIPE 275 +#define SOL_RDS 276 +#define SOL_IUCV 277 +#define SOL_CAIF 278 +#define SOL_ALG 279 +#define SOL_NFC 280 +#define SOL_KCM 281 +#define SOL_TLS 282 +#define SOL_XDP 283 + +#define SOMAXCONN 128 + +#define MSG_OOB 0x0001 +#define MSG_PEEK 0x0002 +#define MSG_DONTROUTE 0x0004 +#define MSG_CTRUNC 0x0008 +#define MSG_PROXY 0x0010 +#define MSG_TRUNC 0x0020 +#define MSG_DONTWAIT 0x0040 +#define MSG_EOR 0x0080 +#define MSG_WAITALL 0x0100 +#define MSG_FIN 0x0200 +#define MSG_SYN 0x0400 +#define MSG_CONFIRM 0x0800 +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 +#define MSG_NOSIGNAL 0x4000 +#define MSG_MORE 0x8000 +#define MSG_WAITFORONE 0x10000 +#define MSG_BATCH 0x40000 +#define MSG_ZEROCOPY 0x4000000 +#define MSG_FASTOPEN 0x20000000 +#define MSG_CMSG_CLOEXEC 0x40000000 + +#endif \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/socklen_t.h b/ext2_root/usr/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..382e738 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/socklen_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_SOCKLEN_T_H +#define _ABIBITS_SOCKLEN_T_H + +typedef unsigned socklen_t; + +#endif /* _ABIBITS_SOCKLEN_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/stat.h b/ext2_root/usr/include/abi-bits/stat.h new file mode 100755 index 0000000..e9a2885 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/stat.h @@ -0,0 +1,148 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__x86_64__) + +struct stat { + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; + unsigned int __pad0; + dev_t st_rdev; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + long __unused[3]; +}; + +#elif (defined(__riscv) && __riscv_xlen == 64) || defined (__aarch64__) || defined(__loongarch64) + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + dev_t __pad1; + off_t st_size; + blksize_t st_blksize; + int __pad2; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + int __pad3[2]; +}; + +#elif defined(__i386__) + +struct stat { + dev_t st_dev; + int __st_dev_padding; + long __st_ino_truncated; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + int __st_rdev_padding; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct { + long tv_sec; + long tv_nsec; + } __st_atim32, __st_mtim32, __st_ctim32; + ino_t st_ino; + + /* These fields are not in the ABI. Their values are */ + /* copied from __st_atim32, __st_mtim32, __st_ctim32 */ + /* accordingly. */ + + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; +}; +#elif defined (__m68k__) + +struct stat { + dev_t st_dev; + unsigned char __st_dev_padding[2]; + unsigned long __st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + unsigned char __st_rdev_padding; + long long st_size; /* TODO: off64_t? */ + blksize_t st_blksize; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + ino_t st_ino; +}; + +#endif + +#define stat64 stat + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_STAT_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/statvfs.h b/ext2_root/usr/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1e2b0ea --- /dev/null +++ b/ext2_root/usr/include/abi-bits/statvfs.h @@ -0,0 +1,51 @@ +#ifndef _ABIBITS_STATVFS_H +#define _ABIBITS_STATVFS_H + +#include +#include + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_NODEV 4 +#define ST_NOEXEC 8 +#define ST_SYNCHRONOUS 16 +#define ST_MANDLOCK 64 +#define ST_WRITE 128 +#define ST_APPEND 256 +#define ST_IMMUTABLE 512 +#define ST_NOATIME 1024 +#define ST_NODIRATIME 2048 + +/* On Linux, this struct is not directly used by the kernel. */ + +/* WARNING: keep `statvfs` and `statvfs64` in sync or bad things will happen! */ +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; + +/* WARNING: keep `statvfs` and `statvfs64` in sync or bad things will happen! */ +struct statvfs64 { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; + +#endif /* _ABIBITS_STATVFS_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/suseconds_t.h b/ext2_root/usr/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..06d8a2c --- /dev/null +++ b/ext2_root/usr/include/abi-bits/suseconds_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SUSECONDS_T_H +#define _ABIBITS_SUSECONDS_T_H + +#include + +typedef long suseconds_t; + +#endif /* _ABIBITS_SUSECONDS_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/termios.h b/ext2_root/usr/include/abi-bits/termios.h new file mode 100755 index 0000000..668e9fd --- /dev/null +++ b/ext2_root/usr/include/abi-bits/termios.h @@ -0,0 +1,155 @@ +#ifndef _ABIBITS_TERMIOS_H +#define _ABIBITS_TERMIOS_H + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +/* indices for the c_cc array in struct termios */ +#define NCCS 32 +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* bitwise flags for c_iflag in struct termios */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* bitwise flags for c_oflag in struct termios */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE) + +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 + +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 + +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 + +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 + +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +#endif + +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 + +/* bitwise constants for c_cflag in struct termios */ +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 + +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 + +/* bitwise constants for c_lflag in struct termios */ +#define ISIG 0000001 +#define ICANON 0000002 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define IEXTEN 0100000 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define EXTA 0000016 +#define EXTB 0000017 +#define CBAUD 0010017 +#define CBAUDEX 0010000 +#define CIBAUD 002003600000 +#define CMSPAR 010000000000 +#define CRTSCTS 020000000000 + +#define XCASE 0000004 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define EXTPROC 0200000 + +#define XTABS 0014000 + +#endif + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; + unsigned short c_oflag; + unsigned short c_cflag; + unsigned short c_lflag; + unsigned char c_line; + unsigned char c_cc[NCC]; +}; + +#endif \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/time.h b/ext2_root/usr/include/abi-bits/time.h new file mode 100755 index 0000000..403066a --- /dev/null +++ b/ext2_root/usr/include/abi-bits/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif /* _ABIBITS_TIME_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/uid_t.h b/ext2_root/usr/include/abi-bits/uid_t.h new file mode 100755 index 0000000..f026b71 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/uid_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif /* _ABIBITS_UID_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/utmp-defines.h b/ext2_root/usr/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..d7a6dba --- /dev/null +++ b/ext2_root/usr/include/abi-bits/utmp-defines.h @@ -0,0 +1,25 @@ +#ifndef _ABIBITS_UTMP_DEFINES_H +#define _ABIBITS_UTMP_DEFINES_H + +#include + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +#ifdef _GNU_SOURCE +#define ACCOUNTING 9 +#endif + +#if __MLIBC_LINUX_OPTION +#define UTMP_FILE "/var/run/utmp" +#define WTMP_FILE "/var/log/wtmp" +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABIBITS_UTMP_DEFINES_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/utmpx.h b/ext2_root/usr/include/abi-bits/utmpx.h new file mode 100755 index 0000000..353cca9 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/utmpx.h @@ -0,0 +1,36 @@ +#ifndef _ABIBITS_UTMPX_H +#define _ABIBITS_UTMPX_H + +#include +#include + +#define __UT_HOSTSIZE 256 +#define __UT_NAMESIZE 32 +#define __UT_LINESIZE 32 + +/* Struct definition taken from musl */ +struct utmpx { + short ut_type; + short __ut_pad1; + pid_t ut_pid; + char ut_line[__UT_LINESIZE]; + char ut_id[4]; + char ut_user[__UT_NAMESIZE]; + char ut_host[__UT_HOSTSIZE]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + int ut_session, __ut_pad2; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +#define e_exit __e_exit +#define e_termination __e_termination + +#define UTMPX_FILE "/var/run/utmp" +#define WTMPX_FILE "/var/log/wtmp" + +#endif /* _ABIBITS_UTMPX_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/utsname.h b/ext2_root/usr/include/abi-bits/utsname.h new file mode 100755 index 0000000..fcfedc1 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/utsname.h @@ -0,0 +1,13 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +#endif /* _ABIBITS_UTSNAME_T_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/vm-flags.h b/ext2_root/usr/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..a7652db --- /dev/null +++ b/ext2_root/usr/include/abi-bits/vm-flags.h @@ -0,0 +1,81 @@ +#ifndef _ABIBITS_VM_FLAGS_H +#define _ABIBITS_VM_FLAGS_H + +#include + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS 0x20 + +#if __MLIBC_LINUX_OPTION + +#define MAP_GROWSDOWN 0x100 +#define MAP_DENYWRITE 0x800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_NORESERVE 0x4000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_SYNC 0x80000 +#define MAP_FIXED_NOREPLACE 0x100000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#define MS_ASYNC 0x01 +#define MS_INVALIDATE 0x02 +#define MS_SYNC 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 0 +#define POSIX_MADV_RANDOM 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_WILLNEED 3 +#define POSIX_MADV_DONTNEED 4 + +#if __MLIBC_LINUX_OPTION + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_REMOVE 9 +#define MADV_DONTFORK 10 +#define MADV_DOFORK 11 +#define MADV_MERGEABLE 12 +#define MADV_UNMERGEABLE 13 +#define MADV_HUGEPAGE 14 +#define MADV_NOHUGEPAGE 15 +#define MADV_DONTDUMP 16 +#define MADV_DODUMP 17 +#define MADV_WIPEONFORK 18 +#define MADV_KEEPONFORK 19 +#define MADV_COLD 20 +#define MADV_PAGEOUT 21 +#define MADV_HWPOISON 100 +#define MADV_SOFT_OFFLINE 101 + +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U +#define MFD_HUGETLB 4U + +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABIBITS_VM_FLAGS_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/abi-bits/wait.h b/ext2_root/usr/include/abi-bits/wait.h new file mode 100755 index 0000000..5a91795 --- /dev/null +++ b/ext2_root/usr/include/abi-bits/wait.h @@ -0,0 +1,34 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#include + +#define WNOHANG 1 +#define WUNTRACED 2 +#define WSTOPPED 2 +#define WEXITED 4 +#define WCONTINUED 8 +#define WNOWAIT 0x01000000 + +#if __MLIBC_LINUX_OPTION + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) (((x) & 0xff00) >> 8) +#define WTERMSIG(x) ((x) & 0x7f) +#define WSTOPSIG(x) WEXITSTATUS(x) +#define WIFEXITED(x) (WTERMSIG(x) == 0) +#define WIFSIGNALED(x) (((signed char) (((x) & 0x7f) + 1) >> 1) > 0) +#define WIFSTOPPED(x) (((x) & 0xff) == 0x7f) +#define WIFCONTINUED(x) ((x) == 0xffff) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +/* glibc extension, but also useful for kernels */ +#define W_EXITCODE(ret, sig) (((ret) << 8) | (sig)) + +#endif /*_ABIBITS_WAIT_H */ \ No newline at end of file diff --git a/ext2_root/usr/include/alloca.h b/ext2_root/usr/include/alloca.h new file mode 100644 index 0000000..edfc80d --- /dev/null +++ b/ext2_root/usr/include/alloca.h @@ -0,0 +1,8 @@ + +#ifndef _ALLOCA_H +#define _ALLOCA_H + +#define alloca __builtin_alloca + +#endif /* _ALLOCA_H */ + diff --git a/ext2_root/usr/include/ar.h b/ext2_root/usr/include/ar.h new file mode 100644 index 0000000..c7a9f38 --- /dev/null +++ b/ext2_root/usr/include/ar.h @@ -0,0 +1,27 @@ + +#ifndef _AR_H +#define _AR_H + +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6]; + char ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/arpa/inet.h b/ext2_root/usr/include/arpa/inet.h new file mode 100644 index 0000000..1a492ca --- /dev/null +++ b/ext2_root/usr/include/arpa/inet.h @@ -0,0 +1,47 @@ +#ifndef _ARPA_INET_H +#define _ARPA_INET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +uint32_t htonl(uint32_t __x); +uint16_t htons(uint16_t __x); +uint32_t ntohl(uint32_t __x); +uint16_t ntohs(uint16_t __x); + +/* ---------------------------------------------------------------------------- */ +/* IPv4 address manipulation. */ +/* ---------------------------------------------------------------------------- */ + +in_addr_t inet_addr(const char *__cp); +in_addr_t inet_network(const char *__cp); +char *inet_ntoa(struct in_addr __in); + +/* GLIBC replacement for inet_addr(). */ +int inet_aton(const char *__cp, struct in_addr *__dest); + +/* ---------------------------------------------------------------------------- */ +/* Generic IP address manipulation. */ +/* ---------------------------------------------------------------------------- */ +const char *inet_ntop(int __af, const void *__restrict __src, char *__restrict __dst, + socklen_t __size) __attribute__((__nonnull__(3))); +int inet_pton(int __af, const char *__restrict __src, void *__restrict __dst); + +struct in_addr inet_makeaddr(in_addr_t __net, in_addr_t __host); +in_addr_t inet_netof(struct in_addr __in); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ARPA_INET_H */ + diff --git a/ext2_root/usr/include/arpa/nameser.h b/ext2_root/usr/include/arpa/nameser.h new file mode 100644 index 0000000..7e2e9f1 --- /dev/null +++ b/ext2_root/usr/include/arpa/nameser.h @@ -0,0 +1,266 @@ +#ifndef _ARPA_NAMESER_H +#define _ARPA_NAMESER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NS_PACKETSZ 512 +#define NS_MAXDNAME 1025 +#define NS_MAXLABEL 63 + +typedef enum __ns_rcode { + ns_r_noerror = 0, + ns_r_formerr = 1, + ns_r_servfail = 2, + ns_r_nxdomain = 3, + ns_r_notimpl = 4, + ns_r_refused = 5, + ns_r_yxdomain = 6, + ns_r_yxrrset = 7, + ns_r_nxrrset = 8, + ns_r_notauth = 9, + ns_r_notzone = 10, + ns_r_max = 11, + ns_r_badvers = 16, + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +typedef enum __ns_type { + ns_t_invalid = 0, + ns_t_a = 1, + ns_t_ns = 2, + ns_t_md = 3, + ns_t_mf = 4, + ns_t_cname = 5, + ns_t_soa = 6, + ns_t_mb = 7, + ns_t_mg = 8, + ns_t_mr = 9, + ns_t_null = 10, + ns_t_wks = 11, + ns_t_ptr = 12, + ns_t_hinfo = 13, + ns_t_minfo = 14, + ns_t_mx = 15, + ns_t_txt = 16, + ns_t_rp = 17, + ns_t_afsdb = 18, + ns_t_x25 = 19, + ns_t_isdn = 20, + ns_t_rt = 21, + ns_t_nsap = 22, + ns_t_nsap_ptr = 23, + ns_t_sig = 24, + ns_t_key = 25, + ns_t_px = 26, + ns_t_gpos = 27, + ns_t_aaaa = 28, + ns_t_loc = 29, + ns_t_nxt = 30, + ns_t_eid = 31, + ns_t_nimloc = 32, + ns_t_srv = 33, + ns_t_atma = 34, + ns_t_naptr = 35, + ns_t_kx = 36, + ns_t_cert = 37, + ns_t_a6 = 38, + ns_t_dname = 39, + ns_t_sink = 40, + ns_t_opt = 41, + ns_t_apl = 42, + ns_t_tkey = 249, + ns_t_tsig = 250, + ns_t_ixfr = 251, + ns_t_axfr = 252, + ns_t_mailb = 253, + ns_t_maila = 254, + ns_t_any = 255, + ns_t_zxfr = 256, + ns_t_max = 65536 +} ns_type; + +typedef enum __ns_class { + ns_c_invalid = 0, + ns_c_in = 1, + ns_c_2 = 2, + ns_c_chaos = 3, + ns_c_hs = 4, + ns_c_none = 254, + ns_c_any = 255, + ns_c_max = 65536 +} ns_class; + +typedef enum __ns_sect { + ns_s_qd = 0, + ns_s_zn = 0, + ns_s_an = 1, + ns_s_pr = 1, + ns_s_ns = 2, + ns_s_ud = 2, + ns_s_ar = 3, + ns_s_max = 4 +} ns_sect; + +typedef struct __ns_msg { + const unsigned char *_msg, *_eom; + uint16_t _id, _flags, _counts[ns_s_max]; + const unsigned char *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const unsigned char *_msg_ptr; +} ns_msg; + +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) + +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + uint16_t type; + uint16_t rr_class; + uint32_t ttl; + uint16_t rdlength; + const unsigned char *rdata; +} ns_rr; + +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr) ((rr).ttl + 0) +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +#ifndef __MLIBC_ABI_ONLY + +#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp) += 2) - 2)) +#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp) += 4) - 4)) +#define NS_PUT16(s, cp) ns_put16((s), ((cp) += 2) - 2) +#define NS_PUT32(l, cp) ns_put32((l), ((cp) += 4) - 4) + +unsigned ns_get16(const unsigned char *__src); +unsigned long ns_get32(const unsigned char *__src); +void ns_put16(unsigned int __value, unsigned char *__src); +void ns_put32(unsigned long __value, unsigned char *__src); + +int ns_initparse(const unsigned char *__msg, int __msglen, ns_msg *__handle); +int ns_parserr(ns_msg *__msg, ns_sect __section, int __rrnum, ns_rr *__rr); +int ns_name_uncompress(const unsigned char *__msg, const unsigned char *__eom, + const unsigned char *__src, char *__dst, size_t __dstsize); + +#endif /* !__MLIBC_ABI_ONLY */ + +typedef struct { + unsigned id :16; +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned qr: 1; + unsigned opcode: 4; + unsigned aa: 1; + unsigned tc: 1; + unsigned rd: 1; + unsigned ra: 1; + unsigned unused :1; + unsigned ad: 1; + unsigned cd: 1; + unsigned rcode :4; +#else + unsigned rd :1; + unsigned tc :1; + unsigned aa :1; + unsigned opcode :4; + unsigned qr :1; + unsigned rcode :4; + unsigned cd: 1; + unsigned ad: 1; + unsigned unused :1; + unsigned ra :1; +#endif + unsigned qdcount :16; + unsigned ancount :16; + unsigned nscount :16; + unsigned arcount :16; +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_A6 ns_t_a6 +#define T_DNAME ns_t_dname +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +#ifdef __cplusplus +} +#endif + +#endif /* _ARPA_NAMESER_H */ diff --git a/ext2_root/usr/include/arpa/nameser_compat.h b/ext2_root/usr/include/arpa/nameser_compat.h new file mode 100644 index 0000000..ee3b1a9 --- /dev/null +++ b/ext2_root/usr/include/arpa/nameser_compat.h @@ -0,0 +1 @@ +#include diff --git a/ext2_root/usr/include/assert.h b/ext2_root/usr/include/assert.h new file mode 100644 index 0000000..dbad1f0 --- /dev/null +++ b/ext2_root/usr/include/assert.h @@ -0,0 +1,46 @@ + +#ifndef _ASSERT_H +#define _ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* NOTE: This is not ISO C. Declared in LSB */ +__attribute__ ((__noreturn__)) void __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ASSERT_H */ + +#include + +#if __MLIBC_GLIBC_OPTION +# include +#endif + +/* NOTE: [7.2] requires this be outside the include guard */ +#ifdef NDEBUG + +#undef assert +#define assert(ignore) ((void)0) + +#else /* NDEBUG */ + +#undef assert +#define assert(assertion) ((void)((assertion) \ + || (__assert_fail(#assertion, __FILE__, __LINE__, __func__), 0))) + +#endif /* NDEBUG */ + +#ifndef __cplusplus +#undef static_assert +#define static_assert _Static_assert +#endif diff --git a/ext2_root/usr/include/bits/ansi/fenv.h b/ext2_root/usr/include/bits/ansi/fenv.h new file mode 100644 index 0000000..326f8c0 --- /dev/null +++ b/ext2_root/usr/include/bits/ansi/fenv.h @@ -0,0 +1,93 @@ +#ifndef MLIBC_FENV_H +#define MLIBC_FENV_H + +#if defined(__x86_64__) || defined(__i386__) + +#define FE_DENORMAL 2 +#define FE_DIVBYZERO 4 +#define FE_INEXACT 32 +#define FE_INVALID 1 +#define FE_OVERFLOW 8 +#define FE_UNDERFLOW 16 + +#define FE_ALL_EXCEPT (FE_DENORMAL | FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0x400 +#define FE_UPWARD 0x800 +#define FE_TOWARDZERO 0xC00 + +#elif defined(__aarch64__) + +#define FE_INVALID 1 +#define FE_DIVBYZERO 2 +#define FE_OVERFLOW 4 +#define FE_UNDERFLOW 8 +#define FE_INEXACT 16 + +#define FE_ALL_EXCEPT 31 + +#define FE_TONEAREST 0 +#define FE_UPWARD 0x400000 +#define FE_DOWNWARD 0x800000 +#define FE_TOWARDZERO 0xC00000 + +#elif defined(__riscv) && __riscv_xlen == 64 + +#define FE_INEXACT 1 +#define FE_UNDERFLOW 2 +#define FE_OVERFLOW 4 +#define FE_DIVBYZERO 8 +#define FE_INVALID 16 + +#define FE_ALL_EXCEPT 31 + +#define FE_TONEAREST 0 +#define FE_TOWARDZERO 1 +#define FE_DOWNWARD 2 +#define FE_UPWARD 3 + +#elif defined (__m68k__) + +#if __HAVE_68881__ || __mcffpu__ || __HAVE_FPU_ + +#define FE_INEXACT 8 +#define FE_DIVBYZERO 16 +#define FE_UNDERFLOW 32 +#define FE_OVERFLOW 64 +#define FE_INVALID 128 + +#define FE_ALL_EXCEPT 0xf8 + +#define FE_TONEAREST 0 +#define FE_TOWARDZERO 16 +#define FE_DOWNWARD 32 +#define FE_UPWARD 48 + +#else + +#define FE_ALL_EXCEPT 0 +#define FE_TONEAREST 0 + +#endif + +#elif defined(__loongarch64) + +#define FE_INEXACT 0x010000 +#define FE_UNDERFLOW 0x020000 +#define FE_OVERFLOW 0x040000 +#define FE_DIVBYZERO 0x080000 +#define FE_INVALID 0x100000 + +#define FE_ALL_EXCEPT (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID) + +#define FE_TONEAREST 0x000 +#define FE_TOWARDZERO 0x100 +#define FE_UPWARD 0x200 +#define FE_DOWNWARD 0x300 + +#else +#error Unknown architecture +#endif + +#endif /* MLIBC_FENV_H */ diff --git a/ext2_root/usr/include/bits/ansi/time_t.h b/ext2_root/usr/include/bits/ansi/time_t.h new file mode 100644 index 0000000..1c29fa0 --- /dev/null +++ b/ext2_root/usr/include/bits/ansi/time_t.h @@ -0,0 +1,8 @@ + +#ifndef MLIBC_TIME_T +#define MLIBC_TIME_T + +typedef long time_t; + +#endif + diff --git a/ext2_root/usr/include/bits/ansi/timespec.h b/ext2_root/usr/include/bits/ansi/timespec.h new file mode 100644 index 0000000..e4ab91e --- /dev/null +++ b/ext2_root/usr/include/bits/ansi/timespec.h @@ -0,0 +1,13 @@ + +#ifndef MLIBC_TIMESPEC_H +#define MLIBC_TIMESPEC_H + +#include + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +#endif /* MLIBC_TIMESPEC_H */ + diff --git a/ext2_root/usr/include/bits/bsd/bsd_stdlib.h b/ext2_root/usr/include/bits/bsd/bsd_stdlib.h new file mode 100644 index 0000000..bb7c9a4 --- /dev/null +++ b/ext2_root/usr/include/bits/bsd/bsd_stdlib.h @@ -0,0 +1,20 @@ + +#ifndef MLIBC_BSD_STDLIB_H +#define MLIBC_BSD_STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int getloadavg(double *__loadavg, int __count); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_BSD_STDLIB_H */ + diff --git a/ext2_root/usr/include/bits/bsd/bsd_unistd.h b/ext2_root/usr/include/bits/bsd/bsd_unistd.h new file mode 100644 index 0000000..3d2de25 --- /dev/null +++ b/ext2_root/usr/include/bits/bsd/bsd_unistd.h @@ -0,0 +1,20 @@ +#ifndef _BSD_UNISTD_H +#define _BSD_UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +void *sbrk(intptr_t __increment); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSD_UNISTD_H */ diff --git a/ext2_root/usr/include/bits/cpu_set.h b/ext2_root/usr/include/bits/cpu_set.h new file mode 100644 index 0000000..69f6923 --- /dev/null +++ b/ext2_root/usr/include/bits/cpu_set.h @@ -0,0 +1,13 @@ +#ifndef _MLIBC_INTERNAL_CPU_SET_H +#define _MLIBC_INTERNAL_CPU_SET_H + +typedef unsigned long __cpu_mask; + +#define CPU_SETSIZE 1024 +#define __NCPUBITS (8 * sizeof(__cpu_mask)) + +typedef struct { + __cpu_mask __bits[CPU_SETSIZE / __NCPUBITS]; +} cpu_set_t; + +#endif /* _MLIBC_INTERNAL_CPU_SET_H */ diff --git a/ext2_root/usr/include/bits/ensure.h b/ext2_root/usr/include/bits/ensure.h new file mode 100644 index 0000000..7bea3e2 --- /dev/null +++ b/ext2_root/usr/include/bits/ensure.h @@ -0,0 +1,45 @@ + +#ifndef MLIBC_ENSURE_H +#define MLIBC_ENSURE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +void __ensure_fail(const char *assertion, const char *file, unsigned int line, + const char *function); + +void __ensure_warn(const char *assertion, const char *file, unsigned int line, + const char *function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define __ensure(assertion) do { if(!(assertion)) \ + __ensure_fail(#assertion, __FILE__, __LINE__, __func__); } while(0) + +#define MLIBC_UNIMPLEMENTED() __ensure_fail("Functionality is not implemented", \ + __FILE__, __LINE__, __func__) + +#define MLIBC_MISSING_SYSDEP() __ensure_warn("Library function fails due to missing sysdep", \ + __FILE__, __LINE__, __func__) + +#define MLIBC_CHECK_OR_ENOSYS(sysdep, ret) ({ \ + if (!(sysdep)) { \ + __ensure_warn("Library function fails due to missing sysdep", \ + __FILE__, __LINE__, __func__); \ + errno = ENOSYS; \ + return (ret); \ + } \ + sysdep; \ + }) + +#define MLIBC_STUB_BODY ({ MLIBC_UNIMPLEMENTED(); __builtin_unreachable(); }) + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_ENSURE_H */ + diff --git a/ext2_root/usr/include/bits/ether_addr.h b/ext2_root/usr/include/bits/ether_addr.h new file mode 100644 index 0000000..3c8f595 --- /dev/null +++ b/ext2_root/usr/include/bits/ether_addr.h @@ -0,0 +1,10 @@ +#ifndef MLIBC_ETHER_ADDR_H +#define MLIBC_ETHER_ADDR_H + +#include + +struct ether_addr { + uint8_t ether_addr_octet[6]; +} __attribute__((__packed__)); + +#endif /* MLIBC_ETHER_ADDR_H */ diff --git a/ext2_root/usr/include/bits/file.h b/ext2_root/usr/include/bits/file.h new file mode 100644 index 0000000..44566f7 --- /dev/null +++ b/ext2_root/usr/include/bits/file.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_FILE_T_H +#define MLIBC_FILE_T_H + +typedef struct __mlibc_file_base FILE; + +#endif /* MLIBC_FILE_T_H */ diff --git a/ext2_root/usr/include/bits/getopt.h b/ext2_root/usr/include/bits/getopt.h new file mode 100644 index 0000000..c2ae35f --- /dev/null +++ b/ext2_root/usr/include/bits/getopt.h @@ -0,0 +1,15 @@ +#ifndef MLIBC_BITS_GETOPT +#define MLIBC_BITS_GETOPT + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#endif /* MLIBC_BITS_GETOPT */ diff --git a/ext2_root/usr/include/bits/glibc/glibc_assert.h b/ext2_root/usr/include/bits/glibc/glibc_assert.h new file mode 100644 index 0000000..9165d29 --- /dev/null +++ b/ext2_root/usr/include/bits/glibc/glibc_assert.h @@ -0,0 +1,32 @@ +#ifndef MLIBC_GLIBC_ASSERT_H +#define MLIBC_GLIBC_ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +__attribute__ ((__noreturn__)) void __assert_fail_perror(int __errno, const char *__file, unsigned int __line, + const char *__function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_GLIBC_ASSERT_H */ + +#ifdef NDEBUG + +#undef assert_perror +#define assert_perror(ignore) ((void)0) + +#else /* NDEBUG */ + +#undef assert_perror +#define assert_perror(errno) (!(errno) \ + || (__assert_fail_perror((errno), __FILE__, __LINE__, __func__), 0)) + +#endif /* NDEBUG */ diff --git a/ext2_root/usr/include/bits/glibc/glibc_icmp6.h b/ext2_root/usr/include/bits/glibc/glibc_icmp6.h new file mode 100644 index 0000000..eafde16 --- /dev/null +++ b/ext2_root/usr/include/bits/glibc/glibc_icmp6.h @@ -0,0 +1,21 @@ +#ifndef _GLIBC_NETINET_ICMP6_H +#define _GLIBC_NETINET_ICMP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define ND_OPT_PREFIX_INFORMATION 3 +#define ND_OPT_REDIRECTED_HEADER 4 +#define ND_OPT_MTU 5 +#define ND_OPT_RTR_ADV_INTERVAL 7 +#define ND_OPT_HOME_AGENT_INFO 8 + +#ifdef __cplusplus +} +#endif + +#endif /* _GLIBC_NETINET_ICMP6_H */ + diff --git a/ext2_root/usr/include/bits/glibc/glibc_malloc.h b/ext2_root/usr/include/bits/glibc/glibc_malloc.h new file mode 100644 index 0000000..62cf009 --- /dev/null +++ b/ext2_root/usr/include/bits/glibc/glibc_malloc.h @@ -0,0 +1,17 @@ +#ifndef _GLIBC_MALLOC_H +#define _GLIBC_MALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +size_t malloc_usable_size(void *__ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* _GLIBC_MALLOC_H */ + diff --git a/ext2_root/usr/include/bits/glibc/glibc_search.h b/ext2_root/usr/include/bits/glibc/glibc_search.h new file mode 100644 index 0000000..338bb28 --- /dev/null +++ b/ext2_root/usr/include/bits/glibc/glibc_search.h @@ -0,0 +1,22 @@ +#ifndef _GLIBC_SEARCH_H +#define _GLIBC_SEARCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int hcreate_r(size_t __num_entries, struct hsearch_data *__htab); +void hdestroy_r(struct hsearch_data *__htab); +int hsearch_r(ENTRY __item, ACTION __action, ENTRY **__ret, struct hsearch_data *__htab); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _GLIBC_SEARCH_H */ diff --git a/ext2_root/usr/include/bits/glibc/glibc_signal.h b/ext2_root/usr/include/bits/glibc/glibc_signal.h new file mode 100644 index 0000000..4761aba --- /dev/null +++ b/ext2_root/usr/include/bits/glibc/glibc_signal.h @@ -0,0 +1,24 @@ +#ifndef MLIBC_GLIBC_SIGNAL_H +#define MLIBC_GLIBC_SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int tgkill(int __tgid, int __tid, int __sig); + +#if defined(_GNU_SOURCE) + +typedef void (*sighandler_t)(int __signo); + +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_GLIBC_SIGNAL_H */ diff --git a/ext2_root/usr/include/bits/glibc/glibc_stdlib.h b/ext2_root/usr/include/bits/glibc/glibc_stdlib.h new file mode 100644 index 0000000..99724b7 --- /dev/null +++ b/ext2_root/usr/include/bits/glibc/glibc_stdlib.h @@ -0,0 +1,20 @@ +#ifndef MLIBC_GLIBC_STDLIB_H +#define MLIBC_GLIBC_STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*comparison_fn_t) (const void *__a, const void *__b); + +#ifndef __MLIBC_ABI_ONLY + +int rpmatch(const char *__resp); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_GLIBC_STDLIB_H */ diff --git a/ext2_root/usr/include/bits/inline-definition.h b/ext2_root/usr/include/bits/inline-definition.h new file mode 100644 index 0000000..939059a --- /dev/null +++ b/ext2_root/usr/include/bits/inline-definition.h @@ -0,0 +1,19 @@ +#ifndef MLIBC_INLINE_DEFINITION_H +#define MLIBC_INLINE_DEFINITION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __MLIBC_EMIT_INLINE_DEFINITIONS +#define __MLIBC_INLINE_DEFINITION +#else +#define __MLIBC_INLINE_DEFINITION __attribute__((__gnu_inline__)) extern __inline__ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_INLINE_DEFINITION_H */ + diff --git a/ext2_root/usr/include/bits/machine.h b/ext2_root/usr/include/bits/machine.h new file mode 100644 index 0000000..ad000f6 --- /dev/null +++ b/ext2_root/usr/include/bits/machine.h @@ -0,0 +1,126 @@ + +#ifndef MLIBC_MACHINE_H +#define MLIBC_MACHINE_H + +#include + +#if defined (__i386__) +struct __mlibc_jmpbuf_register_state { + uint32_t ebx; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t esp; + uint32_t eip; +}; +#elif defined (__x86_64__) +struct __mlibc_jmpbuf_register_state { + uint64_t rbx; + uint64_t rbp; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rsp; + uint64_t rip; +}; +#elif defined (__aarch64__) +struct __mlibc_jmpbuf_register_state { + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + uint64_t x23; + uint64_t x24; + uint64_t x25; + uint64_t x26; + uint64_t x27; + uint64_t x28; + uint64_t x29; + uint64_t x30; + uint64_t sp; + uint64_t pad; + uint64_t d8; + uint64_t d9; + uint64_t d10; + uint64_t d11; + uint64_t d12; + uint64_t d13; + uint64_t d14; + uint64_t d15; +}; +#elif defined (__riscv) && __riscv_xlen == 64 +struct __mlibc_jmpbuf_register_state { + uint64_t ra; + uint64_t s0; + uint64_t s1; + uint64_t s2; + uint64_t s3; + uint64_t s4; + uint64_t s5; + uint64_t s6; + uint64_t s7; + uint64_t s8; + uint64_t s9; + uint64_t s10; + uint64_t s11; + uint64_t sp; + double fs0; + double fs1; + double fs2; + double fs3; + double fs4; + double fs5; + double fs6; + double fs7; + double fs8; + double fs9; + double fs10; + double fs11; +}; +#elif defined (__m68k__) +struct __mlibc_jmpbuf_register_state { + uint32_t d2; + uint32_t d3; + uint32_t d4; + uint32_t d5; + uint32_t d6; + uint32_t d7; + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + uint32_t sp; + uint32_t pc; +}; +#elif defined (__loongarch64) +struct __mlibc_jmpbuf_register_state { + uint64_t ra; + uint64_t sp; + uint64_t u0; + uint64_t s0; + uint64_t s1; + uint64_t s2; + uint64_t s3; + uint64_t s4; + uint64_t s5; + uint64_t s6; + uint64_t s7; + uint64_t s8; + double fs0; + double fs1; + double fs2; + double fs3; + double fs4; + double fs5; + double fs6; + double fs7; +}; +#else +# error "Missing architecture specific code" +#endif + +#endif /* MLIBC_MACHINE_H */ + diff --git a/ext2_root/usr/include/bits/mbstate.h b/ext2_root/usr/include/bits/mbstate.h new file mode 100644 index 0000000..e65604b --- /dev/null +++ b/ext2_root/usr/include/bits/mbstate.h @@ -0,0 +1,12 @@ +#ifndef MLIBC_MBSTATE_H +#define MLIBC_MBSTATE_H + +typedef struct __mlibc_mbstate { + short __progress; + short __shift; + unsigned int __cpoint; +} mbstate_t; + +#define __MLIBC_MBSTATE_INITIALIZER {0, 0, 0} + +#endif /* MLIBC_MBSTATE_H */ diff --git a/ext2_root/usr/include/bits/nl_item.h b/ext2_root/usr/include/bits/nl_item.h new file mode 100644 index 0000000..12e25b0 --- /dev/null +++ b/ext2_root/usr/include/bits/nl_item.h @@ -0,0 +1,84 @@ + +#ifndef _NL_ITEM_H +#define _NL_ITEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int nl_item; + +#define ABDAY_1 0x60000 +#define ABDAY_2 0x60001 +#define ABDAY_3 0x60002 +#define ABDAY_4 0x60003 +#define ABDAY_5 0x60004 +#define ABDAY_6 0x60005 +#define ABDAY_7 0x60006 + +#define DAY_1 0x60007 +#define DAY_2 0x60008 +#define DAY_3 0x60009 +#define DAY_4 0x6000A +#define DAY_5 0x6000B +#define DAY_6 0x6000C +#define DAY_7 0x6000D + +#define ABMON_1 0x6000E +#define ABMON_2 0x6000F +#define ABMON_3 0x60010 +#define ABMON_4 0x60011 +#define ABMON_5 0x60012 +#define ABMON_6 0x60013 +#define ABMON_7 0x60014 +#define ABMON_8 0x60015 +#define ABMON_9 0x60016 +#define ABMON_10 0x60017 +#define ABMON_11 0x60018 +#define ABMON_12 0x60019 + +#define MON_1 0x6001A +#define MON_2 0x6001B +#define MON_3 0x6001C +#define MON_4 0x6001D +#define MON_5 0x6001E +#define MON_6 0x6001F +#define MON_7 0x60020 +#define MON_8 0x60021 +#define MON_9 0x60022 +#define MON_10 0x60023 +#define MON_11 0x60024 +#define MON_12 0x60025 + +#define AM_STR 0x60026 +#define PM_STR 0x60027 + +#define D_T_FMT 0x60028 +#define D_FMT 0x60029 +#define T_FMT 0x6002A +#define T_FMT_AMPM 0x6002B + +#define ERA 0x6002C +#define ERA_D_FMT 0x6002D +#define ALT_DIGITS 0x6002E +#define ERA_D_T_FMT 0x6002F +#define ERA_T_FMT 0x60030 + +#define CODESET 0x30000 + +#define CRNCYSTR 0x40000 + +#define RADIXCHAR 0x50000 +#define DECIMAL_POINT RADIXCHAR +#define THOUSEP 0x50001 +#define THOUSANDS_SEP THOUSEP + +#define YESEXPR 0x70000 +#define NOEXPR 0x70001 + +#ifdef __cplusplus +} +#endif + +#endif /* _NL_ITEM_H */ + diff --git a/ext2_root/usr/include/bits/null.h b/ext2_root/usr/include/bits/null.h new file mode 100644 index 0000000..176008f --- /dev/null +++ b/ext2_root/usr/include/bits/null.h @@ -0,0 +1,16 @@ + +#ifndef MLIBC_NULL_H +#define MLIBC_NULL_H + +#ifdef NULL +#undef NULL +#endif + +#ifndef __cplusplus +# define NULL ((void *)0) +#else +# define NULL 0 +#endif + +#endif /* MLIBC_NULL_H */ + diff --git a/ext2_root/usr/include/bits/off_t.h b/ext2_root/usr/include/bits/off_t.h new file mode 100644 index 0000000..43dcd9e --- /dev/null +++ b/ext2_root/usr/include/bits/off_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_OFF_T_H +#define MLIBC_OFF_T_H + +/* TODO: use something like int64_t instead? */ +typedef long off_t; +typedef long off64_t; + +#endif /* MLIBC_OFF_T_H */ diff --git a/ext2_root/usr/include/bits/posix/fd_set.h b/ext2_root/usr/include/bits/posix/fd_set.h new file mode 100644 index 0000000..5f4ea26 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/fd_set.h @@ -0,0 +1,10 @@ +#ifndef MLIBC_FD_SET_H +#define MLIBC_FD_SET_H + +#include + +typedef struct { + __mlibc_uint8 fds_bits[128]; +} fd_set; + +#endif /* MLIBC_FD_SET_H */ diff --git a/ext2_root/usr/include/bits/posix/id_t.h b/ext2_root/usr/include/bits/posix/id_t.h new file mode 100644 index 0000000..6cba848 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/id_t.h @@ -0,0 +1,6 @@ +#ifndef _MLIBC_ID_T_H +#define _MLIBC_ID_T_H + +typedef unsigned int id_t; + +#endif /* _MLIBC_ID_T_H */ diff --git a/ext2_root/usr/include/bits/posix/in_addr_t.h b/ext2_root/usr/include/bits/posix/in_addr_t.h new file mode 100644 index 0000000..014e384 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/in_addr_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_IN_ADDR_H +#define MLIBC_IN_ADDR_H + +#include + +typedef uint32_t in_addr_t; + +#endif /* MLIBC_IN_ADDR_H */ diff --git a/ext2_root/usr/include/bits/posix/in_port_t.h b/ext2_root/usr/include/bits/posix/in_port_t.h new file mode 100644 index 0000000..537828a --- /dev/null +++ b/ext2_root/usr/include/bits/posix/in_port_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_IN_PORT_H +#define MLIBC_IN_PORT_H + +#include + +typedef uint16_t in_port_t; + +#endif /* MLIBC_IN_PORT_H */ diff --git a/ext2_root/usr/include/bits/posix/iovec.h b/ext2_root/usr/include/bits/posix/iovec.h new file mode 100644 index 0000000..62a3580 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/iovec.h @@ -0,0 +1,11 @@ +#ifndef MLIBC_IOVEC_H +#define MLIBC_IOVEC_H + +#include + +struct iovec { + void *iov_base; + __mlibc_size iov_len; +}; + +#endif /* MLIBC_IOVEC_H */ diff --git a/ext2_root/usr/include/bits/posix/locale_t.h b/ext2_root/usr/include/bits/posix/locale_t.h new file mode 100644 index 0000000..171e298 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/locale_t.h @@ -0,0 +1,14 @@ +#ifndef _LOCALE_T_H +#define _LOCALE_T_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *locale_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _LOCALE_T_H */ diff --git a/ext2_root/usr/include/bits/posix/posix_ctype.h b/ext2_root/usr/include/bits/posix/posix_ctype.h new file mode 100644 index 0000000..4e715fb --- /dev/null +++ b/ext2_root/usr/include/bits/posix/posix_ctype.h @@ -0,0 +1,36 @@ +#ifndef _POSIX_CTYPE_H +#define _POSIX_CTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int isalnum_l(int __c, locale_t __loc); +int isalpha_l(int __c, locale_t __loc); +int isblank_l(int __c, locale_t __loc); +int iscntrl_l(int __c, locale_t __loc); +int isdigit_l(int __c, locale_t __loc); +int isgraph_l(int __c, locale_t __loc); +int islower_l(int __c, locale_t __loc); +int isprint_l(int __c, locale_t __loc); +int ispunct_l(int __c, locale_t __loc); +int isspace_l(int __c, locale_t __loc); +int isupper_l(int __c, locale_t __loc); +int isxdigit_l(int __c, locale_t __loc); + +int isascii_l(int __c, locale_t __loc); + +int tolower_l(int __c, locale_t __loc); +int toupper_l(int __c, locale_t __loc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _POSIX_CTYPE_H */ diff --git a/ext2_root/usr/include/bits/posix/posix_locale.h b/ext2_root/usr/include/bits/posix/posix_locale.h new file mode 100644 index 0000000..2ba2c77 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/posix_locale.h @@ -0,0 +1,23 @@ +#ifndef MLIBC_POSIX_LOCALE_H +#define MLIBC_POSIX_LOCALE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +locale_t newlocale(int __category_mask, const char *__locale, locale_t __base); +void freelocale(locale_t __locobj); +locale_t uselocale(locale_t __locobj); +locale_t duplocale(locale_t __locobj); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_LOCALE_H */ diff --git a/ext2_root/usr/include/bits/posix/posix_signal.h b/ext2_root/usr/include/bits/posix/posix_signal.h new file mode 100644 index 0000000..2d67a84 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/posix_signal.h @@ -0,0 +1,113 @@ + +#ifndef MLIBC_POSIX_SIGNAL_H +#define MLIBC_POSIX_SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ + +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ + +#if defined(__x86_64__) +/* Start Glibc stuff */ + +struct _libc_fpxreg { + unsigned short int significand[4]; + unsigned short int exponent; + unsigned short int __glibc_reserved1[3]; +}; + +struct _libc_xmmreg { + uint32_t element[4]; +}; + +struct _libc_fpstate { + uint16_t cwd; + int16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t dp; + uint32_t mxcsr; + uint32_t mxcr_mask; + struct _libc_fpxreg _st[8]; + struct _libc_xmmreg _xmm[16]; + uint32_t __glibc_reserved1[24]; +}; + +typedef struct _libc_fpstate *fpregset_t; +/* End Glibc stuff */ + +typedef unsigned long int greg_t; +#endif + +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ + +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ + +#ifndef __MLIBC_ABI_ONLY + +/* functions to block / wait for signals */ +int sigsuspend(const sigset_t *__sigmask); +int sigprocmask(int __how, const sigset_t *__restrict __sigmask, sigset_t *__restrict __oldmask); + +int pthread_sigmask(int __how, const sigset_t *__restrict __sigmask, sigset_t *__restrict __oldmask); +int pthread_kill(pthread_t __thrd, int __sig); + +/* functions to handle signals */ +int sigaction(int __signum, const struct sigaction *__restrict __act, struct sigaction *__restrict __oldact); +int sigpending(sigset_t *__set); + +int siginterrupt(int __sig, int __flag); + +int sigaltstack(const stack_t *__restrict __ss, stack_t *__restrict __oss); + +/* functions to raise signals */ +int kill(pid_t __pid, int __number); +int killpg(int __pgrp, int __sig); + +int sigtimedwait(const sigset_t *__restrict __set, siginfo_t *__restrict __info, const struct timespec *__restrict __timeout); +int sigwait(const sigset_t *__restrict __set, int *__restrict __sig); +int sigwaitinfo(const sigset_t *__restrict __set, siginfo_t *__restrict __info); + +/* Glibc extension */ +#if __MLIBC_GLIBC_OPTION +int sigisemptyset(const sigset_t *__set); +#endif /* __MLIBC_GLIBC_OPTION */ + +int sigqueue(pid_t __pid, int __sig, const union sigval __value); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_SIGNAL_H */ + diff --git a/ext2_root/usr/include/bits/posix/posix_stdio.h b/ext2_root/usr/include/bits/posix/posix_stdio.h new file mode 100644 index 0000000..360be7c --- /dev/null +++ b/ext2_root/usr/include/bits/posix/posix_stdio.h @@ -0,0 +1,76 @@ + +#ifndef MLIBC_POSIX_STDIO_H +#define MLIBC_POSIX_STDIO_H + +#include +#include +#include +#include + +/* MISSING: var_list */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define P_tmpdir "/tmp" + +#ifndef __MLIBC_ABI_ONLY + +int fileno(FILE *__file); +FILE *fdopen(int __fd, const char *__mode); + +FILE *fmemopen(void *__restrict __buf, size_t __size, const char *__restrict __mode); +int pclose(FILE *__file); +FILE *popen(const char *__command, const char *__type); +FILE *open_memstream(char **__buf, size_t *__sizeloc); + +int fseeko(FILE *__stream, off_t __offset, int __whence); +int fseeko64(FILE *__stream, off64_t __offset, int __whence); +off_t ftello(FILE *__stream); +off64_t ftello64(FILE *__stream); + +__attribute__((format(__printf__, 2, 3))) int dprintf(int __fd, const char *__format, ...); +__attribute__((format(__printf__, 2, 0))) +int vdprintf(int __fd, const char *__format, __builtin_va_list __args); + +char *fgetln(FILE *__stream, size_t *__size); + +char *tempnam(const char *__dir, const char *__pfx); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define RENAME_EXCHANGE (1 << 1) + +/* GNU extensions */ +typedef ssize_t (cookie_read_function_t)(void *__cookie, char *__buffer, size_t __size); +typedef ssize_t (cookie_write_function_t)(void *__cookie, const char *__buffer, size_t __size); +typedef int (cookie_seek_function_t)(void *__cookie, off_t *, int); +typedef int (cookie_close_function_t)(void *__cookie); + +typedef struct _IO_cookie_io_functions_t { + cookie_read_function_t *read; + cookie_write_function_t *write; + cookie_seek_function_t *seek; + cookie_close_function_t *close; +} cookie_io_functions_t; + +#ifndef __MLIBC_ABI_ONLY + +#if defined(_GNU_SOURCE) + +FILE *fopencookie(void *__restrict __cookie, const char *__restrict __mode, cookie_io_functions_t __io_funcs); + +#endif /* defined(_GNU_SOURCE) */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +/* MISSING: various functions and macros */ + +#endif /* MLIBC_POSIX_STDIO_H */ + + diff --git a/ext2_root/usr/include/bits/posix/posix_stdlib.h b/ext2_root/usr/include/bits/posix/posix_stdlib.h new file mode 100644 index 0000000..350f857 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/posix_stdlib.h @@ -0,0 +1,77 @@ + +#ifndef MLIBC_POSIX_STDLIB_H +#define MLIBC_POSIX_STDLIB_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +long random(void); +double drand48(void); +double erand48(unsigned short __s[3]); +unsigned short *seed48(unsigned short __s[3]); +void srand48(long int __seed); +long int mrand48(void); +long jrand48(unsigned short __s[3]); +char *initstate(unsigned int __seed, char *__state, size_t __size); +char *setstate(char *__state); +void srandom(unsigned int __seed); + +/* ---------------------------------------------------------------------------- */ +/* Environment. */ +/* ---------------------------------------------------------------------------- */ + +int putenv(char *__string); +int setenv(const char *__name, const char *__value, int __overwrite); +int unsetenv(const char *__name); + +/* ---------------------------------------------------------------------------- */ +/* Path handling. */ +/* ---------------------------------------------------------------------------- */ + +int mkstemp(char *__pattern); +int mkstemps(char *__pattern, int __suffixlen); +int mkostemp(char *__pattern, int __flags); +int mkostemps(char *__pattern, int __suffixlen, int __flags); +char *mkdtemp(char *__path); + +char *realpath(const char *__restrict __path, char *__restrict __out); + +/* ---------------------------------------------------------------------------- */ +/* Pseudoterminals */ +/* ---------------------------------------------------------------------------- */ + +int posix_openpt(int __flags); +int grantpt(int __fd); +int unlockpt(int __fd); +char *ptsname(int __fd); +int ptsname_r(int __fd, char *__buf, size_t __len); + +double strtod_l(const char *__restrict__ __nptr, char ** __restrict__ __endptr, locale_t __loc); +long double strtold_l(const char *__restrict__ __nptr, char ** __restrict__ __endptr, locale_t __loc); +float strtof_l(const char *__restrict __string, char **__restrict __end, locale_t __loc); + +int getsubopt(char **__restrict__ __optionp, char *const *__restrict__ __tokens, char **__restrict__ __valuep); + +/* GNU extension */ +char *secure_getenv(const char *__name); +char *canonicalize_file_name(const char *__name); + +/* BSD extension */ +void *reallocarray(void *__ptr, size_t __count, size_t __size); + +int clearenv(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_STDLIB_H */ + diff --git a/ext2_root/usr/include/bits/posix/posix_string.h b/ext2_root/usr/include/bits/posix/posix_string.h new file mode 100644 index 0000000..1e2096a --- /dev/null +++ b/ext2_root/usr/include/bits/posix/posix_string.h @@ -0,0 +1,59 @@ + +#ifndef MLIBC_POSIX_STRING_H +#define MLIBC_POSIX_STRING_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *strdup(const char *__string); +char *strndup(const char *__string, size_t __max_size); +size_t strnlen(const char *__s, size_t __max_size); +char *strtok_r(char *__restrict __s, const char *__restrict __delim, char **__restrict __ptr); +char *strsep(char **__stringp, const char *__delim); +char *strsignal(int __sig); +char *stpcpy(char *__restrict __dest, const char *__restrict __src); +char *stpncpy(char *__restrict __dest, const char *__restrict __src, size_t __n); +void *memccpy(void *__restrict __dest, const void *__restrict __src, int __c, size_t __n); + +int strcoll_l(const char *__s1, const char *__s2, locale_t __locale); + +char *strerror_l(int __errnum, locale_t __locale); + +/* GNU extensions. */ +#if defined(_GNU_SOURCE) +char *strcasestr(const char *__s1, const char *__s2); +#define strdupa(x) ({ \ + const char *__str = (x); \ + size_t __len = strlen(__str) + 1; \ + char *__buf = alloca(__len); \ + (char *) memcpy(__buf, __str, __len); \ +}) +#define strndupa(x, y) ({ \ + const char *__str = (x); \ + size_t __len = strnlen(__str, (y)) + 1; \ + char *__buf = alloca(__len); \ + __buf[__len - 1] = '\0'; \ + (char *) memcpy(__buf, __str, __len - 1); \ +}) +void *memrchr(const void *__m, int __c, size_t __n); +#endif /* defined(_GNU_SOURCE) */ + +/* BSD extensions */ +size_t strlcpy(char *__d, const char *__s, size_t __n); +size_t strlcat(char *__d, const char *__s, size_t __n); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_STRING_H */ + diff --git a/ext2_root/usr/include/bits/posix/posix_time.h b/ext2_root/usr/include/bits/posix/posix_time.h new file mode 100644 index 0000000..71d2cd8 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/posix_time.h @@ -0,0 +1,43 @@ +#ifndef MLIBC_POSIX_TIME_H +#define MLIBC_POSIX_TIME_H + +#include +#include +#include +#include +#include + +#define TIMER_ABSTIME 1 + +#ifdef __cplusplus +extern "C" { +#endif + +struct itimerspec { + struct timespec it_interval; + struct timespec it_value; +}; + +#ifndef __MLIBC_ABI_ONLY + +int timer_getoverrun(timer_t __timerid); + +int utimes(const char *__filename, const struct timeval __tv[2]); + +/* Not standardized, Linux and BSDs have it */ +int futimes(int __fd, const struct timeval __tv[2]); +int lutimes(const char *__filename, const struct timeval __tv[2]); + +int timer_create(clockid_t __clockid, struct sigevent *__restrict __sevp, timer_t *__restrict __timerid); +int timer_settime(timer_t __timerid, int __flags, const struct itimerspec *__restrict __new_value, + struct itimerspec *__restrict __old_value); +int timer_gettime(timer_t __timerid, struct itimerspec *__curr_value); +int timer_delete(timer_t __timerid); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_TIME_H */ diff --git a/ext2_root/usr/include/bits/posix/posix_wctype.h b/ext2_root/usr/include/bits/posix/posix_wctype.h new file mode 100644 index 0000000..3c4bd7a --- /dev/null +++ b/ext2_root/usr/include/bits/posix/posix_wctype.h @@ -0,0 +1,43 @@ +#ifndef _POSIX_WCTYPE_H +#define _POSIX_WCTYPE_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int iswalnum_l(wint_t __wc, locale_t __loc); +int iswblank_l(wint_t __wc, locale_t __loc); +int iswcntrl_l(wint_t __wc, locale_t __loc); +int iswdigit_l(wint_t __wc, locale_t __loc); +int iswgraph_l(wint_t __wc, locale_t __loc); +int iswlower_l(wint_t __wc, locale_t __loc); +int iswprint_l(wint_t __wc, locale_t __loc); +int iswpunct_l(wint_t __wc, locale_t __loc); +int iswspace_l(wint_t __wc, locale_t __loc); +int iswupper_l(wint_t __wc, locale_t __loc); +int iswxdigit_l(wint_t __wc, locale_t __loc); +int iswalpha_l(wint_t __wc, locale_t __loc); + +wctype_t wctype_l(const char *__string, locale_t __loc); +int iswctype_l(wint_t __wc, wctype_t __type, locale_t __loc); + +wint_t towlower_l(wint_t __wc, locale_t __loc); +wint_t towupper_l(wint_t __wc, locale_t __loc); + +wctrans_t wctrans_l(const char *__string, locale_t __loc); +wint_t towctrans_l(wint_t __wc, wctrans_t __trans, locale_t __loc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _POSIX_WCTYPE_H */ diff --git a/ext2_root/usr/include/bits/posix/pthread_t.h b/ext2_root/usr/include/bits/posix/pthread_t.h new file mode 100644 index 0000000..f5e6b70 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/pthread_t.h @@ -0,0 +1,8 @@ +#ifndef _MLIBC_BITS_PTHREAD_T_HPP +#define _MLIBC_BITS_PTHREAD_T_HPP + +#include + +typedef struct __mlibc_thread_data *pthread_t; + +#endif /* _MLIBC_BITS_PTHREAD_T_HPP */ diff --git a/ext2_root/usr/include/bits/posix/stat.h b/ext2_root/usr/include/bits/posix/stat.h new file mode 100644 index 0000000..f08b760 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/stat.h @@ -0,0 +1,24 @@ +#ifndef MLIBC_STAT_H +#define MLIBC_STAT_H + +#include + +/* Used by utimensat and friends */ +#define UTIME_NOW ((1l << 30) - 1l) +#define UTIME_OMIT ((1l << 30) - 2l) + +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +/* POSIX compatibility macros */ +#define st_atime st_atim.tv_sec +#define st_mtime st_mtim.tv_sec +#define st_ctime st_ctim.tv_sec + +#endif /* MLIBC_STAT_H */ + diff --git a/ext2_root/usr/include/bits/posix/timer_t.h b/ext2_root/usr/include/bits/posix/timer_t.h new file mode 100644 index 0000000..b965f37 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/timer_t.h @@ -0,0 +1,6 @@ +#ifndef _MLIBC_TIMER_T_H +#define _MLIBC_TIMER_T_H + +typedef void * timer_t; + +#endif /* _MLIBC_TIMER_T_H */ diff --git a/ext2_root/usr/include/bits/posix/timeval.h b/ext2_root/usr/include/bits/posix/timeval.h new file mode 100644 index 0000000..22670a2 --- /dev/null +++ b/ext2_root/usr/include/bits/posix/timeval.h @@ -0,0 +1,12 @@ +#ifndef MLIBC_TIMEVAL_H +#define MLIBC_TIMEVAL_H + +#include +#include + +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; + +#endif /* MLIBC_TIMEVAL_H */ diff --git a/ext2_root/usr/include/bits/search.h b/ext2_root/usr/include/bits/search.h new file mode 100644 index 0000000..8e650a0 --- /dev/null +++ b/ext2_root/usr/include/bits/search.h @@ -0,0 +1,24 @@ +#ifndef _MLIBC_INTERNAL_SEARCH_H +#define _MLIBC_INTERNAL_SEARCH_H + +#include + +typedef enum { + FIND, + ENTER +} ACTION; + +typedef struct entry { + char *key; + void *data; +} ENTRY; + +struct _ENTRY; + +struct hsearch_data { + struct _ENTRY *table; + unsigned int size; + unsigned int filled; +}; + +#endif /* _MLIBC_INTERNAL_SEARCH_H */ diff --git a/ext2_root/usr/include/bits/sigset_t.h b/ext2_root/usr/include/bits/sigset_t.h new file mode 100644 index 0000000..b3d18a3 --- /dev/null +++ b/ext2_root/usr/include/bits/sigset_t.h @@ -0,0 +1,25 @@ +#ifndef MLIBC_BITS_SIGSET_T_H +#define MLIBC_BITS_SIGSET_T_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* functions to manage sigset_t */ +int sigemptyset(sigset_t *__sigset); +int sigfillset(sigset_t *__sigset); +int sigaddset(sigset_t *__sigset, int __sig); +int sigdelset(sigset_t *__sigset, int __sig); +int sigismember(const sigset_t *__sigset, int __sig); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /*MLIBC_BITS_SIGSET_T_H */ diff --git a/ext2_root/usr/include/bits/size_t.h b/ext2_root/usr/include/bits/size_t.h new file mode 100644 index 0000000..125875c --- /dev/null +++ b/ext2_root/usr/include/bits/size_t.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_SIZE_T_H +#define MLIBC_SIZE_T_H + +typedef __SIZE_TYPE__ size_t; + +#endif /* MLIBC_SIZE_T_H */ diff --git a/ext2_root/usr/include/bits/ssize_t.h b/ext2_root/usr/include/bits/ssize_t.h new file mode 100644 index 0000000..a1a8471 --- /dev/null +++ b/ext2_root/usr/include/bits/ssize_t.h @@ -0,0 +1,15 @@ + +#ifndef MLIBC_SSIZE_T_H +#define MLIBC_SSIZE_T_H + +/* TODO: use ptrdiff_t instead? */ +#if __UINTPTR_MAX__ == __UINT64_MAX__ +typedef long ssize_t; +#elif __UINTPTR_MAX__ == __UINT32_MAX__ +typedef int ssize_t; +#else +#error "unsupported architecture" +#endif + +#endif /* MLIBC_SSIZE_T_H */ + diff --git a/ext2_root/usr/include/bits/threads.h b/ext2_root/usr/include/bits/threads.h new file mode 100644 index 0000000..defc9c4 --- /dev/null +++ b/ext2_root/usr/include/bits/threads.h @@ -0,0 +1,81 @@ +#ifndef _INTERNAL_THREADS_H +#define _INTERNAL_THREADS_H + +#include +#include +#include +#include + +/* values for pthread_attr_{get,set}detachstate(). */ +#define __MLIBC_THREAD_CREATE_JOINABLE 0 +#define __MLIBC_THREAD_CREATE_DETACHED 1 + +/* values for pthread_mutexattr_{get,set}type(). */ +#define __MLIBC_THREAD_MUTEX_DEFAULT 0 +#define __MLIBC_THREAD_MUTEX_NORMAL 0 +#define __MLIBC_THREAD_MUTEX_ERRORCHECK 1 +#define __MLIBC_THREAD_MUTEX_RECURSIVE 2 + +/* values for pthread_mutexattr_{get,set}pshared(). */ +#define __MLIBC_THREAD_PROCESS_PRIVATE 0 +#define __MLIBC_THREAD_PROCESS_SHARED 1 + +/* values for pthread_mutexattr_{get,set}robust(). */ +#define __MLIBC_THREAD_MUTEX_STALLED 0 +#define __MLIBC_THREAD_MUTEX_ROBUST 1 + +/* Values for pthread_mutexattr_{get,set}protocol() */ +#define __MLIBC_THREAD_PRIO_NONE 0 +#define __MLIBC_THREAD_PRIO_INHERIT 1 +#define __MLIBC_THREAD_PRIO_PROTECT 2 + +#define __MLIBC_THREAD_MUTEX_INITIALIZER {0, 0, 0, 0} + +struct sched_param { + int sched_priority; +}; + +struct __mlibc_thread_data; + +struct __mlibc_threadattr { + size_t __mlibc_guardsize; + size_t __mlibc_stacksize; + void *__mlibc_stackaddr; + int __mlibc_detachstate; + int __mlibc_scope; + int __mlibc_inheritsched; + struct sched_param __mlibc_schedparam; + int __mlibc_schedpolicy; + cpu_set_t *__mlibc_cpuset; + size_t __mlibc_cpusetsize; + sigset_t __mlibc_sigmask; + int __mlibc_sigmaskset; +}; + +struct __mlibc_mutex { + unsigned int __mlibc_state; + unsigned int __mlibc_recursion; + unsigned int __mlibc_flags; + int __mlibc_prioceiling; +}; + +struct __mlibc_mutexattr { + int __mlibc_type; + int __mlibc_robust; + int __mlibc_protocol; + int __mlibc_pshared; + int __mlibc_prioceiling; +}; + +struct __mlibc_cond { + unsigned int __mlibc_seq; + unsigned int __mlibc_flags; + clockid_t __mlibc_clock; +}; + +struct __mlibc_condattr { + int __mlibc_pshared; + clockid_t __mlibc_clock; +}; + +#endif /* _INTERNAL_THREADS_H */ diff --git a/ext2_root/usr/include/bits/types.h b/ext2_root/usr/include/bits/types.h new file mode 100644 index 0000000..ee8b2ee --- /dev/null +++ b/ext2_root/usr/include/bits/types.h @@ -0,0 +1,408 @@ +#ifndef _MLIBC_INTERNAL_TYPES_H +#define _MLIBC_INTERNAL_TYPES_H + +typedef __UINT8_TYPE__ __mlibc_uint8; +typedef __UINT16_TYPE__ __mlibc_uint16; +typedef __UINT32_TYPE__ __mlibc_uint32; +typedef __UINT64_TYPE__ __mlibc_uint64; + +typedef __INT8_TYPE__ __mlibc_int8; +typedef __INT16_TYPE__ __mlibc_int16; +typedef __INT32_TYPE__ __mlibc_int32; +typedef __INT64_TYPE__ __mlibc_int64; + +/* Clang and GCC have different mechanisms for INT32_C and friends. */ +#ifdef __clang__ +# define __MLIBC_C_EXPAND_JOIN(x, suffix) x ## suffix +# define __MLIBC_C_JOIN(x, suffix) __MLIBC_C_EXPAND_JOIN(x, suffix) + +# define __MLIBC_INT8_C(x) __MLIBC_C_JOIN(x, __INT8_C_SUFFIX__) +# define __MLIBC_INT16_C(x) __MLIBC_C_JOIN(x, __INT16_C_SUFFIX__) +# define __MLIBC_INT32_C(x) __MLIBC_C_JOIN(x, __INT32_C_SUFFIX__) +# define __MLIBC_INT64_C(x) __MLIBC_C_JOIN(x, __INT64_C_SUFFIX__) + +# define __MLIBC_UINT8_C(x) __MLIBC_C_JOIN(x, __UINT8_C_SUFFIX__) +# define __MLIBC_UINT16_C(x) __MLIBC_C_JOIN(x, __UINT16_C_SUFFIX__) +# define __MLIBC_UINT32_C(x) __MLIBC_C_JOIN(x, __UINT32_C_SUFFIX__) +# define __MLIBC_UINT64_C(x) __MLIBC_C_JOIN(x, __UINT64_C_SUFFIX__) + +# define __MLIBC_INTMAX_C(x) __MLIBC_C_JOIN(x, __INTMAX_C_SUFFIX__) +# define __MLIBC_UINTMAX_C(x) __MLIBC_C_JOIN(x, __UINTMAX_C_SUFFIX__) +#else +# define __MLIBC_INT8_C(x) __INT8_C(x) +# define __MLIBC_INT16_C(x) __INT16_C(x) +# define __MLIBC_INT32_C(x) __INT32_C(x) +# define __MLIBC_INT64_C(x) __INT64_C(x) + +# define __MLIBC_UINT8_C(x) __UINT8_C(x) +# define __MLIBC_UINT16_C(x) __UINT16_C(x) +# define __MLIBC_UINT32_C(x) __UINT32_C(x) +# define __MLIBC_UINT64_C(x) __UINT64_C(x) + +# define __MLIBC_INTMAX_C(x) __INTMAX_C(x) +# define __MLIBC_UINTMAX_C(x) __UINTMAX_C(x) +#endif + +#define __MLIBC_INT8_MAX __INT8_MAX__ +#define __MLIBC_INT16_MAX __INT16_MAX__ +#define __MLIBC_INT32_MAX __INT32_MAX__ +#define __MLIBC_INT64_MAX __INT64_MAX__ + +#define __MLIBC_INT8_MIN (-__MLIBC_INT8_MAX - 1) +#define __MLIBC_INT16_MIN (-__MLIBC_INT16_MAX - 1) +#define __MLIBC_INT32_MIN (-__MLIBC_INT32_MAX - 1) +#define __MLIBC_INT64_MIN (-__MLIBC_INT64_MAX - 1) + +#define __MLIBC_UINT8_MAX __UINT8_MAX__ +#define __MLIBC_UINT16_MAX __UINT16_MAX__ +#define __MLIBC_UINT32_MAX __UINT32_MAX__ +#define __MLIBC_UINT64_MAX __UINT64_MAX__ + +/* Fast types (signed). */ + +#if defined (__i386__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int32 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT32_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT32_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT32_MIN + +typedef __mlibc_int32 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT32_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT32_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT32_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__x86_64__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__aarch64__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__riscv) && __riscv_xlen == 64 + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__m68k__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int32 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT16_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT16_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT16_MIN + +typedef __mlibc_int32 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT32_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT32_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT32_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__loongarch64) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#else +# error "Missing architecture specific code" +#endif + +/* Fast types (unsigned). */ + +#if defined (__i386__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT32_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT32_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT32_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT32_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT32_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT32_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__x86_64__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__aarch64__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__riscv) && __riscv_xlen == 64 + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__m68k__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT16_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT16_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT16_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT32_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT32_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT32_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__loongarch64) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#else +# error "Missing architecture specific code" +#endif + +/* Special types. */ + +typedef __INTMAX_TYPE__ __mlibc_intmax; +typedef __INTPTR_TYPE__ __mlibc_intptr; +typedef __PTRDIFF_TYPE__ __mlibc_ptrdiff; +#define __MLIBC_INTMAX_MAX __INTMAX_MAX__ +#define __MLIBC_INTMAX_MIN (-__INTMAX_MAX__ - 1) +#define __MLIBC_INTPTR_MAX __INTPTR_MAX__ +#define __MLIBC_INTPTR_MIN (-__INTPTR_MAX__ - 1) +#define __MLIBC_PTRDIFF_MAX __PTRDIFF_MAX__ +#define __MLIBC_PTRDIFF_MIN (-__PTRDIFF_MAX__ - 1) + +typedef __UINTMAX_TYPE__ __mlibc_uintmax; +typedef __UINTPTR_TYPE__ __mlibc_uintptr; +typedef __SIZE_TYPE__ __mlibc_size; +#define __MLIBC_UINTMAX_MAX __UINTMAX_MAX__ +#define __MLIBC_UINTPTR_MAX __UINTPTR_MAX__ +#define __MLIBC_SIZE_MAX __SIZE_MAX__ + +/* Other limits. */ + +#define __MLIBC_WCHAR_MAX __WCHAR_MAX__ +#define __MLIBC_WCHAR_MIN __WCHAR_MIN__ + +#define __MLIBC_WINT_MAX __WINT_MAX__ +#define __MLIBC_WINT_MIN __WINT_MIN__ + +#define __MLIBC_SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ +#define __MLIBC_SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__ + +/* ---------------------------------------------------------------------------- */ +/* Sanity checking. Make sure that we agree with the compiler's ABI. */ +/* ---------------------------------------------------------------------------- */ + +#if defined(__cplusplus) && defined(__cpp_static_assert) && __cpp_static_assert >= 200410L +# define __MLIBC_STATIC_ASSERT(c, text) static_assert(c, text) +#elif !defined(__cplusplus) +/* _Static_assert is an extension in C89/C99. */ +# define __MLIBC_STATIC_ASSERT(c, text) __extension__ _Static_assert(c, text) +#else +# define __MLIBC_STATIC_ASSERT(c, text) extern int __static_assert_unavailable +#endif + +#define __MLIBC_CHECK_TYPE(T1, T2) __MLIBC_STATIC_ASSERT(sizeof(T1) == sizeof(T2),\ + #T1 " != " #T2) + +/* Least-width. */ +__MLIBC_CHECK_TYPE(__mlibc_int8, __INT_LEAST8_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int16, __INT_LEAST16_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int32, __INT_LEAST32_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int64, __INT_LEAST64_TYPE__); + +__MLIBC_CHECK_TYPE(__mlibc_uint8, __UINT_LEAST8_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint16, __UINT_LEAST16_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint32, __UINT_LEAST32_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint64, __UINT_LEAST64_TYPE__); + +/* Fast-width. */ +/* Unfortunately, GCC and Clang disagree about fast types. */ +#ifndef __clang__ + __MLIBC_CHECK_TYPE(__mlibc_int_fast8, __INT_FAST8_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast16, __INT_FAST16_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast32, __INT_FAST32_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast64, __INT_FAST64_TYPE__); + + __MLIBC_CHECK_TYPE(__mlibc_uint_fast8, __UINT_FAST8_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast16, __UINT_FAST16_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast32, __UINT_FAST32_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast64, __UINT_FAST64_TYPE__); +#endif + +#endif /* _MLIBC_INTERNAL_TYPES_H */ diff --git a/ext2_root/usr/include/bits/wchar.h b/ext2_root/usr/include/bits/wchar.h new file mode 100644 index 0000000..478eb90 --- /dev/null +++ b/ext2_root/usr/include/bits/wchar.h @@ -0,0 +1,9 @@ +#ifndef MLIBC_WCHAR_H +#define MLIBC_WCHAR_H + +#include + +#define WCHAR_MAX __MLIBC_WCHAR_MAX +#define WCHAR_MIN __MLIBC_WCHAR_MIN + +#endif /* MLIBC_WCHAR_H */ diff --git a/ext2_root/usr/include/bits/wchar_t.h b/ext2_root/usr/include/bits/wchar_t.h new file mode 100644 index 0000000..83aa5e5 --- /dev/null +++ b/ext2_root/usr/include/bits/wchar_t.h @@ -0,0 +1,12 @@ + +#ifndef MLIBC_WCHAR_T_H +#define MLIBC_WCHAR_T_H + +#ifndef __cplusplus + +typedef __WCHAR_TYPE__ wchar_t; + +#endif + +#endif /* MLIBC_WCHAR_T_H */ + diff --git a/ext2_root/usr/include/bits/wctrans_t.h b/ext2_root/usr/include/bits/wctrans_t.h new file mode 100644 index 0000000..acd5878 --- /dev/null +++ b/ext2_root/usr/include/bits/wctrans_t.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_WCTRANS_T_H +#define MLIBC_WCTRANS_T_H + +typedef unsigned long wctrans_t; + +#endif /* MLIBC_WCTRANS_T_H */ diff --git a/ext2_root/usr/include/bits/wctype_t.h b/ext2_root/usr/include/bits/wctype_t.h new file mode 100644 index 0000000..7cb6de4 --- /dev/null +++ b/ext2_root/usr/include/bits/wctype_t.h @@ -0,0 +1,7 @@ +#ifndef MLIBC_WCTYPE_T_H +#define MLIBC_WCTYPE_T_H + +typedef unsigned long wctype_t; + +#endif /* MLIBC_WCTYPE_T_H */ + diff --git a/ext2_root/usr/include/bits/winsize.h b/ext2_root/usr/include/bits/winsize.h new file mode 100644 index 0000000..3edbcd4 --- /dev/null +++ b/ext2_root/usr/include/bits/winsize.h @@ -0,0 +1,13 @@ + +#ifndef MLIBC_WINSIZE_H +#define MLIBC_WINSIZE_H + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#endif /* MLIBC_WINSIZE_H */ + diff --git a/ext2_root/usr/include/bits/wint_t.h b/ext2_root/usr/include/bits/wint_t.h new file mode 100644 index 0000000..f5aaea3 --- /dev/null +++ b/ext2_root/usr/include/bits/wint_t.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_WINT_T_H +#define MLIBC_WINT_T_H + +typedef __WINT_TYPE__ wint_t; + +#endif /* MLIBC_WINT_T_H */ diff --git a/ext2_root/usr/include/byteswap.h b/ext2_root/usr/include/byteswap.h new file mode 100644 index 0000000..29b2838 --- /dev/null +++ b/ext2_root/usr/include/byteswap.h @@ -0,0 +1,23 @@ + +#ifndef _BYTESWAP_H +#define _BYTESWAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define bswap_16(x) __builtin_bswap16(x) +#define bswap_32(x) __builtin_bswap32(x) +#define bswap_64(x) __builtin_bswap64(x) + +/* Some programs like eudev call these functions instead */ +#define __bswap_16(x) __builtin_bswap16(x) +#define __bswap_32(x) __builtin_bswap32(x) +#define __bswap_64(x) __builtin_bswap64(x) + +#ifdef __cplusplus +} +#endif + +#endif /* _BYTESWAP_H */ + diff --git a/ext2_root/usr/include/complex.h b/ext2_root/usr/include/complex.h new file mode 100644 index 0000000..1eae120 --- /dev/null +++ b/ext2_root/usr/include/complex.h @@ -0,0 +1,134 @@ +/* $NetBSD: complex.h,v 1.3 2010/09/15 16:11:30 christos Exp $ */ + +/* + * Written by Matthias Drochner. + * Public domain. + */ + +#ifndef _COMPLEX_H +#define _COMPLEX_H + +#define complex _Complex +#define _Complex_I 1.0fi +#define I _Complex_I + +#define CMPLX(x, y) ((double complex)__builtin_complex((double)(x), (double)(y))) +#define CMPLXF(x, y) ((float complex)__builtin_complex((float)(x), (float)(y))) +#define CMPLXL(x, y) ((long double complex)__builtin_complex((long double)(x), (long double)(y))) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* 7.3.5 Trigonometric functions */ +/* 7.3.5.1 The cacos functions */ +double complex cacos(double complex __x); +float complex cacosf(float complex __x); + +/* 7.3.5.2 The casin functions */ +double complex casin(double complex __x); +float complex casinf(float complex __x); + +/* 7.3.5.1 The catan functions */ +double complex catan(double complex __x); +float complex catanf(float complex __x); + +/* 7.3.5.1 The ccos functions */ +double complex ccos(double complex __x); +float complex ccosf(float complex __x); + +/* 7.3.5.1 The csin functions */ +double complex csin(double complex __x); +float complex csinf(float complex __x); + +/* 7.3.5.1 The ctan functions */ +double complex ctan(double complex __x); +float complex ctanf(float complex __x); + +/* 7.3.6 Hyperbolic functions */ +/* 7.3.6.1 The cacosh functions */ +double complex cacosh(double complex __x); +float complex cacoshf(float complex __x); + +/* 7.3.6.2 The casinh functions */ +double complex casinh(double complex __x); +float complex casinhf(float complex __x); + +/* 7.3.6.3 The catanh functions */ +double complex catanh(double complex __x); +float complex catanhf(float complex __x); + +/* 7.3.6.4 The ccosh functions */ +double complex ccosh(double complex __x); +float complex ccoshf(float complex __x); + +/* 7.3.6.5 The csinh functions */ +double complex csinh(double complex __x); +float complex csinhf(float complex __x); + +/* 7.3.6.6 The ctanh functions */ +double complex ctanh(double complex __x); +float complex ctanhf(float complex __x); + +/* 7.3.7 Exponential and logarithmic functions */ +/* 7.3.7.1 The cexp functions */ +double complex cexp(double complex __x); +float complex cexpf(float complex __x); + +/* 7.3.7.2 The clog functions */ +double complex clog(double complex __x); +float complex clogf(float complex __x); + +/* 7.3.8 Power and absolute-value functions */ +/* 7.3.8.1 The cabs functions */ +/*#ifndef __LIBM0_SOURCE__ */ +/* avoid conflict with historical cabs(struct complex) */ +/* double cabs(double complex __x) __RENAME(__c99_cabs); + float cabsf(float complex __x) __RENAME(__c99_cabsf); + #endif +*/ +double cabs(double complex __x); +float cabsf(float complex __x); + +/* 7.3.8.2 The cpow functions */ +double complex cpow(double complex __x, double complex __y); +float complex cpowf(float complex __x, float complex __y); + +/* 7.3.8.3 The csqrt functions */ +double complex csqrt(double complex __x); +float complex csqrtf(float complex __x); + +/* 7.3.9 Manipulation functions */ +/* 7.3.9.1 The carg functions */ +double carg(double complex __x); +float cargf(float complex __x); + +/* 7.3.9.2 The cimag functions */ +double cimag(double complex __x); +float cimagf(float complex __x); +long double cimagl(long double complex __x); + +/* 7.3.9.3 The conj functions */ +double complex conj(double complex __x); +float complex conjf(float complex __x); +/*long double complex conjl(long double complex __x); */ + +/* 7.3.9.4 The cproj functions */ +double complex cproj(double complex __x); +float complex cprojf(float complex __x); +/*long double complex cprojl(long double complex __x); */ + +/* 7.3.9.5 The creal functions */ +double creal(double complex __x); +float crealf(float complex __x); +long double creall(long double complex __x); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! _COMPLEX_H */ diff --git a/ext2_root/usr/include/ctype.h b/ext2_root/usr/include/ctype.h new file mode 100644 index 0000000..151f1f8 --- /dev/null +++ b/ext2_root/usr/include/ctype.h @@ -0,0 +1,46 @@ +#ifndef _CTYPE_H +#define _CTYPE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* Character classification function [7.4.1] */ +int isalnum(int __c); +int isalpha(int __c); +int isblank(int __c); +int iscntrl(int __c); +int isdigit(int __c); +int isgraph(int __c); +int islower(int __c); +int isprint(int __c); +int ispunct(int __c); +int isspace(int __c); +int isupper(int __c); +int isxdigit(int __c); + +/* glibc extensions. */ +int isascii(int __c); + +/* Character case mapping functions [7.4.2] */ +int tolower(int __c); +int toupper(int __c); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* Borrowed from glibc */ +#define toascii(c) ((c) & 0x7f) + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif /* _CTYPE_H */ diff --git a/ext2_root/usr/include/dirent.h b/ext2_root/usr/include/dirent.h new file mode 100644 index 0000000..95d609a --- /dev/null +++ b/ext2_root/usr/include/dirent.h @@ -0,0 +1,77 @@ + +#ifndef _DIRENT_H +#define _DIRENT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +#define __MLIBC_DIRENT_BODY ino_t d_ino; \ + off_t d_off; \ + unsigned short d_reclen; \ + unsigned char d_type; \ + char d_name[1024]; + +struct dirent { + __MLIBC_DIRENT_BODY +}; + +struct dirent64 { + __MLIBC_DIRENT_BODY +}; + +#define d_fileno d_ino + +#undef __MLIBC_DIRENT_BODY + +#define IFTODT(mode) (((mode) & 0170000) >> 12) + +struct __mlibc_dir_struct { + int __handle; + __mlibc_size __ent_next; + __mlibc_size __ent_limit; + char __ent_buffer[2048]; + struct dirent __current; +}; + +typedef struct __mlibc_dir_struct DIR; + +#ifndef __MLIBC_ABI_ONLY + +int alphasort(const struct dirent **__a, const struct dirent **__b); +int closedir(DIR *__dirp); +int dirfd(DIR *__dirp); +DIR *fdopendir(int __fd); +DIR *opendir(const char *__pathname); +struct dirent *readdir(DIR *__dirp); +struct dirent64 *readdir64(DIR *__dirp); +int readdir_r(DIR *__restrict __dirp, struct dirent *__restrict __entry, struct dirent **__restrict __res); +void rewinddir(DIR *__dirp); +int scandir(const char *__pathname, struct dirent ***__res, int (*__select)(const struct dirent *__entry), + int (*__compare)(const struct dirent **__a, const struct dirent **__b)); +void seekdir(DIR *__dirp, long __loc); +long telldir(DIR *__dirp); +int versionsort(const struct dirent **__a, const struct dirent **__b); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DIRENT_H */ + diff --git a/ext2_root/usr/include/dlfcn.h b/ext2_root/usr/include/dlfcn.h new file mode 100644 index 0000000..2abb1f1 --- /dev/null +++ b/ext2_root/usr/include/dlfcn.h @@ -0,0 +1,96 @@ + +#ifndef _DLFCN_H +#define _DLFCN_H + +#include + +#define RTLD_LOCAL 0 +#define RTLD_LAZY 1 +#define RTLD_NOW 2 +#define RTLD_NOLOAD 4 +#define RTLD_DEEPBIND 8 +#define RTLD_GLOBAL 256 +#define RTLD_NODELETE 4096 + +#define RTLD_NEXT ((void *)-1) +#define RTLD_DEFAULT ((void *)0) + +#define RTLD_DL_SYMENT 1 +#define RTLD_DL_LINKMAP 2 + +#define RTLD_DI_LINKMAP 2 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int dlclose(void *__handle); +char *dlerror(void); +void *dlopen(const char *__name, int __flags); +void *dlsym(void *__restrict __handle, const char *__restrict __name); +void *dlvsym(void *__restrict __handle, const char *__restrict __name, const char *__restrict __version); + +#endif /* !__MLIBC_ABI_ONLY */ + +#if defined(_GNU_SOURCE) && __MLIBC_GLIBC_OPTION + +/*gnu extension */ +typedef struct { + const char *dli_fname; + void *dli_fbase; + const char *dli_sname; + void *dli_saddr; +} Dl_info; + +#if defined(__i386__) +#define DLFO_STRUCT_HAS_EH_DBASE 1 +#define DLFO_STRUCT_HAS_EH_COUNT 0 +#define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME +#elif defined(__arm__) +#define DLFO_STRUCT_HAS_EH_DBASE 0 +#define DLFO_STRUCT_HAS_EH_COUNT 1 +#define DLFO_EH_SEGMENT_TYPE PT_ARM_EXIDX +#else +#define DLFO_STRUCT_HAS_EH_DBASE 0 +#define DLFO_STRUCT_HAS_EH_COUNT 0 +#define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME +#endif + +struct dl_find_object { + unsigned long long dlfo_flags; + void *dlfo_map_start; + void *dlfo_map_end; + struct link_map *dlfo_link_map; + void *dlfo_eh_frame; +#if DLFO_STRUCT_HAS_EH_DBASE + void *dlfo_eh_dbase; +#if __INTPTR_WIDTH__ == 32 + unsigned int __unused0; +#endif +#endif +#if DLFO_STRUCT_HAS_EH_COUNT + int dlfo_eh_count; + unsigned int __unused1; +#endif + unsigned long long __dlfo_unused[7]; +}; + +#ifndef __MLIBC_ABI_ONLY + +int dladdr(const void *__ptr, Dl_info *__out); +int dladdr1(const void *__ptr, Dl_info *__out, void **__extra, int __flags); +int dlinfo(void *__restrict __handle, int __request, void *__restrict __info); +int _dl_find_object(void *__address, struct dl_find_object *__result); + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif /* defined(_GNU_SOURCE) && __MLIBC_GLIBC_OPTION */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DLFCN_H */ + diff --git a/ext2_root/usr/include/elf.h b/ext2_root/usr/include/elf.h new file mode 100644 index 0000000..78c6be8 --- /dev/null +++ b/ext2_root/usr/include/elf.h @@ -0,0 +1,722 @@ +#ifndef _ELF_H +#define _ELF_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* TODO: Convert the enums to #defines so that they work with #ifdef. */ + +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define ELFOSABI_SYSV 0 +#define EM_X86_64 62 + +#define SHF_WRITE 1 +#define SHF_ALLOC 2 +#define SHF_EXECINSTR 4 +#define SHF_STRINGS 32 +#define SHF_INFO_LINK 64 +#define SHF_TLS 1024 + +#define NT_AUXV 6 + +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint16_t Elf64_Section; +typedef Elf64_Half Elf64_Versym; + +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint16_t Elf32_Section; +typedef Elf32_Half Elf32_Versym; + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Machine type */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point address */ + Elf32_Off e_phoff; /* Program header offset */ + Elf32_Off e_shoff; /* Section header offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* Size of program header entry */ + Elf32_Half e_phnum; /* Number of program header entries */ + Elf32_Half e_shentsize; /* Size of section header entry */ + Elf32_Half e_shnum; /* Number of section header entries */ + Elf32_Half e_shstrndx; /* Section name string table index */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Machine type */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point address */ + Elf64_Off e_phoff; /* Program header offset */ + Elf64_Off e_shoff; /* Section header offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size */ + Elf64_Half e_phentsize; /* Size of program header entry */ + Elf64_Half e_phnum; /* Number of program header entries */ + Elf64_Half e_shentsize; /* Size of section header entry */ + Elf64_Half e_shnum; /* Number of section header entries */ + Elf64_Half e_shstrndx; /* Section name string table index */ +} Elf64_Ehdr; + +typedef struct { + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef entry */ +} Elf32_Verdef; + +typedef struct { + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ +} Elf64_Verdef; + +typedef struct { + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux entry */ +} Elf32_Verdaux; + +typedef struct { + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */ +} Elf64_Verdaux; + +typedef struct { + Elf32_Half vn_version; + Elf32_Half vn_cnt; + Elf32_Word vn_file; + Elf32_Word vn_aux; + Elf32_Word vn_next; +} Elf32_Verneed; + +typedef struct { + Elf64_Half vn_version; + Elf64_Half vn_cnt; + Elf64_Word vn_file; + Elf64_Word vn_aux; + Elf64_Word vn_next; +} Elf64_Verneed; + +typedef struct { + Elf32_Word vna_hash; + Elf32_Half vna_flags; + Elf32_Half vna_other; + Elf32_Word vna_name; + Elf32_Word vna_next; +} Elf32_Vernaux; + +typedef struct { + Elf64_Word vna_hash; + Elf64_Half vna_flags; + Elf64_Half vna_other; + Elf64_Word vna_name; + Elf64_Word vna_next; +} Elf64_Vernaux; + +typedef struct { + Elf64_Xword m_value; + Elf64_Xword m_info; + Elf64_Xword m_poffset; + Elf64_Half m_repeat; + Elf64_Half m_stride; +} Elf64_Move; + +typedef struct { + Elf64_Word l_name; + Elf64_Word l_time_stamp; + Elf64_Word l_checksum; + Elf64_Word l_version; + Elf64_Word l_flags; +} Elf64_Lib; + +enum { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4 +}; + +enum { + SHN_UNDEF = 0, + SHN_ABS = 0xFFF1 +}; + +enum { + STN_UNDEF = 0 +}; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Section st_shndx; +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_BIND(unsigned char info) { + return info >> 4; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_TYPE(unsigned char info) { + return info & 0x0F; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_INFO(unsigned char bind, unsigned char type) { + return (bind << 4) | type; +} + +typedef struct { + Elf64_Half si_boundto; + Elf64_Half si_flags; +} Elf64_Syminfo; + +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_BIND(unsigned char info) { + return info >> 4; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_TYPE(unsigned char info) { + return info & 0xF; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_INFO(unsigned char bind, unsigned char type) { + return (bind << 4) | (type & 0xF); +} + +enum { + STB_GLOBAL = 1, + STB_WEAK = 2, + STB_GNU_UNIQUE = 10, + STB_LOPROC = 13, + STB_HIPROC = 15 +}; + +enum { + STT_OBJECT = 1, + STT_FUNC = 2, + STT_TLS = 6, + STT_GNU_IFUNC = 10, + STT_LOPROC = 13, + STT_HIPROC = 15 +}; + +enum { + R_X86_64_NONE = 0, + R_X86_64_64 = 1, + R_X86_64_PC32 = 2, + R_X86_64_PLT32 = 4, + R_X86_64_COPY = 5, + R_X86_64_GLOB_DAT = 6, + R_X86_64_JUMP_SLOT = 7, + R_X86_64_RELATIVE = 8, + R_X86_64_GOTPCREL = 9, + R_X86_64_32 = 10, + R_X86_64_32S = 11, + R_X86_64_PC16 = 13, + R_X86_64_PC8 = 15, + R_X86_64_DTPMOD64 = 16, + R_X86_64_DTPOFF64 = 17, + R_X86_64_TPOFF64 = 18, + R_X86_64_PC64 = 24, + R_X86_64_GOTPC32 = 26, + R_X86_64_TLSDESC = 36, + R_X86_64_IRELATIVE = 37 +}; + +enum { + R_386_NONE = 0, + R_386_32 = 1, + R_386_PC32 = 2, + R_386_COPY = 5, + R_386_GLOB_DAT = 6, + R_386_JMP_SLOT = 7, + R_386_RELATIVE = 8, + R_386_TLS_TPOFF = 14, + R_386_TLS_DTPMOD32 = 35, + R_386_TLS_DTPOFF32 = 36, + R_386_TLS_DESC = 41, + R_386_IRELATIVE = 42 +}; + +enum { + R_AARCH64_NONE = 0, + R_AARCH64_ABS64 = 257, + R_AARCH64_COPY = 1024, + R_AARCH64_GLOB_DAT = 1025, + R_AARCH64_JUMP_SLOT = 1026, + R_AARCH64_RELATIVE = 1027, + R_AARCH64_TLS_DTPMOD64 = 1028, + R_AARCH64_TLS_DTPREL64 = 1029, + R_AARCH64_TLS_TPREL64 = 1030, + R_AARCH64_TLSDESC = 1031, + R_AARCH64_IRELATIVE = 1032 +}; + +#define R_AARCH64_TLS_DTPREL R_AARCH64_TLS_DTPREL64 +#define R_AARCH64_TLS_DTPMOD R_AARCH64_TLS_DTPMOD64 +#define R_AARCH64_TLS_TPREL R_AARCH64_TLS_TPREL64 + +enum { + R_RISCV_NONE = 0, + R_RISCV_32 = 1, + R_RISCV_64 = 2, + R_RISCV_RELATIVE = 3, + R_RISCV_COPY = 4, + R_RISCV_JUMP_SLOT = 5, + R_RISCV_TLS_DTPMOD32 = 6, + R_RISCV_TLS_DTPMOD64 = 7, + R_RISCV_TLS_DTPREL32 = 8, + R_RISCV_TLS_DTPREL64 = 9, + R_RISCV_TLS_TPREL32 = 10, + R_RISCV_TLS_TPREL64 = 11, + R_RISCV_TLSDESC = 12, /* currently a draft but looking good */ + R_RISCV_IRELATIVE = 58 +}; + +enum { + R_68K_NONE = 0, + R_68K_32 = 1, + R_68K_PC32 = 4, + R_68K_COPY = 19, + R_68K_GLOB_DAT = 20, + R_68K_JMP_SLOT = 21, + R_68K_RELATIVE = 22, + + R_68K_TLS_DTPMOD32 = 40, + R_68K_TLS_DTPREL32= 41, + R_68K_TLS_TPREL32= 42 +}; + +enum { + R_LARCH_NONE = 0, + R_LARCH_32 = 1, + R_LARCH_64 = 2, + R_LARCH_RELATIVE = 3, + R_LARCH_COPY = 4, + R_LARCH_JUMP_SLOT = 5, + R_LARCH_TLS_DTPMOD32 = 6, + R_LARCH_TLS_DTPMOD64 = 7, + R_LARCH_TLS_DTPREL32 = 8, + R_LARCH_TLS_DTPREL64 = 9, + R_LARCH_TLS_TPREL32 = 10, + R_LARCH_TLS_TPREL64 = 11, + R_LARCH_IRELATIVE = 12 +}; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf64_Addr r_offset; + uint64_t r_info; +} Elf64_Rel; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +typedef Elf32_Word Elf32_Relr; +typedef Elf64_Xword Elf64_Relr; + +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_SYM(Elf64_Xword info) { + return info >> 32; +} +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_TYPE(Elf64_Xword info) { + return info & 0xFFFFFFFF; +} +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_INFO(Elf64_Xword sym, Elf64_Xword type) { + return ((((Elf64_Xword)(sym)) << 32) + (type)); +} + +__MLIBC_INLINE_DEFINITION Elf32_Word ELF32_R_SYM(Elf32_Word info) { + return info >> 8; +} +__MLIBC_INLINE_DEFINITION Elf32_Word ELF32_R_TYPE(Elf32_Word info) { + return info & 0xFF; +} + +enum { + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_TLS = 7, + PT_NUM = 8, + PT_LOOS = 0x60000000, + PT_GNU_EH_FRAME = 0x6474E550, + PT_GNU_STACK = 0x6474E551, + PT_GNU_RELRO = 0x6474E552, + PT_GNU_PROPERTY = 0x6474E553, + PT_SUNWBSS = 0x6ffffffa, + PT_SUNWSTACK = 0x6ffffffb, + PT_HISUNW = 0x6fffffff, + PT_HIOS = 0x6fffffff, + PT_LOPROC = 0x70000000, + PT_ARM_EXIDX = 0x70000001, + PT_RISCV_ATTRIBUTES = 0x70000003, + PT_HIPROC = 0x7fffffff +}; + +enum { + PF_X = 1, + PF_W = 2, + PF_R = 4 +}; + +typedef struct { + Elf32_Word p_type; /* Type of segment */ + Elf32_Off p_offset; /* Offset in file */ + Elf32_Addr p_vaddr; /* Virtual address in memory */ + Elf32_Addr p_paddr; /* Reserved */ + Elf32_Word p_filesz; /* Size of segment in file */ + Elf32_Word p_memsz; /* Size of segment in memory */ + Elf32_Word p_flags; /* Segment attributes */ + Elf32_Word p_align; /* Alignment of segment */ +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; /* Type of segment */ + Elf64_Word p_flags; /* Segment attributes */ + Elf64_Off p_offset; /* Offset in file */ + Elf64_Addr p_vaddr; /* Virtual address in memory */ + Elf64_Addr p_paddr; /* Reserved */ + Elf64_Xword p_filesz; /* Size of segment in file */ + Elf64_Xword p_memsz; /* Size of segment in memory */ + Elf64_Xword p_align; /* Alignment of segment */ +} Elf64_Phdr; + +enum { + DT_NULL = 0, + DT_NEEDED = 1, + DT_PLTRELSZ = 2, + DT_PLTGOT = 3, + DT_HASH = 4, + DT_STRTAB = 5, + DT_SYMTAB = 6, + DT_RELA = 7, + DT_RELASZ = 8, + DT_RELAENT = 9, + DT_STRSZ = 10, + DT_SYMENT = 11, + DT_INIT = 12, + DT_FINI = 13, + DT_SONAME = 14, + DT_RPATH = 15, + DT_SYMBOLIC = 16, + DT_REL = 17, + DT_RELSZ = 18, + DT_RELENT = 19, + DT_TEXTREL = 22, + DT_BIND_NOW = 24, + DT_INIT_ARRAY = 25, + DT_FINI_ARRAY = 26, + DT_INIT_ARRAYSZ = 27, + DT_FINI_ARRAYSZ = 28, + DT_RUNPATH = 29, + DT_PLTREL = 20, + DT_DEBUG = 21, + DT_JMPREL = 23, + DT_FLAGS = 30, + DT_PREINIT_ARRAY = 32, + DT_PREINIT_ARRAYSZ = 33, + DT_RELRSZ = 35, + DT_RELR = 36, + DT_RELRENT = 37, + DT_LOOS = 0x6000000d, + DT_HIOS = 0x6ffff000, + DT_GNU_HASH = 0x6ffffef5, + DT_TLSDESC_PLT = 0x6ffffef6, + DT_TLSDESC_GOT = 0x6ffffef7, + DT_VERSYM = 0x6ffffff0, + DT_RELACOUNT = 0x6ffffff9, + DT_RELCOUNT = 0x6ffffffa, + DT_FLAGS_1 = 0x6ffffffb, + DT_VERDEF = 0x6ffffffc, + DT_VERDEFNUM = 0x6ffffffd, + DT_VERNEED = 0x6ffffffe, + DT_VERNEEDNUM = 0x6fffffff, + DT_LOPROC = 0x70000000, + DT_HIPROC = 0x7fffffff +}; + +enum { + /* For DT_FLAGS. */ + DF_SYMBOLIC = 0x02, + DF_TEXTREL = 0x04, + DF_BIND_NOW = 0x08, + DF_STATIC_TLS = 0x10, + + /* For DT_FLAGS_1. */ + DF_1_NOW = 0x00000001, + DF_1_NODELETE = 0x00000008, + DF_1_PIE = 0x08000000 +}; + +/* Valid values for note segment descriptor files for core files */ +#define NT_PRSTATUS 1 +#define NT_FPREGSET 2 +#define NT_PRPSINFO 3 + +/* Build ID bits as generated by ld --build-id */ +#define NT_GNU_BUILD_ID 3 + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + +typedef struct { + uint64_t a_type; + union { + uint64_t a_val; + } a_un; +} Elf64_auxv_t; + +typedef struct { + uint32_t a_type; + union { + uint32_t a_val; + } a_un; +} Elf32_auxv_t; + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + +/* ST_TYPE (subfield of st_info) values (symbol type) */ +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +/* ST_BIND (subfield of st_info) values (symbol binding) */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +/* sh_type (section type) values */ +#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_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_SYMTAB_SHNDX 18 + +/* special section indices */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff +#define SHN_HIRESERVE 0xff00 + +/* values for e_machine */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_MIPS 8 +#define EM_PARISC 15 +#define EM_PPC 20 +#define EM_PPC64 21 +#define EM_S390 22 +#define EM_ARM 40 +#define EM_SH 42 +#define EM_SPARCV9 43 +#define EM_IA_64 50 +#define EM_X86_64 62 +#define EM_BLACKFIN 106 +#define EM_AARCH64 183 +#define EM_RISCV 243 +#define EM_LOONGARCH 258 + +/* Linux notes this value as being interim; however applications are using this (Qt6), so we define it here. */ +#define EM_ALPHA 0x9026 + +/* values for e_version */ +#define EV_NONE 0 +#define EV_CURRENT 1 +#define EV_NUM 2 + +/* e_indent constants */ +#define EI_MAG0 0 +#define ELFMAG0 0x7f + +#define EI_MAG1 1 +#define ELFMAG1 'E' + +#define EI_MAG2 2 +#define ELFMAG2 'L' + +#define EI_MAG3 3 +#define ELFMAG3 'F' + +#define ELFMAG "\177ELF" +#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_HPUX 1 +#define ELFOSABI_NETBSD 2 +#define ELFOSABI_GNU 3 +#define ELFOSABI_LINUX ELFOSABI_GNU +#define ELFOSABI_SOLARIS 6 +#define ELFOSABI_AIX 7 +#define ELFOSABI_IRIX 8 +#define ELFOSABI_FREEBSD 9 +#define ELFOSABI_OPENBSD 12 + +#define EI_ABIVERSION 8 + +#define ELF_NOTE_GNU "GNU" + +/* Values for a_type + * these are standard values and shared across at least glibc, musl and freebsd + */ + +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_NOTELF 10 +#define AT_UID 11 +#define AT_EUID 12 +#define AT_GID 13 +#define AT_EGID 14 + +/* Values for Elfxx_Verdef::vd_flags and Elfxx_Vernaux::vna_flags */ +#define VER_FLG_BASE 1 /* Version definition of the file itself */ +#define VER_FLG_WEAK 2 /* Weak version identifier */ + +/* rtld requires presence of some a_type (AT_*) values that are not standardized in the ELF spec */ +#if !defined(AT_EXECFN) || !defined(AT_RANDOM) || !defined(AT_SECURE) +#error "sysdeps' auxv.h is missing some defines that are required for rtld operation" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ELF_H */ diff --git a/ext2_root/usr/include/endian.h b/ext2_root/usr/include/endian.h new file mode 100644 index 0000000..129af98 --- /dev/null +++ b/ext2_root/usr/include/endian.h @@ -0,0 +1,54 @@ +#ifndef _ENDIAN_H +#define _ENDIAN_H + +#include + +#ifdef __GNUC__ +# define BYTE_ORDER __BYTE_ORDER__ +# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +# define BIG_ENDIAN __ORDER_BIG_ENDIAN__ +# define PDP_ENDIAN __ORDER_PDP_ENDIAN__ + +# define __BYTE_ORDER __BYTE_ORDER__ +#ifndef __LITTLE_ENDIAN /* Linux kernel headers define this already */ +# define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif +# define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +# define __PDP_ENDIAN __ORDER_PDP_ENDIAN__ +#else +# error "Unsupported compiler" +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +# define htobe16(x) __bswap_16(x) +# define htole16(x) (uint16_t)(x) +# define be16toh(x) __bswap_16(x) +# define le16toh(x) (uint16_t)(x) + +# define htobe32(x) __bswap_32(x) +# define htole32(x) (uint32_t)(x) +# define be32toh(x) __bswap_32(x) +# define le32toh(x) (uint32_t)(x) + +# define htobe64(x) __bswap_64(x) +# define htole64(x) (uint64_t)(x) +# define be64toh(x) __bswap_64(x) +# define le64toh(x) (uint64_t)(x) +#else +# define htobe16(x) (uint16_t)(x) +# define htole16(x) __bswap_16(x) +# define be16toh(x) (uint16_t)(x) +# define le16toh(x) __bswap_16(x) + +# define htobe32(x) (uint32_t)(x) +# define htole32(x) __bswap_32(x) +# define be32toh(x) (uint32_t)(x) +# define le32toh(x) __bswap_32(x) + +# define htobe64(x) (uint64_t)(x) +# define htole64(x) __bswap_64(x) +# define be64toh(x) (uint64_t)(x) +# define le64toh(x) __bswap_64(x) +#endif + +#endif /* _ENDIAN_H */ diff --git a/ext2_root/usr/include/err.h b/ext2_root/usr/include/err.h new file mode 100644 index 0000000..88341e9 --- /dev/null +++ b/ext2_root/usr/include/err.h @@ -0,0 +1,33 @@ +#ifndef _ERR_H +#define _ERR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +__attribute__((__format__(__printf__, 1, 2))) void warn(const char *__format, ...); +__attribute__((__format__(__printf__, 1, 0))) void vwarn(const char *__format, va_list __args); +__attribute__((__format__(__printf__, 1, 2))) void warnx(const char *__format, ...); +__attribute__((__format__(__printf__, 1, 0))) void vwarnx(const char *__format, va_list __args); + +__attribute__((__noreturn__, __format__(__printf__, 2, 3))) +void err(int __errnum, const char *__format, ...); +__attribute__((__noreturn__, __format__(__printf__, 2, 0))) +void verr(int __errnum, const char *__format, va_list __args); +__attribute__((__noreturn__, , __format__(__printf__, 2, 3))) +void errx(int __errnum, const char *__format, ...); +__attribute__((__noreturn__, __format__(__printf__, 2, 0))) +void verrx(int __errnum, const char *__format, va_list __args); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ERR_H */ + diff --git a/ext2_root/usr/include/errno.h b/ext2_root/usr/include/errno.h new file mode 100644 index 0000000..bbdaf2f --- /dev/null +++ b/ext2_root/usr/include/errno.h @@ -0,0 +1,31 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* Some programs define their own errno as an "extern int" if it is not a macro. */ +#define errno __mlibc_errno +extern __thread int __mlibc_errno; + +int *__errno_location(void); + +/* Linux extensions. */ + +extern char *program_invocation_name; +extern char *program_invocation_short_name; +extern char *__progname; +extern char *__progname_full; + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ERRNO_H */ diff --git a/ext2_root/usr/include/error.h b/ext2_root/usr/include/error.h new file mode 100644 index 0000000..8c68295 --- /dev/null +++ b/ext2_root/usr/include/error.h @@ -0,0 +1,27 @@ +#ifndef _ERROR_H +#define _ERROR_H + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef __MLIBC_ABI_ONLY + +__attribute__((__format__(__printf__, 3, 4))) +void error(int __status, int __errnum, const char *__format, ...); +__attribute__((__format__(__printf__, 5, 6))) +void error_at_line(int __status, int __errnum, const char *__filename, unsigned int __linenum, const char *__format, ...); + +extern unsigned int error_message_count; +extern int error_one_per_line; +extern void (*error_print_progname)(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ERROR_H */ diff --git a/ext2_root/usr/include/execinfo.h b/ext2_root/usr/include/execinfo.h new file mode 100644 index 0000000..0d0d49d --- /dev/null +++ b/ext2_root/usr/include/execinfo.h @@ -0,0 +1,20 @@ +#ifndef _EXECINFO_H +#define _EXECINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int backtrace(void **__buffer, int __size); +char **backtrace_symbols(void *const *__buffer, int __size); +void backtrace_symbols_fd(void *const *__buffer, int __size, int __fd); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/fcntl.h b/ext2_root/usr/include/fcntl.h new file mode 100644 index 0000000..49c42e5 --- /dev/null +++ b/ext2_root/usr/include/fcntl.h @@ -0,0 +1,85 @@ + +#ifndef _FCNTL_H +#define _FCNTL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define O_NDELAY O_NONBLOCK + +/* WARNING: keep `flock` and `flock64` in sync or bad things will happen! */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +#ifndef __MLIBC_ABI_ONLY + +int creat(const char *__path, mode_t __mode); +int fallocate(int __fd, int __mode, off_t __offset, off_t __len); +int fcntl(int __fd, int __command, ...); +int open(const char *__path, int __flags, ...); +int open64(const char *__path, int __flags, ...); +int openat(int __dirfd, const char *__path, int __flags, ...); +int posix_fadvise(int __fd, off_t __offset, off_t __size, int __advice); +int posix_fallocate(int __fd, off_t __offset, off_t __size); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* This is a linux extension */ +#ifdef _GNU_SOURCE +struct file_handle { + unsigned int handle_bytes; + int handle_type; + __extension__ unsigned char f_handle[0]; +}; +#endif + +#ifndef __MLIBC_ABI_ONLY + +#ifdef _GNU_SOURCE +int name_to_handle_at(int __dirfd, const char *__path, struct file_handle *__handle, int *__mount_id, int __flags); +int open_by_handle_at(int __dirfd, struct file_handle *__handle, int __flags); +#endif + +ssize_t splice(int __fd_in, off_t *__off_in, int __fd_out, off_t *__off_out, size_t __len, unsigned int __flags); +ssize_t vmsplice(int __fd, const struct iovec *__iov, size_t __nr_segs, unsigned int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define SPLICE_F_MOVE 1 +#define SPLICE_F_NONBLOCK 2 +#define SPLICE_F_MORE 4 +#define SPLICE_F_GIFT 8 + +#define FALLOC_FL_KEEP_SIZE 1 +#define FALLOC_FL_PUNCH_HOLE 2 + +#ifdef __cplusplus +} +#endif + +#endif /* _FCNTL_H */ + diff --git a/ext2_root/usr/include/features.h b/ext2_root/usr/include/features.h new file mode 100644 index 0000000..d700f10 --- /dev/null +++ b/ext2_root/usr/include/features.h @@ -0,0 +1,6 @@ +#ifndef FEATURES_H +#define FEATURES_H + +/* This header is a stub */ + +#endif diff --git a/ext2_root/usr/include/fenv.h b/ext2_root/usr/include/fenv.h new file mode 100644 index 0000000..7366706 --- /dev/null +++ b/ext2_root/usr/include/fenv.h @@ -0,0 +1,44 @@ + +#ifndef _FENV_H +#define _FENV_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + __mlibc_uint32 __control_word; + __mlibc_uint32 __status_word; + __mlibc_uint32 __unused[5]; + __mlibc_uint32 __mxcsr; +} fenv_t; + +typedef __mlibc_uint16 fexcept_t; + +#ifndef __MLIBC_ABI_ONLY + +int feclearexcept(int __excepts); +int fegetenv(fenv_t *__envp); +int fegetexceptflag(fexcept_t *__envp, int __excepts); +int fegetround(void); +int feholdexcept(fenv_t *__envp); +int feraiseexcept(int __excepts); +int fesetenv(const fenv_t *__envp); +int fesetexceptflag(const fexcept_t *__envp, int __excepts); +int fesetround(int __round); +int fetestexcept(int __excepts); +int feupdateenv(const fenv_t *__envp); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#define FE_DFL_ENV ((const fenv_t *) -1) + +#endif /* _FENV_H */ + diff --git a/ext2_root/usr/include/fnmatch.h b/ext2_root/usr/include/fnmatch.h new file mode 100644 index 0000000..5c5dda0 --- /dev/null +++ b/ext2_root/usr/include/fnmatch.h @@ -0,0 +1,33 @@ + +#ifndef _FNMATCH_H +#define _FNMATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* POSIX-defined fnmatch() flags. */ +#define FNM_PATHNAME 0x1 +#define FNM_NOESCAPE 0x2 +#define FNM_PERIOD 0x4 + +/* GNU extensions for fnmatch() flags. */ +#define FNM_LEADING_DIR 0x8 +#define FNM_CASEFOLD 0x10 +#define FNM_EXTMATCH 0x20 + +/* fnmatch() return values. */ +#define FNM_NOMATCH 1 + +#ifndef __MLIBC_ABI_ONLY + +int fnmatch(const char *__pattern, const char *__string, int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FNMATCH_H */ + diff --git a/ext2_root/usr/include/fstab.h b/ext2_root/usr/include/fstab.h new file mode 100644 index 0000000..2a445f0 --- /dev/null +++ b/ext2_root/usr/include/fstab.h @@ -0,0 +1,23 @@ +#ifndef _FSTAB_H +#define _FSTAB_H + +#define _PATH_FSTAB "/etc/fstab" +#define FSTAB "/etc/fstab" + +#define FSTAB_RW "rw" +#define FSTAB_RQ "rq" +#define FSTAB_RO "ro" +#define FSTAB_SW "sw" +#define FSTAB_XX "xx" + +struct fstab { + char *fs_spec; + char *fs_file; + char *fs_vfstype; + char *fs_mntops; + const char *fs_type; + int fs_freq; + int fs_passno; +}; + +#endif /* _FSTAB_H */ diff --git a/ext2_root/usr/include/ftw.h b/ext2_root/usr/include/ftw.h new file mode 100644 index 0000000..3240ed3 --- /dev/null +++ b/ext2_root/usr/include/ftw.h @@ -0,0 +1,45 @@ + +#ifndef _FTW_H +#define _FTW_H + +#include + +#define FTW_F 1 +#define FTW_D 2 +#define FTW_DNR 3 +#define FTW_DP 4 +#define FTW_NS 5 +#define FTW_SL 6 +#define FTW_SLN 7 + +#define FTW_PHYS 1 +#define FTW_MOUNT 2 +#define FTW_DEPTH 4 +#define FTW_CHDIR 8 + +#define FTW_CONTINUE 0 + +#ifdef __cplusplus +extern "C" { +#endif + +struct FTW { + int base; + int level; +}; + +#ifndef __MLIBC_ABI_ONLY + +int ftw(const char *__dirpath, int (*__fn)(const char *__fpath, const struct stat *__sb, int __typeflag), + int __nopenfd); +int nftw(const char *__dirpath, int (*__fn)(const char *__fpath, const struct stat *__sb, int __typeflag, + struct FTW *__ftwbuf), int __nopenfd, int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FTW_H */ + diff --git a/ext2_root/usr/include/getopt.h b/ext2_root/usr/include/getopt.h new file mode 100644 index 0000000..d3e868b --- /dev/null +++ b/ext2_root/usr/include/getopt.h @@ -0,0 +1,37 @@ + +#ifndef _GETOPT_H +#define _GETOPT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +extern char **environ; +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; +#if __MLIBC_BSD_OPTION +extern int optreset; +#endif /*__MLIBC_BSD_OPTION */ + +int getopt(int __argc, char *const __argv[], const char *__optstring); +int getopt_long(int __argc, char *const __argv[], const char *__optstring, + const struct option *__longopts, int *__longindex); +int getopt_long_only(int __argc, char *const __argv[], const char *__optstring, + const struct option *__longopts, int *__longindex); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ + diff --git a/ext2_root/usr/include/glob.h b/ext2_root/usr/include/glob.h new file mode 100644 index 0000000..57e3219 --- /dev/null +++ b/ext2_root/usr/include/glob.h @@ -0,0 +1,59 @@ + +#ifndef _GLOB_H +#define _GLOB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define GLOB_APPEND 0x01 +#define GLOB_DOOFFS 0x02 +#define GLOB_ERR 0x04 +#define GLOB_MARK 0x08 +#define GLOB_NOCHECK 0x10 +#define GLOB_NOESCAPE 0x20 +#define GLOB_NOSORT 0x40 +#define GLOB_PERIOD 0x80 +#define GLOB_TILDE 0x100 +#define GLOB_TILDE_CHECK 0x200 +#define GLOB_BRACE 0x400 +#define GLOB_NOMAGIC 0x800 +#define GLOB_ALTDIRFUNC 0x1000 +#define GLOB_ONLYDIR 0x2000 +#define GLOB_MAGCHAR 0x4000 + +#define GLOB_ABORTED 1 +#define GLOB_NOMATCH 2 +#define GLOB_NOSPACE 3 +#define GLOB_NOSYS 4 + +struct stat; +typedef struct glob_t { + size_t gl_pathc; + char **gl_pathv; + size_t gl_offs; + int gl_flags; + void (*gl_closedir) (void *); + struct dirent *(*gl_readdir) (void *); + void *(*gl_opendir) (const char *); + int (*gl_lstat) (const char *__restrict, struct stat *__restrict); + int (*gl_stat) (const char *__restrict, struct stat *__restrict); +} glob_t; + +#ifndef __MLIBC_ABI_ONLY + +int glob(const char *__restrict __pattern, int __flags, + int(*__errfunc)(const char *__epath, int __errnum), struct glob_t *__restrict __pglob); +void globfree(struct glob_t *__pglog); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GLOB_H */ + + diff --git a/ext2_root/usr/include/grp.h b/ext2_root/usr/include/grp.h new file mode 100644 index 0000000..6b16d71 --- /dev/null +++ b/ext2_root/usr/include/grp.h @@ -0,0 +1,43 @@ +#ifndef _GRP_H +#define _GRP_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct group { + char *gr_name; + char *gr_passwd; + gid_t gr_gid; + char **gr_mem; +}; + +#ifndef __MLIBC_ABI_ONLY + +void endgrent(void); +struct group *getgrent(void); +struct group *getgrgid(gid_t __gid); +int getgrgid_r(gid_t __gid, struct group *__grp, char *__buf, size_t __buflen, struct group **__res); +struct group *getgrnam(const char *__name); +int getgrnam_r(const char *__name, struct group *__grp, char *__buf, size_t __buflen, struct group **__res); +void setgrent(void); +int putgrent(const struct group *__grp, FILE *__stream); +struct group *fgetgrent(FILE *__stream); + +int setgroups(size_t __size, const gid_t *__list); +int initgroups(const char *__user, gid_t __group); + +/* Non standard extension */ +int getgrouplist(const char *__user, gid_t __group, gid_t *__groups, int *__ngroups); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GRP_H */ diff --git a/ext2_root/usr/include/gshadow.h b/ext2_root/usr/include/gshadow.h new file mode 100644 index 0000000..4517700 --- /dev/null +++ b/ext2_root/usr/include/gshadow.h @@ -0,0 +1,30 @@ +#ifndef _GSHADOW_H +#define _GSHADOW_H + +#include +#include + +#define GSHADOW _PATH_GSHADOW + +struct sgrp { + char *sg_namp; + char *sg_passwd; + char **sg_adm; + char **sg_mem; +}; + +#ifndef __MLIBC_ABI_ONLY + +#ifdef __cplusplus +extern "C" { +#endif + +int getsgnam_r(const char *__name, struct sgrp *__result_buf, char *__buffer, size_t __len, struct sgrp **__result); + +#ifdef __cplusplus +} +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif diff --git a/ext2_root/usr/include/inttypes.h b/ext2_root/usr/include/inttypes.h new file mode 100644 index 0000000..5eeeca1 --- /dev/null +++ b/ext2_root/usr/include/inttypes.h @@ -0,0 +1,206 @@ +#ifndef _STDINT_H +#define _STDINT_H + +#include +#include + +/* Even though this is not strictly not-ABI, it is mlibc-printf specific therefore */ +/* gate behind !__MLIBC_ABI_ONLY */ +#ifndef __MLIBC_ABI_ONLY + +#if UINTPTR_MAX == UINT64_MAX +# define __PRI64 "l" +# define __PRIPTR "l" +#else +# define __PRI64 "ll" +# define __PRIPTR "" +#endif + +/* TODO: This is extremly unelegant and fragile. */ +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" +#define PRId16 "d" +#define PRIi16 "i" +#define PRIdLEAST16 "d" +#define PRIiLEAST16 "i" +#define PRIdFAST16 "ld" +#define PRIiFAST16 "li" +#define PRId32 "d" +#define PRIi32 "i" +#define PRIdLEAST32 "d" +#define PRIiLEAST32 "i" +#define PRIdFAST32 "ld" +#define PRIiFAST32 "li" +#define PRId64 __PRI64 "d" +#define PRIi64 __PRI64 "i" +#define PRIdLEAST64 __PRI64 "d" +#define PRIiLEAST64 __PRI64 "i" +#define PRIdFAST64 __PRI64 "d" +#define PRIiFAST64 __PRI64 "i" +#define PRIdMAX __PRI64 "d" +#define PRIiMAX __PRI64 "i" +#define PRIdPTR __PRIPTR "d" +#define PRIiPTR __PRIPTR "i" +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" +#define PRIo16 "o" +#define PRIu16 "u" +#define PRIx16 "x" +#define PRIX16 "X" +#define PRIoLEAST16 "o" +#define PRIuLEAST16 "u" +#define PRIxLEAST16 "x" +#define PRIXLEAST16 "X" +#define PRIoFAST16 "lo" +#define PRIuFAST16 "lu" +#define PRIxFAST16 "lx" +#define PRIXFAST16 "lX" +#define PRIo32 "o" +#define PRIu32 "u" +#define PRIx32 "x" +#define PRIX32 "X" +#define PRIoLEAST32 "o" +#define PRIuLEAST32 "u" +#define PRIxLEAST32 "x" +#define PRIXLEAST32 "X" +#define PRIoFAST32 "lo" +#define PRIuFAST32 "lu" +#define PRIxFAST32 "lx" +#define PRIXFAST32 "lX" +#define PRIo64 __PRI64 "o" +#define PRIu64 __PRI64 "u" +#define PRIx64 __PRI64 "x" +#define PRIX64 __PRI64 "X" +#define PRIoLEAST64 __PRI64 "o" +#define PRIuLEAST64 __PRI64 "u" +#define PRIxLEAST64 __PRI64 "x" +#define PRIXLEAST64 __PRI64 "X" +#define PRIoFAST64 __PRI64 "o" +#define PRIuFAST64 __PRI64 "u" +#define PRIxFAST64 __PRI64 "x" +#define PRIXFAST64 __PRI64 "X" +#define PRIoMAX __PRI64 "o" +#define PRIuMAX __PRI64 "u" +#define PRIxMAX __PRI64 "x" +#define PRIXMAX __PRI64 "X" +#define PRIoPTR __PRIPTR "o" +#define PRIuPTR __PRIPTR "u" +#define PRIxPTR __PRIPTR "x" +#define PRIXPTR __PRIPTR "X" + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 __PRI64 "i" +#define SCNiLEAST8 "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 __PRI64 "i" +#define SCNiFAST8 "hhi" +#define SCNiFAST16 __PRIPTR "i" +#define SCNiFAST32 __PRIPTR "i" +#define SCNiFAST64 __PRI64 "i" +#define SCNiMAX __PRI64 "i" +#define SCNiPTR __PRIPTR "i" + +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 __PRI64 "d" +#define SCNdLEAST8 "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 __PRI64 "d" +#define SCNdFAST8 "hhd" +#define SCNdFAST16 __PRIPTR "d" +#define SCNdFAST32 __PRIPTR "d" +#define SCNdFAST64 __PRI64 "d" +#define SCNdMAX __PRI64 "d" +#define SCNdPTR __PRIPTR "d" + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 __PRI64 "u" +#define SCNuLEAST8 "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 __PRI64 "u" +#define SCNuFAST8 "hhu" +#define SCNuFAST16 __PRIPTR "u" +#define SCNuFAST32 __PRIPTR "u" +#define SCNuFAST64 __PRI64 "u" +#define SCNuMAX __PRI64 "u" +#define SCNuPTR __PRIPTR "u" + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 __PRI64 "o" +#define SCNoLEAST8 "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 __PRI64 "o" +#define SCNoFAST8 "hho" +#define SCNoFAST16 __PRIPTR "o" +#define SCNoFAST32 __PRIPTR "o" +#define SCNoFAST64 __PRI64 "o" +#define SCNoMAX __PRI64 "o" +#define SCNoPTR __PRIPTR "o" + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 __PRI64 "x" +#define SCNxLEAST8 "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 __PRI64 "x" +#define SCNxFAST8 "hhx" +#define SCNxFAST16 __PRIPTR "x" +#define SCNxFAST32 __PRIPTR "x" +#define SCNxFAST64 __PRI64 "x" +#define SCNxMAX __PRI64 "x" +#define SCNxPTR __PRIPTR "x" + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +#ifndef __MLIBC_ABI_ONLY + +intmax_t imaxabs(intmax_t __x); +imaxdiv_t imaxdiv(intmax_t __x, intmax_t __y); +intmax_t strtoimax(const char *__restrict __string, char **__restrict __end, int __base); +uintmax_t strtoumax(const char *__restrict __string, char **__restrict __end, int __base); +intmax_t wcstoimax(const wchar_t *__restrict __string, wchar_t **__restrict __end, int __base); +uintmax_t wcstoumax(const wchar_t *__restrict __string, wchar_t **__restrict __end, int __base); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _STDINT_H */ diff --git a/ext2_root/usr/include/langinfo.h b/ext2_root/usr/include/langinfo.h new file mode 100644 index 0000000..2a5bf0f --- /dev/null +++ b/ext2_root/usr/include/langinfo.h @@ -0,0 +1,24 @@ + +#ifndef _LANGINFO_H +#define _LANGINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +char *nl_langinfo(nl_item __item); +char *nl_langinfo_l(nl_item __item, locale_t __loc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LANGINFO_H */ + diff --git a/ext2_root/usr/include/libgen.h b/ext2_root/usr/include/libgen.h new file mode 100644 index 0000000..69ece1d --- /dev/null +++ b/ext2_root/usr/include/libgen.h @@ -0,0 +1,28 @@ + +#ifndef _LIBGEN_H +#define _LIBGEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(basename) && defined(_GNU_SOURCE) +/* see: ./options/ansi/include/string.h, search for __mlibc_gnu_basename */ +# undef basename +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *basename(char *__path); +#define basename basename +char *dirname(char *__path); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBGEN_H */ + + diff --git a/ext2_root/usr/include/limits.h b/ext2_root/usr/include/limits.h new file mode 100644 index 0000000..8daa542 --- /dev/null +++ b/ext2_root/usr/include/limits.h @@ -0,0 +1,123 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#define CHAR_BIT 8 + +#ifndef MB_LEN_MAX +# define MB_LEN_MAX 4 +#endif + +#ifdef LONG_MAX +# ifdef LONG_MAX == INT32_MAX +# define LONG_BIT 32 +# else +/* Safe assumption */ +# define LONG_BIT 64 +# endif +#elif defined __LONG_MAX__ +# if __LONG_MAX__ == INT32_MAX +# define LONG_BIT 32 +# else +/* Safe assumption */ +# define LONG_BIT 64 +# endif +#else +# error "Unsupported configuration, please define either LONG_MAX or __LONG_MAX__" +#endif + +#undef SCHAR_MIN +#undef SCHAR_MAX +#undef CHAR_MIN +#undef CHAR_MAX +#undef UCHAR_MAX +#undef SHRT_MIN +#undef SHRT_MAX +#undef USHRT_MAX +#undef INT_MIN +#undef INT_MAX +#undef UINT_MAX +#undef LONG_MIN +#undef LONG_MAX +#undef ULONG_MAX +#undef LLONG_MIN +#undef LLONG_MAX +#undef ULLONG_MAX + +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) +#define SCHAR_MAX __SCHAR_MAX__ +#if __SCHAR_MAX__ == __INT_MAX__ +# define UCHAR_MAX (__SCHAR_MAX__ * 2U + 1U) +#else +# define UCHAR_MAX (__SCHAR_MAX__ * 2 + 1) +#endif + +#ifdef __CHAR_UNSIGNED__ +# define CHAR_MAX UCHAR_MAX +# if __SCHAR_MAX__ == __INT_MAX__ +# define CHAR_MIN 0U +# else +# define CHAR_MIN 0 +# endif +#else +# define CHAR_MAX SCHAR_MAX +# define CHAR_MIN SCHAR_MIN +#endif + +#define SHRT_MIN (-__SHRT_MAX__ - 1) +#define SHRT_MAX __SHRT_MAX__ +#if __SHRT_MAX__ == __INT_MAX__ +# define USHRT_MAX (__SHRT_MAX__ * 2U + 1U) +#else +# define USHRT_MAX (__SHRT_MAX__ * 2 + 1) +#endif + +#define INT_MIN (-__INT_MAX__ - 1) +#define INT_MAX __INT_MAX__ +#define UINT_MAX (__INT_MAX__ * 2U + 1U) + +#define LONG_MIN (-__LONG_MAX__ - 1L) +#define LONG_MAX __LONG_MAX__ +#define ULONG_MAX (__LONG_MAX__ * 2UL + 1UL) + +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1LL) +#define LLONG_MAX __LONG_LONG_MAX__ +#define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1ULL) + +#define NAME_MAX 255 +#define PATH_MAX 4096 +#define LINE_MAX 4096 +#define PIPE_BUF 4096 + +#define CHARCLASS_NAME_MAX 14 +#define RE_DUP_MAX 255 + +#if !defined(NGROUPS_MAX) +/* This value is a guaranteed minimum, get the current maximum from sysconf */ +#define NGROUPS_MAX 8 +#endif /* !defined(NGROUPS_MAX) */ + +/* POSIX states 9 is the minimum for NL_ARGMAX */ +#define NL_ARGMAX 9 + +#if INTPTR_MAX == INT64_MAX +# define SSIZE_MAX LONG_MAX +#elif INTPTR_MAX == INT32_MAX +# define SSIZE_MAX INT_MAX +#endif + +#define _POSIX_ARG_MAX 4096 +#define _POSIX_OPEN_MAX 16 +#define _POSIX_HOST_NAME_MAX 255 +#define _POSIX_NAME_MAX 14 +#define _POSIX_TZNAME_MAX 6 +#define _XOPEN_NAME_MAX 255 + +/* This value is a guaranteed minimum, get the current maximum from sysconf */ +#define TZNAME_MAX _POSIX_TZNAME_MAX + +#define PTHREAD_STACK_MIN 16384 +#define PTHREAD_KEYS_MAX 1024 + +#include + +#endif /* _LIMITS_H */ diff --git a/ext2_root/usr/include/link.h b/ext2_root/usr/include/link.h new file mode 100644 index 0000000..91a5fb6 --- /dev/null +++ b/ext2_root/usr/include/link.h @@ -0,0 +1,58 @@ +#ifndef _LINK_H +#define _LINK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#if defined(__x86_64__) || defined(__aarch64__) \ + || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +# define ElfW(type) Elf64_ ## type +#elif defined(__i386__) || defined(__m68k__) +# define ElfW(type) Elf32_ ## type +#else +# error Unknown architecture +#endif + +struct dl_phdr_info { + ElfW(Addr) dlpi_addr; + const char *dlpi_name; + const ElfW(Phdr) *dlpi_phdr; + ElfW(Half) dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + size_t dlpi_tls_modid; + void *dlpi_tls_data; +}; + +struct link_map { + Elf64_Addr l_addr; + char *l_name; + ElfW(Dyn) *l_ld; + struct link_map *l_next, *l_prev; +}; + +struct r_debug { + int r_version; + struct link_map *r_map; + Elf64_Addr r_brk; + enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state; + Elf64_Addr r_ldbase; +}; + +#ifndef __MLIBC_ABI_ONLY + +int dl_iterate_phdr(int (*__callback)(struct dl_phdr_info* __info, size_t __size, void* __data), void* __data); + +extern ElfW(Dyn) _DYNAMIC[]; + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LINK_H */ diff --git a/ext2_root/usr/include/locale.h b/ext2_root/usr/include/locale.h new file mode 100644 index 0000000..66bddea --- /dev/null +++ b/ext2_root/usr/include/locale.h @@ -0,0 +1,83 @@ + +#ifndef _LOCALE_H +#define _LOCALE_H + +#include + +#include + +#define LC_ALL 1 +#define LC_COLLATE 2 +#define LC_CTYPE 3 +#define LC_MONETARY 4 +#define LC_NUMERIC 5 +#define LC_TIME 6 +#define LC_MESSAGES 7 +#define LC_MEASUREMENT 11 + +#define LC_GLOBAL_LOCALE ((locale_t) -1L) + +#define LC_CTYPE_MASK (1< +#endif /* __MLIBC_POSIX_OPTION */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LOCALE_H */ + diff --git a/ext2_root/usr/include/math.h b/ext2_root/usr/include/math.h new file mode 100644 index 0000000..a4ffd32 --- /dev/null +++ b/ext2_root/usr/include/math.h @@ -0,0 +1,383 @@ + +#ifndef _MATH_H +#define _MATH_H + +#include + +/* this is a posix extension */ +#define M_E 2.7182818284590452354 +#define M_LOG2E 1.4426950408889634074 +#define M_LOG10E 0.43429448190325182765 +#define M_LN2 0.69314718055994530942 +#define M_LN10 2.30258509299404568402 +#define M_PI 3.14159265358979323846 +#define M_PI_2 1.57079632679489661923 +#define M_PI_4 0.78539816339744830962 +#define M_1_PI 0.31830988618379067154 +#define M_2_PI 0.63661977236758134308 +#define M_2_SQRTPI 1.12837916709551257390 +#define M_SQRT2 1.41421356237309504880 +#define M_SQRT1_2 0.70710678118654752440 +#define M_PIl 3.141592653589793238462643383279502884L + +/* The following two definitions are from musl. */ +#define FP_ILOGBNAN (-1 - (int)(((unsigned)-1) >> 1)) +#define FP_ILOGB0 FP_ILOGBNAN + +#ifdef __cplusplus +extern "C" { +#endif + +typedef double double_t; +typedef float float_t; + +#define HUGE_VAL (__builtin_huge_val()) +#define HUGE_VALF (__builtin_huge_valf()) +#define HUGE_VALL (__builtin_huge_vall()) +#define INFINITY (__builtin_inff()) +#define NAN (__builtin_nanf("")) + +/* [C11/7.12.1 Treatment of error conditions] */ + +#define MATH_ERRNO 1 +#define MATH_ERREXCEPT 2 +#define math_errhandling 3 + +/* [C11/7.12.3 Classification macros] */ + +/* NOTE: fpclassify always returns exactly one of those constants */ +/* However making them bitwise disjoint simplifies isfinite() etc. */ +#define FP_INFINITE 1 +#define FP_NAN 2 +#define FP_NORMAL 4 +#define FP_SUBNORMAL 8 +#define FP_ZERO 16 + +#ifndef __MLIBC_ABI_ONLY + +int __fpclassify(double __x); +int __fpclassifyf(float __x); +int __fpclassifyl(long double __x); + +#define fpclassify(x) \ + (sizeof(x) == sizeof(double) ? __fpclassify(x) : \ + (sizeof(x) == sizeof(float) ? __fpclassifyf(x) : \ + (sizeof(x) == sizeof(long double) ? __fpclassifyl(x) : \ + 0))) + +#define isfinite(x) (fpclassify(x) & (FP_NORMAL | FP_SUBNORMAL | FP_ZERO)) +#define isnan(x) (fpclassify(x) == FP_NAN) +#define isinf(x) (fpclassify(x) == FP_INFINITE) +#define isnormal(x) (fpclassify(x) == FP_NORMAL) + +/* FIXME: this is gcc specific */ +#define signbit(x) (__builtin_signbit(x)) + +/* [C11/7.12.14 Comparison macros] */ +#define isunordered(x,y) (isnan((x)) ? ((void)(y),1) : isnan((y))) + +__MLIBC_INLINE_DEFINITION int __mlibc_isless(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x < __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x < __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessl(long double __x, long double __y) { return !isunordered(__x, __y) && __x < __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequal(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x <= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequalf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x <= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequall(long double __x, long double __y) { return !isunordered(__x, __y) && __x <= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreater(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x != __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreaterf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x != __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreaterl(long double __x, long double __y) { return !isunordered(__x, __y) && __x != __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreater(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x > __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x > __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterl(long double __x, long double __y) { return !isunordered(__x, __y) && __x > __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequal(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x >= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequalf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x >= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequall(long double __x, long double __y) { return !isunordered(__x, __y) && __x >= __y; } + +/* TODO: We chould use _Generic here but that does not work in C++ code. */ +#define __MLIBC_CHOOSE_COMPARISON(x, y, p) ( \ + sizeof((x)+(y)) == sizeof(float) ? p##f(x, y) : \ + sizeof((x)+(y)) == sizeof(double) ? p(x, y) : \ + p##l(x, y) ) + +#define isless(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isless) +#define islessequal(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_islessequal) +#define islessgreater(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_islessgreater) +#define isgreater(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isgreater) +#define isgreaterequal(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isgreaterequal) + +/* this is a gnu extension */ +void sincos(double __x, double *__sin, double *__cos); +void sincosf(float __x, float *__sin, float *__cos); +void sincosl(long double __x, long double *__sin, long double *__cos); + +double exp10(double __x); +float exp10f(float __x); +long double exp10l(long double __x); + +double pow10(double __x); +float pow10f(float __x); +long double pow10l(long double __x); + +/* [C11/7.12.4 Trigonometric functions] */ + +double acos(double __x); +float acosf(float __x); +long double acosl(long double __x); + +double asin(double __x); +float asinf(float __x); +long double asinl(long double __x); + +double atan(double __x); +float atanf(float __x); +long double atanl(long double __x); + +double atan2(double __x, double __y); +float atan2f(float __x, float __y); +long double atan2l(long double __x, long double __y); + +double cos(double __x); +float cosf(float __x); +long double cosl(long double __x); + +double sin(double __x); +float sinf(float __x); +long double sinl(long double __x); + +double tan(double __x); +float tanf(float __x); +long double tanl(long double __x); + +/* [C11/7.12.5 Hyperbolic functions] */ + +double acosh(double __x); +float acoshf(float __x); +long double acoshl(long double __x); + +double asinh(double __x); +float asinhf(float __x); +long double asinhl(long double __x); + +double atanh(double __x); +float atanhf(float __x); +long double atanhl(long double __x); + +double cosh(double __x); +float coshf(float __x); +long double coshl(long double __x); + +double sinh(double __x); +float sinhf(float __x); +long double sinhl(long double __x); + +double tanh(double __x); +float tanhf(float __x); +long double tanhl(long double __x); + +/* [C11/7.12.6 Exponential and logarithmic functions] */ + +double exp(double __x); +float expf(float __x); +long double expl(long double __x); + +double exp2(double __x); +float exp2f(float __x); +long double exp2l(long double __x); + +double expm1(double __x); +float expm1f(float __x); +long double expm1l(long double __x); + +double frexp(double __x, int *__power); +float frexpf(float __x, int *__power); +long double frexpl(long double __x, int *__power); + +int ilogb(double __x); +int ilogbf(float __x); +int ilogbl(long double __x); + +double ldexp(double __x, int __power); +float ldexpf(float __x, int __power); +long double ldexpl(long double __x, int __power); + +double log(double __x); +float logf(float __x); +long double logl(long double __x); + +double log10(double __x); +float log10f(float __x); +long double log10l(long double __x); + +double log1p(double __x); +float log1pf(float __x); +long double log1pl(long double __x); + +double log2(double __x); +float log2f(float __x); +long double log2l(long double __x); + +double logb(double __x); +float logbf(float __x); +long double logbl(long double __x); + +double modf(double __x, double *__integral); +float modff(float __x, float *__integral); +long double modfl(long double __x, long double *__integral); + +double scalbn(double __x, int __power); +float scalbnf(float __x, int __power); +long double scalbnl(long double __x, int __power); + +double scalbln(double __x, long __power); +float scalblnf(float __x, long __power); +long double scalblnl(long double __x, long __power); + +/* [C11/7.12.7 Power and absolute-value functions] */ + +double cbrt(double __x); +float cbrtf(float __x); +long double cbrtl(long double __x); + +double fabs(double __x); +float fabsf(float __x); +long double fabsl(long double __x); + +double hypot(double __x, double __y); +float hypotf(float __x, float __y); +long double hypotl(long double __x, long double __y); + +double pow(double __x, double __y); +float powf(float __x, float __y); +long double powl(long double __x, long double __y); + +double sqrt(double __x); +float sqrtf(float __x); +long double sqrtl(long double __x); + +/* [C11/7.12.8 Error and gamma functions] */ + +double erf(double __x); +float erff(float __x); +long double erfl(long double __x); + +double erfc(double __x); +float erfcf(float __x); +long double erfcl(long double __x); + +double lgamma(double __x); +float lgammaf(float __x); +long double lgammal(long double __x); + +double tgamma(double __x); +float tgammaf(float __x); +long double tgammal(long double __x); + +/* [C11/7.12.9 Nearest integer functions] */ + +double ceil(double __x); +float ceilf(float __x); +long double ceill(long double __x); + +double floor(double __x); +float floorf(float __x); +long double floorl(long double __x); + +double nearbyint(double __x); +float nearbyintf(float __x); +long double nearbyintl(long double __x); + +double rint(double __x); +float rintf(float __x); +long double rintl(long double __x); + +long lrint(double __x); +long lrintf(float __x); +long lrintl(long double __x); + +long long llrint(double __x); +long long llrintf(float __x); +long long llrintl(long double __x); + +double round(double __x); +float roundf(float __x); +long double roundl(long double __x); + +long lround(double __x); +long lroundf(float __x); +long lroundl(long double __x); + +long long llround(double __x); +long long llroundf(float __x); +long long llroundl(long double __x); + +double trunc(double __x); +float truncf(float __x); +long double truncl(long double __x); + +/* [C11/7.12.10 Remainder functions] */ + +double fmod(double __x, double __y); +float fmodf(float __x, float __y); +long double fmodl(long double __x, long double __y); + +double remainder(double __x, double __y); +float remainderf(float __x, float __y); +long double remainderl(long double __x, long double __y); + +double remquo(double __x, double __y, int *__quotient); +float remquof(float __x, float __y, int *__quotient); +long double remquol(long double __x, long double __y, int *__quotient); + +/* [C11/7.12.11 Manipulation functions] */ + +double copysign(double __x, double __sign); +float copysignf(float __x, float __sign); +long double copysignl(long double __x, long double __sign); + +double nan(const char *__tag); +float nanf(const char *__tag); +long double nanl(const char *__tag); + +double nextafter(double __x, double __dir); +float nextafterf(float __x, float __dir); +long double nextafterl(long double __x, long double __dir); + +double nexttoward(double __x, long double __dir); +float nexttowardf(float __x, long double __dir); +long double nexttowardl(long double __x, long double __dir); + +/* [C11/7.12.12 Maximum, minimum and positive difference functions] */ + +double fdim(double __x, double __y); +float fdimf(float __x, float __y); +long double fdiml(long double __x, long double __y); + +double fmax(double __x, double __y); +float fmaxf(float __x, float __y); +long double fmaxl(long double __x, long double __y); + +double fmin(double __x, double __y); +float fminf(float __x, float __y); +long double fminl(long double __x, long double __y); + +/* [C11/7.12.13 Floating multiply-add] */ + +double fma(double __x, double __y, double __z); +float fmaf(float __x, float __y, float __z); +long double fmal(long double __x, long double __y, long double __z); + +extern int signgam; +#define __signgam signgam + +/* BSD floating-point classification functions - obsolete */ + +int finite(double __x); +int finitef(float __x); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MATH_H */ + diff --git a/ext2_root/usr/include/memory.h b/ext2_root/usr/include/memory.h new file mode 100644 index 0000000..39adee7 --- /dev/null +++ b/ext2_root/usr/include/memory.h @@ -0,0 +1,6 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#include + +#endif diff --git a/ext2_root/usr/include/mlibc-config.h b/ext2_root/usr/include/mlibc-config.h new file mode 100644 index 0000000..6a7d44c --- /dev/null +++ b/ext2_root/usr/include/mlibc-config.h @@ -0,0 +1,20 @@ +#ifndef _MLIBC_CONFIG_H +#define _MLIBC_CONFIG_H + +#ifdef _GNU_SOURCE +# undef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE 1 +#endif + +#if (defined(_DEFAULT_SOURCE) || (!defined(__STRICT_ANSI__) && !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE))) +# undef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE 1 +#endif + +#define __MLIBC_BSD_OPTION 1 +#define __MLIBC_POSIX_OPTION 1 +#define __MLIBC_LINUX_OPTION 0 +#define __MLIBC_GLIBC_OPTION 1 +#define __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H 0 + +#endif /* _MLIBC_CONFIG_H */ diff --git a/ext2_root/usr/include/mqueue.h b/ext2_root/usr/include/mqueue.h new file mode 100644 index 0000000..cbee138 --- /dev/null +++ b/ext2_root/usr/include/mqueue.h @@ -0,0 +1,26 @@ +#ifndef _MQUEUE_H +#define _MQUEUE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int mqd_t; + +#ifndef __MLIBC_ABI_ONLY + +int mq_getattr(mqd_t __mqdes, struct mq_attr *__attr); +int mq_setattr(mqd_t __mqdes, const struct mq_attr *__restrict__ __newattr, struct mq_attr *__restrict__ __oldattr); +int mq_unlink(const char *__name); +mqd_t mq_open(const char *__name, int __flags, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MQUEUE_H */ + diff --git a/ext2_root/usr/include/net/ethernet.h b/ext2_root/usr/include/net/ethernet.h new file mode 100644 index 0000000..b9358e9 --- /dev/null +++ b/ext2_root/usr/include/net/ethernet.h @@ -0,0 +1,46 @@ +#ifndef _NET_ETHERNET_H +#define _NET_ETHERNET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if __MLIBC_LINUX_OPTION +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#pragma GCC diagnostic ignored "-Wpedantic" +# include +#pragma GCC diagnostic pop +#endif /* __MLIBC_LINUX_OPTION */ + +#define ETHERTYPE_PUP 0x0200 +#define ETHERTYPE_SPRITE 0x0500 +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_REVARP 0x8035 +#define ETHERTYPE_AT 0x809B +#define ETHERTYPE_AARP 0x80F3 +#define ETHERTYPE_VLAN 0x8100 +#define ETHERTYPE_IPX 0x8137 +#define ETHERTYPE_IPV6 0x86dd +#define ETHERTYPE_LOOPBACK 0x9000 + +struct ether_header { + uint8_t ether_dhost[6]; + uint8_t ether_shost[6]; + uint16_t ether_type; +}; + +#define ETHER_ADDR_LEN 6 + +#define ETHERTYPE_IP 0x0800 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/net/if.h b/ext2_root/usr/include/net/if.h new file mode 100644 index 0000000..86cad34 --- /dev/null +++ b/ext2_root/usr/include/net/if.h @@ -0,0 +1,128 @@ + +#ifndef _NET_IF_H +#define _NET_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define IF_NAMESIZE 16 +#define IFNAMSIZ IF_NAMESIZE +#define ALTIFNAMSIZ 128 +#define IFALIASZ 256 + +struct if_nameindex { + unsigned int if_index; + char *if_name; +}; + +struct ifmap { + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq { + union { + char ifrn_name[IFNAMSIZ]; + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short int ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; + char ifru_newname[IFNAMSIZ]; + char *ifru_data; + } ifr_ifru; +}; + +#define ifr_name ifr_ifrn.ifrn_name +#define ifr_hwaddr ifr_ifru.ifru_hwaddr +#define ifr_addr ifr_ifru.ifru_addr +#define ifr_dstaddr ifr_ifru.ifru_dstaddr +#define ifr_broadaddr ifr_ifru.ifru_broadaddr +#define ifr_netmask ifr_ifru.ifru_netmask +#define ifr_flags ifr_ifru.ifru_flags +#define ifr_metric ifr_ifru.ifru_ivalue +#define ifr_mtu ifr_ifru.ifru_mtu +#define ifr_map ifr_ifru.ifru_map +#define ifr_slave ifr_ifru.ifru_slave +#define ifr_data ifr_ifru.ifru_data +#define ifr_ifindex ifr_ifru.ifru_ivalue +#define ifr_bandwidth ifr_ifru.ifru_ivalue +#define ifr_qlen ifr_ifru.ifru_ivalue +#define ifr_newname ifr_ifru.ifru_newname + +struct ifconf { + int ifc_len; + union { + char *ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; + +#define ifc_buf ifc_ifcu.ifcu_buf +#define ifc_req ifc_ifcu.ifcu_req + +#ifndef __MLIBC_ABI_ONLY + +void if_freenameindex(struct if_nameindex *__index); +char *if_indextoname(unsigned int __index, char *__name); +struct if_nameindex *if_nameindex(void); +unsigned int if_nametoindex(const char *__name); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define IFHWADDRLEN 6 + +#define IFF_UP 0x1 +#define IFF_BROADCAST 0x2 +#define IFF_DEBUG 0x4 +#define IFF_LOOPBACK 0x8 +#define IFF_POINTOPOINT 0x10 +#define IFF_NOTRAILERS 0x20 +#define IFF_RUNNING 0x40 +#define IFF_NOARP 0x80 +#define IFF_PROMISC 0x100 +#define IFF_ALLMULTI 0x200 +#define IFF_MASTER 0x400 +#define IFF_SLAVE 0x800 +#define IFF_MULTICAST 0x1000 +#define IFF_PORTSEL 0x2000 +#define IFF_AUTOMEDIA 0x4000 +#define IFF_DYNAMIC 0x8000 +#define IFF_LOWER_UP 0x10000 +#define IFF_DORMANT 0x20000 +#define IFF_ECHO 0x40000 + +#if __MLIBC_LINUX_OPTION + +#define __UAPI_DEF_IF_IFCONF 0 +#define __UAPI_DEF_IF_IFMAP 0 +#define __UAPI_DEF_IF_IFNAMSIZ 0 +#define __UAPI_DEF_IF_IFREQ 0 +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0 +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 0 + +#endif /* __MLIBC_LINUX_OPTION */ + +#ifdef __cplusplus +} +#endif + +#endif /* _NET_IF_H */ + + diff --git a/ext2_root/usr/include/net/if_arp.h b/ext2_root/usr/include/net/if_arp.h new file mode 100644 index 0000000..8701137 --- /dev/null +++ b/ext2_root/usr/include/net/if_arp.h @@ -0,0 +1,105 @@ +#ifndef _NET_IF_ARP_H +#define _NET_IF_ARP_H + +#include +#include +#include + +#define MAX_ADDR_LEN 7 + +#define ARPOP_REQUEST 1 +#define ARPOP_REPLY 2 +#define ARPOP_RREQUEST 3 +#define ARPOP_RREPLY 4 +#define ARPOP_InREQUEST 8 +#define ARPOP_InREPLY 9 +#define ARPOP_NAK 10 + +#define ARPHRD_NETROM 0 +#define ARPHRD_ETHER 1 +#define ARPHRD_EETHER 2 +#define ARPHRD_AX25 3 +#define ARPHRD_PRONET 4 +#define ARPHRD_CHAOS 5 +#define ARPHRD_IEEE802 6 +#define ARPHRD_ARCNET 7 +#define ARPHRD_APPLETLK 8 +#define ARPHRD_DLCI 15 +#define ARPHRD_ATM 19 +#define ARPHRD_METRICOM 23 +#define ARPHRD_IEEE1394 24 +#define ARPHRD_EUI64 27 +#define ARPHRD_INFINIBAND 32 +#define ARPHRD_SLIP 256 +#define ARPHRD_CSLIP 257 +#define ARPHRD_SLIP6 258 +#define ARPHRD_CSLIP6 259 +#define ARPHRD_RSRVD 260 +#define ARPHRD_ADAPT 264 +#define ARPHRD_ROSE 270 +#define ARPHRD_X25 271 +#define ARPHRD_HWX25 272 +#define ARPHRD_CAN 280 +#define ARPHRD_PPP 512 +#define ARPHRD_CISCO 513 +#define ARPHRD_HDLC ARPHRD_CISCO +#define ARPHRD_LAPB 516 +#define ARPHRD_DDCMP 517 +#define ARPHRD_RAWHDLC 518 +#define ARPHRD_RAWIP 519 + +#define ARPHRD_TUNNEL 768 +#define ARPHRD_TUNNEL6 769 +#define ARPHRD_FRAD 770 +#define ARPHRD_SKIP 771 +#define ARPHRD_LOOPBACK 772 +#define ARPHRD_LOCALTLK 773 +#define ARPHRD_FDDI 774 +#define ARPHRD_BIF 775 +#define ARPHRD_SIT 776 +#define ARPHRD_IPDDP 777 +#define ARPHRD_IPGRE 778 +#define ARPHRD_PIMREG 779 +#define ARPHRD_HIPPI 780 +#define ARPHRD_ASH 781 +#define ARPHRD_ECONET 782 +#define ARPHRD_IRDA 783 +#define ARPHRD_FCPP 784 +#define ARPHRD_FCAL 785 +#define ARPHRD_FCPL 786 +#define ARPHRD_FCFABRIC 787 +#define ARPHRD_IEEE802_TR 800 +#define ARPHRD_IEEE80211 801 +#define ARPHRD_IEEE80211_PRISM 802 +#define ARPHRD_IEEE80211_RADIOTAP 803 +#define ARPHRD_IEEE802154 804 +#define ARPHRD_IEEE802154_MONITOR 805 +#define ARPHRD_PHONET 820 +#define ARPHRD_PHONET_PIPE 821 +#define ARPHRD_CAIF 822 +#define ARPHRD_IP6GRE 823 +#define ARPHRD_NETLINK 824 +#define ARPHRD_6LOWPAN 825 +#define ARPHRD_VSOCKMON 826 + +#define ARPHRD_VOID 0xFFFF +#define ARPHRD_NONE 0xFFFE + +struct arphdr { + uint16_t ar_hrd; + uint16_t ar_pro; + uint8_t ar_hln; + uint8_t ar_pln; + uint16_t ar_op; +}; + +struct arpreq { + struct sockaddr arp_pa; + struct sockaddr arp_ha; + int arp_flags; + struct sockaddr arp_netmask; + char arp_dev[16]; +}; + +#endif /* _NET_IF_ARP_H */ + diff --git a/ext2_root/usr/include/net/if_ppp.h b/ext2_root/usr/include/net/if_ppp.h new file mode 100644 index 0000000..55f46b5 --- /dev/null +++ b/ext2_root/usr/include/net/if_ppp.h @@ -0,0 +1,23 @@ +#ifndef _NET_IF_PPP_H +#define _NET_IF_PPP_H + +#include + +#if __MLIBC_LINUX_OPTION +#include +#include + +#define PPPIOCGFLAGS _IOR('t', 90, int) +#define PPPIOCSFLAGS _IOW('t', 89, int) +#define PPPIOCGASYNCMAP _IOR('t', 88, int) +#define PPPIOCSASYNCMAP _IOW('t', 87, int) +#define PPPIOCGUNIT _IOR('t', 86, int) +#define PPPIOCSMRU _IOW('t', 82, int) +#define PPPIOCSMAXCID _IOW('t', 81, int) +#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) +#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) +#define PPPIOCGDEBUG _IOR('t', 65, int) +#define PPPIOCSDEBUG _IOW('t', 64, int) +#endif + +#endif /* _NET_IF_PPP_H */ diff --git a/ext2_root/usr/include/net/route.h b/ext2_root/usr/include/net/route.h new file mode 100644 index 0000000..7537241 --- /dev/null +++ b/ext2_root/usr/include/net/route.h @@ -0,0 +1,35 @@ +#ifndef _NET_ROUTE_H +#define _NET_ROUTE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTF_HOST 0x0004 +#define RTF_REJECT 0x0200 + +struct rtentry { + unsigned long int rt_pad1; + struct sockaddr rt_dst; + struct sockaddr rt_gateway; + struct sockaddr rt_genmask; + unsigned short int rt_flags; + short int rt_pad2; + unsigned long int rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short int rt_pad4[3]; + short int rt_metric; + char *rt_dev; + unsigned long int rt_mtu; + unsigned long int rt_window; + unsigned short int rt_irtt; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NET_ROUTE_H */ diff --git a/ext2_root/usr/include/netax25/ax25.h b/ext2_root/usr/include/netax25/ax25.h new file mode 100644 index 0000000..3fb82da --- /dev/null +++ b/ext2_root/usr/include/netax25/ax25.h @@ -0,0 +1,51 @@ +#ifndef _NETAX25_AX25_H +#define _NETAX25_AX25_H + +#include +#include + +#define AX25_VALUES_IPDEFMODE 0 +#define AX25_VALUES_AXDEFMODE 1 +#define AX25_VALUES_NETROM 2 +#define AX25_VALUES_TEXT 3 +#define AX25_VALUES_BACKOFF 4 +#define AX25_VALUES_CONMODE 5 +#define AX25_VALUES_WINDOW 6 +#define AX25_VALUES_EWINDOW 7 +#define AX25_VALUES_T1 8 +#define AX25_VALUES_T2 9 +#define AX25_VALUES_T3 10 +#define AX25_VALUES_N2 11 +#define AX25_VALUES_DIGI 12 +#define AX25_VALUES_IDLE 13 +#define AX25_VALUES_PACLEN 14 +#define AX25_VALUES_IPMAXQUEUE 15 +#define AX25_MAX_VALUES 20 + +typedef struct { + char ax25_call[7]; +} ax25_address; + +struct sockaddr_ax25 { + sa_family_t sax25_family; + ax25_address sax25_call; + int sax25_ndigis; +}; + +struct ax25_parms_struct { + ax25_address port_addr; + unsigned short values[AX25_MAX_VALUES]; +}; + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCAX25GETUID (SIOCPROTOPRIVATE) +#define SIOCAX25ADDUID (SIOCPROTOPRIVATE + 1) +#define SIOCAX25DELUID (SIOCPROTOPRIVATE + 2) +#define SIOCAX25NOUID (SIOCPROTOPRIVATE + 3) +#define SIOCAX25GETPARMS (SIOCPROTOPRIVATE + 5) +#define SIOCAX25SETPARMS (SIOCPROTOPRIVATE + 6) +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _NETAX25_AX25_H */ diff --git a/ext2_root/usr/include/netdb.h b/ext2_root/usr/include/netdb.h new file mode 100644 index 0000000..9f187fa --- /dev/null +++ b/ext2_root/usr/include/netdb.h @@ -0,0 +1,149 @@ +#ifndef _NETDB_H +#define _NETDB_H + +#include +#include +#include +#include +#include + +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_V4MAPPED 0x08 +#define AI_ALL 0x10 +#define AI_ADDRCONFIG 0x20 +#define AI_NUMERICSERV 0x40 + +#define NI_NOFQDN 0x01 +#define NI_NUMERICHOST 0x02 +#define NI_NAMEREQD 0x04 +#define NI_NUMERICSCOPE 0x08 +#define NI_DGRAM 0x10 + +#define NI_NUMERICSERV 2 +#define NI_MAXSERV 32 +#define NI_IDN 32 +#define NI_IDN_USE_STD3_ASCII_RULES 128 + +#define NI_MAXHOST 1025 + +#define EAI_AGAIN 1 +#define EAI_BADFLAGS 2 +#define EAI_FAIL 3 +#define EAI_FAMILY 4 +#define EAI_MEMORY 5 +#define EAI_NONAME 6 +#define EAI_SERVICE 7 +#define EAI_SOCKTYPE 8 +#define EAI_SYSTEM 9 +#define EAI_OVERFLOW 10 +#define EAI_NODATA 11 +#define EAI_ADDRFAMILY 12 + +#define HOST_NOT_FOUND 1 +#define TRY_AGAIN 2 +#define NO_RECOVERY 3 +#define NO_DATA 4 +#define NO_ADDRESS NO_DATA + +#define IPPORT_RESERVED 1024 + +#define _PATH_SERVICES "/etc/services" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int *__h_errno_location(void); +#define h_errno (*__h_errno_location()) + +#endif /* !__MLIBC_ABI_ONLY */ + +struct hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +#define h_addr h_addr_list[0] /* Required by some programs */ + +struct netent { + char *n_name; + char **n_aliases; + int n_addrtype; + uint32_t n_net; +}; + +struct protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + +struct servent { + char *s_name; + char **s_aliases; + int s_port; + char *s_proto; +}; + +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; + +#ifndef __MLIBC_ABI_ONLY + +void endhostent(void); +void endnetent(void); +void endprotoent(void); +void endservent(void); +void freeaddrinfo(struct addrinfo *__info); +const char *gai_strerror(int __errnum); +int getaddrinfo(const char *__restrict __node, const char *__restrict __service, + const struct addrinfo *__restrict __hints, struct addrinfo **__restrict __res); +struct hostent *gethostent(void); +struct hostent *gethostbyname(const char *__name); +struct hostent *gethostbyname2(const char *__name, int __flags); +struct hostent *gethostbyaddr(const void *__addr, socklen_t __len, int __type); +int gethostbyaddr_r(const void *__restrict __addr, socklen_t __len, int __type, struct hostent *__restrict __ret, + char *__restrict __buf, size_t __buflen, struct hostent **__restrict __res, int *__restrict __h_errnump); +int gethostbyname_r(const char *__restrict __name, struct hostent *__restrict __ret, char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __res, int *__restrict __h_errnump); +int getnameinfo(const struct sockaddr *__restrict __addr, socklen_t __addrlen, + char *__restrict __host, socklen_t __hostlen, char *__restrict __serv, socklen_t __servlen, int __flags); +struct netent *getnetbyaddr(uint32_t __net, int __type); +struct netent *getnetbyname(const char *__name); +struct netent *getnetent(void); +struct protoent *getprotobyname(const char *__name); +struct protoent *getprotobynumber(int __proto); +struct protoent *getprotoent(void); +struct servent *getservbyname(const char *__name, const char *__proto); +struct servent *getservbyport(int __port, const char *__proto); +struct servent *getservent(void); +void sethostent(int __stayopen); +void setnetent(int __stayopen); +void setprotoent(int __stayopen); +void setservent(int __stayopen); + +/* Deprecated GNU extension */ +const char *hstrerror(int __err); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _NETDB_H */ diff --git a/ext2_root/usr/include/netinet/ether.h b/ext2_root/usr/include/netinet/ether.h new file mode 100644 index 0000000..c9add31 --- /dev/null +++ b/ext2_root/usr/include/netinet/ether.h @@ -0,0 +1,24 @@ +#ifndef _NETINET_ETHER_H +#define _NETINET_ETHER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *ether_ntoa(const struct ether_addr *__addr); +char *ether_ntoa_r(const struct ether_addr *__p_a, char *__x); + +struct ether_addr *ether_aton(const char *__asc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /*_NETINET_ETHER_H */ diff --git a/ext2_root/usr/include/netinet/icmp6.h b/ext2_root/usr/include/netinet/icmp6.h new file mode 100644 index 0000000..5251bbd --- /dev/null +++ b/ext2_root/usr/include/netinet/icmp6.h @@ -0,0 +1,209 @@ +#ifndef _NETINET_ICMP6_H +#define _NETINET_ICMP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#if __MLIBC_GLIBC_OPTION +#include +#endif /* __MLIBC_GLIBC_OPTION */ + +#define ICMP6_FILTER 1 + +#define ICMP6_DST_UNREACH 1 +#define ICMP6_PACKET_TOO_BIG 2 +#define ICMP6_TIME_EXCEEDED 3 +#define ICMP6_PARAM_PROB 4 + +#define ICMP6_FILTER_BLOCK 1 +#define ICMP6_FILTER_PASS 2 +#define ICMP6_FILTER_BLOCKOTHERS 3 +#define ICMP6_FILTER_PASSONLY 4 +#define ICMP6_ECHO_REQUEST 128 +#define ICMP6_ECHO_REPLY 129 + +#define MLD_LISTENER_QUERY 130 +#define MLD_LISTENER_REPORT 131 +#define MLD_LISTENER_REDUCTION 132 + +#define ICMP6_DST_UNREACH_NOROUTE 0 +#define ICMP6_DST_UNREACH_ADMIN 1 +#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 +#define ICMP6_DST_UNREACH_ADDR 3 +#define ICMP6_DST_UNREACH_NOPORT 4 + +#define ICMP6_TIME_EXCEED_TRANSIT 0 +#define ICMP6_TIME_EXCEED_REASSEMBLY 1 + +#define ICMP6_PARAMPROB_HEADER 0 +#define ICMP6_PARAMPROB_NEXTHEADER 1 +#define ICMP6_PARAMPROB_OPTION 2 + +struct icmp6_filter { + uint32_t icmp6_filt[8]; +}; + +struct icmp6_hdr { + uint8_t icmp6_type; + uint8_t icmp6_code; + uint16_t icmp6_cksum; + union { + uint32_t icmp6_un_data32[1]; + uint16_t icmp6_un_data16[2]; + uint8_t icmp6_un_data8[4]; + } icmp6_dataun; +}; + +#define icmp6_data32 icmp6_dataun.icmp6_un_data32 +#define icmp6_data16 icmp6_dataun.icmp6_un_data16 +#define icmp6_data8 icmp6_dataun.icmp6_un_data8 + +#define icmp6_pptr icmp6_data32[0] +#define icmp6_mtu icmp6_data32[0] +#define icmp6_id icmp6_data16[0] +#define icmp6_seq icmp6_data16[1] +#define icmp6_maxdelay icmp6_data16[0] + +#define ICMP6_FILTER_WILLPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) == 0) + +#define ICMP6_FILTER_WILLBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) != 0) + +#define ICMP6_FILTER_SETPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1U << ((type) & 31)))) + +#define ICMP6_FILTER_SETBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) |= (1U << ((type) & 31)))) + +#define ICMP6_FILTER_SETPASSALL(filterp) \ + memset (filterp, 0, sizeof (struct icmp6_filter)); + +#define ICMP6_FILTER_SETBLOCKALL(filterp) \ + memset (filterp, 0xFF, sizeof (struct icmp6_filter)); + +#define ND_ROUTER_SOLICIT 133 +#define ND_ROUTER_ADVERT 134 +#define ND_NEIGHBOR_SOLICIT 135 +#define ND_NEIGHBOR_ADVERT 136 +#define ND_REDIRECT 137 + +struct nd_router_solicit { + struct icmp6_hdr nd_rs_hdr; +}; + +#define nd_rs_type nd_rs_hdr.icmp6_type +#define nd_rs_code nd_rs_hdr.icmp6_code +#define nd_rs_cksum nd_rs_hdr.icmp6_cksum +#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0] + +struct nd_router_advert { + struct icmp6_hdr nd_ra_hdr; + uint32_t nd_ra_reachable; + uint32_t nd_ra_retransmit; +}; + +struct nd_opt_hdr { + uint8_t nd_opt_type; + uint8_t nd_opt_len; +}; + +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define ND_OPT_PREFIX_INFORMATION 3 +#define ND_OPT_REDIRECTED_HEADER 4 +#define ND_OPT_MTU 5 +#define ND_OPT_RTR_ADV_INTERVAL 7 +#define ND_OPT_HOME_AGENT_INFO 8 + +struct nd_opt_prefix_info { + uint8_t nd_opt_pi_type; + uint8_t nd_opt_pi_len; + uint8_t nd_opt_pi_prefix_len; + uint8_t nd_opt_pi_flags_reserved; + uint32_t nd_opt_pi_valid_time; + uint32_t nd_opt_pi_preferred_time; + uint32_t nd_opt_pi_reserved2; + struct in6_addr nd_opt_pi_prefix; +}; + +#define ND_OPT_PI_FLAG_RADDR 0x20 +#define ND_OPT_PI_FLAG_AUTO 0x40 +#define ND_OPT_PI_FLAG_ONLINK 0x80 + +#define nd_ra_type nd_ra_hdr.icmp6_type +#define nd_ra_code nd_ra_hdr.icmp6_code +#define nd_ra_cksum nd_ra_hdr.icmp6_cksum +#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0] +#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] +#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] + +#define ND_RA_FLAG_HOME_AGENT 0x20 +#define ND_RA_FLAG_OTHER 0x40 +#define ND_RA_FLAG_MANAGED 0x80 + +struct nd_opt_rd_hdr { + uint8_t nd_opt_rh_type; + uint8_t nd_opt_rh_len; + uint16_t nd_opt_rh_reserved1; + uint32_t nd_opt_rh_reserved2; +}; + +struct nd_opt_mtu { + uint8_t nd_opt_mtu_type; + uint8_t nd_opt_mtu_len; + uint16_t nd_opt_mtu_reserved; + uint32_t nd_opt_mtu_mtu; +}; + +struct nd_neighbor_solicit { + struct icmp6_hdr nd_ns_hdr; + struct in6_addr nd_ns_target; +}; + +#define nd_ns_type nd_ns_hdr.icmp6_type +#define nd_ns_code nd_ns_hdr.icmp6_code +#define nd_ns_cksum nd_ns_hdr.icmp6_cksum + +struct nd_neighbor_advert { + struct icmp6_hdr nd_na_hdr; + struct in6_addr nd_na_target; +}; +#define nd_na_type nd_na_hdr.icmp6_type +#define nd_na_code nd_na_hdr.icmp6_code +#define nd_na_cksum nd_na_hdr.icmp6_cksum +#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0] + +struct nd_redirect { + struct icmp6_hdr nd_rd_hdr; + struct in6_addr nd_rd_target; + struct in6_addr nd_rd_dst; +}; + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum + +#define ND_NA_FLAG_OVERRIDE 0x00000020 +#define ND_NA_FLAG_SOLICITED 0x00000040 +#define ND_NA_FLAG_ROUTER 0x00000080 + +struct nd_opt_home_agent_info { + uint8_t nd_opt_home_agent_info_type; + uint8_t nd_opt_home_agent_info_len; + uint16_t nd_opt_home_agent_info_reserved; + uint16_t nd_opt_home_agent_info_preference; + uint16_t nd_opt_home_agent_info_lifetime; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_ICMP6_H */ + diff --git a/ext2_root/usr/include/netinet/if_ether.h b/ext2_root/usr/include/netinet/if_ether.h new file mode 100644 index 0000000..e79abc3 --- /dev/null +++ b/ext2_root/usr/include/netinet/if_ether.h @@ -0,0 +1,110 @@ +#ifndef _NETINET_IF_ETHER_H +#define _NETINET_IF_ETHER_H + +#include + +#define ETH_ALEN 6 +#define ETH_HLEN 14 +#define ETH_ZLEN 60 +#define ETH_FRAME_LEN 1514 +#define ETH_FCS_LEN 4 + +#define ETH_P_LOOP 0x0060 +#define ETH_P_PUP 0x0200 +#define ETH_P_PUPAT 0x0201 +#define ETH_P_IP 0x0800 +#define ETH_P_X25 0x0805 +#define ETH_P_ARP 0x0806 +#define ETH_P_BPQ 0x08FF +#define ETH_P_IEEEPUP 0x0a00 +#define ETH_P_IEEEPUPAT 0x0a01 +#define ETH_P_BATMAN 0x4305 +#define ETH_P_DEC 0x6000 +#define ETH_P_DNA_DL 0x6001 +#define ETH_P_DNA_RC 0x6002 +#define ETH_P_DNA_RT 0x6003 +#define ETH_P_LAT 0x6004 +#define ETH_P_DIAG 0x6005 +#define ETH_P_CUST 0x6006 +#define ETH_P_SCA 0x6007 +#define ETH_P_TEB 0x6558 +#define ETH_P_RARP 0x8035 +#define ETH_P_ATALK 0x809B +#define ETH_P_AARP 0x80F3 +#define ETH_P_8021Q 0x8100 +#define ETH_P_IPX 0x8137 +#define ETH_P_IPV6 0x86DD +#define ETH_P_PAUSE 0x8808 +#define ETH_P_SLOW 0x8809 +#define ETH_P_WCCP 0x883E +#define ETH_P_MPLS_UC 0x8847 +#define ETH_P_MPLS_MC 0x8848 +#define ETH_P_ATMMPOA 0x884c +#define ETH_P_PPP_DISC 0x8863 +#define ETH_P_PPP_SES 0x8864 +#define ETH_P_LINK_CTL 0x886c +#define ETH_P_ATMFATE 0x8884 +#define ETH_P_PAE 0x888E +#define ETH_P_AOE 0x88A2 +#define ETH_P_8021AD 0x88A8 +#define ETH_P_802_EX1 0x88B5 +#define ETH_P_TIPC 0x88CA +#define ETH_P_8021AH 0x88E7 +#define ETH_P_MVRP 0x88F5 +#define ETH_P_1588 0x88F7 +#define ETH_P_PRP 0x88FB +#define ETH_P_FCOE 0x8906 +#define ETH_P_TDLS 0x890D +#define ETH_P_FIP 0x8914 +#define ETH_P_80221 0x8917 +#define ETH_P_LOOPBACK 0x9000 +#define ETH_P_QINQ1 0x9100 +#define ETH_P_QINQ2 0x9200 +#define ETH_P_QINQ3 0x9300 +#define ETH_P_EDSA 0xDADA +#define ETH_P_AF_IUCV 0xFBFB + +#define ETH_P_802_3_MIN 0x0600 + +#define ETH_P_802_3 0x0001 +#define ETH_P_AX25 0x0002 +#define ETH_P_ALL 0x0003 +#define ETH_P_802_2 0x0004 +#define ETH_P_SNAP 0x0005 +#define ETH_P_DDCMP 0x0006 +#define ETH_P_WAN_PPP 0x0007 +#define ETH_P_PPP_MP 0x0008 +#define ETH_P_LOCALTALK 0x0009 +#define ETH_P_CAN 0x000C +#define ETH_P_CANFD 0x000D +#define ETH_P_PPPTALK 0x0010 +#define ETH_P_TR_802_2 0x0011 +#define ETH_P_MOBITEX 0x0015 +#define ETH_P_CONTROL 0x0016 +#define ETH_P_IRDA 0x0017 +#define ETH_P_ECONET 0x0018 +#define ETH_P_HDLC 0x0019 +#define ETH_P_ARCNET 0x001A +#define ETH_P_DSA 0x001B +#define ETH_P_TRAILER 0x001C +#define ETH_P_PHONET 0x00F5 +#define ETH_P_IEEE802154 0x00F6 +#define ETH_P_CAIF 0x00F7 + +#include +#include + +struct ether_arp { + struct arphdr ea_hdr; + uint8_t arp_sha[ETH_ALEN]; + uint8_t arp_spa[4]; + uint8_t arp_tha[ETH_ALEN]; + uint8_t arp_tpa[4]; +}; +#define arp_hrd ea_hdr.ar_hrd +#define arp_pro ea_hdr.ar_pro +#define arp_hln ea_hdr.ar_hln +#define arp_pln ea_hdr.ar_pln +#define arp_op ea_hdr.ar_op + +#endif /*_NETINET_IF_ETHER_H */ diff --git a/ext2_root/usr/include/netinet/in.h b/ext2_root/usr/include/netinet/in.h new file mode 100644 index 0000000..5dee2bd --- /dev/null +++ b/ext2_root/usr/include/netinet/in.h @@ -0,0 +1,122 @@ + +#ifndef _NETINET_IN_H +#define _NETINET_IN_H + +#include +#include /* struct sockaddr */ +#include +#include +#include +#include + +#if __MLIBC_GLIBC_OPTION + #include +#endif /*__MLIBC_GLIBC_OPTION */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +extern const struct in6_addr in6addr_any; +extern const struct in6_addr in6addr_loopback; + +uint32_t htonl(uint32_t __x); +uint16_t htons(uint16_t __x); +uint32_t ntohl(uint32_t __x); +uint16_t ntohs(uint16_t __x); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define IN6_IS_ADDR_UNSPECIFIED(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + !_a[2] && \ + !_a[3]; \ +}) +#define IN6_IS_ADDR_LOOPBACK(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + !_a[2] && \ + _a[3] == htonl(0x0001); \ +}) +#define IN6_IS_ADDR_MULTICAST(a) (((const uint8_t *) (a))[0] == 0xff) +#define IN6_IS_ADDR_LINKLOCAL(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + (_a[0] & htonl(0xffc00000)) == htonl(0xfe800000); \ +}) +#define IN6_IS_ADDR_SITELOCAL(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + (_a[0] & htonl(0xffc00000)) == htonl(0xfec00000); \ +}) +#define IN6_IS_ADDR_V4MAPPED(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + _a[2] == htonl(0xffff); \ +}) +#define __ARE_4_BYTE_EQUAL(a, b) \ + ((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] && \ + (a)[3] == (b)[3]) +#define IN6_ARE_ADDR_EQUAL(a, b) \ + __ARE_4_BYTE_EQUAL((const uint32_t *)(a), (const uint32_t *)(b)) + +#define IN6_IS_ADDR_V4COMPAT(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + uint8_t *_a8 = (uint8_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && !_a[1] && !_a[2] && (_a8[15] > 1); \ +}) +#define IN6_IS_ADDR_MC_NODELOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x1)); \ +}) +#define IN6_IS_ADDR_MC_LINKLOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x2)); \ +}) +#define IN6_IS_ADDR_MC_SITELOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x5)); \ +}) +#define IN6_IS_ADDR_MC_ORGLOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x8)); \ +}) +#define IN6_IS_ADDR_MC_GLOBAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0xe)); \ +}) + +#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 +#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 +#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) +#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#define MCAST_EXCLUDE 0 +#define MCAST_INCLUDE 1 + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_IN_H */ + diff --git a/ext2_root/usr/include/netinet/in_systm.h b/ext2_root/usr/include/netinet/in_systm.h new file mode 100644 index 0000000..131de89 --- /dev/null +++ b/ext2_root/usr/include/netinet/in_systm.h @@ -0,0 +1,7 @@ + +#ifndef _NETINET_IN_SYSTM_H +#define _NETINET_IN_SYSTM_H + + + +#endif /* _NETINET_IN_SYSTM_H */ diff --git a/ext2_root/usr/include/netinet/ip.h b/ext2_root/usr/include/netinet/ip.h new file mode 100644 index 0000000..cb7c06c --- /dev/null +++ b/ext2_root/usr/include/netinet/ip.h @@ -0,0 +1,118 @@ + +#ifndef _NETINET_IP_H +#define _NETINET_IP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST +#define IPTOS_CLASS_CS0 0x00 +#define IPTOS_CLASS_CS4 0x80 +#define IPTOS_CLASS_CS6 0xC0 +#define IPTOS_DSCP_EF 0xB8 + +#define IPOPT_COPY 0x80 +#define IPOPT_CLASS_MASK 0x60 +#define IPOPT_NUMBER_MASK 0x1f + +#define IPOPT_COPIED(o) ((o) & IPOPT_COPY) +#define IPOPT_CLASS(o) ((o) & IPOPT_CLASS_MASK) +#define IPOPT_NUMBER(o) ((o) & IPOPT_NUMBER_MASK) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_MEASUREMENT IPOPT_DEBMEAS +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 +#define IPOPT_END IPOPT_EOL +#define IPOPT_NOP 1 +#define IPOPT_NOOP IPOPT_NOP + +#define IPOPT_RR 7 +#define IPOPT_TS 68 +#define IPOPT_TIMESTAMP IPOPT_TS +#define IPOPT_SECURITY 130 +#define IPOPT_SEC IPOPT_SECURITY +#define IPOPT_LSRR 131 +#define IPOPT_SATID 136 +#define IPOPT_SID IPOPT_SATID +#define IPOPT_SSRR 137 +#define IPOPT_RA 148 + +#define IPOPT_OPTVAL 0 +#define IPOPT_OLEN 1 +#define IPOPT_OFFSET 2 +#define IPOPT_MINOFF 4 + +#define MAX_IPOPTLEN 40 + +#define IPOPT_TS_TSONLY 0 +#define IPOPT_TS_TSANDADDR 1 +#define IPOPT_TS_PRESPEC 3 + +#define IPDEFTTL 64 + +struct ip { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ip_hl:4; + unsigned int ip_v:4; +#endif +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int ip_v:4; + unsigned int ip_hl:4; +#endif + uint8_t ip_tos; + unsigned short ip_len; + unsigned short ip_id; + unsigned short ip_off; +#define IP_RF 0x8000 +#define IP_DF 0x4000 +#define IP_MF 0x2000 +#define IP_OFFMASK 0x1fff + uint8_t ip_ttl; + uint8_t ip_p; + unsigned short ip_sum; + struct in_addr ip_src, ip_dst; +}; + +#define IPVERSION 4 + +struct iphdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ihl:4; + unsigned int version:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4; + unsigned int ihl:4; +#else +# error "Please fix " +#endif + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_IP_H */ + diff --git a/ext2_root/usr/include/netinet/ip6.h b/ext2_root/usr/include/netinet/ip6.h new file mode 100644 index 0000000..268f8a2 --- /dev/null +++ b/ext2_root/usr/include/netinet/ip6.h @@ -0,0 +1,30 @@ +#ifndef _NETINET_IP6_H +#define _NETINET_IP6_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ip6_hdr { + union { + struct ip6_hdrctl { + uint32_t ip6_un1_flow; + uint16_t ip6_un1_plen; + uint8_t ip6_un1_nxt; + uint8_t ip6_un1_hlim; + } ip6_un1; + uint8_t ip6_un2_vfc; + } ip6_ctlun; + struct in6_addr ip6_src; + struct in6_addr ip6_dst; +}; + +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_IP6_H */ diff --git a/ext2_root/usr/include/netinet/ip_icmp.h b/ext2_root/usr/include/netinet/ip_icmp.h new file mode 100644 index 0000000..c5fecd1 --- /dev/null +++ b/ext2_root/usr/include/netinet/ip_icmp.h @@ -0,0 +1,140 @@ +#ifndef _NETINET_ICMP_H +#define _NETINET_ICMP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +struct icmphdr { + uint8_t type; + uint8_t code; + uint16_t checksum; + union { + struct { + uint16_t id; + uint16_t sequence; + } echo; + uint32_t gateway; + struct { + uint16_t __unused; + uint16_t mtu; + } frag; + uint8_t reserved[4]; + } un; +}; + +#define ICMP_ECHOREPLY 0 +#define ICMP_DEST_UNREACH 3 +#define ICMP_SOURCE_QUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO 8 +#define ICMP_TIME_EXCEEDED 11 +#define ICMP_PARAMETERPROB 12 +#define ICMP_TIMESTAMP 13 +#define ICMP_TIMESTAMPREPLY 14 +#define ICMP_INFO_REQUEST 15 +#define ICMP_INFO_REPLY 16 +#define ICMP_ADDRESS 17 +#define ICMP_ADDRESSREPLY 18 + +#define ICMP_NET_UNREACH 0 +#define ICMP_HOST_UNREACH 1 +#define ICMP_PROT_UNREACH 2 +#define ICMP_PORT_UNREACH 3 +#define ICMP_FRAG_NEEDED 4 +#define ICMP_SR_FAILED 5 +#define ICMP_NET_UNKNOWN 6 +#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_ISOLATED 8 +#define ICMP_NET_ANO 9 +#define ICMP_HOST_ANO 10 +#define ICMP_NET_UNR_TOS 11 +#define ICMP_HOST_UNR_TOS 12 +#define ICMP_PKT_FILTERED 13 +#define ICMP_PREC_VIOLATION 14 +#define ICMP_PREC_CUTOFF 15 +#define NR_ICMP_UNREACH 15 + +#define ICMP_REDIR_NET 0 +#define ICMP_REDIR_HOST 1 +#define ICMP_REDIR_NETTOS 2 +#define ICMP_REDIR_HOSTTOS 3 + +#define ICMP_EXC_TTL 0 +#define ICMP_EXC_FRAGTIME 1 + +#define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) + +struct icmp_ra_addr { + uint32_t ira_addr; + uint32_t ira_preference; +}; + +struct icmp { + uint8_t icmp_type; + uint8_t icmp_code; + uint16_t icmp_cksum; + union { + unsigned char ih_pptr; + struct in_addr ih_gwaddr; + struct ih_idseq { + uint16_t icd_id; + uint16_t icd_seq; + } ih_idseq; + uint32_t ih_void; + + struct ih_pmtu { + uint16_t ipm_void; + uint16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv { + uint8_t irt_num_addrs; + uint8_t irt_wpa; + uint16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; + union { + struct { + uint32_t its_otime; + uint32_t its_rtime; + uint32_t its_ttime; + } id_ts; + struct { + struct ip idi_ip; + } id_ip; + struct icmp_ra_addr id_radv; + uint32_t id_mask; + uint8_t id_data[1]; + } icmp_dun; +}; + +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_ICMP_H */ diff --git a/ext2_root/usr/include/netinet/tcp.h b/ext2_root/usr/include/netinet/tcp.h new file mode 100644 index 0000000..2ac4201 --- /dev/null +++ b/ext2_root/usr/include/netinet/tcp.h @@ -0,0 +1,95 @@ +#ifndef _NETINET_TCP_H +#define _NETINET_TCP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define some macros using same ABI as Linux */ +#define TCP_NODELAY 1 +#define TCP_MAXSEG 2 +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 +#define TCP_KEEPCNT 6 +#define TCP_DEFER_ACCEPT 9 +#define TCP_INFO 11 +#define TCP_CONGESTION 13 +#define TCP_FASTOPEN 23 + +#define TCP_ESTABLISHED 1 +#define TCP_SYN_SENT 2 +#define TCP_SYN_RECV 3 +#define TCP_FIN_WAIT1 4 +#define TCP_FIN_WAIT2 5 +#define TCP_TIME_WAIT 6 +#define TCP_CLOSE 7 +#define TCP_CLOSE_WAIT 8 +#define TCP_LAST_ACK 9 +#define TCP_LISTEN 10 +#define TCP_CLOSING 11 +#define TCP_QUICKACK 12 + +#define SOL_TCP 6 + +#define TCPI_OPT_TIMESTAMPS 1 +#define TCPI_OPT_SACK 2 +#define TCPI_OPT_WSCALE 4 +#define TCPI_OPT_ECN 8 +#define TCPI_OPT_ECN_SEEN 16 +#define TCPI_OPT_SYN_DATA 32 + +enum tcp_ca_state { + TCP_CA_Open = 0, + TCP_CA_Disorder = 1, + TCP_CA_CWR = 2, + TCP_CA_Recovery = 3, + TCP_CA_Loss = 4 +}; + +struct tcp_info { + uint8_t tcpi_state; + uint8_t tcpi_ca_state; + uint8_t tcpi_retransmits; + uint8_t tcpi_probes; + uint8_t tcpi_backoff; + uint8_t tcpi_options; + __extension__ uint8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4; + + uint32_t tcpi_rto; + uint32_t tcpi_ato; + uint32_t tcpi_snd_mss; + uint32_t tcpi_rcv_mss; + + uint32_t tcpi_unacked; + uint32_t tcpi_sacked; + uint32_t tcpi_lost; + uint32_t tcpi_retrans; + uint32_t tcpi_fackets; + + uint32_t tcpi_last_data_sent; + uint32_t tcpi_last_ack_sent; + uint32_t tcpi_last_data_recv; + uint32_t tcpi_last_ack_recv; + + uint32_t tcpi_pmtu; + uint32_t tcpi_rcv_ssthresh; + uint32_t tcpi_rtt; + uint32_t tcpi_rttvar; + uint32_t tcpi_snd_ssthresh; + uint32_t tcpi_snd_cwnd; + uint32_t tcpi_advmss; + uint32_t tcpi_reordering; + + uint32_t tcpi_rcv_rtt; + uint32_t tcpi_rcv_space; + + uint32_t tcpi_total_retrans; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_TCP_H */ diff --git a/ext2_root/usr/include/netinet/udp.h b/ext2_root/usr/include/netinet/udp.h new file mode 100644 index 0000000..1563f1c --- /dev/null +++ b/ext2_root/usr/include/netinet/udp.h @@ -0,0 +1,31 @@ +#ifndef _NETINET_UDP_H +#define _NETINET_UDP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__extension__ struct udphdr { + __extension__ union { + struct { + uint16_t uh_sport; + uint16_t uh_dport; + uint16_t uh_ulen; + uint16_t uh_sum; + }; + struct { + uint16_t source; + uint16_t dest; + uint16_t len; + uint16_t check; + }; + }; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_UDP_H */ diff --git a/ext2_root/usr/include/netipx/ipx.h b/ext2_root/usr/include/netipx/ipx.h new file mode 100644 index 0000000..7b5c774 --- /dev/null +++ b/ext2_root/usr/include/netipx/ipx.h @@ -0,0 +1,35 @@ +#ifndef _NETIPX_IPX_H +#define _NETIPX_IPX_H + +#include +#include +#include + +typedef struct ipx_config_data { + unsigned char ipxcfg_auto_select_primary; + unsigned char ipxcfg_auto_create_interfaces; +} ipx_config_data; + +#define IPX_TYPE 1 +#define IPX_NODE_LEN 6 + +struct sockaddr_ipx { + sa_family_t sipx_family; + uint16_t sipx_port; + uint32_t sipx_network; + unsigned char sipx_node[IPX_NODE_LEN]; + uint8_t sipx_type; + unsigned char sipx_zero; +}; + +#define SOL_IPX 256 + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCAIPXITFCRT (SIOCPROTOPRIVATE) +#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE + 1) +#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE + 2) +#endif + +#endif /* _NETIPX_IPX_H */ diff --git a/ext2_root/usr/include/netrom/netrom.h b/ext2_root/usr/include/netrom/netrom.h new file mode 100644 index 0000000..69497d9 --- /dev/null +++ b/ext2_root/usr/include/netrom/netrom.h @@ -0,0 +1,27 @@ +#ifndef _NETROM_NETROM_H +#define _NETROM_NETROM_H + +#include + +struct nr_parms_struct { + unsigned int quality; + unsigned int obs_count; + unsigned int ttl; + unsigned int timeout; + unsigned int ack_delay; + unsigned int busy_delay; + unsigned int tries; + unsigned int window; + unsigned int paclen; +}; + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCNRGETPARMS (SIOCPROTOPRIVATE) +#define SIOCNRSETPARMS (SIOCPROTOPRIVATE + 1) +#define SIOCNRDECOBS (SIOCPROTOPRIVATE + 2) +#define SIOCNRRTCTL (SIOCPROTOPRIVATE + 3) +#endif + +#endif /* _NETROM_NETROM_H */ diff --git a/ext2_root/usr/include/nl_types.h b/ext2_root/usr/include/nl_types.h new file mode 100644 index 0000000..8878629 --- /dev/null +++ b/ext2_root/usr/include/nl_types.h @@ -0,0 +1,6 @@ +#ifndef NL_TYPES_H +#define NL_TYPES_H + + + +#endif /* NL_TYPES_H */ diff --git a/ext2_root/usr/include/paths.h b/ext2_root/usr/include/paths.h new file mode 100644 index 0000000..81d354a --- /dev/null +++ b/ext2_root/usr/include/paths.h @@ -0,0 +1,41 @@ +/* This file is taken from musl */ +/* Path to original: include/paths.h */ + +#ifndef _PATHS_H +#define _PATHS_H + +#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" +#define _PATH_STDPATH "/bin:/usr/bin:/sbin:/usr/sbin" + +#define _PATH_BSHELL "/bin/sh" +#define _PATH_CONSOLE "/dev/console" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_GSHADOW "/etc/gshadow" +#define _PATH_KLOG "/proc/kmsg" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_MAILDIR "/var/mail" +#define _PATH_MAN "/usr/share/man" +#define _PATH_MNTTAB "/etc/fstab" +#define _PATH_MOUNTED "/etc/mtab" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_PRESERVE "/var/lib" +#define _PATH_SENDMAIL "/usr/sbin/sendmail" +#define _PATH_SHADOW "/etc/shadow" +#define _PATH_SHELLS "/etc/shells" +#define _PATH_TTY "/dev/tty" +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_VI "/usr/bin/vi" +#define _PATH_WTMP "/var/log/wtmp" + +#define _PATH_DEV "/dev/" +#define _PATH_TMP "/tmp/" +#define _PATH_VARDB "/var/lib/misc/" +#define _PATH_VARRUN "/var/run/" +#define _PATH_VARTMP "/var/tmp/" + +#ifdef _GNU_SOURCE +#define _PATH_UTMPX _PATH_UTMP +#define _PATH_WTMPX _PATH_WTMP +#endif + +#endif /* _PATHS_H */ diff --git a/ext2_root/usr/include/poll.h b/ext2_root/usr/include/poll.h new file mode 100644 index 0000000..2611296 --- /dev/null +++ b/ext2_root/usr/include/poll.h @@ -0,0 +1,6 @@ +#ifndef _POLL_H +#define _POLL_H + +#include + +#endif /* _POLL_H */ diff --git a/ext2_root/usr/include/printf.h b/ext2_root/usr/include/printf.h new file mode 100644 index 0000000..b6b86b9 --- /dev/null +++ b/ext2_root/usr/include/printf.h @@ -0,0 +1,41 @@ +#ifndef _PRINTF_H +#define _PRINTF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +/* This seems to be a glibc thing, so constants are from glibc */ +size_t parse_printf_format(const char * __restrict __format, size_t __size, int * __restrict __argtypes); + +#endif /* !__MLIBC_ABI_ONLY */ + +enum { + PA_INT, + PA_CHAR, + PA_WCHAR, + PA_STRING, + PA_WSTRING, + PA_POINTER, + PA_FLOAT, + PA_DOUBLE, + PA_LAST +}; + +#define PA_FLAG_MASK 0xff00 +#define PA_FLAG_LONG_LONG (1 << 8) +#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG +#define PA_FLAG_LONG (1 << 9) +#define PA_FLAG_SHORT (1 << 10) +#define PA_FLAG_PTR (1 << 11) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/pthread.h b/ext2_root/usr/include/pthread.h new file mode 100644 index 0000000..ca024a4 --- /dev/null +++ b/ext2_root/usr/include/pthread.h @@ -0,0 +1,322 @@ + +#ifndef _PTHREAD_H +#define _PTHREAD_H + +#include +#include +/* TODO: pthread is not required to define size_t. */ +#include +#include +#include +#include + +#include +#include + +/* pthread.h is required to include sched.h and time.h */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PTHREAD_CREATE_JOINABLE __MLIBC_THREAD_CREATE_JOINABLE +#define PTHREAD_CREATE_DETACHED __MLIBC_THREAD_CREATE_DETACHED + +/* Values for pthread_attr_{get,set}scope */ +#define PTHREAD_SCOPE_SYSTEM 0 +#define PTHREAD_SCOPE_PROCESS 1 + +/* Values for pthread_attr_{get,set}inheritsched */ +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +/* values for pthread_{get,set}canceltype(). */ +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +/* values for pthread_{get,set}cancelstate(). */ +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 + +/* values for pthread_mutexattr_{get,set}type(). */ +#define PTHREAD_MUTEX_DEFAULT __MLIBC_THREAD_MUTEX_DEFAULT +#define PTHREAD_MUTEX_NORMAL __MLIBC_THREAD_MUTEX_NORMAL +#define PTHREAD_MUTEX_ERRORCHECK __MLIBC_THREAD_MUTEX_ERRORCHECK +#define PTHREAD_MUTEX_RECURSIVE __MLIBC_THREAD_MUTEX_RECURSIVE + +/* values for pthread_mutexattr_{get,set}robust(). */ +#define PTHREAD_MUTEX_STALLED __MLIBC_THREAD_MUTEX_STALLED +#define PTHREAD_MUTEX_ROBUST __MLIBC_THREAD_MUTEX_ROBUST + +/* values for pthread_mutexattr_{get,set}pshared(). */ +#define PTHREAD_PROCESS_PRIVATE __MLIBC_THREAD_PROCESS_PRIVATE +#define PTHREAD_PROCESS_SHARED __MLIBC_THREAD_PROCESS_SHARED + +/* Values for pthread_mutexattr_{get,set}protocol() */ +#define PTHREAD_PRIO_NONE __MLIBC_THREAD_PRIO_NONE +#define PTHREAD_PRIO_INHERIT __MLIBC_THREAD_PRIO_INHERIT +#define PTHREAD_PRIO_PROTECT __MLIBC_THREAD_PRIO_PROTECT + +#define PTHREAD_ONCE_INIT {0} +#define PTHREAD_COND_INITIALIZER {0} +#define PTHREAD_MUTEX_INITIALIZER __MLIBC_THREAD_MUTEX_INITIALIZER +#define PTHREAD_RWLOCK_INITIALIZER {0, 0, 0} + +#define PTHREAD_CANCELED ((void*) -1) + +#define PTHREAD_BARRIER_SERIAL_THREAD -1 + +/* values for pthread_key */ +#define PTHREAD_DESTRUCTOR_ITERATIONS 8 + +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +#define PTHREAD_STACK_MIN 16384 + +#define PTHREAD_ATTR_NO_SIGMASK_NP (-1) + +/* TODO: move to own file and include in sys/types.h */ +typedef struct __mlibc_threadattr pthread_attr_t; + +typedef uintptr_t pthread_key_t; + +struct __mlibc_once { + unsigned int __mlibc_done; +}; +typedef struct __mlibc_once pthread_once_t; + +typedef struct __mlibc_mutexattr pthread_mutexattr_t; + +typedef struct __mlibc_mutex pthread_mutex_t; + +typedef struct __mlibc_condattr pthread_condattr_t; + +typedef struct __mlibc_cond pthread_cond_t; + +struct __mlibc_barrierattr_struct { + int __mlibc_pshared; +}; +typedef struct __mlibc_barrierattr_struct pthread_barrierattr_t; + +struct __mlibc_barrier { + unsigned int __mlibc_waiting; + unsigned int __mlibc_inside; + unsigned int __mlibc_count; + unsigned int __mlibc_seq; + unsigned int __mlibc_flags; +}; +typedef struct __mlibc_barrier pthread_barrier_t; + +struct __mlibc_fair_rwlock { + unsigned int __mlibc_m; /* Mutex. */ + unsigned int __mlibc_rc; /* Reader count (not reference count). */ + unsigned int __mlibc_flags; +}; +typedef struct __mlibc_fair_rwlock pthread_rwlock_t; + +struct __mlibc_rwlockattr { + int __mlibc_pshared; +}; +typedef struct __mlibc_rwlockattr pthread_rwlockattr_t; + +#ifndef __MLIBC_ABI_ONLY + +/* ---------------------------------------------------------------------------- */ +/* pthread_attr and pthread functions. */ +/* ---------------------------------------------------------------------------- */ + +/* pthread_attr functions. */ +int pthread_attr_init(pthread_attr_t *__attr); +int pthread_attr_destroy(pthread_attr_t *__attr); + +int pthread_attr_getdetachstate(const pthread_attr_t *__attr, int *__state); +int pthread_attr_setdetachstate(pthread_attr_t *__attr, int __state); + +int pthread_attr_getstacksize(const pthread_attr_t *__restrict __attr, size_t *__restrict __stacksize); +int pthread_attr_setstacksize(pthread_attr_t *__attr, size_t __stacksize); + +int pthread_attr_getstackaddr(const pthread_attr_t *__attr, void **__stackaddr); +int pthread_attr_setstackaddr(pthread_attr_t *__attr, void *__stackaddr); + +int pthread_attr_getstack(const pthread_attr_t *__attr, void **__stackaddr, size_t *__stacksize); +int pthread_attr_setstack(pthread_attr_t *__attr, void *__stackaddr, size_t __stacksize); + +int pthread_attr_getguardsize(const pthread_attr_t *__restrict __attr, size_t *__restrict __guardsize); +int pthread_attr_setguardsize(pthread_attr_t *__attr, size_t __guardsize); + +int pthread_attr_getscope(const pthread_attr_t *__attr, int *__scope); +int pthread_attr_setscope(pthread_attr_t *__attr, int __scope); + +int pthread_attr_getschedparam(const pthread_attr_t *__restrict __attr, struct sched_param *__restrict __param); +int pthread_attr_setschedparam(pthread_attr_t *__restrict __attr, const struct sched_param *__restrict __param); + +int pthread_attr_getschedpolicy(const pthread_attr_t *__restrict __attr, int *__restrict __schedpolicy); +int pthread_attr_setschedpolicy(pthread_attr_t *__restrict __attr, int __schedpolicy); + +int pthread_attr_getinheritsched(const pthread_attr_t *__restrict __attr, int *__restrict __inheritsched); +int pthread_attr_setinheritsched(pthread_attr_t *__restrict __attr, int __inheritsched); + +#if __MLIBC_LINUX_OPTION +int pthread_attr_getaffinity_np(const pthread_attr_t *__restrict __attr, size_t __cpusetsize, cpu_set_t *__restrict __cpuset); +int pthread_attr_setaffinity_np(pthread_attr_t *__restrict __attr, size_t __cpusetsize, const cpu_set_t *__restrict __cpuset); + +int pthread_attr_getsigmask_np(const pthread_attr_t *__restrict __attr, sigset_t *__restrict __sigmask); +int pthread_attr_setsigmask_np(pthread_attr_t *__restrict __attr, const sigset_t *__restrict __sigmask); + +int pthread_getattr_np(pthread_t __thrd, pthread_attr_t *__attr); + +int pthread_getaffinity_np(pthread_t __thrd, size_t __cpusetsize, cpu_set_t *__cpuset); +int pthread_setaffinity_np(pthread_t __thrd, size_t __cpusetsize, const cpu_set_t *__cpuset); +#endif /* __MLIBC_LINUX_OPTION */ + +/* pthread functions. */ +int pthread_create(pthread_t *__restrict __thrd, const pthread_attr_t *__restrict __attr, + void *(*__fn) (void *__arg), void *__restrict __arg); +pthread_t pthread_self(void); +int pthread_equal(pthread_t __a, pthread_t __b); +__attribute__ ((__noreturn__)) void pthread_exit(void *__arg); + +int pthread_join(pthread_t __thrd, void **__res); +int pthread_detach(pthread_t __thrd); + +void pthread_cleanup_push(void (*__fn) (void *__arg), void *__arg); +void pthread_cleanup_pop(int __execute); + +int pthread_setname_np(pthread_t __thrd, const char *__name); +int pthread_getname_np(pthread_t __thrd, char *__name, size_t __size); + +int pthread_attr_setstack(pthread_attr_t *__attr, void *__stackaddr, size_t __stacksize); +int pthread_attr_getstack(const pthread_attr_t *, void **__stackaddr, size_t *__stacksize); + +int pthread_getattr_np(pthread_t __thrd, pthread_attr_t *__attr); + +int pthread_setschedparam(pthread_t __thrd, int __policy, const struct sched_param *__param); +int pthread_getschedparam(pthread_t __thrd, int *__policy, struct sched_param *__param); + +int pthread_setcanceltype(int __type, int *__oldtype); +int pthread_setcancelstate(int __state, int *__oldstate); +void pthread_testcancel(void); +int pthread_cancel(pthread_t __thrd); + +int pthread_atfork(void (*__prepare) (void), void (*__parent) (void), void (*__child) (void)); + +/* ---------------------------------------------------------------------------- */ +/* pthread_key functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_key_create(pthread_key_t *__key, void (*__destructor) (void *__data)); +int pthread_key_delete(pthread_key_t __key); + +void *pthread_getspecific(pthread_key_t __key); +int pthread_setspecific(pthread_key_t __key, const void *__data); + +/* ---------------------------------------------------------------------------- */ +/* pthread_once functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_once(pthread_once_t *__once, void (*__fn) (void)); + +/* ---------------------------------------------------------------------------- */ +/* pthread_mutexattr and pthread_mutex functions. */ +/* ---------------------------------------------------------------------------- */ + +/* pthread_mutexattr functions */ +int pthread_mutexattr_init(pthread_mutexattr_t *__attr); +int pthread_mutexattr_destroy(pthread_mutexattr_t *__attr); + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict __attr, int *__restrict __type); +int pthread_mutexattr_settype(pthread_mutexattr_t *__attr, int __type); + +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict __attr, int *__restrict __robust); +int pthread_mutexattr_setrobust(pthread_mutexattr_t *__attr, int __robust); + +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__attr, int *__pshared); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *__attr, int __pshared); + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict __attr, int *__restrict __protocol); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *__attr, int __protocol); + +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__attr, int *__prioceiling); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *__attr, int __prioceiling); + +/* pthread_mutex functions */ +int pthread_mutex_init(pthread_mutex_t *__restrict __mtx, const pthread_mutexattr_t *__restrict __attr); +int pthread_mutex_destroy(pthread_mutex_t *__mtx); + +int pthread_mutex_lock(pthread_mutex_t *__mtx); +int pthread_mutex_trylock(pthread_mutex_t *__mtx); +int pthread_mutex_timedlock(pthread_mutex_t *__restrict __mtx, + const struct timespec *__restrict __abs_timeout); +int pthread_mutex_unlock(pthread_mutex_t *__mtx); + +int pthread_mutex_consistent(pthread_mutex_t *__mtx); + +/* ---------------------------------------------------------------------------- */ +/* pthread_condattr and pthread_cond functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_condattr_init(pthread_condattr_t *__attr); +int pthread_condattr_destroy(pthread_condattr_t *__attr); + +int pthread_condattr_getclock(const pthread_condattr_t *__restrict __attr, clockid_t *__restrict __clockid); +int pthread_condattr_setclock(pthread_condattr_t *__attr, clockid_t __clockid); + +int pthread_condattr_getpshared(const pthread_condattr_t *__restrict __attr, int *__restrict __pshared); +int pthread_condattr_setpshared(pthread_condattr_t *__attr, int __pshared); + +int pthread_cond_init(pthread_cond_t *__restrict __cond, const pthread_condattr_t *__restrict __attr); +int pthread_cond_destroy(pthread_cond_t *__cond); + +int pthread_cond_wait(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mtx); +int pthread_cond_timedwait(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mtx, + const struct timespec *__restrict __abs_timeout); +int pthread_cond_signal(pthread_cond_t *__cond); +int pthread_cond_broadcast(pthread_cond_t *__cond); + +/* ---------------------------------------------------------------------------- */ +/* pthread_barrierattr and pthread_barrier functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_barrierattr_init(pthread_barrierattr_t *__attr); +int pthread_barrierattr_destroy(pthread_barrierattr_t *__attr); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *__attr, int __pshared); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict __attr, + int *__restrict __pshared); + +int pthread_barrier_init(pthread_barrier_t *__restrict __barrier, const pthread_barrierattr_t *__restrict __attr, + unsigned int __count); +int pthread_barrier_destroy(pthread_barrier_t *__barrier); + +int pthread_barrier_wait(pthread_barrier_t *__barrier); + +/* ---------------------------------------------------------------------------- */ +/* pthread_wrlockattr and pthread_rwlock functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_rwlockattr_init(pthread_rwlockattr_t *__attr); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *__attr); +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *__attr, int __pshared); +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict __attr, + int *__restrict __pshared); + +int pthread_rwlock_init(pthread_rwlock_t *__restrict __rwlock, const pthread_rwlockattr_t *__restrict __attr); +int pthread_rwlock_destroy(pthread_rwlock_t *__rwlock); +int pthread_rwlock_trywrlock(pthread_rwlock_t *__rwlock); +int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock); +int pthread_rwlock_tryrdlock(pthread_rwlock_t *__rwlock); +int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock); +int pthread_rwlock_unlock(pthread_rwlock_t *__rwlock); + +int pthread_getcpuclockid(pthread_t __thrd, clockid_t *__clockid); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PTHREAD_H */ + diff --git a/ext2_root/usr/include/pty.h b/ext2_root/usr/include/pty.h new file mode 100644 index 0000000..6379ae7 --- /dev/null +++ b/ext2_root/usr/include/pty.h @@ -0,0 +1,23 @@ + +#ifndef _PTY_H +#define _PTY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int openpty(int *__mfd, int *__sfd, char *__name, const struct termios *__ios, const struct winsize *__win); +int forkpty(int *__mfd, char *__name, const struct termios *__ios, const struct winsize *__win); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PTY_H */ + diff --git a/ext2_root/usr/include/pwd.h b/ext2_root/usr/include/pwd.h new file mode 100644 index 0000000..fd4f9c4 --- /dev/null +++ b/ext2_root/usr/include/pwd.h @@ -0,0 +1,45 @@ + +#ifndef _PWD_H +#define _PWD_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct passwd { + char *pw_name; + char *pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + char *pw_gecos; + char *pw_dir; + char *pw_shell; +}; + +#define NSS_BUFLEN_PASSWD 512 + +#ifndef __MLIBC_ABI_ONLY + +void endpwent(void); +struct passwd *getpwent(void); +struct passwd *getpwnam(const char *__name); +int getpwnam_r(const char *__name, struct passwd *__ret, char *__buf, size_t __buflen, struct passwd **__res); +struct passwd *getpwuid(uid_t __uid); +int getpwuid_r(uid_t __uid, struct passwd *__ret, char *__buf, size_t __buflen, struct passwd **__res); +void setpwent(void); +int putpwent(const struct passwd *__pwd, FILE *__f); +struct passwd *fgetpwent(FILE *__f); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PWD_H */ + diff --git a/ext2_root/usr/include/regex.h b/ext2_root/usr/include/regex.h new file mode 100644 index 0000000..8a2c827 --- /dev/null +++ b/ext2_root/usr/include/regex.h @@ -0,0 +1,67 @@ +#ifndef _REGEX_H +#define _REGEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef ptrdiff_t regoff_t; + +typedef struct re_pattern_buffer { + size_t re_nsub; + void *__opaque, *__padding[4]; + size_t __nsub2; + char __padding2; +} regex_t; + +typedef struct { + regoff_t rm_so; + regoff_t rm_eo; +} regmatch_t; + +/* Flags for regcomp(). */ +#define REG_EXTENDED 1 +#define REG_ICASE 2 +#define REG_NEWLINE 4 +#define REG_NOSUB 8 + +/* Flags for regexec(). */ +#define REG_NOTBOL 1 +#define REG_NOTEOL 2 + +/* Errors for regcomp() and regexec(). */ +#define REG_OK 0 +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 + +/* Obsolete in POSIX. */ +#define REG_ENOSYS -1 + +#ifndef __MLIBC_ABI_ONLY + +int regcomp(regex_t *__restrict __regex, const char *__restrict __pattern, int __flags); +int regexec(const regex_t *__restrict __regex, const char *__restrict __string, size_t __nmatch, + regmatch_t *__restrict __pmatch, int __flags); +size_t regerror(int __errcode, const regex_t *__restrict __regex, char *__restrict __errbuf, size_t __errbuf_size); +void regfree(regex_t *__regex); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/resolv.h b/ext2_root/usr/include/resolv.h new file mode 100644 index 0000000..05176fd --- /dev/null +++ b/ext2_root/usr/include/resolv.h @@ -0,0 +1,78 @@ +#ifndef _RESOLV_H +#define _RESOLV_H + +#include + +#define RES_INIT 0x00000001 +#define RES_DEBUG 0x00000002 +#define RES_USEVC 0x00000008 +#define RES_IGNTC 0x00000020 +#define RES_RECURSE 0x00000040 +#define RES_DEFNAMES 0x00000080 +#define RES_STAYOPEN 0x00000100 +#define RES_DNSRCH 0x00000200 + +#define MAXNS 3 +#define MAXDNSRCH 6 + +#define _PATH_RESCONF "/etc/resolv.conf" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int dn_expand(const unsigned char *__msg, const unsigned char *__eomorig, + const unsigned char *__comp_dn, char *__exp_dn, int __size); + +int res_query(const char *__dname, int __class, int __type, + unsigned char *__answer, int __anslen); + +int res_init(void); + +int dn_comp(const char *, unsigned char *, int, unsigned char **, unsigned char **); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* From musl: Unused; purely for broken apps + * To avoid an massive struct, only add the items requested. */ +typedef struct __res_state { + int retrans; + int retry; + unsigned long options; + int nscount; + struct sockaddr_in nsaddr_list[MAXNS]; + char *dnsrch[MAXDNSRCH + 1]; + char defdname[256]; + unsigned ndots:4; + unsigned nsort:4; + union { + char pad[52]; + struct { + uint16_t nscount; + uint16_t nsmap[MAXNS]; + int nssocks[MAXNS]; + uint16_t nscount6; + uint16_t nsinit; + struct sockaddr_in6 *nsaddrs[MAXNS]; + unsigned int _initstamp[2]; + } _ext; + } _u; +} *res_state; + +#ifndef __MLIBC_ABI_ONLY + +struct __res_state *__res_state(void); +#define _res (*__res_state()) + +int res_ninit(res_state __state); +void res_nclose(res_state __state); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _RESOLV_H */ diff --git a/ext2_root/usr/include/sched.h b/ext2_root/usr/include/sched.h new file mode 100644 index 0000000..0b56215 --- /dev/null +++ b/ext2_root/usr/include/sched.h @@ -0,0 +1,50 @@ + +#ifndef _SCHED_H +#define _SCHED_H + +#include +#include +#include +#include + +/* MISSING: time_t, struct timespec */ + +/* MISSING: POSIX [PS], [SS] and [TSP] options */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if __MLIBC_LINUX_OPTION +#include +#include +#endif + +#define SCHED_OTHER 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 +#define SCHED_BATCH 3 +#define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 +#define SCHED_RESET_ON_FORK 0x40000000 + +#ifndef __MLIBC_ABI_ONLY + +int sched_yield(void); + +int sched_get_priority_max(int __policy); +int sched_get_priority_min(int __policy); + +int sched_setscheduler(pid_t __pid, int __policy, const struct sched_param *__param); + +int sched_getparam(pid_t __pid, struct sched_param *__param); +int sched_setparam(pid_t __pid, const struct sched_param *__param); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SCHED_H */ + diff --git a/ext2_root/usr/include/search.h b/ext2_root/usr/include/search.h new file mode 100644 index 0000000..39174b5 --- /dev/null +++ b/ext2_root/usr/include/search.h @@ -0,0 +1,47 @@ + +#ifndef _SEARCH_H +#define _SEARCH_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + preorder, + postorder, + endorder, + leaf +} VISIT; + +#if __MLIBC_GLIBC_OPTION && defined(_GNU_SOURCE) +#include +#endif + +#ifndef __MLIBC_ABI_ONLY + +void *tsearch(const void *__key, void **__root, int(*__compar)(const void *__a, const void *__b)); +void *tfind(const void *__key, void *const *__root, int (*__compar)(const void *__a, const void *__b)); +void *tdelete(const void *__key, void **__root, int(*__compar)(const void * __a, const void *__b)); +void twalk(const void *__key, void (*__action)(const void *__node, VISIT __which, int __depth)); +void tdestroy(void *__root, void (*__free_node)(void *__node)); + +void *lsearch(const void *__key, void *__base, size_t *__nelp, size_t __width, + int (*__compar)(const void *__a, const void *__b)); +void *lfind(const void *__key, const void *__base, size_t *__nelp, + size_t __width, int (*__compar)(const void *__a, const void *__b)); + +int hcreate(size_t __num_entries); +void hdestroy(void); +ENTRY *hsearch(ENTRY __item, ACTION __action); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SEARCH_H */ diff --git a/ext2_root/usr/include/semaphore.h b/ext2_root/usr/include/semaphore.h new file mode 100644 index 0000000..8960150 --- /dev/null +++ b/ext2_root/usr/include/semaphore.h @@ -0,0 +1,37 @@ +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define SEM_VALUE_MAX 0x7FFFFFFF +#define SEM_FAILED ((sem_t *) 0) + +typedef struct sem_ { + unsigned int __mlibc_count; +} sem_t; + +#ifndef __MLIBC_ABI_ONLY + +int sem_init(sem_t *__sem, int __pshared, unsigned int __initial_count); +sem_t *sem_open(const char *__name, int __oflag, ...); +int sem_close(sem_t *__sem); +int sem_unlink(const char *__name); +int sem_destroy(sem_t *__sem); +int sem_wait(sem_t *__sem); +int sem_trywait(sem_t *__sem); +int sem_timedwait(sem_t *__sem, const struct timespec *__abstime); +int sem_post(sem_t *__sem); +int sem_getvalue(sem_t *__sem, int *__sval); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /*_SEMAPHORE_H */ diff --git a/ext2_root/usr/include/setjmp.h b/ext2_root/usr/include/setjmp.h new file mode 100644 index 0000000..1a7740e --- /dev/null +++ b/ext2_root/usr/include/setjmp.h @@ -0,0 +1,57 @@ + +#ifndef _SETJMP_H +#define _SETJMP_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* [C11/7.13] Non-local jumps */ + +typedef struct __jmp_buf { + struct __mlibc_jmpbuf_register_state __reg_state; +} jmp_buf[1]; + +#ifndef __MLIBC_ABI_ONLY + +__attribute__((__returns_twice__)) int setjmp(jmp_buf __buffer); +__attribute__((__noreturn__)) void longjmp(jmp_buf __buffer, int __value); + +/* setjmp is defined as a function macro in the ISO C standard */ +#define setjmp(env) setjmp(env) + +#if __MLIBC_POSIX_OPTION +__attribute__((__returns_twice__)) int _setjmp(jmp_buf __buffer); +/* POSIX-2017.1 says _longjmp shall be declared as a function */ +__attribute__((__noreturn__)) void _longjmp(jmp_buf __buffer, int __value); +#endif /* __MLIBC_POSIX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +/* POSIX Non-local jumps signal extensions */ + +typedef struct __sigjmp_buf { + struct __mlibc_jmpbuf_register_state __reg_state; + int __savesigs; + sigset_t __sigset; +} sigjmp_buf[1]; + +#ifndef __MLIBC_ABI_ONLY + +#if __MLIBC_POSIX_OPTION +__attribute__((__returns_twice__)) int sigsetjmp(sigjmp_buf __buffer, int __savesigs); +__attribute__((__noreturn__)) void siglongjmp(sigjmp_buf __buffer, int __value); +#endif /* __MLIBC_POSIX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SETJMP_H */ + diff --git a/ext2_root/usr/include/shadow.h b/ext2_root/usr/include/shadow.h new file mode 100644 index 0000000..6d16857 --- /dev/null +++ b/ext2_root/usr/include/shadow.h @@ -0,0 +1,43 @@ +#ifndef _SHADOW_H +#define _SHADOW_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spwd { + char *sp_namp; + char *sp_pwdp; + long sp_lstchg; + long sp_min; + long sp_max; + long sp_warn; + long sp_inact; + long sp_expire; + unsigned long sp_flag; +}; + +#define SHADOW _PATH_SHADOW + +#ifndef __MLIBC_ABI_ONLY + +int putspent(const struct spwd *__sp, FILE *__f); +int lckpwdf(void); +int ulckpwdf(void); +struct spwd *getspnam(const char *__name); +int getspnam_r(const char *__name, struct spwd *__sp, char *__buf, size_t __size, struct spwd **__res); +struct spwd *fgetspent(FILE *__f); +void endspent(void); +struct spwd *sgetspent(const char *__s); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/signal.h b/ext2_root/usr/include/signal.h new file mode 100644 index 0000000..69eee4a --- /dev/null +++ b/ext2_root/usr/include/signal.h @@ -0,0 +1,48 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* [7.14] Signal handling basics */ + +typedef int sig_atomic_t; + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +#ifndef __MLIBC_ABI_ONLY + +/* [7.14.1] signal() function */ + +__sighandler signal(int __sig, __sighandler __handler); + +/* [7.14.2] raise() function */ + +int raise(int __sig); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define _NSIG NSIG + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#if __MLIBC_GLIBC_OPTION +# include +#endif + +#endif /* _SIGNAL_H */ diff --git a/ext2_root/usr/include/spawn.h b/ext2_root/usr/include/spawn.h new file mode 100644 index 0000000..ec5d938 --- /dev/null +++ b/ext2_root/usr/include/spawn.h @@ -0,0 +1,82 @@ + +#ifndef _SPAWN_H +#define _SPAWN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int __flags; + pid_t __pgrp; + sigset_t __def, __mask; + int __prio, __pol; + void *__fn; + char __pad[64 - sizeof(void *)]; +} posix_spawnattr_t; + +typedef struct { + int __pad0[2]; + void *__actions; + int __pad[16]; +} posix_spawn_file_actions_t; + +/* MISSIG: sigset_t */ + +struct sched_param; + +#define POSIX_SPAWN_RESETIDS 1 +#define POSIX_SPAWN_SETPGROUP 2 +#define POSIX_SPAWN_SETSIGDEF 4 +#define POSIX_SPAWN_SETSIGMASK 8 +#define POSIX_SPAWN_SETSCHEDPARAM 16 +#define POSIX_SPAWN_SETSCHEDULER 32 +#define POSIX_SPAWN_USEVFORK 64 +#define POSIX_SPAWN_SETSID 128 + +#ifndef __MLIBC_ABI_ONLY + +int posix_spawn(pid_t *__restrict __pid, const char *__restrict __path, + const posix_spawn_file_actions_t *__file_actions, + const posix_spawnattr_t *__restrict __attrs, + char *const __argv[], char *const __envp[]); + +int posix_spawnattr_init(posix_spawnattr_t *__attr); +int posix_spawnattr_destroy(posix_spawnattr_t *__attr); +int posix_spawnattr_setflags(posix_spawnattr_t *__attr, short __flags); +int posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict __attr, + const sigset_t *__restrict __sigdefault); +int posix_spawnattr_setschedparam(posix_spawnattr_t *__restrict __attr, + const struct sched_param *__restrict __schedparam); +int posix_spawnattr_setschedpolicy(posix_spawnattr_t *__attr, int __schedpolicy); +int posix_spawnattr_setsigmask(posix_spawnattr_t *__restrict __attr, + const sigset_t *__restrict __sigmask); +int posix_spawnattr_setpgroup(posix_spawnattr_t *__attr, pid_t __pgroup); +int posix_spawn_file_actions_init(posix_spawn_file_actions_t *__file_actions); +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *__file_actions); +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *__file_actions, + int __fildes, int __newfildes); +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *__file_actions, + int __fildes); +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *__restrict __file_actions, + int __fildes, const char *__restrict __path, int __oflag, mode_t __mode); +int posix_spawnp(pid_t *__restrict __pid, const char *__restrict __file, + const posix_spawn_file_actions_t *__file_actions, + const posix_spawnattr_t *__restrict __attrp, + char *const __argv[], char *const __envp[]); + +/* MISSING: all other functions */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* SPAWN_H */ + diff --git a/ext2_root/usr/include/stdc-predef.h b/ext2_root/usr/include/stdc-predef.h new file mode 100644 index 0000000..a0e3e92 --- /dev/null +++ b/ext2_root/usr/include/stdc-predef.h @@ -0,0 +1,6 @@ +#ifndef _STDC_PREDEF_H +#define _STDC_PREDEF_H + +#define __STDC_ISO_10646__ 201206L + +#endif /* _STDC_PREDEF_H */ diff --git a/ext2_root/usr/include/stdint.h b/ext2_root/usr/include/stdint.h new file mode 100644 index 0000000..36ec413 --- /dev/null +++ b/ext2_root/usr/include/stdint.h @@ -0,0 +1,150 @@ +#ifndef _MLIBC_STDINT_H +#define _MLIBC_STDINT_H + +#include +#include + +/* ---------------------------------------------------------------------------- */ +/* Type definitions. */ +/* ---------------------------------------------------------------------------- */ + +/* Fixed-width (signed). */ +typedef __mlibc_int8 int8_t; +typedef __mlibc_int16 int16_t; +typedef __mlibc_int32 int32_t; +typedef __mlibc_int64 int64_t; + +/* Fixed-width (unsigned). */ +typedef __mlibc_uint8 uint8_t; +typedef __mlibc_uint16 uint16_t; +typedef __mlibc_uint32 uint32_t; +typedef __mlibc_uint64 uint64_t; + +/* Least-width (signed). */ +typedef __mlibc_int8 int_least8_t; +typedef __mlibc_int16 int_least16_t; +typedef __mlibc_int32 int_least32_t; +typedef __mlibc_int64 int_least64_t; + +/* Least-width (unsigned). */ +typedef __mlibc_uint8 uint_least8_t; +typedef __mlibc_uint16 uint_least16_t; +typedef __mlibc_uint32 uint_least32_t; +typedef __mlibc_uint64 uint_least64_t; + +/* Fast-width (signed). */ +typedef __mlibc_int_fast8 int_fast8_t; +typedef __mlibc_int_fast16 int_fast16_t; +typedef __mlibc_int_fast32 int_fast32_t; +typedef __mlibc_int_fast64 int_fast64_t; + +/* Fast-width (unsigned). */ +typedef __mlibc_uint_fast8 uint_fast8_t; +typedef __mlibc_uint_fast16 uint_fast16_t; +typedef __mlibc_uint_fast32 uint_fast32_t; +typedef __mlibc_uint_fast64 uint_fast64_t; + +/* Miscellaneous (signed). */ +typedef __mlibc_intmax intmax_t; +typedef __mlibc_intptr intptr_t; + +/* Miscellaneous (unsigned). */ +typedef __mlibc_uintmax uintmax_t; +typedef __mlibc_uintptr uintptr_t; + +/* ---------------------------------------------------------------------------- */ +/* Constants. */ +/* ---------------------------------------------------------------------------- */ + +/* Fixed-width (signed). */ +#define INT8_C(x) __MLIBC_INT8_C(x) +#define INT16_C(x) __MLIBC_INT16_C(x) +#define INT32_C(x) __MLIBC_INT32_C(x) +#define INT64_C(x) __MLIBC_INT64_C(x) +#define INTMAX_C(x) __MLIBC_INTMAX_C(x) + +/* Fixed-width (unsigned). */ +#define UINT8_C(x) __MLIBC_UINT8_C(x) +#define UINT16_C(x) __MLIBC_UINT16_C(x) +#define UINT32_C(x) __MLIBC_UINT32_C(x) +#define UINT64_C(x) __MLIBC_UINT64_C(x) +#define UINTMAX_C(x) __MLIBC_UINTMAX_C(x) + +/* ---------------------------------------------------------------------------- */ +/* Limits. */ +/* ---------------------------------------------------------------------------- */ + +/* Fixed-width (signed). */ +#define INT8_MAX __MLIBC_INT8_MAX +#define INT16_MAX __MLIBC_INT16_MAX +#define INT32_MAX __MLIBC_INT32_MAX +#define INT64_MAX __MLIBC_INT64_MAX + +#define INT8_MIN __MLIBC_INT8_MIN +#define INT16_MIN __MLIBC_INT16_MIN +#define INT32_MIN __MLIBC_INT32_MIN +#define INT64_MIN __MLIBC_INT64_MIN + +/* Fixed-width (unsigned). */ +#define UINT8_MAX __MLIBC_UINT8_MAX +#define UINT16_MAX __MLIBC_UINT16_MAX +#define UINT32_MAX __MLIBC_UINT32_MAX +#define UINT64_MAX __MLIBC_UINT64_MAX + +/* Least-width (signed). */ +#define INT_LEAST8_MAX __MLIBC_INT8_MAX +#define INT_LEAST16_MAX __MLIBC_INT16_MAX +#define INT_LEAST32_MAX __MLIBC_INT32_MAX +#define INT_LEAST64_MAX __MLIBC_INT64_MAX + +#define INT_LEAST8_MIN __MLIBC_INT8_MIN +#define INT_LEAST16_MIN __MLIBC_INT16_MIN +#define INT_LEAST32_MIN __MLIBC_INT32_MIN +#define INT_LEAST64_MIN __MLIBC_INT64_MIN + +/* Least-width (unsigned). */ +#define UINT_LEAST8_MAX __MLIBC_UINT8_MAX +#define UINT_LEAST16_MAX __MLIBC_UINT16_MAX +#define UINT_LEAST32_MAX __MLIBC_UINT32_MAX +#define UINT_LEAST64_MAX __MLIBC_UINT64_MAX + +/* Fast-width (signed). */ +#define INT_FAST8_MAX __MLIBC_INT_FAST8_MAX +#define INT_FAST16_MAX __MLIBC_INT_FAST16_MAX +#define INT_FAST32_MAX __MLIBC_INT_FAST32_MAX +#define INT_FAST64_MAX __MLIBC_INT_FAST64_MAX + +#define INT_FAST8_MIN __MLIBC_INT_FAST8_MIN +#define INT_FAST16_MIN __MLIBC_INT_FAST16_MIN +#define INT_FAST32_MIN __MLIBC_INT_FAST32_MIN +#define INT_FAST64_MIN __MLIBC_INT_FAST64_MIN + +/* Fast-width (unsigned). */ +#define UINT_FAST8_MAX __MLIBC_UINT_FAST8_MAX +#define UINT_FAST16_MAX __MLIBC_UINT_FAST16_MAX +#define UINT_FAST32_MAX __MLIBC_UINT_FAST32_MAX +#define UINT_FAST64_MAX __MLIBC_UINT_FAST64_MAX + +/* Miscellaneous (signed). */ +#define INTMAX_MAX __MLIBC_INTMAX_MAX +#define INTPTR_MAX __MLIBC_INTPTR_MAX + +#define INTMAX_MIN __MLIBC_INTMAX_MIN +#define INTPTR_MIN __MLIBC_INTPTR_MIN + +/* Miscellaneous (unsigned). */ +#define UINTMAX_MAX __MLIBC_UINTMAX_MAX +#define UINTPTR_MAX __MLIBC_UINTPTR_MAX + +/* Other limits (signed). */ +#define PTRDIFF_MAX __MLIBC_PTRDIFF_MAX +#define PTRDIFF_MIN __MLIBC_PTRDIFF_MIN +#define SIG_ATOMIC_MAX __MLIBC_SIG_ATOMIC_MAX +#define SIG_ATOMIC_MIN __MLIBC_SIG_ATOMIC_MIN +#define WINT_MAX __MLIBC_WINT_MAX +#define WINT_MIN __MLIBC_WINT_MIN + +/* Other limits (unsigned). */ +#define SIZE_MAX __MLIBC_SIZE_MAX + +#endif /* _MLIBC_STDINT_H */ diff --git a/ext2_root/usr/include/stdio.h b/ext2_root/usr/include/stdio.h new file mode 100644 index 0000000..8b6de9f --- /dev/null +++ b/ext2_root/usr/include/stdio.h @@ -0,0 +1,231 @@ + +#ifndef _STDIO_H +#define _STDIO_H + +#include +#include +#include +#include +#include + +/* Glibc extensions require ssize_t. */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* [C11-7.21.1] I/O related types */ + +#define __MLIBC_EOF_BIT 1 +#define __MLIBC_ERROR_BIT 2 + +struct __mlibc_file_base { + /* Buffer for I/O operations. */ + /* We reserve a few extra bytes for ungetc operations. This means */ + /* that __buffer_ptr will point a few bytes *into* the allocation. */ + char *__buffer_ptr; + + /* Number of bytes the buffer can hold. */ + size_t __buffer_size; + + /* Current offset inside the buffer. */ + size_t __offset; + + /* Position inside the buffer that matches the current file pointer. */ + size_t __io_offset; + + /* Valid region of the buffer. */ + size_t __valid_limit; + + /* Begin and end of the dirty region inside the buffer. */ + size_t __dirty_begin; + size_t __dirty_end; + + /* This points to the same place as __buffer_ptr, or a few bytes earlier */ + /* if there are bytes pushed by ungetc. If buffering is disabled, calls */ + /* to ungetc will trigger an allocation. */ + char *__unget_ptr; + + /* 0 if we are currently reading from the buffer. */ + /* 1 if we are currently writing to the buffer. */ + /* This is only really important for pipe-like streams. */ + int __io_mode; + + /* EOF and error bits. */ + int __status_bits; +}; + +typedef off_t fpos_t; + +/* [C11-7.21.1] I/O related macros */ + +#define _IOFBF 1 +#define _IOLBF 2 +#define _IONBF 3 + +#define BUFSIZ 512 + +#define EOF (-1) + +#define FOPEN_MAX 1024 +#define FILENAME_MAX 256 +#define L_tmpnam 256 + +#define TMP_MAX 1024 + +#ifndef __MLIBC_ABI_ONLY + +extern FILE *stderr; +extern FILE *stdin; +extern FILE *stdout; + +/* [C11-7.21.4] Operations on files */ + +int remove(const char *__filename); +int rename(const char *__old_path, const char *__new_path); +int renameat(int __olddirfd, const char *__old_path, int __newdirfd, const char *__new_path); +FILE *tmpfile(void); +char *tmpnam(char *__buffer); + +/* [C11-7.21.5] File access functions */ + +int fclose(FILE *__stream); +int fflush(FILE *__stream); +FILE *fopen(const char *__restrict __filename, const char *__restrict __mode); +FILE *freopen(const char *__restrict __filename, const char *__restrict __mode, FILE *__restrict __stream); +void setbuf(FILE *__restrict __stream, char *__restrict __buffer); +int setvbuf(FILE *__restrict __stream, char *__restrict __buffer, int __mode, size_t __size); +void setlinebuf(FILE *__stream); +void setbuffer(FILE *__stream, char *__buffer, size_t __size); + +/* [C11-7.21.6] Formatted input/output functions */ + +__attribute__((__format__(__printf__, 2, 3))) +int fprintf(FILE *__restrict __stream, const char *__restrict __format, ...); + +__attribute__((__format__(__scanf__, 2, 3))) +int fscanf(FILE *__restrict __stream, const char *__restrict __format, ...); + +__attribute__((__format__(__printf__, 1, 2))) +int printf(const char *__restrict __format, ...); + +__attribute__((__format__(__scanf__, 1, 2))) +int scanf(const char *__restrict __format, ...); + +__attribute__((__format__(__printf__, 3, 4))) +int snprintf(char *__restrict __buffer, size_t __max_size, const char *__restrict __format, ...); + +__attribute__((__format__(__printf__, 2, 3))) +int sprintf(char *__restrict __buffer, const char *__restrict __format, ...); + +__attribute__((__format__(__scanf__, 2, 3))) +int sscanf(const char *__restrict __buffer, const char *__restrict __format, ...); + +__attribute__((__format__(__printf__, 2, 0))) +int vfprintf(FILE *__restrict __stream, const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__scanf__, 2, 0))) +int vfscanf(FILE *__restrict __stream, const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__printf__, 1, 0))) +int vprintf(const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__scanf__, 1, 0))) +int vscanf(const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__printf__, 3, 0))) +int vsnprintf(char *__restrict __buffer, size_t __max_size, + const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__printf__, 2, 0))) +int vsprintf(char *__restrict __buffer, const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__scanf__, 2, 0))) +int vsscanf(const char *__restrict __buffer, const char *__restrict __format, __builtin_va_list __args); + +/* this is a gnu extension */ +__attribute__((__format__(__printf__, 2, 0))) +int vasprintf(char **__buffer, const char *__format, __builtin_va_list __args); + +/* [C11-7.21.7] Character input/output functions */ + +int fgetc(FILE *__stream); +char *fgets(char *__restrict __buffer, int __max_size, FILE *__restrict __stream); +int fputc(int __c, FILE *__stream); +int fputs(const char *__restrict __string, FILE *__restrict __stream); +char *gets(char *__s); +int getc(FILE *__stream); +int getchar(void); +int putc(int __c, FILE *__stream); +int putchar(int __c); +int puts(const char *__string); +int ungetc(int __c, FILE *__stream); + +/* [C11-7.21.8] Direct input/output functions */ + +size_t fread(void *__restrict __buffer, size_t __size, size_t __count, FILE *__restrict __stream); +size_t fwrite(const void *__restrict __buffer, size_t __size, size_t __count, FILE *__restrict __stream); + +/* [C11-7.21.9] File positioning functions */ + +int fgetpos(FILE *__restrict __stream, fpos_t *__restrict __position); +int fseek(FILE *__stream, long __offset, int __whence); +int fsetpos(FILE *__stream, const fpos_t *__position); +long ftell(FILE *__stream); +void rewind(FILE *__stream); + +/* [C11-7.21.10] Error handling functions */ + +void clearerr(FILE *__stream); +int feof(FILE *__stream); +int ferror(FILE *__stream); +void perror(const char *__string); + +/* POSIX unlocked I/O extensions. */ + +int getc_unlocked(FILE *__stream); +int getchar_unlocked(void); +int putc_unlocked(int __c, FILE *__stream); +int putchar_unlocked(int __c); + +/* GLIBC extensions. */ + +ssize_t getline(char **__linep, size_t *__sizep, FILE *__stream); +ssize_t getdelim(char **__linep, size_t *__sizep, int __delim, FILE *__stream); + +__attribute__((__format__(__printf__, 2, 3))) +int asprintf(char **__buffer, const char *__format, ...); + +/* Linux unlocked I/O extensions. */ + +void flockfile(FILE *__stream); +void funlockfile(FILE *__stream); +int ftrylockfile(FILE *__stream); + +void clearerr_unlocked(FILE *__stream); +int feof_unlocked(FILE *__stream); +int ferror_unlocked(FILE *__stream); +int fileno_unlocked(FILE *__stream); +int fflush_unlocked(FILE *__stream); +int fgetc_unlocked(FILE *__stream); +int fputc_unlocked(int __c, FILE *__stream); +size_t fread_unlocked(void *__restrict __buffer, size_t __size, size_t __count, FILE *__restrict __stream); +size_t fwrite_unlocked(const void *__restrict __buffer, size_t __size, size_t __count, FILE *__restrict __stream); + +char *fgets_unlocked(char *__restrict __buffer, int __size, FILE *__restrict __stream); +int fputs_unlocked(const char *__restrict __buffer, FILE *__restrict __stream); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif /* _STDIO_H */ + diff --git a/ext2_root/usr/include/stdio_ext.h b/ext2_root/usr/include/stdio_ext.h new file mode 100644 index 0000000..867c07a --- /dev/null +++ b/ext2_root/usr/include/stdio_ext.h @@ -0,0 +1,42 @@ +#ifndef _STDIO_EXT_H +#define _STDIO_EXT_H + +#include +#include + +#define FSETLOCKING_INTERNAL 1 +#define FSETLOCKING_BYCALLER 2 +#define FSETLOCKING_QUERY 3 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +size_t __fbufsize(FILE *__stream); +size_t __fpending(FILE *__stream); +int __flbf(FILE *__stream); +int __freadable(FILE *__stream); +int __fwritable(FILE *__stream); +int __freading(FILE *__stream); +int __fwriting(FILE *__stream); +int __fsetlocking(FILE *__stream, int __type); +void __fpurge(FILE *__stream); + +void _flushlbf(void); + +/* The following functions are defined by musl. */ + +size_t __freadahead(FILE *__stream); +const char *__freadptr(FILE *__stream, size_t *__size); +void __freadptrinc(FILE *, size_t); +void __fseterr(FILE *__stream); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _STDIO_EXT_H */ diff --git a/ext2_root/usr/include/stdlib.h b/ext2_root/usr/include/stdlib.h new file mode 100644 index 0000000..9df8b08 --- /dev/null +++ b/ext2_root/usr/include/stdlib.h @@ -0,0 +1,131 @@ +#ifndef _STDLIB_H +#define _STDLIB_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* [7.22] General utilities */ + +typedef struct { + int quot, rem; +} div_t; + +typedef struct { + long quot, rem; +} ldiv_t; + +typedef struct { + long long quot, rem; +} lldiv_t; + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#define RAND_MAX 0x7FFFFFFF + +/* TODO: this should not be a compile-time constant */ +#define MB_CUR_MAX ((size_t)4) + +#ifndef __MLIBC_ABI_ONLY + +/* [7.22.1] Numeric conversion functions */ + +double atof(const char *__string); +int atoi(const char *__string); +long atol(const char *__string); +long long atoll(const char *__string); +double strtod(const char *__restrict __string, char **__restrict __end); +float strtof(const char *__restrict __string, char **__restrict __end); +long double strtold(const char *__restrict __string, char **__restrict __end); +long strtol(const char *__restrict __string, char **__restrict __end, int __base); +long long strtoll(const char *__restrict __string, char **__restrict __end, int __base); +unsigned long strtoul(const char *__restrict __string, char **__restrict __end, int __base); +unsigned long long strtoull(const char *__restrict __string, char **__restrict __end, int __base); + +/* [7.22.2] Pseudo-random sequence generation functions */ + +int rand(void); +int rand_r(unsigned *__seed); +void srand(unsigned int __seed); + +/* [7.22.3] Memory management functions */ + +void *aligned_alloc(size_t __alignment, size_t __size); +void *calloc(size_t __count, size_t __size); +void free(void *__pointer); +void *malloc(size_t __size); +void *realloc(void *__pointer, size_t __size); + +int posix_memalign(void **__out, size_t __alignment, size_t __size); + +/* [7.22.4] Communication with the environment */ + +__attribute__((__noreturn__)) void abort(void); +int atexit(void (*__func)(void)); +int at_quick_exit(void (*__func)(void)); +__attribute__((__noreturn__)) void exit(int __status); +__attribute__((__noreturn__)) void _Exit(int __status); +char *getenv(const char *__name); +__attribute__((__noreturn__)) void quick_exit(int __status); +int system(const char *__string); + +/* GLIBC extension. */ +char *mktemp(char *__pattern); + +/* [7.22.5] Searching and sorting utilities */ + +void *bsearch(const void *__key, const void *__base, size_t __count, size_t __size, + int (*__compare)(const void *__a, const void *__b)); +void qsort(void *__base, size_t __count, size_t __size, + int (*__compare)(const void *__a, const void *__b)); +void qsort_r(void *__base, size_t __nmemb, size_t __size, + int (*__compar)(const void *__a, const void *__b, void *__arg), + void *__arg); + +/* [7.22.6] Integer arithmetic functions */ + +int abs(int __number); +long labs(long __number); +long long llabs(long long __number); + +div_t div(int __number, int __denom); +ldiv_t ldiv(long __number, long __denom); +lldiv_t lldiv(long long __number, long long __denom); + +/* [7.22.7] Multibyte character conversion functions */ + +int mblen(const char *__mbs, size_t __limit); +int mbtowc(wchar_t *__restrict __wc, const char *__restrict __mb_chr, size_t __max_size); +int wctomb(char *__mb_chr, wchar_t __wc); + +/* [7.22.8] Multibyte string conversion functions */ + +size_t mbstowcs(wchar_t *__restrict __wc_string, const char *__restrict __mb_string, size_t __max_size); +size_t wcstombs(char *__restrict __mb_string, const wchar_t *__restrict __wc_string, size_t __max_size); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_BSD_OPTION +# include +#endif +#if __MLIBC_POSIX_OPTION +# include +#endif +#if __MLIBC_GLIBC_OPTION +# include +#endif + +#endif /* _STDLIB_H */ + diff --git a/ext2_root/usr/include/string.h b/ext2_root/usr/include/string.h new file mode 100644 index 0000000..cad9dc4 --- /dev/null +++ b/ext2_root/usr/include/string.h @@ -0,0 +1,112 @@ +#ifndef _STRING_H +#define _STRING_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* [7.24.2] Copying functions */ + +void *memcpy(void *__restrict __dest, const void *__restrict __src, size_t __size); +void *memmove(void *__dest, const void *__src, size_t __size); +char *strcpy(char *__restrict __dest, const char *src); +char *strncpy(char *__restrict __dest, const char *__src, size_t __max_size); + +/* [7.24.3] Concatenation functions */ + +char *strcat(char *__restrict __dest, const char *__restrict __src); +char *strncat(char *__restrict __dest, const char *__restrict __src, size_t __max_size); + +/* [7.24.4] Comparison functions */ + +int memcmp(const void *__a, const void *__b, size_t __size); +int strcmp(const char *__a, const char *__b); +int strcoll(const char *__a, const char *__b); +int strncmp(const char *__a, const char *__b, size_t __max_size); +size_t strxfrm(char *__restrict __dest, const char *__restrict __src, size_t __max_size); + +/* [7.24.5] Search functions */ + +void *memchr(const void *__s, int __c, size_t __size); +char *strchr(const char *__s, int __c); +size_t strcspn(const char *__s, const char *__chrs); +char *strpbrk(const char *__s, const char *__chrs); +char *strrchr(const char *__s, int __c); +size_t strspn(const char *__s, const char *__chrs); +char *strstr(const char *__pattern, const char *__s); +char *strtok(char *__restrict __s, const char *__restrict __delimiter); + +/* This is a GNU extension. */ +char *strchrnul(const char * __s, int __c); + +/* [7.24.6] Miscellaneous functions */ + +void *memset(void *__dest, int __c, size_t __size); +char *strerror(int __errnum); +size_t strlen(const char *__s); + +#endif /* !__MLIBC_ABI_ONLY */ + +#if __MLIBC_POSIX_OPTION && defined(_DEFAULT_SOURCE) +#include +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* POSIX extensions. */ +#if defined(_GNU_SOURCE) +char *strerror_r(int __errnum, char *__buffer, size_t __size) __asm__("__gnu_strerror_r"); +#else +int strerror_r(int __errnum, char *__buffer, size_t __size); +#endif + +void *mempcpy(void *__dest, const void *__src, size_t __size); + +/* GNU extensions. */ +int strverscmp(const char *__l0, const char *__r0); +int ffsl(long __i); +int ffsll(long long __i); +void *memmem(const void *__haystack, size_t __haystacklen, const void *__needle, size_t __needlelen); + +/* Handling the basename mess: + * If is included *at all*, we use the XPG-defined basename + * implementation, otherwise, we use the GNU one. Since our ABI previously + * provided the XPG one under basename, we'll have to diverge from GNU here and + * provide __mlibc_gnu_basename instead. + */ +#if __MLIBC_GLIBC_OPTION && defined(_GNU_SOURCE) && !defined(basename) +char *__mlibc_gnu_basename_c(const char *__path); + +# ifdef __cplusplus +extern "C++" { +static inline const char *__mlibc_gnu_basename(const char *__path) { + return __mlibc_gnu_basename_c(__path); +} +static inline char *__mlibc_gnu_basename(char *__path) { + return __mlibc_gnu_basename_c(__path); +} +} +# else +# define __mlibc_gnu_basename __mlibc_gnu_basename_c +# endif + +#define basename __mlibc_gnu_basename +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif /* _STRING_H */ diff --git a/ext2_root/usr/include/strings.h b/ext2_root/usr/include/strings.h new file mode 100644 index 0000000..1a49114 --- /dev/null +++ b/ext2_root/usr/include/strings.h @@ -0,0 +1,33 @@ + +#ifndef _STRINGS_H +#define _STRINGS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *index (const char *__s, int __c); +char *rindex(const char *__s, int __c); + +int ffs(int __word); +int strcasecmp(const char *__a, const char *__b); +int strncasecmp(const char *__a, const char *__b, size_t __size); + +/* Marked as obsolete in posix 2008 but used by at least tracker */ +int bcmp(const void *__s1, const void *__s2, size_t __n); +void bcopy(const void *__s1, void *__s2, size_t __n); +void bzero(void *__s, size_t __n); +void explicit_bzero(void *__s, size_t __len); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _STRINGS_H */ + diff --git a/ext2_root/usr/include/sys/auxv.h b/ext2_root/usr/include/sys/auxv.h new file mode 100644 index 0000000..2e8598c --- /dev/null +++ b/ext2_root/usr/include/sys/auxv.h @@ -0,0 +1,25 @@ +#ifndef _SYS_AUXV_H +#define _SYS_AUXV_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* mlibc extension: Like getauxval but handles errors in a sane way. */ +/* Success: Return 0. */ +/* Failure: Return -1 and set errno. */ +int peekauxval(unsigned long __type, unsigned long *__value); + +unsigned long getauxval(unsigned long __type); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ext2_root/usr/include/sys/cachectl.h b/ext2_root/usr/include/sys/cachectl.h new file mode 100644 index 0000000..f6b2d8c --- /dev/null +++ b/ext2_root/usr/include/sys/cachectl.h @@ -0,0 +1,16 @@ +#ifndef _SYS_CACHECTL_H +#define _SYS_CACHECTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __riscv +int __riscv_flush_icache(void *, void *, unsigned long); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/sys/dir.h b/ext2_root/usr/include/sys/dir.h new file mode 100644 index 0000000..eff112c --- /dev/null +++ b/ext2_root/usr/include/sys/dir.h @@ -0,0 +1,8 @@ +#ifndef _SYS_DIR_H +#define _SYS_DIR_H + +#include + +#define direct dirent + +#endif diff --git a/ext2_root/usr/include/sys/endian.h b/ext2_root/usr/include/sys/endian.h new file mode 100644 index 0000000..e69de29 diff --git a/ext2_root/usr/include/sys/errno.h b/ext2_root/usr/include/sys/errno.h new file mode 100644 index 0000000..339f4fc --- /dev/null +++ b/ext2_root/usr/include/sys/errno.h @@ -0,0 +1 @@ +#include diff --git a/ext2_root/usr/include/sys/fcntl.h b/ext2_root/usr/include/sys/fcntl.h new file mode 100644 index 0000000..cd30455 --- /dev/null +++ b/ext2_root/usr/include/sys/fcntl.h @@ -0,0 +1 @@ +#include diff --git a/ext2_root/usr/include/sys/file.h b/ext2_root/usr/include/sys/file.h new file mode 100644 index 0000000..11dff16 --- /dev/null +++ b/ext2_root/usr/include/sys/file.h @@ -0,0 +1,26 @@ + +#ifndef _SYS_FILE_H +#define _SYS_FILE_H + +#define LOCK_SH 1 +#define LOCK_EX 2 +#define LOCK_NB 4 +#define LOCK_UN 8 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int flock(int __fd, int __op); +int flock64(int __fd, int __op); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_FILE_H */ + diff --git a/ext2_root/usr/include/sys/io.h b/ext2_root/usr/include/sys/io.h new file mode 100644 index 0000000..1ee22f2 --- /dev/null +++ b/ext2_root/usr/include/sys/io.h @@ -0,0 +1,108 @@ +#ifndef _SYS_IO_H +#define _SYS_IO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int ioperm(unsigned long int __from, unsigned long int __num, int __turn_on); + +__attribute__((deprecated)) int iopl(int __level); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __x86_64__ +__MLIBC_INLINE_DEFINITION unsigned char inb(unsigned short int __port) { + unsigned char __value; + __asm__ __volatile__ ("inb %w1,%0":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned char inb_p(unsigned short int __port) { + unsigned char __value; + __asm__ __volatile__ ("inb %w1,%0\noutb %%al,$0x80":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned short int inw(unsigned short int __port) { + unsigned short __value; + __asm__ __volatile__ ("inw %w1,%0":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned short int inw_p(unsigned short int __port) { + unsigned short int __value; + __asm__ __volatile__ ("inw %w1,%0\noutb %%al,$0x80":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned int inl(unsigned short int __port) { + unsigned int __value; + __asm__ __volatile__ ("inl %w1,%0":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned int inl_p(unsigned short int __port) { + unsigned int __value; + __asm__ __volatile__ ("inl %w1,%0\noutb %%al,$0x80":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION void outb(unsigned char value, unsigned short int __port) { + __asm__ __volatile__ ("outb %b0,%w1": :"a" (value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outb_p(unsigned char __value, unsigned short int __port) { + __asm__ __volatile__ ("outb %b0,%w1\noutb %%al,$0x80": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outw(unsigned short int __value, unsigned short int __port) { + __asm__ __volatile__ ("outw %w0,%w1": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outw_p(unsigned short int __value, unsigned short int __port) { + __asm__ __volatile__ ("outw %w0,%w1\noutb %%al,$0x80": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outl(unsigned int __value, unsigned short int __port) { + __asm__ __volatile__ ("outl %0,%w1": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outl_p(unsigned int __value, unsigned short int __port) { + __asm__ __volatile__ ("outl %0,%w1\noutb %%al,$0x80": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void insb(unsigned short int __port, void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; insb":"=D" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void insw(unsigned short int __port, void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; insw":"=D" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void insl(unsigned short int __port, void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; insl":"=D" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void outsb(unsigned short int __port, const void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; outsb":"=S" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void outsw(unsigned short int __port, const void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; outsw":"=S" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void outsl(unsigned short int __port, const void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; outsl":"=S" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_IO_H */ diff --git a/ext2_root/usr/include/sys/ioctl.h b/ext2_root/usr/include/sys/ioctl.h new file mode 100644 index 0000000..f9707b8 --- /dev/null +++ b/ext2_root/usr/include/sys/ioctl.h @@ -0,0 +1,48 @@ +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +#include +#include + +/* On Linux, sys/ioctl.h includes the termios ioctls. */ +#if __MLIBC_LINUX_OPTION +# include +# include +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int ioctl(int __fd, unsigned long __request, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 + +#define FIONREAD 0x541B +#define FIONBIO 0x5421 +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 + +#define SIOCGIFNAME 0x8910 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFMTU 0x8921 +#define SIOCSIFMTU 0x8922 +#define SIOCGIFINDEX 0x8933 + +#define SIOCPROTOPRIVATE 0x89E0 +#define SIOCDEVPRIVATE 0x89F0 + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_IOCTL_H */ diff --git a/ext2_root/usr/include/sys/ipc.h b/ext2_root/usr/include/sys/ipc.h new file mode 100644 index 0000000..d6cd429 --- /dev/null +++ b/ext2_root/usr/include/sys/ipc.h @@ -0,0 +1,20 @@ +#ifndef _SYS_IPC_H +#define _SYS_IPC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +key_t ftok(const char *__path, int __proj_id); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/sys/kd.h b/ext2_root/usr/include/sys/kd.h new file mode 100644 index 0000000..285c694 --- /dev/null +++ b/ext2_root/usr/include/sys/kd.h @@ -0,0 +1,17 @@ +#ifndef _SYS_KD_H +#define _SYS_KD_H + +/* Make sure the header is not loaded. */ +#ifndef _LINUX_TYPES_H +# define _LINUX_TYPES_H 1 +# define __undef_LINUX_TYPES_H +#endif + +#include + +#ifdef __undef_LINUX_TYPES_H +# undef _LINUX_TYPES_H +# undef __undef_LINUX_TYPES_H +#endif + +#endif /* _SYS_KD_H */ diff --git a/ext2_root/usr/include/sys/mman.h b/ext2_root/usr/include/sys/mman.h new file mode 100644 index 0000000..3d17b30 --- /dev/null +++ b/ext2_root/usr/include/sys/mman.h @@ -0,0 +1,46 @@ +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +void *mmap(void *__addr, size_t __size, int __prot, int __flags, int __fd, off_t __offset); +void *mmap64(void *__addr, size_t __size, int __prot, int __flags, int __fd, off64_t __offset); +int mprotect(void *__addr, size_t __size, int __prot); +int munmap(void *__addr, size_t __size); + +int mlock(const void *__addr, size_t __size); +int mlockall(int __flags); +int munlock(const void *__addr, size_t __size); +int munlockall(void); + +int posix_madvise(void *__addr, size_t __size, int __advise); +int msync(void *__addr, size_t __size, int __flags); + +int shm_open(const char *__name, int __oflag, mode_t __mode); +int shm_unlink(const char *__name); + +#if __MLIBC_LINUX_OPTION +void *mremap(void *__old_address, size_t __old_size, size_t __new_size, int __flags, ...); +int remap_file_pages(void *__addr, size_t __size, int __prot, size_t __pgoff, int __flags); +int memfd_create(const char *__name, unsigned int __flags); +int madvise(void *__addr, size_t __size, int __advise); +int mincore(void *__addr, size_t __size, unsigned char *__vec); +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MMAN_H */ diff --git a/ext2_root/usr/include/sys/msg.h b/ext2_root/usr/include/sys/msg.h new file mode 100644 index 0000000..f62220a --- /dev/null +++ b/ext2_root/usr/include/sys/msg.h @@ -0,0 +1,27 @@ +#ifndef _SYS_MSG_H +#define _SYS_MSG_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int msgget(key_t __key, int __msgflg); + +int msgctl(int __msqid, int __cmd, struct msqid_ds *__buf); + +ssize_t msgrcv(int __msqid, void *__msgp, size_t __size, long __msgtyp, int __msgflg); +int msgsnd(int __msqid, const void *__msgp, size_t __size, int __msgflg); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MSG_H */ diff --git a/ext2_root/usr/include/sys/mtio.h b/ext2_root/usr/include/sys/mtio.h new file mode 100644 index 0000000..2ee4873 --- /dev/null +++ b/ext2_root/usr/include/sys/mtio.h @@ -0,0 +1,102 @@ +#ifndef _SYS_MTIO_H +#define _SYS_MTIO_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct mtop { + short int mt_op; + int mt_count; +}; + +struct mtget { + long int mt_type; + long int mt_resid; + long int mt_dsreg; + long int mt_gstat; + long int mt_erreg; + int mt_fileno; + int mt_blkno; +}; + +struct mtpos { + long int mt_blkno; +}; + +struct mtconfiginfo { + long int mt_type; + long int ifc_type; + unsigned short int irqnr; + unsigned short int dmanr; + unsigned short int port; + + unsigned long int debug; + + unsigned have_dens:1; + unsigned have_bsf:1; + unsigned have_fsr:1; + unsigned have_bsr:1; + unsigned have_eod:1; + unsigned have_seek:1; + unsigned have_tell:1; + unsigned have_ras1:1; + unsigned have_ras2:1; + unsigned have_ras3:1; + unsigned have_qfa:1; + + unsigned pad1:5; + char reserved[10]; +}; + +#define MTRESET 0 +#define MTFSF 1 +#define MTBSF 2 +#define MTFSR 3 +#define MTBSR 4 +#define MTWEOF 5 +#define MTREW 6 +#define MTOFFL 7 +#define MTNOP 8 +#define MTRETEN 9 +#define MTBSFM 10 +#define MTFSFM 11 +#define MTEOM 12 +#define MTERASE 13 +#define MTRAS1 14 +#define MTRAS2 15 +#define MTRAS3 16 +#define MTSETBLK 20 +#define MTSETDENSITY 21 +#define MTSEEK 22 +#define MTTELL 23 +#define MTSETDRVBUFFER 24 +#define MTFSS 25 +#define MTBSS 26 +#define MTWSM 27 +#define MTLOCK 28 +#define MTUNLOCK 29 +#define MTLOAD 30 +#define MTUNLOAD 31 +#define MTCOMPRESSION 32 +#define MTSETPART 33 +#define MTMKPART 34 + +#define GMT_WR_PROT(x) ((x) & 0x04000000) + +#if __MLIBC_LINUX_OPTION +#define MTIOCTOP _IOR('m', 1, struct mtop) +#define MTIOCGET _IOR('m', 2, struct mtget) +#define MTIOCPOS _IOR('m', 3, struct mtpos) +#define MTIOCGETCONFIG _IOR('m', 4, struct mtconfiginfo) +#define MTIOCSETCONFIG _IOR('m', 5, struct mtconfiginfo) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MTIO_H */ diff --git a/ext2_root/usr/include/sys/param.h b/ext2_root/usr/include/sys/param.h new file mode 100644 index 0000000..b2c7d71 --- /dev/null +++ b/ext2_root/usr/include/sys/param.h @@ -0,0 +1,35 @@ + +#ifndef _SYS_PARAM_H +#define _SYS_PARAM_H + +#include +#include + +#define NBBY CHAR_BIT +#define NGROUPS NGROUPS_MAX + +/* Report the same value as Linux here. */ +#define MAXNAMLEN 255 +#define MAXPATHLEN 4096 +#define MAXSYMLINKS 20 +#define MAXHOSTNAMELEN HOST_NAME_MAX + +#ifdef __cplusplus +extern "C" { +#endif + +#undef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#undef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define howmany(x, y) (((x) + ((y) - 1)) / (y)) + +#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PARAM_H */ + diff --git a/ext2_root/usr/include/sys/personality.h b/ext2_root/usr/include/sys/personality.h new file mode 100644 index 0000000..f4173ee --- /dev/null +++ b/ext2_root/usr/include/sys/personality.h @@ -0,0 +1,58 @@ +#ifndef _SYS_PERSONALITY_H +#define _SYS_PERSONALITY_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + UNAME26 = 0x0020000, + ADDR_NO_RANDOMIZE = 0x0040000, + FDPIC_FUNCPTRS = 0x0080000, + MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, + READ_IMPLIES_EXEC = 0x0400000, + ADDR_LIMIT_32BIT = 0x0800000, + SHORT_INODE = 0x1000000, + WHOLE_SECONDS = 0x2000000, + STICKY_TIMEOUTS = 0x4000000, + ADDR_LIMIT_3GB = 0x8000000 +}; + +enum { + PER_LINUX = 0x0000, + PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, + PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, + PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, + PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE, + PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, + PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, + PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, + PER_BSD = 0x0006, + PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, + PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, + PER_LINUX32 = 0x0008, + PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, + PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS, + PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS, + PER_IRIX64 = 0x000b | STICKY_TIMEOUTS, + PER_RISCOS = 0x000c, + PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, + PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_OSF4 = 0x000f, + PER_HPUX = 0x0010, + PER_MASK = 0x00ff +}; + +#ifndef __MLIBC_ABI_ONLY + +int personality(unsigned long __persona); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PERSONALITY_H */ diff --git a/ext2_root/usr/include/sys/poll.h b/ext2_root/usr/include/sys/poll.h new file mode 100644 index 0000000..bebe627 --- /dev/null +++ b/ext2_root/usr/include/sys/poll.h @@ -0,0 +1,38 @@ +#ifndef _SYS_POLL_H +#define _SYS_POLL_H + +#include +#include +#include +#include +#include +#include + +typedef __mlibc_size nfds_t; + +#ifdef __cplusplus +extern "C" { +#endif + +struct pollfd { + int fd; + short events; + short revents; +}; + +#ifndef __MLIBC_ABI_ONLY + +int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout); + +#if __MLIBC_LINUX_OPTION +int ppoll(struct pollfd *__fds, nfds_t __nfds, + const struct timespec *__timeout_ts, const sigset_t *__sigmask); +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_POLL_H */ diff --git a/ext2_root/usr/include/sys/procfs.h b/ext2_root/usr/include/sys/procfs.h new file mode 100644 index 0000000..739b702 --- /dev/null +++ b/ext2_root/usr/include/sys/procfs.h @@ -0,0 +1,75 @@ +#ifndef _SYS_PROCFS_H +#define _SYS_PROCFS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof (elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_fpregs_struct elf_fpregset_t; +typedef elf_gregset_t prgregset_t; +typedef struct user_fpregs_struct prfpregset_t; + +#define ELF_PRARGSZ 80 + +struct elf_siginfo { + int si_signo; + int si_code; + int si_errno; +}; + +struct elf_prstatus { + struct elf_siginfo pr_info; + short int pr_cursig; + unsigned long int pr_sigpend; + unsigned long int pr_sighold; + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct timeval pr_utime; + struct timeval pr_stime; + struct timeval pr_cutime; + struct timeval pr_cstime; + elf_gregset_t pr_reg; + int pr_fpvalid; +}; + +struct elf_prpsinfo { + char pr_state; + char pr_sname; + char pr_zomb; + char pr_nice; + unsigned long pr_flag; +#if __INTPTR_WIDTH__ == 32 + unsigned short int pr_uid; + unsigned short int pr_gid; +#else + unsigned int pr_uid; + unsigned int pr_gid; +#endif + int pr_pid; + int pr_ppid; + int pr_pgrp; + int pr_sid; + char pr_fname[16]; + char pr_psargs[ELF_PRARGSZ]; +}; + +typedef pid_t lwpid_t; +typedef void *psaddr_t; +typedef struct elf_prstatus prstatus_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/include/sys/queue.h b/ext2_root/usr/include/sys/queue.h new file mode 100644 index 0000000..219066b --- /dev/null +++ b/ext2_root/usr/include/sys/queue.h @@ -0,0 +1,574 @@ +/* + * Copyright (c) 1991, 1993 + * 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (0) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* _SYS_QUEUE_H_ */ diff --git a/ext2_root/usr/include/sys/reg.h b/ext2_root/usr/include/sys/reg.h new file mode 100644 index 0000000..7e5cf6f --- /dev/null +++ b/ext2_root/usr/include/sys/reg.h @@ -0,0 +1,36 @@ +#ifndef _SYS_REG_H +#define _SYS_REG_H + +#ifdef __x86_64__ +#define R15 0 +#define R14 1 +#define R13 2 +#define R12 3 +#define RBP 4 +#define RBX 5 +#define R11 6 +#define R10 7 +#define R9 8 +#define R8 9 +#define RAX 10 +#define RCX 11 +#define RDX 12 +#define RSI 13 +#define RDI 14 +#define ORIG_RAX 15 +#define RIP 16 +#define CS 17 +#define EFLAGS 18 +#define RSP 19 +#define SS 20 +#define FS_BASE 21 +#define GS_BASE 22 +#define DS 23 +#define ES 24 +#define FS 25 +#define GS 26 +#elif !(defined(__i386__) || defined(__riscv) || defined(__aarch64__) || defined(__m68k__) || defined(__loongarch64)) +#error "Missing architecture specific code." +#endif + +#endif diff --git a/ext2_root/usr/include/sys/resource.h b/ext2_root/usr/include/sys/resource.h new file mode 100644 index 0000000..1259a4e --- /dev/null +++ b/ext2_root/usr/include/sys/resource.h @@ -0,0 +1,53 @@ +#ifndef _SYS_RESOURCE_H +#define _SYS_RESOURCE_H + +#include +#include +#include +#include +#include +#include +#include + +#define PRIO_PROCESS 1 +#define PRIO_PGRP 2 +#define PRIO_USER 3 + +#define PRIO_MIN (-20) +#define PRIO_MAX 20 + +#define RLIM_INFINITY ((rlim_t)-1) +#define RLIM_SAVED_MAX ((rlim_t)-1) +#define RLIM_SAVED_CUR ((rlim_t)-1) + +#define RLIM_NLIMITS RLIMIT_NLIMITS + +#ifdef __cplusplus +extern "C" { +#endif + +struct rlimit { + rlim_t rlim_cur; + rlim_t rlim_max; +}; + +#ifndef __MLIBC_ABI_ONLY + +int getpriority(int __which, id_t __who); +int setpriority(int __which, id_t __who, int __prio); + +int getrusage(int __who, struct rusage *__usage); +int getrlimit(int __resource, struct rlimit *__rlim); +int getrlimit64(int __resource, struct rlimit *__rlim); +int setrlimit(int __resource, const struct rlimit *__rlim); +int setrlimit64(int __resource, const struct rlimit *__rlim); + +int prlimit(pid_t __pid, int __resource, const struct rlimit *__new_limits, struct rlimit *__old_limits); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_RESOURCE_H */ diff --git a/ext2_root/usr/include/sys/select.h b/ext2_root/usr/include/sys/select.h new file mode 100644 index 0000000..10d1a34 --- /dev/null +++ b/ext2_root/usr/include/sys/select.h @@ -0,0 +1,49 @@ + +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H + +#include + +#include +#include +#include +#include +#include + +#define FD_SETSIZE 1024 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long int __fd_mask; +#define __NFDBITS (8 * (int) sizeof (__fd_mask)) + +typedef __fd_mask fd_mask; +#define NFDBITS __NFDBITS + +#ifndef __MLIBC_ABI_ONLY + +void __FD_CLR(int __fd, fd_set *__set); +int __FD_ISSET(int __fd, fd_set *__set); +void __FD_SET(int __fd, fd_set *__set); +void __FD_ZERO(fd_set *__set); + +#define FD_CLR(fd, set) __FD_CLR(fd, set) +#define FD_ISSET(fd, set) __FD_ISSET(fd, set) +#define FD_SET(fd, set) __FD_SET(fd, set) +#define FD_ZERO(set) __FD_ZERO(set) + +int select(int __nfds, fd_set *__restrict __readfds, fd_set *__restrict __writefds, + fd_set *__restrict __exceptfds, struct timeval *__restrict __timeout); +int pselect(int __nfds, fd_set *__restrict __readfds, fd_set *__restrict __writefds, + fd_set *__exceptfds, const struct timespec *__timeout, const sigset_t *__sigmask); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SELECT_H */ + diff --git a/ext2_root/usr/include/sys/sem.h b/ext2_root/usr/include/sys/sem.h new file mode 100644 index 0000000..d98f91f --- /dev/null +++ b/ext2_root/usr/include/sys/sem.h @@ -0,0 +1,46 @@ +#ifndef _SYS_SEM_H +#define _SYS_SEM_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GETPID 11 +#define GETVAL 12 +#define GETALL 13 +#define SETVAL 16 +#define SETALL 17 + +#define SEM_UNDO 0x1000 + +struct sembuf { + unsigned short int sem_num; + short int sem_op; + short int sem_flg; +}; + +struct semid_ds { + struct ipc_perm sem_perm; + time_t sem_otime; + time_t sem_ctime; + + unsigned long sem_nsems; +}; + +#ifndef __MLIBC_ABI_ONLY + +int semget(key_t __key, int __nsems, int __semflg); +int semop(int __semid, struct sembuf *__sops, size_t __nsops); +int semctl(int __semid, int __semnum, int __op, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SEM_H */ diff --git a/ext2_root/usr/include/sys/shm.h b/ext2_root/usr/include/sys/shm.h new file mode 100644 index 0000000..21625be --- /dev/null +++ b/ext2_root/usr/include/sys/shm.h @@ -0,0 +1,28 @@ +#ifndef _SYS_SHM_H +#define _SYS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#include + +#ifndef __MLIBC_ABI_ONLY + +void *shmat(int __shmid, const void *__shmaddr, int __shmflg); +int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf); +int shmdt(const void *__shmaddr); +int shmget(key_t __key, size_t __size, int __shmflg); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SHM_H */ diff --git a/ext2_root/usr/include/sys/signal.h b/ext2_root/usr/include/sys/signal.h new file mode 100644 index 0000000..2e602da --- /dev/null +++ b/ext2_root/usr/include/sys/signal.h @@ -0,0 +1 @@ +#include diff --git a/ext2_root/usr/include/sys/socket.h b/ext2_root/usr/include/sys/socket.h new file mode 100644 index 0000000..69871ee --- /dev/null +++ b/ext2_root/usr/include/sys/socket.h @@ -0,0 +1,107 @@ + +#ifndef _SOCKET_H +#define _SOCKET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sockaddr { + sa_family_t sa_family; + char sa_data[14]; +}; + +/* Control message format: */ +/* The offsets marked with ^ are aligned to alignof(size_t). */ +/* */ +/* |---HEADER---|---DATA---|---PADDING---|---HEADER---|... */ +/* ^ ^ ^ */ +/* |---------CMSG_LEN------| */ +/* |---------------CMSG_SPACE------------| */ + +/* Auxiliary macro. While there is basically no reason for applications */ +/* to use this, it is exported by glibc. */ +#define CMSG_ALIGN(s) (((s) + __alignof__(size_t) - 1) & \ + ~(__alignof__(size_t) - 1)) + +/* Basic macros to return content and padding size of a control message. */ +#define CMSG_LEN(s) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (s)) +#define CMSG_SPACE(s) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(s)) + +/* Provides access to the data of a control message. */ +#define CMSG_DATA(c) ((char *)(c) + CMSG_ALIGN(sizeof(struct cmsghdr))) + +#define __MLIBC_CMSG_NEXT(c) ((char *)(c) + CMSG_ALIGN((c)->cmsg_len)) +#define __MLIBC_MHDR_LIMIT(m) ((char *)(m)->msg_control + (m)->msg_controllen) + +/* For parsing control messages only. */ +/* Returns a pointer to the first header or nullptr if there is none. */ +#define CMSG_FIRSTHDR(m) ((size_t)(m)->msg_controllen <= sizeof(struct cmsghdr) \ + ? (struct cmsghdr *)0 : (struct cmsghdr *) (m)->msg_control) + +/* For parsing control messages only. */ +/* Returns a pointer to the next header or nullptr if there is none. */ +#define CMSG_NXTHDR(m, c) \ + ((c)->cmsg_len < sizeof(struct cmsghdr) || \ + (ptrdiff_t)(sizeof(struct cmsghdr) + CMSG_ALIGN((c)->cmsg_len)) \ + >= __MLIBC_MHDR_LIMIT(m) - (char *)(c) \ + ? (struct cmsghdr *)0 : (struct cmsghdr *)__MLIBC_CMSG_NEXT(c)) + +struct linger{ + int l_onoff; + int l_linger; +}; + +struct ucred { + pid_t pid; + uid_t uid; + gid_t gid; +}; + +#ifndef __MLIBC_ABI_ONLY + +int accept(int __sockfd, struct sockaddr *__restrict __addr, socklen_t *__restrict __addrlen); +int accept4(int __sockfd, struct sockaddr *__restrict __addr, socklen_t *__restrict __addrlen, int __flags); +int bind(int __sockfd, const struct sockaddr *__addr, socklen_t __addrlen); +int connect(int __sockfd, const struct sockaddr *__addr, socklen_t __addrlen); +int getpeername(int __sockfd, struct sockaddr *__restrict __addr, socklen_t *__restrict __addrlen); +int getsockname(int __sockfd, struct sockaddr *__restrict __addr, socklen_t *__restrict __addrlen); +int getsockopt(int __sockfd, int __level, int __optname, void *__restrict __optval, socklen_t *__restrict __optlen); +int listen(int __sockfd, int __backlog); +ssize_t recv(int __sockfd, void *__buf, size_t __size, int __flags); +ssize_t recvfrom(int __sockfd, void *__restrict __buf, size_t __size, int __flags, + struct sockaddr *__restrict __src_addr, socklen_t *__restrict __addrlen); +ssize_t recvmsg(int __sockfd, struct msghdr *__msg, int __flags); +ssize_t send(int __sockfd, const void *__buf, size_t __size, int __flags); +ssize_t sendmsg(int __sockfd, const struct msghdr *__msg, int __flags); +ssize_t sendto(int __sockfd, const void *__buf, size_t __size, int __flags, + const struct sockaddr *__dest_addr, socklen_t __addrlen); +int recvmmsg(int __sockfd, struct mmsghdr *__msgvec, unsigned int __vlen, int __flags, struct timespec *__timeout); +int sendmmsg(int __sockfd, struct mmsghdr *__msgvec, unsigned int __vlen, int __flags); +int setsockopt(int __sockfd, int __level, int __option_name, const void *__optval, socklen_t __optlen); +int shutdown(int __sockfd, int __how); +int sockatmark(int __sockfd); +int socket(int __domain, int __type, int __protocol); +int socketpair(int __domain, int __type, int __protocol, int __sv[2]); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UNISTD_H */ + diff --git a/ext2_root/usr/include/sys/stat.h b/ext2_root/usr/include/sys/stat.h new file mode 100644 index 0000000..98f1d2a --- /dev/null +++ b/ext2_root/usr/include/sys/stat.h @@ -0,0 +1,44 @@ + +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include +#include + +#if __MLIBC_LINUX_OPTION +#include +#endif /* !__MLIBC_LINUX_OPTION */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int chmod(const char *__pathname, mode_t __mode); +int fchmod(int __fd, mode_t __mode); +int fchmodat(int __fd, const char *__pathname, mode_t __mode, int __flags); +int fstat(int __fd, struct stat *__result); +int fstat64(int __fd, struct stat64 *__result); +int fstatat(int __fd, const char *__restrict __pathname, struct stat *__restrict __buf, int __flags); +int futimens(int __fd, const struct timespec __times[2]); +int lstat(const char *__restrict __pathname, struct stat *__restrict __buf); +int lstat64(const char *__restrict __pathname, struct stat64 *__restrict __buf); +int mkdir(const char *__pathname, mode_t __mode); +int mkdirat(int __dirfd, const char *__pathname, mode_t __mode); +int mkfifo(const char *__pathname, mode_t __mode); +int mkfifoat(int __dirfd, const char *__pathname, mode_t __mode); +int mknod(const char *__pathname, mode_t __mode, dev_t __dev); +int mknodat(int __dirfd, const char *__pathname, mode_t __mode, dev_t __dev); +int stat(const char *__restrict __pathname, struct stat *__restrict __buf); +mode_t umask(mode_t __mode); +int utimensat(int __dirfd, const char *__pathname, const struct timespec __times[2], int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_STAT_H */ + diff --git a/ext2_root/usr/include/sys/statvfs.h b/ext2_root/usr/include/sys/statvfs.h new file mode 100644 index 0000000..03e65a3 --- /dev/null +++ b/ext2_root/usr/include/sys/statvfs.h @@ -0,0 +1,24 @@ +#ifndef _SYS_STATVFS_H +#define _SYS_STATVFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int statvfs(const char *__restrict __pathname, struct statvfs *__restrict __buf); +int statvfs64(const char *__restrict __pathname, struct statvfs64 *__restrict __buf); +int fstatvfs(int __fd, struct statvfs *__buf); +int fstatvfs64(int __fd, struct statvfs64 *__buf); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_STATVFS_H */ + diff --git a/ext2_root/usr/include/sys/syslog.h b/ext2_root/usr/include/sys/syslog.h new file mode 100644 index 0000000..7761ece --- /dev/null +++ b/ext2_root/usr/include/sys/syslog.h @@ -0,0 +1 @@ +#include diff --git a/ext2_root/usr/include/sys/termios.h b/ext2_root/usr/include/sys/termios.h new file mode 100644 index 0000000..2176780 --- /dev/null +++ b/ext2_root/usr/include/sys/termios.h @@ -0,0 +1,6 @@ + +#ifndef _SYS_TERMIOS_H +#define _SYS_TERMIOS_H +#include +#endif /* _SYS_TERMIOS_H */ + diff --git a/ext2_root/usr/include/sys/time.h b/ext2_root/usr/include/sys/time.h new file mode 100644 index 0000000..29b8212 --- /dev/null +++ b/ext2_root/usr/include/sys/time.h @@ -0,0 +1,62 @@ +#ifndef _SYS_TIME_H +#define _SYS_TIME_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +#ifndef __MLIBC_ABI_ONLY + +/* TODO: this function is [OB]. disable it by default and add a macro to enable it */ +int gettimeofday(struct timeval *__restrict __result, void *__restrict __unused); +int settimeofday(const struct timeval *__result, const struct timezone *__zone); + +void timeradd(const struct timeval *__a, const struct timeval *__b, struct timeval *__res); +void timersub(const struct timeval *__a, const struct timeval *__b, struct timeval *__res); +void timerclear(struct timeval *__tvp); +int timerisset(struct timeval *__tvp); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* timercmp taken from musl */ +#define timercmp(s,t,op) ((s)->tv_sec == (t)->tv_sec ? \ + (s)->tv_usec op (t)->tv_usec : (s)->tv_sec op (t)->tv_sec) + +#ifndef __MLIBC_ABI_ONLY + +int getitimer(int __which, struct itimerval *__curr_value); +int setitimer(int __which, const struct itimerval *__new_value, + struct itimerval *__old_value); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* The following 2 macros are taken from musl */ +#define TIMEVAL_TO_TIMESPEC(tv, ts) ( \ + (ts)->tv_sec = (tv)->tv_sec, \ + (ts)->tv_nsec = (tv)->tv_usec * 1000, \ + (void)0 ) +#define TIMESPEC_TO_TIMEVAL(tv, ts) ( \ + (tv)->tv_sec = (ts)->tv_sec, \ + (tv)->tv_usec = (ts)->tv_nsec / 1000, \ + (void)0 ) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIME_H */ diff --git a/ext2_root/usr/include/sys/timeb.h b/ext2_root/usr/include/sys/timeb.h new file mode 100644 index 0000000..bf6d718 --- /dev/null +++ b/ext2_root/usr/include/sys/timeb.h @@ -0,0 +1,14 @@ +#ifndef _SYS_TIMEB_H +#define _SYS_TIMEB_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIMEB_H */ diff --git a/ext2_root/usr/include/sys/times.h b/ext2_root/usr/include/sys/times.h new file mode 100644 index 0000000..96556bc --- /dev/null +++ b/ext2_root/usr/include/sys/times.h @@ -0,0 +1,28 @@ +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H + +/* TODO: Only define the clock_t type. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct tms { + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; + +#ifndef __MLIBC_ABI_ONLY + +clock_t times(struct tms *__tms); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIMES_H */ diff --git a/ext2_root/usr/include/sys/timex.h b/ext2_root/usr/include/sys/timex.h new file mode 100644 index 0000000..ebbb8a0 --- /dev/null +++ b/ext2_root/usr/include/sys/timex.h @@ -0,0 +1,80 @@ +#ifndef _SYS_TIMEX_H +#define _SYS_TIMEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +struct timex { + int modes; + long offset; + long freq; + long maxerror; + long esterror; + int status; + long constant; + long precision; + long tolerance; + struct timeval time; + long tick; + long ppsfreq; + long jitter; + int shift; + long stabil; + long jitcnt; + long calcnt; + long errcnt; + long stbcnt; + int tai; + int __padding[11]; +}; + +#define ADJ_OFFSET 0x0001 +#define ADJ_FREQUENCY 0x0002 +#define ADJ_MAXERROR 0x0004 +#define ADJ_ESTERROR 0x0008 +#define ADJ_STATUS 0x0010 +#define ADJ_TIMECONST 0x0020 +#define ADJ_TAI 0x0080 +#define ADJ_SETOFFSET 0x0100 +#define ADJ_MICRO 0x1000 +#define ADJ_NANO 0x2000 +#define ADJ_TICK 0x4000 +#define ADJ_OFFSET_SINGLESHOT 0x8001 +#define ADJ_OFFSET_SS_READ 0xa001 + +#define STA_PLL 0x0001 +#define STA_PPSFREQ 0x0002 +#define STA_PPSTIME 0x0004 +#define STA_FLL 0x0008 +#define STA_INS 0x0010 +#define STA_DEL 0x0020 +#define STA_UNSYNC 0x0040 +#define STA_FREQHOLD 0x0080 +#define STA_PPSSIGNAL 0x0100 +#define STA_PPSJITTER 0x0200 +#define STA_PPSWANDER 0x0400 +#define STA_PPSERROR 0x0800 +#define STA_CLOCKERR 0x1000 +#define STA_NANO 0x2000 +#define STA_MODE 0x4000 +#define STA_CLK 0x8000 + +#define TIME_ERROR 5 + +#ifndef __MLIBC_ABI_ONLY + +int adjtimex(struct timex *__buf); +int clock_adjtime(clockid_t __clockid, struct timex *__buf); +int ntp_adjtime(struct timex *__buf); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIMEX_H */ diff --git a/ext2_root/usr/include/sys/ttydefaults.h b/ext2_root/usr/include/sys/ttydefaults.h new file mode 100644 index 0000000..8ed811f --- /dev/null +++ b/ext2_root/usr/include/sys/ttydefaults.h @@ -0,0 +1,39 @@ + +#ifndef _SYS_TTYDEFAULTS_H +#define _SYS_TTYDEFAULTS_H + +/* Values taken from musl */ + +#define TTYDEF_IFLAG (BRKINT | ISTRIP | ICRNL | IMAXBEL | IXON | IXANY) +#define TTYDEF_OFLAG (OPOST | ONLCR | XTABS) +#define TTYDEF_LFLAG (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL) +#define TTYDEF_CFLAG (CREAD | CS7 | PARENB | HUPCL) +#define TTYDEF_SPEED (B9600) + +#define CTRL(x) ((x) & 037) +#define CEOF CTRL('d') + +#define CEOL '\0' +#define CEOL2 '\0' +#define CSTATUS '\0' + +#define CERASE 0177 +#define CINTR CTRL('c') +#define CKILL CTRL('u') +#define CMIN 1 +#define CQUIT 034 +#define CSUSP CTRL('z') +#define CTIME 0 +#define CDSUSP CTRL('y') +#define CSTART CTRL('q') +#define CSTOP CTRL('s') +#define CLNEXT CTRL('v') +#define CDISCARD CTRL('o') +#define CWERASE CTRL('w') +#define CREPRINT CTRL('r') +#define CEOT CEOF +#define CBRK CEOL +#define CRPRNT CREPRINT +#define CFLUSH CDISCARD + +#endif /* _SYS_TTYDEFAULTS_H */ diff --git a/ext2_root/usr/include/sys/types.h b/ext2_root/usr/include/sys/types.h new file mode 100644 index 0000000..41f6ebc --- /dev/null +++ b/ext2_root/usr/include/sys/types.h @@ -0,0 +1,53 @@ + +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +typedef unsigned int u_int; +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned long int u_long; +typedef char *caddr_t; +typedef off64_t loff_t; + +typedef unsigned long int ulong; +typedef unsigned short int ushort; +typedef unsigned int uint; + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; + +/* BSD extensions */ +typedef int64_t quad_t; +typedef uint64_t u_quad_t; + +#endif /* _SYS_TYPES_H */ + diff --git a/ext2_root/usr/include/sys/ucontext.h b/ext2_root/usr/include/sys/ucontext.h new file mode 100644 index 0000000..cae57f0 --- /dev/null +++ b/ext2_root/usr/include/sys/ucontext.h @@ -0,0 +1,14 @@ +#ifndef _SYS_UCONTEXT_H +#define _SYS_UCONTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_UCONTEXT_H */ diff --git a/ext2_root/usr/include/sys/uio.h b/ext2_root/usr/include/sys/uio.h new file mode 100644 index 0000000..422a7f6 --- /dev/null +++ b/ext2_root/usr/include/sys/uio.h @@ -0,0 +1,37 @@ +#ifndef _SYS_UIO_H +#define _SYS_UIO_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UIO_MAXIOV IOV_MAX + +#ifndef __MLIBC_ABI_ONLY + +ssize_t readv(int __fd, const struct iovec *__iov, int __iovcnt); +ssize_t writev(int __fd, const struct iovec *__iov, int __iovcnt); + +/* Non standard extensions, also found on modern BSD's */ +ssize_t preadv(int __fd, const struct iovec *__iov, int __iovcnt, off_t __offset); +ssize_t pwritev(int __fd, const struct iovec *__iov, int __iovcnt, off_t __offset); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_LINUX_OPTION +#include +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _SYS_UIO_H */ diff --git a/ext2_root/usr/include/sys/un.h b/ext2_root/usr/include/sys/un.h new file mode 100644 index 0000000..7a0093e --- /dev/null +++ b/ext2_root/usr/include/sys/un.h @@ -0,0 +1,24 @@ + +#ifndef _SYS_UN_H +#define _SYS_UN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; + +/* Evaluate to actual length of the `sockaddr_un' structure. */ +#define SUN_LEN(ptr) ((size_t) offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_UN_H */ + diff --git a/ext2_root/usr/include/sys/user.h b/ext2_root/usr/include/sys/user.h new file mode 100644 index 0000000..7963e68 --- /dev/null +++ b/ext2_root/usr/include/sys/user.h @@ -0,0 +1,51 @@ +#ifndef _SYS_USER_H +#define _SYS_USER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* TODO: This assumes x86-64. */ + +struct user_fpregs_struct { + uint16_t cwd, swd, ftw, fop; + uint64_t rip, rdp; + uint32_t mxcsr, mxcr_mask; + uint32_t st_space[32], xmm_space[64], padding[24]; +}; + +struct user_regs_struct { + unsigned long r15, r14, r13, r12, rbp, rbx, r11, r10, r9, r8; + unsigned long rax, rcx, rdx, rsi, rdi, orig_rax, rip; + unsigned long cs, eflags, rsp, ss, fs_base, gs_base, ds, es, fs, gs; +}; + +struct user { + struct user_regs_struct regs; + int u_fpvalid; + struct user_fpregs_struct i387; + unsigned long u_tsize; + unsigned long u_dsize; + unsigned long u_ssize; + unsigned long start_code; + unsigned long start_stack; + long signal; + int reserved; + struct user_regs_struct *u_ar0; + struct user_fpregs_struct *u_fpstate; + unsigned long magic; + char u_comm[32]; + unsigned long u_debugreg[8]; +}; + +#ifdef __cplusplus +} +#endif + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) + +#endif diff --git a/ext2_root/usr/include/sys/utsname.h b/ext2_root/usr/include/sys/utsname.h new file mode 100644 index 0000000..5ae31de --- /dev/null +++ b/ext2_root/usr/include/sys/utsname.h @@ -0,0 +1,22 @@ + +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int uname(struct utsname *__name); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_UTSNAME_H */ + diff --git a/ext2_root/usr/include/sys/wait.h b/ext2_root/usr/include/sys/wait.h new file mode 100644 index 0000000..16e816f --- /dev/null +++ b/ext2_root/usr/include/sys/wait.h @@ -0,0 +1,40 @@ + +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include +#include +/* for siginfo_t */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* According to POSIX, does not make rusage available. */ +struct rusage; + +/* TODO: move to own file and include in sys/types.h */ +typedef enum { + P_ALL, P_PID, P_PGID, P_PIDFD +} idtype_t; + +#ifndef __MLIBC_ABI_ONLY + +pid_t wait(int *__status); +int waitid(idtype_t __idtype, id_t __id, siginfo_t *__siginfo, int __flags); +pid_t waitpid(pid_t __pid, int *__status, int __flags); + +/* GNU extensions. */ +pid_t wait3(int *__status, int __options, struct rusage *__ru); +pid_t wait4(pid_t __pid, int *__status, int __options, struct rusage *__ru); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_WAIT_H */ + diff --git a/ext2_root/usr/include/sysexits.h b/ext2_root/usr/include/sysexits.h new file mode 100644 index 0000000..b2969da --- /dev/null +++ b/ext2_root/usr/include/sysexits.h @@ -0,0 +1,24 @@ +#ifndef _SYSEXITS_H +#define _SYSEXITS_H + +#define EX_OK 0 +#define EX_USAGE 64 +#define EX_DATAERR 65 +#define EX_NOINPUT 66 +#define EX_NOUSER 67 +#define EX_NOHOST 68 +#define EX_UNAVAILABLE 69 +#define EX_SOFTWARE 70 +#define EX_OSERR 71 +#define EX_OSFILE 72 +#define EX_CANTCREAT 73 +#define EX_IOERR 74 +#define EX_TEMPFAIL 75 +#define EX_PROTOCOL 76 +#define EX_NOPERM 77 +#define EX_CONFIG 78 + +#define EX__BASE 64 +#define EX__MAX 78 + +#endif /* _SYSEXITS_H */ diff --git a/ext2_root/usr/include/syslog.h b/ext2_root/usr/include/syslog.h new file mode 100644 index 0000000..971ada6 --- /dev/null +++ b/ext2_root/usr/include/syslog.h @@ -0,0 +1,137 @@ + +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOG_PID 0x01 +#define LOG_CONS 0x02 +#define LOG_NDELAY 0x08 +#define LOG_ODELAY 0x04 +#define LOG_NOWAIT 0x10 +#define LOG_PERROR 0x20 + +#define LOG_KERN (0<<3) +#define LOG_USER (1<<3) +#define LOG_MAIL (2<<3) +#define LOG_DAEMON (3<<3) +#define LOG_AUTH (4<<3) +#define LOG_SYSLOG (5<<3) +#define LOG_LPR (6<<3) +#define LOG_NEWS (7<<3) +#define LOG_UUCP (8<<3) +#define LOG_CRON (9<<3) +#define LOG_AUTHPRIV (10<<3) +#define LOG_FTP (11<<3) + +#define LOG_LOCAL0 (16<<3) +#define LOG_LOCAL1 (17<<3) +#define LOG_LOCAL2 (18<<3) +#define LOG_LOCAL3 (19<<3) +#define LOG_LOCAL4 (20<<3) +#define LOG_LOCAL5 (21<<3) +#define LOG_LOCAL6 (22<<3) +#define LOG_LOCAL7 (23<<3) + +#define LOG_PRIMASK 7 +#define LOG_PRI(p) ((p)&LOG_PRIMASK) +#define LOG_MAKEPRI(f, p) (((f)<<3) | (p)) +#define LOG_MASK(p) (1<<(p)) +#define LOG_UPTO(p) ((1<<((p)+1))-1) +#define LOG_NFACILITIES 24 +#define LOG_FACMASK (0x7F<<3) +#define LOG_FAC(p) (((p)&LOG_FACMASK)>>3) + +#define LOG_EMERG 0 +#define LOG_ALERT 1 +#define LOG_CRIT 2 +#define LOG_ERR 3 +#define LOG_WARNING 4 +#define LOG_NOTICE 5 +#define LOG_INFO 6 +#define LOG_DEBUG 7 + +#if __MLIBC_BSD_OPTION +#if defined(SYSLOG_NAMES) +#define INTERNAL_NOPRI 0x10 +#define INTERNAL_MARK LOG_MAKEPRI(LOG_NFACILITIES << 3, 0) + +typedef struct _code { + char *c_name; + int c_val; +} CODE; +#endif /* SYSLOG_NAMES */ +#endif /* __MLIBC_BSD_OPTION */ + +#ifndef __MLIBC_ABI_ONLY + +#if __MLIBC_BSD_OPTION +#if defined(SYSLOG_NAMES) +CODE prioritynames[] = { + { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, + { "debug", LOG_DEBUG }, + { "emerg", LOG_EMERG }, + { "err", LOG_ERR }, + { "error", LOG_ERR }, + { "info", LOG_INFO }, + { "none", INTERNAL_NOPRI }, + { "notice", LOG_NOTICE }, + { "panic", LOG_EMERG }, + { "warn", LOG_WARNING }, + { "warning", LOG_WARNING }, + { NULL, -1 } +}; + +CODE facilitynames[] = { + { "auth", LOG_AUTH }, + { "authpriv", LOG_AUTHPRIV }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "mark", INTERNAL_MARK }, + { "news", LOG_NEWS }, + { "security", LOG_AUTH }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + { NULL, -1 } +}; +#endif /* SYSLOG_NAMES */ +#endif /* __MLIBC_BSD_OPTION */ + +void closelog(void); +void openlog(const char *__ident, int __option, int __facility); +int setlogmask(int __mask); +__attribute__((__format__(__printf__, 2, 3))) +void syslog(int __priority, const char *__format, ...); + +/* This is a linux extension */ +__attribute__((__format__(__printf__, 2, 0))) +void vsyslog(int __priority, const char *__format, va_list __args); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYSLOG_H */ + diff --git a/ext2_root/usr/include/termios.h b/ext2_root/usr/include/termios.h new file mode 100644 index 0000000..cf2025b --- /dev/null +++ b/ext2_root/usr/include/termios.h @@ -0,0 +1,107 @@ + +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#include +#endif + +/* baud rate constants for speed_t */ +#define B0 0 +#define B50 1 +#define B75 2 +#define B110 3 +#define B134 4 +#define B150 5 +#define B200 6 +#define B300 7 +#define B600 8 +#define B1200 9 +#define B1800 10 +#define B2400 11 +#define B4800 12 +#define B9600 13 +#define B19200 14 +#define B38400 15 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 + +/* constants for tcsetattr() */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +/* constants for tcflush() */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* constants for tcflow() */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_RI TIOCM_RNG +#define TIOCM_CD TIOCM_CAR + +#ifndef __MLIBC_ABI_ONLY + +speed_t cfgetispeed(const struct termios *__tios); +speed_t cfgetospeed(const struct termios *__tios); +int cfsetispeed(struct termios *__tios, speed_t __speed); +int cfsetospeed(struct termios *__tios, speed_t __speed); +void cfmakeraw(struct termios *__tios); +int tcdrain(int __fd); +int tcflow(int __fd, int __action); +int tcflush(int __fd, int __queue_selector); +int tcgetattr(int fd, struct termios *__attr); +pid_t tcgetsid(int __fd); +int tcsendbreak(int __fd, int __duration); +int tcsetattr(int __fd, int __optional_actions, const struct termios *__attr); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* This is a linux extension */ + +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCGSID 0x5429 + +#ifdef __cplusplus +} +#endif + +#endif /* _TERMIOS_H */ + diff --git a/ext2_root/usr/include/threads.h b/ext2_root/usr/include/threads.h new file mode 100644 index 0000000..dab2c9b --- /dev/null +++ b/ext2_root/usr/include/threads.h @@ -0,0 +1,61 @@ +#ifndef _THREADS_H +#define _THREADS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum { + mtx_plain, + mtx_recursive, + mtx_timed +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem +}; + +typedef struct __mlibc_thread_data *thrd_t; +typedef struct __mlibc_mutex mtx_t; +typedef struct __mlibc_cond cnd_t; +#ifndef __cplusplus +#define thread_local _Thread_local +#endif + +typedef int (*thrd_start_t)(void* __arg); + +#ifndef __MLIBC_ABI_ONLY + +int thrd_create(thrd_t *__thr, thrd_start_t __func, void *__arg); +int thrd_equal(thrd_t __lhs, thrd_t __rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec *__duration, struct timespec *__remaining); +void thrd_yield(void); +int thrd_detach(thrd_t __thr); +int thrd_join(thrd_t __thr, int *__res); +__attribute__((__noreturn__)) void thrd_exit(int __res); + +int mtx_init(mtx_t *__mtx, int __type); +void mtx_destroy(mtx_t *__mtx); +int mtx_lock(mtx_t *__mtx); +int mtx_unlock(mtx_t *__mtx); + +int cnd_init(cnd_t *__cond); +void cnd_destroy(cnd_t *__cond); +int cnd_broadcast(cnd_t *__cond); +int cnd_wait(cnd_t *__cond, mtx_t *__mtx); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _THREADS_H */ + diff --git a/ext2_root/usr/include/time.h b/ext2_root/usr/include/time.h new file mode 100644 index 0000000..f54fd13 --- /dev/null +++ b/ext2_root/usr/include/time.h @@ -0,0 +1,142 @@ +#ifndef _TIME_H +#define _TIME_H + +#include +#include +#include +#include +#include + +/* [7.27.1] Components of time */ + +#define CLOCKS_PER_SEC ((clock_t)1000000) + +#define TIME_UTC 1 + +/* POSIX extensions. */ + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_MONOTONIC_RAW 4 +#define CLOCK_REALTIME_COARSE 5 +#define CLOCK_MONOTONIC_COARSE 6 +#define CLOCK_BOOTTIME 7 +#define CLOCK_REALTIME_ALARM 8 +#define CLOCK_BOOTTIME_ALARM 9 +#define CLOCK_TAI 11 + +#ifdef __cplusplus +extern "C" { +#endif + +/* [7.27.1] Components of time */ + +typedef long clock_t; /* Matches Linux' ABI. */ + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +#ifndef __MLIBC_ABI_ONLY + +/* [7.27.2] Time manipulation functions */ + +clock_t clock(void); +double difftime(time_t __a, time_t __b); +time_t mktime(struct tm *__ptr); +time_t time(time_t *__timer); +int timespec_get(struct timespec *__ptr, int __base); + +/* [7.27.3] Time conversion functions */ + +char *asctime(const struct tm *__ptr); +char *ctime(const time_t *__timer); +struct tm *gmtime(const time_t *__timer); +struct tm *gmtime_r(const time_t *__restrict __timer, struct tm *__restrict __result); +struct tm *localtime(const time_t *__timer); +size_t strftime(char *__restrict __dest, size_t __max_size, + const char *__restrict __format, const struct tm *__restrict __ptr); + +void tzset(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +/* POSIX extensions. */ + +#if __MLIBC_POSIX_OPTION +# include +# include +#endif /* __MLIBC_POSIX_OPTION */ + +#include + +#define TIMER_ABSTIME 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +extern int daylight; +extern long timezone; +extern char *tzname[2]; + +int nanosleep(const struct timespec *__req, struct timespec *__rem); + +int clock_getres(clockid_t __clockid, struct timespec *__res); +int clock_gettime(clockid_t __clockid, struct timespec *__res); +int clock_nanosleep(clockid_t __clockid, int __flags, const struct timespec *__req, struct timespec *__rem); +int clock_settime(clockid_t __clockid, const struct timespec *__time); + +struct tm *localtime_r(const time_t *__timer, struct tm *__buf); +char *asctime_r(const struct tm *__tm, char *__buf); +char *ctime_r(const time_t *__timer, char *__buf); + +#if __MLIBC_POSIX_OPTION +#include +char *strptime(const char *__restrict __buf, const char *__restrict __format, + struct tm *__restrict __tm); +int clock_getcpuclockid(pid_t __pid, clockid_t *__clockid); +#endif /* __MLIBC_POSIX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +/* GNU extensions. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +time_t timelocal(struct tm *__tm); +time_t timegm(struct tm *__tm); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TIME_H */ diff --git a/ext2_root/usr/include/uchar.h b/ext2_root/usr/include/uchar.h new file mode 100644 index 0000000..5dcfce1 --- /dev/null +++ b/ext2_root/usr/include/uchar.h @@ -0,0 +1,28 @@ +#ifndef _UCHAR_H +#define _UCHAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* These are builtin types since C++11. */ +#if !defined(__cplusplus) || __cplusplus < 201100L +typedef __CHAR16_TYPE__ char16_t; +typedef __CHAR32_TYPE__ char32_t; +#endif + +#ifndef __MLIBC_ABI_ONLY + +size_t c32rtomb(char *__restrict __s, char32_t __c32, mbstate_t *__restrict __ps); +size_t mbrtoc32(char32_t *__restrict __pc32, const char *__restrict __pmb, size_t __max, mbstate_t *__restrict __ps); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UCHAR_H */ diff --git a/ext2_root/usr/include/ucontext.h b/ext2_root/usr/include/ucontext.h new file mode 100644 index 0000000..6b53906 --- /dev/null +++ b/ext2_root/usr/include/ucontext.h @@ -0,0 +1,23 @@ +#ifndef _UCONTEXT_H +#define _UCONTEXT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef __MLIBC_ABI_ONLY + +int getcontext(ucontext_t *__uctx); +int setcontext(const ucontext_t *__uctx); +void makecontext(ucontext_t *__uctx, void (*__fn)(void), int __argc, ...); +int swapcontext(ucontext_t *__uctx, const ucontext_t *__newctx); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _UCONTEXT_H */ diff --git a/ext2_root/usr/include/unistd.h b/ext2_root/usr/include/unistd.h new file mode 100644 index 0000000..8fcaeab --- /dev/null +++ b/ext2_root/usr/include/unistd.h @@ -0,0 +1,410 @@ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H && __MLIBC_LINUX_OPTION +#include +#endif /* __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H && __MLIBC_LINUX_OPTION */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define _POSIX_VERSION 200809L +#define _POSIX2_VERSION _POSIX_VERSION +#define _XOPEN_VERSION 700 + +#define _POSIX_FSYNC _POSIX_VERSION +#define _POSIX_IPV6 _POSIX_VERSION +#define _POSIX_JOB_CONTROL 1 +#define _POSIX_SAVED_IDS 1 +#define _POSIX_SHELL 1 +#define _POSIX_SPAWN _POSIX_VERSION +#define _POSIX_THREADS _POSIX_VERSION +#define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION +#define _POSIX_MONOTONIC_CLOCK 0 + +/* MISSING: additional _POSIX and _XOPEN feature macros */ +/* MISSING: _POSIX_TIMESTAMP_RESOLUTION and _POSIX2_SYMLINKS */ + +#define _CS_PATH 0 +#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 1 +#define _CS_GNU_LIBC_VERSION 2 +#define _CS_GNU_LIBPTHREAD_VERSION 3 +#define _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS 4 +#define _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS 5 + +#define _CS_POSIX_V6_ILP32_OFF32_CFLAGS 1116 +#define _CS_POSIX_V6_ILP32_OFF32_LDFLAGS 1117 +#define _CS_POSIX_V6_ILP32_OFF32_LIBS 1118 +#define _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS 1119 +#define _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS 1120 +#define _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS 1121 +#define _CS_POSIX_V6_ILP32_OFFBIG_LIBS 1122 +#define _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS 1123 +#define _CS_POSIX_V6_LP64_OFF64_CFLAGS 1124 +#define _CS_POSIX_V6_LP64_OFF64_LDFLAGS 1125 +#define _CS_POSIX_V6_LP64_OFF64_LIBS 1126 +#define _CS_POSIX_V6_LP64_OFF64_LINTFLAGS 1127 +#define _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS 1128 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS 1129 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LIBS 1130 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS 1131 +#define _CS_POSIX_V7_ILP32_OFF32_CFLAGS 1132 +#define _CS_POSIX_V7_ILP32_OFF32_LDFLAGS 1133 +#define _CS_POSIX_V7_ILP32_OFF32_LIBS 1134 +#define _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS 1135 +#define _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS 1136 +#define _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS 1137 +#define _CS_POSIX_V7_ILP32_OFFBIG_LIBS 1138 +#define _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS 1139 +#define _CS_POSIX_V7_LP64_OFF64_CFLAGS 1140 +#define _CS_POSIX_V7_LP64_OFF64_LDFLAGS 1141 +#define _CS_POSIX_V7_LP64_OFF64_LIBS 1142 +#define _CS_POSIX_V7_LP64_OFF64_LINTFLAGS 1143 +#define _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS 1144 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS 1145 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LIBS 1146 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS 1147 +#define _CS_V6_ENV 1148 +#define _CS_V7_ENV 1149 + +/* MISSING: SEEK macros from stdio.h */ + +#define F_LOCK 1 +#define F_TEST 2 +#define F_TLOCK 3 +#define F_ULOCK 4 + +/* MISSING: _PC macros */ +/* For now, use the Linux ABI for _PC constants. */ +#define _PC_LINK_MAX 0 +#define _PC_MAX_CANON 1 +#define _PC_MAX_INPUT 2 +#define _PC_NAME_MAX 3 +#define _PC_PATH_MAX 4 +#define _PC_PIPE_BUF 5 +#define _PC_CHOWN_RESTRICTED 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 + +#define _PC_FILESIZEBITS 9 +#define _PC_SYMLINK_MAX 10 + +/* MISSING: remaining _SC_macros */ +#define _SC_ARG_MAX 0 +#define _SC_CHILD_MAX 1 +#define _SC_CLK_TCK 2 +#define _SC_NGROUPS_MAX 3 +#define _SC_OPEN_MAX 4 +#define _SC_STREAM_MAX 5 +#define _SC_TZNAME_MAX 6 +#define _SC_JOB_CONTROL 7 + +#define _SC_SAVED_IDS 8 +#define _SC_REALTIME_SIGNALS 9 +#define _SC_PRIORITY_SCHEDULING 10 +#define _SC_TIMERS 11 +#define _SC_ASYNCHRONOUS_IO 12 +#define _SC_PRIORITIZED_IO 13 +#define _SC_SYNCHRONIZED_IO 14 +#define _SC_FSYNC 15 +#define _SC_MAPPED_FILES 16 +#define _SC_MEMLOCK 17 +#define _SC_MEMLOCK_RANGE 18 +#define _SC_MEMORY_PROTECTION 19 +#define _SC_MESSAGE_PASSING 20 +#define _SC_SEMAPHORES 21 +#define _SC_SHARED_MEMORY_OBJECTS 22 +#define _SC_AIO_LISTIO_MAX 23 +#define _SC_AIO_MAX 24 +#define _SC_AIO_PRIO_DELTA_MAX 25 +#define _SC_DELAYTIMER_MAX 26 +#define _SC_MQ_OPEN_MAX 27 +#define _SC_MQ_PRIO_MAX 28 +#define _SC_VERSION 29 +#define _SC_PAGE_SIZE 30 +#define _SC_PAGESIZE _SC_PAGE_SIZE +#define _SC_RTSIG_MAX 31 +#define _SC_SEM_NSEMS_MAX 32 +#define _SC_SEM_VALUE_MAX 33 +#define _SC_SIGQUEUE_MAX 34 +#define _SC_TIMER_MAX 35 +#define _SC_BC_BASE_MAX 36 +#define _SC_BC_DIM_MAX 37 +#define _SC_BC_SCALE_MAX 38 +#define _SC_BC_STRING_MAX 39 +#define _SC_COLL_WEIGHTS_MAX 40 +#define _SC_EXPR_NEST_MAX 42 +#define _SC_LINE_MAX 43 +#define _SC_RE_DUP_MAX 44 +#define _SC_2_VERSION 46 +#define _SC_2_C_BIND 47 +#define _SC_2_C_DEV 48 +#define _SC_2_FORT_DEV 49 +#define _SC_2_FORT_RUN 50 +#define _SC_2_SW_DEV 51 +#define _SC_2_LOCALEDEF 52 +#define _SC_IOV_MAX 60 +#define _SC_UIO_MAXIOV _SC_IOV_MAX +#define _SC_THREADS 67 +#define _SC_THREAD_SAFE_FUNCTIONS 68 +#define _SC_GETGR_R_SIZE_MAX 69 +#define _SC_GETPW_R_SIZE_MAX 70 +#define _SC_LOGIN_NAME_MAX 71 +#define _SC_TTY_NAME_MAX 72 +#define _SC_THREAD_DESTRUCTOR_ITERATIONS 73 +#define _SC_THREAD_KEYS_MAX 74 +#define _SC_THREAD_STACK_MIN 75 +#define _SC_THREAD_THREADS_MAX 76 +#define _SC_THREAD_ATTR_STACKADDR 77 +#define _SC_THREAD_ATTR_STACKSIZE 78 +#define _SC_THREAD_PRIORITY_SCHEDULING 79 +#define _SC_THREAD_PRIO_INHERIT 80 +#define _SC_THREAD_PRIO_PROTECT 81 +#define _SC_THREAD_PROCESS_SHARED 82 +#define _SC_NPROCESSORS_CONF 83 +#define _SC_NPROCESSORS_ONLN 84 +#define _SC_PHYS_PAGES 85 +#define _SC_AVPHYS_PAGES 86 +#define _SC_ATEXIT_MAX 87 +#define _SC_PASS_MAX 88 +#define _SC_XOPEN_VERSION 89 +#define _SC_XOPEN_XCU_VERSION 90 +#define _SC_XOPEN_UNIX 91 +#define _SC_XOPEN_CRYPT 92 +#define _SC_XOPEN_ENH_I18N 93 +#define _SC_XOPEN_SHM 94 +#define _SC_2_CHAR_TERM 95 +#define _SC_2_UPE 97 +#define _SC_XOPEN_XPG2 98 +#define _SC_XOPEN_XPG3 99 +#define _SC_XOPEN_XPG4 100 +#define _SC_NZERO 109 +#define _SC_XBS5_ILP32_OFF32 125 +#define _SC_XBS5_ILP32_OFFBIG 126 +#define _SC_XBS5_LP64_OFF64 127 +#define _SC_XBS5_LPBIG_OFFBIG 128 +#define _SC_XOPEN_LEGACY 129 +#define _SC_XOPEN_REALTIME 130 +#define _SC_XOPEN_REALTIME_THREADS 131 +#define _SC_ADVISORY_INFO 132 +#define _SC_BARRIERS 133 +#define _SC_CLOCK_SELECTION 137 +#define _SC_CPUTIME 138 +#define _SC_THREAD_CPUTIME 139 +#define _SC_MONOTONIC_CLOCK 149 +#define _SC_READER_WRITER_LOCKS 153 +#define _SC_SPIN_LOCKS 154 +#define _SC_REGEXP 155 +#define _SC_SHELL 157 +#define _SC_SPAWN 159 +#define _SC_SPORADIC_SERVER 160 +#define _SC_THREAD_SPORADIC_SERVER 161 +#define _SC_TIMEOUTS 164 +#define _SC_TYPED_MEMORY_OBJECTS 165 +#define _SC_2_PBS 168 +#define _SC_2_PBS_ACCOUNTING 169 +#define _SC_2_PBS_LOCATE 170 +#define _SC_2_PBS_MESSAGE 171 +#define _SC_2_PBS_TRACK 172 +#define _SC_SYMLOOP_MAX 173 +#define _SC_STREAMS 174 +#define _SC_2_PBS_CHECKPOINT 175 +#define _SC_V6_ILP32_OFF32 176 +#define _SC_V6_ILP32_OFFBIG 177 +#define _SC_V6_LP64_OFF64 178 +#define _SC_V6_LPBIG_OFFBIG 179 +#define _SC_HOST_NAME_MAX 180 +#define _SC_TRACE 181 +#define _SC_TRACE_EVENT_FILTER 182 +#define _SC_TRACE_INHERIT 183 +#define _SC_TRACE_LOG 184 + +/* Port-specific _SC_* define values */ + +#if defined (__ironclad__) +#define _SC_TOTAL_PAGES 1000 +#define _SC_HOST_OPEN_MAX 1001 +#endif /* defined (__ironclad__) */ + +#define STDERR_FILENO 2 +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 + +#define _POSIX_VDISABLE '\0' + +#define L_ctermid 20 + +/* + * Solving this likely requires us to 'factor out' the typedef into a new + * header file, or use a mechanism like musl's __NEED_intptr_t. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +typedef __mlibc_intptr intptr_t; +#pragma GCC diagnostic pop + +#ifndef __MLIBC_ABI_ONLY + +int access(const char *__path, int __mode); +unsigned int alarm(unsigned int __seconds); +int chdir(const char *__path); +int chown(const char *__path, uid_t __uid, gid_t __gid); +int close(int __fd); +ssize_t confstr(int __name, char *__buf, size_t __size); +char *ctermid(char *__s); +int dup(int __fd); +int dup2(int __src_fd, int __dest_fd); +__attribute__((__noreturn__)) void _exit(int __status); +void endusershell(void); +int execl(const char *__path, const char *__arg, ...); +int execle(const char *__path, const char *__arg, ...); +int execlp(const char *__file, const char *__arg, ...); +int execv(const char *__path, char *const __argv[]); +int execve(const char *__path, char *const __argv[], char *const __envp[]); +int execvp(const char *__file, char *const __argv[]); +int execvpe(const char *__path, char *const __argv[], char *const __envp[]); +int faccessat(int __fd, const char *__path, int __mode, int __flags); +int fchdir(int __fd); +int fchown(int __fd, uid_t __uid, gid_t __gid); +int fchownat(int __fd, const char *__path, uid_t __uid, gid_t __gid, int __flags); +int fdatasync(int __fd); +int fexecve(int __fd, char *const __argv[], char *const __envp[]); +pid_t fork(void); +pid_t vfork(void); +long fpathconf(int __fd, int __name); +int fsync(int __fd); +int ftruncate(int __fd, off_t __size); +int ftruncate64(int __fd, off64_t __size); +char *getcwd(char *__buffer, size_t __size); +gid_t getegid(void); +uid_t geteuid(void); +gid_t getgid(void); +int getgroups(int __size, gid_t __list[]); +long gethostid(void); +int gethostname(char *__buffer, size_t __max_length); +int sethostname(const char *__buffer, size_t __max_length); +char *getlogin(void); +int getlogin_r(char *__buffer, size_t __size); +int getopt(int __argc, char *const __argv[], const char *__optstring); +char *getpass(const char *__prompt); +pid_t getpgid(pid_t __pid); +pid_t getpgrp(void); +pid_t getpid(void); +pid_t getppid(void); +pid_t getsid(pid_t __pid); +uid_t getuid(void); +char *getusershell(void); +int isatty(int __fd); +int lchown(const char *__path, uid_t __uid, gid_t __gid); +int link(const char *__oldpath, const char *__newpath); +int linkat(int __olddirfd, const char *__oldpath, int __newdirfd, const char *__newpath, int __flags); +int lockf(int __fd, int __op, off_t __size); +off_t lseek(int __fd, off_t __offset, int __whence); +off64_t lseek64(int __fd, off64_t __offset, int __whence); +int nice(int __increment); +long pathconf(const char *__path, int __name); +int pause(void); +int pipe(int __pipefd[2]); +ssize_t pread(int __fd, void *__buf, size_t __size, off_t __offset); +ssize_t pread64(int __fd, void *__buf, size_t __size, off_t __offset); +ssize_t pwrite(int __fd, const void *__buf, size_t __size, off_t __offset); +ssize_t pwrite64(int __fd, const void *__buf, size_t __size, off_t __offset); +ssize_t read(int fd, void *buffer, size_t size); +ssize_t readlink(const char *__restrict __path, char *__restrict __buf, size_t __size); +ssize_t readlinkat(int __dirfd, const char *__restrict __path, char *__restrict __buf, size_t __size); +int rmdir(const char *__path); +int setegid(gid_t __egid); +int seteuid(uid_t __euid); +int setgid(gid_t __gid); +int setpgid(pid_t __pid, pid_t __pgid); +pid_t setpgrp(void); +int setregid(gid_t __rgid, gid_t __egid); +int setreuid(uid_t __ruid, uid_t __euid); +pid_t setsid(void); +int setuid(uid_t __uid); +void setusershell(void); +unsigned int sleep(unsigned int __seconds); +void swab(const void *__restrict __from, void *__restrict __to, ssize_t __size); +int symlink(const char *__target, const char *__linkpath); +int symlinkat(const char *__target, int __newdirfd, const char *__linkpath); +void sync(void); +long sysconf(int __name); +pid_t tcgetpgrp(int __fd); +int tcsetpgrp(int __fd, pid_t __pgrp); +int truncate(const char *__path, off_t __size); +int truncate64(const char *__path, off64_t __size); +char *ttyname(int __fd); +int ttyname_r(int __fd, char *__buf, size_t __size); +int unlink(const char *__path); +int unlinkat(int __dirfd, const char *__path, int __flags); +ssize_t write(int __fd, const void *__buffer, size_t __size); + +extern char **environ; +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; + +#endif /* !__MLIBC_ABI_ONLY */ + +/* Non-POSIX functions supported by Linux. */ +#if UINTPTR_MAX == UINT64_MAX +typedef __mlibc_uint64 useconds_t; +#else +typedef __mlibc_uint32 useconds_t; +#endif + +#ifndef __MLIBC_ABI_ONLY + +int getpagesize(void); +char *get_current_dir_name(void); +int usleep(useconds_t __usec); +int chroot(const char *__path); +int daemon(int __nochdir, int __noclose); + +/* This is a Linux extension */ +pid_t gettid(void); +int getentropy(void *__buffer, size_t __size); + +int pipe2(int *__pipefd, int __flags); + +int setresuid(uid_t __ruid, uid_t __euid, uid_t __suid); +int setresgid(gid_t __rgid, gid_t __egid, gid_t __sgid); + +/* Glibc extensions. */ +int getdomainname(char *__name, size_t __len); +int setdomainname(const char *__name, size_t __len); + +int getresuid(uid_t *__ruid, uid_t *__euid, uid_t *__suid); +int getresgid(gid_t *__rgid, gid_t *__egid, gid_t *__sgid); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_LINUX_OPTION +# include +#endif + +#if __MLIBC_BSD_OPTION +# include +#endif + +#endif /* _UNISTD_H */ + diff --git a/ext2_root/usr/include/utime.h b/ext2_root/usr/include/utime.h new file mode 100644 index 0000000..0d5a2b2 --- /dev/null +++ b/ext2_root/usr/include/utime.h @@ -0,0 +1,25 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +#ifndef __MLIBC_ABI_ONLY + +int utime(const char *__filename, const struct utimbuf *__times); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UTIME_H */ diff --git a/ext2_root/usr/include/utmp.h b/ext2_root/usr/include/utmp.h new file mode 100644 index 0000000..101d4d7 --- /dev/null +++ b/ext2_root/usr/include/utmp.h @@ -0,0 +1,24 @@ +#ifndef _UTMP_H +#define _UTMP_H + +#include + +#if __MLIBC_LINUX_OPTION +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int login_tty(int __fd); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UTMP_H */ diff --git a/ext2_root/usr/include/utmpx.h b/ext2_root/usr/include/utmpx.h new file mode 100644 index 0000000..4c7685a --- /dev/null +++ b/ext2_root/usr/include/utmpx.h @@ -0,0 +1,31 @@ + +#ifndef _UTMPX_H +#define _UTMPX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +void endutxent(void); +struct utmpx *getutxent(void); +struct utmpx *getutxid(const struct utmpx *__id); +struct utmpx *getutxline(const struct utmpx *__ut); +struct utmpx *pututxline(const struct utmpx *__line); +void setutxent(void); + +/* extensions */ +void updwtmpx(const char *__wtmp_file, const struct utmpx *__ut); +int utmpxname(const char *__file); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UTMPX_H */ diff --git a/ext2_root/usr/include/wchar.h b/ext2_root/usr/include/wchar.h new file mode 100644 index 0000000..6a58f97 --- /dev/null +++ b/ext2_root/usr/include/wchar.h @@ -0,0 +1,128 @@ +#ifndef _WCHAR_H +#define _WCHAR_H + +#include +#include +#include +#include +#include +#include +#include + +#define WEOF 0xffffffffU + +#ifdef __cplusplus +extern "C" { +#endif + +/* MISSING: struct tm */ + +#ifndef __MLIBC_ABI_ONLY + +/* [7.28.2] Wide formatted I/O functions */ + +int fwprintf(FILE *__restrict __stream, const wchar_t *__restrict __format, ...); +int fwscanf(FILE *__restrict __stream, const wchar_t *__restrict __format, ...); +int vfwprintf(FILE *__restrict __stream, const wchar_t *__restrict __format, __builtin_va_list __args); +int vfwscanf(FILE *__restrict __stream, const wchar_t *__restrict __format, __builtin_va_list __args); + +int swprintf(wchar_t *__restrict __buffer, size_t __max_size, const wchar_t *__restrict __format, ...); +int swscanf(wchar_t *__restrict __buffer, const wchar_t *__restrict __format, ...); +int vswprintf(wchar_t *__restrict __buffer, size_t __max_size, const wchar_t *__restrict __format, __builtin_va_list __args); +int vswscanf(wchar_t *__restrict __buffer, const wchar_t *__restrict __format, __builtin_va_list __args); + +int wprintf(const wchar_t *__restrict __format, ...); +int wscanf(const wchar_t *__restrict __format, ...); +int vwprintf(const wchar_t *__restrict __format, __builtin_va_list __args); +int vwscanf(const wchar_t *__restrict __format, __builtin_va_list __args); + +/* [7.28.3] Wide character I/O functions */ + +wint_t fgetwc(FILE *__stream); +wchar_t *fgetws(wchar_t *__restrict __buffer, int __size, FILE *__restrict __stream); +wint_t fputwc(wchar_t __wc, FILE *__stream); +int fputws(const wchar_t *__restrict __buffer, FILE *__restrict __stream); +int fwide(FILE *__stream, int __mode); +wint_t getwc(FILE *__stream); +wint_t getwchar(void); +wint_t putwc(wchar_t __wc, FILE *__stream); +wint_t putwchar(wchar_t __wc); +wint_t ungetwc(wint_t __wc, FILE *__stream); + +/* [7.28.4] Wide string functions */ + +double wcstod(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr); +float wcstof(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr); +long double wcstold(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr); + +long wcstol(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr, int __base); +long long wcstoll(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr, int __base); +unsigned long wcstoul(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr, int __base); +unsigned long long wcstoull(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr, int __base); + +wchar_t *wcscpy(wchar_t *__restrict __dest, const wchar_t *__restrict __src); +wchar_t *wcsncpy(wchar_t *__restrict __dest, const wchar_t *__restrict __src, size_t __size); +wchar_t *wmemcpy(wchar_t *__restrict __dest, const wchar_t *__restrict __src, size_t __size); +wchar_t *wmemmove(wchar_t *__dest, const wchar_t *__src, size_t __size); + +wchar_t *wcscat(wchar_t *__restrict __dest, const wchar_t *__restrict __src); +wchar_t *wcsncat(wchar_t *__restrict __dest, const wchar_t *__restrict __src, size_t __size); + +int wcscmp(const wchar_t *__a, const wchar_t *__b); +int wcscoll(const wchar_t *__a, const wchar_t *__b); +int wcsncmp(const wchar_t *__a, const wchar_t *__b, size_t __size); +int wcsxfrm(wchar_t *__restrict __dest, const wchar_t *__restrict __src, size_t __size); +int wmemcmp(const wchar_t *__a, const wchar_t *__b, size_t __size); + +wchar_t *wcschr(const wchar_t *__s, wchar_t __wc); +size_t wcscspn(const wchar_t *__dest, const wchar_t *__wchrs); +wchar_t *wcspbrk(const wchar_t *__s, const wchar_t *__wchrs); +wchar_t *wcsrchr(const wchar_t *__s, wchar_t __wc); +size_t wcsspn(const wchar_t *__s, const wchar_t *__wchrs); +wchar_t *wcsstr(const wchar_t *__s, const wchar_t *__b); +wchar_t *wcstok(wchar_t *__restrict __s, const wchar_t *__restrict __delimiter, wchar_t **__restrict __ptr); +wchar_t *wmemchr(const wchar_t *__s, wchar_t __wc, size_t __size); + +size_t wcslen(const wchar_t *__s); +wchar_t *wmemset(wchar_t *__dest, wchar_t __wc, size_t __size); + +/* [7.28.5] Wide date/time functions */ + +/* POSIX says: + * The tag tm is declared as naming an incomplete structure type, the contents of which are + * described in the header . */ +struct tm; +size_t wcsftime(wchar_t *__restrict __buffer, size_t __max_size, const wchar_t *__restrict __format, + const struct tm *__restrict __time); + +/* [7.28.6] Wide conversion functions */ + +wint_t btowc(int __wc); +int wctob(wint_t __wc); + +int mbsinit(const mbstate_t *__state); +size_t mbrlen(const char *__restrict __mbs, size_t __mbs_limit, mbstate_t *__restrict __stp); +size_t mbrtowc(wchar_t *__restrict __wcp, const char *__restrict __mbs, size_t __mbs_limit, mbstate_t *__restrict __stp); +size_t wcrtomb(char *__restrict __mbs, wchar_t __wc, mbstate_t *__restrict __stp); +size_t mbsrtowcs(wchar_t *__restrict __wcs, const char **__restrict __mbs, size_t __mb_limit, mbstate_t *__restrict __stp); +size_t mbsnrtowcs(wchar_t *__restrict __wcs, const char **__restrict __mbs, size_t __mb_limit, size_t __wc_limit, + mbstate_t *__restrict __stp); +size_t wcsrtombs(char *__restrict __mbs, const wchar_t **__restrict __wcs, size_t __mb_limit, mbstate_t *__restrict __stp); +size_t wcsnrtombs(char *__restrict __mbs, const wchar_t **__restrict __wcs, size_t __mb_limit, size_t __wc_limit, + mbstate_t *__restrict __stp); + +/* POSIX extensions */ +int wcwidth(wchar_t __wc); +int wcswidth(const wchar_t *__s, size_t __size); +wchar_t *wcsdup(const wchar_t *__s); +int wcsncasecmp(const wchar_t *__a, const wchar_t *__b, size_t __size); +int wcscasecmp(const wchar_t *__a, const wchar_t *__b); +size_t wcsnlen(const wchar_t *__s, size_t __maxlen); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _WCHAR_H */ diff --git a/ext2_root/usr/include/wctype.h b/ext2_root/usr/include/wctype.h new file mode 100644 index 0000000..ab66f15 --- /dev/null +++ b/ext2_root/usr/include/wctype.h @@ -0,0 +1,51 @@ +#ifndef _WCTYPE_H +#define _WCTYPE_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* [C11/7.30.2.2] Extensible wide character classification functions. */ + +int iswalnum(wint_t __wc); +int iswalpha(wint_t __wc); +int iswblank(wint_t __wc); +int iswcntrl(wint_t __wc); +int iswdigit(wint_t __wc); +int iswgraph(wint_t __wc); +int iswlower(wint_t __wc); +int iswprint(wint_t __wc); +int iswpunct(wint_t __wc); +int iswspace(wint_t __wc); +int iswupper(wint_t __wc); +int iswxdigit(wint_t __wc); + +wctype_t wctype(const char *__string); +int iswctype(wint_t __wc, wctype_t __type); + +/* [C11/7.30.3] Wide character case mapping utilities. */ + +wint_t towlower(wint_t __wc); +wint_t towupper(wint_t __wc); + +wctrans_t wctrans(const char *__string); +wint_t towctrans(wint_t __wc, wctrans_t __trans); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif /* _WCTYPE_H */ diff --git a/ext2_root/usr/include/wordexp.h b/ext2_root/usr/include/wordexp.h new file mode 100644 index 0000000..34dd55a --- /dev/null +++ b/ext2_root/usr/include/wordexp.h @@ -0,0 +1,43 @@ +#ifndef _WORDEXP_H +#define _WORDEXP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define WRDE_APPEND 1 +#define WRDE_DOOFFS 2 +#define WRDE_NOCMD 4 +#define WRDE_REUSE 8 +#define WRDE_SHOWERR 16 +#define WRDE_UNDEF 32 + +#define WRDE_SUCCESS 1 +#define WRDE_BADCHAR 1 +#define WRDE_BADVAL 2 +#define WRDE_CMDSUB 3 +#define WRDE_NOSPACE 4 +#define WRDE_SYNTAX 5 + +typedef struct { + size_t we_wordc; + char **we_wordv; + size_t we_offs; + char *we_strings; + size_t we_nbytes; +} wordexp_t; + +#ifndef __MLIBC_ABI_ONLY + +int wordexp(const char *__s, wordexp_t *__p, int __flags); +void wordfree(wordexp_t *__p); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext2_root/usr/lib/Scrt1.o b/ext2_root/usr/lib/Scrt1.o new file mode 100644 index 0000000..ff5ee5e Binary files /dev/null and b/ext2_root/usr/lib/Scrt1.o differ diff --git a/ext2_root/usr/lib/crt0.o b/ext2_root/usr/lib/crt0.o new file mode 100644 index 0000000..fd59e7b Binary files /dev/null and b/ext2_root/usr/lib/crt0.o differ diff --git a/ext2_root/usr/lib/crt1.o b/ext2_root/usr/lib/crt1.o new file mode 100644 index 0000000..fd59e7b Binary files /dev/null and b/ext2_root/usr/lib/crt1.o differ diff --git a/ext2_root/usr/lib/crti.o b/ext2_root/usr/lib/crti.o new file mode 100644 index 0000000..12b5bf9 Binary files /dev/null and b/ext2_root/usr/lib/crti.o differ diff --git a/ext2_root/usr/lib/crtn.o b/ext2_root/usr/lib/crtn.o new file mode 100644 index 0000000..44a91cd Binary files /dev/null and b/ext2_root/usr/lib/crtn.o differ diff --git a/ext2_root/usr/lib/libc.a b/ext2_root/usr/lib/libc.a new file mode 100644 index 0000000..826d7ed Binary files /dev/null and b/ext2_root/usr/lib/libc.a differ diff --git a/ext2_root/usr/lib/libdl.a b/ext2_root/usr/lib/libdl.a new file mode 100644 index 0000000..cb74d6f Binary files /dev/null and b/ext2_root/usr/lib/libdl.a differ diff --git a/ext2_root/usr/lib/libm.a b/ext2_root/usr/lib/libm.a new file mode 100644 index 0000000..54c8926 Binary files /dev/null and b/ext2_root/usr/lib/libm.a differ diff --git a/ext2_root/usr/lib/libpthread.a b/ext2_root/usr/lib/libpthread.a new file mode 100644 index 0000000..0c55c45 Binary files /dev/null and b/ext2_root/usr/lib/libpthread.a differ diff --git a/ext2_root/usr/lib/libresolv.a b/ext2_root/usr/lib/libresolv.a new file mode 100644 index 0000000..3562441 Binary files /dev/null and b/ext2_root/usr/lib/libresolv.a differ diff --git a/ext2_root/usr/lib/librt.a b/ext2_root/usr/lib/librt.a new file mode 100644 index 0000000..3cf7dad Binary files /dev/null and b/ext2_root/usr/lib/librt.a differ diff --git a/ext2_root/usr/lib/libssp.a b/ext2_root/usr/lib/libssp.a new file mode 100644 index 0000000..dbd4c14 Binary files /dev/null and b/ext2_root/usr/lib/libssp.a differ diff --git a/ext2_root/usr/lib/libssp_nonshared.a b/ext2_root/usr/lib/libssp_nonshared.a new file mode 100644 index 0000000..55bd909 Binary files /dev/null and b/ext2_root/usr/lib/libssp_nonshared.a differ diff --git a/ext2_root/usr/lib/libutil.a b/ext2_root/usr/lib/libutil.a new file mode 100644 index 0000000..e545d04 Binary files /dev/null and b/ext2_root/usr/lib/libutil.a differ diff --git a/src/arch/x86_64/boot/isr.c b/src/arch/x86_64/boot/isr.c index 3818712..9f8bf09 100644 --- a/src/arch/x86_64/boot/isr.c +++ b/src/arch/x86_64/boot/isr.c @@ -55,14 +55,14 @@ void x86_64_ISR_Initialize(void) x86_64_ISR_InitializeGates(); for (int i = 0; i < 256; i++) x86_64_IDT_EnableGate(i); - x86_64_IDT_DisableGate(0x80); // syscall gate if you want + x86_64_IDT_DisableGate(0x80); // syscall gate } void page_fault_handler(Registers* regs, uint64_t cr2) { - // You can decode error bits here: + // bit 0: present // bit 1: write // bit 2: user-mode diff --git a/src/arch/x86_64/cpu/usermode.c b/src/arch/x86_64/cpu/usermode.c index 6ec1d58..05503b8 100644 --- a/src/arch/x86_64/cpu/usermode.c +++ b/src/arch/x86_64/cpu/usermode.c @@ -40,10 +40,14 @@ struct pagemap *create_user_pagemap(void) } /* Copy kernel higher-half mappings (kernel + HHDM) */ - for (size_t i = 256; i < 512; i++) { + for (size_t i = 0; i < 512; i++) { pm->top_level[i] = kernel_pagemap->top_level[i]; } + for (size_t i = 0; i < 256; i++) { + pm->top_level[i] = 0; + } + /* Lower half remains zero (user address space) */ printf("[usermode] user pagemap created (PML4 phys = 0x%lx)\n", (uint64_t)pm->top_level - MEM_PHYS_OFFSET); @@ -53,7 +57,7 @@ struct pagemap *create_user_pagemap(void) uintptr_t setup_user_stack(struct pagemap *pagemap) { - user_stack_phys_base = (uint64_t)pmm_alloc(USER_STACK_PAGES); + user_stack_phys_base = (uint64_t)pmm_allocz(USER_STACK_PAGES); if (!user_stack_phys_base) { printf("Failed to allocate user stack pages!\n"); @@ -83,45 +87,9 @@ uintptr_t setup_user_stack(struct pagemap *pagemap) return rsp; } -__attribute__((naked)) -void enter_user_mode(uint64_t rip, uint64_t rsp) -{ - asm volatile( - "cli\n\t" - "mov $0x1B, %%ax\n\t" - "mov %%ax, %%ds\n\t" - "mov %%ax, %%es\n\t" - "mov %%ax, %%fs\n\t" - "mov %%ax, %%gs\n\t" - - // SS - "pushq $0x1B\n\t" - - // RSP - "pushq %1\n\t" - - // RFLAGS - "pushfq\n\t" - "pop %%rax\n\t" - "or $0x200, %%rax\n\t" - "push %%rax\n\t" - - // CS - "pushq $0x23\n\t" - - // RIP - "pushq %0\n\t" - - "iretq\n\t" - : - : "r"(rip), "r"(rsp) - : "rax", "memory" - ); -} void start_userspace(void) { - struct pagemap *user_pagemap = create_user_pagemap(); if (!user_pagemap) { printf("Failed to create user pagemap\n"); @@ -129,19 +97,35 @@ void start_userspace(void) } void *elf_entry = NULL; - if (!ELF_Read("init.elf", &elf_entry, user_pagemap)) { - printf("Failed to load init.elf\n"); + uint64_t tls_fs_base = 0; + uint64_t phdr_va = 0; + uint16_t phent = 0; + uint16_t phnum = 0; + + if (!ELF_Read("helloworld.elf", + &elf_entry, + user_pagemap, + &tls_fs_base, + &phdr_va, + &phent, + &phnum)) { + printf("Failed to load helloworld.elf\n"); for(;;); } - if (!elf_entry) { - printf("ELF has no entry point\n"); - for(;;); - } + printf("ELF: entry=0x%lx TLS_FS=0x%lx PHDR=0x%lx PHENT=0x%x PHNUM=%u\n", + (uint64_t)elf_entry, tls_fs_base, phdr_va, phent, phnum); uintptr_t user_rsp = setup_user_stack(user_pagemap); printf("Entering usermode RIP=%p RSP=%p\n", elf_entry, (void*)user_rsp); - sched_create_user_task("init", (uint64_t)elf_entry, user_rsp, user_pagemap); + sched_create_user_task("init", + (uint64_t)elf_entry, + user_rsp, + user_pagemap, + tls_fs_base, + phdr_va, + phent, + phnum); } \ No newline at end of file diff --git a/src/arch/x86_64/sys/apic.c b/src/arch/x86_64/sys/apic.c index 4210a6e..0757aba 100644 --- a/src/arch/x86_64/sys/apic.c +++ b/src/arch/x86_64/sys/apic.c @@ -138,7 +138,7 @@ void lapic_init(void) { * ── Step 8: Set Task Priority to 0 ─────────────────────────────────── * * TPR = 0 means the CPU will accept all interrupt priorities. - * Raise this later if you need to block lower-priority interrupts. + * Raise this later if need to block lower-priority interrupts. */ lapic_write(LAPIC_TPR, 0); diff --git a/src/arch/x86_64/sys/apic.h b/src/arch/x86_64/sys/apic.h index 00da6cc..5ba43c9 100644 --- a/src/arch/x86_64/sys/apic.h +++ b/src/arch/x86_64/sys/apic.h @@ -64,9 +64,6 @@ void lapic_init(void); /** * lapic_eoi - Signal end-of-interrupt to the LAPIC. - * Must be called from interrupt handlers that go through the LAPIC - * (i.e. IOAPIC-routed interrupts). ExtINT (i8259) interrupts only - * need the i8259 EOI, which your existing irq.c already sends. */ void lapic_eoi(void); diff --git a/src/arch/x86_64/sys/ioapic.c b/src/arch/x86_64/sys/ioapic.c index c1d192c..0bcc31c 100644 --- a/src/arch/x86_64/sys/ioapic.c +++ b/src/arch/x86_64/sys/ioapic.c @@ -237,7 +237,7 @@ void ioapic_init(void) { * MEM_PHYS_OFFSET. Two MMIO registers are accessed (offsets 0 and * 0x10) so one 4 KiB page is sufficient. * - * TODO: Mark the page UC (cache-disable) in the PTE when your VMM + * TODO: Mark the page UC (cache-disable) in the PTE when VMM * gains support for PAT / PCD flags. */ uint64_t phys = (uint64_t)e->address; @@ -343,7 +343,7 @@ void irq_redirect_to_apic(uint8_t isa_irq, uint8_t vector, /* Mask in the 8259 so it stops firing through LINT0 */ if (g_Driver) { - g_Driver->Mask(isa_irq); // from your irq.c / i8259 + g_Driver->Mask(isa_irq); } /* Programme IOAPIC redirection entry */ diff --git a/src/arch/x86_64/sys/irq.c b/src/arch/x86_64/sys/irq.c index cbd26fb..0034a35 100644 --- a/src/arch/x86_64/sys/irq.c +++ b/src/arch/x86_64/sys/irq.c @@ -22,6 +22,8 @@ extern bool g_IOAPIC; void x86_64_IRQ_Handler(Registers *regs) { int irq = regs->interrupt - PIC_REMAP_OFFSET; + + g_Driver->SendEndOfInterrupt(irq); if (g_IRQHandlers[irq] != NULL) { @@ -33,7 +35,7 @@ void x86_64_IRQ_Handler(Registers *regs) log_warn(MODULE, "Unhandled IRQ %d...", irq); } - g_Driver->SendEndOfInterrupt(irq); + @@ -42,6 +44,7 @@ void x86_64_IRQ_Handler(Registers *regs) void x86_64_APIC_IRQ_Handler(Registers* regs) { uint8_t vector = regs->interrupt; + lapic_eoi(); if (g_APICHandlers[vector] != NULL) { g_APICHandlers[vector](regs); @@ -49,7 +52,7 @@ void x86_64_APIC_IRQ_Handler(Registers* regs) log_warn("APIC", "Unhandled vector 0x%02x", vector); } - lapic_eoi(); // ← This is the key difference from PIC! + // ← This is the key difference from PIC! } diff --git a/src/drivers/audio/pcm.h b/src/drivers/audio/pcm.h index 627d474..af118f7 100644 --- a/src/drivers/audio/pcm.h +++ b/src/drivers/audio/pcm.h @@ -33,7 +33,7 @@ typedef struct __attribute__((packed)) { * • WAV – any PCM WAV (no compression): sample rate / channels / bit depth * are read from the "fmt " chunk automatically. * • Raw – no RIFF header; audio is assumed to be 48 000 Hz, 16-bit, stereo. - * Override with pcm_play_raw() if your file has a different format. + * Override with pcm_play_raw() if file has a different format. * * The function allocates a physically-contiguous DMA buffer, reads the file, * starts playback, blocks until complete, then frees the buffer. diff --git a/src/fs/elf.c b/src/fs/elf.c index 9c9a772..e845ee9 100644 --- a/src/fs/elf.c +++ b/src/fs/elf.c @@ -1,3 +1,4 @@ +// elf.c (now extracts AT_PHDR / AT_PHENT / AT_PHNUM + minor cleanups) #include "elf.h" #include "libk/stdio.h" #include "libk/string.h" @@ -8,148 +9,223 @@ extern uintptr_t g_hhdm_offset; -#define ELF_BUFFER_SIZE (1024 * 1024) - - - - -bool ELF_Read(const char* path, void** entryPoint, struct pagemap *target_pagemap) +bool ELF_Read(const char* path, + void** entryPoint, + struct pagemap *target_pagemap, + uint64_t *out_tls_fs_base, + uint64_t *out_phdr_va, + uint16_t *out_phent, + uint16_t *out_phnum) { - uint32_t size; + *out_tls_fs_base = 0; + *out_phdr_va = 0; + *out_phent = 0; + *out_phnum = 0; - uint8_t* elf_buffer = kmalloc(ELF_BUFFER_SIZE); - if (!elf_buffer) { - printf("ELF: kmalloc failed\n"); + uint32_t inum = ext2_resolve_path(path); + if (!inum) { + printf("ELF: file not found: %s\n", path); return false; } - // ── load file ───────────────────────────────────── - if (!ext2_read_file_from_root(path, elf_buffer, &size)) { - printf("ELF: failed to read file\n"); - kfree(elf_buffer); + ext2_inode_t inode; + if (!ext2_read_inode(inum, &inode)) { + printf("ELF: failed to read inode\n"); return false; } - if (size < sizeof(ELFHeader)) { + uint64_t file_size = inode.i_size; + if (file_size < sizeof(ELFHeader)) { printf("ELF: file too small\n"); - kfree(elf_buffer); + return false; + } + + uint64_t buf_pages = ALIGN_UP(file_size, PAGE_SIZE) / PAGE_SIZE; + void* buffer_phys = pmm_allocz(buf_pages); + if (!buffer_phys) { + printf("ELF: failed to allocate %lu pages for file buffer\n", buf_pages); + return false; + } + + uint8_t* elf_buffer = (uint8_t*)((uintptr_t)buffer_phys + MEM_PHYS_OFFSET); + + if (!ext2_read_file(&inode, elf_buffer)) { + pmm_free(buffer_phys, buf_pages); return false; } ELFHeader* header = (ELFHeader*)elf_buffer; - printf("=== ELF DEBUG ===\n"); - printf("Entry point VA = 0x%lx\n", header->ProgramEntryPosition); - printf("PHDR offset = 0x%lx\n", header->ProgramHeaderTablePosition); - printf("PHDR count = %u\n", header->ProgramHeaderTableEntryCount); + printf("=== ELF DEBUG ===\n" + "Entry=0x%lx PHDR@0x%lx count=%u type=0x%x arch=0x%x\n" + "=== END ===\n", + header->ProgramEntryPosition, + header->ProgramHeaderTablePosition, + header->ProgramHeaderTableEntryCount, + header->Type, + header->InstructionSet); + if (memcmp(header->Magic, ELF_MAGIC, 4) != 0 || + header->Bitness != ELF_BITNESS_64BIT || + header->Endianness != ELF_ENDIANNESS_LITTLE || + (header->Type != ELF_TYPE_EXECUTABLE && header->Type != ELF_TYPE_SHARED) || + header->InstructionSet != ELF_INSTRUCTION_SET_X64) { - - printf("=== END ELF DEBUG ===\n"); - - // ── validate ELF ────────────────────────────────── - if (memcmp(header->Magic, ELF_MAGIC, 4) != 0) { - printf("ELF: bad magic\n"); - kfree(elf_buffer); - return false; - } - - if (header->Bitness != ELF_BITNESS_64BIT) { - printf("ELF: not 64-bit\n"); - kfree(elf_buffer); - return false; - } - - if (header->Endianness != ELF_ENDIANNESS_LITTLE) { - printf("ELF: wrong endianness\n"); - kfree(elf_buffer); - return false; - } - - if (header->Type != ELF_TYPE_EXECUTABLE) { - printf("ELF: not executable\n"); - kfree(elf_buffer); - return false; - } - - if (header->InstructionSet != ELF_INSTRUCTION_SET_X64) { - printf("ELF: wrong arch\n"); - kfree(elf_buffer); - return false; + printf("ELF: unsupported/invalid header\n"); + goto cleanup; } *entryPoint = (void*)header->ProgramEntryPosition; - // ── program headers ─────────────────────────────── + // ------------------------------------------------------------------ + // Parse program headers – LOAD, TLS, and PHDR + // ------------------------------------------------------------------ + uint64_t tls_vaddr = 0, tls_filesz = 0, tls_memsz = 0, tls_align = 8; + uint8_t* tls_src = NULL; + uint64_t phdr_vaddr = 0; + uint8_t* ph_table = elf_buffer + header->ProgramHeaderTablePosition; + uint64_t phdr_table_end = header->ProgramHeaderTablePosition + + (uint64_t)header->ProgramHeaderTableEntryCount * + header->ProgramHeaderTableEntrySize; - for (uint32_t i = 0; i < header->ProgramHeaderTableEntryCount; i++) - { - ELFProgramHeader* ph = (ELFProgramHeader*)(ph_table + - i * header->ProgramHeaderTableEntrySize); + if (phdr_table_end > file_size) { + printf("ELF: program header table extends beyond file\n"); + goto cleanup; + } - if (ph->Type != ELF_PROGRAM_TYPE_LOAD) { - printf("LOAD segment: VA=0x%lx FileSz=0x%lx MemSz=0x%lx\n", - ph->VirtualAddress, ph->FileSize, ph->MemorySize); + for (uint32_t i = 0; i < header->ProgramHeaderTableEntryCount; i++) { + ELFProgramHeader* ph = (ELFProgramHeader*)(ph_table + i * header->ProgramHeaderTableEntrySize); + + // PT_PHDR + if (ph->Type == ELF_PROGRAM_TYPE_PHDR) { + phdr_vaddr = ph->VirtualAddress; + printf("ELF: Found PT_PHDR VA=0x%lx\n", phdr_vaddr); + // fall through + } + + // PT_TLS + if (ph->Type == ELF_PROGRAM_TYPE_TLS) { + tls_vaddr = ph->VirtualAddress; + tls_filesz = ph->FileSize; + tls_memsz = ph->MemorySize; + tls_align = ph->Align ? ph->Align : 8; + tls_src = elf_buffer + ph->Offset; + + if (ph->Offset + ph->FileSize > file_size) { + printf("ELF: PT_TLS segment data out of file bounds\n"); + goto cleanup; + } + + printf("ELF: Found PT_TLS VA=0x%lx FileSz=0x%lx MemSz=0x%lx Align=0x%lx\n", + tls_vaddr, tls_filesz, tls_memsz, tls_align); continue; } - uint64_t virt = ph->VirtualAddress; - uint64_t offset = ph->Offset; - uint64_t memsz = ph->MemorySize; - uint64_t filesz = ph->FileSize; - - if (memsz == 0) + if (ph->Type != ELF_PROGRAM_TYPE_LOAD || ph->MemorySize == 0) continue; - // ── align to page boundary ───────────────────── - uint64_t aligned_virt = ALIGN_DOWN(virt, PAGE_SIZE); - uint64_t page_offset = virt & 0xFFF; - uint64_t aligned_memsz = ALIGN_UP(memsz + page_offset, PAGE_SIZE); - - uint64_t pages = aligned_memsz / PAGE_SIZE; - - // Allocate physical pages - uint64_t phys_base = (uint64_t)pmm_alloc(pages); - if (!phys_base) { - printf("ELF: pmm_alloc failed for %lu pages\n", pages); - kfree(elf_buffer); - return false; + if (ph->Offset + ph->FileSize > file_size) { + printf("ELF: PT_LOAD segment data out of file bounds\n"); + goto cleanup; + } + + // Map with exact permissions + uint64_t map_flags = PAGE_USER; + if (ph->Flags & PF_R) map_flags |= PAGE_READ; + if (ph->Flags & PF_W) map_flags |= PAGE_WRITE; + if (!(ph->Flags & PF_X)) map_flags |= PAGE_NO_EXECUTE; + + uint64_t virt = ph->VirtualAddress; + uint64_t aligned_virt = ALIGN_DOWN(virt, PAGE_SIZE); + uint64_t page_offset = virt & (PAGE_SIZE - 1); + uint64_t aligned_memsz = ALIGN_UP(ph->MemorySize + page_offset, PAGE_SIZE); + uint64_t pages = aligned_memsz / PAGE_SIZE; + + void* seg_phys = pmm_allocz(pages); + if (!seg_phys) { + printf("ELF: failed to allocate physical pages for LOAD segment\n"); + goto cleanup; } - // ── map each page individually using new vmm_map_page ───── for (uint64_t p = 0; p < pages; p++) { - uint64_t virt_addr = aligned_virt + p * PAGE_SIZE; - uint64_t phys_addr = phys_base + p * PAGE_SIZE; - - bool success = vmm_map_page( - target_pagemap, - virt_addr, - phys_addr, - PAGE_READ | PAGE_WRITE | PAGE_USER, // RW + User mode - Size4KiB - ); - - if (!success) { - printf("ELF: failed to map page at 0x%lx\n", virt_addr); - // TODO: cleanup previously mapped pages + free phys - kfree(elf_buffer); - return false; + if (!vmm_map_page(target_pagemap, + aligned_virt + p * PAGE_SIZE, + (uintptr_t)seg_phys + p * PAGE_SIZE, + map_flags, + Size4KiB)) { + pmm_free(seg_phys, pages); + goto cleanup; } } - // ── copy segment data ─────────────────────────────── - uint8_t* dst = (uint8_t*)(phys_base + MEM_PHYS_OFFSET); // via HHDM - uint8_t* src = elf_buffer + offset; - - memcpy(dst + page_offset, src, filesz); - - // ── zero BSS section ──────────────────────────────── - if (memsz > filesz) { - memset(dst + page_offset + filesz, 0, memsz - filesz); + uint8_t* dst = (uint8_t*)((uintptr_t)seg_phys + MEM_PHYS_OFFSET); + memcpy(dst + page_offset, elf_buffer + ph->Offset, ph->FileSize); + if (ph->MemorySize > ph->FileSize) { + memset(dst + page_offset + ph->FileSize, 0, + ph->MemorySize - ph->FileSize); } } - kfree(elf_buffer); + + uint64_t tls_size = tls_memsz ? ALIGN_UP(tls_memsz, tls_align) : 0ULL; + + uint64_t tcb_va = TLS_BASE_VA + PAGE_SIZE; + uint64_t tls_va = tcb_va - tls_size; + + uint64_t page_va = ALIGN_DOWN(tls_va, PAGE_SIZE); + uint64_t tcb_size = sizeof(TCB); + uint64_t block_end_va = tcb_va + tcb_size; + uint64_t block_end_page = ALIGN_UP(block_end_va, PAGE_SIZE); + uint64_t map_pages = ((block_end_page - page_va) / PAGE_SIZE) + 8; + if (map_pages == 0) map_pages = 1; + + void* tls_phys = pmm_allocz(map_pages); + if (!tls_phys) { + printf("ELF: failed to allocate TLS/TCB pages\n"); + goto cleanup; + } + + uint64_t tls_map_flags = PAGE_USER | PAGE_READ | PAGE_WRITE; + for (uint64_t p = 0; p < map_pages; p++) { + if (!vmm_map_page(target_pagemap, + page_va + p * PAGE_SIZE, + (uintptr_t)tls_phys + p * PAGE_SIZE, + tls_map_flags, + Size4KiB)) { + pmm_free(tls_phys, map_pages); + goto cleanup; + } + } + + uint8_t* base_hhdm = (uint8_t*)((uintptr_t)tls_phys + MEM_PHYS_OFFSET); + + if (tls_size > 0) { + uint8_t* tls_dst = base_hhdm + (tls_va - page_va); + if (tls_filesz) memcpy(tls_dst, tls_src, tls_filesz); + if (tls_memsz > tls_filesz) + memset(tls_dst + tls_filesz, 0, tls_memsz - tls_filesz); + } + + TCB* tcb = (TCB*)(base_hhdm + (tcb_va - page_va)); + memset(tcb, 0, sizeof(TCB)); + tcb->self = (void*)tcb_va; + tcb->tid = 1; + + *out_tls_fs_base = tcb_va; + + *out_phdr_va = tls_vaddr ? tls_vaddr : phdr_vaddr; + *out_phent = header->ProgramHeaderTableEntrySize; + *out_phnum = header->ProgramHeaderTableEntryCount; + + printf("ELF: TLS/TCB setup complete TCB@0x%lx TLS@0x%lx FS=0x%lx\n" + " PHDR@0x%lx PHENT=0x%x PHNUM=%u\n", + tcb_va, tls_va, tcb_va, *out_phdr_va, *out_phent, *out_phnum); + + pmm_free(buffer_phys, buf_pages); return true; + +cleanup: + pmm_free(buffer_phys, buf_pages); + return false; } \ No newline at end of file diff --git a/src/fs/elf.h b/src/fs/elf.h index 029eb8a..56f6cb1 100644 --- a/src/fs/elf.h +++ b/src/fs/elf.h @@ -1,11 +1,22 @@ +// elf.h #pragma once #include #include +#include // size_t for TCB #include "mm/vmm.h" +// ELF magic and basic constants #define ELF_MAGIC ("\x7F" "ELF") -#include +// Standard ELF program header flags (bitfield) +#define PF_X 0x00000001 // Execute +#define PF_W 0x00000002 // Write +#define PF_R 0x00000004 // Read + +// Fixed canonical address for the initial thread's TLS + TCB block. +// This lives in the upper half of the 47-bit user address space and +// will never overlap with normal LOAD segments (which are usually low). +#define TLS_BASE_VA 0x00007FFF00000000ULL typedef struct { @@ -18,13 +29,13 @@ typedef struct uint8_t _Padding[7]; uint16_t Type; // relocatable, executable, shared, core - uint16_t InstructionSet; // architecture (was too small for real ELF, but kept) + uint16_t InstructionSet; // architecture uint32_t ELFVersion; - uint64_t ProgramEntryPosition; // FIXED (was 32-bit) - uint64_t ProgramHeaderTablePosition; // FIXED - uint64_t SectionHeaderTablePosition; // FIXED + uint64_t ProgramEntryPosition; + uint64_t ProgramHeaderTablePosition; + uint64_t SectionHeaderTablePosition; uint32_t Flags; @@ -39,80 +50,81 @@ typedef struct enum ELFBitness { - ELF_BITNESS_32BIT = 1, - ELF_BITNESS_64BIT = 2, + ELF_BITNESS_32BIT = 1, + ELF_BITNESS_64BIT = 2, }; enum ELFEndianness { - ELF_ENDIANNESS_LITTLE = 1, - ELF_ENDIANNESS_BIG = 2, + ELF_ENDIANNESS_LITTLE = 1, + ELF_ENDIANNESS_BIG = 2, }; enum ELFInstructionSet { - ELF_INSTRUCTION_SET_NONE = 0, - ELF_INSTRUCTION_SET_X86 = 3, - ELF_INSTRUCTION_SET_ARM = 0x28, - ELF_INSTRUCTION_SET_X64 = 0x3E, - ELF_INSTRUCTION_SET_ARM64 = 0xB7, - ELF_INSTRUCTION_SET_RISCV = 0xF3, + ELF_INSTRUCTION_SET_NONE = 0, + ELF_INSTRUCTION_SET_X86 = 3, + ELF_INSTRUCTION_SET_ARM = 0x28, + ELF_INSTRUCTION_SET_X64 = 0x3E, + ELF_INSTRUCTION_SET_ARM64 = 0xB7, + ELF_INSTRUCTION_SET_RISCV = 0xF3, }; enum ELFType { - ELF_TYPE_RELOCATABLE = 1, - ELF_TYPE_EXECUTABLE = 2, - ELF_TYPE_SHARED = 3, - ELF_TYPE_CORE = 4, + ELF_TYPE_RELOCATABLE = 1, + ELF_TYPE_EXECUTABLE = 2, + ELF_TYPE_SHARED = 3, + ELF_TYPE_CORE = 4, }; typedef struct { uint32_t Type; + uint32_t Flags; uint64_t Offset; uint64_t VirtualAddress; uint64_t PhysicalAddress; uint64_t FileSize; uint64_t MemorySize; - uint32_t Flags; uint64_t Align; -} ELFProgramHeader; +} __attribute__((packed)) ELFProgramHeader; enum ELFProgramType { - // Program header table entry unused. - ELF_PROGRAM_TYPE_NULL = 0, + ELF_PROGRAM_TYPE_NULL = 0, + ELF_PROGRAM_TYPE_LOAD = 1, + ELF_PROGRAM_TYPE_DYNAMIC = 2, + ELF_PROGRAM_TYPE_INTERP = 3, + ELF_PROGRAM_TYPE_NOTE = 4, + ELF_PROGRAM_TYPE_SHLIB = 5, + ELF_PROGRAM_TYPE_PHDR = 6, + ELF_PROGRAM_TYPE_TLS = 7, - // Loadable segment. - ELF_PROGRAM_TYPE_LOAD = 1, - - // Dynamic linking information. - ELF_PROGRAM_TYPE_DYNAMIC = 2, - - // Interpreter information. - ELF_PROGRAM_TYPE_INTERP = 3, - - // Auxiliary information. - ELF_PROGRAM_TYPE_NOTE = 4, - - // Reserved - ELF_PROGRAM_TYPE_SHLIB = 5, - - // Segment containing program header table itself. - ELF_PROGRAM_TYPE_PHDR = 6, - - // Thread-Local Storage template. - ELF_PROGRAM_TYPE_TLS = 7, - - // Reserved inclusive range. Operating system specific. - ELF_PROGRAM_TYPE_LOOS = 0x60000000, - ELF_PROGRAM_TYPE_HIOS = 0x6FFFFFFF, - - // Reserved inclusive range. Processor specific. - ELF_PROGRAM_TYPE_LOPROC = 0x70000000, - ELF_PROGRAM_TYPE_HIPROC = 0x7FFFFFFF, + // OS/processor reserved ranges (we ignore them) + ELF_PROGRAM_TYPE_LOOS = 0x60000000, + ELF_PROGRAM_TYPE_HIOS = 0x6FFFFFFF, + ELF_PROGRAM_TYPE_LOPROC = 0x70000000, + ELF_PROGRAM_TYPE_HIPROC = 0x7FFFFFFF, }; +// Thread Control Block layout expected by mlibc. +// Only the fields mlibc actually reads are populated; the rest stay zero. +typedef struct { + void* self; // 0x00 fs:0 (TCB self-pointer) + size_t dtvSize; // 0x08 + void** dtvPointers; // 0x10 + int tid; // 0x18 + int didExit; // 0x1C + uint8_t padding[8]; // 0x20 + uintptr_t stackCanary; // 0x28 + int cancelBits; // 0x30 +} TCB; -bool ELF_Read(const char* path, void** entryPoint, struct pagemap *target_pagemap); \ No newline at end of file +bool ELF_Read(const char* path, + void** entryPoint, + struct pagemap *target_pagemap, + uint64_t *out_tls_fs_base, + uint64_t *out_phdr_va, // AT_PHDR + uint16_t *out_phent, // AT_PHENT + uint16_t *out_phnum); // AT_PHNUM \ No newline at end of file diff --git a/src/fs/ext2.c b/src/fs/ext2.c index 6d2132b..608af13 100644 --- a/src/fs/ext2.c +++ b/src/fs/ext2.c @@ -344,6 +344,8 @@ bool ext2_read_inode_internal(uint32_t inum, ext2_inode_t* out) { if (!ext2_read_block_raw(gdt[g].bg_inode_table + block_off, buf)) { kfree(buf); return false; } + printf("ext2_read_inode: inum=%u group=%u idx=%u block_off=%u inode_off=%u\n", + inum + 1, g, idx, block_off, inode_off); memcpy(out, buf + inode_off * sb.s_inode_size, sizeof(ext2_inode_t)); kfree(buf); return true; @@ -950,16 +952,21 @@ bool ext2_read_root_dir(void) { bool ext2_read_file_from_root_internal(const char* name, uint8_t* buf, uint32_t* size) { ext2_inode_t root; + printf("EXT2: reading file from root: %s\n", name); if (!ext2_read_inode_internal(2, &root)) return false; + printf("EXT2: root inode: size=%u blocks=%u\n", root.i_size, root.i_blocks); uint32_t inum; if (!ext2_find_in_dir_internal(&root, name, &inum)) { printf("EXT2: not found: %s\n", name); return false; } + printf("EXT2: found in root: inum=%u\n", inum); ext2_inode_t fi; if (!ext2_read_inode_internal(inum, &fi)) return false; + printf("EXT2: file inode: size=%u blocks=%u\n", fi.i_size, fi.i_blocks); *size = fi.i_size; + printf("EXT2: read file: size=%u\n", *size); return ext2_read_file_internal(&fi, buf); } diff --git a/src/libk/debug.c b/src/libk/debug.c index a97e43a..158ce3f 100644 --- a/src/libk/debug.c +++ b/src/libk/debug.c @@ -9,7 +9,7 @@ static const uint32_t g_LogSeverityColors[] = [LVL_INFO] = 0xFFFFFF, // white [LVL_WARN] = 0xFFFF00, // yellow [LVL_ERROR] = 0xFF0000, // red - [LVL_CRITICAL] = 0xFFFFFF, // white (can do red background separately if you want) + [LVL_CRITICAL] = 0xFFFFFF, // white }; diff --git a/src/libk/errno.h b/src/libk/errno.h new file mode 100644 index 0000000..c63fcab --- /dev/null +++ b/src/libk/errno.h @@ -0,0 +1,143 @@ +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again / resource temporarily unavailable */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter / inappropriate ioctl */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ + +#define EWOULDBLOCK EAGAIN /* Operation would block */ + +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK /* Alias for deadlock */ + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ + +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many libs */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ + +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ + +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported */ +#define ENOTSUP EOPNOTSUPP + +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ +#define ECANCELED 125 /* Operation canceled */ +#define ENOKEY 126 /* Required key not available */ +#define EKEYEXPIRED 127 /* Key has expired */ +#define EKEYREVOKED 128 /* Key has been revoked */ +#define EKEYREJECTED 129 /* Key was rejected by service */ + +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ +#define ERFKILL 132 /* Operation not possible due to RF-kill */ +#define EHWPOISON 133 /* Memory page has hardware error */ \ No newline at end of file diff --git a/src/libk/stdio.c b/src/libk/stdio.c index 257bb9a..8fd3e62 100644 --- a/src/libk/stdio.c +++ b/src/libk/stdio.c @@ -14,7 +14,7 @@ static const uint32_t g_LogSeverityColors[] = [LVL_INFO] = 0xFFFFFF, // white [LVL_WARN] = 0xFFFF00, // yellow [LVL_ERROR] = 0xFF0000, // red - [LVL_CRITICAL] = 0xFFFFFF, // white (can do red background separately if you want) + [LVL_CRITICAL] = 0xFFFFFF, // white }; static spinlock_t s_printf_lock = SPINLOCK_INIT; diff --git a/src/main.c b/src/main.c index decb2b1..7904ed9 100644 --- a/src/main.c +++ b/src/main.c @@ -98,6 +98,68 @@ static void hcf(void) { } } +static inline void cpuid(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) { + asm volatile ("cpuid" + : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) + : "a"(leaf), "c"(subleaf)); +} + +int cpu_has_leaf7() { + uint32_t a, b, c, d; + cpuid(0, 0, &a, &b, &c, &d); + return a >= 7; +} + +int cpu_has_fsgsbase() { + if (!cpu_has_leaf7()) + return 0; + + uint32_t a, b, c, d; + cpuid(7, 0, &a, &b, &c, &d); + + return (b & (1u << 0)) != 0; +} + +static inline uint64_t read_cr4(void) { + uint64_t val; + __asm__ volatile ("mov %%cr4, %0" : "=r"(val)); + return val; +} + + +static inline void write_cr4(uint64_t val) { + asm volatile ("mov %0, %%cr4" :: "r"(val)); +} + +static inline uint64_t read_cr0(void) { + uint64_t val; + __asm__ volatile ("mov %%cr0, %0" : "=r"(val)); + return val; +} + +static inline void write_cr0(uint64_t val) { + __asm__ volatile ("mov %0, %%cr0" :: "r"(val)); +} + + +#define CR4_FSGSBASE (1ULL << 16) + + + +void enable_fsgsbase_if_supported() { + if (!cpu_has_fsgsbase()) { + // fallback: don't use wrfsbase + printf("FSGSBASE not supported, skipping wrfsbase/wrgsbase\n"); + return; + } + + uint64_t cr4 = read_cr4(); + cr4 |= CR4_FSGSBASE; + write_cr4(cr4); +} + extern struct kernel_pagemap; uint64_t g_rsdp_phys; @@ -128,6 +190,31 @@ static uacpi_interrupt_ret handle_power_button(uacpi_handle ctx) { } + + + +void init_simd(void) { + uint64_t cr0 = read_cr0(); + uint64_t cr4 = read_cr4(); + + // --- CR0 setup --- + cr0 &= ~(1 << 2); // Clear EM (Emulation) → allow FPU/SSE + cr0 |= (1 << 1); // Set MP (Monitor Coprocessor) + cr0 &= ~(1 << 3); // Clear TS (Task Switched) → no #NM + + // --- CR4 setup --- + cr4 |= (1 << 9); // OSFXSR → enable FXSAVE/FXRSTOR + SSE + cr4 |= (1 << 10); // OSXMMEXCPT → enable SSE exceptions + + write_cr0(cr0); + write_cr4(cr4); + + // Initialize FPU/SSE state + __asm__ volatile ("fninit"); + +} + + void kmain(void) { if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) { hcf(); @@ -354,6 +441,9 @@ void kmain(void) { sched_init(); + enable_fsgsbase_if_supported(); + init_simd(); + start_userspace(); sched_yield(); diff --git a/src/mm/pmm.c b/src/mm/pmm.c index 175aac0..4c8f641 100644 --- a/src/mm/pmm.c +++ b/src/mm/pmm.c @@ -83,10 +83,20 @@ void *pmm_alloc(size_t pages) { void *pmm_allocz(size_t pages) { void *ret = pmm_alloc(pages); - - if (ret) { - memset((void *)((uintptr_t)ret + MEM_PHYS_OFFSET), 0, pages * PAGE_SIZE); // this is at fault for the page fault + if (!ret) return NULL; + + uintptr_t vaddr = (uintptr_t)ret + MEM_PHYS_OFFSET; + // Sanity: make sure we're not zeroing something ridiculous + if (vaddr < MEM_PHYS_OFFSET || vaddr > MEM_PHYS_OFFSET + 0x8000000000ULL) { + printf("PMM: allocz addr 0x%lx looks wrong!\n", vaddr); + pmm_free(ret, pages); + return NULL; } + + uint64_t *p = (uint64_t *)vaddr; + for (size_t i = 0; i < (pages * PAGE_SIZE) / 8; i++) + p[i] = 0; + return ret; } diff --git a/src/mm/slab.c b/src/mm/slab.c index 6e110c3..adf8c69 100644 --- a/src/mm/slab.c +++ b/src/mm/slab.c @@ -36,7 +36,7 @@ static inline struct slab *slab_for(size_t size) { static void create_slab(struct slab *slab, size_t ent_size) { spinlock_init(&slab->lock); - slab->first_free = (void **)((uint64_t)pmm_alloc(1) + MEM_PHYS_OFFSET); + slab->first_free = (void **)((uint64_t)pmm_allocz(1) + MEM_PHYS_OFFSET); slab->ent_size = ent_size; size_t header_offset = ALIGN_UP(sizeof(struct slab_header), ent_size); diff --git a/src/mm/vmm.c b/src/mm/vmm.c index 77eb8ca..70dff93 100644 --- a/src/mm/vmm.c +++ b/src/mm/vmm.c @@ -320,4 +320,13 @@ fail: spinlock_drop(&pagemap->lock); printf("Invalid Phys!\n"); return INVALID_PHYS; -} \ No newline at end of file +} + +uintptr_t find_free_vaddr(struct pagemap *pm, size_t len) { + // Very naive for now - start from a high address + static uintptr_t next = 0x700050000000ULL; + + uintptr_t addr = next; + next += ALIGN_UP(len, 0x1000000ULL); // 16 MiB alignment for simplicity + return addr; +} diff --git a/src/mm/vmm.h b/src/mm/vmm.h index 370cf7f..fe1850a 100644 --- a/src/mm/vmm.h +++ b/src/mm/vmm.h @@ -42,4 +42,6 @@ bool vmm_map_page(struct pagemap *pagemap, uint64_t virt, uint64_t phys, uint64_t flags, enum page_size pg_size); uint64_t vmm_virt_to_phys(struct pagemap *pagemap, uint64_t virt); uint64_t *vmm_virt_to_pte(struct pagemap *pagemap, uintptr_t virt_addr, - bool allocate); \ No newline at end of file + bool allocate); +bool vmm_unmap_page(struct pagemap *pagemap, uintptr_t virt, bool locked); +uintptr_t find_free_vaddr(struct pagemap *pm, size_t len); \ No newline at end of file diff --git a/src/mp/futex.c b/src/mp/futex.c new file mode 100644 index 0000000..2194166 --- /dev/null +++ b/src/mp/futex.c @@ -0,0 +1,84 @@ +#include "futex.h" +#include "mm/memory.h" +#include "string.h" +#include "sched/scheduler.h" +#include "libk/stdio.h" + +#define FUTEX_BUCKETS 256 + +struct futex_waiter { + task_t *task; + int *uaddr; + struct futex_waiter *next; +}; + +static struct futex_waiter *g_futex_table[FUTEX_BUCKETS]; + +static inline uint32_t futex_hash(int *uaddr) { + return ((uintptr_t)uaddr >> 3) & (FUTEX_BUCKETS - 1); +} + +int futex_wait(int *uaddr, int expected) +{ + if (!uaddr) return -1; + + /* 1. check value in user memory */ + if (*uaddr != expected) + return -1; + + uint32_t h = futex_hash(uaddr); + + struct futex_waiter *w = kmalloc(sizeof(*w)); + if (!w) return -1; + + w->task = sched_current(); + w->uaddr = uaddr; + + /* 2. insert into bucket */ + w->next = g_futex_table[h]; + g_futex_table[h] = w; + + /* 3. block task */ + sched_block(TASK_INTERRUPTIBLE); + + return 0; +} + +int futex_wake(int *uaddr, int count) +{ + if (!uaddr || count <= 0) + return 0; + + uint32_t h = futex_hash(uaddr); + + struct futex_waiter **prev = &g_futex_table[h]; + struct futex_waiter *cur = g_futex_table[h]; + + int woken = 0; + + while (cur && woken < count) { + if (cur->uaddr == uaddr) { + + task_t *task = cur->task; + + /* remove from list */ + *prev = cur->next; + + struct futex_waiter *tmp = cur; + cur = cur->next; + + kfree(tmp); + + /* wake task */ + sched_wake(task); + + woken++; + continue; + } + + prev = &cur->next; + cur = cur->next; + } + + return woken; +} diff --git a/src/mp/futex.h b/src/mp/futex.h new file mode 100644 index 0000000..c673b1c --- /dev/null +++ b/src/mp/futex.h @@ -0,0 +1,10 @@ +#pragma once +#include +#include +#include "sched/scheduler.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +int futex_wait(int *uaddr, int expected); +int futex_wake(int *uaddr, int count); \ No newline at end of file diff --git a/src/sched/scheduler.c b/src/sched/scheduler.c index fa4cd02..3d87a41 100644 --- a/src/sched/scheduler.c +++ b/src/sched/scheduler.c @@ -6,6 +6,8 @@ #include "arch/x86_64/sys/pit.h" #include "string.h" +#define IA32_FS_BASE 0xC0000100 + /* ===================================================================== * Forward declarations for GDT/TSS (defined in gdt.c) * ===================================================================== */ @@ -329,43 +331,22 @@ static void kthread_trampoline(void) { sched_exit(0); } -static void user_task_trampoline(void) { - x86_64_EnableInterrupts(); +void set_fs_base(uint64_t base) { + /* ake sure the address is canonical (bits 63..48 all 0 or all 1). + * Non-canonical FS base + any fs: access from user code = #GP. */ + uint64_t high = base >> 48; + if (high != 0 && high != 0xFFFFULL) { + /* Simple sign-extension from bit 47 (common for user-space TLS) */ + if (base & (1ULL << 47)) + base |= 0xFFFFULL << 48; /* negative canonical */ + else + base &= (1ULL << 48) - 1; /* positive canonical */ + } - task_t *self = g_current_task; - - /* - * Build an iretq frame on the current (kernel) stack and enter - * user mode. We reset the stack pointer to the very top of the - * kernel stack first, so the iretq frame doesn't sit below a - * pile of stale context-switch frames. - * - * Segment selectors (from your GDT / STAR setup): - * User CS = 0x23 (GDT index 4, RPL 3) - * User SS = 0x1B (GDT index 3, RPL 3) - */ - uint64_t kstack_top = (uint64_t)self->kernel_stack + self->kernel_stack_size; - uint64_t user_rip = self->user_entry; - uint64_t user_rsp = self->user_stack_top; - - asm volatile( - "movq %0, %%rsp\n\t" /* Reset kernel RSP to stack top */ - "pushq $0x1B\n\t" /* SS – user data segment */ - "pushq %1\n\t" /* RSP – user stack pointer */ - "pushfq\n\t" /* RFLAGS */ - "orq $0x200, (%%rsp)\n\t" /* Set IF so user code runs with */ - /* interrupts enabled */ - "pushq $0x23\n\t" /* CS – user code segment */ - "pushq %2\n\t" /* RIP – user entry point */ - "iretq\n\t" - : - : "r"(kstack_top), "r"(user_rsp), "r"(user_rip) - : "memory" - ); - - __builtin_unreachable(); + asm volatile("wrfsbase %0" : : "r"(base) : "memory"); } + /* ===================================================================== * Kernel stack setup for a new task * @@ -444,13 +425,18 @@ task_t *sched_create_kthread(const char *name, task->vruntime = g_runqueue.min_vruntime; sched_enqueue(task); - printf("[sched] kthread '%s' pid=%d created\n", task->name, task->pid); + //printf("[sched] kthread '%s' pid=%d created\n", task->name, task->pid); return task; } task_t *sched_create_user_task(const char *name, - uint64_t entry_rip, uint64_t user_rsp, - struct pagemap *pm) + uint64_t entry_rip, + uint64_t user_rsp, + struct pagemap *pm, + uint64_t tls_fs_base, + uint64_t phdr_va, + uint16_t phent, + uint16_t phnum) { task_t *task = alloc_task(name, true); if (!task) return NULL; @@ -458,8 +444,11 @@ task_t *sched_create_user_task(const char *name, task->pagemap = pm; task->user_entry = entry_rip; task->user_stack_top= user_rsp; + task->tls_fs_base = tls_fs_base; + task->phdr_va = phdr_va; + task->phent = phent; + task->phnum = phnum; - /* CR3 = physical address of PML4 */ task->ctx.cr3 = (uint64_t)pm->top_level - MEM_PHYS_OFFSET; setup_initial_kstack(task, user_task_trampoline); @@ -467,9 +456,11 @@ task_t *sched_create_user_task(const char *name, task->time_slice = calc_timeslice(task); task->vruntime = g_runqueue.min_vruntime; + for (size_t i = 256; i < 512; i++) { + pm->top_level[i] = kernel_pagemap->top_level[i]; + } + sched_enqueue(task); - printf("[sched] user task '%s' pid=%d created, entry=0x%lx\n", - task->name, task->pid, entry_rip); return task; } @@ -556,6 +547,15 @@ void schedule(void) { task_t *prev = g_runqueue.current; task_t *next = pick_next_task(&g_runqueue); + if (next->is_user) { + if (next->tls_fs_base != 0) { + set_fs_base(next->tls_fs_base); + } else { + printf("Warning: user task '%s' has no TLS FS base set; leaving FS at 0\n", next->name); + } + + } + if (next == prev || next == NULL) { /* Nothing to switch to; keep running current task. */ spinlock_drop(&g_runqueue.lock); @@ -600,6 +600,11 @@ void schedule(void) { spinlock_drop(&g_runqueue.lock); /* ---- Context switch -------------------------------------------- */ + //printf("[sched] switching from '%s' (pid=%d) to '%s' (pid=%d)\n", + // prev->name, prev->pid, next->name, next->pid); + if (next->is_user) { + //printf("switching to user task, fs_base=0x%lx\n", next->tls_fs_base); + } sched_context_switch(&prev->ctx, &next->ctx); /* @@ -705,8 +710,8 @@ void sched_exit(int exit_code) { if (self->parent) task_send_signal(self->parent, SIGCHLD); - printf("[sched] task '%s' pid=%d exited with code %d\n", - self->name, self->pid, exit_code); + //printf("[sched] task '%s' pid=%d exited with code %d\n", + // self->name, self->pid, exit_code); /* Hand off to someone else; we will never return. */ schedule(); @@ -791,65 +796,55 @@ void task_handle_pending_signals(void) { task_t *self = g_current_task; if (!self) return; + /* Only run signal handling when we are about to return to user mode. + * Kernel threads can still get synchronous handlers, but we avoid + * unnecessary work / possible recursion on kernel tasks. */ + if (!self->is_user && !(self->pending_signals & ~self->signal_mask)) + return; + while (self->pending_signals & ~self->signal_mask) { - /* Find the lowest-numbered pending, unblocked signal */ uint64_t deliverable = self->pending_signals & ~self->signal_mask; - int signum = __builtin_ctzll(deliverable) + 1; /* +1: bit 0 = sig 1 */ + int signum = __builtin_ctzll(deliverable) + 1; if (signum >= _NSIG) break; - /* Clear the pending bit */ self->pending_signals &= ~(1ULL << (signum - 1)); sighandler_t handler = self->sigactions[signum].sa_handler; if (handler == SIG_IGN) { - /* Explicitly ignored */ - if (signum == SIGCHLD) continue; /* common: reap silently */ + if (signum == SIGCHLD) continue; continue; + } - } else if (handler != SIG_DFL) { - /* - * User-defined handler. - * - * A full POSIX implementation would build a signal frame on - * the user stack and set registers so that iretq delivers - * the signal; that requires knowing the saved RFLAGS/RIP - * from the ISR frame. We leave this as a TODO and just - * call the handler directly for kernel threads. - * - * For user tasks this is the point where you would push a - * ucontext_t / sigframe onto the user stack and adjust the - * saved user RIP in the ISR frame. - */ + if (handler != SIG_DFL) { if (!self->is_user) { - handler(signum); + handler(signum); /* kernel thread */ } else { - /* TODO: build user-space signal frame */ - printf("[signal] TODO: deliver signal %d to user task '%s'\n", - signum, self->name); + /* TODO: proper sigframe + adjust trap frame on kernel stack */ + printf("[signal] TODO: deliver signal %d to user task '%s' (pid=%d)\n", + signum, self->name, self->pid); + /* For now fall through to default action so we don't silently ignore */ } + } - } else { - /* SIG_DFL */ + /* Default action (also used for user tasks when no handler is installed) */ + if (handler == SIG_DFL || self->is_user) { switch (default_action(signum)) { case SIG_ACTION_TERM: case SIG_ACTION_CORE: printf("[signal] task '%s' pid=%d killed by signal %d\n", self->name, self->pid, signum); - sched_exit(128 + signum); - break; /* unreachable */ + sched_exit(128 + signum); /* does not return */ + break; case SIG_ACTION_STOP: self->state = TASK_STOPPED; - /* Notify parent */ - if (self->parent) task_send_signal(self->parent, SIGCHLD); - sched_block(TASK_STOPPED); + if (self->parent) + task_send_signal(self->parent, SIGCHLD); + sched_block(TASK_STOPPED); /* does not return until CONT */ break; case SIG_ACTION_CONT: - /* Already running (we were woken to handle this) */ - break; - case SIG_ACTION_IGN: break; } diff --git a/src/sched/scheduler.h b/src/sched/scheduler.h index dd2fd28..2ebde48 100644 --- a/src/sched/scheduler.h +++ b/src/sched/scheduler.h @@ -160,6 +160,10 @@ struct task { uint64_t user_stack_top; /* User-space RSP for user tasks */ void (*kthread_entry)(void *arg); /* Kernel thread entry point */ void *kthread_arg; + uint64_t tls_fs_base; /* FS base for user tasks (TLS support) */ + uint64_t phdr_va; + uint16_t phent; + uint16_t phnum; /* ---- Signals ----------------------------------------------------- */ uint64_t pending_signals; /* Bitmask of unhandled signals */ @@ -248,8 +252,14 @@ task_t *sched_create_kthread(const char *name, /* Create a user-space task and enqueue it immediately */ task_t *sched_create_user_task(const char *name, - uint64_t entry_rip, uint64_t user_rsp, - struct pagemap *pm); + uint64_t entry_rip, + uint64_t user_rsp, + struct pagemap *pm, + uint64_t tls_fs_base, + uint64_t phdr_va, + uint16_t phent, + uint16_t phnum); + /* Add a task to the appropriate run queue */ void sched_enqueue(task_t *task); @@ -308,5 +318,9 @@ static inline task_t *sched_current(void) { return g_current_task; } void sched_context_switch(struct cpu_context *from, struct cpu_context *to); +void set_fs_base(uint64_t base); + +extern void user_task_trampoline(void); /* Defined in user_task_trampoline.S */ + /* Kernel stack size for each task */ #define KSTACK_SIZE (32 * 1024) /* 32 KiB — comfortable headroom */ \ No newline at end of file diff --git a/src/sched/user_task_trampoline.S b/src/sched/user_task_trampoline.S new file mode 100644 index 0000000..462ec34 --- /dev/null +++ b/src/sched/user_task_trampoline.S @@ -0,0 +1,118 @@ + +/* ── struct task offsets ─────────────────────────────────────────────────── */ +.equ TASK_KERNEL_STACK, 160 +.equ TASK_KERNEL_STACK_SIZE, 168 +.equ TASK_USER_ENTRY, 176 +.equ TASK_USER_STACK_TOP, 184 +.equ TASK_TLS_FS_BASE, 208 + +.equ TASK_PHDR_VA, 216 +.equ TASK_PHENT, 224 +.equ TASK_PHNUM, 226 + +/* ── GDT selectors ───────────────────────────────────────────────────────── */ +.equ SEL_USER_DS, 0x1B /* ring-3 data (index 3, RPL 3) */ +.equ SEL_USER_CS, 0x23 /* ring-3 code (index 4, RPL 3) */ + +/* ── ELF auxiliary-vector types ──────────────────────────────────────────── */ +.equ AT_NULL, 0 +.equ AT_PAGESZ, 6 +.equ AT_ENTRY, 9 +.equ AT_PHDR, 3 +.equ AT_PHENT, 4 +.equ AT_PHNUM, 5 +.equ AT_BASE, 7 + +/* ═══════════════════════════════════════════════════════════════════════════ + * user_task_trampoline + * ═══════════════════════════════════════════════════════════════════════════ */ +.section .text +.global user_task_trampoline +.type user_task_trampoline, @function + +user_task_trampoline: + movq g_current_task(%rip), %rbx + + /* ── TLS FS base ───────────────────────────────────────────────────── */ + movq TASK_TLS_FS_BASE(%rbx), %rdi + testq %rdi, %rdi + jz .Lno_tls + call set_fs_base + movq g_current_task(%rip), %rbx + +.Lno_tls: +/* ── Stash values we need after we switch stacks ───────────────────── */ + movq TASK_USER_STACK_TOP(%rbx), %r15 + movq TASK_USER_ENTRY(%rbx), %r14 + movq TASK_KERNEL_STACK(%rbx), %r13 + addq TASK_KERNEL_STACK_SIZE(%rbx), %r13 + + /* ── Load auxv values ──────── */ + movq TASK_PHDR_VA(%rbx), %r11 + movzwq TASK_PHENT(%rbx), %r10 + movzwq TASK_PHNUM(%rbx), %r9 + + /* ── Build initial user stack ─────────────────────── */ + /* program name string */ + movabsq $0x726f776f6c6c6568, %rax + movq %rax, -0x20(%r15) + movabsq $0x000000000000646c, %rax + movq %rax, -0x18(%r15) + + /* argc / argv / envp */ + movq $1, -0xB0(%r15) /* argc = 1 */ + leaq -0x20(%r15), %rax + movq %rax, -0xA8(%r15) /* argv[0] */ + movq $0, -0xA0(%r15) + movq $0, -0x98(%r15) /* envp[0] = NULL */ + + /* auxv */ + movq $AT_PAGESZ, -0x90(%r15) + movq $4096, -0x88(%r15) + + movq $AT_ENTRY, -0x80(%r15) + movq %r14, -0x78(%r15) + + movq $AT_PHDR, -0x70(%r15) + movq %r11, -0x68(%r15) + + movq $AT_PHENT, -0x60(%r15) + movq %r10, -0x58(%r15) + + movq $AT_PHNUM, -0x50(%r15) + movq %r9, -0x48(%r15) + + movq $AT_BASE, -0x40(%r15) + movq $0, -0x38(%r15) + + movq $AT_NULL, -0x30(%r15) + movq $0, -0x28(%r15) + + leaq -0xB0(%r15), %r12 /* user RSP */ + + /* ── Pivot to kernel stack top and build iretq frame ──────────────── */ + movq %r13, %rsp + + pushq $SEL_USER_DS + pushq %r12 + pushfq + orq $0x200, (%rsp) + pushq $SEL_USER_CS + pushq %r14 + + /* Zero GPRs */ + xorq %rax, %rax + xorq %rbx, %rbx + xorq %rcx, %rcx + xorq %rdx, %rdx + xorq %rsi, %rsi + xorq %rdi, %rdi + xorq %rbp, %rbp + xorq %r8, %r8 + xorq %r9, %r9 + xorq %r10, %r10 + xorq %r11, %r11 + + iretq + +.size user_task_trampoline, . - user_task_trampoline \ No newline at end of file diff --git a/src/syscall/syscall.c b/src/syscall/syscall.c index fe6ddca..6a8d628 100644 --- a/src/syscall/syscall.c +++ b/src/syscall/syscall.c @@ -4,12 +4,18 @@ #include "fs/vfs.h" #include "syscall.h" #include "sched/scheduler.h" +#include "mm/vmm.h" +#include "mm/pmm.h" +#include "mm/memory.h" +#include "libk/errno.h" +#include "mp/futex.h" #define MSR_EFER 0xC0000080 #define MSR_STAR 0xC0000081 #define MSR_LSTAR 0xC0000082 #define MSR_SFMASK 0xC0000084 #define MSR_KERNEL_GSBASE 0xC0000102 +#define MSR_KERNEL_FSBASE 0xC0000100 #define EFER_SCE (1 << 0) @@ -76,6 +82,76 @@ uint64_t syscall_handler(uint64_t num, case SYS_EXIT_GROUP: sched_exit((int)arg1); //noreturn + + case SYS_MMAP: + { + uintptr_t addr = (uintptr_t)arg1; + size_t len = (size_t)arg2; + int prot = (int)arg3; + int flags = (int)arg4; + int fd = (int)arg5; + off_t offset = (off_t)arg6; + + (void)fd; (void)offset; // we only support anonymous for now + + if (len == 0) + return (uint64_t)MAP_FAILED; + + len = ALIGN_UP(len, PAGE_SIZE); + + if (!(flags & MAP_ANONYMOUS)) { + return (uint64_t)MAP_FAILED; // todo: file backed later + } + + struct pagemap *pm = sched_current()->pagemap; + if (!pm) pm = kernel_pagemap; + + if (!(flags & MAP_FIXED)) { + addr = find_free_vaddr(pm, len); + } + + uint64_t vmm_flags = PAGE_USER | PAGE_READ; + if (prot & PROT_WRITE) vmm_flags |= PAGE_WRITE; + if (prot & PROT_EXEC) vmm_flags |= PAGE_NO_EXECUTE; + + size_t page_count = len / PAGE_SIZE; + void *phys = pmm_allocz(page_count); + if (!phys) { + return (uint64_t)MAP_FAILED; + } + + // Map them + for (size_t i = 0; i < page_count; i++) { + uint64_t va = addr + i * PAGE_SIZE; + uint64_t pa = (uint64_t)phys + i * PAGE_SIZE; + if (!vmm_map_page(pm, va, pa, vmm_flags | PAGE_USER, Size4KiB)) { + pmm_free(phys, page_count); + return (uint64_t)MAP_FAILED; + } + } + + return addr; + } + + case SYS_MUNMAP: + { + uintptr_t addr = (uintptr_t)arg1; + size_t len = (size_t)arg2; + + if (len == 0 || addr == 0) + return 0; + + len = ALIGN_UP(len, PAGE_SIZE); + + struct pagemap *pm = sched_current()->pagemap ?: kernel_pagemap; + + for (size_t i = 0; i < len; i += PAGE_SIZE) { + vmm_unmap_page(pm, addr + i, false); + // TODO: also free the physical page (will need page refcounting or virt_to_phys + pmm_free) + } + + return 0; + } case SYS_SCHED_YIELD: sched_yield(); @@ -159,8 +235,39 @@ uint64_t syscall_handler(uint64_t num, return (uint64_t)task_set_scheduler(t, policy, rt_prio); } + case SYS_TCB_SET: + { + void *pointer = (void*)arg1; + if (pointer == NULL) { + return (uint64_t)-EINVAL; + } + + set_fs_base((uint64_t)pointer); + return 0; + } + + case SYS_FUTEX: + { + int *uaddr = (int*)arg1; + int op = (int)arg2; + int val = (int)arg3; + + switch (op) { + case FUTEX_WAIT: + return (uint64_t)futex_wait(uaddr, val); + case FUTEX_WAKE: + return (uint64_t)futex_wake(uaddr, val); + default: + return -EINVAL; + } + } + default: - return (uint64_t)-1; + { + printf("Unknown syscall: %lu\n", num); + return (uint64_t)-ENOSYS; + } + } } diff --git a/src/syscall/syscall.h b/src/syscall/syscall.h index a10f903..dced74c 100644 --- a/src/syscall/syscall.h +++ b/src/syscall/syscall.h @@ -1,22 +1,46 @@ #pragma once -#define SYS_READ 0 -#define SYS_WRITE 1 -#define SYS_OPEN 2 -#define SYS_CLOSE 3 - -#define SYS_SCHED_YIELD 24 -#define SYS_GETPID 39 -#define SYS_GETPPID 110 -#define SYS_NICE 34 -#define SYS_KILL 62 +#define SYS_READ 0 +#define SYS_WRITE 1 +#define SYS_OPEN 2 +#define SYS_CLOSE 3 +#define SYS_MMAP 9 +#define SYS_MUNMAP 11 +#define SYS_BRK 12 #define SYS_SIGACTION 13 /* rt_sigaction on Linux */ #define SYS_SIGPROCMASK 14 /* rt_sigprocmask on Linux */ +#define SYS_SCHED_YIELD 24 +#define SYS_GETPID 39 + +#define SYS_NICE 34 +#define SYS_FORK 57 +#define SYS_EXECVE 59 #define SYS_EXIT 60 -#define SYS_EXIT_GROUP 231 +#define SYS_KILL 62 + +#define SYS_GETPPID 110 #define SYS_SCHED_GETSCHEDULER 138 #define SYS_SCHED_SETSCHEDULER 139 +#define SYS_FUTEX 202 +#define SYS_EXIT_GROUP 231 +#define SYS_TCB_SET 300 + +typedef int64_t off_t; + + +// Memory protection flags (Linux compatible) +#define PROT_NONE 0x0 +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define PROT_EXEC 0x4 + +// mmap flags +#define MAP_PRIVATE 0x02 +#define MAP_SHARED 0x01 +#define MAP_ANONYMOUS 0x20 +#define MAP_FIXED 0x10 +#define MAP_FAILED ((void*)-1) void syscall_init(void); \ No newline at end of file diff --git a/user/include/mlibc/ABI_BREAKS.md b/user/include/mlibc/ABI_BREAKS.md new file mode 100644 index 0000000..0dd2a63 --- /dev/null +++ b/user/include/mlibc/ABI_BREAKS.md @@ -0,0 +1,33 @@ +# ABI Breaks + +This document lists the ABI breaks that were made in each mlibc major version. + +## Version 5, 6 + +Numerous ABI breaks. These were not properly logged, and are therefore missing here. Pending update, if one ever comes. + +## Version 4 + +- [#814](https://github.com/managarm/mlibc/pull/814): `struct timex`'s `long int tai` changed to the correct `int tai`, and `int __padding[11]` got appended to the struct. +- [#816](https://github.com/managarm/mlibc/pull/816): `sys_wait4` on Linux now correctly returns a `pid_t`, not an `int` as previously. +- [#816](https://github.com/managarm/mlibc/pull/816): All `MS_*` macros of the `sys/mount.h` header were adjusted to match linux. +- [#816](https://github.com/managarm/mlibc/pull/816): `struct epoll_event` now gets correctly packed on `x86_64`. +- [#819](https://github.com/managarm/mlibc/pull/819): `str(n)dupa` is now defined as a pure macro, and not as a macro that points to a function. +- [#828](https://github.com/managarm/mlibc/pull/828): Linux-specific functions previously included in the posix option in `pthreads.h` and `sched.h` are not correctly guarded behind the linux option. +- [#828](https://github.com/managarm/mlibc/pull/828): The `CPU_*` macros of `sched.h` have been rewritten to resolve to internal mlibc implementations, and are now correctly guarded behind the linux option. +- [#735](https://github.com/managarm/mlibc/pull/735): `sched_getcpu` and `setns` were previously mistakenly C++-mangled and not declared, which has now been rectified. + +## Version 3 + +- [#728](https://github.com/managarm/mlibc/pull/728): + The macros `CMSG_{LEN,SPACE,DATA}` were not accounting for padding between + `struct cmsghdr` and it's respective data. This manifested itself as some + parts of control data being skipped on platforms where `struct cmsghdr` is + not divisible by `alignof(size_t)`. +- [#452](https://github.com/managarm/mlibc/pull/452): The functions `FD_{CLR,ISSET,SET,ZERO}` were renamed to `__FD_{CLR,ISSET,SET,ZERO}` and replaced by macros to match Wine's assumptions. +- [#511](https://github.com/managarm/mlibc/pull/511): Musl's regex engine was added, implementing `regcomp` and `regexec`. This required some changes to the `regex_t` struct. +- [#504](https://github.com/managarm/mlibc/pull/504): In the Linux ABI, a `domainname` member was added to `struct utsname`, which is a glibc extension. +- [#311](https://github.com/managarm/mlibc/pull/311): Added all necessary fields in `pthread_attr_t` required for implementing all `pthread_attr` functions. +- [#652](https://github.com/managarm/mlibc/pull/652): The ABI of `struct statfs` and `struct statvfs` was changed to match Linux. `socklen_t` was also changed from `unsigned long` to `unsigned int`. +- [#658](https://github.com/managarm/mlibc/pull/648): In the Linux ABI, `cc_t` was changed from an `unsigned int` to an `unsigned char`. +- [#679](https://github.com/managarm/mlibc/pull/679): The `struct glob_t` received some additional members to bring it up to par with glibc. diff --git a/user/include/mlibc/LICENSE b/user/include/mlibc/LICENSE new file mode 100644 index 0000000..16ab10b --- /dev/null +++ b/user/include/mlibc/LICENSE @@ -0,0 +1,45 @@ +Copyright (C) 2015-2025 mlibc Contributors + +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. + +---- + +Some parts of mlibc are adapted from musl (http://www.musl-libc.org/), which +is licensed as follows: + +Copyright © 2005-2020 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. diff --git a/user/include/mlibc/README.md b/user/include/mlibc/README.md new file mode 100644 index 0000000..711d9d2 --- /dev/null +++ b/user/include/mlibc/README.md @@ -0,0 +1,71 @@ +# mlibc + +mlibc is a fully featured C standard library designed with portability in mind. + +We support a number of architectures (x86-64, AArch64, RISC-V, IA-32, m68k, LoongArch64), and provide a clean syscall abstraction layer for new operating system ports to plug into. + +Unlike other portable C standard libraries like newlib, we aim for feature parity with glibc/musl, i.e full pthread support and GNU extensions. + +mlibc is capable enough to run a range of software, including Xorg, several Wayland compositors, Mesa, and web browsers like WebKitGTK -- though some features are still missing. + +Individual operating systems can opt in or out of certain features as desired; for example POSIX APIs like `pthread` are gated behind the POSIX 'option', Linux APIs like `epoll` are gated behind the Linux option, etc. + +![Continuous Integration](https://github.com/managarm/mlibc/workflows/Continuous%20Integration/badge.svg) + +**Official Discord server:** https://discord.gg/7WB6Ur3 + +**AUR package** (provides `mlibc-gcc`): https://aur.archlinux.org/packages/mlibc + +## Design of the library + +| Directory | Purpose | +| --- | --- | +| `options/` | (More or less) OS-independent headers and code.
`options/` is divided into subdirectories that can be enabled or disabled by ports.| +| `sysdeps/` | OS-specific headers and code.
`sysdeps/` is divided into per-port subdirectories. Exactly one of those subdirectories is enabled in each build.| +| `abis/` | OS-specific interface headers ("ABI headers"). Those contain the constants and structs of the OS interface. For example, the numerical values of `SEEK_SET` or `O_CREAT` live here, as well as structs like `struct stat`. ABI headers are _only_ allowed to contain constants, structs and unions but _no_ function declarations or logic.
`abis/` is divided into per-OS subdirectories but this division is for organizational purposes only. Ports can still mix headers from different `abis/` subdirectories.| + +## Porting mlibc to a new OS + +Ports to new OSes are welcome. To port mlibc to another OS, the following changes need to be made: +1. Add new `sysdeps/` subdirectory `sysdeps/some-new-os/` and a `meson.build` to compile it. Integrate `sysdeps/some-new-os/meson.build` into the toplevel `meson.build`. +2. Create ABI headers in `abis/some-new-os/`. Add symlinks in `sysdeps/some-new-os/include/abi-bits` to your ABI headers. Look at existing ports to figure out the ABI headers required for the options enabled by `sysdeps/some-new-os/meson.build`. +3. In `sysdeps/some-new-os/`, add code to implement (a subset of) the functions from `options/internal/include/mlibc/internal-sysdeps.hpp`. Which subset you need depends on the options that `sysdeps/some-new-os/meson.build` enables. + +We recommend that new ports do not build from `master` as we occasionally make internal changes that cause out-of-tree sysdeps to break. Instead we recommend you pin a specific release (or commit), or to upstream your changes to this repository so that we can build them on our CI and thus any breakages will be fixed by us in-tree. + +## Build Configuration + +The following custom meson options are accepted, in addition to the [built-in options](https://mesonbuild.com/Builtin-options.html). The options below are booleans which default to false (see `meson_options.txt`). + +- `headers_only`: Only install headers; don't build `libc.so` or `ld.so`. +- `no_headers`: Don't install headers; only build `libc.so` and `ld.so`. +- `build_tests`: Build the test suite (see below). +- `x_option`: Enable `x` component of mlibc functionality. See `meson_options.txt` for a full list of possible values for `x`. This may be used to e.g disable POSIX and glibc extensions. +- `linux_kernel_headers`: Allows for directing mlibc to installed linux headers. [These can be obtained easily](https://docs.kernel.org/kbuild/headers_install.html), placed in a directory and this option set to the corresponding path. This is required if the linux option is enabled, i.e. when the linux option is not disabled. +- `debug_allocator`: Replace the normal allocator with a debug allocator (see `mlibc/options/internal/generic/allocator.cpp` for implementation details). +- `use_freestnd_hdrs`: Use freestnd-c{,xx}-hdrs instead of looking for compiler headers. Useful if not using a compiler with the correct target triple. + +The type of library to be built (static, shared, or both) is controlled by meson's `default_library` option. Passing `-Ddefault_library=static` effectively disables the dynamic linker. + +We also support building with `-Db_sanitize=undefined` to use UBSan inside mlibc. Note that this does not enable UBSan for external applications which link against `libc.so`, but it can be useful during development to detect internal bugs (e.g when adding new sysdeps). + +## Running pre-commit hooks + +To format your code before submitting a PR, you should install [`pre-commit`](https://pre-commit.com/). Then do `pre-commit install` to install the git hook which runs each time you commit. Alternatively, you can do `pre-commit run -a` to manually format all files. + +## Running Tests + +The `mlibc` test suite can be run under a Linux host. To do this, first install a set of Linux kernel headers (as described [here](https://docs.kernel.org/kbuild/headers_install.html)). + +A convenience script is provided to download and install the Linux kernel headers into a local `linux-headers` directory: +``` +./scripts/get-linux-headers.sh +``` +Then run from the project root: +``` +meson setup -Dbuild_tests=true -Dlinux_kernel_headers=./linux-headers build +``` +This will create a `build` directory. Then, `cd build` and run the tests (showing output) with: +``` +meson test -v +``` diff --git a/user/include/mlibc/RELEASE_PROCEDURE.md b/user/include/mlibc/RELEASE_PROCEDURE.md new file mode 100644 index 0000000..2792408 --- /dev/null +++ b/user/include/mlibc/RELEASE_PROCEDURE.md @@ -0,0 +1,33 @@ +# Release Procedure + +mlibc uses [semantic versioning v2.0.0](https://semver.org/spec/v2.0.0.html) to denote releases. + +In short: +- A bump in the major version signals an ABI or API break, or otherwise any other major change +involving compatibility breakage. +- A bump in the minor version signals a newly released set of features, while still maintaining +compatibility. +- A bump in the patch signals a bug-fix, while not adding new features. + +The `master` branch is where active development occurs, and where PRs get merged into. Changes +that are deemed appropriate to be backported to a major version branch (including the current, +latest major version branch) are cherry-picked there. + +Releases are tagged off of their respective major version branches once they are ready. + +Major versions get a new, dedicated branch, which is created from `master` when deemed +necessary, usually shortly before the tagging of the first release in the new major version +branch. This branch is called `vN.x`, where `N` is the number of the major version +(and `x` is just a literal "x"). + +Submodules are fixed to specific commits when a major version branch is created. + +The first tag on the major version branch is the `vN.0.0` release. + +Minor versions and patch versions are tagged on their respective major version branches +after the necessary commits are backported onto said branch from `master`. + +## ABI_BREAKS.md + +The `ABI_BREAKS.md` file should be updated in `master` alongside any newly merged commit that +does break ABI, in order to keep track of these changes. diff --git a/user/include/mlibc/abis/aero/access.h b/user/include/mlibc/abis/aero/access.h new file mode 100644 index 0000000..984bbed --- /dev/null +++ b/user/include/mlibc/abis/aero/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 1 +#define R_OK 2 +#define W_OK 4 +#define X_OK 8 + +#endif /* _ABIBITS_ACCESS_H */ diff --git a/user/include/mlibc/abis/aero/auxv.h b/user/include/mlibc/abis/aero/auxv.h new file mode 100644 index 0000000..d46348d --- /dev/null +++ b/user/include/mlibc/abis/aero/auxv.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_EXECPATH 15 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 + +#endif /* _ABIBITS_AUXV_H */ diff --git a/user/include/mlibc/abis/aero/blkcnt_t.h b/user/include/mlibc/abis/aero/blkcnt_t.h new file mode 100644 index 0000000..1222088 --- /dev/null +++ b/user/include/mlibc/abis/aero/blkcnt_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +/* TODO: use int64_t? */ +typedef long blkcnt_t; + +#endif /* _ABIBITS_BLKCNT_T_H */ diff --git a/user/include/mlibc/abis/aero/blksize_t.h b/user/include/mlibc/abis/aero/blksize_t.h new file mode 100644 index 0000000..e4c9f3f --- /dev/null +++ b/user/include/mlibc/abis/aero/blksize_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +/* TODO: use int64_t? */ +typedef long blksize_t; + +#endif /* _ABIBITS_BLKSIZE_T_H */ + diff --git a/user/include/mlibc/abis/aero/clockid_t.h b/user/include/mlibc/abis/aero/clockid_t.h new file mode 100644 index 0000000..c3932ef --- /dev/null +++ b/user/include/mlibc/abis/aero/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef long clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/user/include/mlibc/abis/aero/dev_t.h b/user/include/mlibc/abis/aero/dev_t.h new file mode 100644 index 0000000..16ccd69 --- /dev/null +++ b/user/include/mlibc/abis/aero/dev_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +typedef unsigned long dev_t; + +#endif /* _ABIBITS_DEV_T_H */ + diff --git a/user/include/mlibc/abis/aero/epoll.h b/user/include/mlibc/abis/aero/epoll.h new file mode 100644 index 0000000..71ec2d5 --- /dev/null +++ b/user/include/mlibc/abis/aero/epoll.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_EPOLL_H +#define _ABIBITS_EPOLL_H + +#define EPOLL_CLOEXEC 1 + +#endif /* _ABIBITS_EPOLL_H */ diff --git a/user/include/mlibc/abis/aero/errno.h b/user/include/mlibc/abis/aero/errno.h new file mode 100644 index 0000000..b621828 --- /dev/null +++ b/user/include/mlibc/abis/aero/errno.h @@ -0,0 +1,126 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EDOM 1 +#define EILSEQ 2 +#define ERANGE 3 + +#define E2BIG 1001 +#define EACCES 1002 +#define EADDRINUSE 1003 +#define EADDRNOTAVAIL 1004 +#define EAFNOSUPPORT 1005 +#define EAGAIN 1006 +#define EALREADY 1007 +#define EBADF 1008 +#define EBADMSG 1009 +#define EBUSY 1010 +#define ECANCELED 1011 +#define ECHILD 1012 +#define ECONNABORTED 1013 +#define ECONNREFUSED 1014 +#define ECONNRESET 1015 +#define EDEADLK 1016 +#define EDESTADDRREQ 1017 +#define EDQUOT 1018 +#define EEXIST 1019 +#define EFAULT 1020 +#define EFBIG 1021 +#define EHOSTUNREACH 1022 +#define EIDRM 1023 +#define EINPROGRESS 1024 +#define EINTR 1025 +#define EINVAL 1026 +#define EIO 1027 +#define EISCONN 1028 +#define EISDIR 1029 +#define ELOOP 1030 +#define EMFILE 1031 +#define EMLINK 1032 +#define EMSGSIZE 1034 +#define EMULTIHOP 1035 +#define ENAMETOOLONG 1036 +#define ENETDOWN 1037 +#define ENETRESET 1038 +#define ENETUNREACH 1039 +#define ENFILE 1040 +#define ENOBUFS 1041 +#define ENODEV 1042 +#define ENOENT 1043 +#define ENOEXEC 1044 +#define ENOLCK 1045 +#define ENOLINK 1046 +#define ENOMEM 1047 +#define ENOMSG 1048 +#define ENOPROTOOPT 1049 +#define ENOSPC 1050 +#define ENOSYS 1051 +#define ENOTCONN 1052 +#define ENOTDIR 1053 +#define ENOTEMPTY 1054 +#define ENOTRECOVERABLE 1055 +#define ENOTSOCK 1056 +#define ENOTSUP 1057 +#define ENOTTY 1058 +#define ENXIO 1059 +#define EOPNOTSUPP 1060 +#define EOVERFLOW 1061 +#define EOWNERDEAD 1062 +#define EPERM 1063 +#define EPIPE 1064 +#define EPROTO 1065 +#define EPROTONOSUPPORT 1066 +#define EPROTOTYPE 1067 +#define EROFS 1068 +#define ESPIPE 1069 +#define ESRCH 1070 +#define ESTALE 1071 +#define ETIMEDOUT 1072 +#define ETXTBSY 1073 +#define EWOULDBLOCK EAGAIN +#define EXDEV 1075 +#define ENODATA 1076 +#define ETIME 1077 +#define ENOKEY 1078 +#define ESHUTDOWN 1079 +#define EHOSTDOWN 1080 +#define EBADFD 1081 +#define ENOMEDIUM 1082 +#define ENOTBLK 1083 +#define ENONET 1084 +#define EPFNOSUPPORT 1085 +#define ESOCKTNOSUPPORT 1086 +#define ESTRPIPE 1087 +#define EREMOTEIO 1088 +#define ERFKILL 1089 +#define EBADR 1090 +#define EUNATCH 1091 +#define EMEDIUMTYPE 1092 +#define EREMOTE 1093 +#define EKEYREJECTED 1094 +#define EUCLEAN 1095 +#define EBADSLT 1096 +#define ENOANO 1097 +#define ENOCSI 1098 +#define ENOSTR 1099 +#define ETOOMANYREFS 1100 +#define ENOPKG 1101 +#define EKEYREVOKED 1102 +#define EXFULL 1103 +#define ELNRNG 1104 +#define ENOTUNIQ 1105 +#define ERESTART 1106 +#define EUSERS 1107 +#define ECHRNG 1108 +#define ELIBBAD 1109 +#define EL2HLT 1110 +#define EL3HLT 1111 +#define EKEYEXPIRED 1112 +#define ECOMM 1113 +#define EBADE 1114 +#define EHWPOISON 1115 +#define EBADRQC 1116 + +#define EIEIO 1524152434 + +#endif /* _ABIBITS_ERRNO_H */ diff --git a/user/include/mlibc/abis/aero/gid_t.h b/user/include/mlibc/abis/aero/gid_t.h new file mode 100644 index 0000000..f513e25 --- /dev/null +++ b/user/include/mlibc/abis/aero/gid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif /* _ABIBITS_GID_T_H */ + diff --git a/user/include/mlibc/abis/aero/in.h b/user/include/mlibc/abis/aero/in.h new file mode 100644 index 0000000..3b4df5b --- /dev/null +++ b/user/include/mlibc/abis/aero/in.h @@ -0,0 +1,169 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t pad[8]; +}; +#define sin_zero pad /* for BSD Unix compatibility */ + +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + unsigned int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +#define IPPROTO_IP 1 +#define IPPROTO_IPV6 2 +#define IPPROTO_ICMP 3 +#define IPPROTO_RAW 4 +#define IPPROTO_TCP 5 +#define IPPROTO_UDP 6 +#define IPPROTO_IGMP 7 +#define IPPROTO_IPIP 8 +#define IPPROTO_DCCP 33 +#define IPPROTO_ROUTING 43 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MAX 256 + +#define INADDR_ANY ((in_addr_t)0x00000000) +#define INADDR_BROADCAST ((in_addr_t)0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t)0x7f000001) +#define INADDR_NONE ((in_addr_t)0xffffffff) + +#define INET_ADDRSTRLEN 16 + +#define INET6_ADDRSTRLEN 46 + +#define IPV6_JOIN_GROUP 1 +#define IPV6_LEAVE_GROUP 2 +#define IPV6_MULTICAST_HOPS 3 +#define IPV6_MULTICAST_IF 4 +#define IPV6_MULTICAST_LOOP 5 +#define IPV6_UNICAST_HOPS 6 +#define IPV6_V6ONLY 7 +#define IPV6_PMTUDISC_DONT 8 +#define IPV6_PMTUDISC_DO 9 +#define IPV6_MTU 10 +#define IPV6_2292PKTOPTIONS 11 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_RECVERR 25 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_TCLASS 67 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_OPTIONS 4 +#define IP_PMTUDISC_OMIT 5 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_UNICAST_IF 13 +#define IP_MTU 14 + +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_DO 2 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#endif /* _ABIBITS_IN_H */ diff --git a/user/include/mlibc/abis/aero/ino_t.h b/user/include/mlibc/abis/aero/ino_t.h new file mode 100644 index 0000000..049e16e --- /dev/null +++ b/user/include/mlibc/abis/aero/ino_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +/* TODO: use (u)int64_t? */ +typedef long ino_t; + +#endif /* _ABIBITS_INO_T_H */ + diff --git a/user/include/mlibc/abis/aero/inotify.h b/user/include/mlibc/abis/aero/inotify.h new file mode 100644 index 0000000..f30a0bc --- /dev/null +++ b/user/include/mlibc/abis/aero/inotify.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_INOTIFY_H +#define _ABIBITS_INOTIFY_H + +#define IN_CLOEXEC 1 +#define IN_NONBLOCK 2 + +#endif /* _ABIBITS_INOTIFY_H */ diff --git a/user/include/mlibc/abis/aero/ipc.h b/user/include/mlibc/abis/aero/ipc.h new file mode 100644 index 0000000..5507c55 --- /dev/null +++ b/user/include/mlibc/abis/aero/ipc.h @@ -0,0 +1,51 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + short __ipc_perm_seq; + short __pad; + unsigned long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/abis/aero/limits.h b/user/include/mlibc/abis/aero/limits.h new file mode 100644 index 0000000..9c7bdf1 --- /dev/null +++ b/user/include/mlibc/abis/aero/limits.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 + +/* Niceness related */ +#define NZERO 20 + +/* Maximum hostname length, posix defines it as 255 */ +#define HOST_NAME_MAX 255 + +#define OPEN_MAX 256 + +#endif /*_ABIBITS_LIMITS_H */ diff --git a/user/include/mlibc/abis/aero/mode_t.h b/user/include/mlibc/abis/aero/mode_t.h new file mode 100644 index 0000000..b1a11f3 --- /dev/null +++ b/user/include/mlibc/abis/aero/mode_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef int mode_t; + +#endif /* _ABIBITS_MODE_T_H */ + diff --git a/user/include/mlibc/abis/aero/nlink_t.h b/user/include/mlibc/abis/aero/nlink_t.h new file mode 100644 index 0000000..49c7e0f --- /dev/null +++ b/user/include/mlibc/abis/aero/nlink_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef int nlink_t; + +#endif /* _ABIBITS_NLINK_T_H */ + diff --git a/user/include/mlibc/abis/aero/packet.h b/user/include/mlibc/abis/aero/packet.h new file mode 100644 index 0000000..ae4b92e --- /dev/null +++ b/user/include/mlibc/abis/aero/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif /* _ABIBITS_PACKET_H */ diff --git a/user/include/mlibc/abis/aero/pid_t.h b/user/include/mlibc/abis/aero/pid_t.h new file mode 100644 index 0000000..9591edb --- /dev/null +++ b/user/include/mlibc/abis/aero/pid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif /* _ABIBITS_PID_T_H */ + diff --git a/user/include/mlibc/abis/aero/poll.h b/user/include/mlibc/abis/aero/poll.h new file mode 100644 index 0000000..c2ef284 --- /dev/null +++ b/user/include/mlibc/abis/aero/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x01 +#define POLLOUT 0x02 +#define POLLPRI 0x04 +#define POLLHUP 0x08 +#define POLLERR 0x10 +#define POLLRDHUP 0x20 +#define POLLNVAL 0x40 +#define POLLWRNORM 0x80 +#define POLLRDNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLRDBAND 0x400 + +#endif /* _ABIBITS_POLL_H */ diff --git a/user/include/mlibc/abis/aero/ptrace.h b/user/include/mlibc/abis/aero/ptrace.h new file mode 100644 index 0000000..158bf67 --- /dev/null +++ b/user/include/mlibc/abis/aero/ptrace.h @@ -0,0 +1,56 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 14 +#define PTRACE_SETREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_GETFPREGS 20 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_CE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif /* _ABIBITS_PTRACE_H */ diff --git a/user/include/mlibc/abis/aero/random.h b/user/include/mlibc/abis/aero/random.h new file mode 100644 index 0000000..8e9fe26 --- /dev/null +++ b/user/include/mlibc/abis/aero/random.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_RANDOM_H +#define _ABIBITS_RANDOM_H + +#define GRND_RANDOM 1 +#define GRND_NONBLOCK 2 + +#endif /* _ABIBITS_RANDOM_H */ diff --git a/user/include/mlibc/abis/aero/resource.h b/user/include/mlibc/abis/aero/resource.h new file mode 100644 index 0000000..6cb82b2 --- /dev/null +++ b/user/include/mlibc/abis/aero/resource.h @@ -0,0 +1,53 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 1 +#define RUSAGE_CHILDREN 2 + +#define RLIMIT_CORE 1 +#define RLIMIT_CPU 2 +#define RLIMIT_DATA 3 +#define RLIMIT_FSIZE 4 +#define RLIMIT_NOFILE 5 +#define RLIMIT_STACK 6 +#define RLIMIT_AS 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_RSS 9 +#define RLIMIT_NPROC 10 +#define RLIMIT_LOCKS 11 +#define RLIMIT_SIGPENDING 12 +#define RLIMIT_MSGQUEUE 13 +#define RLIMIT_NICE 14 +#define RLIMIT_RTPRIO 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long int ru_maxrss; + long int ru_ixrss; + long int ru_idrss; + long int ru_isrss; + long int ru_minflt; + long int ru_majflt; + long int ru_nswap; + long int ru_inblock; + long int ru_oublock; + long int ru_msgsnd; + long int ru_msgrcv; + long int ru_nsignals; + long int ru_nvcsw; + long int ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RESOURCE_H */ diff --git a/user/include/mlibc/abis/aero/rlim_t.h b/user/include/mlibc/abis/aero/rlim_t.h new file mode 100644 index 0000000..68cfcf5 --- /dev/null +++ b/user/include/mlibc/abis/aero/rlim_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +typedef unsigned long long rlim_t; + +#endif /* _ABIBITS_RLIM_T_H */ diff --git a/user/include/mlibc/abis/aero/seek-whence.h b/user/include/mlibc/abis/aero/seek-whence.h new file mode 100644 index 0000000..4d986e9 --- /dev/null +++ b/user/include/mlibc/abis/aero/seek-whence.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 3 +#define SEEK_DATA 4 +#define SEEK_HOLE 5 + +#endif /* _ABIBITS_SEEK_WHENCE_H */ diff --git a/user/include/mlibc/abis/aero/shm.h b/user/include/mlibc/abis/aero/shm.h new file mode 100644 index 0000000..d435691 --- /dev/null +++ b/user/include/mlibc/abis/aero/shm.h @@ -0,0 +1,84 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; +}; + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/user/include/mlibc/abis/aero/socket.h b/user/include/mlibc/abis/aero/socket.h new file mode 100644 index 0000000..d7754f4 --- /dev/null +++ b/user/include/mlibc/abis/aero/socket.h @@ -0,0 +1,165 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t)]; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +/*MISSING: CMSG_DATA, CMSG_NXTHDR, CMSG_FIRSTHDR */ + +#define SCM_CREDENTIALS 0x02 + +#define SOCK_DGRAM 1 +#define SOCK_RAW 2 +#define SOCK_SEQPACKET 3 +#define SOCK_STREAM 4 +#define SOCK_DCCP 5 +#define SOCK_NONBLOCK 0x10000 +#define SOCK_CLOEXEC 0x20000 +#define SOCK_RDM 0x40000 + +#define SOL_SOCKET 1 +#define SOL_IPV6 41 +#define SOL_PACKET 263 +#define SOL_NETLINK 270 + +#define SO_ACCEPTCONN 1 +#define SO_BROADCAST 2 +#define SO_DEBUG 3 +#define SO_DONTROUTE 4 +#define SO_ERROR 5 +#define SO_KEEPALIVE 6 +#define SO_LINGER 7 +#define SO_OOBINLINE 8 +#define SO_RCVBUF 9 +#define SO_RCVLOWAT 10 +#define SO_RCVTIMEO 11 +#define SO_REUSEADDR 12 +#define SO_SNDBUF 13 +#define SO_SNDLOWAT 14 +#define SO_SNDTIMEO 15 +#define SO_TYPE 16 +#define SO_SNDBUFFORCE 17 +#define SO_PEERCRED 18 +#define SO_ATTACH_FILTER 19 +#define SO_PASSCRED 20 +#define SO_RCVBUFFORCE 21 +#define SO_DETACH_FILTER 22 +#define SO_PROTOCOL 23 +#define SO_REUSEPORT 24 +#define SO_TIMESTAMP 25 +#define SO_PEERSEC 26 +#define SO_BINDTODEVICE 27 +#define SO_DOMAIN 28 +#define SO_PASSSEC 29 +#define SO_TIMESTAMPNS 30 +#define SO_PRIORITY 31 +#define SO_MARK 32 + +#define SOMAXCONN 1 + +#define MSG_CTRUNC 0x1 +#define MSG_DONTROUTE 0x2 +#define MSG_EOR 0x4 +#define MSG_OOB 0x8 +#define MSG_NOSIGNAL 0x10 +#define MSG_PEEK 0x20 +#define MSG_TRUNC 0x40 +#define MSG_WAITALL 0x80 +#define MSG_FIN 0x200 +#define MSG_CONFIRM 0x800 + +/* Linux extensions. */ +#define MSG_DONTWAIT 0x1000 +#define MSG_CMSG_CLOEXEC 0x2000 +#define MSG_MORE 0x4000 +#define MSG_FASTOPEN 0x20000000 + +/* GNU (?) extension: Protocol family constants. */ + +#define PF_INET 1 +#define PF_INET6 2 +#define PF_UNIX 3 +#define PF_LOCAL 3 +#define PF_UNSPEC 4 +#define PF_NETLINK 5 +#define PF_BRIDGE 6 +#define PF_APPLETALK 7 +#define PF_BLUETOOTH 8 +#define PF_DECnet 9 +#define PF_IPX 10 +#define PF_ISDN 11 +#define PF_SNA 12 +#define PF_PACKET 13 +#define PF_AX25 14 +#define PF_NETROM 15 +#define PF_ROSE 16 +#define PF_TIPC 30 +#define PF_ALG 38 +#define PF_MAX 46 + +#define AF_INET PF_INET +#define AF_INET6 PF_INET6 +#define AF_UNIX PF_UNIX +#define AF_LOCAL PF_LOCAL +#define AF_UNSPEC PF_UNSPEC +#define AF_NETLINK PF_NETLINK +#define AF_BRIDGE PF_BRIDGE +#define AF_APPLETALK PF_APPLETALK +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_DECnet PF_DECnet +#define AF_IPX PF_IPX +#define AF_ISDN PF_ISDN +#define AF_SNA PF_SNA +#define AF_PACKET PF_PACKET +#define AF_PACKET PF_PACKET +#define AF_AX25 PF_AX25 +#define AF_NETROM PF_NETROM +#define AF_ROSE PF_ROSE +#define AF_TIPC PF_TIPC +#define AF_ALG PF_ALG +#define AF_MAX PF_MAX + +#define SHUT_RD 1 +#define SHUT_RDWR 2 +#define SHUT_WR 3 +#endif diff --git a/user/include/mlibc/abis/aero/time.h b/user/include/mlibc/abis/aero/time.h new file mode 100644 index 0000000..dfc342e --- /dev/null +++ b/user/include/mlibc/abis/aero/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif /* _ABIBITS_TIME_H */ diff --git a/user/include/mlibc/abis/aero/uid_t.h b/user/include/mlibc/abis/aero/uid_t.h new file mode 100644 index 0000000..976540b --- /dev/null +++ b/user/include/mlibc/abis/aero/uid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif /* _ABIBITS_UID_T_H */ + diff --git a/user/include/mlibc/abis/aero/vm-flags.h b/user/include/mlibc/abis/aero/vm-flags.h new file mode 100644 index 0000000..769275a --- /dev/null +++ b/user/include/mlibc/abis/aero/vm-flags.h @@ -0,0 +1,46 @@ +#ifndef _ABIBITS_MMAP_FLAGS_H +#define _ABIBITS_MMAP_FLAGS_H + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_PRIVATE 0x01 +#define MAP_SHARED 0x02 +#define MAP_FIXED 0x04 +#define MAP_ANON 0x08 +#define MAP_ANONYMOUS 0x08 +#define MAP_NORESERVE 0x10 +#define MAP_FIXED_NOREPLACE 0x20 + +#define MS_ASYNC 0x01 +#define MS_SYNC 0x02 +#define MS_INVALIDATE 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_RANDOM 3 +#define POSIX_MADV_DONTNEED 4 +#define POSIX_MADV_WILLNEED 5 + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 + +/* Linux extensions: */ +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U + +#endif /* _ABIBITS_MMAP_FLAGS_H */ diff --git a/user/include/mlibc/abis/astral/ipc.h b/user/include/mlibc/abis/astral/ipc.h new file mode 100644 index 0000000..5507c55 --- /dev/null +++ b/user/include/mlibc/abis/astral/ipc.h @@ -0,0 +1,51 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + short __ipc_perm_seq; + short __pad; + unsigned long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/abis/astral/random.h b/user/include/mlibc/abis/astral/random.h new file mode 100644 index 0000000..8e9fe26 --- /dev/null +++ b/user/include/mlibc/abis/astral/random.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_RANDOM_H +#define _ABIBITS_RANDOM_H + +#define GRND_RANDOM 1 +#define GRND_NONBLOCK 2 + +#endif /* _ABIBITS_RANDOM_H */ diff --git a/user/include/mlibc/abis/astral/rlim_t.h b/user/include/mlibc/abis/astral/rlim_t.h new file mode 100644 index 0000000..68cfcf5 --- /dev/null +++ b/user/include/mlibc/abis/astral/rlim_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +typedef unsigned long long rlim_t; + +#endif /* _ABIBITS_RLIM_T_H */ diff --git a/user/include/mlibc/abis/astral/shm.h b/user/include/mlibc/abis/astral/shm.h new file mode 100644 index 0000000..d435691 --- /dev/null +++ b/user/include/mlibc/abis/astral/shm.h @@ -0,0 +1,84 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; +}; + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/user/include/mlibc/abis/dripos/access.h b/user/include/mlibc/abis/dripos/access.h new file mode 100644 index 0000000..984bbed --- /dev/null +++ b/user/include/mlibc/abis/dripos/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 1 +#define R_OK 2 +#define W_OK 4 +#define X_OK 8 + +#endif /* _ABIBITS_ACCESS_H */ diff --git a/user/include/mlibc/abis/dripos/auxv.h b/user/include/mlibc/abis/dripos/auxv.h new file mode 100644 index 0000000..4e93ed3 --- /dev/null +++ b/user/include/mlibc/abis/dripos/auxv.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 + +#endif diff --git a/user/include/mlibc/abis/dripos/blkcnt_t.h b/user/include/mlibc/abis/dripos/blkcnt_t.h new file mode 100644 index 0000000..1222088 --- /dev/null +++ b/user/include/mlibc/abis/dripos/blkcnt_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +/* TODO: use int64_t? */ +typedef long blkcnt_t; + +#endif /* _ABIBITS_BLKCNT_T_H */ diff --git a/user/include/mlibc/abis/dripos/blksize_t.h b/user/include/mlibc/abis/dripos/blksize_t.h new file mode 100644 index 0000000..e4c9f3f --- /dev/null +++ b/user/include/mlibc/abis/dripos/blksize_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +/* TODO: use int64_t? */ +typedef long blksize_t; + +#endif /* _ABIBITS_BLKSIZE_T_H */ + diff --git a/user/include/mlibc/abis/dripos/clockid_t.h b/user/include/mlibc/abis/dripos/clockid_t.h new file mode 100644 index 0000000..c3932ef --- /dev/null +++ b/user/include/mlibc/abis/dripos/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef long clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/user/include/mlibc/abis/dripos/dev_t.h b/user/include/mlibc/abis/dripos/dev_t.h new file mode 100644 index 0000000..16ccd69 --- /dev/null +++ b/user/include/mlibc/abis/dripos/dev_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +typedef unsigned long dev_t; + +#endif /* _ABIBITS_DEV_T_H */ + diff --git a/user/include/mlibc/abis/dripos/epoll.h b/user/include/mlibc/abis/dripos/epoll.h new file mode 100644 index 0000000..71ec2d5 --- /dev/null +++ b/user/include/mlibc/abis/dripos/epoll.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_EPOLL_H +#define _ABIBITS_EPOLL_H + +#define EPOLL_CLOEXEC 1 + +#endif /* _ABIBITS_EPOLL_H */ diff --git a/user/include/mlibc/abis/dripos/errno.h b/user/include/mlibc/abis/dripos/errno.h new file mode 100644 index 0000000..0375024 --- /dev/null +++ b/user/include/mlibc/abis/dripos/errno.h @@ -0,0 +1,149 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* Input/output error */ +#define ENXIO 6 /* Device not configured */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EDEADLK 11 /* Resource deadlock avoided */ + /* 11 was EAGAIN */ + +#define ENOMEM 12 /* Cannot allocate memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ + +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device busy */ + +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* Operation not supported by device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ + +#define ETXTBSY 26 /* Text file busy */ + +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ + +/* math software */ +#define EDOM 33 /* Numerical argument out of domain */ +#define ERANGE 34 /* Result too large */ + +/* non-blocking and interrupt i/o */ +#define EAGAIN 35 /* Resource temporarily unavailable */ + +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported on socket */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Connection timed out */ +#define ECONNREFUSED 61 /* Connection refused */ + +#define ELOOP 62 /* Too many levels of symbolic links */ + +#define ENAMETOOLONG 63 /* File name too long */ + +/* should be rearranged */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ + +/* quotas & mush */ +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ + +/* Network File System */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ + + +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ + +#define EFTYPE 79 /* Inappropriate file type or format */ +#define EOVERFLOW 80 +#define EILSEQ 81 + +#define EBADMSG 82 +#define ECANCELED 83 +#define EIDRM 84 +#define EMULTIHOP 85 +#define ENOLINK 86 +#define ENOMSG 87 +#define ENOTRECOVERABLE 88 +#define ENOTSUP 89 +#define EOWNERDEAD 90 +#define EPROTO 91 +#define ENODATA 92 +#define ETIME 93 +#define ENOKEY 94 +#define EBADFD 95 +#define ENOMEDIUM 96 +#define ENONET 97 +#define ESTRPIPE 98 +#define EREMOTEIO 99 +#define ERFKILL 100 +#define EBADR 101 +#define EUNATCH 102 +#define EMEDIUMTYPE 103 +#define EKEYREJECTED 104 +#define EUCLEAN 105 +#define EBADSLT 106 +#define ENOANO 107 +#define ENOCSI 108 +#define ENOSTR 109 +#define ENOPKG 110 +#define EKEYREVOKED 111 +#define EXFULL 112 +#define ELNRNG 113 +#define ENOTUNIQ 114 +#define ERESTART 115 +#define ENOTSUP 116 + +#endif diff --git a/user/include/mlibc/abis/dripos/fcntl.h b/user/include/mlibc/abis/dripos/fcntl.h new file mode 100644 index 0000000..e61b32c --- /dev/null +++ b/user/include/mlibc/abis/dripos/fcntl.h @@ -0,0 +1,85 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +/* reserve 3 bits for the access mode */ +#define O_ACCMODE 0x0007 +#define O_EXEC 1 +#define O_RDONLY 2 +#define O_RDWR 3 +#define O_SEARCH 4 +#define O_WRONLY 5 + +/* these flags get their own bit */ +#define O_APPEND 0x000008 +#define O_CREAT 0x000010 +#define O_DIRECTORY 0x000020 +#define O_EXCL 0x000040 +#define O_NOCTTY 0x000080 +#define O_NOFOLLOW 0x000100 +#define O_TRUNC 0x000200 +#define O_NONBLOCK 0x000400 +#define O_DSYNC 0x000800 +#define O_RSYNC 0x001000 +#define O_SYNC 0x002000 +#define O_CLOEXEC 0x004000 +#define O_PATH 0x008000 +#define O_LARGEFILE 0x010000 +#define O_NOATIME 0x020000 +#define O_ASYNC 0x040000 +#define O_TMPFILE 0x080000 +#define O_DIRECT 0x100000 + +/* constants for fcntl()'s command argument */ +#define F_DUPFD 1 +#define F_DUPFD_CLOEXEC 2 +#define F_GETFD 3 +#define F_SETFD 4 +#define F_GETFL 5 +#define F_SETFL 6 +#define F_GETLK 7 +#define F_SETLK 8 +#define F_SETLK64 F_SETLK +#define F_SETLKW 9 +#define F_SETLKW64 F_SETLKW +#define F_GETOWN 10 +#define F_SETOWN 11 + +/* constants for struct flock's l_type member */ +#define F_RDLCK 1 +#define F_UNLCK 2 +#define F_WRLCK 3 + +/* constants for fcntl()'s additional argument of F_GETFD and F_SETFD */ +#define FD_CLOEXEC 1 + +/* Used by mmap */ +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 +#define F_SEAL_SEAL 0x0010 +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define AT_EMPTY_PATH 1 +#define AT_SYMLINK_FOLLOW 2 +#define AT_SYMLINK_NOFOLLOW 4 +#define AT_REMOVEDIR 8 +#define AT_EACCESS 512 +#define AT_NO_AUTOMOUNT 1024 +#define AT_STATX_SYNC_AS_STAT 0 +#define AT_STATX_FORCE_SYNC 2048 +#define AT_STATX_DONT_SYNC 4096 +#define AT_STATX_SYNC_TYPE 6144 + +#define AT_FDCWD -100 + +#define POSIX_FADV_NORMAL 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_NOREUSE 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_WILLNEED 5 +#define POSIX_FADV_RANDOM 6 + +#endif /* _ABITBITS_FCNTL_H */ diff --git a/user/include/mlibc/abis/dripos/gid_t.h b/user/include/mlibc/abis/dripos/gid_t.h new file mode 100644 index 0000000..f513e25 --- /dev/null +++ b/user/include/mlibc/abis/dripos/gid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif /* _ABIBITS_GID_T_H */ + diff --git a/user/include/mlibc/abis/dripos/in.h b/user/include/mlibc/abis/dripos/in.h new file mode 100644 index 0000000..3b4df5b --- /dev/null +++ b/user/include/mlibc/abis/dripos/in.h @@ -0,0 +1,169 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t pad[8]; +}; +#define sin_zero pad /* for BSD Unix compatibility */ + +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + unsigned int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +#define IPPROTO_IP 1 +#define IPPROTO_IPV6 2 +#define IPPROTO_ICMP 3 +#define IPPROTO_RAW 4 +#define IPPROTO_TCP 5 +#define IPPROTO_UDP 6 +#define IPPROTO_IGMP 7 +#define IPPROTO_IPIP 8 +#define IPPROTO_DCCP 33 +#define IPPROTO_ROUTING 43 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MAX 256 + +#define INADDR_ANY ((in_addr_t)0x00000000) +#define INADDR_BROADCAST ((in_addr_t)0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t)0x7f000001) +#define INADDR_NONE ((in_addr_t)0xffffffff) + +#define INET_ADDRSTRLEN 16 + +#define INET6_ADDRSTRLEN 46 + +#define IPV6_JOIN_GROUP 1 +#define IPV6_LEAVE_GROUP 2 +#define IPV6_MULTICAST_HOPS 3 +#define IPV6_MULTICAST_IF 4 +#define IPV6_MULTICAST_LOOP 5 +#define IPV6_UNICAST_HOPS 6 +#define IPV6_V6ONLY 7 +#define IPV6_PMTUDISC_DONT 8 +#define IPV6_PMTUDISC_DO 9 +#define IPV6_MTU 10 +#define IPV6_2292PKTOPTIONS 11 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_RECVERR 25 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_TCLASS 67 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_OPTIONS 4 +#define IP_PMTUDISC_OMIT 5 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_UNICAST_IF 13 +#define IP_MTU 14 + +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_DO 2 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#endif /* _ABIBITS_IN_H */ diff --git a/user/include/mlibc/abis/dripos/ino_t.h b/user/include/mlibc/abis/dripos/ino_t.h new file mode 100644 index 0000000..049e16e --- /dev/null +++ b/user/include/mlibc/abis/dripos/ino_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +/* TODO: use (u)int64_t? */ +typedef long ino_t; + +#endif /* _ABIBITS_INO_T_H */ + diff --git a/user/include/mlibc/abis/dripos/inotify.h b/user/include/mlibc/abis/dripos/inotify.h new file mode 100644 index 0000000..f30a0bc --- /dev/null +++ b/user/include/mlibc/abis/dripos/inotify.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_INOTIFY_H +#define _ABIBITS_INOTIFY_H + +#define IN_CLOEXEC 1 +#define IN_NONBLOCK 2 + +#endif /* _ABIBITS_INOTIFY_H */ diff --git a/user/include/mlibc/abis/dripos/ipc.h b/user/include/mlibc/abis/dripos/ipc.h new file mode 100644 index 0000000..5507c55 --- /dev/null +++ b/user/include/mlibc/abis/dripos/ipc.h @@ -0,0 +1,51 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + short __ipc_perm_seq; + short __pad; + unsigned long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/abis/dripos/limits.h b/user/include/mlibc/abis/dripos/limits.h new file mode 100644 index 0000000..9c7bdf1 --- /dev/null +++ b/user/include/mlibc/abis/dripos/limits.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 + +/* Niceness related */ +#define NZERO 20 + +/* Maximum hostname length, posix defines it as 255 */ +#define HOST_NAME_MAX 255 + +#define OPEN_MAX 256 + +#endif /*_ABIBITS_LIMITS_H */ diff --git a/user/include/mlibc/abis/dripos/mode_t.h b/user/include/mlibc/abis/dripos/mode_t.h new file mode 100644 index 0000000..b1a11f3 --- /dev/null +++ b/user/include/mlibc/abis/dripos/mode_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef int mode_t; + +#endif /* _ABIBITS_MODE_T_H */ + diff --git a/user/include/mlibc/abis/dripos/nlink_t.h b/user/include/mlibc/abis/dripos/nlink_t.h new file mode 100644 index 0000000..49c7e0f --- /dev/null +++ b/user/include/mlibc/abis/dripos/nlink_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef int nlink_t; + +#endif /* _ABIBITS_NLINK_T_H */ + diff --git a/user/include/mlibc/abis/dripos/packet.h b/user/include/mlibc/abis/dripos/packet.h new file mode 100644 index 0000000..ae4b92e --- /dev/null +++ b/user/include/mlibc/abis/dripos/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif /* _ABIBITS_PACKET_H */ diff --git a/user/include/mlibc/abis/dripos/pid_t.h b/user/include/mlibc/abis/dripos/pid_t.h new file mode 100644 index 0000000..9591edb --- /dev/null +++ b/user/include/mlibc/abis/dripos/pid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif /* _ABIBITS_PID_T_H */ + diff --git a/user/include/mlibc/abis/dripos/poll.h b/user/include/mlibc/abis/dripos/poll.h new file mode 100644 index 0000000..c2ef284 --- /dev/null +++ b/user/include/mlibc/abis/dripos/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x01 +#define POLLOUT 0x02 +#define POLLPRI 0x04 +#define POLLHUP 0x08 +#define POLLERR 0x10 +#define POLLRDHUP 0x20 +#define POLLNVAL 0x40 +#define POLLWRNORM 0x80 +#define POLLRDNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLRDBAND 0x400 + +#endif /* _ABIBITS_POLL_H */ diff --git a/user/include/mlibc/abis/dripos/ptrace.h b/user/include/mlibc/abis/dripos/ptrace.h new file mode 100644 index 0000000..158bf67 --- /dev/null +++ b/user/include/mlibc/abis/dripos/ptrace.h @@ -0,0 +1,56 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 14 +#define PTRACE_SETREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_GETFPREGS 20 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_CE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif /* _ABIBITS_PTRACE_H */ diff --git a/user/include/mlibc/abis/dripos/resource.h b/user/include/mlibc/abis/dripos/resource.h new file mode 100644 index 0000000..6cb82b2 --- /dev/null +++ b/user/include/mlibc/abis/dripos/resource.h @@ -0,0 +1,53 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 1 +#define RUSAGE_CHILDREN 2 + +#define RLIMIT_CORE 1 +#define RLIMIT_CPU 2 +#define RLIMIT_DATA 3 +#define RLIMIT_FSIZE 4 +#define RLIMIT_NOFILE 5 +#define RLIMIT_STACK 6 +#define RLIMIT_AS 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_RSS 9 +#define RLIMIT_NPROC 10 +#define RLIMIT_LOCKS 11 +#define RLIMIT_SIGPENDING 12 +#define RLIMIT_MSGQUEUE 13 +#define RLIMIT_NICE 14 +#define RLIMIT_RTPRIO 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long int ru_maxrss; + long int ru_ixrss; + long int ru_idrss; + long int ru_isrss; + long int ru_minflt; + long int ru_majflt; + long int ru_nswap; + long int ru_inblock; + long int ru_oublock; + long int ru_msgsnd; + long int ru_msgrcv; + long int ru_nsignals; + long int ru_nvcsw; + long int ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RESOURCE_H */ diff --git a/user/include/mlibc/abis/dripos/rlim_t.h b/user/include/mlibc/abis/dripos/rlim_t.h new file mode 100644 index 0000000..68cfcf5 --- /dev/null +++ b/user/include/mlibc/abis/dripos/rlim_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +typedef unsigned long long rlim_t; + +#endif /* _ABIBITS_RLIM_T_H */ diff --git a/user/include/mlibc/abis/dripos/seek-whence.h b/user/include/mlibc/abis/dripos/seek-whence.h new file mode 100644 index 0000000..4d986e9 --- /dev/null +++ b/user/include/mlibc/abis/dripos/seek-whence.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 3 +#define SEEK_DATA 4 +#define SEEK_HOLE 5 + +#endif /* _ABIBITS_SEEK_WHENCE_H */ diff --git a/user/include/mlibc/abis/dripos/shm.h b/user/include/mlibc/abis/dripos/shm.h new file mode 100644 index 0000000..d435691 --- /dev/null +++ b/user/include/mlibc/abis/dripos/shm.h @@ -0,0 +1,84 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; +}; + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/user/include/mlibc/abis/dripos/sigevent.h b/user/include/mlibc/abis/dripos/sigevent.h new file mode 100644 index 0000000..a5be61a --- /dev/null +++ b/user/include/mlibc/abis/dripos/sigevent.h @@ -0,0 +1,23 @@ +#ifndef _ABIBITS_SIGEVENT_H +#define _ABIBITS_SIGEVENT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sigevent { + int sigev_notify; + int sigev_signo; + union sigval sigev_value; + void (*sigev_notify_function)(union sigval); + /* MISSING: sigev_notify_attributes */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGEVENT_H */ diff --git a/user/include/mlibc/abis/dripos/signal.h b/user/include/mlibc/abis/dripos/signal.h new file mode 100644 index 0000000..f0c4db4 --- /dev/null +++ b/user/include/mlibc/abis/dripos/signal.h @@ -0,0 +1,184 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#if __MLIBC_BUILDING_MLIBC +#warning signal.h is a broken header originally from the deprecated "mlibc" ABI. \ + We suggest to use abis/linux/signal.h instead. \ + Note that this will potentially require kernel changes. +#endif + +#include +#include +#include +#include +#include + +typedef struct { + int si_signo; + int si_code; + int si_errno; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + int si_status; + union sigval si_value; +} siginfo_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Argument for signal() */ +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(-2)) +#define SIG_IGN ((__sighandler)(void *)(-3)) + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGRTMIN 32 +#define SIGRTMAX 33 +#define SIGCANCEL 34 + +/* siginfo->si_info constants */ +/* SIGBUS */ +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 + +/* SIGILL */ +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +/* SIGSEGV */ +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +typedef __mlibc_uint64 sigset_t; + +#define SIGUNUSED SIGSYS + +/* constants for sigprocmask() */ +#define SIG_BLOCK 1 +#define SIG_UNBLOCK 2 +#define SIG_SETMASK 3 + +#define SA_NOCLDSTOP (1 << 0) +#define SA_ONSTACK (1 << 1) +#define SA_RESETHAND (1 << 2) +#define SA_RESTART (1 << 3) +#define SA_SIGINFO (1 << 4) +#define SA_NOCLDWAIT (1 << 5) +#define SA_NODEFER (1 << 6) + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + size_t ss_size; + int ss_flags; +} stack_t; + +/* constants for sigev_notify of struct sigevent */ +#define SIGEV_NONE 1 +#define SIGEV_SIGNAL 2 +#define SIGEV_THREAD 3 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +#define NSIG 65 +#define _NSIG NSIG + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +struct sigaction { + void (*sa_handler)(int); + sigset_t sa_mask; + int sa_flags; + void (*sa_sigaction)(int, siginfo_t *, void *); +}; + +#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) +/* TODO: This is wrong for AArch64. */ + +typedef struct { + unsigned long oldmask; + unsigned long gregs[16]; + unsigned long pc, pr, sr; + unsigned long gbr, mach, macl; + unsigned long fpregs[16]; + unsigned long xfpregs[16]; + unsigned int fpscr, fpul, ownedfp; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGNAL_H */ diff --git a/user/include/mlibc/abis/dripos/socket.h b/user/include/mlibc/abis/dripos/socket.h new file mode 100644 index 0000000..d7754f4 --- /dev/null +++ b/user/include/mlibc/abis/dripos/socket.h @@ -0,0 +1,165 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t)]; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +/*MISSING: CMSG_DATA, CMSG_NXTHDR, CMSG_FIRSTHDR */ + +#define SCM_CREDENTIALS 0x02 + +#define SOCK_DGRAM 1 +#define SOCK_RAW 2 +#define SOCK_SEQPACKET 3 +#define SOCK_STREAM 4 +#define SOCK_DCCP 5 +#define SOCK_NONBLOCK 0x10000 +#define SOCK_CLOEXEC 0x20000 +#define SOCK_RDM 0x40000 + +#define SOL_SOCKET 1 +#define SOL_IPV6 41 +#define SOL_PACKET 263 +#define SOL_NETLINK 270 + +#define SO_ACCEPTCONN 1 +#define SO_BROADCAST 2 +#define SO_DEBUG 3 +#define SO_DONTROUTE 4 +#define SO_ERROR 5 +#define SO_KEEPALIVE 6 +#define SO_LINGER 7 +#define SO_OOBINLINE 8 +#define SO_RCVBUF 9 +#define SO_RCVLOWAT 10 +#define SO_RCVTIMEO 11 +#define SO_REUSEADDR 12 +#define SO_SNDBUF 13 +#define SO_SNDLOWAT 14 +#define SO_SNDTIMEO 15 +#define SO_TYPE 16 +#define SO_SNDBUFFORCE 17 +#define SO_PEERCRED 18 +#define SO_ATTACH_FILTER 19 +#define SO_PASSCRED 20 +#define SO_RCVBUFFORCE 21 +#define SO_DETACH_FILTER 22 +#define SO_PROTOCOL 23 +#define SO_REUSEPORT 24 +#define SO_TIMESTAMP 25 +#define SO_PEERSEC 26 +#define SO_BINDTODEVICE 27 +#define SO_DOMAIN 28 +#define SO_PASSSEC 29 +#define SO_TIMESTAMPNS 30 +#define SO_PRIORITY 31 +#define SO_MARK 32 + +#define SOMAXCONN 1 + +#define MSG_CTRUNC 0x1 +#define MSG_DONTROUTE 0x2 +#define MSG_EOR 0x4 +#define MSG_OOB 0x8 +#define MSG_NOSIGNAL 0x10 +#define MSG_PEEK 0x20 +#define MSG_TRUNC 0x40 +#define MSG_WAITALL 0x80 +#define MSG_FIN 0x200 +#define MSG_CONFIRM 0x800 + +/* Linux extensions. */ +#define MSG_DONTWAIT 0x1000 +#define MSG_CMSG_CLOEXEC 0x2000 +#define MSG_MORE 0x4000 +#define MSG_FASTOPEN 0x20000000 + +/* GNU (?) extension: Protocol family constants. */ + +#define PF_INET 1 +#define PF_INET6 2 +#define PF_UNIX 3 +#define PF_LOCAL 3 +#define PF_UNSPEC 4 +#define PF_NETLINK 5 +#define PF_BRIDGE 6 +#define PF_APPLETALK 7 +#define PF_BLUETOOTH 8 +#define PF_DECnet 9 +#define PF_IPX 10 +#define PF_ISDN 11 +#define PF_SNA 12 +#define PF_PACKET 13 +#define PF_AX25 14 +#define PF_NETROM 15 +#define PF_ROSE 16 +#define PF_TIPC 30 +#define PF_ALG 38 +#define PF_MAX 46 + +#define AF_INET PF_INET +#define AF_INET6 PF_INET6 +#define AF_UNIX PF_UNIX +#define AF_LOCAL PF_LOCAL +#define AF_UNSPEC PF_UNSPEC +#define AF_NETLINK PF_NETLINK +#define AF_BRIDGE PF_BRIDGE +#define AF_APPLETALK PF_APPLETALK +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_DECnet PF_DECnet +#define AF_IPX PF_IPX +#define AF_ISDN PF_ISDN +#define AF_SNA PF_SNA +#define AF_PACKET PF_PACKET +#define AF_PACKET PF_PACKET +#define AF_AX25 PF_AX25 +#define AF_NETROM PF_NETROM +#define AF_ROSE PF_ROSE +#define AF_TIPC PF_TIPC +#define AF_ALG PF_ALG +#define AF_MAX PF_MAX + +#define SHUT_RD 1 +#define SHUT_RDWR 2 +#define SHUT_WR 3 +#endif diff --git a/user/include/mlibc/abis/dripos/stat.h b/user/include/mlibc/abis/dripos/stat.h new file mode 100644 index 0000000..37f6aaa --- /dev/null +++ b/user/include/mlibc/abis/dripos/stat.h @@ -0,0 +1,69 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + blksize_t st_blksize; + blkcnt_t st_blocks; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_STAT_H */ diff --git a/user/include/mlibc/abis/dripos/termios.h b/user/include/mlibc/abis/dripos/termios.h new file mode 100644 index 0000000..32efd08 --- /dev/null +++ b/user/include/mlibc/abis/dripos/termios.h @@ -0,0 +1,119 @@ +#ifndef _ABIBITS_TERMIOS_H +#define _ABIBITS_TERMIOS_H + +#if __MLIBC_BUILDING_MLIBC +#warning termios.h is a broken header originally from the deprecated "mlibc" ABI. \ + We suggest to use abis/linux/termios.h instead. \ + Note that this will potentially require kernel changes. +#endif + +typedef unsigned int cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +/* indices for the c_cc array in struct termios */ +#define NCCS 11 +#define VEOF 0 +#define VEOL 1 +#define VERASE 2 +#define VINTR 3 +#define VKILL 4 +#define VMIN 5 +#define VQUIT 6 +#define VSTART 7 +#define VSTOP 8 +#define VSUSP 9 +#define VTIME 10 + +/* bitwise flags for c_iflag in struct termios */ +#define BRKINT 0x0001 +#define ICRNL 0x0002 +#define IGNBRK 0x0004 +#define IGNCR 0x0008 +#define IGNPAR 0x0010 +#define INLCR 0x0020 +#define INPCK 0x0040 +#define ISTRIP 0x0080 +#define IXANY 0x0100 +#define IXOFF 0x0200 +#define IXON 0x0400 +#define PARMRK 0x0800 + +/* bitwise flags for c_oflag in struct termios */ +#define OPOST 0x0001 +#define ONLCR 0x0002 +#define OCRNL 0x0004 +#define ONOCR 0x0008 +#define ONLRET 0x0010 +#define OFDEL 0x0020 +#define OFILL 0x0040 + +#define NLDLY 0x0080 +#define NL0 0x0000 +#define NL1 0x0080 + +#define CRDLY 0x0300 +#define CR0 0x0000 +#define CR1 0x0100 +#define CR2 0x0200 +#define CR3 0x0300 + +#define TABDLY 0x0C00 +#define TAB0 0x0000 +#define TAB1 0x0400 +#define TAB2 0x0800 +#define TAB3 0x0C00 + +#define BSDLY 0x1000 +#define BS0 0x0000 +#define BS1 0x1000 + +#define VTDLY 0x2000 +#define VT0 0x0000 +#define VT1 0x2000 + +#define FFDLY 0x4000 +#define FF0 0x0000 +#define FF1 0x4000 + +/* bitwise constants for c_cflag in struct termios */ +#define CSIZE 0x0003 +#define CS5 0x0000 +#define CS6 0x0001 +#define CS7 0x0002 +#define CS8 0x0003 + +#define CSTOPB 0x0004 +#define CREAD 0x0008 +#define PARENB 0x0010 +#define PARODD 0x0020 +#define HUPCL 0x0040 +#define CLOCAL 0x0080 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define CBAUD 0x100F +#endif + +/* bitwise constants for c_lflag in struct termios */ +#define ECHO 0x0001 +#define ECHOE 0x0002 +#define ECHOK 0x0004 +#define ECHONL 0x0008 +#define ICANON 0x0010 +#define IEXTEN 0x0020 +#define ISIG 0x0040 +#define NOFLSH 0x0080 +#define TOSTOP 0x0100 +#define ECHOPRT 0x0200 + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +}; + +#endif diff --git a/user/include/mlibc/abis/dripos/uid_t.h b/user/include/mlibc/abis/dripos/uid_t.h new file mode 100644 index 0000000..976540b --- /dev/null +++ b/user/include/mlibc/abis/dripos/uid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif /* _ABIBITS_UID_T_H */ + diff --git a/user/include/mlibc/abis/dripos/utsname.h b/user/include/mlibc/abis/dripos/utsname.h new file mode 100644 index 0000000..080df37 --- /dev/null +++ b/user/include/mlibc/abis/dripos/utsname.h @@ -0,0 +1,18 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +#if __MLIBC_BUILDING_MLIBC +#warning utsname.h is a broken header originally from the deprecated "mlibc" ABI. \ + We suggest to use abis/linux/utsname.h instead. \ + Note that this will potentially require kernel changes. +#endif + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; +}; + +#endif /* _ABIBITS_UTSNAME_T_H */ diff --git a/user/include/mlibc/abis/dripos/vm-flags.h b/user/include/mlibc/abis/dripos/vm-flags.h new file mode 100644 index 0000000..769275a --- /dev/null +++ b/user/include/mlibc/abis/dripos/vm-flags.h @@ -0,0 +1,46 @@ +#ifndef _ABIBITS_MMAP_FLAGS_H +#define _ABIBITS_MMAP_FLAGS_H + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_PRIVATE 0x01 +#define MAP_SHARED 0x02 +#define MAP_FIXED 0x04 +#define MAP_ANON 0x08 +#define MAP_ANONYMOUS 0x08 +#define MAP_NORESERVE 0x10 +#define MAP_FIXED_NOREPLACE 0x20 + +#define MS_ASYNC 0x01 +#define MS_SYNC 0x02 +#define MS_INVALIDATE 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_RANDOM 3 +#define POSIX_MADV_DONTNEED 4 +#define POSIX_MADV_WILLNEED 5 + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 + +/* Linux extensions: */ +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U + +#endif /* _ABIBITS_MMAP_FLAGS_H */ diff --git a/user/include/mlibc/abis/dripos/wait.h b/user/include/mlibc/abis/dripos/wait.h new file mode 100644 index 0000000..e9ec1b8 --- /dev/null +++ b/user/include/mlibc/abis/dripos/wait.h @@ -0,0 +1,31 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#if __MLIBC_BUILDING_MLIBC +#warning wait.h is a broken header originally from the deprecated "mlibc" ABI. \ + We suggest to use abis/linux/wait.h instead. \ + Note that this will potentially require kernel changes. +#endif + +#define WCONTINUED 1 +#define WNOHANG 2 +#define WUNTRACED 4 +#define WEXITED 8 +#define WNOWAIT 16 +#define WSTOPPED 32 + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) ((x) & 0x000000FF) +#define WIFCONTINUED(x) ((x) & 0x00000100) +#define WIFEXITED(x) ((x) & 0x00000200) +#define WIFSIGNALED(x) ((x) & 0x00000400) +#define WIFSTOPPED(x) ((x) & 0x00000800) +#define WSTOPSIG(x) (((x) & 0x00FF0000) >> 16) +#define WTERMSIG(x) (((x) & 0xFF000000) >> 24) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +#endif /*_ABIBITS_WAIT_H */ diff --git a/user/include/mlibc/abis/ironclad/access.h b/user/include/mlibc/abis/ironclad/access.h new file mode 100644 index 0000000..984bbed --- /dev/null +++ b/user/include/mlibc/abis/ironclad/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 1 +#define R_OK 2 +#define W_OK 4 +#define X_OK 8 + +#endif /* _ABIBITS_ACCESS_H */ diff --git a/user/include/mlibc/abis/ironclad/auxv.h b/user/include/mlibc/abis/ironclad/auxv.h new file mode 100644 index 0000000..8a80546 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/auxv.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_HWCAP 16 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 + +#endif diff --git a/user/include/mlibc/abis/ironclad/blkcnt_t.h b/user/include/mlibc/abis/ironclad/blkcnt_t.h new file mode 100644 index 0000000..1222088 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/blkcnt_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +/* TODO: use int64_t? */ +typedef long blkcnt_t; + +#endif /* _ABIBITS_BLKCNT_T_H */ diff --git a/user/include/mlibc/abis/ironclad/blksize_t.h b/user/include/mlibc/abis/ironclad/blksize_t.h new file mode 100644 index 0000000..a0f23b2 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/blksize_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +/* TODO: use int64_t? */ +typedef long blksize_t; + +#endif /* _ABIBITS_BLKSIZE_T_H */ + diff --git a/user/include/mlibc/abis/ironclad/clockid_t.h b/user/include/mlibc/abis/ironclad/clockid_t.h new file mode 100644 index 0000000..c3932ef --- /dev/null +++ b/user/include/mlibc/abis/ironclad/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef long clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/user/include/mlibc/abis/ironclad/dev_t.h b/user/include/mlibc/abis/ironclad/dev_t.h new file mode 100644 index 0000000..bb83c72 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/dev_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +typedef unsigned long dev_t; + +#endif /* _ABIBITS_DEV_T_H */ diff --git a/user/include/mlibc/abis/ironclad/errno.h b/user/include/mlibc/abis/ironclad/errno.h new file mode 100644 index 0000000..30636cf --- /dev/null +++ b/user/include/mlibc/abis/ironclad/errno.h @@ -0,0 +1,127 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EDOM 1 +#define EILSEQ 2 +#define ERANGE 3 + +#define E2BIG 1001 +#define EACCES 1002 +#define EADDRINUSE 1003 +#define EADDRNOTAVAIL 1004 +#define EAFNOSUPPORT 1005 +#define EAGAIN 1006 +#define EALREADY 1007 +#define EBADF 1008 +#define EBADMSG 1009 +#define EBUSY 1010 +#define ECANCELED 1011 +#define ECHILD 1012 +#define ECONNABORTED 1013 +#define ECONNREFUSED 1014 +#define ECONNRESET 1015 +#define EDEADLK 1016 +#define EDESTADDRREQ 1017 +#define EDQUOT 1018 +#define EEXIST 1019 +#define EFAULT 1020 +#define EFBIG 1021 +#define EHOSTUNREACH 1022 +#define EIDRM 1023 +#define EINPROGRESS 1024 +#define EINTR 1025 +#define EINVAL 1026 +#define EIO 1027 +#define EISCONN 1028 +#define EISDIR 1029 +#define ELOOP 1030 +#define EMFILE 1031 +#define EMLINK 1032 +#define EMSGSIZE 1034 +#define EMULTIHOP 1035 +#define ENAMETOOLONG 1036 +#define ENETDOWN 1037 +#define ENETRESET 1038 +#define ENETUNREACH 1039 +#define ENFILE 1040 +#define ENOBUFS 1041 +#define ENODEV 1042 +#define ENOENT 1043 +#define ENOEXEC 1044 +#define ENOLCK 1045 +#define ENOLINK 1046 +#define ENOMEM 1047 +#define ENOMSG 1048 +#define ENOPROTOOPT 1049 +#define ENOSPC 1050 +#define ENOSYS 1051 +#define ENOTCONN 1052 +#define ENOTDIR 1053 +#define ENOTEMPTY 1054 +#define ENOTRECOVERABLE 1055 +#define ENOTSOCK 1056 +#define ENOTSUP 1057 +#define ENOTTY 1058 +#define ENXIO 1059 +#define EOPNOTSUPP 1060 +#define EOVERFLOW 1061 +#define EOWNERDEAD 1062 +#define EPERM 1063 +#define EPIPE 1064 +#define EPROTO 1065 +#define EPROTONOSUPPORT 1066 +#define EPROTOTYPE 1067 +#define EROFS 1068 +#define ESPIPE 1069 +#define ESRCH 1070 +#define ESTALE 1071 +#define ETIMEDOUT 1072 +#define ETXTBSY 1073 +#define EWOULDBLOCK EAGAIN +#define EXDEV 1075 +#define ENODATA 1076 +#define ETIME 1077 +#define ENOKEY 1078 +#define ESHUTDOWN 1079 +#define EHOSTDOWN 1080 +#define EBADFD 1081 +#define ENOMEDIUM 1082 +#define ENOTBLK 1083 +#define ENONET 1084 +#define EPFNOSUPPORT 1085 +#define ESOCKTNOSUPPORT 1086 +#define ESTRPIPE 1087 +#define EREMOTEIO 1088 +#define ERFKILL 1089 +#define EBADR 1090 +#define EUNATCH 1091 +#define EMEDIUMTYPE 1092 +#define EREMOTE 1093 +#define EKEYREJECTED 1094 +#define EUCLEAN 1095 +#define EBADSLT 1096 +#define ENOANO 1097 +#define ENOCSI 1098 +#define ENOSTR 1099 +#define ETOOMANYREFS 1100 +#define ENOPKG 1101 +#define EKEYREVOKED 1102 +#define EXFULL 1103 +#define ELNRNG 1104 +#define ENOTUNIQ 1105 +#define ERESTART 1106 +#define EUSERS 1107 +#define ECHRNG 1108 +#define ELIBBAD 1109 +#define EL2HLT 1110 +#define EL3HLT 1111 +#define EKEYEXPIRED 1112 +#define ECOMM 1113 +#define EBADE 1114 +#define EHWPOISON 1115 +#define EBADRQC 1116 +#define EPROGMISMATCH 1117 + +#define EIEIO 1524152434 + +#endif /* _ABIBITS_ERRNO_H */ diff --git a/user/include/mlibc/abis/ironclad/fcntl.h b/user/include/mlibc/abis/ironclad/fcntl.h new file mode 100644 index 0000000..950188b --- /dev/null +++ b/user/include/mlibc/abis/ironclad/fcntl.h @@ -0,0 +1,81 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +/* Flags supported by the kernel. */ +#define O_ACCMODE (3 << 0) +#define O_RDONLY (1 << 0) +#define O_WRONLY (1 << 1) +#define O_RDWR (3 << 0) +#define O_APPEND (1 << 2) +#define O_CLOEXEC (1 << 3) +#define O_NOFOLLOW (1 << 4) +#define O_NONBLOCK (1 << 5) +#define O_CLOFORK (1 << 6) + +/* Flags emulated by userland, we just have to make sure they dont overlap with */ +/* kernel flags. */ +#define O_CREAT (1 << 7) +#define O_EXCL (1 << 8) +#define O_TRUNC (1 << 9) + +/* Stubbed flags, the value really doesnt matter as long as they dont overlap */ +/* with usable ones. */ +/* Implemented here as some software needs them to compile. */ +#define O_SEARCH (1 << 10) +#define O_EXEC (1 << 11) +#define O_NOCTTY (1 << 12) +#define O_DSYNC (1 << 13) +#define O_RSYNC (1 << 14) +#define O_SYNC (1 << 15) +#define O_PATH (1 << 16) +#define O_DIRECTORY (1 << 17) +#define O_LARGEFILE (1 << 18) +#define O_NOATIME (1 << 19) +#define O_TMPFILE (1 << 20) + +/* Fcntl flags. */ +#define FD_CLOEXEC 1 +#define FD_CLOFORK 2 +#define F_DUPFD 1 +#define F_DUPFD_CLOEXEC 2 +#define F_GETFD 3 +#define F_SETFD 4 +#define F_GETFL 5 +#define F_SETFL 6 +#define F_GETPIPE_SZ 7 +#define F_SETPIPE_SZ 8 +#define F_GETLK 9 +#define F_SETLK 10 +#define F_SETLKW 11 + +#define F_RDLCK 1 +#define F_UNLCK 2 +#define F_WRLCK 3 + +/* Stubbed fcntl flags. */ +#define F_GETOWN 10 +#define F_SETOWN 11 + +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 +#define F_SEAL_SEAL 0x0010 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +/* At flags. */ +#define AT_REMOVEDIR 500 +#define AT_EACCESS 512 +#define AT_FDCWD (-100) +#define AT_EMPTY_PATH 1 +#define AT_SYMLINK_FOLLOW 0 +#define AT_SYMLINK_NOFOLLOW 2 + +#define POSIX_FADV_NORMAL 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_NOREUSE 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_WILLNEED 5 +#define POSIX_FADV_RANDOM 6 + +#endif /* _ABIBITS_FCNTL_H */ diff --git a/user/include/mlibc/abis/ironclad/fsblkcnt_t.h b/user/include/mlibc/abis/ironclad/fsblkcnt_t.h new file mode 100644 index 0000000..0d74456 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/fsblkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSBLKCNT_T_H +#define _ABIBITS_FSBLKCNT_T_H + +#include + +typedef __mlibc_uint64 fsblkcnt_t; + +#endif /* _ABIBITS_FSBLKCNT_T_H */ diff --git a/user/include/mlibc/abis/ironclad/fsfilcnt_t.h b/user/include/mlibc/abis/ironclad/fsfilcnt_t.h new file mode 100644 index 0000000..1abda9a --- /dev/null +++ b/user/include/mlibc/abis/ironclad/fsfilcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSFILCNT_T_H +#define _ABIBITS_FSFILCNT_T_H + +#include + +typedef __mlibc_uint64 fsfilcnt_t; + +#endif /* _ABIBITS_FSFILCNT_T_H */ diff --git a/user/include/mlibc/abis/ironclad/gid_t.h b/user/include/mlibc/abis/ironclad/gid_t.h new file mode 100644 index 0000000..c10e7aa --- /dev/null +++ b/user/include/mlibc/abis/ironclad/gid_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif /* _ABIBITS_GID_T_H */ diff --git a/user/include/mlibc/abis/ironclad/in.h b/user/include/mlibc/abis/ironclad/in.h new file mode 100644 index 0000000..2b70358 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/in.h @@ -0,0 +1,168 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t pad[8]; +}; +#define sin_zero pad /* for BSD Unix compatibility */ + +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + unsigned int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +#define IPPROTO_IP 1 +#define IPPROTO_IPV6 2 +#define IPPROTO_ICMP 3 +#define IPPROTO_RAW 4 +#define IPPROTO_TCP 5 +#define IPPROTO_UDP 6 +#define IPPROTO_IGMP 7 +#define IPPROTO_IPIP 8 +#define IPPROTO_DCCP 33 +#define IPPROTO_ROUTING 43 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MAX 256 + +#define INADDR_ANY ((in_addr_t)0x00000000) +#define INADDR_BROADCAST ((in_addr_t)0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t)0x7f000001) +#define INADDR_NONE ((in_addr_t)0xffffffff) + +#define INET_ADDRSTRLEN 16 + +#define INET6_ADDRSTRLEN 46 + +#define IPV6_JOIN_GROUP 1 +#define IPV6_LEAVE_GROUP 2 +#define IPV6_MULTICAST_HOPS 3 +#define IPV6_MULTICAST_IF 4 +#define IPV6_MULTICAST_LOOP 5 +#define IPV6_UNICAST_HOPS 6 +#define IPV6_V6ONLY 7 +#define IPV6_PMTUDISC_DONT 8 +#define IPV6_PMTUDISC_DO 9 +#define IPV6_MTU 10 +#define IPV6_2292PKTOPTIONS 11 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_RECVERR 25 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_TCLASS 67 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_OPTIONS 4 +#define IP_PMTUDISC_OMIT 5 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_UNICAST_IF 13 +#define IP_MTU 14 + +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_DO 2 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#endif /* _ABIBITS_IN_H */ diff --git a/user/include/mlibc/abis/ironclad/ino_t.h b/user/include/mlibc/abis/ironclad/ino_t.h new file mode 100644 index 0000000..825a812 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/ino_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +/* TODO: use (u)int64_t? */ +typedef long ino_t; + +#endif /* _ABIBITS_INO_T_H */ diff --git a/user/include/mlibc/abis/ironclad/ioctls.h b/user/include/mlibc/abis/ironclad/ioctls.h new file mode 100644 index 0000000..c39abb5 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/ioctls.h @@ -0,0 +1,13 @@ +#ifndef _ABIBITS_IOCTLS_H +#define _ABIBITS_IOCTLS_H + +#define SIOCPROTOPRIVATE 0x89E0 +#define SIOCGIFNAME 0x8910 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFINDEX 0x8933 +#define SIOCATMARK 0x8905 +#define SIOCGIFHWADDR 0x8927 + +#endif /* _ABIBITS_IOCTLS_H */ diff --git a/user/include/mlibc/abis/ironclad/ipc.h b/user/include/mlibc/abis/ironclad/ipc.h new file mode 100644 index 0000000..5507c55 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/ipc.h @@ -0,0 +1,51 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + short __ipc_perm_seq; + short __pad; + unsigned long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/abis/ironclad/limits.h b/user/include/mlibc/abis/ironclad/limits.h new file mode 100644 index 0000000..9c7bdf1 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/limits.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 + +/* Niceness related */ +#define NZERO 20 + +/* Maximum hostname length, posix defines it as 255 */ +#define HOST_NAME_MAX 255 + +#define OPEN_MAX 256 + +#endif /*_ABIBITS_LIMITS_H */ diff --git a/user/include/mlibc/abis/ironclad/mode_t.h b/user/include/mlibc/abis/ironclad/mode_t.h new file mode 100644 index 0000000..d2158b2 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/mode_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef int mode_t; + +#endif /* _ABIBITS_MODE_T_H */ diff --git a/user/include/mlibc/abis/ironclad/mqueue.h b/user/include/mlibc/abis/ironclad/mqueue.h new file mode 100644 index 0000000..f18210c --- /dev/null +++ b/user/include/mlibc/abis/ironclad/mqueue.h @@ -0,0 +1,20 @@ +#ifndef _ABIBITS_MQUEUE_H +#define _ABIBITS_MQUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct mq_attr { + long mq_flags; + long mq_maxmsg; + long mq_msgsize; + long mq_curmsgs; + long __pad[4]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MQUEUE_H */ diff --git a/user/include/mlibc/abis/ironclad/msg.h b/user/include/mlibc/abis/ironclad/msg.h new file mode 100644 index 0000000..5e890c0 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/msg.h @@ -0,0 +1,39 @@ +#ifndef _ABIBITS_MSG_H +#define _ABIBITS_MSG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__i386__) +typedef __mlibc_uint64 msglen_t; +typedef __mlibc_uint64 msgqnum_t; +#else +typedef unsigned long msglen_t; +typedef unsigned long msgqnum_t; +#endif + +struct msqid_ds { + struct ipc_perm msg_perm; + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MSG_H */ + diff --git a/user/include/mlibc/abis/ironclad/nlink_t.h b/user/include/mlibc/abis/ironclad/nlink_t.h new file mode 100644 index 0000000..009bbaa --- /dev/null +++ b/user/include/mlibc/abis/ironclad/nlink_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef int nlink_t; + +#endif /* _ABIBITS_NLINK_T_H */ diff --git a/user/include/mlibc/abis/ironclad/packet.h b/user/include/mlibc/abis/ironclad/packet.h new file mode 100644 index 0000000..ae4b92e --- /dev/null +++ b/user/include/mlibc/abis/ironclad/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif /* _ABIBITS_PACKET_H */ diff --git a/user/include/mlibc/abis/ironclad/pid_t.h b/user/include/mlibc/abis/ironclad/pid_t.h new file mode 100644 index 0000000..8ebf9ed --- /dev/null +++ b/user/include/mlibc/abis/ironclad/pid_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif /* _ABIBITS_PID_T_H */ diff --git a/user/include/mlibc/abis/ironclad/poll.h b/user/include/mlibc/abis/ironclad/poll.h new file mode 100644 index 0000000..c2ef284 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x01 +#define POLLOUT 0x02 +#define POLLPRI 0x04 +#define POLLHUP 0x08 +#define POLLERR 0x10 +#define POLLRDHUP 0x20 +#define POLLNVAL 0x40 +#define POLLWRNORM 0x80 +#define POLLRDNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLRDBAND 0x400 + +#endif /* _ABIBITS_POLL_H */ diff --git a/user/include/mlibc/abis/ironclad/ptrace.h b/user/include/mlibc/abis/ironclad/ptrace.h new file mode 100644 index 0000000..158bf67 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/ptrace.h @@ -0,0 +1,56 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 14 +#define PTRACE_SETREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_GETFPREGS 20 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_CE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif /* _ABIBITS_PTRACE_H */ diff --git a/user/include/mlibc/abis/ironclad/reboot.h b/user/include/mlibc/abis/ironclad/reboot.h new file mode 100644 index 0000000..01bccec --- /dev/null +++ b/user/include/mlibc/abis/ironclad/reboot.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_REBOOT_H +#define _ABIBITS_REBOOT_H + +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + +#endif /* _ABIBITS_REBOOT_H */ diff --git a/user/include/mlibc/abis/ironclad/resource.h b/user/include/mlibc/abis/ironclad/resource.h new file mode 100644 index 0000000..6cb82b2 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/resource.h @@ -0,0 +1,53 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 1 +#define RUSAGE_CHILDREN 2 + +#define RLIMIT_CORE 1 +#define RLIMIT_CPU 2 +#define RLIMIT_DATA 3 +#define RLIMIT_FSIZE 4 +#define RLIMIT_NOFILE 5 +#define RLIMIT_STACK 6 +#define RLIMIT_AS 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_RSS 9 +#define RLIMIT_NPROC 10 +#define RLIMIT_LOCKS 11 +#define RLIMIT_SIGPENDING 12 +#define RLIMIT_MSGQUEUE 13 +#define RLIMIT_NICE 14 +#define RLIMIT_RTPRIO 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long int ru_maxrss; + long int ru_ixrss; + long int ru_idrss; + long int ru_isrss; + long int ru_minflt; + long int ru_majflt; + long int ru_nswap; + long int ru_inblock; + long int ru_oublock; + long int ru_msgsnd; + long int ru_msgrcv; + long int ru_nsignals; + long int ru_nvcsw; + long int ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RESOURCE_H */ diff --git a/user/include/mlibc/abis/ironclad/riscv-hwprobe.h b/user/include/mlibc/abis/ironclad/riscv-hwprobe.h new file mode 100644 index 0000000..14b19c0 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/riscv-hwprobe.h @@ -0,0 +1,107 @@ +#ifndef _ABIBITS_RISCV_HWPROBE_H +#define _ABIBITS_RISCV_HWPROBE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct riscv_hwprobe { + signed long long int key; + unsigned long long int value; +}; + +#define RISCV_HWPROBE_KEY_MVENDORID 0 +#define RISCV_HWPROBE_KEY_MARCHID 1 +#define RISCV_HWPROBE_KEY_MIMPID 2 +#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3 +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0) +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 +#define RISCV_HWPROBE_IMA_FD (1 << 0) +#define RISCV_HWPROBE_IMA_C (1 << 1) +#define RISCV_HWPROBE_IMA_V (1 << 2) +#define RISCV_HWPROBE_EXT_ZBA (1 << 3) +#define RISCV_HWPROBE_EXT_ZBB (1 << 4) +#define RISCV_HWPROBE_EXT_ZBS (1 << 5) +#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) +#define RISCV_HWPROBE_EXT_ZBC (1 << 7) +#define RISCV_HWPROBE_EXT_ZBKB (1 << 8) +#define RISCV_HWPROBE_EXT_ZBKC (1 << 9) +#define RISCV_HWPROBE_EXT_ZBKX (1 << 10) +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#define RISCV_HWPROBE_EXT_ZKNH (1 << 13) +#define RISCV_HWPROBE_EXT_ZKSED (1 << 14) +#define RISCV_HWPROBE_EXT_ZKSH (1 << 15) +#define RISCV_HWPROBE_EXT_ZKT (1 << 16) +#define RISCV_HWPROBE_EXT_ZVBB (1 << 17) +#define RISCV_HWPROBE_EXT_ZVBC (1 << 18) +#define RISCV_HWPROBE_EXT_ZVKB (1 << 19) +#define RISCV_HWPROBE_EXT_ZVKG (1 << 20) +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22) +#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23) +#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24) +#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25) +#define RISCV_HWPROBE_EXT_ZVKT (1 << 26) +#define RISCV_HWPROBE_EXT_ZFH (1 << 27) +#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) +#define RISCV_HWPROBE_EXT_ZVFH (1 << 30) +#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31) +#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) +#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) +#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) +#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) +#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36) +#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37) +#define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38) +#define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39) +#define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40) +#define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41) +#define RISCV_HWPROBE_EXT_ZIMOP (1ULL << 42) +#define RISCV_HWPROBE_EXT_ZCA (1ULL << 43) +#define RISCV_HWPROBE_EXT_ZCB (1ULL << 44) +#define RISCV_HWPROBE_EXT_ZCD (1ULL << 45) +#define RISCV_HWPROBE_EXT_ZCF (1ULL << 46) +#define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47) +#define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48) +#define RISCV_HWPROBE_EXT_SUPM (1ULL << 49) +#define RISCV_HWPROBE_EXT_ZICNTR (1ULL << 50) +#define RISCV_HWPROBE_EXT_ZIHPM (1ULL << 51) +#define RISCV_HWPROBE_EXT_ZFBFMIN (1ULL << 52) +#define RISCV_HWPROBE_EXT_ZVFBFMIN (1ULL << 53) +#define RISCV_HWPROBE_EXT_ZVFBFWMA (1ULL << 54) +#define RISCV_HWPROBE_EXT_ZICBOM (1ULL << 55) +#define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) +#define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) +#define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58) +#define RISCV_HWPROBE_KEY_CPUPERF_0 5 +#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) +#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) +#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0) +#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) +#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) +#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7 +#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8 +#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0 11 +#define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE 12 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0 13 + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RISCV_HWPROBE_H */ diff --git a/user/include/mlibc/abis/ironclad/rlim_t.h b/user/include/mlibc/abis/ironclad/rlim_t.h new file mode 100644 index 0000000..68cfcf5 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/rlim_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +typedef unsigned long long rlim_t; + +#endif /* _ABIBITS_RLIM_T_H */ diff --git a/user/include/mlibc/abis/ironclad/seek-whence.h b/user/include/mlibc/abis/ironclad/seek-whence.h new file mode 100644 index 0000000..f7f8e7a --- /dev/null +++ b/user/include/mlibc/abis/ironclad/seek-whence.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_SET 1 +#define SEEK_CUR 2 +#define SEEK_END 4 + +#endif /* _ABIBITS_SEEK_WHENCE_H */ diff --git a/user/include/mlibc/abis/ironclad/shm.h b/user/include/mlibc/abis/ironclad/shm.h new file mode 100644 index 0000000..d435691 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/shm.h @@ -0,0 +1,84 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; +}; + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/user/include/mlibc/abis/ironclad/sigevent.h b/user/include/mlibc/abis/ironclad/sigevent.h new file mode 100644 index 0000000..9e71588 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/sigevent.h @@ -0,0 +1,22 @@ +#ifndef _ABIBITS_SIGEVENT_H +#define _ABIBITS_SIGEVENT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sigevent { + int sigev_notify; + int sigev_signo; + union sigval sigev_value; + void (*sigev_notify_function)(union sigval); + /* MISSING: sigev_notify_attributes */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGEVENT_H */ diff --git a/user/include/mlibc/abis/ironclad/signal.h b/user/include/mlibc/abis/ironclad/signal.h new file mode 100644 index 0000000..2634cbe --- /dev/null +++ b/user/include/mlibc/abis/ironclad/signal.h @@ -0,0 +1,177 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#include +#include +#include +#include + +typedef struct { + int si_signo; + int si_code; + int si_errno; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + int si_status; + union sigval si_value; +} siginfo_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Argument for signal() */ +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(-2)) +#define SIG_IGN ((__sighandler)(void *)(-3)) + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGCONT 4 +#define SIGBUS 5 +#define SIGABRT 6 +#define SIGCHLD 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGILL 10 +#define SIGPIPE 11 +#define SIGSEGV 12 +#define SIGSTOP 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGTSTP 16 +#define SIGTTIN 17 +#define SIGTTOU 18 +#define SIGUSR1 19 +#define SIGUSR2 20 +#define SIGIO 21 +#define SIGPOLL SIGIO +#define SIGPROF 22 +#define SIGSYS 23 +#define SIGCANCEL SIGSYS +#define SIGTRAP 24 +#define SIGURG 25 +#define SIGVTALRM 26 +#define SIGXCPU 27 +#define SIGXFSZ 28 +#define SIGWINCH 29 +#define SIGPWR 30 + +/* siginfo->si_info constants */ +/* SIGBUS */ +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 + +/* SIGILL */ +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +/* SIGSEGV */ +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +/* TODO: replace this by uint64_t */ +typedef long sigset_t; + +#define SIGUNUSED SIGSYS + +/* constants for sigprocmask() */ +#define SIG_BLOCK 1 +#define SIG_UNBLOCK 2 +#define SIG_SETMASK 3 + +#define SA_NOCLDSTOP (1 << 0) +#define SA_ONSTACK (1 << 1) +#define SA_RESETHAND (1 << 2) +#define SA_RESTART (1 << 3) +#define SA_SIGINFO (1 << 4) +#define SA_NOCLDWAIT (1 << 5) +#define SA_NODEFER (1 << 6) + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + size_t ss_size; + int ss_flags; +} stack_t; + +/* constants for sigev_notify of struct sigevent */ +#define SIGEV_NONE 1 +#define SIGEV_SIGNAL 2 +#define SIGEV_THREAD 3 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +#define NSIG 65 +#define _NSIG NSIG + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + }; + void (*sa_restorer)(void); + sigset_t sa_mask; + int sa_flags; +}; + +#if defined(__x86_64__) || defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) +/* TODO: This is wrong for AArch64. */ + +typedef struct { + unsigned long oldmask; + unsigned long gregs[16]; + unsigned long pc, pr, sr; + unsigned long gbr, mach, macl; + unsigned long fpregs[16]; + unsigned long xfpregs[16]; + unsigned int fpscr, fpul, ownedfp; +} mcontext_t; + +typedef struct __ucontext { + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGNAL_H */ diff --git a/user/include/mlibc/abis/ironclad/sigval.h b/user/include/mlibc/abis/ironclad/sigval.h new file mode 100644 index 0000000..123ba77 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/sigval.h @@ -0,0 +1,17 @@ +#ifndef _ABIBITS_SIGVAL_H +#define _ABIBITS_SIGVAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +union sigval { + int sival_int; + void *sival_ptr; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGVAL_H */ diff --git a/user/include/mlibc/abis/ironclad/socket.h b/user/include/mlibc/abis/ironclad/socket.h new file mode 100644 index 0000000..4a0f333 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/socket.h @@ -0,0 +1,164 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t)]; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +/*MISSING: CMSG_DATA, CMSG_NXTHDR, CMSG_FIRSTHDR */ + +#define SCM_CREDENTIALS 0x02 + +#define SOCK_DGRAM (1 << 0) +#define SOCK_RAW (1 << 1) +#define SOCK_STREAM (1 << 2) +#define SOCK_SEQPACKET (1 << 3) +#define SOCK_NONBLOCK (1 << 15) +#define SOCK_CLOEXEC (1 << 16) +#define SOCK_CLOFORK (1 << 17) + +#define SOL_SOCKET 1 +#define SOL_IPV6 41 +#define SOL_PACKET 263 +#define SOL_NETLINK 270 + +#define SO_ACCEPTCONN 1 +#define SO_BROADCAST 2 +#define SO_DEBUG 3 +#define SO_DONTROUTE 4 +#define SO_ERROR 5 +#define SO_KEEPALIVE 6 +#define SO_LINGER 7 +#define SO_OOBINLINE 8 +#define SO_RCVBUF 9 +#define SO_RCVLOWAT 10 +#define SO_RCVTIMEO 11 +#define SO_REUSEADDR 12 +#define SO_SNDBUF 13 +#define SO_SNDLOWAT 14 +#define SO_SNDTIMEO 15 +#define SO_TYPE 16 +#define SO_SNDBUFFORCE 17 +#define SO_PEERCRED 18 +#define SO_ATTACH_FILTER 19 +#define SO_PASSCRED 20 +#define SO_RCVBUFFORCE 21 +#define SO_DETACH_FILTER 22 +#define SO_PROTOCOL 23 +#define SO_REUSEPORT 24 +#define SO_TIMESTAMP 25 +#define SO_PEERSEC 26 +#define SO_BINDTODEVICE 27 +#define SO_DOMAIN 28 +#define SO_PASSSEC 29 +#define SO_TIMESTAMPNS 30 +#define SO_PRIORITY 31 +#define SO_MARK 32 + +#define SOMAXCONN 1 + +#define MSG_CTRUNC 0x1 +#define MSG_DONTROUTE 0x2 +#define MSG_EOR 0x4 +#define MSG_OOB 0x8 +#define MSG_NOSIGNAL 0x10 +#define MSG_PEEK 0x20 +#define MSG_TRUNC 0x40 +#define MSG_WAITALL 0x80 +#define MSG_FIN 0x200 +#define MSG_CONFIRM 0x800 + +/* Linux extensions. */ +#define MSG_DONTWAIT 0x1000 +#define MSG_CMSG_CLOEXEC 0x2000 +#define MSG_MORE 0x4000 +#define MSG_FASTOPEN 0x20000000 + +/* GNU (?) extension: Protocol family constants. */ + +#define PF_INET 1 +#define PF_INET6 2 +#define PF_UNIX 3 +#define PF_LOCAL 3 +#define PF_UNSPEC 4 +#define PF_NETLINK 5 +#define PF_BRIDGE 6 +#define PF_APPLETALK 7 +#define PF_BLUETOOTH 8 +#define PF_DECnet 9 +#define PF_IPX 10 +#define PF_ISDN 11 +#define PF_SNA 12 +#define PF_PACKET 13 +#define PF_AX25 14 +#define PF_NETROM 15 +#define PF_ROSE 16 +#define PF_TIPC 30 +#define PF_ALG 38 +#define PF_MAX 46 + +#define AF_INET PF_INET +#define AF_INET6 PF_INET6 +#define AF_UNIX PF_UNIX +#define AF_LOCAL PF_LOCAL +#define AF_UNSPEC PF_UNSPEC +#define AF_NETLINK PF_NETLINK +#define AF_BRIDGE PF_BRIDGE +#define AF_APPLETALK PF_APPLETALK +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_DECnet PF_DECnet +#define AF_IPX PF_IPX +#define AF_ISDN PF_ISDN +#define AF_SNA PF_SNA +#define AF_PACKET PF_PACKET +#define AF_PACKET PF_PACKET +#define AF_AX25 PF_AX25 +#define AF_NETROM PF_NETROM +#define AF_ROSE PF_ROSE +#define AF_TIPC PF_TIPC +#define AF_ALG PF_ALG +#define AF_MAX PF_MAX + +#define SHUT_RD 1 +#define SHUT_RDWR 2 +#define SHUT_WR 3 +#endif diff --git a/user/include/mlibc/abis/ironclad/socklen_t.h b/user/include/mlibc/abis/ironclad/socklen_t.h new file mode 100644 index 0000000..190e5f9 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/socklen_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_SOCKLEN_T_H +#define _ABIBITS_SOCKLEN_T_H + +typedef unsigned socklen_t; + +#endif /* _ABIBITS_SOCKLEN_T_H */ diff --git a/user/include/mlibc/abis/ironclad/stat.h b/user/include/mlibc/abis/ironclad/stat.h new file mode 100644 index 0000000..7a507a0 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/stat.h @@ -0,0 +1,72 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +#define st_birthtim st_btim + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + struct timespec st_btim; + blksize_t st_blksize; + blkcnt_t st_blocks; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_STAT_H */ diff --git a/user/include/mlibc/abis/ironclad/statvfs.h b/user/include/mlibc/abis/ironclad/statvfs.h new file mode 100644 index 0000000..3b73bd8 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/statvfs.h @@ -0,0 +1,30 @@ +#ifndef _ABIBITS_STATVFS_H +#define _ABIBITS_STATVFS_H + +#include +#include + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_MANDLOCK 64 + +/* On Linux, this struct is not directly used by the kernel. */ +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; + char f_basetype[80]; +}; + +#endif /* _ABIBITS_STATVFS_H */ + diff --git a/user/include/mlibc/abis/ironclad/suseconds_t.h b/user/include/mlibc/abis/ironclad/suseconds_t.h new file mode 100644 index 0000000..723ddfa --- /dev/null +++ b/user/include/mlibc/abis/ironclad/suseconds_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SUSECONDS_T_H +#define _ABIBITS_SUSECONDS_T_H + +#include + +typedef __mlibc_int64 suseconds_t; + +#endif /* _ABIBITS_SUSECONDS_T_H */ diff --git a/user/include/mlibc/abis/ironclad/termios.h b/user/include/mlibc/abis/ironclad/termios.h new file mode 100644 index 0000000..32f23be --- /dev/null +++ b/user/include/mlibc/abis/ironclad/termios.h @@ -0,0 +1,117 @@ +#ifndef _ABIBITS_TERMIOS_H +#define _ABIBITS_TERMIOS_H + +typedef unsigned int cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +/* indices for the c_cc array in struct termios */ +#define NCCS 11 +#define VEOF 0 +#define VEOL 1 +#define VERASE 2 +#define VINTR 3 +#define VKILL 4 +#define VMIN 5 +#define VQUIT 6 +#define VSTART 7 +#define VSTOP 8 +#define VSUSP 9 +#define VTIME 10 +#define VLNEXT 15 + +/* bitwise flags for c_iflag in struct termios */ +#define BRKINT 0x0001 +#define ICRNL 0x0002 +#define IGNBRK 0x0004 +#define IGNCR 0x0008 +#define IGNPAR 0x0010 +#define INLCR 0x0020 +#define INPCK 0x0040 +#define ISTRIP 0x0080 +#define IXANY 0x0100 +#define IXOFF 0x0200 +#define IXON 0x0400 +#define PARMRK 0x0800 +#define ECHOCTL 0001000 +#define IMAXBEL 0020000 +#define ECHOKE 0004000 + +/* bitwise flags for c_oflag in struct termios */ +#define OPOST 0x0001 +#define ONLCR 0x0002 +#define OCRNL 0x0004 +#define ONOCR 0x0008 +#define ONLRET 0x0010 +#define OFDEL 0x0020 +#define OFILL 0x0040 + +#define NLDLY 0x0080 +#define NL0 0x0000 +#define NL1 0x0080 + +#define CRDLY 0x0300 +#define CR0 0x0000 +#define CR1 0x0100 +#define CR2 0x0200 +#define CR3 0x0300 + +#define TABDLY 0x0C00 +#define TAB0 0x0000 +#define TAB1 0x0400 +#define TAB2 0x0800 +#define TAB3 0x0C00 + +#define BSDLY 0x1000 +#define BS0 0x0000 +#define BS1 0x1000 + +#define VTDLY 0x2000 +#define VT0 0x0000 +#define VT1 0x2000 + +#define FFDLY 0x4000 +#define FF0 0x0000 +#define FF1 0x4000 + +/* bitwise constants for c_cflag in struct termios */ +#define CSIZE 0x0003 +#define CS5 0x0000 +#define CS6 0x0001 +#define CS7 0x0002 +#define CS8 0x0003 + +#define CSTOPB 0x0004 +#define CREAD 0x0008 +#define PARENB 0x0010 +#define PARODD 0x0020 +#define HUPCL 0x0040 +#define CLOCAL 0x0080 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define CBAUD 0x100F +#endif + +/* bitwise constants for c_lflag in struct termios */ +#define ECHO 0x0001 +#define ECHOE 0x0002 +#define ECHOK 0x0004 +#define ECHONL 0x0008 +#define ICANON 0x0010 +#define IEXTEN 0x0020 +#define ISIG 0x0040 +#define NOFLSH 0x0080 +#define TOSTOP 0x0100 +#define ECHOPRT 0x0200 + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +}; + +#endif diff --git a/user/include/mlibc/abis/ironclad/time.h b/user/include/mlibc/abis/ironclad/time.h new file mode 100644 index 0000000..dfc342e --- /dev/null +++ b/user/include/mlibc/abis/ironclad/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif /* _ABIBITS_TIME_H */ diff --git a/user/include/mlibc/abis/ironclad/uid_t.h b/user/include/mlibc/abis/ironclad/uid_t.h new file mode 100644 index 0000000..d39fa5f --- /dev/null +++ b/user/include/mlibc/abis/ironclad/uid_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif /* _ABIBITS_UID_T_H */ diff --git a/user/include/mlibc/abis/ironclad/utmp-defines.h b/user/include/mlibc/abis/ironclad/utmp-defines.h new file mode 100644 index 0000000..16d071f --- /dev/null +++ b/user/include/mlibc/abis/ironclad/utmp-defines.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_UTMP_DEFINES_H +#define _ABIBITS_UTMP_DEFINES_H + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +#endif /* _ABIBITS_UTMP_DEFINES_H */ diff --git a/user/include/mlibc/abis/ironclad/utmpx.h b/user/include/mlibc/abis/ironclad/utmpx.h new file mode 100644 index 0000000..4ad9db6 --- /dev/null +++ b/user/include/mlibc/abis/ironclad/utmpx.h @@ -0,0 +1,36 @@ +#ifndef _ABIBITS_UTMPX_H +#define _ABIBITS_UTMPX_H + +#include +#include + +#define __UT_HOSTSIZE 256 +#define __UT_NAMESIZE 32 +#define __UT_LINESIZE 32 + +/* Struct definition taken from musl */ +struct utmpx { + short ut_type; + short __ut_pad1; + pid_t ut_pid; + char ut_line[__UT_LINESIZE]; + char ut_id[4]; + char ut_user[__UT_NAMESIZE]; + char ut_host[__UT_HOSTSIZE]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + int ut_session, __ut_pad2; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +#define e_exit __e_exit +#define e_termination __e_termination + +#define UTMPX_FILE "/var/run/utmp" +#define WTMPX_FILE "/var/log/wtmp" + +#endif /* _ABIBITS_UTMPX_H */ diff --git a/user/include/mlibc/abis/ironclad/utsname.h b/user/include/mlibc/abis/ironclad/utsname.h new file mode 100644 index 0000000..598746f --- /dev/null +++ b/user/include/mlibc/abis/ironclad/utsname.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; +}; + +#endif /* _ABIBITS_UTSNAME_T_H */ diff --git a/user/include/mlibc/abis/ironclad/vm-flags.h b/user/include/mlibc/abis/ironclad/vm-flags.h new file mode 100644 index 0000000..0c894cd --- /dev/null +++ b/user/include/mlibc/abis/ironclad/vm-flags.h @@ -0,0 +1,31 @@ +#ifndef _ABIBITS_MMAP_FLAGS_H +#define _ABIBITS_MMAP_FLAGS_H + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_PRIVATE 0x01 +#define MAP_SHARED 0x02 +#define MAP_FIXED 0x04 +#define MAP_ANON 0x08 +#define MAP_ANONYMOUS 0x08 +#define MAP_NORESERVE 0x10 + +#define MS_ASYNC 0x01 +#define MS_SYNC 0x02 +#define MS_INVALIDATE 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_RANDOM 3 +#define POSIX_MADV_DONTNEED 4 +#define POSIX_MADV_WILLNEED 5 + +#endif /* _ABIBITS_MMAP_FLAGS_H */ diff --git a/user/include/mlibc/abis/ironclad/wait.h b/user/include/mlibc/abis/ironclad/wait.h new file mode 100644 index 0000000..f7fd89c --- /dev/null +++ b/user/include/mlibc/abis/ironclad/wait.h @@ -0,0 +1,25 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#define WCONTINUED 1 +#define WNOHANG 2 +#define WUNTRACED 4 +#define WEXITED 8 +#define WNOWAIT 16 +#define WSTOPPED 32 + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) ((x) & 0x000000FF) +#define WIFCONTINUED(x) ((x) & 0x00000100) +#define WIFEXITED(x) ((x) & 0x00000200) +#define WIFSIGNALED(x) ((x) & 0x00000400) +#define WIFSTOPPED(x) ((x) & 0x00000800) +#define WSTOPSIG(x) (((x) & 0x00FF0000) >> 16) +#define WTERMSIG(x) (((x) & 0xFF000000) >> 24) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +#endif /*_ABIBITS_WAIT_H */ diff --git a/user/include/mlibc/abis/keyronex/ipc.h b/user/include/mlibc/abis/keyronex/ipc.h new file mode 100644 index 0000000..5507c55 --- /dev/null +++ b/user/include/mlibc/abis/keyronex/ipc.h @@ -0,0 +1,51 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + short __ipc_perm_seq; + short __pad; + unsigned long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/abis/keyronex/random.h b/user/include/mlibc/abis/keyronex/random.h new file mode 100644 index 0000000..8e9fe26 --- /dev/null +++ b/user/include/mlibc/abis/keyronex/random.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_RANDOM_H +#define _ABIBITS_RANDOM_H + +#define GRND_RANDOM 1 +#define GRND_NONBLOCK 2 + +#endif /* _ABIBITS_RANDOM_H */ diff --git a/user/include/mlibc/abis/keyronex/riscv-hwprobe.h b/user/include/mlibc/abis/keyronex/riscv-hwprobe.h new file mode 100644 index 0000000..14b19c0 --- /dev/null +++ b/user/include/mlibc/abis/keyronex/riscv-hwprobe.h @@ -0,0 +1,107 @@ +#ifndef _ABIBITS_RISCV_HWPROBE_H +#define _ABIBITS_RISCV_HWPROBE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct riscv_hwprobe { + signed long long int key; + unsigned long long int value; +}; + +#define RISCV_HWPROBE_KEY_MVENDORID 0 +#define RISCV_HWPROBE_KEY_MARCHID 1 +#define RISCV_HWPROBE_KEY_MIMPID 2 +#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3 +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0) +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 +#define RISCV_HWPROBE_IMA_FD (1 << 0) +#define RISCV_HWPROBE_IMA_C (1 << 1) +#define RISCV_HWPROBE_IMA_V (1 << 2) +#define RISCV_HWPROBE_EXT_ZBA (1 << 3) +#define RISCV_HWPROBE_EXT_ZBB (1 << 4) +#define RISCV_HWPROBE_EXT_ZBS (1 << 5) +#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) +#define RISCV_HWPROBE_EXT_ZBC (1 << 7) +#define RISCV_HWPROBE_EXT_ZBKB (1 << 8) +#define RISCV_HWPROBE_EXT_ZBKC (1 << 9) +#define RISCV_HWPROBE_EXT_ZBKX (1 << 10) +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#define RISCV_HWPROBE_EXT_ZKNH (1 << 13) +#define RISCV_HWPROBE_EXT_ZKSED (1 << 14) +#define RISCV_HWPROBE_EXT_ZKSH (1 << 15) +#define RISCV_HWPROBE_EXT_ZKT (1 << 16) +#define RISCV_HWPROBE_EXT_ZVBB (1 << 17) +#define RISCV_HWPROBE_EXT_ZVBC (1 << 18) +#define RISCV_HWPROBE_EXT_ZVKB (1 << 19) +#define RISCV_HWPROBE_EXT_ZVKG (1 << 20) +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22) +#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23) +#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24) +#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25) +#define RISCV_HWPROBE_EXT_ZVKT (1 << 26) +#define RISCV_HWPROBE_EXT_ZFH (1 << 27) +#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) +#define RISCV_HWPROBE_EXT_ZVFH (1 << 30) +#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31) +#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) +#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) +#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) +#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) +#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36) +#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37) +#define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38) +#define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39) +#define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40) +#define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41) +#define RISCV_HWPROBE_EXT_ZIMOP (1ULL << 42) +#define RISCV_HWPROBE_EXT_ZCA (1ULL << 43) +#define RISCV_HWPROBE_EXT_ZCB (1ULL << 44) +#define RISCV_HWPROBE_EXT_ZCD (1ULL << 45) +#define RISCV_HWPROBE_EXT_ZCF (1ULL << 46) +#define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47) +#define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48) +#define RISCV_HWPROBE_EXT_SUPM (1ULL << 49) +#define RISCV_HWPROBE_EXT_ZICNTR (1ULL << 50) +#define RISCV_HWPROBE_EXT_ZIHPM (1ULL << 51) +#define RISCV_HWPROBE_EXT_ZFBFMIN (1ULL << 52) +#define RISCV_HWPROBE_EXT_ZVFBFMIN (1ULL << 53) +#define RISCV_HWPROBE_EXT_ZVFBFWMA (1ULL << 54) +#define RISCV_HWPROBE_EXT_ZICBOM (1ULL << 55) +#define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) +#define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) +#define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58) +#define RISCV_HWPROBE_KEY_CPUPERF_0 5 +#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) +#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) +#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0) +#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) +#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) +#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7 +#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8 +#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0 11 +#define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE 12 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0 13 + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RISCV_HWPROBE_H */ diff --git a/user/include/mlibc/abis/keyronex/rlim_t.h b/user/include/mlibc/abis/keyronex/rlim_t.h new file mode 100644 index 0000000..68cfcf5 --- /dev/null +++ b/user/include/mlibc/abis/keyronex/rlim_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +typedef unsigned long long rlim_t; + +#endif /* _ABIBITS_RLIM_T_H */ diff --git a/user/include/mlibc/abis/keyronex/shm.h b/user/include/mlibc/abis/keyronex/shm.h new file mode 100644 index 0000000..d435691 --- /dev/null +++ b/user/include/mlibc/abis/keyronex/shm.h @@ -0,0 +1,84 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; +}; + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/user/include/mlibc/abis/lemon/access.h b/user/include/mlibc/abis/lemon/access.h new file mode 100644 index 0000000..984bbed --- /dev/null +++ b/user/include/mlibc/abis/lemon/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 1 +#define R_OK 2 +#define W_OK 4 +#define X_OK 8 + +#endif /* _ABIBITS_ACCESS_H */ diff --git a/user/include/mlibc/abis/lemon/auxv.h b/user/include/mlibc/abis/lemon/auxv.h new file mode 100644 index 0000000..da7a438 --- /dev/null +++ b/user/include/mlibc/abis/lemon/auxv.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_EXECPATH 15 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 + +#endif diff --git a/user/include/mlibc/abis/lemon/blkcnt_t.h b/user/include/mlibc/abis/lemon/blkcnt_t.h new file mode 100644 index 0000000..1222088 --- /dev/null +++ b/user/include/mlibc/abis/lemon/blkcnt_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +/* TODO: use int64_t? */ +typedef long blkcnt_t; + +#endif /* _ABIBITS_BLKCNT_T_H */ diff --git a/user/include/mlibc/abis/lemon/blksize_t.h b/user/include/mlibc/abis/lemon/blksize_t.h new file mode 100644 index 0000000..e4c9f3f --- /dev/null +++ b/user/include/mlibc/abis/lemon/blksize_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +/* TODO: use int64_t? */ +typedef long blksize_t; + +#endif /* _ABIBITS_BLKSIZE_T_H */ + diff --git a/user/include/mlibc/abis/lemon/clockid_t.h b/user/include/mlibc/abis/lemon/clockid_t.h new file mode 100644 index 0000000..c3932ef --- /dev/null +++ b/user/include/mlibc/abis/lemon/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef long clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/user/include/mlibc/abis/lemon/dev_t.h b/user/include/mlibc/abis/lemon/dev_t.h new file mode 100644 index 0000000..16ccd69 --- /dev/null +++ b/user/include/mlibc/abis/lemon/dev_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +typedef unsigned long dev_t; + +#endif /* _ABIBITS_DEV_T_H */ + diff --git a/user/include/mlibc/abis/lemon/epoll.h b/user/include/mlibc/abis/lemon/epoll.h new file mode 100644 index 0000000..71ec2d5 --- /dev/null +++ b/user/include/mlibc/abis/lemon/epoll.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_EPOLL_H +#define _ABIBITS_EPOLL_H + +#define EPOLL_CLOEXEC 1 + +#endif /* _ABIBITS_EPOLL_H */ diff --git a/user/include/mlibc/abis/lemon/errno.h b/user/include/mlibc/abis/lemon/errno.h new file mode 100644 index 0000000..b621828 --- /dev/null +++ b/user/include/mlibc/abis/lemon/errno.h @@ -0,0 +1,126 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EDOM 1 +#define EILSEQ 2 +#define ERANGE 3 + +#define E2BIG 1001 +#define EACCES 1002 +#define EADDRINUSE 1003 +#define EADDRNOTAVAIL 1004 +#define EAFNOSUPPORT 1005 +#define EAGAIN 1006 +#define EALREADY 1007 +#define EBADF 1008 +#define EBADMSG 1009 +#define EBUSY 1010 +#define ECANCELED 1011 +#define ECHILD 1012 +#define ECONNABORTED 1013 +#define ECONNREFUSED 1014 +#define ECONNRESET 1015 +#define EDEADLK 1016 +#define EDESTADDRREQ 1017 +#define EDQUOT 1018 +#define EEXIST 1019 +#define EFAULT 1020 +#define EFBIG 1021 +#define EHOSTUNREACH 1022 +#define EIDRM 1023 +#define EINPROGRESS 1024 +#define EINTR 1025 +#define EINVAL 1026 +#define EIO 1027 +#define EISCONN 1028 +#define EISDIR 1029 +#define ELOOP 1030 +#define EMFILE 1031 +#define EMLINK 1032 +#define EMSGSIZE 1034 +#define EMULTIHOP 1035 +#define ENAMETOOLONG 1036 +#define ENETDOWN 1037 +#define ENETRESET 1038 +#define ENETUNREACH 1039 +#define ENFILE 1040 +#define ENOBUFS 1041 +#define ENODEV 1042 +#define ENOENT 1043 +#define ENOEXEC 1044 +#define ENOLCK 1045 +#define ENOLINK 1046 +#define ENOMEM 1047 +#define ENOMSG 1048 +#define ENOPROTOOPT 1049 +#define ENOSPC 1050 +#define ENOSYS 1051 +#define ENOTCONN 1052 +#define ENOTDIR 1053 +#define ENOTEMPTY 1054 +#define ENOTRECOVERABLE 1055 +#define ENOTSOCK 1056 +#define ENOTSUP 1057 +#define ENOTTY 1058 +#define ENXIO 1059 +#define EOPNOTSUPP 1060 +#define EOVERFLOW 1061 +#define EOWNERDEAD 1062 +#define EPERM 1063 +#define EPIPE 1064 +#define EPROTO 1065 +#define EPROTONOSUPPORT 1066 +#define EPROTOTYPE 1067 +#define EROFS 1068 +#define ESPIPE 1069 +#define ESRCH 1070 +#define ESTALE 1071 +#define ETIMEDOUT 1072 +#define ETXTBSY 1073 +#define EWOULDBLOCK EAGAIN +#define EXDEV 1075 +#define ENODATA 1076 +#define ETIME 1077 +#define ENOKEY 1078 +#define ESHUTDOWN 1079 +#define EHOSTDOWN 1080 +#define EBADFD 1081 +#define ENOMEDIUM 1082 +#define ENOTBLK 1083 +#define ENONET 1084 +#define EPFNOSUPPORT 1085 +#define ESOCKTNOSUPPORT 1086 +#define ESTRPIPE 1087 +#define EREMOTEIO 1088 +#define ERFKILL 1089 +#define EBADR 1090 +#define EUNATCH 1091 +#define EMEDIUMTYPE 1092 +#define EREMOTE 1093 +#define EKEYREJECTED 1094 +#define EUCLEAN 1095 +#define EBADSLT 1096 +#define ENOANO 1097 +#define ENOCSI 1098 +#define ENOSTR 1099 +#define ETOOMANYREFS 1100 +#define ENOPKG 1101 +#define EKEYREVOKED 1102 +#define EXFULL 1103 +#define ELNRNG 1104 +#define ENOTUNIQ 1105 +#define ERESTART 1106 +#define EUSERS 1107 +#define ECHRNG 1108 +#define ELIBBAD 1109 +#define EL2HLT 1110 +#define EL3HLT 1111 +#define EKEYEXPIRED 1112 +#define ECOMM 1113 +#define EBADE 1114 +#define EHWPOISON 1115 +#define EBADRQC 1116 + +#define EIEIO 1524152434 + +#endif /* _ABIBITS_ERRNO_H */ diff --git a/user/include/mlibc/abis/lemon/fcntl.h b/user/include/mlibc/abis/lemon/fcntl.h new file mode 100644 index 0000000..e61b32c --- /dev/null +++ b/user/include/mlibc/abis/lemon/fcntl.h @@ -0,0 +1,85 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +/* reserve 3 bits for the access mode */ +#define O_ACCMODE 0x0007 +#define O_EXEC 1 +#define O_RDONLY 2 +#define O_RDWR 3 +#define O_SEARCH 4 +#define O_WRONLY 5 + +/* these flags get their own bit */ +#define O_APPEND 0x000008 +#define O_CREAT 0x000010 +#define O_DIRECTORY 0x000020 +#define O_EXCL 0x000040 +#define O_NOCTTY 0x000080 +#define O_NOFOLLOW 0x000100 +#define O_TRUNC 0x000200 +#define O_NONBLOCK 0x000400 +#define O_DSYNC 0x000800 +#define O_RSYNC 0x001000 +#define O_SYNC 0x002000 +#define O_CLOEXEC 0x004000 +#define O_PATH 0x008000 +#define O_LARGEFILE 0x010000 +#define O_NOATIME 0x020000 +#define O_ASYNC 0x040000 +#define O_TMPFILE 0x080000 +#define O_DIRECT 0x100000 + +/* constants for fcntl()'s command argument */ +#define F_DUPFD 1 +#define F_DUPFD_CLOEXEC 2 +#define F_GETFD 3 +#define F_SETFD 4 +#define F_GETFL 5 +#define F_SETFL 6 +#define F_GETLK 7 +#define F_SETLK 8 +#define F_SETLK64 F_SETLK +#define F_SETLKW 9 +#define F_SETLKW64 F_SETLKW +#define F_GETOWN 10 +#define F_SETOWN 11 + +/* constants for struct flock's l_type member */ +#define F_RDLCK 1 +#define F_UNLCK 2 +#define F_WRLCK 3 + +/* constants for fcntl()'s additional argument of F_GETFD and F_SETFD */ +#define FD_CLOEXEC 1 + +/* Used by mmap */ +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 +#define F_SEAL_SEAL 0x0010 +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define AT_EMPTY_PATH 1 +#define AT_SYMLINK_FOLLOW 2 +#define AT_SYMLINK_NOFOLLOW 4 +#define AT_REMOVEDIR 8 +#define AT_EACCESS 512 +#define AT_NO_AUTOMOUNT 1024 +#define AT_STATX_SYNC_AS_STAT 0 +#define AT_STATX_FORCE_SYNC 2048 +#define AT_STATX_DONT_SYNC 4096 +#define AT_STATX_SYNC_TYPE 6144 + +#define AT_FDCWD -100 + +#define POSIX_FADV_NORMAL 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_NOREUSE 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_WILLNEED 5 +#define POSIX_FADV_RANDOM 6 + +#endif /* _ABITBITS_FCNTL_H */ diff --git a/user/include/mlibc/abis/lemon/gid_t.h b/user/include/mlibc/abis/lemon/gid_t.h new file mode 100644 index 0000000..f513e25 --- /dev/null +++ b/user/include/mlibc/abis/lemon/gid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif /* _ABIBITS_GID_T_H */ + diff --git a/user/include/mlibc/abis/lemon/in.h b/user/include/mlibc/abis/lemon/in.h new file mode 100644 index 0000000..3b4df5b --- /dev/null +++ b/user/include/mlibc/abis/lemon/in.h @@ -0,0 +1,169 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t pad[8]; +}; +#define sin_zero pad /* for BSD Unix compatibility */ + +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + unsigned int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +#define IPPROTO_IP 1 +#define IPPROTO_IPV6 2 +#define IPPROTO_ICMP 3 +#define IPPROTO_RAW 4 +#define IPPROTO_TCP 5 +#define IPPROTO_UDP 6 +#define IPPROTO_IGMP 7 +#define IPPROTO_IPIP 8 +#define IPPROTO_DCCP 33 +#define IPPROTO_ROUTING 43 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MAX 256 + +#define INADDR_ANY ((in_addr_t)0x00000000) +#define INADDR_BROADCAST ((in_addr_t)0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t)0x7f000001) +#define INADDR_NONE ((in_addr_t)0xffffffff) + +#define INET_ADDRSTRLEN 16 + +#define INET6_ADDRSTRLEN 46 + +#define IPV6_JOIN_GROUP 1 +#define IPV6_LEAVE_GROUP 2 +#define IPV6_MULTICAST_HOPS 3 +#define IPV6_MULTICAST_IF 4 +#define IPV6_MULTICAST_LOOP 5 +#define IPV6_UNICAST_HOPS 6 +#define IPV6_V6ONLY 7 +#define IPV6_PMTUDISC_DONT 8 +#define IPV6_PMTUDISC_DO 9 +#define IPV6_MTU 10 +#define IPV6_2292PKTOPTIONS 11 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_RECVERR 25 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_TCLASS 67 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_OPTIONS 4 +#define IP_PMTUDISC_OMIT 5 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_UNICAST_IF 13 +#define IP_MTU 14 + +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_DO 2 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#endif /* _ABIBITS_IN_H */ diff --git a/user/include/mlibc/abis/lemon/ino_t.h b/user/include/mlibc/abis/lemon/ino_t.h new file mode 100644 index 0000000..049e16e --- /dev/null +++ b/user/include/mlibc/abis/lemon/ino_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +/* TODO: use (u)int64_t? */ +typedef long ino_t; + +#endif /* _ABIBITS_INO_T_H */ + diff --git a/user/include/mlibc/abis/lemon/inotify.h b/user/include/mlibc/abis/lemon/inotify.h new file mode 100644 index 0000000..f30a0bc --- /dev/null +++ b/user/include/mlibc/abis/lemon/inotify.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_INOTIFY_H +#define _ABIBITS_INOTIFY_H + +#define IN_CLOEXEC 1 +#define IN_NONBLOCK 2 + +#endif /* _ABIBITS_INOTIFY_H */ diff --git a/user/include/mlibc/abis/lemon/ipc.h b/user/include/mlibc/abis/lemon/ipc.h new file mode 100644 index 0000000..5507c55 --- /dev/null +++ b/user/include/mlibc/abis/lemon/ipc.h @@ -0,0 +1,51 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + short __ipc_perm_seq; + short __pad; + unsigned long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/abis/lemon/limits.h b/user/include/mlibc/abis/lemon/limits.h new file mode 100644 index 0000000..9c7bdf1 --- /dev/null +++ b/user/include/mlibc/abis/lemon/limits.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 + +/* Niceness related */ +#define NZERO 20 + +/* Maximum hostname length, posix defines it as 255 */ +#define HOST_NAME_MAX 255 + +#define OPEN_MAX 256 + +#endif /*_ABIBITS_LIMITS_H */ diff --git a/user/include/mlibc/abis/lemon/mode_t.h b/user/include/mlibc/abis/lemon/mode_t.h new file mode 100644 index 0000000..b1a11f3 --- /dev/null +++ b/user/include/mlibc/abis/lemon/mode_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef int mode_t; + +#endif /* _ABIBITS_MODE_T_H */ + diff --git a/user/include/mlibc/abis/lemon/nlink_t.h b/user/include/mlibc/abis/lemon/nlink_t.h new file mode 100644 index 0000000..49c7e0f --- /dev/null +++ b/user/include/mlibc/abis/lemon/nlink_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef int nlink_t; + +#endif /* _ABIBITS_NLINK_T_H */ + diff --git a/user/include/mlibc/abis/lemon/packet.h b/user/include/mlibc/abis/lemon/packet.h new file mode 100644 index 0000000..ae4b92e --- /dev/null +++ b/user/include/mlibc/abis/lemon/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif /* _ABIBITS_PACKET_H */ diff --git a/user/include/mlibc/abis/lemon/pid_t.h b/user/include/mlibc/abis/lemon/pid_t.h new file mode 100644 index 0000000..9591edb --- /dev/null +++ b/user/include/mlibc/abis/lemon/pid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif /* _ABIBITS_PID_T_H */ + diff --git a/user/include/mlibc/abis/lemon/poll.h b/user/include/mlibc/abis/lemon/poll.h new file mode 100644 index 0000000..c2ef284 --- /dev/null +++ b/user/include/mlibc/abis/lemon/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x01 +#define POLLOUT 0x02 +#define POLLPRI 0x04 +#define POLLHUP 0x08 +#define POLLERR 0x10 +#define POLLRDHUP 0x20 +#define POLLNVAL 0x40 +#define POLLWRNORM 0x80 +#define POLLRDNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLRDBAND 0x400 + +#endif /* _ABIBITS_POLL_H */ diff --git a/user/include/mlibc/abis/lemon/ptrace.h b/user/include/mlibc/abis/lemon/ptrace.h new file mode 100644 index 0000000..158bf67 --- /dev/null +++ b/user/include/mlibc/abis/lemon/ptrace.h @@ -0,0 +1,56 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 14 +#define PTRACE_SETREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_GETFPREGS 20 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_CE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif /* _ABIBITS_PTRACE_H */ diff --git a/user/include/mlibc/abis/lemon/random.h b/user/include/mlibc/abis/lemon/random.h new file mode 100644 index 0000000..8e9fe26 --- /dev/null +++ b/user/include/mlibc/abis/lemon/random.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_RANDOM_H +#define _ABIBITS_RANDOM_H + +#define GRND_RANDOM 1 +#define GRND_NONBLOCK 2 + +#endif /* _ABIBITS_RANDOM_H */ diff --git a/user/include/mlibc/abis/lemon/resource.h b/user/include/mlibc/abis/lemon/resource.h new file mode 100644 index 0000000..6cb82b2 --- /dev/null +++ b/user/include/mlibc/abis/lemon/resource.h @@ -0,0 +1,53 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 1 +#define RUSAGE_CHILDREN 2 + +#define RLIMIT_CORE 1 +#define RLIMIT_CPU 2 +#define RLIMIT_DATA 3 +#define RLIMIT_FSIZE 4 +#define RLIMIT_NOFILE 5 +#define RLIMIT_STACK 6 +#define RLIMIT_AS 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_RSS 9 +#define RLIMIT_NPROC 10 +#define RLIMIT_LOCKS 11 +#define RLIMIT_SIGPENDING 12 +#define RLIMIT_MSGQUEUE 13 +#define RLIMIT_NICE 14 +#define RLIMIT_RTPRIO 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long int ru_maxrss; + long int ru_ixrss; + long int ru_idrss; + long int ru_isrss; + long int ru_minflt; + long int ru_majflt; + long int ru_nswap; + long int ru_inblock; + long int ru_oublock; + long int ru_msgsnd; + long int ru_msgrcv; + long int ru_nsignals; + long int ru_nvcsw; + long int ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RESOURCE_H */ diff --git a/user/include/mlibc/abis/lemon/rlim_t.h b/user/include/mlibc/abis/lemon/rlim_t.h new file mode 100644 index 0000000..68cfcf5 --- /dev/null +++ b/user/include/mlibc/abis/lemon/rlim_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +typedef unsigned long long rlim_t; + +#endif /* _ABIBITS_RLIM_T_H */ diff --git a/user/include/mlibc/abis/lemon/shm.h b/user/include/mlibc/abis/lemon/shm.h new file mode 100644 index 0000000..d435691 --- /dev/null +++ b/user/include/mlibc/abis/lemon/shm.h @@ -0,0 +1,84 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; +}; + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/user/include/mlibc/abis/lemon/stat.h b/user/include/mlibc/abis/lemon/stat.h new file mode 100644 index 0000000..37f6aaa --- /dev/null +++ b/user/include/mlibc/abis/lemon/stat.h @@ -0,0 +1,69 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + blksize_t st_blksize; + blkcnt_t st_blocks; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_STAT_H */ diff --git a/user/include/mlibc/abis/lemon/time.h b/user/include/mlibc/abis/lemon/time.h new file mode 100644 index 0000000..dfc342e --- /dev/null +++ b/user/include/mlibc/abis/lemon/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif /* _ABIBITS_TIME_H */ diff --git a/user/include/mlibc/abis/lemon/uid_t.h b/user/include/mlibc/abis/lemon/uid_t.h new file mode 100644 index 0000000..976540b --- /dev/null +++ b/user/include/mlibc/abis/lemon/uid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif /* _ABIBITS_UID_T_H */ + diff --git a/user/include/mlibc/abis/lemon/utsname.h b/user/include/mlibc/abis/lemon/utsname.h new file mode 100644 index 0000000..080df37 --- /dev/null +++ b/user/include/mlibc/abis/lemon/utsname.h @@ -0,0 +1,18 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +#if __MLIBC_BUILDING_MLIBC +#warning utsname.h is a broken header originally from the deprecated "mlibc" ABI. \ + We suggest to use abis/linux/utsname.h instead. \ + Note that this will potentially require kernel changes. +#endif + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; +}; + +#endif /* _ABIBITS_UTSNAME_T_H */ diff --git a/user/include/mlibc/abis/lemon/vm-flags.h b/user/include/mlibc/abis/lemon/vm-flags.h new file mode 100644 index 0000000..769275a --- /dev/null +++ b/user/include/mlibc/abis/lemon/vm-flags.h @@ -0,0 +1,46 @@ +#ifndef _ABIBITS_MMAP_FLAGS_H +#define _ABIBITS_MMAP_FLAGS_H + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_PRIVATE 0x01 +#define MAP_SHARED 0x02 +#define MAP_FIXED 0x04 +#define MAP_ANON 0x08 +#define MAP_ANONYMOUS 0x08 +#define MAP_NORESERVE 0x10 +#define MAP_FIXED_NOREPLACE 0x20 + +#define MS_ASYNC 0x01 +#define MS_SYNC 0x02 +#define MS_INVALIDATE 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_RANDOM 3 +#define POSIX_MADV_DONTNEED 4 +#define POSIX_MADV_WILLNEED 5 + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 + +/* Linux extensions: */ +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U + +#endif /* _ABIBITS_MMAP_FLAGS_H */ diff --git a/user/include/mlibc/abis/linux/access.h b/user/include/mlibc/abis/linux/access.h new file mode 100644 index 0000000..320044a --- /dev/null +++ b/user/include/mlibc/abis/linux/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +#endif /* _ABIBITS_ACCESS_H */ diff --git a/user/include/mlibc/abis/linux/auxv.h b/user/include/mlibc/abis/linux/auxv.h new file mode 100644 index 0000000..b86f199 --- /dev/null +++ b/user/include/mlibc/abis/linux/auxv.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_PLATFORM 15 +#define AT_HWCAP 16 +#define AT_CLKTCK 17 +#define AT_FPUCW 18 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_HWCAP2 26 +#define AT_HWCAP3 29 +#define AT_HWCAP4 30 +#define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 + +#endif /* _ABIBITS_AUXV_H */ diff --git a/user/include/mlibc/abis/linux/blkcnt_t.h b/user/include/mlibc/abis/linux/blkcnt_t.h new file mode 100644 index 0000000..fbbb9b8 --- /dev/null +++ b/user/include/mlibc/abis/linux/blkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +#include + +typedef __mlibc_int64 blkcnt_t; + +#endif /* _ABIBITS_BLKCNT_T_H */ diff --git a/user/include/mlibc/abis/linux/blksize_t.h b/user/include/mlibc/abis/linux/blksize_t.h new file mode 100644 index 0000000..02b207a --- /dev/null +++ b/user/include/mlibc/abis/linux/blksize_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +typedef long blksize_t; + +#endif /* _ABIBITS_BLKSIZE_T_H */ + diff --git a/user/include/mlibc/abis/linux/clockid_t.h b/user/include/mlibc/abis/linux/clockid_t.h new file mode 100644 index 0000000..8d92826 --- /dev/null +++ b/user/include/mlibc/abis/linux/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef int clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/user/include/mlibc/abis/linux/dev_t.h b/user/include/mlibc/abis/linux/dev_t.h new file mode 100644 index 0000000..c39ab67 --- /dev/null +++ b/user/include/mlibc/abis/linux/dev_t.h @@ -0,0 +1,10 @@ + +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +#include + +typedef __mlibc_uint64 dev_t; + +#endif /* _ABIBITS_DEV_T_H */ + diff --git a/user/include/mlibc/abis/linux/epoll.h b/user/include/mlibc/abis/linux/epoll.h new file mode 100644 index 0000000..ebfcda5 --- /dev/null +++ b/user/include/mlibc/abis/linux/epoll.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_EPOLL_H +#define _ABIBITS_EPOLL_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define EPOLL_CLOEXEC 02000000 /* Same as __MLIBC_O_CLOEXEC */ + +#endif /* _ABIBITS_EPOLL_H */ diff --git a/user/include/mlibc/abis/linux/errno.h b/user/include/mlibc/abis/linux/errno.h new file mode 100644 index 0000000..bac314f --- /dev/null +++ b/user/include/mlibc/abis/linux/errno.h @@ -0,0 +1,143 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EWOULDBLOCK EAGAIN +#define ENOMSG 42 +#define EIDRM 43 +#define ECHRNG 44 +#define EL2NSYNC 45 +#define EL3HLT 46 +#define EL3RST 47 +#define ELNRNG 48 +#define EUNATCH 49 +#define ENOCSI 50 +#define EL2HLT 51 +#define EBADE 52 +#define EBADR 53 +#define EXFULL 54 +#define ENOANO 55 +#define EBADRQC 56 +#define EBADSLT 57 +#define EDEADLOCK EDEADLK +#define EBFONT 59 +#define ENOSTR 60 +#define ENODATA 61 +#define ETIME 62 +#define ENOSR 63 +#define ENONET 64 +#define ENOPKG 65 +#define EREMOTE 66 +#define ENOLINK 67 +#define EADV 68 +#define ESRMNT 69 +#define ECOMM 70 +#define EPROTO 71 +#define EMULTIHOP 72 +#define EDOTDOT 73 +#define EBADMSG 74 +#define EOVERFLOW 75 +#define ENOTUNIQ 76 +#define EBADFD 77 +#define EREMCHG 78 +#define ELIBACC 79 +#define ELIBBAD 80 +#define ELIBSCN 81 +#define ELIBMAX 82 +#define ELIBEXEC 83 +#define EILSEQ 84 +#define ERESTART 85 +#define ESTRPIPE 86 +#define EUSERS 87 +#define ENOTSOCK 88 +#define EDESTADDRREQ 89 +#define EMSGSIZE 90 +#define EPROTOTYPE 91 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP 95 +#define ENOTSUP EOPNOTSUPP +#define EPFNOSUPPORT 96 +#define EAFNOSUPPORT 97 +#define EADDRINUSE 98 +#define EADDRNOTAVAIL 99 +#define ENETDOWN 100 +#define ENETUNREACH 101 +#define ENETRESET 102 +#define ECONNABORTED 103 +#define ECONNRESET 104 +#define ENOBUFS 105 +#define EISCONN 106 +#define ENOTCONN 107 +#define ESHUTDOWN 108 +#define ETOOMANYREFS 109 +#define ETIMEDOUT 110 +#define ECONNREFUSED 111 +#define EHOSTDOWN 112 +#define EHOSTUNREACH 113 +#define EALREADY 114 +#define EINPROGRESS 115 +#define ESTALE 116 +#define EUCLEAN 117 +#define ENOTNAM 118 +#define ENAVAIL 119 +#define EISNAM 120 +#define EREMOTEIO 121 +#define EDQUOT 122 +#define ENOMEDIUM 123 +#define EMEDIUMTYPE 124 +#define ECANCELED 125 +#define ENOKEY 126 +#define EKEYEXPIRED 127 +#define EKEYREVOKED 128 +#define EKEYREJECTED 129 +#define EOWNERDEAD 130 +#define ENOTRECOVERABLE 131 +#define ERFKILL 132 +#define EHWPOISON 133 + + +/* This is mlibc-specific. */ +#define EIEIO 4095 + +#endif /* _ABIBITS_ERRNO_H */ diff --git a/user/include/mlibc/abis/linux/fcntl.h b/user/include/mlibc/abis/linux/fcntl.h new file mode 100644 index 0000000..8eb92bc --- /dev/null +++ b/user/include/mlibc/abis/linux/fcntl.h @@ -0,0 +1,124 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +#include +#include + +#define O_PATH 010000000 + +#define O_ACCMODE (03 | O_PATH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_LARGEFILE 0100000 +#define O_NOATIME 01000000 +#define O_TMPFILE 020000000 + +#define O_EXEC O_PATH +#define O_SEARCH O_PATH + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLK64 F_SETLK +#define F_SETLKW 7 +#define F_SETLKW64 F_SETLKW + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 + +#define F_SETLEASE 1024 +#define F_GETLEASE 1025 +#define F_NOTIFY 1026 +#define F_DUPFD_CLOEXEC 1030 +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define F_SEAL_SEAL 0x0001 +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 + +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define FD_CLOEXEC 1 + +#define AT_FDCWD -100 +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 +#define AT_NO_AUTOMOUNT 0x800 +#define AT_EMPTY_PATH 0x1000 + +#if __MLIBC_LINUX_OPTION + +#define DN_ACCESS 1 +#define DN_MODIFY 2 +#define DN_CREATE 4 +#define DN_DELETE 8 +#define DN_RENAME 16 +#define DN_ATTRIB 32 +#define DN_MULTISHOT 0x80000000 + +#define AT_STATX_SYNC_AS_STAT 0x0000 +#define AT_STATX_FORCE_SYNC 0x2000 +#define AT_STATX_DONT_SYNC 0x4000 +#define AT_STATX_SYNC_TYPE 0x6000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#if defined(_GNU_SOURCE) +struct f_owner_ex { + int type; + pid_t pid; +}; +#endif /* _GNU_SOURCE */ + +#define F_OWNER_TID 0 +#define F_OWNER_PID 1 +#define F_OWNER_PGRP 2 + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 + +#endif /* _ABIBITS_FCNTL_H */ diff --git a/user/include/mlibc/abis/linux/fsblkcnt_t.h b/user/include/mlibc/abis/linux/fsblkcnt_t.h new file mode 100644 index 0000000..0d74456 --- /dev/null +++ b/user/include/mlibc/abis/linux/fsblkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSBLKCNT_T_H +#define _ABIBITS_FSBLKCNT_T_H + +#include + +typedef __mlibc_uint64 fsblkcnt_t; + +#endif /* _ABIBITS_FSBLKCNT_T_H */ diff --git a/user/include/mlibc/abis/linux/fsfilcnt_t.h b/user/include/mlibc/abis/linux/fsfilcnt_t.h new file mode 100644 index 0000000..1abda9a --- /dev/null +++ b/user/include/mlibc/abis/linux/fsfilcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSFILCNT_T_H +#define _ABIBITS_FSFILCNT_T_H + +#include + +typedef __mlibc_uint64 fsfilcnt_t; + +#endif /* _ABIBITS_FSFILCNT_T_H */ diff --git a/user/include/mlibc/abis/linux/gid_t.h b/user/include/mlibc/abis/linux/gid_t.h new file mode 100644 index 0000000..f513e25 --- /dev/null +++ b/user/include/mlibc/abis/linux/gid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif /* _ABIBITS_GID_T_H */ + diff --git a/user/include/mlibc/abis/linux/in.h b/user/include/mlibc/abis/linux/in.h new file mode 100644 index 0000000..3ed7919 --- /dev/null +++ b/user/include/mlibc/abis/linux/in.h @@ -0,0 +1,235 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t sin_zero[8]; +}; + +#if !__MLIBC_LINUX_OPTION || (!defined(_UAPI_LINUX_IN6_H) && !defined(_UAPI_IPV6_H)) +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; +#endif /* !__MLIBC_LINUX_OPTION || (!defined(_UAPI_LINUX_IN6_H) && !defined(_UAPI_IPV6_H)) */ + +#define MCAST_INCLUDE 1 + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_req { + uint32_t gr_interface; + struct sockaddr_storage gr_group; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#define INADDR_ANY ((in_addr_t) 0x00000000) +#define INADDR_BROADCAST ((in_addr_t) 0xffffffff) +#define INADDR_NONE ((in_addr_t) 0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t) 0x7f000001) + +#define INADDR_UNSPEC_GROUP ((in_addr_t) 0xe0000000) +#define INADDR_ALLHOSTS_GROUP ((in_addr_t) 0xe0000001) +#define INADDR_ALLRTRS_GROUP ((in_addr_t) 0xe0000002) +#define INADDR_ALLSNOOPERS_GROUP ((in_addr_t) 0xe000006a) +#define INADDR_MAX_LOCAL_GROUP ((in_addr_t) 0xe00000ff) + +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + +#define IPPORT_RESERVED 1024 + +#define IPPROTO_IP 0 +#define IPPROTO_HOPOPTS 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_IGMP 2 +#define IPPROTO_IPIP 4 +#define IPPROTO_TCP 6 +#define IPPROTO_EGP 8 +#define IPPROTO_PUP 12 +#define IPPROTO_UDP 17 +#define IPPROTO_IDP 22 +#define IPPROTO_TP 29 +#define IPPROTO_DCCP 33 +#define IPPROTO_IPV6 41 +#define IPPROTO_ROUTING 43 +#define IPPROTO_FRAGMENT 44 +#define IPPROTO_RSVP 46 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_NONE 59 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_MTP 92 +#define IPPROTO_BEETPH 94 +#define IPPROTO_ENCAP 98 +#define IPPROTO_PIM 103 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_MH 135 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MPLS 137 +#define IPPROTO_RAW 255 +#define IPPROTO_MAX 256 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_HDRINCL 3 +#define IP_OPTIONS 4 +#define IP_RECVOPTS 6 +#define IP_RETOPTS 7 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_MTU 14 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define IP_UNICAST_IF 50 + +#define IPV6_2292PKTOPTIONS 6 +#define IPV6_2292HOPLIMIT 8 +#define IPV6_UNICAST_HOPS 16 +#define IPV6_MULTICAST_IF 17 +#define IPV6_MULTICAST_HOPS 18 +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_JOIN_GROUP 20 +#define IPV6_LEAVE_GROUP 21 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_MTU 24 +#define IPV6_RECVERR 25 +#define IPV6_V6ONLY 26 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 + +#define IPV6_RECVTCLASS 66 +#define IPV6_TCLASS 67 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#define IPV6_PMTUDISC_DONT 0 +#define IPV6_PMTUDISC_WANT 1 +#define IPV6_PMTUDISC_DO 2 +#define IPV6_PMTUDISC_PROBE 3 +#define IPV6_PMTUDISC_INTERFACE 4 +#define IPV6_PMTUDISC_OMIT 5 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_WANT 1 +#define IP_PMTUDISC_DO 2 +#define IP_PMTUDISC_PROBE 3 +#define IP_PMTUDISC_INTERFACE 4 +#define IP_PMTUDISC_OMIT 5 + +#define MCAST_JOIN_GROUP 42 +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#if __MLIBC_LINUX_OPTION + +#define __UAPI_DEF_IN_ADDR 0 +#define __UAPI_DEF_IN_CLASS 0 +#define __UAPI_DEF_IN_IPPROTO 0 +#define __UAPI_DEF_IN_PKTINFO 0 +#define __UAPI_DEF_IP_MREQ 0 +#define __UAPI_DEF_SOCKADDR_IN 0 + +#define __UAPI_DEF_IN6_ADDR 0 +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#define __UAPI_DEF_IN6_PKTINFO 0 +#define __UAPI_DEF_IP6_MTUINFO 0 +#define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_MREQ 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 +#define __UAPI_DEF_SOCKADDR_IN6 0 + +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABITBITS_IN_H */ diff --git a/user/include/mlibc/abis/linux/ino_t.h b/user/include/mlibc/abis/linux/ino_t.h new file mode 100644 index 0000000..3f48c32 --- /dev/null +++ b/user/include/mlibc/abis/linux/ino_t.h @@ -0,0 +1,11 @@ + +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +#include + +typedef __mlibc_uint64 ino_t; +typedef ino_t ino64_t; + +#endif /* _ABIBITS_INO_T_H */ + diff --git a/user/include/mlibc/abis/linux/inotify.h b/user/include/mlibc/abis/linux/inotify.h new file mode 100644 index 0000000..c3989ce --- /dev/null +++ b/user/include/mlibc/abis/linux/inotify.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_INOTIFY_H +#define _ABIBITS_INOTIFY_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#include + +#define IN_CLOEXEC O_CLOEXEC +#define IN_NONBLOCK O_NONBLOCK + +#endif /* _ABIBITS_INOTIFY_H */ diff --git a/user/include/mlibc/abis/linux/ioctls.h b/user/include/mlibc/abis/linux/ioctls.h new file mode 100644 index 0000000..f3606a3 --- /dev/null +++ b/user/include/mlibc/abis/linux/ioctls.h @@ -0,0 +1,20 @@ +#ifndef _ABIBITS_IOCTLS_H +#define _ABIBITS_IOCTLS_H + +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D + +#define SIOCPROTOPRIVATE 0x89E0 +#define SIOCGSTAMP 0x8906 +#define SIOCGIFNAME 0x8910 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFADDR 0x8915 +#define SIOCGIFINDEX 0x8933 +#define SIOCATMARK 0x8905 +#define SIOCGIFHWADDR 0x8927 +#define SIOCGIFBRDADDR 0x8919 +#define SIOCGIFNETMASK 0x891B + +#endif /* _ABIBITS_IOCTLS_H */ diff --git a/user/include/mlibc/abis/linux/ipc.h b/user/include/mlibc/abis/linux/ipc.h new file mode 100644 index 0000000..b5f9f11 --- /dev/null +++ b/user/include/mlibc/abis/linux/ipc.h @@ -0,0 +1,50 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + int __ipc_perm_seq; + long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/abis/linux/limits.h b/user/include/mlibc/abis/linux/limits.h new file mode 100644 index 0000000..1363bc0 --- /dev/null +++ b/user/include/mlibc/abis/linux/limits.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 +#define LOGIN_NAME_MAX 256 +#define HOST_NAME_MAX 64 +#define NAME_MAX 255 +#define OPEN_MAX 256 + +#endif /*_ABIBITS_LIMITS_H */ diff --git a/user/include/mlibc/abis/linux/mode_t.h b/user/include/mlibc/abis/linux/mode_t.h new file mode 100644 index 0000000..8deed27 --- /dev/null +++ b/user/include/mlibc/abis/linux/mode_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef unsigned int mode_t; + +#endif /* _ABIBITS_MODE_T_H */ + diff --git a/user/include/mlibc/abis/linux/mqueue.h b/user/include/mlibc/abis/linux/mqueue.h new file mode 100644 index 0000000..1e2d3eb --- /dev/null +++ b/user/include/mlibc/abis/linux/mqueue.h @@ -0,0 +1,21 @@ +#ifndef _ABIBITS_MQUEUE_H +#define _ABIBITS_MQUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct mq_attr { + long mq_flags; + long mq_maxmsg; + long mq_msgsize; + long mq_curmsgs; + long __pad[4]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MQUEUE_H */ + diff --git a/user/include/mlibc/abis/linux/msg.h b/user/include/mlibc/abis/linux/msg.h new file mode 100644 index 0000000..577456c --- /dev/null +++ b/user/include/mlibc/abis/linux/msg.h @@ -0,0 +1,45 @@ +#ifndef _ABIBITS_MSG_H +#define _ABIBITS_MSG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long msglen_t; +typedef unsigned long msgqnum_t; + +struct msqid64_ds { + struct ipc64_perm msg_perm; +#if (UINTPTR_MAX == UINT64_MAX) /* || x32 ABI */ + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; +#else + unsigned long msg_stime; + unsigned long msg_stime_high; + unsigned long msg_rtime; + unsigned long msg_rtime_high; + unsigned long msg_ctime; + unsigned long msg_ctime_high; +#endif + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; +}; + +#define msqid_ds msqid64_ds + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MSG_H */ + diff --git a/user/include/mlibc/abis/linux/nlink_t.h b/user/include/mlibc/abis/linux/nlink_t.h new file mode 100644 index 0000000..eb15553 --- /dev/null +++ b/user/include/mlibc/abis/linux/nlink_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef unsigned long nlink_t; + +#endif /* _ABIBITS_NLINK_T_H */ + diff --git a/user/include/mlibc/abis/linux/packet.h b/user/include/mlibc/abis/linux/packet.h new file mode 100644 index 0000000..ae4b92e --- /dev/null +++ b/user/include/mlibc/abis/linux/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif /* _ABIBITS_PACKET_H */ diff --git a/user/include/mlibc/abis/linux/pid_t.h b/user/include/mlibc/abis/linux/pid_t.h new file mode 100644 index 0000000..9591edb --- /dev/null +++ b/user/include/mlibc/abis/linux/pid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif /* _ABIBITS_PID_T_H */ + diff --git a/user/include/mlibc/abis/linux/poll.h b/user/include/mlibc/abis/linux/poll.h new file mode 100644 index 0000000..780d439 --- /dev/null +++ b/user/include/mlibc/abis/linux/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 +#define POLLRDNORM 0x0040 +#define POLLRDBAND 0x0080 +#define POLLWRNORM 0x0100 +#define POLLWRBAND 0x0200 +#define POLLRDHUP 0x2000 + +#endif /* _ABIBITS_POLL_H */ diff --git a/user/include/mlibc/abis/linux/ptrace.h b/user/include/mlibc/abis/linux/ptrace.h new file mode 100644 index 0000000..08f7b09 --- /dev/null +++ b/user/include/mlibc/abis/linux/ptrace.h @@ -0,0 +1,65 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error "ptrace() is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_POKEUSER 6 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 +#define PTRACE_EVENT_STOP 128 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif /* _ABIBITS_PTRACE_H */ diff --git a/user/include/mlibc/abis/linux/random.h b/user/include/mlibc/abis/linux/random.h new file mode 100644 index 0000000..ccddf9f --- /dev/null +++ b/user/include/mlibc/abis/linux/random.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_RANDOM_H +#define _ABIBITS_RANDOM_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error "getrandom() is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define GRND_NONBLOCK 0x0001 +#define GRND_RANDOM 0x0002 +#define GRND_INSECURE 0x0004 + +#endif /* _ABIBITS_RANDOM_H */ diff --git a/user/include/mlibc/abis/linux/reboot.h b/user/include/mlibc/abis/linux/reboot.h new file mode 100644 index 0000000..23a467c --- /dev/null +++ b/user/include/mlibc/abis/linux/reboot.h @@ -0,0 +1,18 @@ +#ifndef _ABIBITS_REBOOT_H +#define _ABIBITS_REBOOT_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + +#endif /* _ABIBITS_REBOOT_H */ diff --git a/user/include/mlibc/abis/linux/resource.h b/user/include/mlibc/abis/linux/resource.h new file mode 100644 index 0000000..57d2de4 --- /dev/null +++ b/user/include/mlibc/abis/linux/resource.h @@ -0,0 +1,54 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN -1 + +#define RLIMIT_CPU 0 +#define RLIMIT_FSIZE 1 +#define RLIMIT_DATA 2 +#define RLIMIT_STACK 3 +#define RLIMIT_CORE 4 +#define RLIMIT_RSS 5 +#define RLIMIT_NPROC 6 +#define RLIMIT_NOFILE 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_AS 9 +#define RLIMIT_LOCKS 10 +#define RLIMIT_SIGPENDING 11 +#define RLIMIT_MSGQUEUE 12 +#define RLIMIT_NICE 13 +#define RLIMIT_RTPRIO 14 +#define RLIMIT_RTTIME 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RESOURCE_H */ diff --git a/user/include/mlibc/abis/linux/riscv-hwprobe.h b/user/include/mlibc/abis/linux/riscv-hwprobe.h new file mode 100644 index 0000000..14b19c0 --- /dev/null +++ b/user/include/mlibc/abis/linux/riscv-hwprobe.h @@ -0,0 +1,107 @@ +#ifndef _ABIBITS_RISCV_HWPROBE_H +#define _ABIBITS_RISCV_HWPROBE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct riscv_hwprobe { + signed long long int key; + unsigned long long int value; +}; + +#define RISCV_HWPROBE_KEY_MVENDORID 0 +#define RISCV_HWPROBE_KEY_MARCHID 1 +#define RISCV_HWPROBE_KEY_MIMPID 2 +#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3 +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0) +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 +#define RISCV_HWPROBE_IMA_FD (1 << 0) +#define RISCV_HWPROBE_IMA_C (1 << 1) +#define RISCV_HWPROBE_IMA_V (1 << 2) +#define RISCV_HWPROBE_EXT_ZBA (1 << 3) +#define RISCV_HWPROBE_EXT_ZBB (1 << 4) +#define RISCV_HWPROBE_EXT_ZBS (1 << 5) +#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) +#define RISCV_HWPROBE_EXT_ZBC (1 << 7) +#define RISCV_HWPROBE_EXT_ZBKB (1 << 8) +#define RISCV_HWPROBE_EXT_ZBKC (1 << 9) +#define RISCV_HWPROBE_EXT_ZBKX (1 << 10) +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#define RISCV_HWPROBE_EXT_ZKNH (1 << 13) +#define RISCV_HWPROBE_EXT_ZKSED (1 << 14) +#define RISCV_HWPROBE_EXT_ZKSH (1 << 15) +#define RISCV_HWPROBE_EXT_ZKT (1 << 16) +#define RISCV_HWPROBE_EXT_ZVBB (1 << 17) +#define RISCV_HWPROBE_EXT_ZVBC (1 << 18) +#define RISCV_HWPROBE_EXT_ZVKB (1 << 19) +#define RISCV_HWPROBE_EXT_ZVKG (1 << 20) +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22) +#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23) +#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24) +#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25) +#define RISCV_HWPROBE_EXT_ZVKT (1 << 26) +#define RISCV_HWPROBE_EXT_ZFH (1 << 27) +#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) +#define RISCV_HWPROBE_EXT_ZVFH (1 << 30) +#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31) +#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) +#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) +#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) +#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) +#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36) +#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37) +#define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38) +#define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39) +#define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40) +#define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41) +#define RISCV_HWPROBE_EXT_ZIMOP (1ULL << 42) +#define RISCV_HWPROBE_EXT_ZCA (1ULL << 43) +#define RISCV_HWPROBE_EXT_ZCB (1ULL << 44) +#define RISCV_HWPROBE_EXT_ZCD (1ULL << 45) +#define RISCV_HWPROBE_EXT_ZCF (1ULL << 46) +#define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47) +#define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48) +#define RISCV_HWPROBE_EXT_SUPM (1ULL << 49) +#define RISCV_HWPROBE_EXT_ZICNTR (1ULL << 50) +#define RISCV_HWPROBE_EXT_ZIHPM (1ULL << 51) +#define RISCV_HWPROBE_EXT_ZFBFMIN (1ULL << 52) +#define RISCV_HWPROBE_EXT_ZVFBFMIN (1ULL << 53) +#define RISCV_HWPROBE_EXT_ZVFBFWMA (1ULL << 54) +#define RISCV_HWPROBE_EXT_ZICBOM (1ULL << 55) +#define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) +#define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) +#define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58) +#define RISCV_HWPROBE_KEY_CPUPERF_0 5 +#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) +#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) +#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0) +#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) +#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) +#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7 +#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8 +#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0 11 +#define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE 12 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0 13 + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RISCV_HWPROBE_H */ diff --git a/user/include/mlibc/abis/linux/rlim_t.h b/user/include/mlibc/abis/linux/rlim_t.h new file mode 100644 index 0000000..1f2871c --- /dev/null +++ b/user/include/mlibc/abis/linux/rlim_t.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +#if __INTPTR_WIDTH__ == 32 +typedef unsigned long long int rlim_t; +#else +typedef unsigned long int rlim_t; +#endif + +#endif /* _ABIBITS_RLIM_T_H */ diff --git a/user/include/mlibc/abis/linux/seek-whence.h b/user/include/mlibc/abis/linux/seek-whence.h new file mode 100644 index 0000000..7add0a1 --- /dev/null +++ b/user/include/mlibc/abis/linux/seek-whence.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_DATA 3 +#define SEEK_HOLE 4 + +#endif /* _ABIBITS_SEEK_WHENCE_H */ diff --git a/user/include/mlibc/abis/linux/shm.h b/user/include/mlibc/abis/linux/shm.h new file mode 100644 index 0000000..ad137bc --- /dev/null +++ b/user/include/mlibc/abis/linux/shm.h @@ -0,0 +1,107 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +#if defined(__i386__) || defined(__m68k__) +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + unsigned long __shm_atime_lo; + unsigned long __shm_atime_hi; + unsigned long __shm_dtime_lo; + unsigned long __shm_dtime_hi; + unsigned long __shm_ctime_lo; + unsigned long __shm_ctime_hi; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __unused[3]; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; +}; +#elif defined(__x86_64__) || defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __unused[2]; +}; +#else +#error "Missing architecture specific code." +#endif + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/user/include/mlibc/abis/linux/sigevent.h b/user/include/mlibc/abis/linux/sigevent.h new file mode 100644 index 0000000..41e1d81 --- /dev/null +++ b/user/include/mlibc/abis/linux/sigevent.h @@ -0,0 +1,24 @@ +#ifndef _ABIBITS_SIGEVENT_H +#define _ABIBITS_SIGEVENT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sigevent { + union sigval sigev_value; + int sigev_notify; + int sigev_signo; + void (*sigev_notify_function)(union sigval); + struct __mlibc_threadattr *sigev_notify_attributes; + pid_t sigev_notify_thread_id; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGEVENT_H */ diff --git a/user/include/mlibc/abis/linux/signal.h b/user/include/mlibc/abis/linux/signal.h new file mode 100644 index 0000000..d04b46e --- /dev/null +++ b/user/include/mlibc/abis/linux/signal.h @@ -0,0 +1,647 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#include +#include +#include +#include +#include +#include + +#define POLL_IN 1 +#define POLL_OUT 2 +#define POLL_MSG 3 +#define POLL_ERR 4 +#define POLL_PRI 5 +#define POLL_HUP 6 + +/* struct taken from musl. */ + +typedef struct { + int si_signo, si_errno, si_code; + union { + char __pad[128 - 2*sizeof(int) - sizeof(long)]; + struct { + union { + struct { + pid_t si_pid; + uid_t si_uid; + } __piduid; + struct { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union { + union sigval si_value; + struct { + int si_status; + clock_t si_utime, si_stime; + } __sigchld; + } __second; + } __si_common; + struct { + void *si_addr; + short si_addr_lsb; + union { + struct { + void *si_lower; + void *si_upper; + } __addr_bnd; + unsigned si_pkey; + } __first; + } __sigfault; + struct { + long si_band; + int si_fd; + } __sigpoll; + struct { + void *si_call_addr; + int si_syscall; + unsigned si_arch; + } __sigsys; + } __si_fields; +} siginfo_t; +#define si_pid __si_fields.__si_common.__first.__piduid.si_pid +#define si_uid __si_fields.__si_common.__first.__piduid.si_uid +#define si_status __si_fields.__si_common.__second.__sigchld.si_status +#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime +#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime +#define si_value __si_fields.__si_common.__second.si_value +#define si_addr __si_fields.__sigfault.si_addr +#define si_addr_lsb __si_fields.__sigfault.si_addr_lsb +#define si_lower __si_fields.__sigfault.__first.__addr_bnd.si_lower +#define si_upper __si_fields.__sigfault.__first.__addr_bnd.si_upper +#define si_pkey __si_fields.__sigfault.__first.si_pkey +#define si_band __si_fields.__sigpoll.si_band +#define si_fd __si_fields.__sigpoll.si_fd +#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid +#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun +#define si_ptr si_value.sival_ptr +#define si_int si_value.sival_int +#define si_call_addr __si_fields.__sigsys.si_call_addr +#define si_syscall __si_fields.__sigsys.si_syscall +#define si_arch __si_fields.__sigsys.si_arch + +/* Required for sys_sigaction sysdep. */ +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +/* SA_NOMASK is an alias for SA_NODEFER */ +/* SA_ONESHOT is an alias for SA_RESETHAND */ +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +#ifdef __cplusplus +extern "C" { +#endif + +/* Argument for signal() */ +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(0)) +#define SIG_IGN ((__sighandler)(void *)(1)) + +#define SIGABRT 6 +#define SIGFPE 8 +#define SIGILL 4 +#define SIGINT 2 +#define SIGSEGV 11 +#define SIGTERM 15 +#define SIGPROF 27 +#define SIGIO 29 +#define SIGPWR 30 +#define SIGRTMIN 35 +#define SIGRTMAX 64 + +typedef struct { + unsigned long sig[1024 / (8 * sizeof(long))]; +} sigset_t; + +/* constants for sigprocmask() */ +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +#define SIGHUP 1 +#define SIGQUIT 3 +#define SIGTRAP 5 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGWINCH 28 +#define SIGPOLL 29 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS +#define SIGCANCEL 32 +#define SIGTIMER 33 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +/* constants for sigev_notify of struct sigevent */ +#define SIGEV_SIGNAL 0 +#define SIGEV_NONE 1 +#define SIGEV_THREAD 2 +#define SIGEV_THREAD_ID 4 + +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 +#define BUS_MCEERR_AR 4 +#define BUS_MCEERR_AO 5 + +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +#define NSIG 65 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +#if defined(__i386__) +#define REG_GS 0 +#define REG_FS 1 +#define REG_ES 2 +#define REG_DS 3 +#define REG_EDI 4 +#define REG_ESI 5 +#define REG_EBP 6 +#define REG_ESP 7 +#define REG_EBX 8 +#define REG_EDX 9 +#define REG_ECX 10 +#define REG_EAX 11 +#define REG_TRAPNO 12 +#define REG_ERR 13 +#define REG_EIP 14 +#define REG_CS 15 +#define REG_EFL 16 +#define REG_UESP 17 +#define REG_SS 18 +#define NGREG 19 +#elif defined(__x86_64__) +#define REG_R8 0 +#define REG_R9 1 +#define REG_R10 2 +#define REG_R11 3 +#define REG_R12 4 +#define REG_R13 5 +#define REG_R14 6 +#define REG_R15 7 +#define REG_RDI 8 +#define REG_RSI 9 +#define REG_RBP 10 +#define REG_RBX 11 +#define REG_RDX 12 +#define REG_RAX 13 +#define REG_RCX 14 +#define REG_RSP 15 +#define REG_RIP 16 +#define REG_EFL 17 +#define REG_CSGSFS 18 +#define REG_ERR 19 +#define REG_TRAPNO 20 +#define REG_OLDMASK 21 +#define REG_CR2 22 +#define NGREG 23 +#endif + +#include + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + } __sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; +}; + +#define sa_handler __sa_handler.sa_handler +#define sa_sigaction __sa_handler.sa_sigaction + +/* Taken from the linux kernel headers */ + +#if defined(__x86_64__) || defined(__i386__) + +struct _fpreg { + unsigned short significand[4]; + unsigned short exponent; +}; + +struct _fpxreg { + unsigned short significand[4]; + unsigned short exponent; + unsigned short padding[3]; +}; + +struct _xmmreg { + uint32_t element[4]; +}; + +struct _fpstate { +#if defined(__x86_64__) + uint16_t cwd; + uint16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t rdp; + uint32_t mxcsr; + uint32_t mxcr_mask; + struct _fpxreg _st[8]; + struct _xmmreg _xmm[16]; + uint32_t padding[24]; +#elif defined(__i386__) + uint32_t cw; + uint32_t sw; + uint32_t tag; + uint32_t ipoff; + uint32_t cssel; + uint32_t dataoff; + uint32_t datasel; + struct _fpreg _st[8]; + uint16_t status; + uint16_t magic; + + /* FXSR FPU */ + + uint32_t _fxsr_env[6]; + uint32_t mxscr; + uint32_t reserved; + struct _fpxreg _fxsr_st[8]; + struct _xmmreg _xmm[8]; + + uint32_t padding2[56]; +#endif +}; + +struct sigcontext { +#if defined(__x86_64__) + unsigned long r8, r9, r10, r11, r12, r13, r14, r15; + unsigned long rdi, rsi, rbp, rbx, rdx, rax, rcx, rsp, rip, eflags; + unsigned short cs, gs, fs, __pad0; + unsigned long err, trapno, oldmask, cr2; + struct _fpstate *fpstate; + unsigned long __reserved1[8]; +#elif defined(__i386__) + unsigned short gs, __gsh, fs, __fsh, es, __esh, ds, __dsh; + unsigned long edi, esi, ebp, esp, ebx, edx, ecx, eax; + unsigned long trapno, err, eip; + unsigned short cs, __csh; + unsigned long eflags, esp_at_signal; + unsigned short ss, __ssh; + struct _fpstate *fpstate; + unsigned long oldmask, cr2; +#endif +}; + +typedef struct { + unsigned long gregs[NGREG]; + struct _fpstate *fpregs; + unsigned long __reserved1[8]; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#elif defined(__riscv) && __riscv_xlen == 64 +/* Definitions from Linux kernel headers. */ + +#define NGREG 32 + +enum { + REG_PC = 0, +#define REG_PC REG_PC + REG_RA = 1, +#define REG_RA REG_RA + REG_SP = 2, +#define REG_SP REG_SP + REG_TP = 4, +#define REG_TP REG_TP + REG_S0 = 8, +#define REG_S0 REG_S0 + REG_A0 = 10 +#define REG_A0 REG_A0 +}; + +struct __riscv_f_ext_state { + uint32_t f[32]; + uint32_t fcsr; +}; + +struct __riscv_d_ext_state { + uint64_t f[32]; + uint32_t fcsr; +}; + +struct __riscv_q_ext_state { + uint64_t f[64] __attribute__((__aligned__(16))); + uint32_t fcsr; + uint32_t reserved[3]; +}; + +union __riscv_fp_state { + struct __riscv_f_ext_state f; + struct __riscv_d_ext_state d; + struct __riscv_q_ext_state q; +}; + +typedef unsigned long __riscv_mc_gp_state[NGREG]; + +typedef struct sigcontext { + __riscv_mc_gp_state gregs; + union __riscv_fp_state fpregs; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + uint8_t __unused[1024 / 8 - sizeof(sigset_t)]; +#pragma GCC diagnostic pop + mcontext_t uc_mcontext; +} ucontext_t; + +#elif defined (__aarch64__) + +#define NGREG 34 + +typedef struct sigcontext { + uint64_t fault_address; + uint64_t regs[31]; + uint64_t sp; + uint64_t pc; + uint64_t pstate; + uint8_t __reserved[4096]; +} mcontext_t; + +#define FPSIMD_MAGIC 0x46508001 +#define ESR_MAGIC 0x45535201 +#define EXTRA_MAGIC 0x45585401 +#define SVE_MAGIC 0x53564501 +struct _aarch64_ctx { + uint32_t magic; + uint32_t size; +}; +struct fpsimd_context { + struct _aarch64_ctx head; + uint32_t fpsr; + uint32_t fpcr; + __uint128_t vregs[32]; +}; +struct esr_context { + struct _aarch64_ctx head; + uint64_t esr; +}; +struct extra_context { + struct _aarch64_ctx head; + uint64_t datap; + uint32_t size; + uint32_t __reserved[3]; +}; +struct sve_context { + struct _aarch64_ctx head; + uint16_t vl; + uint16_t __reserved[3]; +}; +#define SVE_VQ_BYTES 16 +#define SVE_VQ_MIN 1 +#define SVE_VQ_MAX 512 +#define SVE_VL_MIN (SVE_VQ_MIN * SVE_VQ_BYTES) +#define SVE_VL_MAX (SVE_VQ_MAX * SVE_VQ_BYTES) +#define SVE_NUM_ZREGS 32 +#define SVE_NUM_PREGS 16 +#define sve_vl_valid(vl) \ + ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX) +#define sve_vq_from_vl(vl) ((vl) / SVE_VQ_BYTES) +#define sve_vl_from_vq(vq) ((vq) * SVE_VQ_BYTES) +#define SVE_SIG_ZREG_SIZE(vq) ((unsigned)(vq) * SVE_VQ_BYTES) +#define SVE_SIG_PREG_SIZE(vq) ((unsigned)(vq) * (SVE_VQ_BYTES / 8)) +#define SVE_SIG_FFR_SIZE(vq) SVE_SIG_PREG_SIZE(vq) +#define SVE_SIG_REGS_OFFSET \ + ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1)) \ + / SVE_VQ_BYTES * SVE_VQ_BYTES) +#define SVE_SIG_ZREGS_OFFSET SVE_SIG_REGS_OFFSET +#define SVE_SIG_ZREG_OFFSET(vq, n) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n)) +#define SVE_SIG_ZREGS_SIZE(vq) \ + (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET) +#define SVE_SIG_PREGS_OFFSET(vq) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq)) +#define SVE_SIG_PREG_OFFSET(vq, n) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n)) +#define SVE_SIG_PREGS_SIZE(vq) \ + (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq)) +#define SVE_SIG_FFR_OFFSET(vq) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq)) +#define SVE_SIG_REGS_SIZE(vq) \ + (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET) +#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq)) + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + mcontext_t uc_mcontext; +} ucontext_t; + +#elif defined (__m68k__) + +/* taken from musl */ + +#if defined(_GNU_SOURCE) || defined(__MLIBC_BUILDING_MLIBC) +enum { R_D0 = 0 }; +#define R_D0 R_D0 +enum { R_D1 = 1 }; +#define R_D1 R_D1 +enum { R_D2 = 2 }; +#define R_D2 R_D2 +enum { R_D3 = 3 }; +#define R_D3 R_D3 +enum { R_D4 = 4 }; +#define R_D4 R_D4 +enum { R_D5 = 5 }; +#define R_D5 R_D5 +enum { R_D6 = 6 }; +#define R_D6 R_D6 +enum { R_D7 = 7 }; +#define R_D7 R_D7 +enum { R_A0 = 8 }; +#define R_A0 R_A0 +enum { R_A1 = 9 }; +#define R_A1 R_A1 +enum { R_A2 = 10 }; +#define R_A2 R_A2 +enum { R_A3 = 11 }; +#define R_A3 R_A3 +enum { R_A4 = 12 }; +#define R_A4 R_A4 +enum { R_A5 = 13 }; +#define R_A5 R_A5 +enum { R_A6 = 14 }; +#define R_A6 R_A6 +enum { R_A7 = 15 }; +#define R_A7 R_A7 +enum { R_SP = 15 }; +#define R_SP R_SP +enum { R_PC = 16 }; +#define R_PC R_PC +enum { R_PS = 17 }; +#define R_PS R_PS +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(__MLIBC_BUILDING_MLIBC) + +struct sigcontext { + unsigned long sc_mask, sc_usp, sc_d0, sc_d1, sc_a0, sc_a1; + unsigned short sc_sr; + unsigned long sc_pc; + unsigned short sc_formatvec; + unsigned long sc_fpregs[6], sc_fpcntl[3]; + unsigned char sc_fpstate[216]; +}; + +typedef int greg_t, gregset_t[18]; +typedef struct { + int f_pcr, f_psr, f_fpiaddr, f_fpregs[8][3]; +} fpregset_t; + +typedef struct { + int version; + gregset_t gregs; + fpregset_t fpregs; +} mcontext_t; +#else +typedef struct { + int __version; + int __gregs[18]; + int __fpregs[27]; +} mcontext_t; +#endif + +struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + long __reserved[80]; + sigset_t uc_sigmask; +} ucontext_t; + +#elif defined(__loongarch64) +/* Taken from musl. */ + +#define NGREG 32 +#define REG_RA 1 +#define REG_SP 3 +#define REG_S0 23 +#define REG_S1 24 +#define REG_A0 4 +#define REG_S2 25 +#define REG_NARGS 8 + +typedef unsigned long greg_t, gregset_t[32]; + +struct sigcontext { + unsigned long sc_pc; + unsigned long sc_regs[32]; + unsigned sc_flags; + unsigned long sc_extcontext[1] __attribute__((__aligned__(16))); +}; + +typedef struct { + unsigned long pc; + unsigned long gregs[32]; + unsigned flags; + unsigned long extcontext[1] __attribute__((__aligned__(16))); +} mcontext_t; + +struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + long __uc_pad; + mcontext_t uc_mcontext; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGNAL_H */ diff --git a/user/include/mlibc/abis/linux/sigval.h b/user/include/mlibc/abis/linux/sigval.h new file mode 100644 index 0000000..123ba77 --- /dev/null +++ b/user/include/mlibc/abis/linux/sigval.h @@ -0,0 +1,17 @@ +#ifndef _ABIBITS_SIGVAL_H +#define _ABIBITS_SIGVAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +union sigval { + int sival_int; + void *sival_ptr; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGVAL_H */ diff --git a/user/include/mlibc/abis/linux/socket.h b/user/include/mlibc/abis/linux/socket.h new file mode 100644 index 0000000..ab8a60b --- /dev/null +++ b/user/include/mlibc/abis/linux/socket.h @@ -0,0 +1,329 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned short sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + size_t msg_iovlen; /* int in POSIX */ + void *msg_control; + size_t msg_controllen; /* socklen_t in POSIX */ + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t) - sizeof(long)]; + long __force_alignment; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + size_t cmsg_len; /* socklen_t in POSIX */ + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_CREDENTIALS 2 + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#ifndef SOCK_STREAM +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#endif + +#define SOCK_RAW 3 +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 +#define SOCK_DCCP 6 +#define SOCK_PACKET 10 + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 02000000 +#define SOCK_NONBLOCK 04000 +#endif + +#define PF_UNSPEC 0 +#define PF_LOCAL 1 +#define PF_UNIX PF_LOCAL +#define PF_FILE PF_LOCAL +#define PF_INET 2 +#define PF_AX25 3 +#define PF_IPX 4 +#define PF_APPLETALK 5 +#define PF_NETROM 6 +#define PF_BRIDGE 7 +#define PF_ATMPVC 8 +#define PF_X25 9 +#define PF_INET6 10 +#define PF_ROSE 11 +#define PF_DECnet 12 +#define PF_NETBEUI 13 +#define PF_SECURITY 14 +#define PF_KEY 15 +#define PF_NETLINK 16 +#define PF_ROUTE PF_NETLINK +#define PF_PACKET 17 +#define PF_ASH 18 +#define PF_ECONET 19 +#define PF_ATMSVC 20 +#define PF_RDS 21 +#define PF_SNA 22 +#define PF_IRDA 23 +#define PF_PPPOX 24 +#define PF_WANPIPE 25 +#define PF_LLC 26 +#define PF_IB 27 +#define PF_MPLS 28 +#define PF_CAN 29 +#define PF_TIPC 30 +#define PF_BLUETOOTH 31 +#define PF_IUCV 32 +#define PF_RXRPC 33 +#define PF_ISDN 34 +#define PF_PHONET 35 +#define PF_IEEE802154 36 +#define PF_CAIF 37 +#define PF_ALG 38 +#define PF_NFC 39 +#define PF_VSOCK 40 +#define PF_KCM 41 +#define PF_QIPCRTR 42 +#define PF_SMC 43 +#define PF_XDP 44 +#define PF_MAX 45 + +#define AF_UNSPEC PF_UNSPEC +#define AF_LOCAL PF_LOCAL +#define AF_UNIX AF_LOCAL +#define AF_FILE AF_LOCAL +#define AF_INET PF_INET +#define AF_AX25 PF_AX25 +#define AF_IPX PF_IPX +#define AF_APPLETALK PF_APPLETALK +#define AF_NETROM PF_NETROM +#define AF_BRIDGE PF_BRIDGE +#define AF_ATMPVC PF_ATMPVC +#define AF_X25 PF_X25 +#define AF_INET6 PF_INET6 +#define AF_ROSE PF_ROSE +#define AF_DECnet PF_DECnet +#define AF_NETBEUI PF_NETBEUI +#define AF_SECURITY PF_SECURITY +#define AF_KEY PF_KEY +#define AF_NETLINK PF_NETLINK +#define AF_ROUTE PF_ROUTE +#define AF_PACKET PF_PACKET +#define AF_ASH PF_ASH +#define AF_ECONET PF_ECONET +#define AF_ATMSVC PF_ATMSVC +#define AF_RDS PF_RDS +#define AF_SNA PF_SNA +#define AF_IRDA PF_IRDA +#define AF_PPPOX PF_PPPOX +#define AF_WANPIPE PF_WANPIPE +#define AF_LLC PF_LLC +#define AF_IB PF_IB +#define AF_MPLS PF_MPLS +#define AF_CAN PF_CAN +#define AF_TIPC PF_TIPC +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_IUCV PF_IUCV +#define AF_RXRPC PF_RXRPC +#define AF_ISDN PF_ISDN +#define AF_PHONET PF_PHONET +#define AF_IEEE802154 PF_IEEE802154 +#define AF_CAIF PF_CAIF +#define AF_ALG PF_ALG +#define AF_NFC PF_NFC +#define AF_VSOCK PF_VSOCK +#define AF_KCM PF_KCM +#define AF_QIPCRTR PF_QIPCRTR +#define AF_SMC PF_SMC +#define AF_XDP PF_XDP +#define AF_MAX PF_MAX + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +#define SO_REUSEPORT 15 +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_ACCEPTCONN 30 +#define SO_PEERSEC 31 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 + +#ifndef SO_RCVTIMEO +#if __LONG_MAX == 0x7fffffff +#define SO_RCVTIMEO 66 +#else +#define SO_RCVTIMEO 20 +#endif +#endif + +#ifndef SO_RCVTIMEO_OLD +#define SO_RCVTIMEO_OLD 20 +#endif + +#ifndef SO_SNDTIMEO +#if __LONG_MAX == 0x7fffffff +#define SO_SNDTIMEO 67 +#else +#define SO_SNDTIMEO 21 +#endif +#endif + +#ifndef SO_SNDTIMEO_OLD +#define SO_SNDTIMEO_OLD 21 +#endif + +#ifndef SO_TIMESTAMP +#if __LONG_MAX == 0x7fffffff +#define SO_TIMESTAMP 63 +#define SO_TIMESTAMPNS 64 +#define SO_TIMESTAMPING 65 +#else +#define SO_TIMESTAMP 29 +#define SO_TIMESTAMPNS 35 +#define SO_TIMESTAMPING 37 +#endif +#endif + +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 +#define SO_GET_FILTER SO_ATTACH_FILTER + +#define SO_PEERNAME 28 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SO_PASSSEC 34 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS +#define SO_MARK 36 +#define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 +#define SO_NOFCS 43 +#define SO_LOCK_FILTER 44 +#define SO_SELECT_ERR_QUEUE 45 +#define SO_BUSY_POLL 46 +#define SO_MAX_PACING_RATE 47 +#define SO_BPF_EXTENSIONS 48 +#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#define SO_ATTACH_REUSEPORT_CBPF 51 +#define SO_ATTACH_REUSEPORT_EBPF 52 +#define SO_CNX_ADVICE 53 +#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_MEMINFO 55 +#define SO_INCOMING_NAPI_ID 56 +#define SO_COOKIE 57 +#define SCM_TIMESTAMPING_PKTINFO 58 +#define SO_PEERGROUPS 59 +#define SO_ZEROCOPY 60 +#define SO_TXTIME 61 +#define SCM_TXTIME SO_TXTIME +#define SO_BINDTOIFINDEX 62 +#define SO_DETACH_REUSEPORT_BPF 68 + +#define SOL_SOCKET 1 + +#define SOL_IP 0 +#define SOL_IPV6 41 +#define SOL_ICMPV6 58 + +#define SOL_RAW 255 +#define SOL_DECNET 261 +#define SOL_X25 262 +#define SOL_PACKET 263 +#define SOL_ATM 264 +#define SOL_AAL 265 +#define SOL_IRDA 266 +#define SOL_NETBEUI 267 +#define SOL_LLC 268 +#define SOL_DCCP 269 +#define SOL_NETLINK 270 +#define SOL_TIPC 271 +#define SOL_RXRPC 272 +#define SOL_PPPOL2TP 273 +#define SOL_BLUETOOTH 274 +#define SOL_PNPIPE 275 +#define SOL_RDS 276 +#define SOL_IUCV 277 +#define SOL_CAIF 278 +#define SOL_ALG 279 +#define SOL_NFC 280 +#define SOL_KCM 281 +#define SOL_TLS 282 +#define SOL_XDP 283 + +#define SOMAXCONN 128 + +#define MSG_OOB 0x0001 +#define MSG_PEEK 0x0002 +#define MSG_DONTROUTE 0x0004 +#define MSG_CTRUNC 0x0008 +#define MSG_PROXY 0x0010 +#define MSG_TRUNC 0x0020 +#define MSG_DONTWAIT 0x0040 +#define MSG_EOR 0x0080 +#define MSG_WAITALL 0x0100 +#define MSG_FIN 0x0200 +#define MSG_SYN 0x0400 +#define MSG_CONFIRM 0x0800 +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 +#define MSG_NOSIGNAL 0x4000 +#define MSG_MORE 0x8000 +#define MSG_WAITFORONE 0x10000 +#define MSG_BATCH 0x40000 +#define MSG_ZEROCOPY 0x4000000 +#define MSG_FASTOPEN 0x20000000 +#define MSG_CMSG_CLOEXEC 0x40000000 + +#endif diff --git a/user/include/mlibc/abis/linux/socklen_t.h b/user/include/mlibc/abis/linux/socklen_t.h new file mode 100644 index 0000000..190e5f9 --- /dev/null +++ b/user/include/mlibc/abis/linux/socklen_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_SOCKLEN_T_H +#define _ABIBITS_SOCKLEN_T_H + +typedef unsigned socklen_t; + +#endif /* _ABIBITS_SOCKLEN_T_H */ diff --git a/user/include/mlibc/abis/linux/stat.h b/user/include/mlibc/abis/linux/stat.h new file mode 100644 index 0000000..57992c5 --- /dev/null +++ b/user/include/mlibc/abis/linux/stat.h @@ -0,0 +1,148 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__x86_64__) + +struct stat { + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; + unsigned int __pad0; + dev_t st_rdev; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + long __unused[3]; +}; + +#elif (defined(__riscv) && __riscv_xlen == 64) || defined (__aarch64__) || defined(__loongarch64) + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + dev_t __pad1; + off_t st_size; + blksize_t st_blksize; + int __pad2; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + int __pad3[2]; +}; + +#elif defined(__i386__) + +struct stat { + dev_t st_dev; + int __st_dev_padding; + long __st_ino_truncated; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + int __st_rdev_padding; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct { + long tv_sec; + long tv_nsec; + } __st_atim32, __st_mtim32, __st_ctim32; + ino_t st_ino; + + /* These fields are not in the ABI. Their values are */ + /* copied from __st_atim32, __st_mtim32, __st_ctim32 */ + /* accordingly. */ + + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; +}; +#elif defined (__m68k__) + +struct stat { + dev_t st_dev; + unsigned char __st_dev_padding[2]; + unsigned long __st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + unsigned char __st_rdev_padding; + long long st_size; /* TODO: off64_t? */ + blksize_t st_blksize; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + ino_t st_ino; +}; + +#endif + +#define stat64 stat + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_STAT_H */ diff --git a/user/include/mlibc/abis/linux/statfs.h b/user/include/mlibc/abis/linux/statfs.h new file mode 100644 index 0000000..c28372b --- /dev/null +++ b/user/include/mlibc/abis/linux/statfs.h @@ -0,0 +1,50 @@ +#ifndef _ABIBITS_STATFS_H +#define _ABIBITS_STATFS_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error "statfs() is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#include +#include + +typedef struct __mlibc_fsid { + int __val[2]; +} fsid_t; + +/* WARNING: keep `statfs` and `statfs64` in sync or bad things will happen! */ +struct statfs { + unsigned long f_type; + unsigned long f_bsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsid_t f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_flags; + unsigned long __f_spare[4]; +}; + +/* WARNING: keep `statfs` and `statfs64` in sync or bad things will happen! */ +struct statfs64 { + unsigned long f_type; + unsigned long f_bsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsid_t f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_flags; + unsigned long __f_spare[4]; +}; + +#endif /* _ABIBITS_STATFS_H */ + diff --git a/user/include/mlibc/abis/linux/statvfs.h b/user/include/mlibc/abis/linux/statvfs.h new file mode 100644 index 0000000..9e35770 --- /dev/null +++ b/user/include/mlibc/abis/linux/statvfs.h @@ -0,0 +1,52 @@ +#ifndef _ABIBITS_STATVFS_H +#define _ABIBITS_STATVFS_H + +#include +#include + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_NODEV 4 +#define ST_NOEXEC 8 +#define ST_SYNCHRONOUS 16 +#define ST_MANDLOCK 64 +#define ST_WRITE 128 +#define ST_APPEND 256 +#define ST_IMMUTABLE 512 +#define ST_NOATIME 1024 +#define ST_NODIRATIME 2048 + +/* On Linux, this struct is not directly used by the kernel. */ + +/* WARNING: keep `statvfs` and `statvfs64` in sync or bad things will happen! */ +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; + +/* WARNING: keep `statvfs` and `statvfs64` in sync or bad things will happen! */ +struct statvfs64 { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; + +#endif /* _ABIBITS_STATVFS_H */ + diff --git a/user/include/mlibc/abis/linux/statx.h b/user/include/mlibc/abis/linux/statx.h new file mode 100644 index 0000000..f979b4d --- /dev/null +++ b/user/include/mlibc/abis/linux/statx.h @@ -0,0 +1,77 @@ +#ifndef _ABIBITS_STATX_H +#define _ABIBITS_STATX_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error "statx() is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#include + +struct statx_timestamp { + __mlibc_int64 tv_sec; + __mlibc_uint32 tv_nsec; + __mlibc_uint32 __padding; +}; + +#define STATX_TYPE 0x1 +#define STATX_MODE 0x2 +#define STATX_NLINK 0x4 +#define STATX_UID 0x8 +#define STATX_GID 0x10 +#define STATX_ATIME 0x20 +#define STATX_MTIME 0x40 +#define STATX_CTIME 0x80 +#define STATX_INO 0x100 +#define STATX_SIZE 0x200 +#define STATX_BLOCKS 0x400 +#define STATX_BASIC_STATS 0x7ff +#define STATX_BTIME 0x800 +#define STATX_MNT_ID 0x1000 +#define STATX_DIOALIGN 0x2000 +#define STATX_ALL 0xfff + +#define STATX_ATTR_COMPRESSED 0x4 +#define STATX_ATTR_IMMUTABLE 0x10 +#define STATX_ATTR_APPEND 0x20 +#define STATX_ATTR_NODUMP 0x40 +#define STATX_ATTR_ENCRYPTED 0x800 +#define STATX_ATTR_AUTOMOUNT 0x1000 +#define STATX_ATTR_MOUNT_ROOT 0x2000 +#define STATX_ATTR_VERITY 0x100000 +#define STATX_ATTR_DAX 0x200000 + +struct statx { + __mlibc_uint32 stx_mask; + + __mlibc_uint32 stx_blksize; + __mlibc_uint64 stx_attributes; + __mlibc_uint32 stx_nlink; + __mlibc_uint32 stx_uid; + __mlibc_uint32 stx_gid; + __mlibc_uint16 stx_mode; + __mlibc_uint16 __padding; + __mlibc_uint64 stx_ino; + __mlibc_uint64 stx_size; + __mlibc_uint64 stx_blocks; + __mlibc_uint64 stx_attributes_mask; + + struct statx_timestamp stx_atime; + struct statx_timestamp stx_btime; + struct statx_timestamp stx_ctime; + struct statx_timestamp stx_mtime; + + __mlibc_uint32 stx_rdev_major; + __mlibc_uint32 stx_rdev_minor; + __mlibc_uint32 stx_dev_major; + __mlibc_uint32 stx_dev_minor; + + __mlibc_uint64 stx_mnt_id; + __mlibc_uint32 stx_dio_mem_align; + __mlibc_uint32 stx_dio_offset_align; + + __mlibc_uint64 __padding1[12]; +}; + +#endif diff --git a/user/include/mlibc/abis/linux/suseconds_t.h b/user/include/mlibc/abis/linux/suseconds_t.h new file mode 100644 index 0000000..1de1a7c --- /dev/null +++ b/user/include/mlibc/abis/linux/suseconds_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SUSECONDS_T_H +#define _ABIBITS_SUSECONDS_T_H + +#include + +typedef long suseconds_t; + +#endif /* _ABIBITS_SUSECONDS_T_H */ diff --git a/user/include/mlibc/abis/linux/termios.h b/user/include/mlibc/abis/linux/termios.h new file mode 100644 index 0000000..7cc387f --- /dev/null +++ b/user/include/mlibc/abis/linux/termios.h @@ -0,0 +1,155 @@ +#ifndef _ABIBITS_TERMIOS_H +#define _ABIBITS_TERMIOS_H + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +/* indices for the c_cc array in struct termios */ +#define NCCS 32 +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* bitwise flags for c_iflag in struct termios */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* bitwise flags for c_oflag in struct termios */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE) + +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 + +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 + +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 + +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 + +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +#endif + +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 + +/* bitwise constants for c_cflag in struct termios */ +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 + +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 + +/* bitwise constants for c_lflag in struct termios */ +#define ISIG 0000001 +#define ICANON 0000002 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define IEXTEN 0100000 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define EXTA 0000016 +#define EXTB 0000017 +#define CBAUD 0010017 +#define CBAUDEX 0010000 +#define CIBAUD 002003600000 +#define CMSPAR 010000000000 +#define CRTSCTS 020000000000 + +#define XCASE 0000004 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define EXTPROC 0200000 + +#define XTABS 0014000 + +#endif + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; + unsigned short c_oflag; + unsigned short c_cflag; + unsigned short c_lflag; + unsigned char c_line; + unsigned char c_cc[NCC]; +}; + +#endif diff --git a/user/include/mlibc/abis/linux/time.h b/user/include/mlibc/abis/linux/time.h new file mode 100644 index 0000000..dfc342e --- /dev/null +++ b/user/include/mlibc/abis/linux/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif /* _ABIBITS_TIME_H */ diff --git a/user/include/mlibc/abis/linux/uid_t.h b/user/include/mlibc/abis/linux/uid_t.h new file mode 100644 index 0000000..976540b --- /dev/null +++ b/user/include/mlibc/abis/linux/uid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif /* _ABIBITS_UID_T_H */ + diff --git a/user/include/mlibc/abis/linux/utmp-defines.h b/user/include/mlibc/abis/linux/utmp-defines.h new file mode 100644 index 0000000..cfc95e1 --- /dev/null +++ b/user/include/mlibc/abis/linux/utmp-defines.h @@ -0,0 +1,25 @@ +#ifndef _ABIBITS_UTMP_DEFINES_H +#define _ABIBITS_UTMP_DEFINES_H + +#include + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +#ifdef _GNU_SOURCE +#define ACCOUNTING 9 +#endif + +#if __MLIBC_LINUX_OPTION +#define UTMP_FILE "/var/run/utmp" +#define WTMP_FILE "/var/log/wtmp" +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABIBITS_UTMP_DEFINES_H */ diff --git a/user/include/mlibc/abis/linux/utmpx.h b/user/include/mlibc/abis/linux/utmpx.h new file mode 100644 index 0000000..4ad9db6 --- /dev/null +++ b/user/include/mlibc/abis/linux/utmpx.h @@ -0,0 +1,36 @@ +#ifndef _ABIBITS_UTMPX_H +#define _ABIBITS_UTMPX_H + +#include +#include + +#define __UT_HOSTSIZE 256 +#define __UT_NAMESIZE 32 +#define __UT_LINESIZE 32 + +/* Struct definition taken from musl */ +struct utmpx { + short ut_type; + short __ut_pad1; + pid_t ut_pid; + char ut_line[__UT_LINESIZE]; + char ut_id[4]; + char ut_user[__UT_NAMESIZE]; + char ut_host[__UT_HOSTSIZE]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + int ut_session, __ut_pad2; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +#define e_exit __e_exit +#define e_termination __e_termination + +#define UTMPX_FILE "/var/run/utmp" +#define WTMPX_FILE "/var/log/wtmp" + +#endif /* _ABIBITS_UTMPX_H */ diff --git a/user/include/mlibc/abis/linux/utsname.h b/user/include/mlibc/abis/linux/utsname.h new file mode 100644 index 0000000..d0f9a61 --- /dev/null +++ b/user/include/mlibc/abis/linux/utsname.h @@ -0,0 +1,13 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +#endif /* _ABIBITS_UTSNAME_T_H */ diff --git a/user/include/mlibc/abis/linux/vm-flags.h b/user/include/mlibc/abis/linux/vm-flags.h new file mode 100644 index 0000000..930289b --- /dev/null +++ b/user/include/mlibc/abis/linux/vm-flags.h @@ -0,0 +1,81 @@ +#ifndef _ABIBITS_VM_FLAGS_H +#define _ABIBITS_VM_FLAGS_H + +#include + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS 0x20 + +#if __MLIBC_LINUX_OPTION + +#define MAP_GROWSDOWN 0x100 +#define MAP_DENYWRITE 0x800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_NORESERVE 0x4000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_SYNC 0x80000 +#define MAP_FIXED_NOREPLACE 0x100000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#define MS_ASYNC 0x01 +#define MS_INVALIDATE 0x02 +#define MS_SYNC 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 0 +#define POSIX_MADV_RANDOM 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_WILLNEED 3 +#define POSIX_MADV_DONTNEED 4 + +#if __MLIBC_LINUX_OPTION + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_REMOVE 9 +#define MADV_DONTFORK 10 +#define MADV_DOFORK 11 +#define MADV_MERGEABLE 12 +#define MADV_UNMERGEABLE 13 +#define MADV_HUGEPAGE 14 +#define MADV_NOHUGEPAGE 15 +#define MADV_DONTDUMP 16 +#define MADV_DODUMP 17 +#define MADV_WIPEONFORK 18 +#define MADV_KEEPONFORK 19 +#define MADV_COLD 20 +#define MADV_PAGEOUT 21 +#define MADV_HWPOISON 100 +#define MADV_SOFT_OFFLINE 101 + +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U +#define MFD_HUGETLB 4U + +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABIBITS_VM_FLAGS_H */ diff --git a/user/include/mlibc/abis/linux/vt.h b/user/include/mlibc/abis/linux/vt.h new file mode 100644 index 0000000..7f434e7 --- /dev/null +++ b/user/include/mlibc/abis/linux/vt.h @@ -0,0 +1,82 @@ +#ifndef _ABIBITS_VT_H +#define _ABIBITS_VT_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define MIN_NR_CONSOLES 1 +#define MAX_NR_CONSOLES 63 + +#define VT_OPENQRY 0x5600 +#define VT_GETMODE 0x5601 +#define VT_SETMODE 0x5602 +#define VT_GETSTATE 0x5603 +#define VT_SENDSIG 0x5604 +#define VT_RELDISP 0x5605 +#define VT_ACTIVATE 0x5606 +#define VT_WAITACTIVE 0x5607 +#define VT_DISALLOCATE 0x5608 +#define VT_RESIZE 0x5609 +#define VT_RESIZEX 0x560A +#define VT_LOCKSWITCH 0x560B +#define VT_UNLOCKSWITCH 0x560C +#define VT_GETHIFONTMASK 0x560D +#define VT_WAITEVENT 0x560E +#define VT_SETACTIVATE 0x560F + +struct vt_mode { + char mode; + char waitv; + short relsig; + short acqsig; + short frsig; +}; + +#define VT_AUTO 0x00 +#define VT_PROCESS 0x01 +#define VT_ACKACQ 0x02 + +struct vt_stat { + unsigned short v_active; + unsigned short v_signal; + unsigned short v_state; +}; + +struct vt_sizes { + unsigned short v_rows; + unsigned short v_cols; + unsigned short v_scrollsize; +}; + +struct vt_consize { + unsigned short v_rows; + unsigned short v_cols; + unsigned short v_vlin; + unsigned short v_clin; + unsigned short v_vcol; + unsigned short v_ccol; +}; + +#define VT_EVENT_SWITCH 0x0001 +#define VT_EVENT_BLANK 0x0002 +#define VT_EVENT_UNBLANK 0x0004 +#define VT_EVENT_RESIZE 0x0008 +#define VT_MAX_EVENT 0x000F + +struct vt_event { + unsigned int event; + + unsigned int oldev; + unsigned int newev; + unsigned int pad[4]; +}; + +struct vt_setactivate { + unsigned int console; + struct vt_mode mode; +}; + +#endif /* _ABIBITS_VT_H */ diff --git a/user/include/mlibc/abis/linux/wait.h b/user/include/mlibc/abis/linux/wait.h new file mode 100644 index 0000000..1cb0dcc --- /dev/null +++ b/user/include/mlibc/abis/linux/wait.h @@ -0,0 +1,34 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#include + +#define WNOHANG 1 +#define WUNTRACED 2 +#define WSTOPPED 2 +#define WEXITED 4 +#define WCONTINUED 8 +#define WNOWAIT 0x01000000 + +#if __MLIBC_LINUX_OPTION + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) (((x) & 0xff00) >> 8) +#define WTERMSIG(x) ((x) & 0x7f) +#define WSTOPSIG(x) WEXITSTATUS(x) +#define WIFEXITED(x) (WTERMSIG(x) == 0) +#define WIFSIGNALED(x) (((signed char) (((x) & 0x7f) + 1) >> 1) > 0) +#define WIFSTOPPED(x) (((x) & 0xff) == 0x7f) +#define WIFCONTINUED(x) ((x) == 0xffff) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +/* glibc extension, but also useful for kernels */ +#define W_EXITCODE(ret, sig) (((ret) << 8) | (sig)) + +#endif /*_ABIBITS_WAIT_H */ diff --git a/user/include/mlibc/abis/linux/xattr.h b/user/include/mlibc/abis/linux/xattr.h new file mode 100644 index 0000000..588e398 --- /dev/null +++ b/user/include/mlibc/abis/linux/xattr.h @@ -0,0 +1,27 @@ +#ifndef MLIBC_ABIS_LINUX_XATTR_H +#define MLIBC_ABIS_LINUX_XATTR_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +/* __USE_KERNEL_XATTR_DEFS is exported when XATTR_* are emitted, and + * __UAPI_DEF_XATTR is used to determine the behaviour of the + * header (through ), if it's set + * to 1, the header exports xattr defines and __USE_KERNEL_XATTR_DEFS. + * This applies for pretty much all other defines in libc-compat.h + * AFAICT. + */ +#ifndef __USE_KERNEL_XATTR_DEFS +enum { + XATTR_CREATE = 1, +#define XATTR_CREATE XATTR_CREATE + XATTR_REPLACE = 2 +#define XATTR_REPLACE XATTR_REPLACE +}; +# define __UAPI_DEF_XATTR 0 +#endif + +#endif /* MLIBC_ABIS_LINUX_XATTR_H */ diff --git a/user/include/mlibc/abis/managarm/auxv.h b/user/include/mlibc/abis/managarm/auxv.h new file mode 100644 index 0000000..3326a4b --- /dev/null +++ b/user/include/mlibc/abis/managarm/auxv.h @@ -0,0 +1,17 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_HWCAP 16 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 + +/* managarm specific auxvector entries. */ + +#define AT_XPIPE 0x1000 +#define AT_OPENFILES 0x1001 +#define AT_FS_SERVER 0x1102 +#define AT_MBUS_SERVER 0x1103 + +#endif /* _ABIBITS_AUXV_H */ diff --git a/user/include/mlibc/abis/menix/fcntl.h b/user/include/mlibc/abis/menix/fcntl.h new file mode 100644 index 0000000..910f640 --- /dev/null +++ b/user/include/mlibc/abis/menix/fcntl.h @@ -0,0 +1,118 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +#include +#include + +#define O_RDONLY (1 << 0) +#define O_WRONLY (1 << 1) +#define O_CREAT (1 << 6) +#define O_EXCL (1 << 7) +#define O_NOCTTY (1 << 8) +#define O_TRUNC (1 << 9) +#define O_APPEND (1 << 10) +#define O_NONBLOCK (1 << 11) +#define O_DSYNC (1 << 12) +#define O_ASYNC (1 << 13) +#define O_DIRECT (1 << 14) +#define O_LARGEFILE (1 << 15) +#define O_DIRECTORY (1 << 16) +#define O_NOFOLLOW (1 << 17) +#define O_NOATIME (1 << 18) +#define O_CLOEXEC (1 << 19) +#define O_PATH (1 << 21) +#define O_TMPFILE (1 << 22) +#define O_SYNC (O_DIRECTORY | O_TMPFILE) +#define O_RSYNC O_SYNC + +#define O_EXEC O_PATH +#define O_SEARCH O_PATH + +#define O_RDWR (O_RDONLY | O_WRONLY) +#define O_ACCMODE (O_RDWR | O_PATH) + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLK64 F_SETLK +#define F_SETLKW 7 +#define F_SETLKW64 F_SETLKW + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 + +#define F_SETLEASE 1024 +#define F_GETLEASE 1025 +#define F_NOTIFY 1026 +#define F_DUPFD_CLOEXEC 1030 +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define F_SEAL_SEAL (1 << 0) +#define F_SEAL_SHRINK (1 << 1) +#define F_SEAL_GROW (1 << 2) +#define F_SEAL_WRITE (1 << 3) + +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define FD_CLOEXEC 1 + +#define AT_FDCWD (-100) + +#define AT_SYMLINK_NOFOLLOW (1 << 8) +#define AT_SYMLINK_FOLLOW (1 << 9) +#define AT_REMOVEDIR (1 << 10) +#define AT_EACCESS (1 << 11) +#define AT_NO_AUTOMOUNT (1 << 12) +#define AT_EMPTY_PATH (1 << 13) + +#define DN_ACCESS 1 +#define DN_MODIFY 2 +#define DN_CREATE 4 +#define DN_DELETE 8 +#define DN_RENAME 16 +#define DN_ATTRIB 32 +#define DN_MULTISHOT 0x80000000 + +#define AT_STATX_SYNC_AS_STAT 0x0000 +#define AT_STATX_FORCE_SYNC (1 << 14) +#define AT_STATX_DONT_SYNC (1 << 15) +#define AT_STATX_SYNC_TYPE (AT_STATX_FORCE_SYNC | AT_STATX_DONT_SYNC) + +#if defined(_GNU_SOURCE) +struct f_owner_ex { + int type; + pid_t pid; +}; +#endif /* _GNU_SOURCE */ + +#define F_OWNER_TID 0 + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 + +#endif diff --git a/user/include/mlibc/abis/menix/reboot.h b/user/include/mlibc/abis/menix/reboot.h new file mode 100644 index 0000000..56498b8 --- /dev/null +++ b/user/include/mlibc/abis/menix/reboot.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_REBOOT_H +#define _ABIBITS_REBOOT_H + +#define RB_AUTOBOOT 0xdeadb007 +#define RB_HALT_SYSTEM 0xdeaddead +#define RB_ENABLE_CAD 0xdeadcad1 +#define RB_DISABLE_CAD 0xdeadcad0 +#define RB_POWER_OFF 0xdead00ff +#define RB_SW_SUSPEND 0xdead2222 +#define RB_KEXEC 0xdeadecec + +#endif /* _ABIBITS_REBOOT_H */ diff --git a/user/include/mlibc/abis/menix/stat.h b/user/include/mlibc/abis/menix/stat.h new file mode 100644 index 0000000..81d395c --- /dev/null +++ b/user/include/mlibc/abis/menix/stat.h @@ -0,0 +1,71 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + blksize_t st_blksize; + blkcnt_t st_blocks; +}; + +#define stat64 stat + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_STAT_H */ diff --git a/user/include/mlibc/abis/vinix/reboot.h b/user/include/mlibc/abis/vinix/reboot.h new file mode 100644 index 0000000..01bccec --- /dev/null +++ b/user/include/mlibc/abis/vinix/reboot.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_REBOOT_H +#define _ABIBITS_REBOOT_H + +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + +#endif /* _ABIBITS_REBOOT_H */ diff --git a/user/include/mlibc/abis/vinix/sigevent.h b/user/include/mlibc/abis/vinix/sigevent.h new file mode 100644 index 0000000..d764178 --- /dev/null +++ b/user/include/mlibc/abis/vinix/sigevent.h @@ -0,0 +1,24 @@ +#ifndef _ABIBITS_SIGEVENT_H +#define _ABIBITS_SIGEVENT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sigevent { + int sigev_notify; + int sigev_signo; + union sigval sigev_value; + void (*sigev_notify_function)(union sigval); + /* MISSING: sigev_notify_attributes */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGEVENT_H */ + diff --git a/user/include/mlibc/abis/vinix/signal.h b/user/include/mlibc/abis/vinix/signal.h new file mode 100644 index 0000000..8626400 --- /dev/null +++ b/user/include/mlibc/abis/vinix/signal.h @@ -0,0 +1,179 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#include +#include +#include +#include + +typedef struct { + int si_signo; + int si_code; + int si_errno; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + int si_status; + union sigval si_value; +} siginfo_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Argument for signal() */ +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(-2)) +#define SIG_IGN ((__sighandler)(void *)(-3)) + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGRTMIN 32 +#define SIGRTMAX 33 +#define SIGCANCEL 34 + +/* siginfo->si_info constants */ +/* SIGBUS */ +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 + +/* SIGILL */ +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +/* SIGSEGV */ +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +/* TODO: replace this by uint64_t */ +typedef long sigset_t; + +#define SIGUNUSED SIGSYS + +/* constants for sigprocmask() */ +#define SIG_BLOCK 1 +#define SIG_UNBLOCK 2 +#define SIG_SETMASK 3 + +#define SA_NOCLDSTOP (1 << 0) +#define SA_ONSTACK (1 << 1) +#define SA_RESETHAND (1 << 2) +#define SA_RESTART (1 << 3) +#define SA_SIGINFO (1 << 4) +#define SA_NOCLDWAIT (1 << 5) +#define SA_NODEFER (1 << 6) + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + size_t ss_size; + int ss_flags; +} stack_t; + +/* constants for sigev_notify of struct sigevent */ +#define SIGEV_NONE 1 +#define SIGEV_SIGNAL 2 +#define SIGEV_THREAD 3 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +#define NSIG 65 + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + }; + sigset_t sa_mask; + int sa_flags; +}; + +#if defined(__x86_64__) || defined(__aarch64__) +/* TODO: This is wrong for AArch64. */ + +typedef struct { + unsigned long oldmask; + unsigned long gregs[16]; + unsigned long pc, pr, sr; + unsigned long gbr, mach, macl; + unsigned long fpregs[16]; + unsigned long xfpregs[16]; + unsigned int fpscr, fpul, ownedfp; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGNAL_H */ diff --git a/user/include/mlibc/abis/vinix/statvfs.h b/user/include/mlibc/abis/vinix/statvfs.h new file mode 100644 index 0000000..370fcc1 --- /dev/null +++ b/user/include/mlibc/abis/vinix/statvfs.h @@ -0,0 +1,36 @@ +#ifndef _ABIBITS_STATVFS_H +#define _ABIBITS_STATVFS_H + +#include +#include + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_MANDLOCK 64 + +#define FSTYPSZ 16 + +/* On Linux, this struct is not directly used by the kernel. */ +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + + unsigned long f_fsid; + char f_basetype[FSTYPSZ]; + + unsigned long f_flag; + unsigned long f_namemax; + char f_fstr[32]; + unsigned long f_filler[16]; +}; + +#endif /* _ABIBITS_STATVFS_H */ + + diff --git a/user/include/mlibc/abis/vinix/utmp-defines.h b/user/include/mlibc/abis/vinix/utmp-defines.h new file mode 100644 index 0000000..16d071f --- /dev/null +++ b/user/include/mlibc/abis/vinix/utmp-defines.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_UTMP_DEFINES_H +#define _ABIBITS_UTMP_DEFINES_H + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +#endif /* _ABIBITS_UTMP_DEFINES_H */ diff --git a/user/include/mlibc/abis/vinix/utmpx.h b/user/include/mlibc/abis/vinix/utmpx.h new file mode 100644 index 0000000..4ad9db6 --- /dev/null +++ b/user/include/mlibc/abis/vinix/utmpx.h @@ -0,0 +1,36 @@ +#ifndef _ABIBITS_UTMPX_H +#define _ABIBITS_UTMPX_H + +#include +#include + +#define __UT_HOSTSIZE 256 +#define __UT_NAMESIZE 32 +#define __UT_LINESIZE 32 + +/* Struct definition taken from musl */ +struct utmpx { + short ut_type; + short __ut_pad1; + pid_t ut_pid; + char ut_line[__UT_LINESIZE]; + char ut_id[4]; + char ut_user[__UT_NAMESIZE]; + char ut_host[__UT_HOSTSIZE]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + int ut_session, __ut_pad2; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +#define e_exit __e_exit +#define e_termination __e_termination + +#define UTMPX_FILE "/var/run/utmp" +#define WTMPX_FILE "/var/log/wtmp" + +#endif /* _ABIBITS_UTMPX_H */ diff --git a/user/include/mlibc/ci/abidiff_suppress.ini b/user/include/mlibc/ci/abidiff_suppress.ini new file mode 100644 index 0000000..0f68976 --- /dev/null +++ b/user/include/mlibc/ci/abidiff_suppress.ini @@ -0,0 +1,2 @@ +[suppress_function] +name_regexp = ^(mlibc|frg|std)::.* diff --git a/user/include/mlibc/ci/aero.cross-file b/user/include/mlibc/ci/aero.cross-file new file mode 100644 index 0000000..4ce4a9c --- /dev/null +++ b/user/include/mlibc/ci/aero.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'aero' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/astral.cross-file b/user/include/mlibc/ci/astral.cross-file new file mode 100644 index 0000000..cf968b4 --- /dev/null +++ b/user/include/mlibc/ci/astral.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'astral' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/bootstrap.yml b/user/include/mlibc/ci/bootstrap.yml new file mode 100644 index 0000000..f8dcae3 --- /dev/null +++ b/user/include/mlibc/ci/bootstrap.yml @@ -0,0 +1,228 @@ +declare_options: + - name: arch + default: x86_64 + - name: compiler + default: gcc + +sources: + - name: mlibc + git: 'https://github.com/managarm/mlibc.git' + branch: 'master' + + - name: linux + url: 'https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.14.tar.xz' + extract_path: 'linux-6.14' + format: 'tar.xz' + version: '6.14' + + - name: libdrm + subdir: 'ports' + git: 'https://gitlab.freedesktop.org/mesa/drm.git' + tag: 'libdrm-2.4.124' + version: '2.4.124' + +tools: [] + +packages: + - name: mlibc + architecture: '@OPTION:arch@' + from_source: mlibc + pkgs_required: + - linux-headers + - libdrm-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized', '-Wno-unknown-warning-option']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized', '-Wno-unknown-warning-option']" + - "-Dlibgcc_dependency=false" + - "-Duse_freestnd_hdrs=enabled" + - "-Dbuild_tests=true" + - "-Db_sanitize=undefined" + - "-Ddefault_library=both" + - "-Dwerror=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@-@OPTION:compiler@.cross-file" + - '@THIS_SOURCE_DIR@' + environ: + CFLAGS: '-Wno-error=maybe-uninitialized' + CXXFLAGS: '-Wno-error=maybe-uninitialized' + LDFLAGS: '-Wl,/tmp/libgcc-@OPTION:arch@.a' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: mlibc-static + architecture: '@OPTION:arch@' + from_source: mlibc + pkgs_required: + - linux-headers + - libdrm-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Dlibgcc_dependency=false" + - "-Duse_freestnd_hdrs=enabled" + - "-Dbuild_tests=true" + - "-Db_sanitize=undefined" + - "-Ddefault_library=static" + - "-Dwerror=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@-@OPTION:compiler@.cross-file" + - '@THIS_SOURCE_DIR@' + environ: + LDFLAGS: '-Wl,/tmp/libgcc-@OPTION:arch@.a' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: mlibc-shared + from_source: mlibc + pkgs_required: + - linux-headers + - libdrm-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Dlibgcc_dependency=false" + - "-Duse_freestnd_hdrs=enabled" + - "-Dbuild_tests=true" + - "-Db_sanitize=undefined" + - "-Ddefault_library=shared" + - "-Dwerror=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@-@OPTION:compiler@.cross-file" + - '@THIS_SOURCE_DIR@' + environ: + LDFLAGS: '-Wl,/tmp/libgcc-@OPTION:arch@.a' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: mlibc-ansi-only + architecture: '@OPTION:arch@' + from_source: mlibc + pkgs_required: + - linux-headers + - libdrm-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Dlibgcc_dependency=false" + - "-Duse_freestnd_hdrs=enabled" + - "-Dbuild_tests=true" + - "-Db_sanitize=undefined" + - "-Ddefault_library=both" + - "-Dwerror=true" + - "-Dposix_option=disabled" + - "-Dlinux_option=disabled" + - "-Dglibc_option=disabled" + - "-Dbsd_option=disabled" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@-@OPTION:compiler@.cross-file" + - '@THIS_SOURCE_DIR@' + environ: + LDFLAGS: '-Wl,/tmp/libgcc-@OPTION:arch@.a' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: mlibc-headers-only + architecture: '@OPTION:arch@' + from_source: mlibc + pkgs_required: + - linux-headers + - libdrm-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Dlibgcc_dependency=false" + - "-Duse_freestnd_hdrs=enabled" + - "-Db_sanitize=undefined" + - "-Dwerror=true" + - "-Dheaders_only=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@-@OPTION:compiler@.cross-file" + - '@THIS_SOURCE_DIR@' + environ: + LDFLAGS: '-Wl,/tmp/libgcc-@OPTION:arch@.a' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: linux-headers + architecture: '@OPTION:arch@' + from_source: linux + configure: + # custom build system requires in tree-ish builds + - args: ['cp', '-Tr', '@THIS_SOURCE_DIR@/', '.'] + build: + - args: | + LINUX_ARCH="@OPTION:arch@" + case "$LINUX_ARCH" in + "aarch64") + LINUX_ARCH="arm64" + ;; + "riscv64") + LINUX_ARCH="riscv" + ;; + "loongarch64") + LINUX_ARCH="loongarch" + ;; + esac + make O=@THIS_COLLECT_DIR@ ARCH="$LINUX_ARCH" headers_install + + - name: libdrm-headers + architecture: '@OPTION:arch@' + from_source: 'libdrm' + build: + - args: ['mkdir', '-p', '@THIS_COLLECT_DIR@/usr/src/libdrm-headers'] + - args: | + cat << EOF > @THIS_COLLECT_DIR@/usr/src/libdrm-headers/meson.build + project('libdrm-headers') + libdrm_dep = declare_dependency(include_directories: include_directories('include')) + EOF + - args: ['cp', '-r', '@THIS_SOURCE_DIR@/include', '@THIS_COLLECT_DIR@/usr/src/libdrm-headers/include'] diff --git a/user/include/mlibc/ci/dripos.cross-file b/user/include/mlibc/ci/dripos.cross-file new file mode 100644 index 0000000..d0aa493 --- /dev/null +++ b/user/include/mlibc/ci/dripos.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'dripos' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/ironclad.cross-file b/user/include/mlibc/ci/ironclad.cross-file new file mode 100644 index 0000000..1a35948 --- /dev/null +++ b/user/include/mlibc/ci/ironclad.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'ironclad' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/keyronex.cross-file b/user/include/mlibc/ci/keyronex.cross-file new file mode 100644 index 0000000..685f9c2 --- /dev/null +++ b/user/include/mlibc/ci/keyronex.cross-file @@ -0,0 +1,9 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[host_machine] +system = 'keyronex' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/lemon.cross-file b/user/include/mlibc/ci/lemon.cross-file new file mode 100644 index 0000000..45821de --- /dev/null +++ b/user/include/mlibc/ci/lemon.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'lemon' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/linux-aarch64-gcc.cross-file b/user/include/mlibc/ci/linux-aarch64-gcc.cross-file new file mode 100644 index 0000000..269deac --- /dev/null +++ b/user/include/mlibc/ci/linux-aarch64-gcc.cross-file @@ -0,0 +1,13 @@ +[properties] +skip_sanity_check = true + +[binaries] +c = 'aarch64-linux-gnu-gcc' +cpp = 'aarch64-linux-gnu-g++' +exe_wrapper = 'qemu-aarch64' + +[host_machine] +system = 'linux' +cpu_family = 'aarch64' +cpu = 'unknown' +endian = 'little' diff --git a/user/include/mlibc/ci/linux-loongarch64-gcc.cross-file b/user/include/mlibc/ci/linux-loongarch64-gcc.cross-file new file mode 100644 index 0000000..4719d60 --- /dev/null +++ b/user/include/mlibc/ci/linux-loongarch64-gcc.cross-file @@ -0,0 +1,13 @@ +[binaries] +c = 'loongarch64-linux-gnu-gcc' +cpp = 'loongarch64-linux-gnu-g++' +exe_wrapper = 'qemu-loongarch64' + +[host_machine] +system = 'linux' +cpu_family = 'loongarch64' +cpu = 'loongarch64' +endian = 'little' + +[properties] +skip_sanity_check = true diff --git a/user/include/mlibc/ci/linux-m68k-gcc.cross-file b/user/include/mlibc/ci/linux-m68k-gcc.cross-file new file mode 100644 index 0000000..8f93e5f --- /dev/null +++ b/user/include/mlibc/ci/linux-m68k-gcc.cross-file @@ -0,0 +1,13 @@ +[binaries] +c = 'm68k-linux-gnu-gcc' +cpp = 'm68k-linux-gnu-g++' +exe_wrapper = 'qemu-m68k' + +[host_machine] +system = 'linux' +cpu_family = 'm68k' +cpu = 'm68k' +endian = 'big' + +[properties] +skip_sanity_check = true diff --git a/user/include/mlibc/ci/linux-riscv64-gcc.cross-file b/user/include/mlibc/ci/linux-riscv64-gcc.cross-file new file mode 100644 index 0000000..b5b8f53 --- /dev/null +++ b/user/include/mlibc/ci/linux-riscv64-gcc.cross-file @@ -0,0 +1,13 @@ +[properties] +skip_sanity_check = true + +[binaries] +c = 'riscv64-linux-gnu-gcc' +cpp = 'riscv64-linux-gnu-g++' +exe_wrapper = 'qemu-riscv64' + +[host_machine] +system = 'linux' +cpu_family = 'riscv64' +cpu = 'unknown' +endian = 'little' diff --git a/user/include/mlibc/ci/linux-x86-gcc.cross-file b/user/include/mlibc/ci/linux-x86-gcc.cross-file new file mode 100644 index 0000000..efa5023 --- /dev/null +++ b/user/include/mlibc/ci/linux-x86-gcc.cross-file @@ -0,0 +1,13 @@ +[binaries] +c = 'i686-linux-gnu-gcc' +cpp = 'i686-linux-gnu-g++' +exe_wrapper = 'qemu-i386' + +[host_machine] +system = 'linux' +cpu_family = 'x86' +cpu = 'i386' +endian = 'little' + +[properties] +skip_sanity_check = true diff --git a/user/include/mlibc/ci/linux-x86_64-clang.cross-file b/user/include/mlibc/ci/linux-x86_64-clang.cross-file new file mode 100644 index 0000000..36492af --- /dev/null +++ b/user/include/mlibc/ci/linux-x86_64-clang.cross-file @@ -0,0 +1,11 @@ +[binaries] +c = 'clang' +c_ld = 'lld' +cpp = 'clang++' +cpp_ld = 'lld' + +[host_machine] +system = 'linux' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/linux-x86_64-gcc.cross-file b/user/include/mlibc/ci/linux-x86_64-gcc.cross-file new file mode 100644 index 0000000..9a0937c --- /dev/null +++ b/user/include/mlibc/ci/linux-x86_64-gcc.cross-file @@ -0,0 +1,9 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[host_machine] +system = 'linux' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/managarm.cross-file b/user/include/mlibc/ci/managarm.cross-file new file mode 100644 index 0000000..c4351f9 --- /dev/null +++ b/user/include/mlibc/ci/managarm.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'managarm' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/menix.cross-file b/user/include/mlibc/ci/menix.cross-file new file mode 100644 index 0000000..4acbc7a --- /dev/null +++ b/user/include/mlibc/ci/menix.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'menix' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' \ No newline at end of file diff --git a/user/include/mlibc/ci/nyaux.cross-file b/user/include/mlibc/ci/nyaux.cross-file new file mode 100644 index 0000000..c47106d --- /dev/null +++ b/user/include/mlibc/ci/nyaux.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'nyaux' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/ci/vinix.cross-file b/user/include/mlibc/ci/vinix.cross-file new file mode 100644 index 0000000..ab3e601 --- /dev/null +++ b/user/include/mlibc/ci/vinix.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'gcc' +cpp = 'g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'vinix' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/user/include/mlibc/dummy-libs/libdl/src/dummy.cpp b/user/include/mlibc/dummy-libs/libdl/src/dummy.cpp new file mode 100644 index 0000000..c9d4287 --- /dev/null +++ b/user/include/mlibc/dummy-libs/libdl/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libdl because g++ always links with -ldl +// The actual functions reside inside libc + +extern "C" void __mlibc_libdl_dummy(void) { } + diff --git a/user/include/mlibc/dummy-libs/libm/src/dummy.cpp b/user/include/mlibc/dummy-libs/libm/src/dummy.cpp new file mode 100644 index 0000000..eed43ca --- /dev/null +++ b/user/include/mlibc/dummy-libs/libm/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libm because g++ always links with -lm +// The actual math functions reside inside libc + +extern "C" void __mlibc_libm_dummy(void) { } + diff --git a/user/include/mlibc/dummy-libs/libpthread/src/dummy.cpp b/user/include/mlibc/dummy-libs/libpthread/src/dummy.cpp new file mode 100644 index 0000000..3f8c51a --- /dev/null +++ b/user/include/mlibc/dummy-libs/libpthread/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libpthread because g++ always links with -lpthread +// The actual functions reside inside libc + +extern "C" void __mlibc_libpthread_dummy(void) { } + diff --git a/user/include/mlibc/dummy-libs/libresolv/src/dummy.cpp b/user/include/mlibc/dummy-libs/libresolv/src/dummy.cpp new file mode 100644 index 0000000..5feb1c3 --- /dev/null +++ b/user/include/mlibc/dummy-libs/libresolv/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libresolv because some programs always links with -lresolv +// The actual functions reside inside libc + +extern "C" void __mlibc_libresolv_dummy(void) { } + diff --git a/user/include/mlibc/dummy-libs/librt/src/dummy.cpp b/user/include/mlibc/dummy-libs/librt/src/dummy.cpp new file mode 100644 index 0000000..35c3852 --- /dev/null +++ b/user/include/mlibc/dummy-libs/librt/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty librt because g++ always links with -lrt +// The actual functions reside inside libc + +extern "C" void __mlibc_librt_dummy(void) { } + diff --git a/user/include/mlibc/dummy-libs/libssp/src/dummy.cpp b/user/include/mlibc/dummy-libs/libssp/src/dummy.cpp new file mode 100644 index 0000000..43286c1 --- /dev/null +++ b/user/include/mlibc/dummy-libs/libssp/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libsso because some packages expect -lssp +// The actual ssp functions are provided by libc. + +extern "C" void __mlibc_libssp_dummy(void) { } + diff --git a/user/include/mlibc/dummy-libs/libssp_nonshared/src/dummy.cpp b/user/include/mlibc/dummy-libs/libssp_nonshared/src/dummy.cpp new file mode 100644 index 0000000..dcd8e90 --- /dev/null +++ b/user/include/mlibc/dummy-libs/libssp_nonshared/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libsso because some packages expect -lssp_nonshared +// The actual ssp functions are provided by libc. + +extern "C" void __mlibc_libssp_nonshared_dummy(void) { } + diff --git a/user/include/mlibc/dummy-libs/libutil/src/dummy.cpp b/user/include/mlibc/dummy-libs/libutil/src/dummy.cpp new file mode 100644 index 0000000..c295ee5 --- /dev/null +++ b/user/include/mlibc/dummy-libs/libutil/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libutil because g++ always links with -lutil +// The actual functions reside inside libc + +extern "C" void __mlibc_libutil_dummy(void) { } + diff --git a/user/include/mlibc/helloworld b/user/include/mlibc/helloworld new file mode 100755 index 0000000..be5e0f8 Binary files /dev/null and b/user/include/mlibc/helloworld differ diff --git a/user/include/mlibc/helloworld.c b/user/include/mlibc/helloworld.c new file mode 100644 index 0000000..00aa25e --- /dev/null +++ b/user/include/mlibc/helloworld.c @@ -0,0 +1,7 @@ +#include + +int main(void) { + printf("Hello, world!\n"); + return 0; +} + diff --git a/user/include/mlibc/internal-config.h.in b/user/include/mlibc/internal-config.h.in new file mode 100644 index 0000000..3d03434 --- /dev/null +++ b/user/include/mlibc/internal-config.h.in @@ -0,0 +1,11 @@ +#pragma once + +#mesondefine MLIBC_SYSTEM_NAME +#mesondefine MLIBC_DEFAULT_LIBRARY_PATHS +#mesondefine MLIBC_NUM_DEFAULT_LIBRARY_PATHS +#mesondefine MLIBC_MAP_DSO_SEGMENTS +#mesondefine MLIBC_MMAP_ALLOCATE_DSO +#mesondefine MLIBC_MAP_FILE_WINDOWS +#mesondefine MLIBC_STATIC_BUILD +#mesondefine MLIBC_DEBUG_ALLOCATOR + diff --git a/user/include/mlibc/meson.build b/user/include/mlibc/meson.build new file mode 100644 index 0000000..bd57852 --- /dev/null +++ b/user/include/mlibc/meson.build @@ -0,0 +1,603 @@ +project('mlibc', version: '6.3.1', default_options: ['warning_level=2', 'c_std=gnu11', 'cpp_std=c++23'], meson_version: '>=1.3.0') + +fs = import('fs') + +rtld_include_dirs = [ + include_directories('options/internal/include'), + include_directories('options/internal' / host_machine.cpu_family() + '-include'), + include_directories('options/rtld' / host_machine.cpu_family()), + include_directories('options/rtld/include'), +] +libc_include_dirs = [ + include_directories('options/internal/include'), + include_directories('options/elf/include'), + include_directories('options/lsb/include'), + include_directories('options/rtld/include'), + include_directories('options/rtld' / host_machine.cpu_family()), + include_directories('options/internal' / host_machine.cpu_family() + '-include') +] + +rtld_sources = [ ] +rtld_dso_sources = [ ] +libc_sources = [ ] +libc_sublibs = [ ] + +libc_deps = [ ] +rtld_deps = [ ] + +headers_only = get_option('headers_only') +no_headers = get_option('no_headers') +library_type = get_option('default_library') +build_tests = get_option('build_tests') +build_tests_host_libc = get_option('build_tests_host_libc') +libgcc_dependency = get_option('libgcc_dependency') +internal_conf = configuration_data() +mlibc_conf = configuration_data() + +if not headers_only + add_languages('c', 'cpp', native: true, required: false) + add_languages('c', 'cpp', native: false) + c_compiler = meson.get_compiler('c') + cpp_compiler = meson.get_compiler('cpp') + + target_triple = run_command(c_compiler.cmd_array(), '-dumpmachine', check: true).stdout() + use_freestnd_hdrs = get_option('use_freestnd_hdrs').disable_auto_if( + target_triple.to_lower().contains('mlibc')) + + freestnd_c_hdrs_dep = dependency( + 'freestnd-c-hdrs-' + host_machine.cpu_family(), + required: use_freestnd_hdrs, + fallback: ['freestnd-c-hdrs', 'freestnd_c_hdrs_dep'], + ) + libc_deps += freestnd_c_hdrs_dep + rtld_deps += freestnd_c_hdrs_dep + + freestnd_cxx_hdrs_dep = dependency( + 'freestnd-cxx-hdrs-' + host_machine.cpu_family(), + required: use_freestnd_hdrs, + fallback: ['freestnd-cxx-hdrs', 'freestnd_cxx_hdrs_dep'], + ) + libc_deps += freestnd_cxx_hdrs_dep + rtld_deps += freestnd_cxx_hdrs_dep + + frigg_dep = dependency( + 'frigg', + default_options: [ + 'frigg_no_install=true', + 'build_tests=disabled' + ], + fallback: ['frigg', 'frigg_dep'], + ) + libc_deps += frigg_dep + rtld_deps += frigg_dep + + add_project_arguments('-Wno-unused-function', '-D__MLIBC_BUILDING_MLIBC', language: ['c', 'cpp']) + add_project_arguments('-nostdinc', '-fno-builtin', '-ffreestanding', language: ['c', 'cpp']) + add_project_arguments('-Werror=misleading-indentation', language: ['c', 'cpp']) + add_project_arguments('-fno-rtti', '-fno-exceptions', language: 'cpp') + add_project_link_arguments('-nostdlib', language: ['c', 'cpp']) + + if get_option('buildtype').startswith('debug') + add_project_arguments('-D__MLIBC_DEBUG', language : ['c', 'cpp']) + endif + + if not freestnd_c_hdrs_dep.found() + searchdirs = run_command(c_compiler.cmd_array(), '-print-search-dirs', + check: true).stdout() + searchdirs_arr = searchdirs.split('\n') + searchline = 'install: ' + ccdir = '' + if c_compiler.get_id() == 'clang' + searchline = 'libraries: =' + endif + + foreach line : searchdirs_arr + if line.startswith(searchline) + ccdir = line.strip(searchline) + ccdir = ccdir.split(':')[0] + break + endif + endforeach + + if ccdir == '' + error('could not find compiler-specific header directory') + endif + + if c_compiler.get_id() == 'gcc' and fs.exists(ccdir / 'include-fixed') + rtld_include_dirs += include_directories(ccdir / 'include-fixed') + libc_include_dirs += include_directories(ccdir / 'include-fixed') + endif + + rtld_include_dirs += include_directories(ccdir / 'include') + libc_include_dirs += include_directories(ccdir / 'include') + endif + + if not freestnd_cxx_hdrs_dep.found() + cplusplus_include_path = [] + + c_output = run_command(c_compiler.cmd_array(), '-E', '-v', '-x', 'c', + '/dev/null', '-o', '-', + capture: true, + check: true).stderr().split('\n') + + cpp_output = run_command(cpp_compiler.cmd_array(), '-E', '-v', '-x', + 'c++', '/dev/null', '-o', '-', + capture: true, + check: true).stderr().split('\n') + + c_relevant_lines = [] + + relevantmarker = '#include <...>' + relevant_started = false + + foreach line : c_output + if relevant_started + if not line.startswith(' ') + break + endif + c_relevant_lines += line.strip() + elif line.startswith(relevantmarker) + relevant_started = true + endif + endforeach + + relevant_started = false + + foreach line : cpp_output + if relevant_started + if not line.startswith(' ') + break + endif + debug('maybe relevant', line) + stripped = line.strip() + if stripped in c_relevant_lines + debug('not relevant (is C)', line) + continue + endif + cplusplus_include_path += include_directories(stripped) + elif line.startswith(relevantmarker) + relevant_started = true + endif + endforeach + + rtld_include_dirs += cplusplus_include_path + libc_include_dirs += cplusplus_include_path + endif +endif + +default_library_paths = get_option('default_library_paths') +if default_library_paths.length() == 0 + target_word_size = { + 'x86_64': 64, + 'x86': 32, + 'riscv64': 64, + 'riscv32': 32, + 'aarch64': 64, + 'arm': 32, + 'm68k': 32, + 'loongarch64': 64, + } + if target_word_size.get(target_machine.cpu_family()) == 64 + default_library_paths = ['/lib', '/lib64', '/usr/lib', '/usr/lib64'] + else + default_library_paths = ['/lib', '/usr/lib'] + endif +endif + +internal_conf.set_quoted('MLIBC_SYSTEM_NAME', host_machine.system()) +internal_conf.set_quoted('MLIBC_DEFAULT_LIBRARY_PATHS', '\\n'.join(default_library_paths)) +internal_conf.set('MLIBC_NUM_DEFAULT_LIBRARY_PATHS', default_library_paths.length()) +internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', false) +internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', false) +internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', false) +internal_conf.set10('MLIBC_DEBUG_ALLOCATOR', get_option('debug_allocator')) + +#---------------------------------------------------------------------------------------- +# Configuration based on sysdeps. +#---------------------------------------------------------------------------------------- + +rtld_include_dirs += include_directories('sysdeps/generic-helpers/include') +libc_include_dirs += include_directories('sysdeps/generic-helpers/include') + +# Process sysdeps first, as sysdeps might want to disable unsupported options. +provides_bits_syscall_h = false +if host_machine.system() == 'linux' + provides_bits_syscall_h = true + rtld_include_dirs += include_directories('sysdeps/linux/include') + libc_include_dirs += include_directories('sysdeps/linux/include') + + if not headers_only + if get_option('linux_kernel_headers') == '' + error('linux_kernel_headers is not set') + endif + + if not import('fs').is_dir(get_option('linux_kernel_headers')) + error('linux_kernel_headers is not set to a valid path') + endif + + rtld_include_dirs += include_directories(get_option('linux_kernel_headers')) + libc_include_dirs += include_directories(get_option('linux_kernel_headers')) + endif + + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', true) + subdir('sysdeps/linux') +elif host_machine.system() == 'aero' + rtld_include_dirs += include_directories('sysdeps/aero/include') + libc_include_dirs += include_directories('sysdeps/aero/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + subdir('sysdeps/aero') +elif host_machine.system() == 'managarm' + # TODO: Adopt the include_directories() commands from the managarm meson.build. + rtld_include_dirs += include_directories('sysdeps/managarm/include') + libc_include_dirs += include_directories('sysdeps/managarm/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + subdir('sysdeps/managarm') +elif host_machine.system() == 'ironclad' + rtld_include_dirs += include_directories('sysdeps/ironclad/include') + libc_include_dirs += include_directories('sysdeps/ironclad/include') + internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', true) + subdir('sysdeps/ironclad') +elif host_machine.system() == 'keyronex' + rtld_include_dirs += include_directories('sysdeps/keyronex/include') + libc_include_dirs += include_directories('sysdeps/keyronex/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + subdir('sysdeps/keyronex') +elif host_machine.system() == 'vinix' + rtld_include_dirs += include_directories('sysdeps/vinix/include') + libc_include_dirs += include_directories('sysdeps/vinix/include') + subdir('sysdeps/vinix') +elif host_machine.system() == 'lemon' + rtld_include_dirs += include_directories('sysdeps/lemon/include') + libc_include_dirs += include_directories('sysdeps/lemon/include') + subdir('sysdeps/lemon') +elif host_machine.system() == 'dripos' + rtld_include_dirs += include_directories('sysdeps/dripos/include') + libc_include_dirs += include_directories('sysdeps/dripos/include') + subdir('sysdeps/dripos') +elif host_machine.system() == 'astral' + rtld_include_dirs += include_directories('sysdeps/astral/include') + libc_include_dirs += include_directories('sysdeps/astral/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', true) + subdir('sysdeps/astral') +elif host_machine.system() == 'menix' + rtld_include_dirs += include_directories('sysdeps/menix/include') + libc_include_dirs += include_directories('sysdeps/menix/include') + subdir('sysdeps/menix') +elif host_machine.system() == 'nyaux' + rtld_include_dirs += include_directories('sysdeps/nyaux/include') + libc_include_dirs += include_directories('sysdeps/nyaux/include') + subdir('sysdeps/nyaux') +elif host_machine.system() == 'kirkos' + subdir('sysdeps/kirkos') +else + error('No sysdeps defined for OS: ' + host_machine.system()) +endif + +#---------------------------------------------------------------------------------------- +# Configuration based on enabled options. +#---------------------------------------------------------------------------------------- + +posix_option = get_option('posix_option').require(sysdep_supported_options.get('posix')).allowed() +linux_option = get_option('linux_option').require(sysdep_supported_options.get('linux')).allowed() +glibc_option = get_option('glibc_option').require(sysdep_supported_options.get('glibc')).allowed() +bsd_option = get_option('bsd_option').require(sysdep_supported_options.get('bsd')).allowed() + +mlibc_conf.set10('__MLIBC_POSIX_OPTION', posix_option) +mlibc_conf.set10('__MLIBC_LINUX_OPTION', linux_option) +mlibc_conf.set10('__MLIBC_GLIBC_OPTION', glibc_option) +mlibc_conf.set10('__MLIBC_BSD_OPTION', bsd_option) +mlibc_conf.set10('__MLIBC_SYSDEP_HAS_BITS_SYSCALL_H', provides_bits_syscall_h) + +rtld_include_dirs += include_directories('options/ansi/include') +libc_include_dirs += include_directories('options/ansi/include') + +if posix_option + rtld_include_dirs += include_directories('options/posix/include') + libc_include_dirs += include_directories('options/posix/include') +endif + +if linux_option + if not headers_only + if get_option('linux_kernel_headers') == '' + error('linux_kernel_headers is not set') + endif + + if not import('fs').is_dir(get_option('linux_kernel_headers')) + error('linux_kernel_headers is not set to a valid path') + endif + + cc_search_path = run_command(meson.get_compiler('cpp', native: true), '-E', '-Wp,-v', '-xc', '/dev/null', check: true).stderr() + search_paths = [] + + search_started = false + foreach line : cc_search_path.strip().splitlines() + if not search_started and line == '#include <...> search starts here:' + search_started = true + continue + elif search_started and line == 'End of search list.' + search_started = false + elif search_started + search_paths += line.strip() + endif + endforeach + + foreach path : search_paths + if fs.is_samepath(get_option('linux_kernel_headers'), path) + warning('Please install Linux kernel headers to a directory using \'make headers_install\'.') + error('Using system include paths for \'linux_kernel_headers\' is unsupported!') + endif + endforeach + endif + + rtld_include_dirs += include_directories('options/linux/include') + libc_include_dirs += include_directories('options/linux/include') + + linux_kernel_dep = declare_dependency(include_directories: include_directories(get_option('linux_kernel_headers'))) + + libc_deps += linux_kernel_dep + rtld_deps += linux_kernel_dep +endif + +if glibc_option + rtld_include_dirs += include_directories('options/glibc/include') + libc_include_dirs += include_directories('options/glibc/include') +endif + +if bsd_option + rtld_include_dirs += include_directories('options/bsd/include') + libc_include_dirs += include_directories('options/bsd/include') +endif + +rtld_include_dirs += include_directories('options/elf/include') +libc_include_dirs += include_directories('options/elf/include') +libc_include_dirs += include_directories('.') + +#---------------------------------------------------------------------------------------- + +configure_file(input: 'internal-config.h.in', + output: 'internal-config.h', + configuration: internal_conf) + +configure_file(input: 'mlibc-config.h.in', + output: 'mlibc-config.h', + configuration: mlibc_conf, + install: not no_headers, + install_dir: get_option('includedir')) + +internal_sources = [ + 'options/internal/generic/allocator.cpp', + 'options/internal/generic/charcode.cpp', + 'options/internal/generic/charset.cpp', + 'options/internal/generic/debug.cpp', + 'options/internal/generic/ensure.cpp', + 'options/internal/generic/essential.cpp', + 'options/internal/generic/frigg.cpp', + 'options/internal/generic/getopt.cpp', + 'options/internal/generic/global-config.cpp', + 'options/internal/generic/inline-emitter.cpp', + 'options/internal/generic/locale.cpp', + 'options/internal/generic/sigset.cpp', + 'options/internal/generic/strings.cpp', + 'options/internal/generic/ubsan.cpp', + 'options/internal/generic/threads.cpp', + 'options/internal/generic/search.cpp', + 'options/internal/gcc/stack_protector.cpp', + 'options/internal/gcc/guard-abi.cpp', + 'options/internal/gcc-extra/cxxabi.cpp', + 'options/internal' / host_machine.cpu_family() / 'setjmp.S', + 'options/internal' / host_machine.cpu_family() / 'fenv.S', +] + +if host_machine.cpu_family() == 'riscv64' + internal_sources += [ + 'options/internal/riscv64/hwprobe.cpp', + ] +endif + +if not no_headers + install_headers( + 'options/internal/include/stdint.h' + ) + + if host_machine.cpu_family() == 'riscv64' + install_headers( + 'options/internal/riscv64-include/sys/hwprobe.h', + subdir: 'sys' + ) + endif + + install_headers( + 'options/internal/include/bits/wchar_t.h', + 'options/internal/include/bits/wchar.h', + 'options/internal/include/bits/wint_t.h', + 'options/internal/include/bits/wctrans_t.h', + 'options/internal/include/bits/wctype_t.h', + 'options/internal/include/bits/size_t.h', + 'options/internal/include/bits/types.h', + 'options/internal/include/bits/ensure.h', + 'options/internal/include/bits/machine.h', + 'options/internal/include/bits/mbstate.h', + 'options/internal/include/bits/nl_item.h', + 'options/internal/include/bits/null.h', + 'options/internal/include/bits/off_t.h', + 'options/internal/include/bits/file.h', + 'options/internal/include/bits/ssize_t.h', + 'options/internal/include/bits/sigset_t.h', + 'options/internal/include/bits/inline-definition.h', + 'options/internal/include/bits/ether_addr.h', + 'options/internal/include/bits/cpu_set.h', + 'options/internal/include/bits/threads.h', + 'options/internal/include/bits/winsize.h', + 'options/internal/include/bits/search.h', + 'options/internal/include/bits/getopt.h', + subdir: 'bits' + ) +endif + +rtld_sources += [ + 'options/internal/gcc/stack_protector.cpp', + 'options/internal/gcc/guard-abi.cpp', + 'options/internal/generic/allocator.cpp', + 'options/internal/generic/debug.cpp', + 'options/internal/generic/ensure.cpp', + 'options/internal/generic/essential.cpp', + 'options/internal/generic/inline-emitter.cpp', + 'options/internal/generic/frigg.cpp', + 'options/internal/generic/ubsan.cpp', + 'options/rtld/generic/main.cpp', + 'options/rtld/generic/linker.cpp', + 'options/rtld' / host_machine.cpu_family() / 'runtime.S' +] + +rtld_dso_sources += ['options/rtld' / host_machine.cpu_family() / 'entry.S'] + +subdir('options/elf') +subdir('options/ansi') +subdir('options/posix') +subdir('options/lsb') +subdir('options/glibc') +subdir('options/linux') +subdir('options/bsd') + +rtlib_deps = [] + +if not headers_only + if libgcc_dependency + libgcc = meson.get_compiler('c').find_library('gcc', required: false) + + compiler_rt_name = 'libclang_rt.builtins-' + host_machine.cpu_family() + compiler_rt = meson.get_compiler('c').find_library(compiler_rt_name, required: false) + + if not compiler_rt.found() + compiler_rt_name = 'libclang_rt.builtins' + compiler_rt = meson.get_compiler('c').find_library(compiler_rt_name, required: false) + endif + + if libgcc.found() + rtlib_deps += libgcc + elif compiler_rt.found() + rtlib_deps += compiler_rt + else + error('neither libgcc nor ' + compiler_rt_name + ' was found') + endif + endif + + ld_cpp_args = [ + '-fvisibility=hidden', + '-fvisibility-inlines-hidden', + '-fno-stack-protector', + '-DMLIBC_BUILDING_RTLD', + '-Wno-extern-c-compat', + '-Wno-unknown-pragmas', + ] + + libc_cpp_args = [ + '-Wno-unknown-pragmas', + '-DFRG_HAVE_LIBC', + ] + + if c_compiler.get_id() == 'clang' + libc_cpp_args += ['-fno-sanitize=function', '-Wno-vla-cxx-extension'] + ld_cpp_args += ['-fno-sanitize=function'] + endif + + libc_all_sources = [ + libc_sources, + internal_sources, + ansi_sources, + lsb_sources, + ] + + ld_library_name = get_option('ld_library_name') + + # Our libraries have different behaviour when built as static and shared libraries. + # Hence we need to rebuild the object files with a different define for each mode. + if library_type in ['static', 'both'] + static_cpp_args = [ + '-DMLIBC_STATIC_BUILD', + ] + ld_static_lib = static_library(ld_library_name, rtld_sources, + name_prefix: '', + cpp_args: ld_cpp_args + static_cpp_args, + include_directories: rtld_include_dirs, + dependencies: rtld_deps + rtlib_deps, + install: false + ) + libc_static = static_library('c', libc_all_sources, + cpp_args: static_cpp_args + ['-fno-stack-protector', libc_cpp_args], + include_directories: libc_include_dirs, + dependencies: libc_deps + rtlib_deps, + link_with: [ld_static_lib], + link_whole: [libc_sublibs, ld_static_lib], + install: true + ) + endif + if library_type in ['shared', 'both'] + ld_shared_lib = shared_library(ld_library_name, rtld_sources + rtld_dso_sources, + name_prefix: '', + cpp_args: ld_cpp_args, + include_directories: rtld_include_dirs, + dependencies: rtld_deps + rtlib_deps, + install: true + ) + hide_everything_ld = (meson.current_source_dir() + / 'scripts/hide-everything.ld') + libc_shared = shared_library('c', libc_all_sources, + cpp_args: [libc_cpp_args], + include_directories: libc_include_dirs, + dependencies: libc_deps + rtlib_deps, + link_with: [ld_shared_lib], + link_whole: libc_sublibs, + link_args: ['-Wl,--version-script,' + hide_everything_ld], + link_depends: [hide_everything_ld], + install: true + ) + endif + + library('pthread', 'dummy-libs/libpthread/src/dummy.cpp', cpp_args: libc_cpp_args, install: true) + library('rt', 'dummy-libs/librt/src/dummy.cpp', cpp_args: libc_cpp_args, install: true) + library('util', 'dummy-libs/libutil/src/dummy.cpp', cpp_args: libc_cpp_args, install: true) + library('m', 'dummy-libs/libm/src/dummy.cpp', cpp_args: libc_cpp_args, install: true) + library('resolv', 'dummy-libs/libresolv/src/dummy.cpp', cpp_args: libc_cpp_args, install: true) + library('dl', 'dummy-libs/libdl/src/dummy.cpp', cpp_args: libc_cpp_args, install: true) + library('ssp', 'dummy-libs/libssp/src/dummy.cpp', cpp_args: libc_cpp_args, install: true) + library('ssp_nonshared', 'dummy-libs/libssp_nonshared/src/dummy.cpp', cpp_args: libc_cpp_args, install: true) +endif + +summary_info = {} +summary_info += {'Build tests': build_tests} +summary_info += {'Build host-libc tests': build_tests_host_libc} +summary(summary_info, bool_yn: true, section: 'tests') + +summary_info = {} +summary_info += {'headers-only': headers_only} +summary_info += {'POSIX option': get_option('posix_option')} +summary_info += {'Linux option': get_option('linux_option')} +summary_info += {'glibc option': get_option('glibc_option')} +summary_info += {'BSD option': get_option('bsd_option')} +summary_info += {'debug allocator': get_option('debug_allocator')} +summary_info += {'libgcc dependency': libgcc_dependency} +summary(summary_info, bool_yn: true, section: 'mlibc options') + +if build_tests + subdir('tests/') +endif + +hdoc = find_program('hdoc', required: false) + +conf_data = configuration_data() +conf_data.set('source_root', meson.global_source_root()) +conf_data.set('build_root', meson.global_build_root()) +configure_file(input: 'scripts/hdoc.toml.in', + output: '.hdoc.toml', configuration: conf_data) + +if hdoc.found() + run_target('hdoc', command : [hdoc.full_path(), '--verbose']) +endif diff --git a/user/include/mlibc/meson_options.txt b/user/include/mlibc/meson_options.txt new file mode 100644 index 0000000..b977981 --- /dev/null +++ b/user/include/mlibc/meson_options.txt @@ -0,0 +1,17 @@ +option('headers_only', type : 'boolean', value : false) +option('no_headers', type : 'boolean', value : false) +option('build_tests', type: 'boolean', value : false) +option('build_tests_host_libc', type: 'boolean', value : true) +option('posix_option', type: 'feature', value : 'auto') +option('linux_option', type: 'feature', value : 'auto') +option('glibc_option', type: 'feature', value : 'auto') +option('bsd_option', type: 'feature', value : 'auto') +option('libgcc_dependency', type : 'boolean', value : true) +option('linux_kernel_headers', type: 'string', value : '') +option('default_library_paths', type: 'array', value: []) +option('debug_allocator', type : 'boolean', value : false, + description : 'Enable the debug allocator, which uses mmap for every allocation and adds guard pages for each allocation') +option('use_freestnd_hdrs', type : 'feature', value : 'auto', + description : 'Use freestnd-c{,xx}-hdrs instead of looking for compiler headers') +option('ld_library_name', type: 'string', value: 'ld', + description: 'Name of the ld library to build. Defaults to "ld".') diff --git a/user/include/mlibc/mlibc-config.h.in b/user/include/mlibc/mlibc-config.h.in new file mode 100644 index 0000000..dcea1f9 --- /dev/null +++ b/user/include/mlibc/mlibc-config.h.in @@ -0,0 +1,20 @@ +#ifndef _MLIBC_CONFIG_H +#define _MLIBC_CONFIG_H + +#ifdef _GNU_SOURCE +# undef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE 1 +#endif + +#if (defined(_DEFAULT_SOURCE) || (!defined(__STRICT_ANSI__) && !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE))) +# undef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE 1 +#endif + +#mesondefine __MLIBC_BSD_OPTION +#mesondefine __MLIBC_POSIX_OPTION +#mesondefine __MLIBC_LINUX_OPTION +#mesondefine __MLIBC_GLIBC_OPTION +#mesondefine __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H + +#endif /* _MLIBC_CONFIG_H */ diff --git a/user/include/mlibc/options/ansi/generic/assert.cpp b/user/include/mlibc/options/ansi/generic/assert.cpp new file mode 100644 index 0000000..6ebb6ed --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/assert.cpp @@ -0,0 +1,13 @@ + +#include +#include +#include + +#include + +[[gnu::noreturn]] void __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function) { + fprintf(stderr, "In function %s, file %s:%d: Assertion '%s' failed!\n", + function, file, line, assertion); + abort(); +} diff --git a/user/include/mlibc/options/ansi/generic/complex.c b/user/include/mlibc/options/ansi/generic/complex.c new file mode 100644 index 0000000..069626b --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex.c @@ -0,0 +1,9 @@ +#include + +long double cimagl(long double complex z) { + return __imag__(z); +} + +long double creall(long double complex z) { + return __real__(z); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cabs.c b/user/include/mlibc/options/ansi/generic/complex/cabs.c new file mode 100644 index 0000000..b97579b --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cabs.c @@ -0,0 +1,59 @@ +/* $NetBSD: cabs.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>, <>---complex absolute-value + +INDEX + cabs +INDEX + cabsf +INDEX + cabsl + +SYNOPSIS + #include + double cabs(double complex <[z]>); + float cabsf(float complex <[z]>); + long double cabsl(long double complex <[z]>); + + +DESCRIPTION + These functions compute compute the complex absolute value + (also called norm, modulus, or magnitude) of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cabs* functions return the complex absolute value. + +PORTABILITY + <>, <> and <> are ISO C99 + +QUICKREF + <>, <> and <> are ISO C99 + +*/ + + +#include +#include + +double +cabs(double complex z) +{ + + return hypot( creal(z), cimag(z) ); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cabsf.c b/user/include/mlibc/options/ansi/generic/complex/cabsf.c new file mode 100644 index 0000000..635e23e --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cabsf.c @@ -0,0 +1,19 @@ +/* $NetBSD: cabsf.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float +cabsf(float complex z) +{ + + return hypotf( crealf(z), cimagf(z) ); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cacos.c b/user/include/mlibc/options/ansi/generic/complex/cacos.c new file mode 100644 index 0000000..2b0b82a --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cacos.c @@ -0,0 +1,99 @@ +/* $NetBSD: cacos.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc cosine + +INDEX + cacos +INDEX + cacosf + +SYNOPSIS + #include + double complex cacos(double complex <[z]>); + float complex cacosf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc cosine of <[z]>, + with branch cuts outside the interval [-1, +1] along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc cosine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [0, pi] along the real axis. + @end ifnottex + @tex + These functions return the complex arc cosine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [<<0>>, $\pi$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +cacos(double complex z) +{ + double complex w; + + /* FIXME: The original NetBSD code results in an ICE when trying to + build this function on ARM/Thumb using gcc 4.5.1. For now we use + a hopefully temporary workaround. */ +#if 0 + w = casin(z); + w = (M_PI_2 - creal(w)) - cimag(w) * I; +#else + double complex tmp0, tmp1; + + tmp0 = casin(z); + tmp1 = M_PI_2 - creal(tmp0); + w = tmp1 - (cimag(tmp0) * I); +#endif + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cacosf.c b/user/include/mlibc/options/ansi/generic/complex/cacosf.c new file mode 100644 index 0000000..3874dd5 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cacosf.c @@ -0,0 +1,46 @@ +/* $NetBSD: cacosf.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cacosf(float complex z) +{ + float complex w; + + w = casinf(z); + w = ((float)M_PI_2 - crealf(w)) - cimagf(w) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cacosh.c b/user/include/mlibc/options/ansi/generic/complex/cacosh.c new file mode 100644 index 0000000..857b5c3 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cacosh.c @@ -0,0 +1,93 @@ +/* $NetBSD: cacosh.c,v 1.2 2009/08/03 19:41:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic cosine + +INDEX + cacosh +INDEX + cacoshf + +SYNOPSIS + #include + double complex cacosh(double complex <[z]>); + float complex cacoshf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc hyperbolic cosine of <[z]>, + with a branch cut at values less than 1 along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic cosine value, + in the range of a half-strip of non-negative values along the + real axis and in the interval [-i * pi, +i * pi] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic cosine value, + in the range of a half-strip of non-negative values along the + real axis and in the interval [$-i\pi$, $+i\pi$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +cacosh(double complex z) +{ + double complex w; + +#if 0 /* does not give the principal value */ + w = I * cacos(z); +#else + w = clog(z + csqrt(z + 1) * csqrt(z - 1)); +#endif + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cacoshf.c b/user/include/mlibc/options/ansi/generic/complex/cacoshf.c new file mode 100644 index 0000000..41a557a --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cacoshf.c @@ -0,0 +1,48 @@ +/* $NetBSD: cacoshf.c,v 1.2 2009/08/03 19:41:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +cacoshf(float complex z) +{ + float complex w; + +#if 0 /* does not give the principal value */ + w = I * cacosf(z); +#else + w = clogf(z + csqrtf(z + 1) * csqrtf(z - 1)); +#endif + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/carg.c b/user/include/mlibc/options/ansi/generic/complex/carg.c new file mode 100644 index 0000000..f7efb40 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/carg.c @@ -0,0 +1,59 @@ +/* $NetBSD: carg.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---argument (phase angle) + +INDEX + carg +INDEX + cargf + +SYNOPSIS + #include + double carg(double complex <[z]>); + float cargf(float complex <[z]>); + + +DESCRIPTION + These functions compute the argument (also called phase angle) + of <[z]>, with a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + The carg functions return the value of the argument in the + interval [-pi, +pi] + @end ifnottex + @tex + The carg functions return the value of the argument in the + interval [$-\pi$, $+\pi$] + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double +carg(double complex z) +{ + + return atan2( cimag(z) , creal(z) ); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cargf.c b/user/include/mlibc/options/ansi/generic/complex/cargf.c new file mode 100644 index 0000000..1683d21 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cargf.c @@ -0,0 +1,19 @@ +/* $NetBSD: cargf.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float +cargf(float complex z) +{ + + return atan2f( cimagf(z), crealf(z) ); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/casin.c b/user/include/mlibc/options/ansi/generic/complex/casin.c new file mode 100644 index 0000000..ced1053 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/casin.c @@ -0,0 +1,165 @@ +/* $NetBSD: casin.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc sine + +INDEX + casin +INDEX + casinf + +SYNOPSIS + #include + double complex casin(double complex <[z]>); + float complex casinf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc sine of <[z]>, + with branch cuts outside the interval [-1, +1] along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc sine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [-pi/2, +pi/2] along the real axis. + @end ifnottex + @tex + These functions return the complex arc sine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [$-\pi/2$, $+\pi/2$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +#ifdef __weak_alias +__weak_alias(casin, _casin) +#endif + +double complex +casin(double complex z) +{ + double complex w; + double complex ca, ct, zz, z2; + double x, y; + + x = creal(z); + y = cimag(z); + +#if 0 /* MD: test is incorrect, casin(>1) is defined */ + if (y == 0.0) { + if (fabs(x) > 1.0) { + w = M_PI_2 + 0.0 * I; +#if 0 + mtherr ("casin", DOMAIN); +#endif + } else { + w = asin(x) + 0.0 * I; + } + return w; + } +#endif + +/* Power series expansion */ +/* +b = cabs(z); +if( b < 0.125 ) +{ +z2.r = (x - y) * (x + y); +z2.i = 2.0 * x * y; + +cn = 1.0; +n = 1.0; +ca.r = x; +ca.i = y; +sum.r = x; +sum.i = y; +do + { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabs(ct.r) + fabs(ct.i); + } +while( b > MACHEP ); +w->r = sum.r; +w->i = sum.i; +return; +} +*/ + + + ca = x + y * I; + ct = ca * I; + /* sqrt( 1 - z*z) */ + /* cmul( &ca, &ca, &zz ) */ + /*x * x - y * y */ + zz = (x - y) * (x + y) + (2.0 * x * y) * I; + + zz = 1.0 - creal(zz) - cimag(zz) * I; + z2 = csqrt(zz); + + zz = ct + z2; + zz = clog(zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0 * I); + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/casinf.c b/user/include/mlibc/options/ansi/generic/complex/casinf.c new file mode 100644 index 0000000..9a9f759 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/casinf.c @@ -0,0 +1,122 @@ +/* $NetBSD: casinf.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +#ifdef __weak_alias +__weak_alias(casinf, _casinf) +#endif + +float complex +casinf(float complex z) +{ + float complex w; + float complex ca, ct, zz, z2; + float x, y; + + x = crealf(z); + y = cimagf(z); + +#if 0 /* MD: test is incorrect, casin(>1) is defined */ + if (y == 0.0f) { + if (fabsf(x) > 1.0) { + w = M_PI_2 + 0.0f * I; +#if 0 + mtherr ("casin", DOMAIN); +#endif + } else { + w = asinf(x) + 0.0f * I; + } + return w; + } +#endif + +/* Power series expansion */ +/* +b = cabsf(z); +if( b < 0.125 ) +{ +z2.r = (x - y) * (x + y); +z2.i = 2.0 * x * y; + +cn = 1.0; +n = 1.0; +ca.r = x; +ca.i = y; +sum.r = x; +sum.i = y; +do + { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabsf(ct.r) + fabsf(ct.i); + } +while( b > MACHEP ); +w->r = sum.r; +w->i = sum.i; +return; +} +*/ + + + ca = x + y * I; + ct = ca * I; + /* sqrt( 1 - z*z) */ + /* cmul( &ca, &ca, &zz ) */ + /*x * x - y * y */ + zz = (x - y) * (x + y) + (2.0f * x * y) * I; + + zz = 1.0f - crealf(zz) - cimagf(zz) * I; + z2 = csqrtf(zz); + + zz = ct + z2; + zz = clogf(zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0f * I); + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/casinh.c b/user/include/mlibc/options/ansi/generic/complex/casinh.c new file mode 100644 index 0000000..b4326b9 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/casinh.c @@ -0,0 +1,97 @@ +/* $NetBSD: casinh.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic sine + +INDEX + casinh +INDEX + casinhf + +SYNOPSIS + #include + double complex casinh(double complex <[z]>); + float complex casinhf(float complex <[z]>); + + +DESCRIPTION + @ifnottex + These functions compute the complex arc hyperbolic sine of <[z]>, + with branch cuts outside the interval [-i, +i] along the + imaginary axis. + @end ifnottex + @tex + These functions compute the complex arc hyperbolic sine of <[z]>, + with branch cuts outside the interval [$-i$, $+i$] along the + imaginary axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic sine value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [-i*p/2, +i*p/2] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic sine value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [$-i\pi/2$, $+i\pi/2$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +casinh(double complex z) +{ + double complex w; + + w = -1.0 * I * casin(z * I); + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/casinhf.c b/user/include/mlibc/options/ansi/generic/complex/casinhf.c new file mode 100644 index 0000000..0db55a0 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/casinhf.c @@ -0,0 +1,44 @@ +/* $NetBSD: casinhf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +casinhf(float complex z) +{ + float complex w; + + w = -1.0f * I * casinf(z * I); + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/catan.c b/user/include/mlibc/options/ansi/generic/complex/catan.c new file mode 100644 index 0000000..34d75b8 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/catan.c @@ -0,0 +1,128 @@ +/* $NetBSD: catan.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc tangent + +INDEX + catan +INDEX + catanf + +SYNOPSIS + #include + double complex catan(double complex <[z]>); + float complex catanf(float complex <[z]>); + + +DESCRIPTION + @ifnottex + These functions compute the complex arc tangent of <[z]>, + with branch cuts outside the interval [-i, +i] along the + imaginary axis. + @end ifnottex + @tex + These functions compute the complex arc tangent of <[z]>, + with branch cuts outside the interval [$-i$, $+i$] along the + imaginary axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc tangent value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [-pi/2, +pi/2] along the real axis. + @end ifnottex + @tex + These functions return the complex arc tangent, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [$-\pi/2$, $+\pi/2$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +#ifdef __weak_alias +__weak_alias(catan, _catan) +#endif + +double complex +catan(double complex z) +{ + double complex w; + double a, t, x, x2, y; + + x = creal(z); + y = cimag(z); + + if ((x == 0.0) && (y > 1.0)) + goto ovrf; + + x2 = x * x; + a = 1.0 - x2 - (y * y); + + t = 0.5 * atan2(2.0 * x, a); + w = _redupi(t); + + t = y - 1.0; + a = x2 + (t * t); + if (a == 0.0) + goto ovrf; + + t = y + 1.0; + a = (x2 + (t * t))/a; + w = w + (0.25 * log(a)) * I; + return w; + +ovrf: +#if 0 + mtherr ("catan", OVERFLOW); +#endif + w = HUGE_VAL + HUGE_VAL * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/catanf.c b/user/include/mlibc/options/ansi/generic/complex/catanf.c new file mode 100644 index 0000000..9dc2fb2 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/catanf.c @@ -0,0 +1,77 @@ +/* $NetBSD: catanf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +#ifdef __weak_alias +__weak_alias(catanf, _catanf) +#endif + +float complex +catanf(float complex z) +{ + float complex w; + float a, t, x, x2, y; + + x = crealf(z); + y = cimagf(z); + + if ((x == 0.0f) && (y > 1.0f)) + goto ovrf; + + x2 = x * x; + a = 1.0f - x2 - (y * y); + + t = 0.5f * atan2f(2.0f * x, a); + w = _redupif(t); + + t = y - 1.0f; + a = x2 + (t * t); + if (a == 0.0f) + goto ovrf; + + t = y + 1.0f; + a = (x2 + (t * t))/a; + w = w + (0.25f * logf(a)) * I; + return w; + +ovrf: +#if 0 + mtherr ("catan", OVERFLOW); +#endif + w = HUGE_VALF + HUGE_VALF * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/catanh.c b/user/include/mlibc/options/ansi/generic/complex/catanh.c new file mode 100644 index 0000000..1bb0555 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/catanh.c @@ -0,0 +1,90 @@ +/* $NetBSD: catanh.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic tangent + +INDEX + catanh +INDEX + catanhf + +SYNOPSIS + #include + double complex catanh(double complex <[z]>); + float complex catanhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc hyperbolic tan of <[z]>, + with branch cuts outside the interval [-1, +1] along the + real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic tangent value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [-i*p/2, +i*p/2] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic tangent value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [$-i\pi/2$, $+i\pi/2$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +catanh(double complex z) +{ + double complex w; + + w = -1.0 * I * catan(z * I); + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/catanhf.c b/user/include/mlibc/options/ansi/generic/complex/catanhf.c new file mode 100644 index 0000000..fe6127a --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/catanhf.c @@ -0,0 +1,44 @@ +/* $NetBSD: catanhf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +catanhf(float complex z) +{ + float complex w; + + w = -1.0f * I * catanf(z * I); + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/ccos.c b/user/include/mlibc/options/ansi/generic/complex/ccos.c new file mode 100644 index 0000000..516632e --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/ccos.c @@ -0,0 +1,81 @@ +/* $NetBSD: ccos.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex cosine + +INDEX + ccos +INDEX + ccosf + +SYNOPSIS + #include + double complex ccos(double complex <[z]>); + float complex ccosf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex cosine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex cosine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +ccos(double complex z) +{ + double complex w; + double ch, sh; + + _cchsh(cimag(z), &ch, &sh); + w = cos(creal(z)) * ch - (sin(creal(z)) * sh) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/ccosf.c b/user/include/mlibc/options/ansi/generic/complex/ccosf.c new file mode 100644 index 0000000..805e24f --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/ccosf.c @@ -0,0 +1,48 @@ +/* $NetBSD: ccosf.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +ccosf(float complex z) +{ + float complex w; + float ch, sh; + + _cchshf(cimagf(z), &ch, &sh); + w = cosf(crealf(z)) * ch - (sinf(crealf(z)) * sh) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/ccosh.c b/user/include/mlibc/options/ansi/generic/complex/ccosh.c new file mode 100644 index 0000000..818acc8 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/ccosh.c @@ -0,0 +1,81 @@ +/* $NetBSD: ccosh.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic cosine + +INDEX + ccosh +INDEX + ccoshf + +SYNOPSIS + #include + double complex ccosh(double complex <[z]>); + float complex ccoshf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic cosine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic cosine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +ccosh(double complex z) +{ + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = cosh(x) * cos(y) + (sinh(x) * sin(y)) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/ccoshf.c b/user/include/mlibc/options/ansi/generic/complex/ccoshf.c new file mode 100644 index 0000000..af11353 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/ccoshf.c @@ -0,0 +1,48 @@ +/* $NetBSD: ccoshf.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +ccoshf(float complex z) +{ + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = coshf(x) * cosf(y) + (sinhf(x) * sinf(y)) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cephes_subr.c b/user/include/mlibc/options/ansi/generic/complex/cephes_subr.c new file mode 100644 index 0000000..5eacff6 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cephes_subr.c @@ -0,0 +1,126 @@ +/* $NetBSD: cephes_subr.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subr.h" + +/* calculate cosh and sinh */ + +void +_cchsh(double x, double *c, double *s) +{ + double e, ei; + + if (fabs(x) <= 0.5) { + *c = cosh(x); + *s = sinh(x); + } else { + e = exp(x); + ei = 0.5 / e; + e = 0.5 * e; + *s = e - ei; + *c = e + ei; + } +} + +/* Program to subtract nearest integer multiple of PI */ + +/* extended precision value of PI: */ +static const double DP1 = 3.14159265160560607910E0; +static const double DP2 = 1.98418714791870343106E-9; +static const double DP3 = 1.14423774522196636802E-17; +#define MACHEP 1.1e-16 + +double +_redupi(double x) +{ + double t; + long i; + + t = x / M_PI; + if (t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +double +_ctans(double complex z) +{ + double f, x, x2, y, y2, rn, t; + double d; + + x = fabs(2.0 * creal(z)); + y = fabs(2.0 * cimag(z)); + + x = _redupi(x); + + x = x * x; + y = y * y; + x2 = 1.0; + y2 = 1.0; + f = 1.0; + rn = 0.0; + d = 0.0; + do { + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } while (fabs(t/d) > MACHEP); + return d; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cephes_subr.h b/user/include/mlibc/options/ansi/generic/complex/cephes_subr.h new file mode 100644 index 0000000..3c75d63 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cephes_subr.h @@ -0,0 +1,8 @@ +/* $NetBSD: cephes_subr.h,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +__attribute__((__visibility__("hidden"))) +void _cchsh(double, double *, double *); +__attribute__((__visibility__("hidden"))) +double _redupi(double); +__attribute__((__visibility__("hidden"))) +double _ctans(double complex); diff --git a/user/include/mlibc/options/ansi/generic/complex/cephes_subrf.c b/user/include/mlibc/options/ansi/generic/complex/cephes_subrf.c new file mode 100644 index 0000000..4a32581 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cephes_subrf.c @@ -0,0 +1,125 @@ +/* $NetBSD: cephes_subrf.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +/* calculate cosh and sinh */ + +void +_cchshf(float x, float *c, float *s) +{ + float e, ei; + + if (fabsf(x) <= 0.5f) { + *c = coshf(x); + *s = sinhf(x); + } else { + e = expf(x); + ei = 0.5f / e; + e = 0.5f * e; + *s = e - ei; + *c = e + ei; + } +} + +/* Program to subtract nearest integer multiple of PI */ + +/* extended precision value of PI: */ +static const double DP1 = 3.140625; +static const double DP2 = 9.67502593994140625E-4; +static const double DP3 = 1.509957990978376432E-7; +#define MACHEPF 3.0e-8 + +float +_redupif(float x) +{ + float t; + long i; + + t = x / (float)M_PI; + if (t >= 0.0f) + t += 0.5f; + else + t -= 0.5f; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +float +_ctansf(float complex z) +{ + float f, x, x2, y, y2, rn, t, d; + + x = fabsf(2.0f * crealf(z)); + y = fabsf(2.0f * cimagf(z)); + + x = _redupif(x); + + x = x * x; + y = y * y; + x2 = 1.0f; + y2 = 1.0f; + f = 1.0f; + rn = 0.0f; + d = 0.0f; + do { + rn += 1.0f; + f *= rn; + rn += 1.0f; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0f; + f *= rn; + rn += 1.0f; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } while (fabsf(t/d) > MACHEPF); + return d; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cephes_subrf.h b/user/include/mlibc/options/ansi/generic/complex/cephes_subrf.h new file mode 100644 index 0000000..8d62fc1 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cephes_subrf.h @@ -0,0 +1,8 @@ +/* $NetBSD: cephes_subrf.h,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +__attribute__((__visibility__("hidden"))) +void _cchshf(float, float *, float *); +__attribute__((__visibility__("hidden"))) +float _redupif(float); +__attribute__((__visibility__("hidden"))) +float _ctansf(float complex); diff --git a/user/include/mlibc/options/ansi/generic/complex/cexp.c b/user/include/mlibc/options/ansi/generic/complex/cexp.c new file mode 100644 index 0000000..1c1291d --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cexp.c @@ -0,0 +1,82 @@ +/* $NetBSD: cexp.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex base-e exponential + +INDEX + cexp +INDEX + cexpf + +SYNOPSIS + #include + double complex cexp(double complex <[z]>); + float complex cexpf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex base-<[e]> exponential of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cexp functions return the complex base-<[e]> exponential value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +cexp(double complex z) +{ + double complex w; + double r, x, y; + + x = creal(z); + y = cimag(z); + r = exp(x); + w = r * cos(y) + r * sin(y) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cexpf.c b/user/include/mlibc/options/ansi/generic/complex/cexpf.c new file mode 100644 index 0000000..07fab1f --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cexpf.c @@ -0,0 +1,49 @@ +/* $NetBSD: cexpf.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cexpf(float complex z) +{ + float complex w; + float r, x, y; + + x = crealf(z); + y = cimagf(z); + r = expf(x); + w = r * cosf(y) + r * sinf(y) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cimag.c b/user/include/mlibc/options/ansi/generic/complex/cimag.c new file mode 100644 index 0000000..dfc9891 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cimag.c @@ -0,0 +1,60 @@ +/* $NetBSD: cimag.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>, <>---imaginary part + +INDEX + cimag +INDEX + cimagf +INDEX + cimagl + +SYNOPSIS + #include + double cimag(double complex <[z]>); + float cimagf(float complex <[z]>); + long double cimagl(long double complex <[z]>); + + +DESCRIPTION + These functions compute the imaginary part of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cimag* functions return the imaginary part value (as a real). + +PORTABILITY + <>, <> and <> are ISO C99 + +QUICKREF + <>, <> and <> are ISO C99 + +*/ + + +#include + +#include "fdlibm.h" + +double +cimag(double complex z) +{ + double_complex w = { .z = z }; + + return (IMAG_PART(w)); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cimagf.c b/user/include/mlibc/options/ansi/generic/complex/cimagf.c new file mode 100644 index 0000000..28ed81c --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cimagf.c @@ -0,0 +1,21 @@ +/* $NetBSD: cimagf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float +cimagf(float complex z) +{ + float_complex w = { .z = z }; + + return (IMAG_PART(w)); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/clog.c b/user/include/mlibc/options/ansi/generic/complex/clog.c new file mode 100644 index 0000000..488f3b8 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/clog.c @@ -0,0 +1,91 @@ +/* $NetBSD: clog.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex base-e logarithm + +INDEX + clog +INDEX + clogf + +SYNOPSIS + #include + double complex clog(double complex <[z]>); + float complex clogf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex natural (base-<[e]>) logarithm + of <[z]>, with a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + The clog functions return the complex natural logarithm value, in + the range of a strip mathematically unbounded along the real axis + and in the interval [-i*pi , +i*pi] along the imaginary axis. + @end ifnottex + @tex + The clog functions return the complex natural logarithm value, in + the range of a strip mathematically unbounded along the real axis + and in the interval [$-i\pi$, $+i\pi$] along the imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +clog(double complex z) +{ + double complex w; + double p, rr; + + rr = cabs(z); + p = log(rr); + rr = atan2(cimag(z), creal(z)); + w = p + rr * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/clogf.c b/user/include/mlibc/options/ansi/generic/complex/clogf.c new file mode 100644 index 0000000..078cea5 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/clogf.c @@ -0,0 +1,49 @@ +/* $NetBSD: clogf.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +clogf(float complex z) +{ + float complex w; + float p, rr; + + rr = cabsf(z); + p = logf(rr); + rr = atan2f(cimagf(z), crealf(z)); + w = p + rr * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/conj.c b/user/include/mlibc/options/ansi/generic/complex/conj.c new file mode 100644 index 0000000..ce4443f --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/conj.c @@ -0,0 +1,56 @@ +/* $NetBSD: conj.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex conjugate + +INDEX + conj +INDEX + conjf + +SYNOPSIS + #include + double complex conj(double complex <[z]>); + float complex conjf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex conjugate of <[z]>, + by reversing the sign of its imaginary part. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The conj functions return the complex conjugate value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include + +#include "fdlibm.h" + +double complex +conj(double complex z) +{ + double_complex w = { .z = z }; + + IMAG_PART(w) = -IMAG_PART(w); + + return (w.z); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/conjf.c b/user/include/mlibc/options/ansi/generic/complex/conjf.c new file mode 100644 index 0000000..0ca71ef --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/conjf.c @@ -0,0 +1,23 @@ +/* $NetBSD: conjf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float complex +conjf(float complex z) +{ + float_complex w = { .z = z }; + + IMAG_PART(w) = -IMAG_PART(w); + + return (w.z); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cpow.c b/user/include/mlibc/options/ansi/generic/complex/cpow.c new file mode 100644 index 0000000..e7c419b --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cpow.c @@ -0,0 +1,101 @@ +/* $NetBSD: cpow.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex power + +INDEX + cpow +INDEX + cpowf + +SYNOPSIS + #include + double complex cpow(double complex <[x]>, double complex <[y]>); + float complex cpowf(float complex <[x]>, float complex <[y]>); + + +DESCRIPTION + @ifnottex + The cpow functions compute the complex power function x^y + power, with a branch cut for the first parameter along the + negative real axis. + @end ifnottex + @tex + The cpow functions compute the complex power function $x^y$ + power, with a branch cut for the first parameter along the + negative real axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cpow functions return the complex power function value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +cpow(double complex a, double complex z) +{ + double complex w; + double x, y, r, theta, absa, arga; + + x = creal(z); + y = cimag(z); + absa = cabs(a); + if (absa == 0.0) { + return (0.0 + 0.0 * I); + } + arga = carg(a); + r = pow(absa, x); + theta = x * arga; + if (y != 0.0) { + r = r * exp(-y * arga); + theta = theta + y * log(absa); + } + w = r * cos(theta) + (r * sin(theta)) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cpowf.c b/user/include/mlibc/options/ansi/generic/complex/cpowf.c new file mode 100644 index 0000000..1e736af --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cpowf.c @@ -0,0 +1,59 @@ +/* $NetBSD: cpowf.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cpowf(float complex a, float complex z) +{ + float complex w; + float x, y, r, theta, absa, arga; + + x = crealf(z); + y = cimagf(z); + absa = cabsf(a); + if (absa == 0.0f) { + return (0.0f + 0.0f * I); + } + arga = cargf(a); + r = powf(absa, x); + theta = x * arga; + if (y != 0.0f) { + r = r * expf(-y * arga); + theta = theta + y * logf(absa); + } + w = r * cosf(theta) + (r * sinf(theta)) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cproj.c b/user/include/mlibc/options/ansi/generic/complex/cproj.c new file mode 100644 index 0000000..e43e812 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cproj.c @@ -0,0 +1,105 @@ +/* $NetBSD: cproj.c,v 1.3 2010/09/20 17:51:38 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>--- Riemann sphere projection + +INDEX + cproj +INDEX + cprojf + +SYNOPSIS + #include + double complex cproj(double complex <[z]>); + float complex cprojf(float complex <[z]>); + + +DESCRIPTION + These functions compute a projection of <[z]> onto the Riemann + sphere: <[z]> projects to <[z]> except that all complex infinities + (even those with one infinite part and one NaN part) project + to positive infinity on the real axis. If <[z]> has an infinite part, + then <>(<[z]>) is equivalent to + + INFINITY + I * copysign(0.0, cimag(z)) + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cproj functions return the value of the projection onto + the Riemann sphere. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +/*__RCSID("$NetBSD: cproj.c,v 1.3 2010/09/20 17:51:38 christos Exp $"); */ + +#include +#include + +#include "fdlibm.h" + +/* + * cproj(double complex z) + * + * These functions return the value of the projection (not stereographic!) + * onto the Riemann sphere. + * + * z projects to z, except that all complex infinities (even those with one + * infinite part and one NaN part) project to positive infinity on the real axis. + * If z has an infinite part, then cproj(z) shall be equivalent to: + * + * INFINITY + I * copysign(0.0, cimag(z)) + */ +double complex +cproj(double complex z) +{ + double_complex w = { .z = z }; + + if (isinf(creal(z)) || isinf(cimag(z))) { +#ifdef __INFINITY + REAL_PART(w) = __INFINITY; +#else + REAL_PART(w) = INFINITY; +#endif + IMAG_PART(w) = copysign(0.0, cimag(z)); + } + + return (w.z); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/cprojf.c b/user/include/mlibc/options/ansi/generic/complex/cprojf.c new file mode 100644 index 0000000..76c3d8a --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/cprojf.c @@ -0,0 +1,67 @@ +/* $NetBSD: cprojf.c,v 1.3 2010/09/20 17:51:38 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/*__RCSID("$NetBSD: cprojf.c,v 1.3 2010/09/20 17:51:38 christos Exp $"); */ + +#include +#include + +#include "fdlibm.h" + +/* + * cprojf(float complex z) + * + * These functions return the value of the projection (not stereographic!) + * onto the Riemann sphere. + * + * z projects to z, except that all complex infinities (even those with one + * infinite part and one NaN part) project to positive infinity on the real axis. + * If z has an infinite part, then cproj(z) shall be equivalent to: + * + * INFINITY + I * copysign(0.0, cimag(z)) + */ + +float complex +cprojf(float complex z) +{ + float_complex w = { .z = z }; + + if (isinf(crealf(z)) || isinf(cimagf(z))) { +#ifdef __INFINITY + REAL_PART(w) = __INFINITY; +#else + REAL_PART(w) = INFINITY; +#endif + IMAG_PART(w) = copysignf(0.0, cimagf(z)); + } + + return (w.z); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/creal.c b/user/include/mlibc/options/ansi/generic/complex/creal.c new file mode 100644 index 0000000..7aea26e --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/creal.c @@ -0,0 +1,60 @@ +/* $NetBSD: creal.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>, <>---real part + +INDEX + creal +INDEX + crealf +INDEX + creall + +SYNOPSIS + #include + double creal(double complex <[z]>); + float crealf(float complex <[z]>); + double long creall(long double complex <[z]>); + + +DESCRIPTION + These functions compute the real part of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The creal* functions return the real part value. + +PORTABILITY + <>, <> and <> are ISO C99 + +QUICKREF + <>, <> and <> are ISO C99 + +*/ + + +#include + +#include "fdlibm.h" + +double +creal(double complex z) +{ + double_complex w = { .z = z }; + + return (REAL_PART(w)); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/crealf.c b/user/include/mlibc/options/ansi/generic/complex/crealf.c new file mode 100644 index 0000000..245986d --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/crealf.c @@ -0,0 +1,21 @@ +/* $NetBSD: crealf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float +crealf(float complex z) +{ + float_complex w = { .z = z }; + + return (REAL_PART(w)); +} diff --git a/user/include/mlibc/options/ansi/generic/complex/csin.c b/user/include/mlibc/options/ansi/generic/complex/csin.c new file mode 100644 index 0000000..24702ed --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/csin.c @@ -0,0 +1,81 @@ +/* $NetBSD: csin.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex sine + +INDEX + csin +INDEX + csinf + +SYNOPSIS + #include + double complex csin(double complex <[z]>); + float complex csinf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex sine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex sine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +csin(double complex z) +{ + double complex w; + double ch, sh; + + _cchsh(cimag(z), &ch, &sh); + w = sin(creal(z)) * ch + (cos(creal(z)) * sh) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/csinf.c b/user/include/mlibc/options/ansi/generic/complex/csinf.c new file mode 100644 index 0000000..68cefe4 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/csinf.c @@ -0,0 +1,48 @@ +/* $NetBSD: csinf.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +csinf(float complex z) +{ + float complex w; + float ch, sh; + + _cchshf(cimagf(z), &ch, &sh); + w = sinf(crealf(z)) * ch + (cosf(crealf(z)) * sh) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/csinh.c b/user/include/mlibc/options/ansi/generic/complex/csinh.c new file mode 100644 index 0000000..b3f24ee --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/csinh.c @@ -0,0 +1,80 @@ +/* $NetBSD: csinh.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic sine + +INDEX + csinh +INDEX + csinhf + +SYNOPSIS + #include + double complex csinh(double complex <[z]>); + float complex csinhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic sine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic sine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +csinh(double complex z) +{ + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = sinh(x) * cos(y) + (cosh(x) * sin(y)) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/csinhf.c b/user/include/mlibc/options/ansi/generic/complex/csinhf.c new file mode 100644 index 0000000..3cd6ba7 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/csinhf.c @@ -0,0 +1,48 @@ +/* $NetBSD: csinhf.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +csinhf(float complex z) +{ + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = sinhf(x) * cosf(y) + (coshf(x) * sinf(y)) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/csqrt.c b/user/include/mlibc/options/ansi/generic/complex/csqrt.c new file mode 100644 index 0000000..aecdcb4 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/csqrt.c @@ -0,0 +1,137 @@ +/* $NetBSD: csqrt.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex square root + +INDEX + csqrt +INDEX + csqrtf + +SYNOPSIS + #include + double complex csqrt(double complex <[z]>); + float complex csqrtf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex square root of <[z]>, with + a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The csqrt functions return the complex square root value, in + the range of the right halfplane (including the imaginary axis). + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +csqrt(double complex z) +{ + double complex w; + double x, y, r, t, scale; + + x = creal (z); + y = cimag (z); + + if (y == 0.0) { + if (x == 0.0) { + w = 0.0 + y * I; + } else { + r = fabs(x); + r = sqrt(r); + if (x < 0.0) { + w = 0.0 + r * I; + } else { + w = r + y * I; + } + } + return w; + } + if (x == 0.0) { + r = fabs(y); + r = sqrt(0.5 * r); + if (y > 0) + w = r + r * I; + else + w = r - r * I; + return w; + } + /* Rescale to avoid internal overflow or underflow. */ + if ((fabs(x) > 4.0) || (fabs(y) > 4.0)) { + x *= 0.25; + y *= 0.25; + scale = 2.0; + } else { +#if 1 + x *= 1.8014398509481984e16; /* 2^54 */ + y *= 1.8014398509481984e16; + scale = 7.450580596923828125e-9; /* 2^-27 */ +#else + x *= 4.0; + y *= 4.0; + scale = 0.5; +#endif + } + w = x + y * I; + r = cabs(w); + if (x > 0) { + t = sqrt(0.5 * r + 0.5 * x); + r = scale * fabs((0.5 * y) / t ); + t *= scale; + } else { + r = sqrt(0.5 * r - 0.5 * x); + t = scale * fabs((0.5 * y) / r); + r *= scale; + } + if (y < 0) + w = t - r * I; + else + w = t + r * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/csqrtf.c b/user/include/mlibc/options/ansi/generic/complex/csqrtf.c new file mode 100644 index 0000000..13451fa --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/csqrtf.c @@ -0,0 +1,102 @@ +/* $NetBSD: csqrtf.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +csqrtf(float complex z) +{ + float complex w; + float x, y, r, t, scale; + + x = crealf (z); + y = cimagf (z); + + if (y == 0.0f) { + if (x < 0.0f) { + w = 0.0f + sqrtf(-x) * I; + return w; + } else if (x == 0.0f) { + return (0.0f + y * I); + } else { + w = sqrtf(x) + y * I; + return w; + } + } + + if (x == 0.0f) { + r = fabsf(y); + r = sqrtf(0.5f * r); + if (y > 0) + w = r + r * I; + else + w = r - r * I; + return w; + } + + /* Rescale to avoid internal overflow or underflow. */ + if ((fabsf(x) > 4.0f) || (fabsf(y) > 4.0f)) { + x *= 0.25f; + y *= 0.25f; + scale = 2.0f; + } else { +#if 1 + x *= 6.7108864e7f; /* 2^26 */ + y *= 6.7108864e7f; + scale = 1.220703125e-4f; /* 2^-13 */ +#else + x *= 4.0f; + y *= 4.0f; + scale = 0.5f; +#endif + } + w = x + y * I; + r = cabsf(w); + if( x > 0 ) { + t = sqrtf(0.5f * r + 0.5f * x); + r = scale * fabsf((0.5f * y) / t); + t *= scale; + } else { + r = sqrtf(0.5f * r - 0.5f * x); + t = scale * fabsf((0.5f * y) / r); + r *= scale; + } + + if (y < 0) + w = t - r * I; + else + w = t + r * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/ctan.c b/user/include/mlibc/options/ansi/generic/complex/ctan.c new file mode 100644 index 0000000..0d6074b --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/ctan.c @@ -0,0 +1,91 @@ +/* $NetBSD: ctan.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex tangent + +INDEX + ctan +INDEX + ctanf + +SYNOPSIS + #include + double complex ctan(double complex <[z]>); + float complex ctanf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex tangent of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex tangent value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +ctan(double complex z) +{ + double complex w; + double d; + + d = cos(2.0 * creal(z)) + cosh(2.0 * cimag(z)); + + if (fabs(d) < 0.25) + d = _ctans(z); + + if (d == 0.0) { + /* mtherr ("ctan", OVERFLOW); */ + w = HUGE_VAL + HUGE_VAL * I; + return w; + } + + w = sin(2.0 * creal(z)) / d + (sinh(2.0 * cimag(z)) / d) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/ctanf.c b/user/include/mlibc/options/ansi/generic/complex/ctanf.c new file mode 100644 index 0000000..a75ff1c --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/ctanf.c @@ -0,0 +1,58 @@ +/* $NetBSD: ctanf.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +ctanf(float complex z) +{ + float complex w; + float d; + + d = cosf(2.0f * crealf(z)) + coshf(2.0f * cimagf(z)); + + if (fabsf(d) < 0.25f) + d = _ctansf(z); + + if (d == 0.0f) { + /* mtherr ("ctan", OVERFLOW); */ + w = HUGE_VALF + HUGE_VALF * I; + return w; + } + + w = sinf(2.0f * crealf(z)) / d + (sinhf(2.0f * cimagf(z)) / d) * I; + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/ctanh.c b/user/include/mlibc/options/ansi/generic/complex/ctanh.c new file mode 100644 index 0000000..a86e971 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/ctanh.c @@ -0,0 +1,83 @@ +/* $NetBSD: ctanh.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic tangent + +INDEX + ctanh +INDEX + ctanhf + +SYNOPSIS + #include + double complex ctanh(double complex <[z]>); + float complex ctanhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic tangent of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic tangent value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +ctanh(double complex z) +{ + double complex w; + double x, y, d; + + x = creal(z); + y = cimag(z); + d = cosh(2.0 * x) + cos(2.0 * y); + w = sinh(2.0 * x) / d + (sin(2.0 * y) / d) * I; + + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/ctanhf.c b/user/include/mlibc/options/ansi/generic/complex/ctanhf.c new file mode 100644 index 0000000..6aaf20f --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/ctanhf.c @@ -0,0 +1,50 @@ +/* $NetBSD: ctanhf.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +ctanhf(float complex z) +{ + float complex w; + float x, y, d; + + x = crealf(z); + y = cimagf(z); + d = coshf(2.0f * x) + cosf(2.0f * y); + w = sinhf(2.0f * x) / d + (sinf(2.0f * y) / d) * I; + + return w; +} diff --git a/user/include/mlibc/options/ansi/generic/complex/fdlibm.h b/user/include/mlibc/options/ansi/generic/complex/fdlibm.h new file mode 100644 index 0000000..75cdd2a --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/complex/fdlibm.h @@ -0,0 +1,17 @@ +#ifndef __MLIBC_FDLIBM_H +#define __MLIBC_FDLIBM_H + +#define REAL_PART(z) ((z).parts[0]) +#define IMAG_PART(z) ((z).parts[1]) + +typedef union { + float complex z; + float parts[2]; +} float_complex; + +typedef union { + double complex z; + double parts[2]; +} double_complex; + +#endif diff --git a/user/include/mlibc/options/ansi/generic/ctype.cpp b/user/include/mlibc/options/ansi/generic/ctype.cpp new file mode 100644 index 0000000..d5a2321 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/ctype.cpp @@ -0,0 +1,326 @@ + +#include +#include + +#include +#include + +// -------------------------------------------------------------------------------------- +// char ctype functions. +// -------------------------------------------------------------------------------------- + +int isalpha(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alpha(cp); +} + +int isdigit(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_digit(cp); +} + +int isxdigit(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_xdigit(cp); +} + +int isalnum(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alnum(cp); +} + +int ispunct(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_punct(cp); +} + +int isgraph(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_graph(cp); +} + +int isblank(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_blank(cp); +} + +int isspace(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_space(cp); +} + +int isprint(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_print(cp); +} + +int islower(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_lower(cp); +} + +int isupper(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_upper(cp); +} + +int iscntrl(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::generic_is_control(cp); +} + +int isascii(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return cp <= 0x7F; +} + +// -------------------------------------------------------------------------------------- +// wchar_t ctype functions. +// -------------------------------------------------------------------------------------- + +int iswalpha(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alpha(cp); +} + +int iswdigit(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_digit(cp); +} + +int iswxdigit(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_xdigit(cp); +} + +int iswalnum(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alnum(cp); +} + +int iswpunct(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_punct(cp); +} + +int iswgraph(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_graph(cp); +} + +int iswblank(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_blank(cp); +} + +int iswspace(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_space(cp); +} + +int iswprint(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_print(cp); +} + +int iswlower(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_lower(cp); +} + +int iswupper(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_upper(cp); +} + +int iswcntrl(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::generic_is_control(cp); +} + +// -------------------------------------------------------------------------------------- +// iswctype functions. +// -------------------------------------------------------------------------------------- + +namespace { + enum { + ct_null, + ct_alnum, + ct_alpha, + ct_blank, + ct_cntrl, + ct_digit, + ct_graph, + ct_lower, + ct_print, + ct_punct, + ct_space, + ct_upper, + ct_xdigit, + ct_count + }; +} // namespace + +wctype_t wctype(const char *cs) { + frg::string_view s{cs}; + if(s == "alnum") return ct_alnum; + if(s == "alpha") return ct_alpha; + if(s == "blank") return ct_blank; + if(s == "cntrl") return ct_cntrl; + if(s == "digit") return ct_digit; + if(s == "graph") return ct_graph; + if(s == "lower") return ct_lower; + if(s == "print") return ct_print; + if(s == "punct") return ct_punct; + if(s == "space") return ct_space; + if(s == "upper") return ct_upper; + if(s == "xdigit") return ct_xdigit; + mlibc::infoLogger() << "mlibc: wctype(\"" << cs << "\") is not supported" << frg::endlog; + return ct_null; +} + +int iswctype(wint_t wc, wctype_t type) { + switch (type) { + case ct_alnum: + return iswalnum(wc); + case ct_alpha: + return iswalpha(wc); + case ct_blank: + return iswblank(wc); + case ct_cntrl: + return iswcntrl(wc); + case ct_digit: + return iswdigit(wc); + case ct_graph: + return iswgraph(wc); + case ct_lower: + return iswlower(wc); + case ct_print: + return iswprint(wc); + case ct_punct: + return iswpunct(wc); + case ct_space: + return iswspace(wc); + case ct_upper: + return iswupper(wc); + case ct_xdigit: + return iswxdigit(wc); + } + return 0; +} + +// -------------------------------------------------------------------------------------- +// char conversion functions. +// -------------------------------------------------------------------------------------- + +int tolower(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return nc; + return mlibc::current_charset()->to_lower(cp); +} + +int toupper(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return nc; + return mlibc::current_charset()->to_upper(cp); +} + +// -------------------------------------------------------------------------------------- +// wchar_t conversion functions. +// -------------------------------------------------------------------------------------- + +wint_t towlower(wint_t wc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(wc, cp); e != mlibc::charcode_error::null) + return wc; + return mlibc::current_charset()->to_lower(cp); +} + +wint_t towupper(wint_t wc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(wc, cp); e != mlibc::charcode_error::null) + return wc; + return mlibc::current_charset()->to_upper(cp); +} + diff --git a/user/include/mlibc/options/ansi/generic/environment.cpp b/user/include/mlibc/options/ansi/generic/environment.cpp new file mode 100644 index 0000000..c9f2893 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/environment.cpp @@ -0,0 +1,168 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace { + char *empty_environment[] = { nullptr }; +} // namespace + +char **environ = empty_environment; + +namespace { + +size_t find_environ_index(frg::string_view name) { + for(size_t i = 0; environ[i]; i++) { + frg::string_view view{environ[i]}; + size_t s = view.find_first('='); + if(s == size_t(-1)) { + mlibc::infoLogger() << "mlibc: environment string \"" + << frg::escape_fmt{view.data(), view.size()} + << "\" does not contain an equals sign (=)" << frg::endlog; + continue; + } + if(view.sub_string(0, s) == name) + return i; + } + + return -1; +} + +// Environment vector that is mutated by putenv() and setenv(). +// Cannot be global as it is accessed during library initialization. +frg::vector &get_vector() { + static frg::vector vector{getAllocator()}; + return vector; +} + +void update_vector() { + auto &vector = get_vector(); + if(environ == vector.data()) + return; + + // If the environ variable was changed, we copy the environment. + // Note that we must only copy the pointers but not the strings themselves! + vector.clear(); + for(size_t i = 0; environ[i]; i++) + vector.push(environ[i]); + vector.push(nullptr); + + environ = vector.data(); +} + +void assign_variable(frg::string_view name, const char *string, bool overwrite) { + auto &vector = get_vector(); + __ensure(environ == vector.data()); + + auto k = find_environ_index(name); + if(k != size_t(-1)) { + if(overwrite) + vector[k] = const_cast(string); + }else{ + // Last pointer of environ must always be a null delimiter. + __ensure(!vector.back()); + vector.back() = const_cast(string); + vector.push(nullptr); + } + + // push() might have re-allocated the vector. + environ = vector.data(); +} + +void unassign_variable(frg::string_view name) { + auto &vector = get_vector(); + __ensure(environ == vector.data()); + + auto k = find_environ_index(name); + if(k == size_t(-1)) + return; + + // Last pointer of environ must always be a null delimiter. + __ensure(vector.size() >= 2 && !vector.back()); + std::swap(vector[k], vector[vector.size() - 2]); + vector.pop(); + vector.back() = nullptr; + + // pop() might have re-allocated the vector. + environ = vector.data(); +} + +} // anonymous namespace + +char *getenv(const char *name) { + auto k = find_environ_index(name); + if(k == size_t(-1)) + return nullptr; + + frg::string_view view{environ[k]}; + size_t s = view.find_first('='); + __ensure(s != size_t(-1)); + return const_cast(view.data() + s + 1); +} + +namespace mlibc { + +int putenv(char *string) { + frg::string_view view{string}; + size_t s = view.find_first('='); + if(s == size_t(-1)) { + // GLIBC EXTENSION + update_vector(); + unassign_variable(string); + return 0; + } + + update_vector(); + assign_variable(view.sub_string(0, s), string, true); + return 0; +} + +} // namespace mlibc + +#if __MLIBC_POSIX_OPTION + +int putenv(char *string) { + return mlibc::putenv(string); +} + +int setenv(const char *name, const char *value, int overwrite) { + frg::string_view view{name}; + size_t s = view.find_first('='); + if(s != size_t(-1)) { + mlibc::infoLogger() << "mlibc: environment variable \"" + << frg::escape_fmt{view.data(), view.size()} << "\" contains an equals sign" + << frg::endlog; + errno = EINVAL; + return -1; + } + + // We never free strings here. TODO: Reuse them? + char *string; + __ensure(asprintf(&string, "%s=%s", name, value) > 0); + __ensure(string); + + update_vector(); + assign_variable(name, string, overwrite); + return 0; +} + +int unsetenv(const char *name) { + update_vector(); + unassign_variable(name); + return 0; +} + +int clearenv(void) { + auto vector = get_vector(); + vector.clear(); + update_vector(); + return 0; +} + +#endif /* __MLIBC_POSIX_OPTION */ diff --git a/user/include/mlibc/options/ansi/generic/errno.cpp b/user/include/mlibc/options/ansi/generic/errno.cpp new file mode 100644 index 0000000..8229a9a --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/errno.cpp @@ -0,0 +1,12 @@ +#include + +int __thread __mlibc_errno; + +char *program_invocation_name = nullptr; +char *program_invocation_short_name = nullptr; +extern char *__progname __attribute__((__weak__, __alias__("program_invocation_short_name"))); +extern char *__progname_full __attribute__((__weak__, __alias__("program_invocation_name"))); + +int *__errno_location() { + return &__mlibc_errno; +} diff --git a/user/include/mlibc/options/ansi/generic/fenv.cpp b/user/include/mlibc/options/ansi/generic/fenv.cpp new file mode 100644 index 0000000..7153844 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/fenv.cpp @@ -0,0 +1,43 @@ + +#include +#include + +// The functions that are not in this file but are defined in the header +// are implemented like musl does in assembly. +extern "C" __attribute__((__visibility__("hidden"))) int __fesetround(int); + +int fegetexceptflag(fexcept_t *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int feholdexcept(fenv_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int fesetexceptflag(const fexcept_t *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int fesetround(int r) { + if (r != FE_TONEAREST +#ifdef FE_DOWNWARD + && r != FE_DOWNWARD +#endif +#ifdef FE_UPWARD + && r != FE_UPWARD +#endif +#ifdef FE_TOWARDZERO + && r != FE_TOWARDZERO +#endif + ) + return -1; + return __fesetround(r); +} + +int feupdateenv(const fenv_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/ansi/generic/file-io.cpp b/user/include/mlibc/options/ansi/generic/file-io.cpp new file mode 100644 index 0000000..c6c6043 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/file-io.cpp @@ -0,0 +1,750 @@ + +#include +#include +#include +#include +#include +#if __MLIBC_GLIBC_OPTION +#include +#endif + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +// -------------------------------------------------------------------------------------- +// abstract_file implementation. +// -------------------------------------------------------------------------------------- + +namespace { + using file_list = frg::intrusive_list< + abstract_file, + frg::locate_member< + abstract_file, + frg::default_list_hook, + &abstract_file::_list_hook + > + >; + + // Useful when debugging the FILE implementation. + constexpr bool globallyDisableBuffering = false; + + // The maximum number of characters we permit the user to ungetc. + constexpr size_t ungetBufferSize = 8; + + // List of files that will be flushed before exit(). + file_list &global_file_list() { + static frg::eternal list; + return list.get(); + }; +} // namespace + +// For pipe-like streams (seek returns ESPIPE), we need to make sure +// that the buffer only ever contains all-dirty or all-clean data. +// Regarding _type and _bufmode: +// As we might construct FILE objects for FDs that are not actually +// open (e.g. for std{in,out,err}), we defer the type determination and cache the result. + +abstract_file::abstract_file(void (*do_dispose)(abstract_file *)) +: _type{stream_type::unknown}, _bufmode{buffer_mode::unknown}, _do_dispose{do_dispose} { + // TODO: For __fwriting to work correctly, set the __io_mode to 1 if the write is write-only. + __buffer_ptr = nullptr; + __unget_ptr = nullptr; + __buffer_size = 4096; + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + __dirty_begin = 0; + __dirty_end = 0; + __io_mode = 0; + __status_bits = 0; + + global_file_list().push_back(this); +} + +abstract_file::~abstract_file() { + if(__dirty_begin != __dirty_end) + mlibc::infoLogger() << "mlibc warning: File is not flushed before destruction" + << frg::endlog; + + if(__buffer_ptr) + getAllocator().free(__buffer_ptr - ungetBufferSize); + + auto it = global_file_list().iterator_to(this); + global_file_list().erase(it); +} + +void abstract_file::dispose() { + if(!_do_dispose) + return; + _do_dispose(this); +} + +// Note that read() and write() are asymmetric: +// While read() can trigger a write-back, write() can never trigger a read-ahead(). +// This peculiarity is reflected in their code. + +int abstract_file::read(char *buffer, size_t max_size, size_t *actual_size) { + __ensure(max_size); + + if(_init_bufmode()) + return -1; + + size_t unget_length = 0; + if (__unget_ptr != __buffer_ptr) { + unget_length = frg::min(max_size, (size_t)(__buffer_ptr - __unget_ptr)); + memcpy(buffer, __unget_ptr, unget_length); + + __unget_ptr += unget_length; + buffer += unget_length; + max_size -= unget_length; + + if (max_size == 0) { + *actual_size = unget_length; + return 0; + } + } + + if(globallyDisableBuffering || _bufmode == buffer_mode::no_buffer) { + size_t io_size; + if(int e = io_read(buffer, max_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + if(!io_size) + __status_bits |= __MLIBC_EOF_BIT; + *actual_size = io_size + unget_length; + return 0; + } + + // Ensure correct buffer type for pipe-like streams. + // TODO: In order to support pipe-like streams we need to write-back the buffer. + if(__io_mode && __valid_limit) + mlibc::panicLogger() << "mlibc: Cannot read-write to same pipe-like stream" + << frg::endlog; + __io_mode = 0; + + // Clear the buffer, then buffer new data. + if(__offset == __valid_limit) { + // TODO: We only have to write-back/reset if __valid_limit reaches the buffer end. + if(int e = _write_back(); e) + return e; + if(int e = _reset(); e) + return e; + + // Perform a read-ahead. + _ensure_allocation(); + size_t io_size; + if(int e = io_read(__buffer_ptr, __buffer_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + if(!io_size) { + __status_bits |= __MLIBC_EOF_BIT; + *actual_size = 0; + return 0; + } + + __io_offset = io_size; + __valid_limit = io_size; + } + + // Return data from the buffer. + __ensure(__offset < __valid_limit); + + auto chunk = frg::min(size_t(__valid_limit - __offset), max_size); + memcpy(buffer, __buffer_ptr + __offset, chunk); + __offset += chunk; + + *actual_size = chunk + unget_length; + return 0; +} + +int abstract_file::write(const char *buffer, size_t max_size, size_t *actual_size) { + __ensure(max_size); + + if(_init_bufmode()) + return -1; + if(globallyDisableBuffering || _bufmode == buffer_mode::no_buffer) { + // As we do not buffer, nothing can be dirty. + __ensure(__dirty_begin == __dirty_end); + size_t io_size; + if(int e = io_write(buffer, max_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + *actual_size = io_size; + return 0; + } + + // Flush the buffer if necessary. + if(__offset == __buffer_size) { + if(int e = _write_back(); e) + return e; + if(int e = _reset(); e) + return e; + } + + // Ensure correct buffer type for pipe-like streams. + // TODO: We could full support pipe-like files + // by ungetc()ing all data before a write happens, + // however, for now we just report an error. + if(!__io_mode && __valid_limit) // TODO: Only check this for pipe-like streams. + mlibc::panicLogger() << "mlibc: Cannot read-write to same pipe-like stream" + << frg::endlog; + __io_mode = 1; + + __ensure(__offset < __buffer_size); + auto chunk = frg::min(__buffer_size - __offset, max_size); + + // Line-buffered streams perform I/O on full lines. + bool flush_line = false; + if(_bufmode == buffer_mode::line_buffer) { + auto nl = reinterpret_cast(memchr(buffer, '\n', chunk)); + if(nl) { + chunk = nl + 1 - buffer; + flush_line = true; + } + } + __ensure(chunk); + + // Buffer data (without necessarily performing I/O). + _ensure_allocation(); + memcpy(__buffer_ptr + __offset, buffer, chunk); + + if(__dirty_begin != __dirty_end) { + __dirty_begin = frg::min(__dirty_begin, __offset); + __dirty_end = frg::max(__dirty_end, __offset + chunk); + }else{ + __dirty_begin = __offset; + __dirty_end = __offset + chunk; + } + __valid_limit = frg::max(__offset + chunk, __valid_limit); + __offset += chunk; + + // Flush line-buffered streams. + if(flush_line) { + if(_write_back()) + return -1; + } + + *actual_size = chunk; + return 0; +} + +int abstract_file::unget(char c) { + if (!__unget_ptr) { + // This can happen if the file is unbuffered, but we still need + // a space to store ungetc'd data. + __ensure(!__buffer_ptr); + _ensure_allocation(); + __ensure(__unget_ptr); + } + + if ((size_t)(__buffer_ptr - __unget_ptr) + 1 > ungetBufferSize) + return EOF; + else { + *(--__unget_ptr) = c; + return c; + } +} + +int abstract_file::update_bufmode(buffer_mode mode) { + // setvbuf() has undefined behavior if I/O has been performed. + __ensure(__dirty_begin == __dirty_end + && "update_bufmode() must only be called before performing I/O"); + _bufmode = mode; + return 0; +} + +void abstract_file::purge() { + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + __dirty_end = __dirty_begin; + __unget_ptr = __buffer_ptr; +} + +int abstract_file::flush() { + if (__dirty_end != __dirty_begin) { + if (int e = _write_back(); e) + return e; + } + + if (int e = _save_pos(); e) + return e; + purge(); + return 0; +} + +int abstract_file::tell(off_t *current_offset) { + off_t seek_offset; + if(int e = io_seek(0, SEEK_CUR, &seek_offset); e) + return e; + + *current_offset = seek_offset + + (off_t(__offset) - off_t(__io_offset)) + + (off_t(__unget_ptr) - off_t(__buffer_ptr)); + return 0; +} + +int abstract_file::seek(off_t offset, int whence) { + if(int e = _write_back(); e) + return e; + + off_t new_offset; + if(whence == SEEK_CUR) { + auto seek_offset = offset + (off_t(__offset) - off_t(__io_offset)); + if(int e = io_seek(seek_offset, whence, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + }else{ + __ensure(whence == SEEK_SET || whence == SEEK_END); + if(int e = io_seek(offset, whence, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + } + + // We just forget the current buffer. + // TODO: If the seek is "small", we can just modify our internal offset. + purge(); + + return 0; +} + +int abstract_file::_init_type() { + if(_type != stream_type::unknown) + return 0; + + if(int e = determine_type(&_type); e) + return e; + __ensure(_type != stream_type::unknown); + return 0; +} + +int abstract_file::_init_bufmode() { + if(_bufmode != buffer_mode::unknown) + return 0; + + if(determine_bufmode(&_bufmode)) + return -1; + __ensure(_bufmode != buffer_mode::unknown); + return 0; +} + +int abstract_file::_write_back() { + if(int e = _init_type(); e) + return e; + + if(__dirty_begin == __dirty_end) + return 0; + + // For non-pipe streams, first do a seek to reset the + // I/O position to zero, then do a write(). + if(_type == stream_type::file_like) { + if(__io_offset != __dirty_begin) { + __ensure(__dirty_begin - __io_offset > 0); + off_t new_offset; + if(int e = io_seek(off_t(__dirty_begin) - off_t(__io_offset), SEEK_CUR, &new_offset); e) + return e; + __io_offset = __dirty_begin; + } + }else{ + __ensure(_type == stream_type::pipe_like); + __ensure(__io_offset == __dirty_begin); + } + + // Now, we are in the correct position to write-back everything. + while(__io_offset < __dirty_end) { + size_t io_size; + if(int e = io_write(__buffer_ptr + __io_offset, __dirty_end - __io_offset, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + __ensure(io_size > 0 && "io_write() is expected to always write at least one byte"); + __io_offset += io_size; + __dirty_begin += io_size; + } + + return 0; +} + +int abstract_file::_save_pos() { + if (int e = _init_type(); e) + return e; + if (int e = _init_bufmode(); e) + return e; + + if (_type == stream_type::file_like && _bufmode != buffer_mode::no_buffer) { + off_t new_offset; + auto seek_offset = (off_t(__offset) - off_t(__io_offset)); + if (int e = io_seek(seek_offset, SEEK_CUR, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + mlibc::infoLogger() << "hit io_seek() error " << e << frg::endlog; + return e; + } + return 0; + } + return 0; // nothing to do for the rest +} + +int abstract_file::_reset() { + if(int e = _init_type(); e) + return e; + + // For pipe-like files, we must not forget already read data. + // TODO: Report this error to the user. + if(_type == stream_type::pipe_like) + __ensure(__offset == __valid_limit); + + __ensure(__dirty_begin == __dirty_end); + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + + return 0; +} + +// This may still be called when buffering is disabled, for ungetc. +void abstract_file::_ensure_allocation() { + if(__buffer_ptr) + return; + + auto ptr = getAllocator().allocate(__buffer_size + ungetBufferSize); + __buffer_ptr = reinterpret_cast(ptr) + ungetBufferSize; + __unget_ptr = __buffer_ptr; +} + +// -------------------------------------------------------------------------------------- +// fd_file implementation. +// -------------------------------------------------------------------------------------- + +fd_file::fd_file(int fd, void (*do_dispose)(abstract_file *), bool force_unbuffered) +: abstract_file{do_dispose}, _fd{fd}, _force_unbuffered{force_unbuffered} { } + +int fd_file::fd() { + return _fd; +} + +int fd_file::close() { + if(__dirty_begin != __dirty_end) + mlibc::infoLogger() << "mlibc warning: File is not flushed before closing" + << frg::endlog; + if(int e = mlibc::sys_close(_fd); e) + return e; + return 0; +} + +int fd_file::reopen(const char *path, const char *mode) { + int mode_flags = parse_modestring(mode); + + int fd; + if(int e = sys_open(path, mode_flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, &fd); e) { + return e; + } + + flush(); + close(); + getAllocator().deallocate(__buffer_ptr, __buffer_size + ungetBufferSize); + + __buffer_ptr = nullptr; + __unget_ptr = nullptr; + __buffer_size = 4096; + _reset(); + _fd = fd; + + if(mode_flags & O_APPEND) { + seek(0, SEEK_END); + } + + return 0; +} + +int fd_file::determine_type(stream_type *type) { + off_t offset; + int e = mlibc::sys_seek(_fd, 0, SEEK_CUR, &offset); + if(!e) { + *type = stream_type::file_like; + return 0; + }else if(e == ESPIPE) { + *type = stream_type::pipe_like; + return 0; + }else{ + return e; + } +} + +int fd_file::determine_bufmode(buffer_mode *mode) { + // When isatty() is not implemented, we fall back to the safest default (no buffering). + if(!mlibc::sys_isatty) { + MLIBC_MISSING_SYSDEP(); + *mode = buffer_mode::no_buffer; + return 0; + } + if(_force_unbuffered) { + *mode = buffer_mode::no_buffer; + return 0; + } + + if(int e = mlibc::sys_isatty(_fd); !e) { + *mode = buffer_mode::line_buffer; + return 0; + }else if(e == ENOTTY) { + *mode = buffer_mode::full_buffer; + return 0; + }else{ + mlibc::infoLogger() << "mlibc: sys_isatty() failed while determining whether" + " stream is interactive" << frg::endlog; + return -1; + } +} + +int fd_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + ssize_t s; + if(int e = mlibc::sys_read(_fd, buffer, max_size, &s); e) + return e; + *actual_size = s; + return 0; +} + +int fd_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + ssize_t s; + if(int e = mlibc::sys_write(_fd, buffer, max_size, &s); e) + return e; + *actual_size = s; + return 0; +} + +int fd_file::io_seek(off_t offset, int whence, off_t *new_offset) { + if(int e = mlibc::sys_seek(_fd, offset, whence, new_offset); e) + return e; + return 0; +} + +int fd_file::parse_modestring(const char *mode) { + // Consume the first char; this must be 'r', 'w' or 'a'. + int flags = 0; + bool has_plus = strchr(mode, '+'); + if (*mode == 'r') { + if (has_plus) { + flags = O_RDWR; + } else { + flags = O_RDONLY; + } + } else if (*mode == 'w') { + if (has_plus) { + flags = O_RDWR; + } else { + flags = O_WRONLY; + } + flags |= O_CREAT | O_TRUNC; + } else if (*mode == 'a') { + if (has_plus) { + flags = O_APPEND | O_RDWR; + } else { + flags = O_APPEND | O_WRONLY; + } + flags |= O_CREAT; + } else { + mlibc::infoLogger() << "Illegal fopen() mode '" << *mode << "'" << frg::endlog; + } + mode += 1; + + // Consume additional flags. + while (*mode) { + if (*mode == '+') { + mode++; // This is already handled above. + } else if (*mode == 'b') { + mode++; // mlibc assumes that there is no distinction between text and binary. + } else if (*mode == 'e') { + flags |= O_CLOEXEC; + mode++; + } else if (*mode == 'x') { + flags |= O_EXCL; + mode++; + } else { + mlibc::infoLogger() << "Illegal fopen() flag '" << mode << "'" << frg::endlog; + mode++; + } + } + + return flags; +} + +} // namespace mlibc + +namespace { + mlibc::fd_file stdin_file{0}; + mlibc::fd_file stdout_file{1}; + mlibc::fd_file stderr_file{2, nullptr, true}; + + struct stdio_guard { + stdio_guard() { } + + ~stdio_guard() { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file before exit()" + << frg::endlog; + } + } + } global_stdio_guard; +} // namespace + +FILE *stderr = &stderr_file; +FILE *stdin = &stdin_file; +FILE *stdout = &stdout_file; + +int fileno_unlocked(FILE *file_base) { + auto file = static_cast(file_base); + return file->fd(); +} + +int fileno(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fileno_unlocked(file_base); +} + +FILE *fopen(const char *path, const char *mode) { + int flags = mlibc::fd_file::parse_modestring(mode); + + int fd; + if(int e = mlibc::sys_open(path, flags, 0666, &fd); e) { + errno = e; + return nullptr; + } + + return frg::construct(getAllocator(), fd, + mlibc::file_dispose_cb); +} + +int fclose(FILE *file_base) { + auto file = static_cast(file_base); + int e = 0; + if(file->flush()) + e = EOF; + if(file->close()) + e = EOF; + file->dispose(); + return e; +} + +int fseek(FILE *file_base, long offset, int whence) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + if(int e = file->seek(offset, whence); e) { + errno = e; + return -1; + } + return 0; +} + +long ftell(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + off_t current_offset; + if(int e = file->tell(¤t_offset); e) { + errno = e; + return -1; + } + return current_offset; +} + +int fflush_unlocked(FILE *file_base) { + if(file_base == nullptr) { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file" + << frg::endlog; + } + return 0; + } + auto file = static_cast(file_base); + if(file->flush()) + return EOF; + return 0; +} +int fflush(FILE *file_base) { + if(file_base == nullptr) { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + frg::unique_lock lock(it->_lock); + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file" + << frg::endlog; + } + return 0; + } + + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + if (file->flush()) + return EOF; + return 0; +} + +int setvbuf(FILE *file_base, char *, int mode, size_t) { + // TODO: We could also honor the buffer, but for now use just set the mode. + auto file = static_cast(file_base); + if(mode == _IONBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::no_buffer); e) { + errno = e; + return -1; + } + }else if(mode == _IOLBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::line_buffer); e) { + errno = e; + return -1; + } + }else if(mode == _IOFBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::full_buffer); e) { + errno = e; + return -1; + } + }else{ + errno = EINVAL; + return -1; + } + + return 0; +} + +void rewind(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + file->seek(0, SEEK_SET); + file_base->__status_bits &= ~(__MLIBC_EOF_BIT | __MLIBC_ERROR_BIT); +} + +int ungetc(int c, FILE *file_base) { + if (c == EOF) + return EOF; + + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return file->unget(c); +} + +#if __MLIBC_GLIBC_OPTION +void __fpurge(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + file->purge(); +} +#endif + diff --git a/user/include/mlibc/options/ansi/generic/inttypes.cpp b/user/include/mlibc/options/ansi/generic/inttypes.cpp new file mode 100644 index 0000000..5cfa562 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/inttypes.cpp @@ -0,0 +1,100 @@ + +#include +#include +#include + +#include +#include + +static const char *__mlibc_digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + +intmax_t imaxabs(intmax_t num) { + return num < 0 ? -num : num; +} +imaxdiv_t imaxdiv(intmax_t number, intmax_t denom) { + imaxdiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +template T strtoxmax(const char *it, char **out, int base) { + T v = 0; + bool negate = false; + const unsigned char *s = (const unsigned char *)it; + int c; + + if(std::is_signed_v) { + if(*s == '+') { + s++; + }else if(*s == '-') { + negate = true; + s++; + } + } + + do { + c = *s++; + } while (isspace(c)); + if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + if(base == 8) { + if(*it != 0) + goto parse_digits; + it++; + }else if(base == 16) { + if(*it != 0) + goto parse_digits; + it++; + if(*it != 'x' && *it != 'X') + goto parse_digits; + it++; + } + +parse_digits: + while(*it) { + if(isspace(*it)) { + it++; + continue; + } + + __ensure(base <= 10); // TODO: For base > 10 we need to implement tolower(). + //auto c = strchr(__mlibc_digits, tolower(*it)); + auto c = strchr(__mlibc_digits, *it); + if(!c || (c - __mlibc_digits) >= base) + break; + v = v * base + (c - __mlibc_digits); + it++; + } + + if(std::is_signed_v) { + if(negate) + v = -v; + } + + if(out) + *out = const_cast(it); + return v; +} + +intmax_t strtoimax(const char *it, char **out, int base) { + // TODO: This function has to check for overflow! + return strtoxmax(it, out, base); +} +uintmax_t strtoumax(const char *it, char **out, int base) { + return strtoxmax(it, out, base); +} +intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/ansi/generic/locale.cpp b/user/include/mlibc/options/ansi/generic/locale.cpp new file mode 100644 index 0000000..1bedbd6 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/locale.cpp @@ -0,0 +1,196 @@ + +#include +#include +#include + +#include + +#include +#include + +namespace { + // Values of the C locale are defined by the C standard. + constexpr lconv c_lconv = { + const_cast("."), // decimal_point + const_cast(""), // thousands_sep + const_cast(""), // grouping + const_cast(""), // mon_decimal_point + const_cast(""), // mon_thousands_sep + const_cast(""), // mon_grouping + const_cast(""), // positive_sign + const_cast(""), // negative_sign + const_cast(""), // currency_symbol + CHAR_MAX, // frac_digits + CHAR_MAX, // p_cs_precedes + CHAR_MAX, // n_cs_precedes + CHAR_MAX, // p_sep_by_space + CHAR_MAX, // n_sep_by_space + CHAR_MAX, // p_sign_posn + CHAR_MAX, // n_sign_posn + const_cast(""), // int_curr_symbol + CHAR_MAX, // int_frac_digits + CHAR_MAX, // int_p_cs_precedes + CHAR_MAX, // int_n_cs_precedes + CHAR_MAX, // int_p_sep_by_space + CHAR_MAX, // int_n_sep_by_space + CHAR_MAX, // int_p_sign_posn + CHAR_MAX // int_n_sign_posn + }; +} // namespace + +namespace mlibc { + struct locale_description { + // Identifier of this locale. used in setlocale(). + const char *name; + lconv lc; + }; + + constinit const locale_description c_locale{ + .name = "C", + .lc = c_lconv + }; + + constinit const locale_description posix_locale{ + .name = "POSIX", + .lc = c_lconv + }; + + const locale_description *query_locale_description(const char *name) { + if(!strcmp(name, "C")) + return &c_locale; + if(!strcmp(name, "POSIX")) + return &posix_locale; + return nullptr; + } + + const locale_description *collate_facet; + const locale_description *ctype_facet; + const locale_description *monetary_facet; + const locale_description *numeric_facet; + const locale_description *time_facet; + const locale_description *messages_facet; +} // namespace mlibc + +[[gnu::constructor]] +static void init_locale() { + mlibc::collate_facet = &mlibc::c_locale; + mlibc::ctype_facet = &mlibc::c_locale; + mlibc::monetary_facet = &mlibc::c_locale; + mlibc::numeric_facet = &mlibc::c_locale; + mlibc::time_facet = &mlibc::c_locale; + mlibc::messages_facet = &mlibc::c_locale; +} + +char *setlocale(int category, const char *name) { + if(category == LC_ALL) { + // ´TODO: Implement correct return value when categories differ. + auto current_desc = mlibc::collate_facet; + __ensure(current_desc == mlibc::ctype_facet); + __ensure(current_desc == mlibc::monetary_facet); + __ensure(current_desc == mlibc::numeric_facet); + __ensure(current_desc == mlibc::time_facet); + __ensure(current_desc == mlibc::messages_facet); + + if(name) { + // Our default C locale is the C locale. + if(!strlen(name)) + name = "C"; + + auto new_desc = mlibc::query_locale_description(name); + if(!new_desc) { + mlibc::infoLogger() << "mlibc: Locale " << name + << " is not supported" << frg::endlog; + return nullptr; + } + + mlibc::collate_facet = new_desc; + mlibc::ctype_facet = new_desc; + mlibc::monetary_facet = new_desc; + mlibc::numeric_facet = new_desc; + mlibc::time_facet = new_desc; + mlibc::messages_facet = new_desc; + } + return const_cast(current_desc->name); + }else{ + const mlibc::locale_description **facet_ptr; + switch(category) { + case LC_COLLATE: + facet_ptr = &mlibc::collate_facet; + break; + case LC_CTYPE: + facet_ptr = &mlibc::ctype_facet; + break; + case LC_MONETARY: + facet_ptr = &mlibc::monetary_facet; + break; + case LC_NUMERIC: + facet_ptr = &mlibc::numeric_facet; + break; + case LC_TIME: + facet_ptr = &mlibc::time_facet; + break; + case LC_MESSAGES: + facet_ptr = &mlibc::messages_facet; + break; + default: + mlibc::infoLogger() << "mlibc: Unexpected value " << category + << " for category in setlocale()" << frg::endlog; + return nullptr; + } + + auto current_desc = *facet_ptr; + if(name) { + // Our default C locale is the C locale. + if(!strlen(name)) + name = "C"; + + auto new_desc = mlibc::query_locale_description(name); + if(!new_desc) { + mlibc::infoLogger() << "mlibc: Locale " << name + << " is not supported" << frg::endlog; + return nullptr; + } + + *facet_ptr = new_desc; + } + return const_cast(current_desc->name); + } +} + +namespace { + lconv effective_lc; +} // namespace + +struct lconv *localeconv(void) { + // Numeric locale. + const auto &numeric_lc = mlibc::numeric_facet->lc; + effective_lc.decimal_point = numeric_lc.decimal_point; + effective_lc.thousands_sep = numeric_lc.thousands_sep; + effective_lc.grouping = numeric_lc.grouping; + + // Monetary locale. + const auto &monetary_lc = mlibc::monetary_facet->lc; + effective_lc.mon_decimal_point = monetary_lc.mon_decimal_point; + effective_lc.mon_thousands_sep = monetary_lc.mon_thousands_sep; + effective_lc.mon_grouping = monetary_lc.mon_grouping; + effective_lc.positive_sign = monetary_lc.positive_sign; + effective_lc.negative_sign = monetary_lc.negative_sign; + effective_lc.currency_symbol = monetary_lc.currency_symbol; + effective_lc.frac_digits = monetary_lc.frac_digits; + effective_lc.p_cs_precedes = monetary_lc.p_cs_precedes; + effective_lc.n_cs_precedes = monetary_lc.n_cs_precedes; + effective_lc.p_sep_by_space = monetary_lc.p_sep_by_space; + effective_lc.n_sep_by_space = monetary_lc.n_sep_by_space; + effective_lc.p_sign_posn = monetary_lc.p_sign_posn; + effective_lc.n_sign_posn = monetary_lc.n_sign_posn; + effective_lc.int_curr_symbol = monetary_lc.int_curr_symbol; + effective_lc.int_frac_digits = monetary_lc.int_frac_digits; + effective_lc.int_p_cs_precedes = monetary_lc.int_p_cs_precedes; + effective_lc.int_n_cs_precedes = monetary_lc.int_n_cs_precedes; + effective_lc.int_p_sep_by_space = monetary_lc.int_p_sep_by_space; + effective_lc.int_n_sep_by_space = monetary_lc.int_n_sep_by_space; + effective_lc.int_p_sign_posn = monetary_lc.int_p_sign_posn; + effective_lc.int_n_sign_posn = monetary_lc.int_n_sign_posn; + + return &effective_lc; +} diff --git a/user/include/mlibc/options/ansi/generic/signal.cpp b/user/include/mlibc/options/ansi/generic/signal.cpp new file mode 100644 index 0000000..0e1b44f --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/signal.cpp @@ -0,0 +1,44 @@ + +#include +#include +#include + +#include +#include + +__sighandler signal(int sn, __sighandler handler) { + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + struct sigaction old; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaction, SIG_ERR); + if(int e = mlibc::sys_sigaction(sn, &sa, &old)){ + errno = e; + return SIG_ERR; + } + return old.sa_handler; +} + +int raise(int sig) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getpid && mlibc::sys_kill, -1); + pid_t pid = mlibc::sys_getpid(); + + if (int e = mlibc::sys_kill(pid, sig)) { + errno = e; + return -1; + } + + return 0; +} + +// This is a POSIX extension, but we have it in here for sigsetjmp +int sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigprocmask, -1); + if(int e = mlibc::sys_sigprocmask(how, set, retrieve); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/user/include/mlibc/options/ansi/generic/stdio.cpp b/user/include/mlibc/options/ansi/generic/stdio.cpp new file mode 100644 index 0000000..070168f --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/stdio.cpp @@ -0,0 +1,1500 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +template +struct PrintfAgent { + PrintfAgent(F *formatter, frg::va_struct *vsp) + : _formatter{formatter}, _vsp{vsp} { } + + frg::expected operator() (char c) { + _formatter->append(c); + return {}; + } + frg::expected operator() (const char *c, size_t n) { + _formatter->append(c, n); + return {}; + } + + frg::expected operator() (char t, frg::format_options opts, + frg::printf_size_mod szmod) { + switch(t) { + case 'c': + if (szmod == frg::printf_size_mod::long_size) { + char c_buf[MB_LEN_MAX]; + auto c = static_cast(va_arg(_vsp->args, wint_t)); + mbstate_t shift_state = {}; + size_t res = wcrtomb(c_buf, c, &shift_state); + if (res == size_t(-1)) + return frg::format_error::agent_error; + _formatter->append(c_buf, res); + break; + } + frg::do_printf_chars(*_formatter, t, opts, szmod, _vsp); + break; + case 'p': case 's': + frg::do_printf_chars(*_formatter, t, opts, szmod, _vsp); + break; + case 'd': case 'i': case 'o': case 'x': case 'X': case 'b': case 'B': case 'u': + frg::do_printf_ints(*_formatter, t, opts, szmod, _vsp); + break; + case 'f': case 'F': case 'g': case 'G': case 'e': case 'E': + frg::do_printf_floats(*_formatter, t, opts, szmod, _vsp); + break; + case 'm': + __ensure(!opts.fill_zeros); + __ensure(!opts.left_justify); + __ensure(!opts.alt_conversion); + __ensure(opts.minimum_width == 0); + __ensure(szmod == frg::printf_size_mod::default_size); + __ensure(!opts.precision); + _formatter->append(strerror(errno)); + break; + case 'n': { + switch(szmod) { + case frg::printf_size_mod::default_size: { + auto p = va_arg(_vsp->args, int *); + *p = _formatter->count; + } break; + case frg::printf_size_mod::char_size: { + auto p = va_arg(_vsp->args, signed char *); + *p = static_cast(_formatter->count); + } break; + case frg::printf_size_mod::short_size: { + auto p = va_arg(_vsp->args, short *); + *p = static_cast(_formatter->count); + } break; + case frg::printf_size_mod::long_size: { + auto p = va_arg(_vsp->args, long *); + *p = static_cast(_formatter->count); + } break; + case frg::printf_size_mod::longlong_size: { + auto p = va_arg(_vsp->args, long long *); + *p = static_cast(_formatter->count); + } break; + case frg::printf_size_mod::longdouble_size: + __ensure(!"Illegal size for %n printf modifier"); + break; + case frg::printf_size_mod::native_size: { + auto p = va_arg(_vsp->args, ptrdiff_t *); + *p = static_cast(_formatter->count); + } break; + case frg::printf_size_mod::intmax_size: { + auto p = va_arg(_vsp->args, intmax_t *); + *p = static_cast(_formatter->count); + } break; + } + + break; + } + default: + mlibc::infoLogger() << "\e[31mmlibc: Unknown printf terminator '" + << t << "'\e[39m" << frg::endlog; + __ensure(!"Illegal printf terminator"); + } + + return {}; + } + +private: + F *_formatter; + frg::va_struct *_vsp; +}; + +struct StreamPrinter { + StreamPrinter(FILE *stream) + : stream(stream), count(0) { } + + void append(char c) { + fwrite_unlocked(&c, 1, 1, stream); + count++; + } + + void append(const char *str) { + fwrite_unlocked(str, strlen(str), 1, stream); + count += strlen(str); + } + + void append(const char *str, size_t n) { + fwrite_unlocked(str, n, 1, stream); + count += n; + } + + FILE *stream; + size_t count; +}; + +struct BufferPrinter { + BufferPrinter(char *buffer) + : buffer(buffer), count(0) { } + + void append(char c) { + buffer[count] = c; + count++; + } + + void append(const char *str) { + // TODO: use strcat + for(size_t i = 0; str[i]; i++) { + buffer[count] = str[i]; + count++; + } + } + + void append(const char *str, size_t n) { + // TODO: use strcat + for(size_t i = 0; i < n; i++) { + buffer[count] = str[i]; + count++; + } + } + + char *buffer; + size_t count; +}; + +struct LimitedPrinter { + LimitedPrinter(char *buffer, size_t limit) + : buffer(buffer), limit(limit), count(0) { } + + void append(char c) { + if(count < limit) + buffer[count] = c; + count++; + } + + void append(const char *str) { + // TODO: use strcat + for(size_t i = 0; str[i]; i++) + append(str[i]); + } + + void append(const char *str, size_t n) { + // TODO: use strcat + for(size_t i = 0; i < n; i++) + append(str[i]); + } + + char *buffer; + size_t limit; + size_t count; +}; + +struct ResizePrinter { + ResizePrinter() + : buffer(nullptr), limit(0), count(0) { } + + void expand() { + if(count == limit) { + auto new_limit = frg::max(2 * limit, size_t(16)); + auto new_buffer = reinterpret_cast(malloc(new_limit)); + __ensure(new_buffer); + memcpy(new_buffer, buffer, count); + free(buffer); + buffer = new_buffer; + limit = new_limit; + } + __ensure(count < limit); + } + + void append(char c) { + expand(); + buffer[count] = c; + count++; + } + + void append(const char *str) { + for(size_t i = 0; str[i]; i++) + append(str[i]); + } + + void append(const char *str, size_t n) { + for(size_t i = 0; i < n; i++) + append(str[i]); + } + + char *buffer; + size_t limit; + size_t count; +}; + +int remove(const char *filename) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_rmdir, -1); + if(int e = mlibc::sys_rmdir(filename); e) { + if (e == ENOTDIR) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlinkat, -1); + if(e = mlibc::sys_unlinkat(AT_FDCWD, filename, 0); e) { + errno = e; + return -1; + } + + return 0; + } + return -1; + } + + return 0; +} + +int rename(const char *path, const char *new_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_rename, -1); + if(int e = mlibc::sys_rename(path, new_path); e) { + errno = e; + return -1; + } + return 0; +} + +int renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_renameat, -1); + if(int e = mlibc::sys_renameat(olddirfd, old_path, newdirfd, new_path); e) { + errno = e; + return -1; + } + return 0; +} + +FILE *tmpfile(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *tmpnam(char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// fflush() is provided by the POSIX sublibrary +// fopen() is provided by the POSIX sublibrary +FILE *freopen(const char *__restrict path, const char *__restrict mode, FILE *__restrict f) { + auto file = static_cast(f); + frg::unique_lock lock(file->_lock); + + if(file->reopen(path, mode) == -1) { + errno = EINVAL; + return nullptr; + } + + return f; +} + +void setbuf(FILE *__restrict stream, char *__restrict buffer) { + setvbuf(stream, buffer, buffer ? _IOFBF : _IONBF, BUFSIZ); +} +// setvbuf() is provided by the POSIX sublibrary + +void setlinebuf(FILE *stream) { + setvbuf(stream, nullptr, _IOLBF, 0); +} + +void setbuffer(FILE *f, char *buf, size_t size) { + setvbuf(f, buf, buf ? _IOFBF : _IONBF, size); +} + +int fprintf(FILE *__restrict stream, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfprintf(stream, format, args); + va_end(args); + return result; +} + +int fscanf(FILE *__restrict stream, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfscanf(stream, format, args); + va_end(args); + return result; +} + +int printf(const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfprintf(stdout, format, args); + va_end(args); + return result; +} + +namespace { + enum { + SCANF_TYPE_CHAR, + SCANF_TYPE_SHORT, + SCANF_TYPE_INTMAX, + SCANF_TYPE_L, + SCANF_TYPE_LL, + SCANF_TYPE_PTRDIFF, + SCANF_TYPE_SIZE_T, + SCANF_TYPE_INT + }; +} // namespace + +static void store_int(void *dest, unsigned int size, unsigned long long i) { + switch (size) { + case SCANF_TYPE_CHAR: + *(char *)dest = i; + break; + case SCANF_TYPE_SHORT: + *(short *)dest = i; + break; + case SCANF_TYPE_INTMAX: + *(intmax_t *)dest = i; + break; + case SCANF_TYPE_L: + *(long *)dest = i; + break; + case SCANF_TYPE_LL: + *(long long *)dest = i; + break; + case SCANF_TYPE_PTRDIFF: + *(ptrdiff_t *)dest = i; + break; + case SCANF_TYPE_SIZE_T: + *(size_t *)dest = i; + break; + /* fallthrough */ + case SCANF_TYPE_INT: + default: + *(int *)dest = i; + break; + } +} + +template +static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) { + #define NOMATCH_CHECK(cond) ({ if(cond) return match_count; }) // if cond is true, matching error + #define EOF_CHECK(cond) ({ if(cond) return match_count ? match_count : EOF; }) // if cond is true, no more data to read + int match_count = 0; + for (; *fmt; fmt++) { + if (isspace(*fmt)) { + while (isspace(fmt[1])) fmt++; + while (isspace(handler.look_ahead())) + handler.consume(); + continue; + } + + if (*fmt != '%' || fmt[1] == '%') { + if (*fmt == '%') + fmt++; + char c = handler.consume(); + EOF_CHECK(c == '\0'); + NOMATCH_CHECK(c != *fmt); + continue; + } + + void *dest = nullptr; + /* %n$ format */ + if (isdigit(*fmt) && fmt[1] == '$') { + /* TODO: dest = get_arg_at_pos(args, *fmt -'0'); */ + fmt += 3; + } else { + if (fmt[1] != '*') { + dest = va_arg(args, void*); + } + fmt++; + } + + bool allocate_buf = false; + auto temp_dest = frg::string{getAllocator()}; + auto temp_wdest = frg::basic_string{getAllocator()}; + int count = 0; + + const auto append_to_buffer = [&](char c) { + if(allocate_buf) { + temp_dest += c; + } else { + char *typed_dest = (char *)dest; + if(typed_dest) + typed_dest[count] = c; + } + + count++; + }; + + const auto append_to_wbuffer = [&](wchar_t c) { + if(allocate_buf) { + temp_wdest += c; + } else { + wchar_t *typed_dest = (wchar_t *)dest; + if(typed_dest) + typed_dest[count] = c; + } + + count++; + }; + + int width = 0; + if (*fmt == '*') { + fmt++; + } else if (*fmt == '\'') { + /* TODO: numeric seperators locale stuff */ + mlibc::infoLogger() << "do_scanf: \' not implemented!" << frg::endlog; + fmt++; + continue; + } else if (*fmt == 'm') { + allocate_buf = true; + fmt++; + } else if (*fmt >= '0' && *fmt <= '9') { + /* read in width specifier */ + width = 0; + while (*fmt >= '0' && *fmt <= '9') { + width = width * 10 + (*fmt - '0'); + fmt++; + continue; + } + } + + /* type modifiers */ + unsigned int type = SCANF_TYPE_INT; + unsigned int base = 10; + switch (*fmt) { + case 'h': { + if (fmt[1] == 'h') { + type = SCANF_TYPE_CHAR; + fmt += 2; + break; + } + type = SCANF_TYPE_SHORT; + fmt++; + break; + } + case 'j': { + type = SCANF_TYPE_INTMAX; + fmt++; + break; + } + case 'l': { + if (fmt[1] == 'l') { + type = SCANF_TYPE_LL; + fmt += 2; + break; + } + type = SCANF_TYPE_L; + fmt++; + break; + } + case 'L': { + type = SCANF_TYPE_LL; + fmt++; + break; + } + case 'q': { + type = SCANF_TYPE_LL; + fmt++; + break; + } + case 't': { + type = SCANF_TYPE_PTRDIFF; + fmt++; + break; + } + case 'z': { + type = SCANF_TYPE_SIZE_T; + fmt++; + break; + } + } + + // Leading whitespace is skipped for most conversions except these. + if (*fmt != 'c' && *fmt != '[' && *fmt != 'n') { + while (isspace(handler.look_ahead())) + handler.consume(); + } + + switch (*fmt) { + case 'd': + case 'u': + base = 10; + [[fallthrough]]; + case 'i': { + bool is_negative = false; + unsigned long long res = 0; + char c = handler.look_ahead(); + EOF_CHECK(c == '\0'); + + if(c == '-') { + handler.consume(); + is_negative = true; + } else if(c == '+') + handler.consume(); + + if(*fmt == 'i' && handler.look_ahead() == '0') { + handler.consume(); + c = handler.look_ahead(); + if(tolower(c) == 'x') { + handler.consume(); + base = 16; + } else if(tolower(c) == 'b') { + handler.consume(); + base = 2; + } else { + base = 8; + } + } + + c = handler.look_ahead(); + int count = 0; + switch (base) { + case 10: + NOMATCH_CHECK(!isdigit(c)); + while (c >= '0' && c <= '9') { + handler.consume(); + res = res * 10 + (c - '0'); + c = handler.look_ahead(); + } + break; + case 16: + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A' + 10); + } else { + break; + } + count++; + c = handler.look_ahead(); + } + NOMATCH_CHECK(count == 0); + break; + case 8: + while (c >= '0' && c <= '7') { + handler.consume(); + res = res * 8 + (c - '0'); + c = handler.look_ahead(); + } + // no need for a match check, the starting 0 was already consumed + break; + case 2: + NOMATCH_CHECK(c != '0' && c != '1'); + while (c == '0' || c == '1') { + handler.consume(); + res = res * 2 + (c - '0'); + c = handler.look_ahead(); + } + break; + } + + if (dest) { + if(is_negative) + store_int(dest, type, -res); + else + store_int(dest, type, res); + } + break; + } + case 'o': { + bool is_negative = false; + unsigned long long res = 0; + char c = handler.look_ahead(); + EOF_CHECK(c == '\0'); + + if(c == '-') { + handler.consume(); + is_negative = true; + } else if(c == '+') + handler.consume(); + + c = handler.look_ahead(); + NOMATCH_CHECK(!(c >= '0' && c <= '7')); + while (c >= '0' && c <= '7') { + handler.consume(); + res = res * 8 + (c - '0'); + c = handler.look_ahead(); + } + + if (dest) { + if(is_negative) + store_int(dest, type, -res); + else + store_int(dest, type, res); + } + break; + } + case 'x': + case 'X': { + bool is_negative = false; + unsigned long long res = 0; + char c = handler.look_ahead(); + int count = 0; + EOF_CHECK(c == '\0'); + + if(c == '-') { + handler.consume(); + is_negative = true; + } else if(c == '+') + handler.consume(); + + c = handler.look_ahead(); + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (tolower(c) == 'x') { + handler.consume(); + c = handler.look_ahead(); + } + } + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A' + 10); + } else { + break; + } + count++; + c = handler.look_ahead(); + } + NOMATCH_CHECK(count == 0); + + if (dest) { + if(is_negative) + store_int(dest, type, -res); + else + store_int(dest, type, res); + } + break; + } + case 'b': { + bool is_negative = false; + unsigned long long res = 0; + char c = handler.look_ahead(); + int count = 0; + EOF_CHECK(c == '\0'); + + if(c == '-') { + handler.consume(); + is_negative = true; + } else if(c == '+') + handler.consume(); + + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (tolower(c) == 'b') { + handler.consume(); + c = handler.look_ahead(); + } + } + while (true) { + if (c == '0' || c == '1') { + handler.consume(); + res = res * 2 + (c - '0'); + } else { + break; + } + count++; + c = handler.look_ahead(); + } + NOMATCH_CHECK(count == 0); + + if (dest) { + if(is_negative) + store_int(dest, type, -res); + else + store_int(dest, type, res); + } + break; + } + case 's': { + char c = handler.look_ahead(); + EOF_CHECK(c == '\0'); + while (c && !isspace(c)) { + handler.consume(); + + if(type == SCANF_TYPE_L) + append_to_wbuffer(c); + else + append_to_buffer(c); + + c = handler.look_ahead(); + if (width && count >= width) + break; + } + NOMATCH_CHECK(count == 0); + + if(type == SCANF_TYPE_L) + append_to_wbuffer(L'\0'); + else + append_to_buffer('\0'); + + break; + } + case 'c': { + char c = handler.look_ahead(); + EOF_CHECK(c == '\0'); + if (!width) + width = 1; + while (c && count < width) { + handler.consume(); + + if(type == SCANF_TYPE_L) + append_to_wbuffer(c); + else + append_to_buffer(c); + + c = handler.look_ahead(); + } + break; + } + case '[': { + fmt++; + int invert = 0; + if (*fmt == '^') { + invert = 1; + fmt++; + } + + char scanset[257]; + memset(&scanset[0], invert, sizeof(char) * 257); + scanset[0] = '\0'; + + if (*fmt == '-') { + fmt++; + scanset[1+'-'] = 1 - invert; + } else if (*fmt == ']') { + fmt++; + scanset[1+']'] = 1 - invert; + } + + for (; *fmt != ']'; fmt++) { + if (!*fmt) return EOF; + if (*fmt == '-' && *fmt != ']') { + fmt++; + for (char c = *(fmt - 2); c < *fmt; c++) + scanset[1 + c] = 1 - invert; + } + scanset[1 + *fmt] = 1 - invert; + } + + char c = handler.look_ahead(); + EOF_CHECK(c == '\0'); + while (c && (!width || count < width)) { + handler.consume(); + if (!scanset[1 + c]) + break; + + if(type == SCANF_TYPE_L) + append_to_wbuffer(c); + else + append_to_buffer(c); + + c = handler.look_ahead(); + } + NOMATCH_CHECK(count == 0); + + if(type == SCANF_TYPE_L) + append_to_wbuffer(L'\0'); + else + append_to_buffer('\0'); + + break; + } + case 'p': { + unsigned long long res = 0; + char c = handler.look_ahead(); + int count = 0; + EOF_CHECK(c == '\0'); + + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (tolower(c) == 'x') { + handler.consume(); + c = handler.look_ahead(); + } + } + + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A' + 10); + } else { + break; + } + count++; + c = handler.look_ahead(); + } + NOMATCH_CHECK(count == 0); + void **typed_dest = (void **)dest; + *typed_dest = (void *)(uintptr_t)res; + break; + } + case 'n': { + if(dest) { + switch(type) { + case SCANF_TYPE_CHAR: + *(signed char *)dest = (signed char)handler.num_consumed; + break; + case SCANF_TYPE_SHORT: + *(short *)dest = (short)handler.num_consumed; + break; + case SCANF_TYPE_INTMAX: + *(intmax_t *)dest = (intmax_t)handler.num_consumed; + break; + case SCANF_TYPE_L: + *(long *)dest = (long)handler.num_consumed; + break; + case SCANF_TYPE_LL: + *(long long *)dest = (long long)handler.num_consumed; + break; + case SCANF_TYPE_PTRDIFF: + *(ptrdiff_t *)dest = (ptrdiff_t)handler.num_consumed; + break; + case SCANF_TYPE_SIZE_T: + *(size_t *)dest = (size_t)handler.num_consumed; + break; + case SCANF_TYPE_INT: + *(int *)dest = (int)handler.num_consumed; + break; + } + } + + continue; + } + } + + if(allocate_buf && dest) { + if(type == SCANF_TYPE_L) { + wchar_t *temp = (wchar_t *)getAllocator().allocate((temp_wdest.size() + 1) * sizeof(wchar_t)); + memcpy(temp, temp_wdest.data(), temp_wdest.size() * sizeof(wchar_t)); + temp[temp_wdest.size()] = L'\0'; + + wchar_t **dest_ptr = (wchar_t **)dest; + *dest_ptr = temp; + } else { + char *temp = (char *)getAllocator().allocate(temp_dest.size() + 1); + memcpy(temp, temp_dest.data(), temp_dest.size()); + temp[temp_dest.size()] = '\0'; + + char **dest_ptr = (char **)dest; + *dest_ptr = temp; + } + } + + if (dest) match_count++; + } + return match_count; +} + +int scanf(const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfscanf(stdin, format, args); + va_end(args); + return result; +} + +int snprintf(char *__restrict buffer, size_t max_size, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf(buffer, max_size, format, args); + va_end(args); + return result; +} + +int sprintf(char *__restrict buffer, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vsprintf(buffer, format, args); + va_end(args); + return result; +} + +int sscanf(const char *__restrict buffer, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + + int result = vsscanf(buffer, format, args); + + va_end(args); + return result; +} + +int vfprintf(FILE *__restrict stream, const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + StreamPrinter p{stream}; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + + return p.count; +} + +int vfscanf(FILE *__restrict stream, const char *__restrict format, __builtin_va_list args) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + + struct { + char look_ahead() { + char c; + size_t actual_size; + file->read(&c, 1, &actual_size); + if (actual_size) + file->unget(c); + return actual_size ? c : 0; + } + + char consume() { + char c; + size_t actual_size; + file->read(&c, 1, &actual_size); + if (actual_size) + num_consumed++; + return actual_size ? c : 0; + } + + mlibc::abstract_file *file; + int num_consumed; + } handler = {file, 0}; + + return do_scanf(handler, format, args); +} + +int vprintf(const char *__restrict format, __builtin_va_list args){ + return vfprintf(stdout, format, args); +} + +int vscanf(const char *__restrict, __builtin_va_list) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int vsnprintf(char *__restrict buffer, size_t max_size, + const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + LimitedPrinter p{buffer, max_size ? max_size - 1 : 0}; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + if (max_size) + p.buffer[frg::min(max_size - 1, p.count)] = 0; + return p.count; +} + +int vsprintf(char *__restrict buffer, const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + BufferPrinter p(buffer); +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + p.buffer[p.count] = 0; + return p.count; +} + +int vsscanf(const char *__restrict buffer, const char *__restrict format, __builtin_va_list args) { + struct { + char look_ahead() { + return *buffer; + } + + char consume() { + num_consumed++; + return *buffer++; + } + + const char *buffer; + int num_consumed; + } handler = {buffer, 0}; + + int result = do_scanf(handler, format, args); + + return result; +} + +int fwprintf(FILE *__restrict, const wchar_t *__restrict, ...) { MLIBC_STUB_BODY; } +int fwscanf(FILE *__restrict, const wchar_t *__restrict, ...) { MLIBC_STUB_BODY; } +int vfwprintf(FILE *__restrict, const wchar_t *__restrict, __builtin_va_list) { MLIBC_STUB_BODY; } +int vfwscanf(FILE *__restrict, const wchar_t *__restrict, __builtin_va_list) { MLIBC_STUB_BODY; } + +int swprintf(wchar_t *__restrict, size_t, const wchar_t *__restrict, ...) { MLIBC_STUB_BODY; } +int swscanf(wchar_t *__restrict, const wchar_t *__restrict, ...) { MLIBC_STUB_BODY; } +int vswprintf(wchar_t *__restrict, size_t, const wchar_t *__restrict, __builtin_va_list) { MLIBC_STUB_BODY; } +int vswscanf(wchar_t *__restrict, const wchar_t *__restrict, __builtin_va_list) { MLIBC_STUB_BODY; } + +int wprintf(const wchar_t *__restrict, ...) { MLIBC_STUB_BODY; } +int wscanf(const wchar_t *__restrict, ...) { MLIBC_STUB_BODY; } +int vwprintf(const wchar_t *__restrict, __builtin_va_list) { MLIBC_STUB_BODY; } +int vwscanf(const wchar_t *__restrict, __builtin_va_list) { MLIBC_STUB_BODY; } + +int fgetc(FILE *stream) { + char c; + auto bytes_read = fread(&c, 1, 1, stream); + if(bytes_read != 1) + return EOF; + return c; +} + +char *fgets(char *__restrict buffer, int max_size, FILE *__restrict stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fgets_unlocked(buffer, max_size, stream); +} + +int fputc_unlocked(int c, FILE *stream) { + char d = c; + if(fwrite_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return 1; +} + +int fputc(int c, FILE *stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fputc_unlocked(c, stream); +} + +int fputs_unlocked(const char *__restrict string, FILE *__restrict stream) { + // fwrite with a length of 0 will return 0, so we need to explicitly allow + // zero length strings. + size_t length = strlen(string); + if (length != 0 && fwrite_unlocked(string, length, 1, stream) != 1) + return EOF; + return 1; +} + +int fputs(const char *__restrict string, FILE *__restrict stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fputs_unlocked(string, stream); +} + +int getc_unlocked(FILE *stream) { + return fgetc_unlocked(stream); +} + +int getc(FILE *stream) { + return fgetc(stream); +} + +int getchar_unlocked(void) { + return fgetc_unlocked(stdin); +} + +int getchar(void) { + return fgetc(stdin); +} + +char *gets(char *s){ + return fgets(s, INT_MAX, stdin); +} + +int putc_unlocked(int c, FILE *stream) { + char d = c; + if(fwrite_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return c; +} + +int putc(int c, FILE *stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return putc_unlocked(c, stream); +} + +int putchar_unlocked(int c) { + return putc_unlocked(c, stdout); +} + +int putchar(int c) { + auto file = static_cast(stdout); + frg::unique_lock lock(file->_lock); + return putchar_unlocked(c); +} + +int puts(const char *string) { + auto file = static_cast(stdout); + frg::unique_lock lock(file->_lock); + + size_t progress = 0; + size_t len = strlen(string); + while(progress < len) { + size_t chunk; + if(file->write(string + progress, + len - progress, &chunk)) { + return EOF; + }else if(!chunk) { + return EOF; + } + + progress += chunk; + } + + size_t unused; + if (!file->write("\n", 1, &unused)) { + return EOF; + } + + return 1; +} + +wint_t fgetwc(FILE *) { MLIBC_STUB_BODY; } +wchar_t *fgetws(wchar_t *__restrict, int, FILE *__restrict) { MLIBC_STUB_BODY; } +wint_t fputwc(wchar_t, FILE *) { MLIBC_STUB_BODY; } +int fputws(const wchar_t *__restrict, FILE *__restrict) { MLIBC_STUB_BODY; } +int fwide(FILE *, int) { MLIBC_STUB_BODY; } +wint_t getwc(FILE *) { MLIBC_STUB_BODY; } +wint_t getwchar(void) { MLIBC_STUB_BODY; } +wint_t putwc(wchar_t, FILE *) { MLIBC_STUB_BODY; } +wint_t putwchar(wchar_t) { MLIBC_STUB_BODY; } +wint_t ungetwc(wint_t, FILE *) { MLIBC_STUB_BODY; } + +size_t fread(void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fread_unlocked(buffer, size, count, file_base); +} + +size_t fwrite(const void *buffer, size_t size , size_t count, FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fwrite_unlocked(buffer, size, count, file_base); +} + +int fgetpos(FILE *__restrict f, fpos_t *__restrict out) { + auto file = static_cast(f); + off_t current_offset; + + if(int e = file->tell(¤t_offset); e) { + errno = e; + return -1; + } + + *out = static_cast(current_offset); + + return 0; +} + +// fseek() is provided by the POSIX sublibrary +int fsetpos(FILE *f, const fpos_t *pos) { + auto file = static_cast(f); + frg::unique_lock lock(file->_lock); + if(int e = file->seek(*pos, SEEK_SET); e) { + errno = e; + return -1; + } + return 0; +} +// ftell() is provided by the POSIX sublibrary + +void clearerr(FILE *file_base) { + file_base->__status_bits = 0; +} + +int feof(FILE *file_base) { + return file_base->__status_bits & __MLIBC_EOF_BIT; +} + +int ferror(FILE *file_base) { + return file_base->__status_bits & __MLIBC_ERROR_BIT; +} + +void perror(const char *string) { + int error = errno; + if (string && *string) { + fprintf(stderr, "%s: ", string); + } + fprintf(stderr, "%s\n", strerror(error)); +} + +// POSIX extensions. + +ssize_t getline(char **line, size_t *n, FILE *stream) { + return getdelim(line, n, '\n', stream); +} + +ssize_t getdelim(char **line, size_t *n, int delim, FILE *stream) { + // Otherwise, we cannot store the buffer / size. + if(!line || !n) { + errno = EINVAL; + return -1; + } + + char *buffer = *line; + /* set the starting capacity to 512 if buffer = NULL */ + size_t capacity = (!buffer) ? 512 : *n; + size_t nwritten = 0; + + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + + // Avoid allocating if we've already hit the end + auto c = fgetc_unlocked(stream); + if (c == EOF || ferror(stream)) { + return -1; + } else { + file->unget(c); + } + + while (true) { + // Fill the buffer + while (buffer && capacity > 0 && nwritten < capacity - 1) { + auto c = fgetc_unlocked(stream); + if (ferror(stream)) { + return -1; + } else if (c == EOF) { + buffer[nwritten] = 0; + return nwritten; + } + + buffer[nwritten++] = c; + + if (c == delim) { + buffer[nwritten] = 0; + return nwritten; + } + } + + // Double the size of the buffer (but make sure it's at least 1024) + capacity = (capacity >= 1024) ? capacity * 2 : 1024; + buffer = reinterpret_cast(getAllocator().reallocate(*line, capacity)); + if (!buffer) { + errno = ENOMEM; + return -1; + } + + *line = buffer; + *n = capacity; + } +} + +// GLIBC extensions. + +int asprintf(char **out, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vasprintf(out, format, args); + va_end(args); + return result; +} + +int vasprintf(char **out, const char *format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + ResizePrinter p; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + p.expand(); + p.buffer[p.count] = 0; + *out = p.buffer; + return p.count; +} + +// Linux unlocked I/O extensions. + +void flockfile(FILE *file_base) { + static_cast(file_base)->_lock.lock(); +} + +void funlockfile(FILE *file_base) { + static_cast(file_base)->_lock.unlock(); +} + +int ftrylockfile(FILE *file_base) { + static_cast(file_base)->_lock.try_lock(); + return 0; +} + +void clearerr_unlocked(FILE *file_base) { + file_base->__status_bits = 0; +} + +int feof_unlocked(FILE *file_base) { + return file_base->__status_bits & __MLIBC_EOF_BIT; +} + +int ferror_unlocked(FILE *file_base) { + return file_base->__status_bits & __MLIBC_ERROR_BIT; +} + +int fgetc_unlocked(FILE *stream) { + unsigned char d; + if(fread_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return (int)d; +} + +size_t fread_unlocked(void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + if(!size || !count) + return 0; + + // Distinguish two cases here: If the object size is one, we perform byte-wise reads. + // Otherwise, we try to read each object individually. + if(size == 1) { + size_t progress = 0; + while(progress < count) { + size_t chunk; + if(int e = file->read((char *)buffer + progress, + count - progress, &chunk)) { + errno = e; + return 0; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + return progress; + }else{ + for(size_t i = 0; i < count; i++) { + size_t progress = 0; + while(progress < size) { + size_t chunk; + if(int e = file->read((char *)buffer + i * size + progress, + size - progress, &chunk)) { + errno = e; + return 0; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + if(progress < size) + return i; + } + + return count; + } +} + +size_t fwrite_unlocked(const void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + if(!size || !count) + return 0; + + // Distinguish two cases here: If the object size is one, we perform byte-wise writes. + // Otherwise, we try to write each object individually. + if(size == 1) { + size_t progress = 0; + while(progress < count) { + size_t chunk; + if(file->write((const char *)buffer + progress, + count - progress, &chunk)) { + // TODO: Handle I/O errors. + mlibc::infoLogger() << "mlibc: fwrite() I/O errors are not handled" + << frg::endlog; + break; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + return progress; + }else{ + for(size_t i = 0; i < count; i++) { + size_t progress = 0; + while(progress < size) { + size_t chunk; + if(file->write((const char *)buffer + i * size + progress, + size - progress, &chunk)) { + // TODO: Handle I/O errors. + mlibc::infoLogger() << "mlibc: fwrite() I/O errors are not handled" + << frg::endlog; + break; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + if(progress < size) + return i; + } + + return count; + } +} + +char *fgets_unlocked(char *__restrict buffer, int max_size, FILE *__restrict stream) { + __ensure(max_size > 0); + for(int i = 0; ; i++) { + if(i == max_size - 1) { + buffer[i] = 0; + return buffer; + } + + auto c = fgetc_unlocked(stream); + + // If fgetc() fails, there is either an EOF or an I/O error. + if(c == EOF) { + if(i) { + buffer[i] = 0; + return buffer; + } else { + // In this case, the buffer is not changed. + return nullptr; + } + } else { + buffer[i] = c; + } + + if(c == '\n') { + buffer[i + 1] = 0; + return buffer; + } + } +} diff --git a/user/include/mlibc/options/ansi/generic/stdlib.cpp b/user/include/mlibc/options/ansi/generic/stdlib.cpp new file mode 100644 index 0000000..23e106f --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/stdlib.cpp @@ -0,0 +1,519 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if __MLIBC_POSIX_OPTION +#include +#endif // __MLIBC_POSIX_OPTION + +extern "C" int __cxa_atexit(void (*function)(void *), void *argument, void *dso_tag); +void __mlibc_do_finalize(); + +namespace { + // According to the first paragraph of [C11 7.22.7], + // mblen(), mbtowc() and wctomb() have an internal state. + // The string functions mbstowcs() and wcstombs() do *not* have this state. + thread_local __mlibc_mbstate mblen_state = __MLIBC_MBSTATE_INITIALIZER; + thread_local __mlibc_mbstate mbtowc_state = __MLIBC_MBSTATE_INITIALIZER; + + __mlibc_mutex exit_mutex = __MLIBC_THREAD_MUTEX_INITIALIZER; +} // namespace + +double atof(const char *string) { + return strtod(string, nullptr); +} +int atoi(const char *string) { + return strtol(string, nullptr, 10); +} +long atol(const char *string) { + return strtol(string, nullptr, 10); +} +long long atoll(const char *string) { + return strtoll(string, nullptr, 10); +} + +// POSIX extensions but are here for simplicities sake. Forward declaration is here +// to avoid exporting sigprocmask when posix is disabled. +int sigprocmask(int, const sigset_t *__restrict, sigset_t *__restrict); +extern "C" { + __attribute__((__returns_twice__)) int __sigsetjmp(sigjmp_buf buffer, int savesigs) { + buffer[0].__savesigs = savesigs; + if (savesigs) + sigprocmask(0, nullptr, &buffer[0].__sigset); + return 0; + } +} + +__attribute__((__noreturn__)) void siglongjmp(sigjmp_buf buffer, int value) { + if (buffer[0].__savesigs) + sigprocmask(SIG_SETMASK, &buffer[0].__sigset, nullptr); + jmp_buf b; + b[0].__reg_state = buffer[0].__reg_state; + longjmp(b, value); +} + +double strtod(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} +float strtof(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} +long double strtold(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} + +long strtol(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +long long strtoll(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +unsigned long strtoul(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +unsigned long long strtoull(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} + +frg::mt19937 __mlibc_rand_engine; + +int rand() { + // rand() is specified to return a positive number so we discard the MSB. + return static_cast(__mlibc_rand_engine() & 0x7FFFFFFF); +} + +static unsigned temper(unsigned x) { + x ^= x >> 11; + x ^= x << 7 & 0x9D2C5680; + x ^= x << 15 & 0xEFC60000; + x ^= x >> 18; + return x; +} + +int rand_r(unsigned *seed) { + return temper(*seed = *seed * 1103515245 + 12345) / 2; +} + +void srand(unsigned int s) { + __mlibc_rand_engine.seed(s); +} + +void *aligned_alloc(size_t alignment, size_t size) { + void *ptr; + + // alignment must be a power of two, and size % alignment must be 0 + if (alignment & (alignment - 1) || size & (alignment - 1)) { + errno = EINVAL; + return nullptr; + } + + // posix_memalign requires that the alignment is a multiple of sizeof(void *) + if (alignment < sizeof(void *)) + alignment = sizeof(void *); + + int ret = posix_memalign(&ptr, alignment, size); + if (ret) { + errno = ret; + return nullptr; + } + return ptr; + +} +void *calloc(size_t count, size_t size) { + // we want to ensure that count*size > SIZE_MAX doesn't happen + // to prevent overflowing, we divide both sides of the inequality by size and check with that + if(size && count > (SIZE_MAX / size)) { + errno = EINVAL; + return nullptr; + } + + // TODO: this could be done more efficient if the OS gives us already zero'd pages + void *ptr = malloc(count * size); + if(!ptr) + return nullptr; + memset(ptr, 0, count * size); + return ptr; +} +// free() is provided by the platform +// malloc() is provided by the platform +// realloc() is provided by the platform + +void abort(void) { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGABRT); + if (mlibc::sys_sigprocmask) { + mlibc::sys_sigprocmask(SIG_UNBLOCK, &set, nullptr); + } + + raise(SIGABRT); + + sigfillset(&set); + sigdelset(&set, SIGABRT); + if (mlibc::sys_sigprocmask) { + mlibc::sys_sigprocmask(SIG_SETMASK, &set, nullptr); + } + + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + + if (mlibc::sys_sigaction(SIGABRT, &sa, nullptr)) + mlibc::panicLogger() << "mlibc: sigaction failed in abort" << frg::endlog; + + if (raise(SIGABRT)) + mlibc::panicLogger() << "mlibc: raise failed in abort" << frg::endlog; + + __builtin_trap(); +} + +int atexit(void (*func)(void)) { + // TODO: the function pointer types are not compatible; + // the conversion here is undefined behavior. its fine to do + // this on the x86_64 abi though. + __cxa_atexit((void (*) (void *))func, nullptr, nullptr); + return 0; +} +int at_quick_exit(void (*func)(void)) { + (void)func; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void exit(int status) { + // for concurrent calls to exit() or quick_exit(), all but the first shall block until termination + // see https://austingroupbugs.net/view.php?id=1845 + mlibc::thread_mutex_lock(&exit_mutex); + + __mlibc_do_finalize(); + mlibc::sys_exit(status); +} + +void _Exit(int status) { + mlibc::sys_exit(status); +} + +// getenv() is provided by POSIX +void quick_exit(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +extern char **environ; + +int system(const char *command) { + int status = -1; + pid_t child; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork && mlibc::sys_waitpid && + mlibc::sys_execve && mlibc::sys_sigprocmask && mlibc::sys_sigaction, -1); + +#if __MLIBC_POSIX_OPTION + pthread_testcancel(); +#endif // __MLIBC_POSIX_OPTION + + if (!command) { + return 1; + } + + struct sigaction new_sa, old_int, old_quit; + sigset_t new_mask, old_mask; + + new_sa.sa_handler = SIG_IGN; + new_sa.sa_flags = 0; + sigemptyset(&new_sa.sa_mask); + mlibc::sys_sigaction(SIGINT, &new_sa, &old_int); + mlibc::sys_sigaction(SIGQUIT, &new_sa, &old_quit); + + sigemptyset(&new_mask); + sigaddset(&new_mask, SIGCHLD); + mlibc::sys_sigprocmask(SIG_BLOCK, &new_mask, &old_mask); + + if (int e = mlibc::sys_fork(&child)) { + errno = e; + } else if (!child) { + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + const char *args[] = { + "sh", "-c", command, nullptr + }; + + mlibc::sys_execve("/bin/sh", const_cast(args), environ); + _Exit(127); + } else { + int err; + pid_t unused; + + while ((err = mlibc::sys_waitpid(child, &status, 0, nullptr, &unused)) < 0) { + if (err == EINTR) + continue; + + errno = err; + status = -1; + } + } + + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + return status; +} + +char *mktemp(char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void *bsearch(const void *key, const void *base, size_t count, size_t size, + int (*compare)(const void *, const void *)) { + // Invariant: Element is in the interval [i, j). + size_t i = 0; + size_t j = count; + + while(i < j) { + size_t k = (j - i) / 2; + auto element = reinterpret_cast(base) + (i + k) * size; + auto res = compare(key, element); + if(res < 0) { + j = i + k; + }else if(res > 0) { + i = i + k + 1; + }else{ + return const_cast(element); + } + } + __ensure(i == j); + + return nullptr; +} + +static int qsort_callback(const void *a, const void *b, void *arg) { + auto compare = reinterpret_cast(arg); + + return compare(a, b); +} + +void qsort(void *base, size_t count, size_t size, + int (*compare)(const void *, const void *)) { + return qsort_r(base, count, size, qsort_callback, (void *) compare); +} + +void qsort_r(void *base, size_t count, size_t size, + int (*compare)(const void *, const void *, void *), + void *arg) { + // TODO: implement a faster sort + for(size_t i = 0; i < count; i++) { + void *u = (void *)((uintptr_t)base + i * size); + for(size_t j = i + 1; j < count; j++) { + void *v = (void *)((uintptr_t)base + j * size); + if(compare(u, v, arg) <= 0) + continue; + + // swap u and v + char *u_bytes = (char *)u; + char *v_bytes = (char *)v; + for(size_t k = 0; k < size; k++) { + char temp = u_bytes[k]; + u_bytes[k] = v_bytes[k]; + v_bytes[k] = temp; + } + } + } +} + +int abs(int num) { + return num < 0 ? -num : num; +} + +long labs(long num) { + return num < 0 ? -num : num; +} + +long long llabs(long long num) { + return num < 0 ? -num : num; +} + +div_t div(int number, int denom) { + div_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +ldiv_t ldiv(long number, long denom) { + ldiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +lldiv_t lldiv(long long number, long long denom) { + lldiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +int mblen(const char *mbs, size_t mb_limit) { + auto cc = mlibc::current_charcode(); + wchar_t wc; + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{&wc, &wc + 1}; + + if(!mbs) { + mblen_state = __MLIBC_MBSTATE_INITIALIZER; + return cc->has_shift_states; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, mblen_state); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return nseq.it - mbs; +} + +int mbtowc(wchar_t *__restrict wc, const char *__restrict mb, size_t max_size) { + auto cc = mlibc::current_charcode(); + __ensure(max_size); + + // If wc is NULL, decode into a single local character which we discard + // to obtain the length. + wchar_t tmp_wc; + if (!wc) + wc = &tmp_wc; + + if (mb) { + if (*mb) { + mlibc::code_seq wseq{wc, wc + 1}; + mlibc::code_seq nseq{mb, mb + frg::min(max_size, MB_CUR_MAX)}; + auto e = cc->decode_wtranscode(nseq, wseq, mbtowc_state); + switch(e) { + // We keep the state, so we can simply return here. + case mlibc::charcode_error::input_underflow: + case mlibc::charcode_error::null: { + return nseq.it - mb; + } + case mlibc::charcode_error::illegal_input: { + errno = -EILSEQ; + return -1; + } + case mlibc::charcode_error::dirty: { + mlibc::panicLogger() << "decode_wtranscode() charcode_error::dirty errors are not handled" << frg::endlog; + break; + } + case mlibc::charcode_error::output_overflow: { + mlibc::panicLogger() << "decode_wtranscode() charcode_error::output_overflow errors are not handled" << frg::endlog; + break; + } + } + __builtin_unreachable(); + } else { + *wc = L'\0'; + return 0; // When mbs is a null byte, return 0 + } + } else { + mblen_state = __MLIBC_MBSTATE_INITIALIZER; + return cc->has_shift_states; + } +} + +int wctomb(char *, wchar_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +size_t mbstowcs(wchar_t *__restrict wcs, const char *__restrict mbs, size_t wc_limit) { + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{mbs, nullptr}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + return n; + } +} + +size_t wcstombs(char *__restrict mb_string, const wchar_t *__restrict wc_string, size_t max_size) { + const wchar_t *wcs = wc_string; + return wcsrtombs(mb_string, &wcs, max_size, nullptr); +} + +void free(void *ptr) { + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) { + mlibc::infoLogger() << "mlibc (PID ?): free() on " + << ptr << frg::endlog; + if((uintptr_t)ptr & 1) + mlibc::infoLogger() << __builtin_return_address(0) << frg::endlog; + } + getAllocator().free(ptr); +} + +void *malloc(size_t size) { + auto nptr = getAllocator().allocate(size); + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) + mlibc::infoLogger() << "mlibc (PID ?): malloc() returns " + << nptr << frg::endlog; + return nptr; +} + +void *realloc(void *ptr, size_t size) { + auto nptr = getAllocator().reallocate(ptr, size); + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) + mlibc::infoLogger() << "mlibc (PID ?): realloc() on " + << ptr << " returns " << nptr << frg::endlog; + return nptr; +} + +int posix_memalign(void **out, size_t align, size_t size) { + if(align < sizeof(void *)) + return EINVAL; + if(align & (align - 1)) // Make sure that align is a power of two. + return EINVAL; + auto p = getAllocator().allocate(frg::max(align, size)); + if(!p) + return ENOMEM; + // Hope that the alignment was respected. This works on the current allocator. + // TODO: Make the allocator alignment-aware. + __ensure(!(reinterpret_cast(p) & (align - 1))); + *out = p; + return 0; +} diff --git a/user/include/mlibc/options/ansi/generic/string.cpp b/user/include/mlibc/options/ansi/generic/string.cpp new file mode 100644 index 0000000..cc8942c --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/string.cpp @@ -0,0 +1,550 @@ +#undef _GNU_SOURCE + +#include +#include +#include +#include + +#include +#include + +// memset() is defined in options/internals. +// memcpy() is defined in options/internals. +// memmove() is defined in options/internals. +// strlen() is defined in options/internals. + +char *strcpy(char *__restrict dest, const char *src) { + char *dest_bytes = (char *)dest; + char *src_bytes = (char *)src; + while(*src_bytes) + *(dest_bytes++) = *(src_bytes++); + *dest_bytes = 0; + return dest; +} +char *strncpy(char *__restrict dest, const char *src, size_t max_size) { + auto dest_bytes = static_cast(dest); + auto src_bytes = static_cast(src); + size_t i = 0; + while(*src_bytes && i < max_size) { + *(dest_bytes++) = *(src_bytes++); + i++; + } + while(i < max_size) { + *(dest_bytes++) = 0; + i++; + } + return dest; +} + +char *strcat(char *__restrict dest, const char *__restrict src) { + strcpy(dest + strlen(dest), src); + return dest; +} +char *strncat(char *__restrict dest, const char *__restrict src, size_t max_size) { + auto dest_bytes = static_cast(dest); + auto src_bytes = static_cast(src); + dest_bytes += strlen(dest); + size_t i = 0; + while(*src_bytes && i < max_size) { + *(dest_bytes++) = *(src_bytes++); + i++; + } + *dest_bytes = 0; + return dest; +} + +int memcmp(const void *a, const void *b, size_t size) { + for(size_t i = 0; i < size; i++) { + auto a_byte = static_cast(a)[i]; + auto b_byte = static_cast(b)[i]; + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + } + return 0; +} +int strcmp(const char *a, const char *b) { + size_t i = 0; + while(true) { + unsigned char a_byte = a[i]; + unsigned char b_byte = b[i]; + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + i++; + } +} + +int strcoll(const char *a, const char *b) { + // TODO: strcoll should take "LC_COLLATE" into account. + return strcmp(a, b); +} + +int strncmp(const char *a, const char *b, size_t max_size) { + size_t i = 0; + while(true) { + if(!(i < max_size)) + return 0; + unsigned char a_byte = a[i]; + unsigned char b_byte = b[i]; + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + i++; + } +} + +size_t strxfrm(char *__restrict dest, const char *__restrict src, size_t n) { + // NOTE: This might not work for non ANSI charsets. + size_t l = strlen(src); + + // man page: If the value returned is n or more, the contents of dest are indeterminate. + if(n > l) + strncpy(dest, src, n); + + return l; +} + +void *memchr(const void *s, int c, size_t size) { + auto s_bytes = static_cast(s); + for(size_t i = 0; i < size; i++) + if(s_bytes[i] == static_cast(c)) + return const_cast(s_bytes + i); + return nullptr; +} +char *strchr(const char *s, int c) { + size_t i = 0; + while(s[i]) { + if(s[i] == c) + return const_cast(&s[i]); + i++; + } + if(c == 0) + return const_cast(&s[i]); + return nullptr; +} +size_t strcspn(const char *s, const char *chrs) { + size_t n = 0; + while(true) { + if(!s[n] || strchr(chrs, s[n])) + return n; + n++; + } +} +char *strpbrk(const char *s, const char *chrs) { + size_t n = 0; + while(s[n]) { + if(strchr(chrs, s[n])) + return const_cast(s + n); + n++; + } + return nullptr; +} +char *strrchr(const char *s, int c) { + // The null-terminator is considered to be part of the string. + size_t length = strlen(s); + for(size_t i = 0; i <= length; i++) { + if(s[length - i] == c) + return const_cast(s + (length - i)); + } + return nullptr; +} +size_t strspn(const char *s, const char *chrs) { + size_t n = 0; + while(true) { + if(!s[n] || !strchr(chrs, s[n])) + return n; + n++; + } +} +char *strstr(const char *s, const char *pattern) { + for(size_t i = 0; s[i]; i++) { + bool found = true; + for(size_t j = 0; pattern[j]; j++) { + if(!pattern[j] || s[i + j] == pattern[j]) + continue; + + found = false; + break; + } + + if(found) + return const_cast(&s[i]); + } + + return nullptr; +} +char *strtok_r(char *__restrict s, const char *__restrict del, char **__restrict m) { + __ensure(m); + + // We use *m = null to memorize that the entire string was consumed. + char *tok; + if(s) { + tok = s; + }else if(*m) { + tok = *m; + }else { + return nullptr; + } + + // Skip initial delimiters. + // After this loop: *tok is non-null iff we return a token. + while(*tok && strchr(del, *tok)) + tok++; + + // Replace the following delimiter by a null-terminator. + // After this loop: *p is null iff we reached the end of the string. + auto p = tok; + while(*p && !strchr(del, *p)) + p++; + + if(*p) { + *p = 0; + *m = p + 1; + }else{ + *m = nullptr; + } + if(p == tok) + return nullptr; + return tok; +} +char *strtok(char *__restrict s, const char *__restrict delimiter) { + static char *saved; + return strtok_r(s, delimiter, &saved); +} + +// This is a GNU extension. +char *strchrnul(const char *s, int c) { + size_t i = 0; + while(s[i]) { + if(s[i] == c) + return const_cast(s + i); + i++; + } + return const_cast(s + i); +} + +double wcstod(const wchar_t *__restrict, wchar_t **__restrict) { MLIBC_STUB_BODY; } +float wcstof(const wchar_t *__restrict, wchar_t **__restrict) { MLIBC_STUB_BODY; } +long double wcstold(const wchar_t *__restrict, wchar_t **__restrict) { MLIBC_STUB_BODY; } + +long wcstol(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +unsigned long wcstoul(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +long long wcstoll(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +unsigned long long wcstoull(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} + +wchar_t *wcscpy(wchar_t *__restrict dest, const wchar_t *__restrict src) { + wchar_t *a = dest; + while((*dest++ = *src++)); + return a; +} + +wchar_t *wcsncpy(wchar_t *__restrict dest, const wchar_t *__restrict src, size_t n) { + wchar_t *a = dest; + while(n && *src) + n--, *dest++ = *src++; + wmemset(dest, 0, n); + return a; +} + +wchar_t *wmemcpy(wchar_t *__restrict dest, const wchar_t *__restrict src, size_t n) { + memcpy(dest, src, n * sizeof(wchar_t)); + return dest; +} + +wchar_t *wmemmove(wchar_t *dest, const wchar_t *src, size_t n) { + memmove(dest, src, n * sizeof(wchar_t)); + return dest; +} + +wchar_t *wcscat(wchar_t *__restrict dest, const wchar_t *__restrict src) { + wcscpy(dest + wcslen(dest), src); + return dest; +} + +wchar_t *wcsncat(wchar_t *__restrict, const wchar_t *__restrict, size_t) { MLIBC_STUB_BODY; } + +int wcscmp(const wchar_t *l, const wchar_t *r) { + for(; *l == *r && *l && *r; l++, r++); + return *l - *r; +} + +int wcscoll(const wchar_t *, const wchar_t *) { MLIBC_STUB_BODY; } +int wcsncmp(const wchar_t *, const wchar_t *, size_t) { MLIBC_STUB_BODY; } +int wcsxfrm(wchar_t *__restrict, const wchar_t *__restrict, size_t) { MLIBC_STUB_BODY; } + +int wmemcmp(const wchar_t *a, const wchar_t *b, size_t size) { + for(size_t i = 0; i < size; i++) { + auto a_byte = a[i]; + auto b_byte = b[i]; + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + } + return 0; +} + +wchar_t *wcschr(const wchar_t *s, wchar_t c) { + if(!c) + return (wchar_t *)s + wcslen(s); + for(; *s && *s != c; s++); + return *s ? (wchar_t *)s : nullptr; +} + +size_t wcscspn(const wchar_t *, const wchar_t *) { MLIBC_STUB_BODY; } +wchar_t *wcspbrk(const wchar_t *, const wchar_t *) { MLIBC_STUB_BODY; } + +wchar_t *wcsrchr(const wchar_t *s, wchar_t c) { + const wchar_t *p; + for(p = s + wcslen(s); p >= s && *p != c; p--); + return p >= s ? (wchar_t *)p : nullptr; +} + +size_t wcsspn(const wchar_t *, const wchar_t *) { MLIBC_STUB_BODY; } +wchar_t *wcsstr(const wchar_t *, const wchar_t *) { MLIBC_STUB_BODY; } +wchar_t *wcstok(wchar_t *__restrict, const wchar_t *__restrict, wchar_t **__restrict) { MLIBC_STUB_BODY; } + +wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t size) { + auto s_bytes = s; + for(size_t i = 0; i < size; i++) + if(s_bytes[i] == c) + return const_cast(s_bytes + i); + return nullptr; +} + +size_t wcslen(const wchar_t *s) { + const wchar_t *a; + for(a = s; *s; s++); + return s-a; +} + +wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n) { + wchar_t *ret = d; + while(n--) + *d++ = c; + return ret; +} + +char *strerror(int e) { + const char *s; + switch(e) { + case EAGAIN: s = "Operation would block (EAGAIN)"; break; + case EACCES: s = "Access denied (EACCESS)"; break; + case EBADF: s = "Bad file descriptor (EBADF)"; break; + case EEXIST: s = "File exists already (EEXIST)"; break; + case EFAULT: s = "Access violation (EFAULT)"; break; + case EINTR: s = "Operation interrupted (EINTR)"; break; + case EINVAL: s = "Invalid argument (EINVAL)"; break; + case EIO: s = "I/O error (EIO)"; break; + case EISDIR: s = "Resource is directory (EISDIR)"; break; + case ENOENT: s = "No such file or directory (ENOENT)"; break; + case ENOMEM: s = "Out of memory (ENOMEM)"; break; + case ENOTDIR: s = "Expected directory instead of file (ENOTDIR)"; break; + case ENOSYS: s = "Operation not implemented (ENOSYS)"; break; + case EPERM: s = "Operation not permitted (EPERM)"; break; + case EPIPE: s = "Broken pipe (EPIPE)"; break; + case ESPIPE: s = "Seek not possible (ESPIPE)"; break; + case ENXIO: s = "No such device or address (ENXIO)"; break; + case ENOEXEC: s = "Exec format error (ENOEXEC)"; break; + case ENOSPC: s = "No space left on device (ENOSPC)"; break; + case ENOTSOCK: s = "Socket operation on non-socket (ENOTSOCK)"; break; + case ENOTCONN: s = "Transport endpoint is not connected (ENOTCONN)"; break; + case EDOM: s = "Numerical argument out of domain (EDOM)"; break; + case EILSEQ: s = "Invalid or incomplete multibyte or wide character (EILSEQ)"; break; + case ERANGE: s = "Numerical result out of range (ERANGE)"; break; + case E2BIG: s = "Argument list too long (E2BIG)"; break; + case EADDRINUSE: s = "Address already in use (EADDRINUSE)"; break; + case EADDRNOTAVAIL: s = "Cannot assign requested address (EADDRNOTAVAIL)"; break; + case EAFNOSUPPORT: s = "Address family not supported by protocol (EAFNOSUPPORT)"; break; + case EALREADY: s = "Operation already in progress (EALREADY)"; break; + case EBADMSG: s = "Bad message (EBADMSG)"; break; + case EBUSY: s = "Device or resource busy (EBUSY)"; break; + case ECANCELED: s = "Operation canceled (ECANCELED)"; break; + case ECHILD: s = "No child processes (ECHILD)"; break; + case ECONNABORTED: s = "Software caused connection abort (ECONNABORTED)"; break; + case ECONNREFUSED: s = "Connection refused (ECONNREFUSED)"; break; + case ECONNRESET: s = "Connection reset by peer (ECONNRESET)"; break; + case EDEADLK: s = "Resource deadlock avoided (EDEADLK)"; break; + case EDESTADDRREQ: s = "Destination address required (EDESTADDRREQ)"; break; + case EDQUOT: s = "Disk quota exceeded (EDQUOT)"; break; + case EFBIG: s = "File too large (EFBIG)"; break; + case EHOSTUNREACH: s = "No route to host (EHOSTUNREACH)"; break; + case EIDRM: s = "Identifier removed (EIDRM)"; break; + case EINPROGRESS: s = "Operation now in progress (EINPROGRESS)"; break; + case EISCONN: s = "Transport endpoint is already connected (EISCONN)"; break; + case ELOOP: s = "Too many levels of symbolic links (ELOOP)"; break; + case EMFILE: s = "Too many open files (EMFILE)"; break; + case EMLINK: s = "Too many links (EMLINK)"; break; + case EMSGSIZE: s = "Message too long (EMSGSIZE)"; break; + case EMULTIHOP: s = "Multihop attempted (EMULTIHOP)"; break; + case ENAMETOOLONG: s = "File name too long (ENAMETOOLONG)"; break; + case ENETDOWN: s = "Network is down (ENETDOWN)"; break; + case ENETRESET: s = "Network dropped connection on reset (ENETRESET)"; break; + case ENETUNREACH: s = "Network is unreachable (ENETUNREACH)"; break; + case ENFILE: s = "Too many open files in system (ENFILE)"; break; + case ENOBUFS: s = "No buffer space available (ENOBUFS)"; break; + case ENODEV: s = "No such device (ENODEV)"; break; + case ENOLCK: s = "No locks available (ENOLCK)"; break; + case ENOLINK: s = "Link has been severed (ENOLINK)"; break; + case ENOMSG: s = "No message of desired type (ENOMSG)"; break; + case ENOPROTOOPT: s = "Protocol not available (ENOPROTOOPT)"; break; + case ENOTEMPTY: s = "Directory not empty (ENOTEMPTY)"; break; + case ENOTRECOVERABLE: s = "Sate not recoverable (ENOTRECOVERABLE)"; break; + case ENOTSUP: s = "Operation not supported (ENOTSUP)"; break; + case ENOTTY: s = "Inappropriate ioctl for device (ENOTTY)"; break; + case EOVERFLOW: s = "Value too large for defined datatype (EOVERFLOW)"; break; +#if EOPNOTSUPP != ENOTSUP + /* these are aliases on the mlibc abi */ + case EOPNOTSUPP: s = "Operation not supported (EOPNOTSUP)"; break; +#endif + case EOWNERDEAD: s = "Owner died (EOWNERDEAD)"; break; + case EPROTO: s = "Protocol error (EPROTO)"; break; + case EPROTONOSUPPORT: s = "Protocol not supported (EPROTONOSUPPORT)"; break; + case EPROTOTYPE: s = "Protocol wrong type for socket (EPROTOTYPE)"; break; + case EROFS: s = "Read-only file system (EROFS)"; break; + case ESRCH: s = "No such process (ESRCH)"; break; + case ESTALE: s = "Stale file handle (ESTALE)"; break; + case ETIMEDOUT: s = "Connection timed out (ETIMEDOUT)"; break; + case ETXTBSY: s = "Text file busy (ETXTBSY)"; break; + case EXDEV: s = "Invalid cross-device link (EXDEV)"; break; + case ENODATA: s = "No data available (ENODATA)"; break; + case ETIME: s = "Timer expired (ETIME)"; break; + case ENOKEY: s = "Required key not available (ENOKEY)"; break; + case ESHUTDOWN: s = "Cannot send after transport endpoint shutdown (ESHUTDOWN)"; break; + case EHOSTDOWN: s = "Host is down (EHOSTDOWN)"; break; + case EBADFD: s = "File descriptor in bad state (EBADFD)"; break; + case ENOMEDIUM: s = "No medium found (ENOMEDIUM)"; break; + case ENOTBLK: s = "Block device required (ENOTBLK)"; break; + case ENONET: s = "Machine is not on the network (ENONET)"; break; + case EPFNOSUPPORT: s = "Protocol family not supported (EPFNOSUPPORT)"; break; + case ESOCKTNOSUPPORT: s = "Socket type not supported (ESOCKTNOSUPPORT)"; break; + case ESTRPIPE: s = "Streams pipe error (ESTRPIPE)"; break; + case EREMOTEIO: s = "Remote I/O error (EREMOTEIO)"; break; + case ERFKILL: s = "Operation not possible due to RF-kill (ERFKILL)"; break; + case EBADR: s = "Invalid request descriptor (EBADR)"; break; + case EUNATCH: s = "Protocol driver not attached (EUNATCH)"; break; + case EMEDIUMTYPE: s = "Wrong medium type (EMEDIUMTYPE)"; break; + case EREMOTE: s = "Object is remote (EREMOTE)"; break; + case EKEYREJECTED: s = "Key was rejected by service (EKEYREJECTED)"; break; + case EUCLEAN: s = "Structure needs cleaning (EUCLEAN)"; break; + case EBADSLT: s = "Invalid slot (EBADSLT)"; break; + case ENOANO: s = "No anode (ENOANO)"; break; + case ENOCSI: s = "No CSI structure available (ENOCSI)"; break; + case ENOSTR: s = "Device not a stream (ENOSTR)"; break; + case ETOOMANYREFS: s = "Too many references: cannot splice (ETOOMANYREFS)"; break; + case ENOPKG: s = "Package not installed (ENOPKG)"; break; + case EKEYREVOKED: s = "Key has been revoked (EKEYREVOKED)"; break; + case EXFULL: s = "Exchange full (EXFULL)"; break; + case ELNRNG: s = "Link number out of range (ELNRNG)"; break; + case ENOTUNIQ: s = "Name not unique on network (ENOTUNIQ)"; break; + case ERESTART: s = "Interrupted system call should be restarted (ERESTART)"; break; + case EUSERS: s = "Too many users (EUSERS)"; break; + +#ifdef EIEIO + case EIEIO: s = "Computer bought the farm; OS internal error (EIEIO)"; break; +#endif + + default: + s = "Unknown error code (?)"; + } + return const_cast(s); +} +// strlen() is defined in options/internals. + +extern "C" char *__gnu_strerror_r(int e, char *buffer, size_t bufsz) { + auto s = strerror(e); + strncpy(buffer, s, bufsz); + return buffer; +} + +// POSIX extensions. + +int strerror_r(int e, char *buffer, size_t bufsz) { + auto s = strerror(e); + strncpy(buffer, s, bufsz); + // Note that strerror_r does not set errno on error! + if(strlen(s) >= bufsz) + return ERANGE; + return 0; +} + +void *mempcpy(void *dest, const void *src, size_t len) { + return (char *)memcpy(dest, src, len) + len; +} + +// GNU extensions. +// Taken from musl. +int strverscmp(const char *l0, const char *r0) { + const unsigned char *l = (const unsigned char *)l0; + const unsigned char *r = (const unsigned char *)r0; + size_t i, dp, j; + int z = 1; + + /* Find maximal matching prefix and track its maximal digit + * suffix and whether those digits are all zeros. */ + for(dp = i = 0; l[i] == r[i]; i++) { + int c = l[i]; + if(!c) + return 0; + if(!isdigit(c)) + dp = i + 1, z = 1; + else if(c != '0') + z = 0; + } + + if(l[dp] != '0' && r[dp] != '0') { + /* If we're not looking at a digit sequence that began + * with a zero, longest digit string is greater. */ + for(j = i; isdigit(l[j]); j++) { + if(!isdigit(r[j])) + return 1; + } + if(isdigit(r[j])) + return -1; + } else if(z && dp < i && (isdigit(l[i]) || isdigit(r[i]))) { + /* Otherwise, if common prefix of digit sequence is + * all zeros, digits order less than non-digits. */ + return (unsigned char)(l[i] - '0') - (unsigned char)(r[i] - '0'); + } + + return l[i] - r[i]; +} + +void *memmem(const void *hs, size_t haystackLen, const void *nd, size_t needleLen) { + const char *haystack = static_cast(hs); + const char *needle = static_cast(nd); + + for (size_t i = 0; i < haystackLen; i++) { + bool found = true; + + for (size_t j = 0; j < needleLen; j++) { + if (i + j >= haystackLen || haystack[i + j] != needle[j]) { + found = false; + break; + } + } + + if(found) + return const_cast(&haystack[i]); + } + + return nullptr; +} diff --git a/user/include/mlibc/options/ansi/generic/threads.cpp b/user/include/mlibc/options/ansi/generic/threads.cpp new file mode 100644 index 0000000..1921811 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/threads.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { + int res = mlibc::thread_create(thr, nullptr, reinterpret_cast(func), arg, true); + + if(!res) { + return thrd_success; + } + + return (res == ENOMEM) ? thrd_nomem : thrd_error; +} + +int thrd_equal(thrd_t t1, thrd_t t2) { + if(t1 == t2) { + return 1; + } + return 0; +} + +thrd_t thrd_current(void) { + return reinterpret_cast(mlibc::get_current_tcb()); +} + +int thrd_sleep(const struct timespec *, struct timespec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void thrd_yield(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int thrd_detach(thrd_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int thrd_join(thrd_t thr, int *res) { + if(mlibc::thread_join(thr, res) != 0) { + return thrd_error; + } + + return thrd_success; +} + +__attribute__((__noreturn__)) void thrd_exit(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int mtx_init(mtx_t *mtx, int type) { + struct __mlibc_mutexattr attr; + mlibc::thread_mutexattr_init(&attr); + + if(type & mtx_recursive) { + mlibc::thread_mutexattr_settype(&attr, __MLIBC_THREAD_MUTEX_RECURSIVE); + } + + int res = mlibc::thread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + mlibc::thread_mutexattr_destroy(&attr); + + return res; +} + +void mtx_destroy(mtx_t *mtx) { + mlibc::thread_mutex_destroy(mtx); +} + +int mtx_lock(mtx_t *mtx) { + return mlibc::thread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; +} + +int mtx_unlock(mtx_t *mtx) { + return mlibc::thread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +int cnd_init(cnd_t *cond) { + return mlibc::thread_cond_init(cond, nullptr) == 0 ? thrd_success : thrd_error; +} + +void cnd_destroy(cnd_t *cond) { + mlibc::thread_cond_destroy(cond); +} + +int cnd_broadcast(cnd_t *cond) { + return mlibc::thread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) { + return mlibc::thread_cond_timedwait(cond, mtx, nullptr) == 0 ? thrd_success : thrd_error; +} diff --git a/user/include/mlibc/options/ansi/generic/time.cpp b/user/include/mlibc/options/ansi/generic/time.cpp new file mode 100644 index 0000000..3e374ba --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/time.cpp @@ -0,0 +1,1319 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __MLIBC_POSIX_OPTION +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// The DST rules to use if TZ has no rules and we can't load posixinfo. +// POSIX does not specify the default DST rules, for historical reasons +// America/New_York is a common default. +#define TZ_DEFAULT_RULE_STRING ",M3.2.0,M11.1.0" + +const char __utc[] = "UTC"; + +// Variables defined by POSIX. +int daylight; +long timezone; +char *tzname[2]; + +static FutexLock __time_lock; + +// Function taken from musl +clock_t clock(void) { + struct timespec ts; + + if(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) + return -1; + + if(ts.tv_sec > LONG_MAX / 1000000 || ts.tv_nsec / 1000 > LONG_MAX - 1000000 * ts.tv_sec) + return -1; + + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; +} + +double difftime(time_t a, time_t b) { + return a - b; +} + +time_t mktime(struct tm *tm) { + return timegm(tm); +} + +/* There is no other implemented value than TIME_UTC; all other values + * are considered erroneous. */ +// Function taken from musl +int timespec_get(struct timespec *ts, int base) { + if(base != TIME_UTC) + return 0; + int ret = clock_gettime(CLOCK_REALTIME, ts); + return ret < 0 ? 0 : base; +} + +char *asctime(const struct tm *ptr) { + static char buf[26]; + return asctime_r(ptr, buf); +} + +char *ctime(const time_t *timer) { + struct tm *tm = localtime(timer); + if(!tm) { + return nullptr; + } + return asctime(tm); +} + +struct tm *gmtime(const time_t *unix_gmt) { + static thread_local struct tm per_thread_tm; + return gmtime_r(unix_gmt, &per_thread_tm); +} + +struct tm *localtime(const time_t *unix_gmt) { + tzset(); + static thread_local struct tm per_thread_tm; + return localtime_r(unix_gmt, &per_thread_tm); +} + +size_t strftime(char *__restrict dest, size_t max_size, + const char *__restrict format, const struct tm *__restrict tm) { + auto c = format; + auto p = dest; + [[maybe_unused]] bool use_alternative_symbols = false; + [[maybe_unused]] bool use_alternative_era_format = false; + + while(*c) { + int chunk; + auto space = (dest + max_size) - p; + __ensure(space >= 0); + + if(*c != '%') { + if(!space) + return 0; + *p = *c; + c++; + p++; + continue; + } + + if(*(c + 1) == 'O') { + std::array valid{{'B', 'b', 'd', 'e', 'H', 'I', 'm', 'M', 'S', 'u', 'U', 'V', 'w', 'W', 'y'}}; + auto next = *(c + 2); + if(std::find(valid.begin(), valid.end(), next) != valid.end()) { + use_alternative_symbols = true; + c++; + } else { + *p = '%'; + p++; + c++; + *p = 'O'; + p++; + c++; + continue; + } + } else if(*(c + 1) == 'E') { + std::array valid{{'c', 'C', 'x', 'X', 'y', 'Y'}}; + auto next = *(c + 2); + if(std::find(valid.begin(), valid.end(), next) != valid.end()) { + use_alternative_era_format = true; + c++; + } else { + *p = '%'; + p++; + c++; + *p = 'E'; + p++; + c++; + continue; + } + } + + switch(*++c) { + case 'Y': { + chunk = snprintf(p, space, "%d", 1900 + tm->tm_year); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'm': { + chunk = snprintf(p, space, "%.2d", tm->tm_mon + 1); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'd': { + chunk = snprintf(p, space, "%.2d", tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'z': { + auto min = tm->tm_gmtoff / 60; + auto diff = ((min / 60) * 100) + (min % 60); + chunk = snprintf(p, space, "%c%04d", diff >= 0 ? '+' : '-', abs(diff)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'Z': { + chunk = snprintf(p, space, "%s", "UTC"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'H': { + chunk = snprintf(p, space, "%.2i", tm->tm_hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'M': { + chunk = snprintf(p, space, "%.2i", tm->tm_min); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'S': { + chunk = snprintf(p, space, "%.2d", tm->tm_sec); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'R': { + chunk = snprintf(p, space, "%.2i:%.2i", tm->tm_hour, tm->tm_min); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'T': { + chunk = snprintf(p, space, "%.2i:%.2i:%.2i", tm->tm_hour, tm->tm_min, tm->tm_sec); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'F': { + chunk = snprintf(p, space, "%d-%.2d-%.2d", 1900 + tm->tm_year, tm->tm_mon + 1, + tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'D': { + chunk = snprintf(p, space, "%.2d/%.2d/%.2d", tm->tm_mon + 1, tm->tm_mday, (tm->tm_year + 1900) % 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'a': { + int day = tm->tm_wday; + if(day < 0 || day > 6) + __ensure(!"Day not in bounds."); + + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(ABDAY_1 + day)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'b': + case 'B': + case 'h': { + int mon = tm->tm_mon; + if(mon < 0 || mon > 11) + __ensure(!"Month not in bounds."); + + nl_item item = (*c == 'B') ? MON_1 : ABMON_1; + + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(item + mon)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'c': { + int day = tm->tm_wday; + if(day < 0 || day > 6) + __ensure(!"Day not in bounds."); + + int mon = tm->tm_mon; + if(mon < 0 || mon > 11) + __ensure(!"Month not in bounds."); + + chunk = snprintf(p, space, "%s %s %2d %.2i:%.2i:%.2d %d", mlibc::nl_langinfo(ABDAY_1 + day), + mlibc::nl_langinfo(ABMON_1 + mon), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 1900 + tm->tm_year); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'e': { + chunk = snprintf(p, space, "%2d", tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'l': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%2d", hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'k': { + chunk = snprintf(p, space, "%2d", tm->tm_hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'I': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%.2d", hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'p': { + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo((tm->tm_hour < 12) ? AM_STR : PM_STR)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'P': { + char *str = mlibc::nl_langinfo((tm->tm_hour < 12) ? AM_STR : PM_STR); + char *str_lower = reinterpret_cast(getAllocator().allocate(strlen(str) + 1)); + for(size_t i = 0; str[i]; i++) + str_lower[i] = tolower(str[i]); + str_lower[strlen(str)] = '\0'; + + chunk = snprintf(p, space, "%s", str_lower); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'C': { + chunk = snprintf(p, space, "%.2d", (1900 + tm->tm_year) / 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'y': { + chunk = snprintf(p, space, "%.2d", (1900 + tm->tm_year) % 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'j': { + chunk = snprintf(p, space, "%.3d", tm->tm_yday + 1); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'A': { + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(DAY_1 + tm->tm_wday)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'r': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%.2i:%.2i:%.2i %s", hour, tm->tm_min, tm->tm_sec, + mlibc::nl_langinfo((tm->tm_hour < 12) ? AM_STR : PM_STR)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case '%': { + chunk = snprintf(p, space, "%%"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'n': { + chunk = snprintf(p, space, "\n"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 't': { + chunk = snprintf(p, space, "\t"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'x': { + return strftime(dest, max_size, mlibc::nl_langinfo(D_FMT), tm); + } + case 'X': { + return strftime(dest, max_size, mlibc::nl_langinfo(T_FMT), tm); + } + case '\0': { + chunk = snprintf(p, space, "%%"); + if(chunk >= space) + return 0; + p += chunk; + break; + } + default: + mlibc::panicLogger() << "mlibc: strftime unknown format type: " << c << frg::endlog; + } + } + + auto space = (dest + max_size) - p; + if(!space) + return 0; + + *p = '\0'; + return (p - dest); +} + +size_t wcsftime(wchar_t *__restrict, size_t, const wchar_t *__restrict, + const struct tm *__restrict) { + mlibc::infoLogger() << "mlibc: wcsftime is a stub" << frg::endlog; + return 0; +} + +namespace { + +// Given a pointer to a timezone string, extract a number and check if it's in +// range; if it's not, return NULL. Otherwise, return a pointer to the first +// character not part of the number. +template +const char *getnum(const char *str, T *nump, T min, T max) { + if (str == nullptr || !isdigit(*str)) + return nullptr; + + char c = *str; + T num = 0; + do { + num = num * 10 + (c - '0'); + if (num > max) + return nullptr; + c = *++str; + } while (isdigit(c)); + if (num < min) + return nullptr; + *nump = num; + return str; +} + +// Given a pointer into a timezone string, extract an offset, in +// [+-]hh[:mm[:ss]] form. If any error occurs, return NULL. Otherwise, return a +// pointer to the first character not part of the time. +const char *getoffset(const char *str, long *offset) { + bool negative = false; + if (*str == '-') { + negative = true; + str++; + } else if (*str == '+') { + str++; + } + + unsigned int num; + // `24 * 7 - 1` allows for quasi-POSIX rules like "M10.4.6/26", which does + // not conform to POSIX, but specifies the equivalent of "02:00 on the + // first Sunday on or after 23 Oct". + str = getnum(str, &num, 0, 24 * 7 - 1); + if (str == nullptr) + return nullptr; + *offset = num * 60 * 60; + if (*str == ':') { + str++; + str = getnum(str, &num, 0, 59); + if (str == nullptr) + return nullptr; + *offset += num * 60; + if (*str == ':') { + str++; + // Allows for leap seconds. + str = getnum(str, &num, 0, 60); + if (str == nullptr) + return nullptr; + *offset += num; + } + } + + if (negative) + *offset *= -1; + + return str; +} + +enum RuleType { + TZFILE, // mlibc-internal rule type for TZ files + JULIAN_DAY, // Jn = Julian day + DAY_OF_YEAR, // n = day of year + MONTH_NTH_DAY_OF_WEEK, // Mm.n.d = month, week, day of week +}; + +struct Rule { + RuleType type; + uint16_t day; + uint8_t week; + uint8_t month; + long time; +}; + +// Given a pointer into a timezone string, extract a rule in the form +// date[/time]. If a valid rule is not found, return NULL; otherwise, return a +// pointer to the first character not part of the rule. +const char *getrule(const char *str, Rule *rule) { + if (*str == 'J') { // Julian day + rule->type = JULIAN_DAY; + str++; + str = getnum(str, &rule->day, 1, 365); + } else if (*str == 'M') { // Month, week, day + rule->type = MONTH_NTH_DAY_OF_WEEK; + str++; + str = getnum(str, &rule->month, 1, 12); + if (str == nullptr) + return nullptr; + if (*str++ != '.') + return nullptr; + str = getnum(str, &rule->week, 1, 5); + if (str == nullptr) + return nullptr; + if (*str++ != '.') + return nullptr; + str = getnum(str, &rule->day, 0, 6); + } else if (isdigit(*str)) { // Day of year + rule->type = DAY_OF_YEAR; + str = getnum(str, &rule->day, 0, 365); + } else { + return nullptr; + } + + if (str == nullptr) + return nullptr; + + if (*str == '/') { + str++; + str = getoffset(str, &rule->time); + } else { + // Fallback to 02:00:00. + rule->time = 2 * 60 * 60; + } + + return str; +} + +struct[[gnu::packed]] ttinfo { + int32_t tt_gmtoff; + unsigned char tt_isdst; + unsigned char tt_abbrind; +}; + +// Let's just assume there's a maximum of two for now. +ttinfo tt_infos[2]; +Rule rules[2]; + +bool parse_tz(const char *tz, char *tz_name, char *tz_name_dst, size_t tz_name_max) { + // POSIX defines :*characters* as a valid but implementation-defined format. + // glibc ignores the initial colon and parses the rest as TZ. + if (*tz == ':') + tz++; + + // The timezone name may be wrapped in angle brackets, in which case we + // parse them in quoted mode. + bool quoted = false; + if (*tz == '<') { + quoted = true; + tz++; + } + + // Try parsing the timezone name. + auto *tzn = tz; + size_t tzn_len = 0; + for (;; tz++) { + tzn_len = tz - tzn; + if (*tz == '\0') + break; + + if (tzn_len > tz_name_max) + return true; + + // Advance until the end of the timezone name. + if (isalpha(*tz)) + continue; + if (quoted && (*tz == '+' || *tz == '-' || isdigit(*tz))) + continue; + + // Check if the timezone name has a valid length. + if (tzn_len < 3) + return true; + + // Consume the terminating angle bracket. + if (quoted && *tz == '>') { + tz++; + } else if (quoted) { + mlibc::infoLogger() << "mlibc: TZ name has unclosed angle bracket" << frg::endlog; + return true; + } + + break; + } + + long offset = 0; + tz = getoffset(tz, &offset); + if (tz == nullptr) + return true; + + // If we're here, this MUST be of the POSIX timezone format. + // Write the TZ name to the buffer passed to the function. + memcpy(tz_name, tzn, tzn_len); + tz_name[tzn_len] = '\0'; + + timezone = offset; + + tt_infos[0].tt_gmtoff = -offset; + tt_infos[0].tt_isdst = false; + tt_infos[0].tt_abbrind = 0; + + // If there's nothing left to parse, we should set tz_name_dst to tz_name. + // This matches glibc behaviour. + if (*tz == '\0') { + memcpy(tz_name_dst, tzn, tzn_len); + tz_name_dst[tzn_len] = '\0'; + return false; + } + + // From now on, we won't return an error but silently stop parsing. This + // makes a parsing error on the rest of the TZ environment variable not + // prevent setting the values we parsed before this point. This matches + // glibc behaviour. + + // The timezone name may be wrapped in angle brackets, in which case we + // parse them in quoted mode. + quoted = false; + if (*tz == '<') { + quoted = true; + tz++; + } + + // Try parsing the alternate timezone (DST) name. + auto *tzn_dst = tz; + size_t tzn_len_dst = 0; + for (;; tz++) { + tzn_len_dst = tz - tzn_dst; + if (*tz == '\0') + break; + + if (tzn_len_dst > tz_name_max) + return false; + + // Advance until the end of the timezone name. + if (isalpha(*tz)) + continue; + if (quoted && (*tz == '+' || *tz == '-' || isdigit(*tz))) + continue; + + // Check if the timezone name has a valid length. + if (tzn_len_dst < 3) + return false; + + // Consume the terminating angle bracket. + if (quoted && *tz == '>') { + tz++; + } else if (quoted) { + mlibc::infoLogger() << "mlibc: TZ name has unclosed angle bracket" << frg::endlog; + return false; + } + + break; + } + + // Write the TZ name to the buffer passed to the function. + memcpy(tz_name_dst, tzn_dst, tzn_len_dst); + tz_name_dst[tzn_len_dst] = '\0'; + + // Fallback to 1 hour ahead of standard time. + long offset_dst = offset - 60 * 60; + if (*tz != '\0' && *tz != ',') { + tz = getoffset(tz, &offset_dst); + if (tz == nullptr) + return false; + } + + // TODO: Attempt to fallback to posixrules before falling back to this. + if (*tz == '\0') + tz = TZ_DEFAULT_RULE_STRING; + + if (*tz == ',') { + tz++; + tz = getrule(tz, &rules[0]); + if (tz == nullptr) + return false; + if (*tz != ',') + return false; + tz++; + tz = getrule(tz, &rules[1]); + if (tz == nullptr) + return false; + if (*tz != '\0') + return false; + } else { + return false; + } + + tt_infos[1].tt_gmtoff = -offset_dst; + tt_infos[1].tt_isdst = true; + tt_infos[1].tt_abbrind = 0; + + daylight = 1; + + return false; +} + +struct tzfile { + uint8_t magic[4]; + uint8_t version; + uint8_t reserved[15]; + uint32_t tzh_ttisgmtcnt; + uint32_t tzh_ttisstdcnt; + uint32_t tzh_leapcnt; + uint32_t tzh_timecnt; + uint32_t tzh_typecnt; + uint32_t tzh_charcnt; +}; + +frg::string parse_tzfile_path(const char *tz) { + // POSIX defines :*characters* as a valid but implementation-defined format. + // This was originally introduced as a way to support geographical + // timezones in the format :Area/Location, but the colon was dropped in POSIX. + if (*tz == ':') + tz++; + + frg::string path {getAllocator()}; + // TODO: generic path helpers in options/internal? + if (*tz == '/') { + path += tz; + } else if (*tz == '.') { + // FIXME: Figure out what we actually need to do in this case, consider + // supporting relative paths or defaulting to UTC instead. + mlibc::infoLogger() << "mlibc: relative path in TZ not supported, " + "defaulting to /etc/localtime" << frg::endlog; + path += "/etc/localtime"; + } else { + const char *tzdir = getenv("TZDIR"); + if (tzdir == nullptr || *tzdir == '\0') { + tzdir = "/usr/share/zoneinfo"; + } else if (*tzdir != '/') { + mlibc::infoLogger() << "mlibc: non-absolute path in TZDIR not " + "supported, defaulting to /usr/share/zoneinfo" << frg::endlog; + tzdir = "/usr/share/zoneinfo"; + } + + path += tzdir; + path += "/"; + path += tz; + } + + return path; +} + +bool parse_tzfile(const char *tz) { + frg::string path = parse_tzfile_path(tz); + + // Check if file exists, otherwise fallback to the default. + if (!mlibc::sys_stat) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"cannot proceed without sys_stat"); + } + struct stat info; + if (mlibc::sys_stat(mlibc::fsfd_target::path, -1, path.data(), 0, &info)) + return true; + + // FIXME: Make this fallible so the above check is not needed. + file_window window {path.data()}; + + // TODO(geert): we can probably cache this somehow + tzfile tzfile_time; + memcpy(&tzfile_time, reinterpret_cast(window.get()), sizeof(tzfile)); + tzfile_time.tzh_ttisgmtcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisgmtcnt); + tzfile_time.tzh_ttisstdcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisstdcnt); + tzfile_time.tzh_leapcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_leapcnt); + tzfile_time.tzh_timecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_timecnt); + tzfile_time.tzh_typecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_typecnt); + tzfile_time.tzh_charcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_charcnt); + + if (tzfile_time.magic[0] != 'T' || tzfile_time.magic[1] != 'Z' || tzfile_time.magic[2] != 'i' + || tzfile_time.magic[3] != 'f') { + mlibc::infoLogger() << "mlibc: " << path << " is not a valid TZinfo file" << frg::endlog; + return true; + } + + if (tzfile_time.version != '\0' && tzfile_time.version != '2' && tzfile_time.version != '3') { + mlibc::infoLogger() << "mlibc: " << path << " has an invalid TZinfo version" + << frg::endlog; + return true; + } + + // There should be at least one entry in the ttinfo table. + if (!tzfile_time.tzh_typecnt) + return true; + + char *abbrevs = reinterpret_cast(window.get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + tzfile_time.tzh_typecnt * sizeof(struct ttinfo); + bool found_std = false; + bool found_dst = false; + // start from the last ttinfo entry, this matches the behaviour of glibc and musl + for (int i = tzfile_time.tzh_typecnt; i > 0; i--) { + ttinfo time_info; + memcpy(&time_info, reinterpret_cast(window.get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + i * sizeof(ttinfo), sizeof(ttinfo)); + time_info.tt_gmtoff = mlibc::bit_util::byteswap(time_info.tt_gmtoff); + if (!time_info.tt_isdst && !found_std) { + tzname[0] = abbrevs + time_info.tt_abbrind; + timezone = -time_info.tt_gmtoff; + found_std = true; + } + if (time_info.tt_isdst && !found_dst) { + tzname[1] = abbrevs + time_info.tt_abbrind; + timezone = -time_info.tt_gmtoff; + daylight = 1; + found_dst = true; + } + if (found_std && found_dst) + break; + } + + rules[0].type = TZFILE; + rules[1].type = TZFILE; + + return false; +} + +// Assumes __time_lock is taken +// TODO(geert): this function doesn't properly handle the case where +// information might be missing from the tzinfo file +void do_tzset(void) { + const char *tz = getenv("TZ"); + if (tz == nullptr) + tz = "/etc/localtime"; + if (*tz == '\0') + tz = "UTC0"; + + size_t tz_name_max = TZNAME_MAX; +#if __MLIBC_POSIX_OPTION + if (long sc_tz_name_max = sysconf(_SC_TZNAME_MAX); sc_tz_name_max > TZNAME_MAX) + tz_name_max = static_cast(sc_tz_name_max); +#endif + + // 1 byte for null + char *tz_name = (char *) malloc(tz_name_max + 1); + char *tz_name_dst = (char *) malloc(tz_name_max + 1); + memset(tz_name, 0, tz_name_max + 1); + memset(tz_name_dst, 0, tz_name_max + 1); + + // Reset daylight in case the TZ environment variable changed. + daylight = 0; + + if (!parse_tz(tz, tz_name, tz_name_dst, tz_name_max)) { + tzname[0] = tz_name; + tzname[1] = tz_name_dst; + return; + } + + // Try parsing as a geographic timezone. + if (parse_tzfile(tz)) { + // This should always succeed. + __ensure(!parse_tz("UTC0", tz_name, tz_name_dst, tz_name_max)); + tzname[0] = tz_name; + tzname[1] = tz_name_dst; + } +} + +} // namespace + +void tzset(void) { + frg::unique_lock lock(__time_lock); + do_tzset(); +} + +// POSIX extensions. + +int nanosleep(const struct timespec *req, struct timespec *) { + if (req->tv_sec < 0 || req->tv_nsec > 999999999 || req->tv_nsec < 0) { + errno = EINVAL; + return -1; + } + + if(!mlibc::sys_sleep) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_sleep()"); + } + + struct timespec tmp = *req; + + int e = mlibc::sys_sleep(&tmp.tv_sec, &tmp.tv_nsec); + if (!e) { + return 0; + } else { + errno = e; + return -1; + } +} + +int clock_getres(clockid_t clockid, struct timespec *res) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_clock_getres, -1); + if(int e = mlibc::sys_clock_getres(clockid, &res->tv_sec, &res->tv_nsec); e) { + errno = e; + return -1; + } + return 0; +} + +int clock_gettime(clockid_t clock, struct timespec *time) { + if(int e = mlibc::sys_clock_get(clock, &time->tv_sec, &time->tv_nsec); e) { + errno = e; + return -1; + } + return 0; +} + +int clock_nanosleep(clockid_t clockid, int, const struct timespec *req, struct timespec *) { + mlibc::infoLogger() << "clock_nanosleep is implemented as nanosleep!" << frg::endlog; + __ensure(clockid == CLOCK_REALTIME || clockid == CLOCK_MONOTONIC); + return nanosleep(req, nullptr); +} + +int clock_settime(clockid_t clock, const struct timespec *time) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_clock_set, -1); + if(int e = mlibc::sys_clock_set(clock, time->tv_sec, time->tv_nsec); e) { + errno = e; + return -1; + } + return 0; +} + +time_t time(time_t *out) { + time_t secs; + long nanos; + if(int e = mlibc::sys_clock_get(CLOCK_REALTIME, &secs, &nanos); e) { + errno = e; + return (time_t)-1; + } + if(out) + *out = secs; + return secs; +} + +namespace { + +void civil_from_days(time_t days_since_epoch, int *year, unsigned int *month, unsigned int *day) { + time_t time = days_since_epoch + 719468; + int era = (time >= 0 ? time : time - 146096) / 146097; + unsigned int doe = static_cast(time - era * 146097); + unsigned int yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; + int y = static_cast(yoe) + era * 400; + unsigned int doy = doe - (365*yoe + yoe/4 - yoe/100); + unsigned int mp = (5*doy + 2)/153; + unsigned int d = doy - (153*mp+2)/5 + 1; + unsigned int m = mp + (mp < 10 ? 3 : -9); + + *year = y + (m <= 2); + *month = m; + *day = d; +} + +void weekday_from_days(time_t days_since_epoch, unsigned int *weekday) { + *weekday = static_cast(days_since_epoch >= -4 ? + (days_since_epoch+4) % 7 : (days_since_epoch+5) % 7 + 6); +} + +void yearday_from_date(unsigned int year, unsigned int month, unsigned int day, unsigned int *yday) { + unsigned int n1 = 275 * month / 9; + unsigned int n2 = (month + 9) / 12; + unsigned int n3 = (1 + (year - 4 * year / 4 + 2) / 3); + *yday = n1 - (n2 * n3) + day - 30; +} + +static bool is_leap_year(int year) { + return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); +} + +// Given a rule and a year, compute the time of the transition in seconds since the epoch. +// TODO: Take into account the time of day when the transition occurs +time_t time_from_rule(const Rule &rule, int year) { + if (rule.type == JULIAN_DAY) { + // Jn: Julian day, ignoring Feb 29 + uint16_t day = rule.day - 1; + if (is_leap_year(year) && day >= 60) + day = rule.day; + + struct tm t = {}; + t.tm_year = year - 1900; + t.tm_yday = day; + return mktime(&t); + } else if (rule.type == DAY_OF_YEAR) { + // n: zero-based day of year, including Feb 29 in leap years + struct tm t = {}; + t.tm_year = year - 1900; + t.tm_yday = rule.day; + return mktime(&t); + } else if (rule.type == MONTH_NTH_DAY_OF_WEEK) { + // Mm.n.d: Month, week, weekday (month 1-12, week 1-5, weekday 0=Sun) + + // Find the first day of the month + struct tm t = {}; + t.tm_year = year - 1900; + t.tm_mon = rule.month - 1; + t.tm_mday = 1; + mktime(&t); + + int first_wday = t.tm_wday; + int day = 1 + ((7 + rule.day - first_wday) % 7) + (rule.week - 1) * 7; + // If week==5, but that day is past the end of the month, go back by 7 days + t.tm_mday = day; + mktime(&t); + if (rule.week == 5 && t.tm_mon != rule.month - 1) + day -= 7; + + t.tm_year = year - 1900; + t.tm_mon = rule.month - 1; + t.tm_mday = day; + t.tm_hour = 0; + t.tm_min = 0; + t.tm_sec = 0; + return mktime(&t); + } else { + __ensure(!"Invalid rule type"); + __builtin_unreachable(); + } +} + +// Assumes TZ environment variable rules are used, not TZFILE. +bool is_in_dst(time_t unix_gmt) { + if (rules[0].type == TZFILE) + __ensure(!"is_in_dst() called with invalid rules"); + + int year; + unsigned int _month; + unsigned int _day; + civil_from_days(unix_gmt / (60 * 60 * 24), &year, &_month, &_day); + + // Get the start and end transition days of the year + int start_time = time_from_rule(rules[0], year); + int end_time = time_from_rule(rules[1], year); + + // Check if the unix_gmt falls within the DST period + if (start_time <= end_time) { + return unix_gmt >= start_time && unix_gmt < end_time; + } else { + // DST period wraps around the year end + return unix_gmt >= start_time || unix_gmt < end_time; + } +} + +int unix_local_from_gmt_tzfile(time_t unix_gmt, time_t *offset, bool *dst, char **tm_zone) { + const char *tz = getenv("TZ"); + + if (!tz || *tz == '\0') + tz = "/etc/localtime"; + + frg::string path = parse_tzfile_path(tz); + + // Check if file exists + if (!mlibc::sys_stat) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"cannot proceed without sys_stat"); + } + struct stat info; + if (mlibc::sys_stat(mlibc::fsfd_target::path, -1, path.data(), 0, &info)) + return -1; + + // FIXME: Make this fallible so the above check is not needed. + file_window window {path.data()}; + + // TODO(geert): we can probably cache this somehow + tzfile tzfile_time; + memcpy(&tzfile_time, reinterpret_cast(window.get()), sizeof(tzfile)); + tzfile_time.tzh_ttisgmtcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisgmtcnt); + tzfile_time.tzh_ttisstdcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisstdcnt); + tzfile_time.tzh_leapcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_leapcnt); + tzfile_time.tzh_timecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_timecnt); + tzfile_time.tzh_typecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_typecnt); + tzfile_time.tzh_charcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_charcnt); + + if (tzfile_time.magic[0] != 'T' || tzfile_time.magic[1] != 'Z' || tzfile_time.magic[2] != 'i' + || tzfile_time.magic[3] != 'f') { + mlibc::infoLogger() << "mlibc: " << path << " is not a valid TZinfo file" << frg::endlog; + return -1; + } + + if (tzfile_time.version != '\0' && tzfile_time.version != '2' && tzfile_time.version != '3') { + mlibc::infoLogger() << "mlibc: " << path << " has an invalid TZinfo version" + << frg::endlog; + return -1; + } + + int index = -1; + for (size_t i = 0; i < tzfile_time.tzh_timecnt; i++) { + int32_t ttime; + memcpy(&ttime, reinterpret_cast(window.get()) + sizeof(tzfile) + + i * sizeof(int32_t), sizeof(int32_t)); + ttime = mlibc::bit_util::byteswap(ttime); + // If we are before the first transition, the format dicates that + // the first ttinfo entry should be used (and not the ttinfo entry pointed + // to by the first transition time). + if (i && ttime > unix_gmt) { + index = i - 1; + break; + } + } + + // The format dictates that if no transition is applicable, + // the first entry in the file is chosen. + uint8_t ttinfo_index = 0; + if (index >= 0) { + memcpy(&ttinfo_index, reinterpret_cast(window.get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + index * sizeof(uint8_t), sizeof(uint8_t)); + } + + // There should be at least one entry in the ttinfo table. + // TODO: If there is not, we might want to fall back to UTC, no DST (?). + __ensure(tzfile_time.tzh_typecnt); + + ttinfo time_info; + memcpy(&time_info, reinterpret_cast(window.get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + ttinfo_index * sizeof(ttinfo), sizeof(ttinfo)); + time_info.tt_gmtoff = mlibc::bit_util::byteswap(time_info.tt_gmtoff); + + char *abbrevs = reinterpret_cast(window.get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + tzfile_time.tzh_typecnt * sizeof(struct ttinfo); + + *offset = time_info.tt_gmtoff; + *dst = time_info.tt_isdst; + *tm_zone = abbrevs + time_info.tt_abbrind; + return 0; +} + +// Looks up the local time rules for a given +// UNIX GMT timestamp (seconds since 1970 GMT, ignoring leap seconds). +// This function assumes the __time_lock has been taken +int unix_local_from_gmt(time_t unix_gmt, time_t *offset, bool *dst, char **tm_zone) { + do_tzset(); + + if (daylight && rules[0].type == TZFILE) + return unix_local_from_gmt_tzfile(unix_gmt, offset, dst, tm_zone); + + if (daylight && is_in_dst(unix_gmt)) { + *offset = tt_infos[1].tt_gmtoff; + *dst = true; + *tm_zone = tzname[1]; + return 0; + } + + *offset = -timezone; + *dst = false; + *tm_zone = tzname[0]; + return 0; +} + +} //anonymous namespace + +struct tm *gmtime_r(const time_t *unix_gmt, struct tm *res) { + int year; + unsigned int month; + unsigned int day; + unsigned int weekday; + unsigned int yday; + + time_t unix_local = *unix_gmt; + + int days_since_epoch = unix_local / (60*60*24); + civil_from_days(days_since_epoch, &year, &month, &day); + weekday_from_days(days_since_epoch, &weekday); + yearday_from_date(year, month, day, &yday); + + res->tm_sec = unix_local % 60; + res->tm_min = (unix_local / 60) % 60; + res->tm_hour = (unix_local / (60*60)) % 24; + res->tm_mday = day; + res->tm_mon = month - 1; + res->tm_year = year - 1900; + res->tm_wday = weekday; + res->tm_yday = yday - 1; + res->tm_isdst = -1; + res->tm_zone = __utc; + res->tm_gmtoff = 0; + + return res; +} + +struct tm *localtime_r(const time_t *unix_gmt, struct tm *res) { + int year; + unsigned int month; + unsigned int day; + unsigned int weekday; + unsigned int yday; + + time_t offset = 0; + bool dst; + char *tm_zone; + frg::unique_lock lock(__time_lock); + // TODO: Set errno if the conversion fails. + if(unix_local_from_gmt(*unix_gmt, &offset, &dst, &tm_zone)) { + __ensure(!"Error parsing /etc/localtime"); + __builtin_unreachable(); + } + time_t unix_local = *unix_gmt + offset; + + int days_since_epoch = unix_local / (60*60*24); + civil_from_days(days_since_epoch, &year, &month, &day); + weekday_from_days(days_since_epoch, &weekday); + yearday_from_date(year, month, day, &yday); + + res->tm_sec = unix_local % 60; + res->tm_min = (unix_local / 60) % 60; + res->tm_hour = (unix_local / (60*60)) % 24; + res->tm_mday = day; + res->tm_mon = month - 1; + res->tm_year = year - 1900; + res->tm_wday = weekday; + res->tm_yday = yday - 1; + res->tm_isdst = dst; + res->tm_zone = tm_zone; + res->tm_gmtoff = offset; + + return res; +} + +// This implementation of asctime_r is taken from sortix +char *asctime_r(const struct tm *tm, char *buf) { + static char weekday_names[7][4] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static char month_names[12][4] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec" }; + sprintf(buf, "%.3s %.3s%3d %.2d:%.2d%.2d %d\n", + weekday_names[tm->tm_wday], + month_names[tm->tm_mon], + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + tm->tm_year + 1900); + return buf; +} + +char *ctime_r(const time_t *clock, char *buf) { + return asctime_r(localtime(clock), buf); +} + +time_t timelocal(struct tm *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +constexpr static int days_from_civil(int y, unsigned m, unsigned d) noexcept { + y -= m <= 2; + const int era = (y >= 0 ? y : y - 399) / 400; + const unsigned yoe = static_cast(y - era * 400); // [0, 399] + const unsigned doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; // [0, 365] + const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] + return era * 146097 + static_cast(doe) - 719468; +} + +time_t timegm(struct tm *tm) { + time_t year = tm->tm_year + 1900; + time_t month = tm->tm_mon + 1; + time_t days = days_from_civil(year, month, tm->tm_mday); + time_t secs = (days * 86400) + (tm->tm_hour * 60 * 60) + (tm->tm_min * 60) + tm->tm_sec; + return secs; +} diff --git a/user/include/mlibc/options/ansi/generic/uchar.cpp b/user/include/mlibc/options/ansi/generic/uchar.cpp new file mode 100644 index 0000000..56d0b34 --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/uchar.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +size_t c32rtomb(char *__restrict s, char32_t c32, mbstate_t *__restrict ps) { + return wcrtomb(s, c32, ps); +} + +size_t mbrtoc32(char32_t *__restrict pc32, const char *__restrict pmb, size_t max, mbstate_t *__restrict ps) { + static mbstate_t internal_state; + + if(!ps) + ps = &internal_state; + + if(!pmb) + return mbrtoc32(nullptr, "", 1, ps); + + wchar_t wc; + size_t ret = mbrtowc(&wc, pmb, max, ps); + + if (ret <= 4 && pc32) + *pc32 = wc; + + return ret; +} diff --git a/user/include/mlibc/options/ansi/generic/wchar.cpp b/user/include/mlibc/options/ansi/generic/wchar.cpp new file mode 100644 index 0000000..d4b56af --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/wchar.cpp @@ -0,0 +1,790 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + // All conversion functions mbrlen(), mbrtowc(), wcrtomb(), + // mbsrtowcs() and wcsrtombs() have an internal state. + __mlibc_mbstate mbrlen_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate mbrtowc_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate mbsrtowcs_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate wcsrtombs_state = __MLIBC_MBSTATE_INITIALIZER; +} // namespace + +wint_t btowc(int c) { + if(c == EOF) + return WEOF; + + char nc = c; + auto cc = mlibc::current_charcode(); + wchar_t wc; + if(auto e = cc->promote_wtranscode(nc, wc); e != mlibc::charcode_error::null) + return WEOF; + return wc; +} + +int wctob(wint_t wc) { + // TODO: Revisit this once we have character encoding functions. + return wc; +} + +int mbsinit(const mbstate_t *stp) { + if(!stp) + return -1; + return !stp->__progress && !stp->__shift; +} + +size_t mbrlen(const char *__restrict mbs, size_t mb_limit, mbstate_t *__restrict stp) { + auto cc = mlibc::current_charcode(); + wchar_t wc; + + if(!stp) + stp = &mbrlen_state; + if(!mbs) { + *stp = __MLIBC_MBSTATE_INITIALIZER; + return 0; + } + + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{&wc, &wc + 1}; + if(auto e = cc->decode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return nseq.it - mbs; +} + +size_t mbrtowc(wchar_t *__restrict wcp, const char *__restrict mbs, size_t mb_limit, mbstate_t *__restrict stp) { + auto cc = mlibc::current_charcode(); + + if(!stp) + stp = &mbrtowc_state; + if(!mbs) { + *stp = __MLIBC_MBSTATE_INITIALIZER; + return 0; + } + + wchar_t temp = 0; + if(!wcp) + wcp = &temp; + + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{wcp, wcp + 1}; + if(auto e = cc->decode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + if(e == mlibc::charcode_error::input_underflow) + return static_cast(-2); + __ensure(e == mlibc::charcode_error::illegal_input); + errno = EILSEQ; + return static_cast(-1); + }else{ + if (*mbs) { + return nseq.it - mbs; + } else { + *stp = __MLIBC_MBSTATE_INITIALIZER; + *wcp = 0; + return 0; + } + } +} + +size_t wcrtomb(char *__restrict mbs, wchar_t wc, mbstate_t *__restrict stp) { + auto cc = mlibc::current_charcode(); + + // wcrtomb() always takes a mbstate_t. + __ensure(stp); + + // TODO: Implement the following case: + __ensure(mbs); + + mlibc::code_seq wseq{&wc, &wc + 1}; + mlibc::code_seq nseq{mbs, mbs + MB_LEN_MAX}; + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = nseq.it - mbs; + if(!n) // Null-terminate resulting wide string. + *mbs = 0; + return n; + } +} + +size_t mbsrtowcs(wchar_t *__restrict wcs, const char **__restrict mbsp, size_t wc_limit, mbstate_t *__restrict stp) { + __ensure(mbsp); + + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{*mbsp, nullptr}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!stp) + stp = &mbsrtowcs_state; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + *mbsp = nullptr; + return n; + } +} + +size_t mbsnrtowcs(wchar_t *__restrict wcs, const char **__restrict mbsp, size_t mb_limit, size_t wc_limit, mbstate_t *__restrict stp) { + __ensure(mbsp); + + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{*mbsp, (*mbsp) + mb_limit}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!stp) + stp = &mbsrtowcs_state; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + *mbsp = nullptr; + return n; + } +} + +size_t wcsrtombs(char *__restrict mbs, const wchar_t **__restrict wcsp, size_t mb_limit, mbstate_t *__restrict stp) { + __ensure(wcsp && "wcsrtombs() with null input"); + auto cc = mlibc::current_charcode(); + mlibc::code_seq wseq{*wcsp, nullptr}; + + if(!stp) + stp = &wcsrtombs_state; + + if(!mbs) { + size_t size; + if(auto e = cc->encode_wtranscode_length(wseq, &size, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + *wcsp = wseq.it; + size_t n = nseq.it - mbs; + if(n < mb_limit) // Null-terminate resulting narrow string. + mbs[n] = 0; + return n; + } +} + +size_t wcsnrtombs(char *__restrict mbs, const wchar_t **__restrict wcsp, size_t wc_limit, size_t mb_limit, mbstate_t *__restrict stp) { + __ensure(wcsp && "wcsrtombs() with null input"); + auto cc = mlibc::current_charcode(); + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{*wcsp, (*wcsp) + wc_limit}; + + if(!stp) + stp = &wcsrtombs_state; + + if(!mbs) { + size_t size; + if(auto e = cc->encode_wtranscode_length(wseq, &size, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + *wcsp = wseq.it; + size_t n = nseq.it - mbs; + if(n < mb_limit) // Null-terminate resulting narrow string. + mbs[n] = 0; + return n; + } +} + +/* + * The code in this anonymous namespace and the wcwidth function below + * are taken from https://github.com/termux/wcwidth/, under the following license: + * + * Copyright (C) Fredrik Fornwall 2016. + * Distributed under the MIT License. + * + * Implementation of wcwidth(3) as a C port of: + * https://github.com/jquast/wcwidth + * + * Report issues at: + * https://github.com/termux/wcwidth + */ + +namespace { + +struct width_interval { + int start; + int end; +}; + +// From https://github.com/jquast/wcwidth/blob/master/wcwidth/table_zero.py +// at commit b29897e5a1b403a0e36f7fc991614981cbc42475 (2020-07-14): +struct width_interval ZERO_WIDTH[] = { + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x007fd, 0x007fd}, // Nko Dantayalan ..Nko Dantayalan + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d3, 0x008e1}, // Arabic Small Low Waw ..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x009fe, 0x009fe}, // Bengali Sandhi Mark ..Bengali Sandhi Mark + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00afa, 0x00aff}, // Gujarati Sign Sukun ..Gujarati Sign Two-circle + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b55, 0x00b56}, // (nil) ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c04, 0x00c04}, // Telugu Sign Combining An..Telugu Sign Combining An + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d00, 0x00d01}, // Malayalam Sign Combining..Malayalam Sign Candrabin + {0x00d3b, 0x00d3c}, // Malayalam Sign Vertical ..Malayalam Sign Circular + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00d81, 0x00d81}, // (nil) ..(nil) + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00ebc}, // Lao Vowel Sign I ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01ac0}, // Combining Doubled Circum..(nil) + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df9}, // Combining Dotted Grave A..Combining Wide Inverted + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a82c, 0x0a82c}, // (nil) ..(nil) + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a8ff, 0x0a8ff}, // Devanagari Vowel Sign Ay..Devanagari Vowel Sign Ay + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bd}, // Javanese Vowel Sign Pepe..Javanese Consonant Sign + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x10d24, 0x10d27}, // Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas + {0x10eab, 0x10eac}, // (nil) ..(nil) + {0x10f46, 0x10f50}, // Sogdian Combining Dot Be..Sogdian Combining Stroke + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111c9, 0x111cc}, // Sharada Sandhi Mark ..Sharada Extra Short Vowe + {0x111cf, 0x111cf}, // (nil) ..(nil) + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133b, 0x1133c}, // Combining Bindu Below ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x1145e, 0x1145e}, // Newa Sandhi Mark ..Newa Sandhi Mark + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x1182f, 0x11837}, // Dogra Vowel Sign U ..Dogra Sign Anusvara + {0x11839, 0x1183a}, // Dogra Sign Virama ..Dogra Sign Nukta + {0x1193b, 0x1193c}, // (nil) ..(nil) + {0x1193e, 0x1193e}, // (nil) ..(nil) + {0x11943, 0x11943}, // (nil) ..(nil) + {0x119d4, 0x119d7}, // Nandinagari Vowel Sign U..Nandinagari Vowel Sign V + {0x119da, 0x119db}, // Nandinagari Vowel Sign E..Nandinagari Vowel Sign A + {0x119e0, 0x119e0}, // Nandinagari Sign Virama ..Nandinagari Sign Virama + {0x11a01, 0x11a0a}, // Zanabazar Square Vowel S..Zanabazar Square Vowel L + {0x11a33, 0x11a38}, // Zanabazar Square Final C..Zanabazar Square Sign An + {0x11a3b, 0x11a3e}, // Zanabazar Square Cluster..Zanabazar Square Cluster + {0x11a47, 0x11a47}, // Zanabazar Square Subjoin..Zanabazar Square Subjoin + {0x11a51, 0x11a56}, // Soyombo Vowel Sign I ..Soyombo Vowel Sign Oe + {0x11a59, 0x11a5b}, // Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar + {0x11a8a, 0x11a96}, // Soyombo Final Consonant ..Soyombo Sign Anusvara + {0x11a98, 0x11a99}, // Soyombo Gemination Mark ..Soyombo Subjoiner + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x11d31, 0x11d36}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3a, 0x11d3a}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3c, 0x11d3d}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3f, 0x11d45}, // Masaram Gondi Vowel Sign..Masaram Gondi Virama + {0x11d47, 0x11d47}, // Masaram Gondi Ra-kara ..Masaram Gondi Ra-kara + {0x11d90, 0x11d91}, // Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign + {0x11d95, 0x11d95}, // Gunjala Gondi Sign Anusv..Gunjala Gondi Sign Anusv + {0x11d97, 0x11d97}, // Gunjala Gondi Virama ..Gunjala Gondi Virama + {0x11ef3, 0x11ef4}, // Makasar Vowel Sign I ..Makasar Vowel Sign U + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f4f, 0x16f4f}, // Miao Sign Consonant Modi..Miao Sign Consonant Modi + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x16fe4, 0x16fe4}, // (nil) ..(nil) + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e130, 0x1e136}, // Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T + {0x1e2ec, 0x1e2ef}, // Wancho Tone Tup ..Wancho Tone Koini + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 +}; + +// https://github.com/jquast/wcwidth/blob/master/wcwidth/table_wide.py +// at commit b29897e5a1b403a0e36f7fc991614981cbc42475 (2020-07-14): +struct width_interval WIDE_EASTASIAN[] = { + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312f}, // Bopomofo Letter B ..Bopomofo Letter Nn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031e3}, // Ideographic Annotation L..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x04dbf}, // Partnership Sign ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe4}, // Tangut Iteration Mark ..(nil) + {0x16ff0, 0x16ff1}, // (nil) ..(nil) + {0x17000, 0x187f7}, // (nil) ..(nil) + {0x18800, 0x18cd5}, // Tangut Component-001 ..(nil) + {0x18d00, 0x18d08}, // (nil) ..(nil) + {0x1b000, 0x1b11e}, // Katakana Letter Archaic ..Hentaigana Letter N-mu-m + {0x1b150, 0x1b152}, // Hiragana Letter Small Wi..Hiragana Letter Small Wo + {0x1b164, 0x1b167}, // Katakana Letter Small Wi..Katakana Letter Small N + {0x1b170, 0x1b2fb}, // Nushu Character-1b170 ..Nushu Character-1b2fb + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f260, 0x1f265}, // Rounded Symbol For Fu ..Rounded Symbol For Cai + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6d5, 0x1f6d7}, // Hindu Temple ..(nil) + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6fc}, // Scooter ..(nil) + {0x1f7e0, 0x1f7eb}, // Large Orange Circle ..Large Brown Square + {0x1f90c, 0x1f93a}, // (nil) ..Fencer + {0x1f93c, 0x1f945}, // Wrestlers ..Goal Net + {0x1f947, 0x1f978}, // First Place Medal ..(nil) + {0x1f97a, 0x1f9cb}, // Face With Pleading Eyes ..(nil) + {0x1f9cd, 0x1f9ff}, // Standing Person ..Nazar Amulet + {0x1fa70, 0x1fa74}, // Ballet Shoes ..(nil) + {0x1fa78, 0x1fa7a}, // Drop Of Blood ..Stethoscope + {0x1fa80, 0x1fa86}, // Yo-yo ..(nil) + {0x1fa90, 0x1faa8}, // Ringed Planet ..(nil) + {0x1fab0, 0x1fab6}, // (nil) ..(nil) + {0x1fac0, 0x1fac2}, // (nil) ..(nil) + {0x1fad0, 0x1fad6}, // (nil) ..(nil) + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) +}; + +bool intable(struct width_interval* table, int table_length, int c) { + // First quick check for Latin1 etc. characters. + if (c < table[0].start) return false; + + // Binary search in table. + int bot = 0; + int top = table_length - 1; + while (top >= bot) { + int mid = (bot + top) / 2; + if (table[mid].end < c) { + bot = mid + 1; + } else if (table[mid].start > c) { + top = mid - 1; + } else { + return true; + } + } + return false; +} + +} // namespace + +int wcwidth(wchar_t ucs) { + // NOTE: created by hand, there isn't anything identifiable other than + // general Cf category code to identify these, and some characters in Cf + // category code are of non-zero width. + if (ucs == 0 || ucs == 0x034F || (0x200B <= ucs && ucs <= 0x200F) || + ucs == 0x2028 || ucs == 0x2029 || (0x202A <= ucs && ucs <= 0x202E) || + (0x2060 <= ucs && ucs <= 0x2063)) { + return 0; + } + + // C0/C1 control characters. + if (ucs < 32 || (0x07F <= ucs && ucs < 0x0A0)) return -1; + + // Combining characters with zero width. + if (intable(ZERO_WIDTH, sizeof(ZERO_WIDTH) / sizeof(struct width_interval), ucs)) return 0; + + return intable(WIDE_EASTASIAN, sizeof(WIDE_EASTASIAN) / sizeof(struct width_interval), ucs) ? 2 : 1; +} + +int wcswidth(const wchar_t *wcs, size_t n) { + int ret = 0; + for(size_t i = 0; i < n && wcs[i]; i++) { + int cols = wcwidth(wcs[i]); + if (cols < 0) + return -1; + ret += cols; + } + + return ret; +} + +wchar_t *wcsdup(const wchar_t *s) { + size_t len = wcslen(s); + wchar_t *ret = (wchar_t *) malloc(sizeof(wchar_t) * (len + 1)); + if(!ret) + return nullptr; + wmemcpy(ret, s, len + 1); + return ret; +} + +int wcsncasecmp(const wchar_t* s1, const wchar_t* s2, size_t n) { + for(size_t i = 0; i < n; i++) { + wint_t c1 = towlower(s1[i]); + wint_t c2 = towlower(s2[i]); + if(c1 == L'\0' && c2 == L'\0') + return 0; + if(c1 < c2) + return -1; + if(c1 > c2) + return 1; + } + return 0; +} + +int wcscasecmp(const wchar_t *, const wchar_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +size_t wcsnlen(const wchar_t *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/ansi/generic/wctype.cpp b/user/include/mlibc/options/ansi/generic/wctype.cpp new file mode 100644 index 0000000..b89291d --- /dev/null +++ b/user/include/mlibc/options/ansi/generic/wctype.cpp @@ -0,0 +1,9 @@ + +#include +#include +#include +#include + +wctrans_t wctrans(const char *) { MLIBC_STUB_BODY; } +wint_t towctrans(wint_t, wctrans_t) { MLIBC_STUB_BODY; } + diff --git a/user/include/mlibc/options/ansi/include/alloca.h b/user/include/mlibc/options/ansi/include/alloca.h new file mode 100644 index 0000000..edfc80d --- /dev/null +++ b/user/include/mlibc/options/ansi/include/alloca.h @@ -0,0 +1,8 @@ + +#ifndef _ALLOCA_H +#define _ALLOCA_H + +#define alloca __builtin_alloca + +#endif /* _ALLOCA_H */ + diff --git a/user/include/mlibc/options/ansi/include/assert.h b/user/include/mlibc/options/ansi/include/assert.h new file mode 100644 index 0000000..dbad1f0 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/assert.h @@ -0,0 +1,46 @@ + +#ifndef _ASSERT_H +#define _ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* NOTE: This is not ISO C. Declared in LSB */ +__attribute__ ((__noreturn__)) void __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ASSERT_H */ + +#include + +#if __MLIBC_GLIBC_OPTION +# include +#endif + +/* NOTE: [7.2] requires this be outside the include guard */ +#ifdef NDEBUG + +#undef assert +#define assert(ignore) ((void)0) + +#else /* NDEBUG */ + +#undef assert +#define assert(assertion) ((void)((assertion) \ + || (__assert_fail(#assertion, __FILE__, __LINE__, __func__), 0))) + +#endif /* NDEBUG */ + +#ifndef __cplusplus +#undef static_assert +#define static_assert _Static_assert +#endif diff --git a/user/include/mlibc/options/ansi/include/bits/ansi/fenv.h b/user/include/mlibc/options/ansi/include/bits/ansi/fenv.h new file mode 100644 index 0000000..326f8c0 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/bits/ansi/fenv.h @@ -0,0 +1,93 @@ +#ifndef MLIBC_FENV_H +#define MLIBC_FENV_H + +#if defined(__x86_64__) || defined(__i386__) + +#define FE_DENORMAL 2 +#define FE_DIVBYZERO 4 +#define FE_INEXACT 32 +#define FE_INVALID 1 +#define FE_OVERFLOW 8 +#define FE_UNDERFLOW 16 + +#define FE_ALL_EXCEPT (FE_DENORMAL | FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0x400 +#define FE_UPWARD 0x800 +#define FE_TOWARDZERO 0xC00 + +#elif defined(__aarch64__) + +#define FE_INVALID 1 +#define FE_DIVBYZERO 2 +#define FE_OVERFLOW 4 +#define FE_UNDERFLOW 8 +#define FE_INEXACT 16 + +#define FE_ALL_EXCEPT 31 + +#define FE_TONEAREST 0 +#define FE_UPWARD 0x400000 +#define FE_DOWNWARD 0x800000 +#define FE_TOWARDZERO 0xC00000 + +#elif defined(__riscv) && __riscv_xlen == 64 + +#define FE_INEXACT 1 +#define FE_UNDERFLOW 2 +#define FE_OVERFLOW 4 +#define FE_DIVBYZERO 8 +#define FE_INVALID 16 + +#define FE_ALL_EXCEPT 31 + +#define FE_TONEAREST 0 +#define FE_TOWARDZERO 1 +#define FE_DOWNWARD 2 +#define FE_UPWARD 3 + +#elif defined (__m68k__) + +#if __HAVE_68881__ || __mcffpu__ || __HAVE_FPU_ + +#define FE_INEXACT 8 +#define FE_DIVBYZERO 16 +#define FE_UNDERFLOW 32 +#define FE_OVERFLOW 64 +#define FE_INVALID 128 + +#define FE_ALL_EXCEPT 0xf8 + +#define FE_TONEAREST 0 +#define FE_TOWARDZERO 16 +#define FE_DOWNWARD 32 +#define FE_UPWARD 48 + +#else + +#define FE_ALL_EXCEPT 0 +#define FE_TONEAREST 0 + +#endif + +#elif defined(__loongarch64) + +#define FE_INEXACT 0x010000 +#define FE_UNDERFLOW 0x020000 +#define FE_OVERFLOW 0x040000 +#define FE_DIVBYZERO 0x080000 +#define FE_INVALID 0x100000 + +#define FE_ALL_EXCEPT (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID) + +#define FE_TONEAREST 0x000 +#define FE_TOWARDZERO 0x100 +#define FE_UPWARD 0x200 +#define FE_DOWNWARD 0x300 + +#else +#error Unknown architecture +#endif + +#endif /* MLIBC_FENV_H */ diff --git a/user/include/mlibc/options/ansi/include/bits/ansi/time_t.h b/user/include/mlibc/options/ansi/include/bits/ansi/time_t.h new file mode 100644 index 0000000..1c29fa0 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/bits/ansi/time_t.h @@ -0,0 +1,8 @@ + +#ifndef MLIBC_TIME_T +#define MLIBC_TIME_T + +typedef long time_t; + +#endif + diff --git a/user/include/mlibc/options/ansi/include/bits/ansi/timespec.h b/user/include/mlibc/options/ansi/include/bits/ansi/timespec.h new file mode 100644 index 0000000..e4ab91e --- /dev/null +++ b/user/include/mlibc/options/ansi/include/bits/ansi/timespec.h @@ -0,0 +1,13 @@ + +#ifndef MLIBC_TIMESPEC_H +#define MLIBC_TIMESPEC_H + +#include + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +#endif /* MLIBC_TIMESPEC_H */ + diff --git a/user/include/mlibc/options/ansi/include/complex.h b/user/include/mlibc/options/ansi/include/complex.h new file mode 100644 index 0000000..1eae120 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/complex.h @@ -0,0 +1,134 @@ +/* $NetBSD: complex.h,v 1.3 2010/09/15 16:11:30 christos Exp $ */ + +/* + * Written by Matthias Drochner. + * Public domain. + */ + +#ifndef _COMPLEX_H +#define _COMPLEX_H + +#define complex _Complex +#define _Complex_I 1.0fi +#define I _Complex_I + +#define CMPLX(x, y) ((double complex)__builtin_complex((double)(x), (double)(y))) +#define CMPLXF(x, y) ((float complex)__builtin_complex((float)(x), (float)(y))) +#define CMPLXL(x, y) ((long double complex)__builtin_complex((long double)(x), (long double)(y))) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* 7.3.5 Trigonometric functions */ +/* 7.3.5.1 The cacos functions */ +double complex cacos(double complex __x); +float complex cacosf(float complex __x); + +/* 7.3.5.2 The casin functions */ +double complex casin(double complex __x); +float complex casinf(float complex __x); + +/* 7.3.5.1 The catan functions */ +double complex catan(double complex __x); +float complex catanf(float complex __x); + +/* 7.3.5.1 The ccos functions */ +double complex ccos(double complex __x); +float complex ccosf(float complex __x); + +/* 7.3.5.1 The csin functions */ +double complex csin(double complex __x); +float complex csinf(float complex __x); + +/* 7.3.5.1 The ctan functions */ +double complex ctan(double complex __x); +float complex ctanf(float complex __x); + +/* 7.3.6 Hyperbolic functions */ +/* 7.3.6.1 The cacosh functions */ +double complex cacosh(double complex __x); +float complex cacoshf(float complex __x); + +/* 7.3.6.2 The casinh functions */ +double complex casinh(double complex __x); +float complex casinhf(float complex __x); + +/* 7.3.6.3 The catanh functions */ +double complex catanh(double complex __x); +float complex catanhf(float complex __x); + +/* 7.3.6.4 The ccosh functions */ +double complex ccosh(double complex __x); +float complex ccoshf(float complex __x); + +/* 7.3.6.5 The csinh functions */ +double complex csinh(double complex __x); +float complex csinhf(float complex __x); + +/* 7.3.6.6 The ctanh functions */ +double complex ctanh(double complex __x); +float complex ctanhf(float complex __x); + +/* 7.3.7 Exponential and logarithmic functions */ +/* 7.3.7.1 The cexp functions */ +double complex cexp(double complex __x); +float complex cexpf(float complex __x); + +/* 7.3.7.2 The clog functions */ +double complex clog(double complex __x); +float complex clogf(float complex __x); + +/* 7.3.8 Power and absolute-value functions */ +/* 7.3.8.1 The cabs functions */ +/*#ifndef __LIBM0_SOURCE__ */ +/* avoid conflict with historical cabs(struct complex) */ +/* double cabs(double complex __x) __RENAME(__c99_cabs); + float cabsf(float complex __x) __RENAME(__c99_cabsf); + #endif +*/ +double cabs(double complex __x); +float cabsf(float complex __x); + +/* 7.3.8.2 The cpow functions */ +double complex cpow(double complex __x, double complex __y); +float complex cpowf(float complex __x, float complex __y); + +/* 7.3.8.3 The csqrt functions */ +double complex csqrt(double complex __x); +float complex csqrtf(float complex __x); + +/* 7.3.9 Manipulation functions */ +/* 7.3.9.1 The carg functions */ +double carg(double complex __x); +float cargf(float complex __x); + +/* 7.3.9.2 The cimag functions */ +double cimag(double complex __x); +float cimagf(float complex __x); +long double cimagl(long double complex __x); + +/* 7.3.9.3 The conj functions */ +double complex conj(double complex __x); +float complex conjf(float complex __x); +/*long double complex conjl(long double complex __x); */ + +/* 7.3.9.4 The cproj functions */ +double complex cproj(double complex __x); +float complex cprojf(float complex __x); +/*long double complex cprojl(long double complex __x); */ + +/* 7.3.9.5 The creal functions */ +double creal(double complex __x); +float crealf(float complex __x); +long double creall(long double complex __x); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! _COMPLEX_H */ diff --git a/user/include/mlibc/options/ansi/include/ctype.h b/user/include/mlibc/options/ansi/include/ctype.h new file mode 100644 index 0000000..151f1f8 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/ctype.h @@ -0,0 +1,46 @@ +#ifndef _CTYPE_H +#define _CTYPE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* Character classification function [7.4.1] */ +int isalnum(int __c); +int isalpha(int __c); +int isblank(int __c); +int iscntrl(int __c); +int isdigit(int __c); +int isgraph(int __c); +int islower(int __c); +int isprint(int __c); +int ispunct(int __c); +int isspace(int __c); +int isupper(int __c); +int isxdigit(int __c); + +/* glibc extensions. */ +int isascii(int __c); + +/* Character case mapping functions [7.4.2] */ +int tolower(int __c); +int toupper(int __c); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* Borrowed from glibc */ +#define toascii(c) ((c) & 0x7f) + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif /* _CTYPE_H */ diff --git a/user/include/mlibc/options/ansi/include/errno.h b/user/include/mlibc/options/ansi/include/errno.h new file mode 100644 index 0000000..bbdaf2f --- /dev/null +++ b/user/include/mlibc/options/ansi/include/errno.h @@ -0,0 +1,31 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* Some programs define their own errno as an "extern int" if it is not a macro. */ +#define errno __mlibc_errno +extern __thread int __mlibc_errno; + +int *__errno_location(void); + +/* Linux extensions. */ + +extern char *program_invocation_name; +extern char *program_invocation_short_name; +extern char *__progname; +extern char *__progname_full; + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ERRNO_H */ diff --git a/user/include/mlibc/options/ansi/include/fenv.h b/user/include/mlibc/options/ansi/include/fenv.h new file mode 100644 index 0000000..7366706 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/fenv.h @@ -0,0 +1,44 @@ + +#ifndef _FENV_H +#define _FENV_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + __mlibc_uint32 __control_word; + __mlibc_uint32 __status_word; + __mlibc_uint32 __unused[5]; + __mlibc_uint32 __mxcsr; +} fenv_t; + +typedef __mlibc_uint16 fexcept_t; + +#ifndef __MLIBC_ABI_ONLY + +int feclearexcept(int __excepts); +int fegetenv(fenv_t *__envp); +int fegetexceptflag(fexcept_t *__envp, int __excepts); +int fegetround(void); +int feholdexcept(fenv_t *__envp); +int feraiseexcept(int __excepts); +int fesetenv(const fenv_t *__envp); +int fesetexceptflag(const fexcept_t *__envp, int __excepts); +int fesetround(int __round); +int fetestexcept(int __excepts); +int feupdateenv(const fenv_t *__envp); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#define FE_DFL_ENV ((const fenv_t *) -1) + +#endif /* _FENV_H */ + diff --git a/user/include/mlibc/options/ansi/include/inttypes.h b/user/include/mlibc/options/ansi/include/inttypes.h new file mode 100644 index 0000000..5eeeca1 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/inttypes.h @@ -0,0 +1,206 @@ +#ifndef _STDINT_H +#define _STDINT_H + +#include +#include + +/* Even though this is not strictly not-ABI, it is mlibc-printf specific therefore */ +/* gate behind !__MLIBC_ABI_ONLY */ +#ifndef __MLIBC_ABI_ONLY + +#if UINTPTR_MAX == UINT64_MAX +# define __PRI64 "l" +# define __PRIPTR "l" +#else +# define __PRI64 "ll" +# define __PRIPTR "" +#endif + +/* TODO: This is extremly unelegant and fragile. */ +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" +#define PRId16 "d" +#define PRIi16 "i" +#define PRIdLEAST16 "d" +#define PRIiLEAST16 "i" +#define PRIdFAST16 "ld" +#define PRIiFAST16 "li" +#define PRId32 "d" +#define PRIi32 "i" +#define PRIdLEAST32 "d" +#define PRIiLEAST32 "i" +#define PRIdFAST32 "ld" +#define PRIiFAST32 "li" +#define PRId64 __PRI64 "d" +#define PRIi64 __PRI64 "i" +#define PRIdLEAST64 __PRI64 "d" +#define PRIiLEAST64 __PRI64 "i" +#define PRIdFAST64 __PRI64 "d" +#define PRIiFAST64 __PRI64 "i" +#define PRIdMAX __PRI64 "d" +#define PRIiMAX __PRI64 "i" +#define PRIdPTR __PRIPTR "d" +#define PRIiPTR __PRIPTR "i" +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" +#define PRIo16 "o" +#define PRIu16 "u" +#define PRIx16 "x" +#define PRIX16 "X" +#define PRIoLEAST16 "o" +#define PRIuLEAST16 "u" +#define PRIxLEAST16 "x" +#define PRIXLEAST16 "X" +#define PRIoFAST16 "lo" +#define PRIuFAST16 "lu" +#define PRIxFAST16 "lx" +#define PRIXFAST16 "lX" +#define PRIo32 "o" +#define PRIu32 "u" +#define PRIx32 "x" +#define PRIX32 "X" +#define PRIoLEAST32 "o" +#define PRIuLEAST32 "u" +#define PRIxLEAST32 "x" +#define PRIXLEAST32 "X" +#define PRIoFAST32 "lo" +#define PRIuFAST32 "lu" +#define PRIxFAST32 "lx" +#define PRIXFAST32 "lX" +#define PRIo64 __PRI64 "o" +#define PRIu64 __PRI64 "u" +#define PRIx64 __PRI64 "x" +#define PRIX64 __PRI64 "X" +#define PRIoLEAST64 __PRI64 "o" +#define PRIuLEAST64 __PRI64 "u" +#define PRIxLEAST64 __PRI64 "x" +#define PRIXLEAST64 __PRI64 "X" +#define PRIoFAST64 __PRI64 "o" +#define PRIuFAST64 __PRI64 "u" +#define PRIxFAST64 __PRI64 "x" +#define PRIXFAST64 __PRI64 "X" +#define PRIoMAX __PRI64 "o" +#define PRIuMAX __PRI64 "u" +#define PRIxMAX __PRI64 "x" +#define PRIXMAX __PRI64 "X" +#define PRIoPTR __PRIPTR "o" +#define PRIuPTR __PRIPTR "u" +#define PRIxPTR __PRIPTR "x" +#define PRIXPTR __PRIPTR "X" + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 __PRI64 "i" +#define SCNiLEAST8 "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 __PRI64 "i" +#define SCNiFAST8 "hhi" +#define SCNiFAST16 __PRIPTR "i" +#define SCNiFAST32 __PRIPTR "i" +#define SCNiFAST64 __PRI64 "i" +#define SCNiMAX __PRI64 "i" +#define SCNiPTR __PRIPTR "i" + +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 __PRI64 "d" +#define SCNdLEAST8 "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 __PRI64 "d" +#define SCNdFAST8 "hhd" +#define SCNdFAST16 __PRIPTR "d" +#define SCNdFAST32 __PRIPTR "d" +#define SCNdFAST64 __PRI64 "d" +#define SCNdMAX __PRI64 "d" +#define SCNdPTR __PRIPTR "d" + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 __PRI64 "u" +#define SCNuLEAST8 "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 __PRI64 "u" +#define SCNuFAST8 "hhu" +#define SCNuFAST16 __PRIPTR "u" +#define SCNuFAST32 __PRIPTR "u" +#define SCNuFAST64 __PRI64 "u" +#define SCNuMAX __PRI64 "u" +#define SCNuPTR __PRIPTR "u" + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 __PRI64 "o" +#define SCNoLEAST8 "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 __PRI64 "o" +#define SCNoFAST8 "hho" +#define SCNoFAST16 __PRIPTR "o" +#define SCNoFAST32 __PRIPTR "o" +#define SCNoFAST64 __PRI64 "o" +#define SCNoMAX __PRI64 "o" +#define SCNoPTR __PRIPTR "o" + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 __PRI64 "x" +#define SCNxLEAST8 "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 __PRI64 "x" +#define SCNxFAST8 "hhx" +#define SCNxFAST16 __PRIPTR "x" +#define SCNxFAST32 __PRIPTR "x" +#define SCNxFAST64 __PRI64 "x" +#define SCNxMAX __PRI64 "x" +#define SCNxPTR __PRIPTR "x" + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +#ifndef __MLIBC_ABI_ONLY + +intmax_t imaxabs(intmax_t __x); +imaxdiv_t imaxdiv(intmax_t __x, intmax_t __y); +intmax_t strtoimax(const char *__restrict __string, char **__restrict __end, int __base); +uintmax_t strtoumax(const char *__restrict __string, char **__restrict __end, int __base); +intmax_t wcstoimax(const wchar_t *__restrict __string, wchar_t **__restrict __end, int __base); +uintmax_t wcstoumax(const wchar_t *__restrict __string, wchar_t **__restrict __end, int __base); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _STDINT_H */ diff --git a/user/include/mlibc/options/ansi/include/limits.h b/user/include/mlibc/options/ansi/include/limits.h new file mode 100644 index 0000000..8daa542 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/limits.h @@ -0,0 +1,123 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#define CHAR_BIT 8 + +#ifndef MB_LEN_MAX +# define MB_LEN_MAX 4 +#endif + +#ifdef LONG_MAX +# ifdef LONG_MAX == INT32_MAX +# define LONG_BIT 32 +# else +/* Safe assumption */ +# define LONG_BIT 64 +# endif +#elif defined __LONG_MAX__ +# if __LONG_MAX__ == INT32_MAX +# define LONG_BIT 32 +# else +/* Safe assumption */ +# define LONG_BIT 64 +# endif +#else +# error "Unsupported configuration, please define either LONG_MAX or __LONG_MAX__" +#endif + +#undef SCHAR_MIN +#undef SCHAR_MAX +#undef CHAR_MIN +#undef CHAR_MAX +#undef UCHAR_MAX +#undef SHRT_MIN +#undef SHRT_MAX +#undef USHRT_MAX +#undef INT_MIN +#undef INT_MAX +#undef UINT_MAX +#undef LONG_MIN +#undef LONG_MAX +#undef ULONG_MAX +#undef LLONG_MIN +#undef LLONG_MAX +#undef ULLONG_MAX + +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) +#define SCHAR_MAX __SCHAR_MAX__ +#if __SCHAR_MAX__ == __INT_MAX__ +# define UCHAR_MAX (__SCHAR_MAX__ * 2U + 1U) +#else +# define UCHAR_MAX (__SCHAR_MAX__ * 2 + 1) +#endif + +#ifdef __CHAR_UNSIGNED__ +# define CHAR_MAX UCHAR_MAX +# if __SCHAR_MAX__ == __INT_MAX__ +# define CHAR_MIN 0U +# else +# define CHAR_MIN 0 +# endif +#else +# define CHAR_MAX SCHAR_MAX +# define CHAR_MIN SCHAR_MIN +#endif + +#define SHRT_MIN (-__SHRT_MAX__ - 1) +#define SHRT_MAX __SHRT_MAX__ +#if __SHRT_MAX__ == __INT_MAX__ +# define USHRT_MAX (__SHRT_MAX__ * 2U + 1U) +#else +# define USHRT_MAX (__SHRT_MAX__ * 2 + 1) +#endif + +#define INT_MIN (-__INT_MAX__ - 1) +#define INT_MAX __INT_MAX__ +#define UINT_MAX (__INT_MAX__ * 2U + 1U) + +#define LONG_MIN (-__LONG_MAX__ - 1L) +#define LONG_MAX __LONG_MAX__ +#define ULONG_MAX (__LONG_MAX__ * 2UL + 1UL) + +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1LL) +#define LLONG_MAX __LONG_LONG_MAX__ +#define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1ULL) + +#define NAME_MAX 255 +#define PATH_MAX 4096 +#define LINE_MAX 4096 +#define PIPE_BUF 4096 + +#define CHARCLASS_NAME_MAX 14 +#define RE_DUP_MAX 255 + +#if !defined(NGROUPS_MAX) +/* This value is a guaranteed minimum, get the current maximum from sysconf */ +#define NGROUPS_MAX 8 +#endif /* !defined(NGROUPS_MAX) */ + +/* POSIX states 9 is the minimum for NL_ARGMAX */ +#define NL_ARGMAX 9 + +#if INTPTR_MAX == INT64_MAX +# define SSIZE_MAX LONG_MAX +#elif INTPTR_MAX == INT32_MAX +# define SSIZE_MAX INT_MAX +#endif + +#define _POSIX_ARG_MAX 4096 +#define _POSIX_OPEN_MAX 16 +#define _POSIX_HOST_NAME_MAX 255 +#define _POSIX_NAME_MAX 14 +#define _POSIX_TZNAME_MAX 6 +#define _XOPEN_NAME_MAX 255 + +/* This value is a guaranteed minimum, get the current maximum from sysconf */ +#define TZNAME_MAX _POSIX_TZNAME_MAX + +#define PTHREAD_STACK_MIN 16384 +#define PTHREAD_KEYS_MAX 1024 + +#include + +#endif /* _LIMITS_H */ diff --git a/user/include/mlibc/options/ansi/include/locale.h b/user/include/mlibc/options/ansi/include/locale.h new file mode 100644 index 0000000..66bddea --- /dev/null +++ b/user/include/mlibc/options/ansi/include/locale.h @@ -0,0 +1,83 @@ + +#ifndef _LOCALE_H +#define _LOCALE_H + +#include + +#include + +#define LC_ALL 1 +#define LC_COLLATE 2 +#define LC_CTYPE 3 +#define LC_MONETARY 4 +#define LC_NUMERIC 5 +#define LC_TIME 6 +#define LC_MESSAGES 7 +#define LC_MEASUREMENT 11 + +#define LC_GLOBAL_LOCALE ((locale_t) -1L) + +#define LC_CTYPE_MASK (1< +#endif /* __MLIBC_POSIX_OPTION */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LOCALE_H */ + diff --git a/user/include/mlibc/options/ansi/include/math.h b/user/include/mlibc/options/ansi/include/math.h new file mode 100644 index 0000000..a4ffd32 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/math.h @@ -0,0 +1,383 @@ + +#ifndef _MATH_H +#define _MATH_H + +#include + +/* this is a posix extension */ +#define M_E 2.7182818284590452354 +#define M_LOG2E 1.4426950408889634074 +#define M_LOG10E 0.43429448190325182765 +#define M_LN2 0.69314718055994530942 +#define M_LN10 2.30258509299404568402 +#define M_PI 3.14159265358979323846 +#define M_PI_2 1.57079632679489661923 +#define M_PI_4 0.78539816339744830962 +#define M_1_PI 0.31830988618379067154 +#define M_2_PI 0.63661977236758134308 +#define M_2_SQRTPI 1.12837916709551257390 +#define M_SQRT2 1.41421356237309504880 +#define M_SQRT1_2 0.70710678118654752440 +#define M_PIl 3.141592653589793238462643383279502884L + +/* The following two definitions are from musl. */ +#define FP_ILOGBNAN (-1 - (int)(((unsigned)-1) >> 1)) +#define FP_ILOGB0 FP_ILOGBNAN + +#ifdef __cplusplus +extern "C" { +#endif + +typedef double double_t; +typedef float float_t; + +#define HUGE_VAL (__builtin_huge_val()) +#define HUGE_VALF (__builtin_huge_valf()) +#define HUGE_VALL (__builtin_huge_vall()) +#define INFINITY (__builtin_inff()) +#define NAN (__builtin_nanf("")) + +/* [C11/7.12.1 Treatment of error conditions] */ + +#define MATH_ERRNO 1 +#define MATH_ERREXCEPT 2 +#define math_errhandling 3 + +/* [C11/7.12.3 Classification macros] */ + +/* NOTE: fpclassify always returns exactly one of those constants */ +/* However making them bitwise disjoint simplifies isfinite() etc. */ +#define FP_INFINITE 1 +#define FP_NAN 2 +#define FP_NORMAL 4 +#define FP_SUBNORMAL 8 +#define FP_ZERO 16 + +#ifndef __MLIBC_ABI_ONLY + +int __fpclassify(double __x); +int __fpclassifyf(float __x); +int __fpclassifyl(long double __x); + +#define fpclassify(x) \ + (sizeof(x) == sizeof(double) ? __fpclassify(x) : \ + (sizeof(x) == sizeof(float) ? __fpclassifyf(x) : \ + (sizeof(x) == sizeof(long double) ? __fpclassifyl(x) : \ + 0))) + +#define isfinite(x) (fpclassify(x) & (FP_NORMAL | FP_SUBNORMAL | FP_ZERO)) +#define isnan(x) (fpclassify(x) == FP_NAN) +#define isinf(x) (fpclassify(x) == FP_INFINITE) +#define isnormal(x) (fpclassify(x) == FP_NORMAL) + +/* FIXME: this is gcc specific */ +#define signbit(x) (__builtin_signbit(x)) + +/* [C11/7.12.14 Comparison macros] */ +#define isunordered(x,y) (isnan((x)) ? ((void)(y),1) : isnan((y))) + +__MLIBC_INLINE_DEFINITION int __mlibc_isless(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x < __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x < __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessl(long double __x, long double __y) { return !isunordered(__x, __y) && __x < __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequal(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x <= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequalf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x <= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequall(long double __x, long double __y) { return !isunordered(__x, __y) && __x <= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreater(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x != __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreaterf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x != __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreaterl(long double __x, long double __y) { return !isunordered(__x, __y) && __x != __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreater(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x > __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x > __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterl(long double __x, long double __y) { return !isunordered(__x, __y) && __x > __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequal(double_t __x, double_t __y) { return !isunordered(__x, __y) && __x >= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequalf(float_t __x, float_t __y) { return !isunordered(__x, __y) && __x >= __y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequall(long double __x, long double __y) { return !isunordered(__x, __y) && __x >= __y; } + +/* TODO: We chould use _Generic here but that does not work in C++ code. */ +#define __MLIBC_CHOOSE_COMPARISON(x, y, p) ( \ + sizeof((x)+(y)) == sizeof(float) ? p##f(x, y) : \ + sizeof((x)+(y)) == sizeof(double) ? p(x, y) : \ + p##l(x, y) ) + +#define isless(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isless) +#define islessequal(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_islessequal) +#define islessgreater(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_islessgreater) +#define isgreater(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isgreater) +#define isgreaterequal(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isgreaterequal) + +/* this is a gnu extension */ +void sincos(double __x, double *__sin, double *__cos); +void sincosf(float __x, float *__sin, float *__cos); +void sincosl(long double __x, long double *__sin, long double *__cos); + +double exp10(double __x); +float exp10f(float __x); +long double exp10l(long double __x); + +double pow10(double __x); +float pow10f(float __x); +long double pow10l(long double __x); + +/* [C11/7.12.4 Trigonometric functions] */ + +double acos(double __x); +float acosf(float __x); +long double acosl(long double __x); + +double asin(double __x); +float asinf(float __x); +long double asinl(long double __x); + +double atan(double __x); +float atanf(float __x); +long double atanl(long double __x); + +double atan2(double __x, double __y); +float atan2f(float __x, float __y); +long double atan2l(long double __x, long double __y); + +double cos(double __x); +float cosf(float __x); +long double cosl(long double __x); + +double sin(double __x); +float sinf(float __x); +long double sinl(long double __x); + +double tan(double __x); +float tanf(float __x); +long double tanl(long double __x); + +/* [C11/7.12.5 Hyperbolic functions] */ + +double acosh(double __x); +float acoshf(float __x); +long double acoshl(long double __x); + +double asinh(double __x); +float asinhf(float __x); +long double asinhl(long double __x); + +double atanh(double __x); +float atanhf(float __x); +long double atanhl(long double __x); + +double cosh(double __x); +float coshf(float __x); +long double coshl(long double __x); + +double sinh(double __x); +float sinhf(float __x); +long double sinhl(long double __x); + +double tanh(double __x); +float tanhf(float __x); +long double tanhl(long double __x); + +/* [C11/7.12.6 Exponential and logarithmic functions] */ + +double exp(double __x); +float expf(float __x); +long double expl(long double __x); + +double exp2(double __x); +float exp2f(float __x); +long double exp2l(long double __x); + +double expm1(double __x); +float expm1f(float __x); +long double expm1l(long double __x); + +double frexp(double __x, int *__power); +float frexpf(float __x, int *__power); +long double frexpl(long double __x, int *__power); + +int ilogb(double __x); +int ilogbf(float __x); +int ilogbl(long double __x); + +double ldexp(double __x, int __power); +float ldexpf(float __x, int __power); +long double ldexpl(long double __x, int __power); + +double log(double __x); +float logf(float __x); +long double logl(long double __x); + +double log10(double __x); +float log10f(float __x); +long double log10l(long double __x); + +double log1p(double __x); +float log1pf(float __x); +long double log1pl(long double __x); + +double log2(double __x); +float log2f(float __x); +long double log2l(long double __x); + +double logb(double __x); +float logbf(float __x); +long double logbl(long double __x); + +double modf(double __x, double *__integral); +float modff(float __x, float *__integral); +long double modfl(long double __x, long double *__integral); + +double scalbn(double __x, int __power); +float scalbnf(float __x, int __power); +long double scalbnl(long double __x, int __power); + +double scalbln(double __x, long __power); +float scalblnf(float __x, long __power); +long double scalblnl(long double __x, long __power); + +/* [C11/7.12.7 Power and absolute-value functions] */ + +double cbrt(double __x); +float cbrtf(float __x); +long double cbrtl(long double __x); + +double fabs(double __x); +float fabsf(float __x); +long double fabsl(long double __x); + +double hypot(double __x, double __y); +float hypotf(float __x, float __y); +long double hypotl(long double __x, long double __y); + +double pow(double __x, double __y); +float powf(float __x, float __y); +long double powl(long double __x, long double __y); + +double sqrt(double __x); +float sqrtf(float __x); +long double sqrtl(long double __x); + +/* [C11/7.12.8 Error and gamma functions] */ + +double erf(double __x); +float erff(float __x); +long double erfl(long double __x); + +double erfc(double __x); +float erfcf(float __x); +long double erfcl(long double __x); + +double lgamma(double __x); +float lgammaf(float __x); +long double lgammal(long double __x); + +double tgamma(double __x); +float tgammaf(float __x); +long double tgammal(long double __x); + +/* [C11/7.12.9 Nearest integer functions] */ + +double ceil(double __x); +float ceilf(float __x); +long double ceill(long double __x); + +double floor(double __x); +float floorf(float __x); +long double floorl(long double __x); + +double nearbyint(double __x); +float nearbyintf(float __x); +long double nearbyintl(long double __x); + +double rint(double __x); +float rintf(float __x); +long double rintl(long double __x); + +long lrint(double __x); +long lrintf(float __x); +long lrintl(long double __x); + +long long llrint(double __x); +long long llrintf(float __x); +long long llrintl(long double __x); + +double round(double __x); +float roundf(float __x); +long double roundl(long double __x); + +long lround(double __x); +long lroundf(float __x); +long lroundl(long double __x); + +long long llround(double __x); +long long llroundf(float __x); +long long llroundl(long double __x); + +double trunc(double __x); +float truncf(float __x); +long double truncl(long double __x); + +/* [C11/7.12.10 Remainder functions] */ + +double fmod(double __x, double __y); +float fmodf(float __x, float __y); +long double fmodl(long double __x, long double __y); + +double remainder(double __x, double __y); +float remainderf(float __x, float __y); +long double remainderl(long double __x, long double __y); + +double remquo(double __x, double __y, int *__quotient); +float remquof(float __x, float __y, int *__quotient); +long double remquol(long double __x, long double __y, int *__quotient); + +/* [C11/7.12.11 Manipulation functions] */ + +double copysign(double __x, double __sign); +float copysignf(float __x, float __sign); +long double copysignl(long double __x, long double __sign); + +double nan(const char *__tag); +float nanf(const char *__tag); +long double nanl(const char *__tag); + +double nextafter(double __x, double __dir); +float nextafterf(float __x, float __dir); +long double nextafterl(long double __x, long double __dir); + +double nexttoward(double __x, long double __dir); +float nexttowardf(float __x, long double __dir); +long double nexttowardl(long double __x, long double __dir); + +/* [C11/7.12.12 Maximum, minimum and positive difference functions] */ + +double fdim(double __x, double __y); +float fdimf(float __x, float __y); +long double fdiml(long double __x, long double __y); + +double fmax(double __x, double __y); +float fmaxf(float __x, float __y); +long double fmaxl(long double __x, long double __y); + +double fmin(double __x, double __y); +float fminf(float __x, float __y); +long double fminl(long double __x, long double __y); + +/* [C11/7.12.13 Floating multiply-add] */ + +double fma(double __x, double __y, double __z); +float fmaf(float __x, float __y, float __z); +long double fmal(long double __x, long double __y, long double __z); + +extern int signgam; +#define __signgam signgam + +/* BSD floating-point classification functions - obsolete */ + +int finite(double __x); +int finitef(float __x); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MATH_H */ + diff --git a/user/include/mlibc/options/ansi/include/mlibc/ansi-sysdeps.hpp b/user/include/mlibc/options/ansi/include/mlibc/ansi-sysdeps.hpp new file mode 100644 index 0000000..2fbe4a4 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/mlibc/ansi-sysdeps.hpp @@ -0,0 +1,72 @@ +#ifndef MLIBC_ANSI_SYSDEPS +#define MLIBC_ANSI_SYSDEPS + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rusage; + +namespace [[gnu::visibility("hidden")]] mlibc { + +[[noreturn]] void sys_exit(int status); +[[noreturn, gnu::weak]] void sys_thread_exit(); + +// If *stack is not null, it should point to the lowest addressable byte of the stack. +// Returns the new stack pointer in *stack and the stack base in *stack_base. +[[gnu::weak]] int sys_prepare_stack(void **stack, void *entry, void *user_arg, void* tcb, size_t *stack_size, size_t *guard_size, void **stack_base); +[[gnu::weak]] int sys_clone(void *tcb, pid_t *pid_out, void *stack); + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time); +int sys_futex_wake(int *pointer); + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +[[gnu::weak]] int sys_flock(int fd, int options); + +[[gnu::weak]] int sys_open_dir(const char *path, int *handle); +[[gnu::weak]] int sys_read_entries(int handle, void *buffer, size_t max_size, + size_t *bytes_read); + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written); +[[gnu::weak]] int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read); + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset); +int sys_close(int fd); + +int sys_clock_get(int clock, time_t *secs, long *nanos); +[[gnu::weak]] int sys_clock_set(int clock, time_t secs, long nanos); +[[gnu::weak]] int sys_clock_getres(int clock, time_t *secs, long *nanos); +[[gnu::weak]] int sys_sleep(time_t *secs, long *nanos); +// In contrast to the isatty() library function, the sysdep function uses return value +// zero (and not one) to indicate that the file is a terminal. +[[gnu::weak]] int sys_isatty(int fd); +[[gnu::weak]] int sys_rmdir(const char *path); +[[gnu::weak]] int sys_unlinkat(int dirfd, const char *path, int flags); +[[gnu::weak]] int sys_rename(const char *path, const char *new_path); +[[gnu::weak]] int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path); + +[[gnu::weak]] int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve); +[[gnu::weak]] int sys_sigaction(int, const struct sigaction *__restrict, + struct sigaction *__restrict); + +[[gnu::weak]] int sys_fork(pid_t *child); +[[gnu::weak]] int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid); +[[gnu::weak]] int sys_execve(const char *path, char *const argv[], char *const envp[]); + +[[gnu::weak]] pid_t sys_getpid(); +[[gnu::weak]] int sys_kill(int, int); + +} //namespace mlibc + +#endif // MLIBC_ANSI_SYSDEPS diff --git a/user/include/mlibc/options/ansi/include/mlibc/environment.hpp b/user/include/mlibc/options/ansi/include/mlibc/environment.hpp new file mode 100644 index 0000000..7fd5cf9 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/mlibc/environment.hpp @@ -0,0 +1,10 @@ +#ifndef MLIBC_ENVIRONMENT_HPP +#define MLIBC_ENVIRONMENT_HPP + +namespace mlibc { + +int putenv(char *string); + +} // namespace mlibc + +#endif // MLIBC_ENVIRONMENT_HPP diff --git a/user/include/mlibc/options/ansi/include/mlibc/file-io.hpp b/user/include/mlibc/options/ansi/include/mlibc/file-io.hpp new file mode 100644 index 0000000..75beca4 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/mlibc/file-io.hpp @@ -0,0 +1,130 @@ +#ifndef MLIBC_FILE_IO_HPP +#define MLIBC_FILE_IO_HPP + +#include + +#include +#include +#include + +namespace mlibc { + +enum class stream_type { + unknown, + file_like, + pipe_like +}; + +enum class buffer_mode { + unknown, + no_buffer, + line_buffer, + full_buffer +}; +struct StdioLock { + bool uselock = true; + RecursiveFutexLock futexlock; + void lock() { + if (uselock) { + futexlock.lock(); + } + + } + void unlock() { + if (uselock) { + futexlock.unlock(); + } + } + void try_lock() { + if (uselock) { + futexlock.try_lock(); + } + } +}; +struct abstract_file : __mlibc_file_base { +public: + abstract_file(void (*do_dispose)(abstract_file *) = nullptr); + + abstract_file(const abstract_file &) = delete; + + abstract_file &operator= (const abstract_file &) = delete; + + virtual ~abstract_file(); + + void dispose(); + + virtual int close() = 0; + virtual int reopen(const char *path, const char *mode) = 0; + + int read(char *buffer, size_t max_size, size_t *actual_size); + int write(const char *buffer, size_t max_size, size_t *actual_size); + int unget(char c); + + int update_bufmode(buffer_mode mode); + + void purge(); + int flush(); + + int tell(off_t *current_offset); + int seek(off_t offset, int whence); + +protected: + virtual int determine_type(stream_type *type) = 0; + virtual int determine_bufmode(buffer_mode *mode) = 0; + virtual int io_read(char *buffer, size_t max_size, size_t *actual_size) = 0; + virtual int io_write(const char *buffer, size_t max_size, size_t *actual_size) = 0; + virtual int io_seek(off_t offset, int whence, off_t *new_offset) = 0; + + int _reset(); +private: + int _init_type(); + int _init_bufmode(); + + int _write_back(); + int _save_pos(); + + void _ensure_allocation(); + + stream_type _type; + buffer_mode _bufmode; + void (*_do_dispose)(abstract_file *); + +public: + // lock for file operations + StdioLock _lock; + // All files are stored in a global linked list, so that they can be flushed at exit(). + frg::default_list_hook _list_hook; +}; + +struct fd_file : abstract_file { + fd_file(int fd, void (*do_dispose)(abstract_file *) = nullptr, bool force_unbuffered = false); + + int fd(); + + int close() override; + int reopen(const char *path, const char *mode) override; + + static int parse_modestring(const char *mode); + +protected: + int determine_type(stream_type *type) override; + int determine_bufmode(buffer_mode *mode) override; + + int io_read(char *buffer, size_t max_size, size_t *actual_size) override; + int io_write(const char *buffer, size_t max_size, size_t *actual_size) override; + int io_seek(off_t offset, int whence, off_t *new_offset) override; + +private: + // Underlying file descriptor. + int _fd; + bool _force_unbuffered; +}; + +template +void file_dispose_cb(abstract_file *base) { + frg::destruct(getAllocator(), static_cast(base)); +} + +} // namespace mlibc + +#endif // MLIBC_FILE_IO_HPP diff --git a/user/include/mlibc/options/ansi/include/setjmp.h b/user/include/mlibc/options/ansi/include/setjmp.h new file mode 100644 index 0000000..1a7740e --- /dev/null +++ b/user/include/mlibc/options/ansi/include/setjmp.h @@ -0,0 +1,57 @@ + +#ifndef _SETJMP_H +#define _SETJMP_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* [C11/7.13] Non-local jumps */ + +typedef struct __jmp_buf { + struct __mlibc_jmpbuf_register_state __reg_state; +} jmp_buf[1]; + +#ifndef __MLIBC_ABI_ONLY + +__attribute__((__returns_twice__)) int setjmp(jmp_buf __buffer); +__attribute__((__noreturn__)) void longjmp(jmp_buf __buffer, int __value); + +/* setjmp is defined as a function macro in the ISO C standard */ +#define setjmp(env) setjmp(env) + +#if __MLIBC_POSIX_OPTION +__attribute__((__returns_twice__)) int _setjmp(jmp_buf __buffer); +/* POSIX-2017.1 says _longjmp shall be declared as a function */ +__attribute__((__noreturn__)) void _longjmp(jmp_buf __buffer, int __value); +#endif /* __MLIBC_POSIX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +/* POSIX Non-local jumps signal extensions */ + +typedef struct __sigjmp_buf { + struct __mlibc_jmpbuf_register_state __reg_state; + int __savesigs; + sigset_t __sigset; +} sigjmp_buf[1]; + +#ifndef __MLIBC_ABI_ONLY + +#if __MLIBC_POSIX_OPTION +__attribute__((__returns_twice__)) int sigsetjmp(sigjmp_buf __buffer, int __savesigs); +__attribute__((__noreturn__)) void siglongjmp(sigjmp_buf __buffer, int __value); +#endif /* __MLIBC_POSIX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SETJMP_H */ + diff --git a/user/include/mlibc/options/ansi/include/signal.h b/user/include/mlibc/options/ansi/include/signal.h new file mode 100644 index 0000000..69eee4a --- /dev/null +++ b/user/include/mlibc/options/ansi/include/signal.h @@ -0,0 +1,48 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* [7.14] Signal handling basics */ + +typedef int sig_atomic_t; + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +#ifndef __MLIBC_ABI_ONLY + +/* [7.14.1] signal() function */ + +__sighandler signal(int __sig, __sighandler __handler); + +/* [7.14.2] raise() function */ + +int raise(int __sig); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define _NSIG NSIG + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#if __MLIBC_GLIBC_OPTION +# include +#endif + +#endif /* _SIGNAL_H */ diff --git a/user/include/mlibc/options/ansi/include/stdc-predef.h b/user/include/mlibc/options/ansi/include/stdc-predef.h new file mode 100644 index 0000000..a0e3e92 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/stdc-predef.h @@ -0,0 +1,6 @@ +#ifndef _STDC_PREDEF_H +#define _STDC_PREDEF_H + +#define __STDC_ISO_10646__ 201206L + +#endif /* _STDC_PREDEF_H */ diff --git a/user/include/mlibc/options/ansi/include/stdio.h b/user/include/mlibc/options/ansi/include/stdio.h new file mode 100644 index 0000000..8b6de9f --- /dev/null +++ b/user/include/mlibc/options/ansi/include/stdio.h @@ -0,0 +1,231 @@ + +#ifndef _STDIO_H +#define _STDIO_H + +#include +#include +#include +#include +#include + +/* Glibc extensions require ssize_t. */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* [C11-7.21.1] I/O related types */ + +#define __MLIBC_EOF_BIT 1 +#define __MLIBC_ERROR_BIT 2 + +struct __mlibc_file_base { + /* Buffer for I/O operations. */ + /* We reserve a few extra bytes for ungetc operations. This means */ + /* that __buffer_ptr will point a few bytes *into* the allocation. */ + char *__buffer_ptr; + + /* Number of bytes the buffer can hold. */ + size_t __buffer_size; + + /* Current offset inside the buffer. */ + size_t __offset; + + /* Position inside the buffer that matches the current file pointer. */ + size_t __io_offset; + + /* Valid region of the buffer. */ + size_t __valid_limit; + + /* Begin and end of the dirty region inside the buffer. */ + size_t __dirty_begin; + size_t __dirty_end; + + /* This points to the same place as __buffer_ptr, or a few bytes earlier */ + /* if there are bytes pushed by ungetc. If buffering is disabled, calls */ + /* to ungetc will trigger an allocation. */ + char *__unget_ptr; + + /* 0 if we are currently reading from the buffer. */ + /* 1 if we are currently writing to the buffer. */ + /* This is only really important for pipe-like streams. */ + int __io_mode; + + /* EOF and error bits. */ + int __status_bits; +}; + +typedef off_t fpos_t; + +/* [C11-7.21.1] I/O related macros */ + +#define _IOFBF 1 +#define _IOLBF 2 +#define _IONBF 3 + +#define BUFSIZ 512 + +#define EOF (-1) + +#define FOPEN_MAX 1024 +#define FILENAME_MAX 256 +#define L_tmpnam 256 + +#define TMP_MAX 1024 + +#ifndef __MLIBC_ABI_ONLY + +extern FILE *stderr; +extern FILE *stdin; +extern FILE *stdout; + +/* [C11-7.21.4] Operations on files */ + +int remove(const char *__filename); +int rename(const char *__old_path, const char *__new_path); +int renameat(int __olddirfd, const char *__old_path, int __newdirfd, const char *__new_path); +FILE *tmpfile(void); +char *tmpnam(char *__buffer); + +/* [C11-7.21.5] File access functions */ + +int fclose(FILE *__stream); +int fflush(FILE *__stream); +FILE *fopen(const char *__restrict __filename, const char *__restrict __mode); +FILE *freopen(const char *__restrict __filename, const char *__restrict __mode, FILE *__restrict __stream); +void setbuf(FILE *__restrict __stream, char *__restrict __buffer); +int setvbuf(FILE *__restrict __stream, char *__restrict __buffer, int __mode, size_t __size); +void setlinebuf(FILE *__stream); +void setbuffer(FILE *__stream, char *__buffer, size_t __size); + +/* [C11-7.21.6] Formatted input/output functions */ + +__attribute__((__format__(__printf__, 2, 3))) +int fprintf(FILE *__restrict __stream, const char *__restrict __format, ...); + +__attribute__((__format__(__scanf__, 2, 3))) +int fscanf(FILE *__restrict __stream, const char *__restrict __format, ...); + +__attribute__((__format__(__printf__, 1, 2))) +int printf(const char *__restrict __format, ...); + +__attribute__((__format__(__scanf__, 1, 2))) +int scanf(const char *__restrict __format, ...); + +__attribute__((__format__(__printf__, 3, 4))) +int snprintf(char *__restrict __buffer, size_t __max_size, const char *__restrict __format, ...); + +__attribute__((__format__(__printf__, 2, 3))) +int sprintf(char *__restrict __buffer, const char *__restrict __format, ...); + +__attribute__((__format__(__scanf__, 2, 3))) +int sscanf(const char *__restrict __buffer, const char *__restrict __format, ...); + +__attribute__((__format__(__printf__, 2, 0))) +int vfprintf(FILE *__restrict __stream, const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__scanf__, 2, 0))) +int vfscanf(FILE *__restrict __stream, const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__printf__, 1, 0))) +int vprintf(const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__scanf__, 1, 0))) +int vscanf(const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__printf__, 3, 0))) +int vsnprintf(char *__restrict __buffer, size_t __max_size, + const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__printf__, 2, 0))) +int vsprintf(char *__restrict __buffer, const char *__restrict __format, __builtin_va_list __args); + +__attribute__((__format__(__scanf__, 2, 0))) +int vsscanf(const char *__restrict __buffer, const char *__restrict __format, __builtin_va_list __args); + +/* this is a gnu extension */ +__attribute__((__format__(__printf__, 2, 0))) +int vasprintf(char **__buffer, const char *__format, __builtin_va_list __args); + +/* [C11-7.21.7] Character input/output functions */ + +int fgetc(FILE *__stream); +char *fgets(char *__restrict __buffer, int __max_size, FILE *__restrict __stream); +int fputc(int __c, FILE *__stream); +int fputs(const char *__restrict __string, FILE *__restrict __stream); +char *gets(char *__s); +int getc(FILE *__stream); +int getchar(void); +int putc(int __c, FILE *__stream); +int putchar(int __c); +int puts(const char *__string); +int ungetc(int __c, FILE *__stream); + +/* [C11-7.21.8] Direct input/output functions */ + +size_t fread(void *__restrict __buffer, size_t __size, size_t __count, FILE *__restrict __stream); +size_t fwrite(const void *__restrict __buffer, size_t __size, size_t __count, FILE *__restrict __stream); + +/* [C11-7.21.9] File positioning functions */ + +int fgetpos(FILE *__restrict __stream, fpos_t *__restrict __position); +int fseek(FILE *__stream, long __offset, int __whence); +int fsetpos(FILE *__stream, const fpos_t *__position); +long ftell(FILE *__stream); +void rewind(FILE *__stream); + +/* [C11-7.21.10] Error handling functions */ + +void clearerr(FILE *__stream); +int feof(FILE *__stream); +int ferror(FILE *__stream); +void perror(const char *__string); + +/* POSIX unlocked I/O extensions. */ + +int getc_unlocked(FILE *__stream); +int getchar_unlocked(void); +int putc_unlocked(int __c, FILE *__stream); +int putchar_unlocked(int __c); + +/* GLIBC extensions. */ + +ssize_t getline(char **__linep, size_t *__sizep, FILE *__stream); +ssize_t getdelim(char **__linep, size_t *__sizep, int __delim, FILE *__stream); + +__attribute__((__format__(__printf__, 2, 3))) +int asprintf(char **__buffer, const char *__format, ...); + +/* Linux unlocked I/O extensions. */ + +void flockfile(FILE *__stream); +void funlockfile(FILE *__stream); +int ftrylockfile(FILE *__stream); + +void clearerr_unlocked(FILE *__stream); +int feof_unlocked(FILE *__stream); +int ferror_unlocked(FILE *__stream); +int fileno_unlocked(FILE *__stream); +int fflush_unlocked(FILE *__stream); +int fgetc_unlocked(FILE *__stream); +int fputc_unlocked(int __c, FILE *__stream); +size_t fread_unlocked(void *__restrict __buffer, size_t __size, size_t __count, FILE *__restrict __stream); +size_t fwrite_unlocked(const void *__restrict __buffer, size_t __size, size_t __count, FILE *__restrict __stream); + +char *fgets_unlocked(char *__restrict __buffer, int __size, FILE *__restrict __stream); +int fputs_unlocked(const char *__restrict __buffer, FILE *__restrict __stream); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif /* _STDIO_H */ + diff --git a/user/include/mlibc/options/ansi/include/stdlib.h b/user/include/mlibc/options/ansi/include/stdlib.h new file mode 100644 index 0000000..9df8b08 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/stdlib.h @@ -0,0 +1,131 @@ +#ifndef _STDLIB_H +#define _STDLIB_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* [7.22] General utilities */ + +typedef struct { + int quot, rem; +} div_t; + +typedef struct { + long quot, rem; +} ldiv_t; + +typedef struct { + long long quot, rem; +} lldiv_t; + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#define RAND_MAX 0x7FFFFFFF + +/* TODO: this should not be a compile-time constant */ +#define MB_CUR_MAX ((size_t)4) + +#ifndef __MLIBC_ABI_ONLY + +/* [7.22.1] Numeric conversion functions */ + +double atof(const char *__string); +int atoi(const char *__string); +long atol(const char *__string); +long long atoll(const char *__string); +double strtod(const char *__restrict __string, char **__restrict __end); +float strtof(const char *__restrict __string, char **__restrict __end); +long double strtold(const char *__restrict __string, char **__restrict __end); +long strtol(const char *__restrict __string, char **__restrict __end, int __base); +long long strtoll(const char *__restrict __string, char **__restrict __end, int __base); +unsigned long strtoul(const char *__restrict __string, char **__restrict __end, int __base); +unsigned long long strtoull(const char *__restrict __string, char **__restrict __end, int __base); + +/* [7.22.2] Pseudo-random sequence generation functions */ + +int rand(void); +int rand_r(unsigned *__seed); +void srand(unsigned int __seed); + +/* [7.22.3] Memory management functions */ + +void *aligned_alloc(size_t __alignment, size_t __size); +void *calloc(size_t __count, size_t __size); +void free(void *__pointer); +void *malloc(size_t __size); +void *realloc(void *__pointer, size_t __size); + +int posix_memalign(void **__out, size_t __alignment, size_t __size); + +/* [7.22.4] Communication with the environment */ + +__attribute__((__noreturn__)) void abort(void); +int atexit(void (*__func)(void)); +int at_quick_exit(void (*__func)(void)); +__attribute__((__noreturn__)) void exit(int __status); +__attribute__((__noreturn__)) void _Exit(int __status); +char *getenv(const char *__name); +__attribute__((__noreturn__)) void quick_exit(int __status); +int system(const char *__string); + +/* GLIBC extension. */ +char *mktemp(char *__pattern); + +/* [7.22.5] Searching and sorting utilities */ + +void *bsearch(const void *__key, const void *__base, size_t __count, size_t __size, + int (*__compare)(const void *__a, const void *__b)); +void qsort(void *__base, size_t __count, size_t __size, + int (*__compare)(const void *__a, const void *__b)); +void qsort_r(void *__base, size_t __nmemb, size_t __size, + int (*__compar)(const void *__a, const void *__b, void *__arg), + void *__arg); + +/* [7.22.6] Integer arithmetic functions */ + +int abs(int __number); +long labs(long __number); +long long llabs(long long __number); + +div_t div(int __number, int __denom); +ldiv_t ldiv(long __number, long __denom); +lldiv_t lldiv(long long __number, long long __denom); + +/* [7.22.7] Multibyte character conversion functions */ + +int mblen(const char *__mbs, size_t __limit); +int mbtowc(wchar_t *__restrict __wc, const char *__restrict __mb_chr, size_t __max_size); +int wctomb(char *__mb_chr, wchar_t __wc); + +/* [7.22.8] Multibyte string conversion functions */ + +size_t mbstowcs(wchar_t *__restrict __wc_string, const char *__restrict __mb_string, size_t __max_size); +size_t wcstombs(char *__restrict __mb_string, const wchar_t *__restrict __wc_string, size_t __max_size); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_BSD_OPTION +# include +#endif +#if __MLIBC_POSIX_OPTION +# include +#endif +#if __MLIBC_GLIBC_OPTION +# include +#endif + +#endif /* _STDLIB_H */ + diff --git a/user/include/mlibc/options/ansi/include/string.h b/user/include/mlibc/options/ansi/include/string.h new file mode 100644 index 0000000..cad9dc4 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/string.h @@ -0,0 +1,112 @@ +#ifndef _STRING_H +#define _STRING_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* [7.24.2] Copying functions */ + +void *memcpy(void *__restrict __dest, const void *__restrict __src, size_t __size); +void *memmove(void *__dest, const void *__src, size_t __size); +char *strcpy(char *__restrict __dest, const char *src); +char *strncpy(char *__restrict __dest, const char *__src, size_t __max_size); + +/* [7.24.3] Concatenation functions */ + +char *strcat(char *__restrict __dest, const char *__restrict __src); +char *strncat(char *__restrict __dest, const char *__restrict __src, size_t __max_size); + +/* [7.24.4] Comparison functions */ + +int memcmp(const void *__a, const void *__b, size_t __size); +int strcmp(const char *__a, const char *__b); +int strcoll(const char *__a, const char *__b); +int strncmp(const char *__a, const char *__b, size_t __max_size); +size_t strxfrm(char *__restrict __dest, const char *__restrict __src, size_t __max_size); + +/* [7.24.5] Search functions */ + +void *memchr(const void *__s, int __c, size_t __size); +char *strchr(const char *__s, int __c); +size_t strcspn(const char *__s, const char *__chrs); +char *strpbrk(const char *__s, const char *__chrs); +char *strrchr(const char *__s, int __c); +size_t strspn(const char *__s, const char *__chrs); +char *strstr(const char *__pattern, const char *__s); +char *strtok(char *__restrict __s, const char *__restrict __delimiter); + +/* This is a GNU extension. */ +char *strchrnul(const char * __s, int __c); + +/* [7.24.6] Miscellaneous functions */ + +void *memset(void *__dest, int __c, size_t __size); +char *strerror(int __errnum); +size_t strlen(const char *__s); + +#endif /* !__MLIBC_ABI_ONLY */ + +#if __MLIBC_POSIX_OPTION && defined(_DEFAULT_SOURCE) +#include +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* POSIX extensions. */ +#if defined(_GNU_SOURCE) +char *strerror_r(int __errnum, char *__buffer, size_t __size) __asm__("__gnu_strerror_r"); +#else +int strerror_r(int __errnum, char *__buffer, size_t __size); +#endif + +void *mempcpy(void *__dest, const void *__src, size_t __size); + +/* GNU extensions. */ +int strverscmp(const char *__l0, const char *__r0); +int ffsl(long __i); +int ffsll(long long __i); +void *memmem(const void *__haystack, size_t __haystacklen, const void *__needle, size_t __needlelen); + +/* Handling the basename mess: + * If is included *at all*, we use the XPG-defined basename + * implementation, otherwise, we use the GNU one. Since our ABI previously + * provided the XPG one under basename, we'll have to diverge from GNU here and + * provide __mlibc_gnu_basename instead. + */ +#if __MLIBC_GLIBC_OPTION && defined(_GNU_SOURCE) && !defined(basename) +char *__mlibc_gnu_basename_c(const char *__path); + +# ifdef __cplusplus +extern "C++" { +static inline const char *__mlibc_gnu_basename(const char *__path) { + return __mlibc_gnu_basename_c(__path); +} +static inline char *__mlibc_gnu_basename(char *__path) { + return __mlibc_gnu_basename_c(__path); +} +} +# else +# define __mlibc_gnu_basename __mlibc_gnu_basename_c +# endif + +#define basename __mlibc_gnu_basename +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif /* _STRING_H */ diff --git a/user/include/mlibc/options/ansi/include/threads.h b/user/include/mlibc/options/ansi/include/threads.h new file mode 100644 index 0000000..dab2c9b --- /dev/null +++ b/user/include/mlibc/options/ansi/include/threads.h @@ -0,0 +1,61 @@ +#ifndef _THREADS_H +#define _THREADS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum { + mtx_plain, + mtx_recursive, + mtx_timed +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem +}; + +typedef struct __mlibc_thread_data *thrd_t; +typedef struct __mlibc_mutex mtx_t; +typedef struct __mlibc_cond cnd_t; +#ifndef __cplusplus +#define thread_local _Thread_local +#endif + +typedef int (*thrd_start_t)(void* __arg); + +#ifndef __MLIBC_ABI_ONLY + +int thrd_create(thrd_t *__thr, thrd_start_t __func, void *__arg); +int thrd_equal(thrd_t __lhs, thrd_t __rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec *__duration, struct timespec *__remaining); +void thrd_yield(void); +int thrd_detach(thrd_t __thr); +int thrd_join(thrd_t __thr, int *__res); +__attribute__((__noreturn__)) void thrd_exit(int __res); + +int mtx_init(mtx_t *__mtx, int __type); +void mtx_destroy(mtx_t *__mtx); +int mtx_lock(mtx_t *__mtx); +int mtx_unlock(mtx_t *__mtx); + +int cnd_init(cnd_t *__cond); +void cnd_destroy(cnd_t *__cond); +int cnd_broadcast(cnd_t *__cond); +int cnd_wait(cnd_t *__cond, mtx_t *__mtx); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _THREADS_H */ + diff --git a/user/include/mlibc/options/ansi/include/time.h b/user/include/mlibc/options/ansi/include/time.h new file mode 100644 index 0000000..f54fd13 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/time.h @@ -0,0 +1,142 @@ +#ifndef _TIME_H +#define _TIME_H + +#include +#include +#include +#include +#include + +/* [7.27.1] Components of time */ + +#define CLOCKS_PER_SEC ((clock_t)1000000) + +#define TIME_UTC 1 + +/* POSIX extensions. */ + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_MONOTONIC_RAW 4 +#define CLOCK_REALTIME_COARSE 5 +#define CLOCK_MONOTONIC_COARSE 6 +#define CLOCK_BOOTTIME 7 +#define CLOCK_REALTIME_ALARM 8 +#define CLOCK_BOOTTIME_ALARM 9 +#define CLOCK_TAI 11 + +#ifdef __cplusplus +extern "C" { +#endif + +/* [7.27.1] Components of time */ + +typedef long clock_t; /* Matches Linux' ABI. */ + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +#ifndef __MLIBC_ABI_ONLY + +/* [7.27.2] Time manipulation functions */ + +clock_t clock(void); +double difftime(time_t __a, time_t __b); +time_t mktime(struct tm *__ptr); +time_t time(time_t *__timer); +int timespec_get(struct timespec *__ptr, int __base); + +/* [7.27.3] Time conversion functions */ + +char *asctime(const struct tm *__ptr); +char *ctime(const time_t *__timer); +struct tm *gmtime(const time_t *__timer); +struct tm *gmtime_r(const time_t *__restrict __timer, struct tm *__restrict __result); +struct tm *localtime(const time_t *__timer); +size_t strftime(char *__restrict __dest, size_t __max_size, + const char *__restrict __format, const struct tm *__restrict __ptr); + +void tzset(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +/* POSIX extensions. */ + +#if __MLIBC_POSIX_OPTION +# include +# include +#endif /* __MLIBC_POSIX_OPTION */ + +#include + +#define TIMER_ABSTIME 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +extern int daylight; +extern long timezone; +extern char *tzname[2]; + +int nanosleep(const struct timespec *__req, struct timespec *__rem); + +int clock_getres(clockid_t __clockid, struct timespec *__res); +int clock_gettime(clockid_t __clockid, struct timespec *__res); +int clock_nanosleep(clockid_t __clockid, int __flags, const struct timespec *__req, struct timespec *__rem); +int clock_settime(clockid_t __clockid, const struct timespec *__time); + +struct tm *localtime_r(const time_t *__timer, struct tm *__buf); +char *asctime_r(const struct tm *__tm, char *__buf); +char *ctime_r(const time_t *__timer, char *__buf); + +#if __MLIBC_POSIX_OPTION +#include +char *strptime(const char *__restrict __buf, const char *__restrict __format, + struct tm *__restrict __tm); +int clock_getcpuclockid(pid_t __pid, clockid_t *__clockid); +#endif /* __MLIBC_POSIX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +/* GNU extensions. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +time_t timelocal(struct tm *__tm); +time_t timegm(struct tm *__tm); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TIME_H */ diff --git a/user/include/mlibc/options/ansi/include/uchar.h b/user/include/mlibc/options/ansi/include/uchar.h new file mode 100644 index 0000000..5dcfce1 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/uchar.h @@ -0,0 +1,28 @@ +#ifndef _UCHAR_H +#define _UCHAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* These are builtin types since C++11. */ +#if !defined(__cplusplus) || __cplusplus < 201100L +typedef __CHAR16_TYPE__ char16_t; +typedef __CHAR32_TYPE__ char32_t; +#endif + +#ifndef __MLIBC_ABI_ONLY + +size_t c32rtomb(char *__restrict __s, char32_t __c32, mbstate_t *__restrict __ps); +size_t mbrtoc32(char32_t *__restrict __pc32, const char *__restrict __pmb, size_t __max, mbstate_t *__restrict __ps); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UCHAR_H */ diff --git a/user/include/mlibc/options/ansi/include/wchar.h b/user/include/mlibc/options/ansi/include/wchar.h new file mode 100644 index 0000000..6a58f97 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/wchar.h @@ -0,0 +1,128 @@ +#ifndef _WCHAR_H +#define _WCHAR_H + +#include +#include +#include +#include +#include +#include +#include + +#define WEOF 0xffffffffU + +#ifdef __cplusplus +extern "C" { +#endif + +/* MISSING: struct tm */ + +#ifndef __MLIBC_ABI_ONLY + +/* [7.28.2] Wide formatted I/O functions */ + +int fwprintf(FILE *__restrict __stream, const wchar_t *__restrict __format, ...); +int fwscanf(FILE *__restrict __stream, const wchar_t *__restrict __format, ...); +int vfwprintf(FILE *__restrict __stream, const wchar_t *__restrict __format, __builtin_va_list __args); +int vfwscanf(FILE *__restrict __stream, const wchar_t *__restrict __format, __builtin_va_list __args); + +int swprintf(wchar_t *__restrict __buffer, size_t __max_size, const wchar_t *__restrict __format, ...); +int swscanf(wchar_t *__restrict __buffer, const wchar_t *__restrict __format, ...); +int vswprintf(wchar_t *__restrict __buffer, size_t __max_size, const wchar_t *__restrict __format, __builtin_va_list __args); +int vswscanf(wchar_t *__restrict __buffer, const wchar_t *__restrict __format, __builtin_va_list __args); + +int wprintf(const wchar_t *__restrict __format, ...); +int wscanf(const wchar_t *__restrict __format, ...); +int vwprintf(const wchar_t *__restrict __format, __builtin_va_list __args); +int vwscanf(const wchar_t *__restrict __format, __builtin_va_list __args); + +/* [7.28.3] Wide character I/O functions */ + +wint_t fgetwc(FILE *__stream); +wchar_t *fgetws(wchar_t *__restrict __buffer, int __size, FILE *__restrict __stream); +wint_t fputwc(wchar_t __wc, FILE *__stream); +int fputws(const wchar_t *__restrict __buffer, FILE *__restrict __stream); +int fwide(FILE *__stream, int __mode); +wint_t getwc(FILE *__stream); +wint_t getwchar(void); +wint_t putwc(wchar_t __wc, FILE *__stream); +wint_t putwchar(wchar_t __wc); +wint_t ungetwc(wint_t __wc, FILE *__stream); + +/* [7.28.4] Wide string functions */ + +double wcstod(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr); +float wcstof(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr); +long double wcstold(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr); + +long wcstol(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr, int __base); +long long wcstoll(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr, int __base); +unsigned long wcstoul(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr, int __base); +unsigned long long wcstoull(const wchar_t *__restrict __nptr, wchar_t **__restrict __endptr, int __base); + +wchar_t *wcscpy(wchar_t *__restrict __dest, const wchar_t *__restrict __src); +wchar_t *wcsncpy(wchar_t *__restrict __dest, const wchar_t *__restrict __src, size_t __size); +wchar_t *wmemcpy(wchar_t *__restrict __dest, const wchar_t *__restrict __src, size_t __size); +wchar_t *wmemmove(wchar_t *__dest, const wchar_t *__src, size_t __size); + +wchar_t *wcscat(wchar_t *__restrict __dest, const wchar_t *__restrict __src); +wchar_t *wcsncat(wchar_t *__restrict __dest, const wchar_t *__restrict __src, size_t __size); + +int wcscmp(const wchar_t *__a, const wchar_t *__b); +int wcscoll(const wchar_t *__a, const wchar_t *__b); +int wcsncmp(const wchar_t *__a, const wchar_t *__b, size_t __size); +int wcsxfrm(wchar_t *__restrict __dest, const wchar_t *__restrict __src, size_t __size); +int wmemcmp(const wchar_t *__a, const wchar_t *__b, size_t __size); + +wchar_t *wcschr(const wchar_t *__s, wchar_t __wc); +size_t wcscspn(const wchar_t *__dest, const wchar_t *__wchrs); +wchar_t *wcspbrk(const wchar_t *__s, const wchar_t *__wchrs); +wchar_t *wcsrchr(const wchar_t *__s, wchar_t __wc); +size_t wcsspn(const wchar_t *__s, const wchar_t *__wchrs); +wchar_t *wcsstr(const wchar_t *__s, const wchar_t *__b); +wchar_t *wcstok(wchar_t *__restrict __s, const wchar_t *__restrict __delimiter, wchar_t **__restrict __ptr); +wchar_t *wmemchr(const wchar_t *__s, wchar_t __wc, size_t __size); + +size_t wcslen(const wchar_t *__s); +wchar_t *wmemset(wchar_t *__dest, wchar_t __wc, size_t __size); + +/* [7.28.5] Wide date/time functions */ + +/* POSIX says: + * The tag tm is declared as naming an incomplete structure type, the contents of which are + * described in the header . */ +struct tm; +size_t wcsftime(wchar_t *__restrict __buffer, size_t __max_size, const wchar_t *__restrict __format, + const struct tm *__restrict __time); + +/* [7.28.6] Wide conversion functions */ + +wint_t btowc(int __wc); +int wctob(wint_t __wc); + +int mbsinit(const mbstate_t *__state); +size_t mbrlen(const char *__restrict __mbs, size_t __mbs_limit, mbstate_t *__restrict __stp); +size_t mbrtowc(wchar_t *__restrict __wcp, const char *__restrict __mbs, size_t __mbs_limit, mbstate_t *__restrict __stp); +size_t wcrtomb(char *__restrict __mbs, wchar_t __wc, mbstate_t *__restrict __stp); +size_t mbsrtowcs(wchar_t *__restrict __wcs, const char **__restrict __mbs, size_t __mb_limit, mbstate_t *__restrict __stp); +size_t mbsnrtowcs(wchar_t *__restrict __wcs, const char **__restrict __mbs, size_t __mb_limit, size_t __wc_limit, + mbstate_t *__restrict __stp); +size_t wcsrtombs(char *__restrict __mbs, const wchar_t **__restrict __wcs, size_t __mb_limit, mbstate_t *__restrict __stp); +size_t wcsnrtombs(char *__restrict __mbs, const wchar_t **__restrict __wcs, size_t __mb_limit, size_t __wc_limit, + mbstate_t *__restrict __stp); + +/* POSIX extensions */ +int wcwidth(wchar_t __wc); +int wcswidth(const wchar_t *__s, size_t __size); +wchar_t *wcsdup(const wchar_t *__s); +int wcsncasecmp(const wchar_t *__a, const wchar_t *__b, size_t __size); +int wcscasecmp(const wchar_t *__a, const wchar_t *__b); +size_t wcsnlen(const wchar_t *__s, size_t __maxlen); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _WCHAR_H */ diff --git a/user/include/mlibc/options/ansi/include/wctype.h b/user/include/mlibc/options/ansi/include/wctype.h new file mode 100644 index 0000000..ab66f15 --- /dev/null +++ b/user/include/mlibc/options/ansi/include/wctype.h @@ -0,0 +1,51 @@ +#ifndef _WCTYPE_H +#define _WCTYPE_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* [C11/7.30.2.2] Extensible wide character classification functions. */ + +int iswalnum(wint_t __wc); +int iswalpha(wint_t __wc); +int iswblank(wint_t __wc); +int iswcntrl(wint_t __wc); +int iswdigit(wint_t __wc); +int iswgraph(wint_t __wc); +int iswlower(wint_t __wc); +int iswprint(wint_t __wc); +int iswpunct(wint_t __wc); +int iswspace(wint_t __wc); +int iswupper(wint_t __wc); +int iswxdigit(wint_t __wc); + +wctype_t wctype(const char *__string); +int iswctype(wint_t __wc, wctype_t __type); + +/* [C11/7.30.3] Wide character case mapping utilities. */ + +wint_t towlower(wint_t __wc); +wint_t towupper(wint_t __wc); + +wctrans_t wctrans(const char *__string); +wint_t towctrans(wint_t __wc, wctrans_t __trans); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif /* _WCTYPE_H */ diff --git a/user/include/mlibc/options/ansi/meson.build b/user/include/mlibc/options/ansi/meson.build new file mode 100644 index 0000000..e57a8d6 --- /dev/null +++ b/user/include/mlibc/options/ansi/meson.build @@ -0,0 +1,329 @@ +ansi_sources = files( + 'generic/stdlib.cpp', + 'generic/assert.cpp', + 'generic/complex.c', + + 'generic/complex/csqrt.c', + 'generic/complex/csinhf.c', + 'generic/complex/ccoshf.c', + 'generic/complex/cacosh.c', + 'generic/complex/casinf.c', + 'generic/complex/clogf.c', + 'generic/complex/csqrtf.c', + 'generic/complex/cimag.c', + 'generic/complex/catanh.c', + 'generic/complex/carg.c', + 'generic/complex/cproj.c', + 'generic/complex/cephes_subr.c', + 'generic/complex/ccos.c', + 'generic/complex/cexp.c', + 'generic/complex/crealf.c', + 'generic/complex/cabs.c', + 'generic/complex/csinh.c', + 'generic/complex/casinhf.c', + 'generic/complex/cephes_subrf.c', + 'generic/complex/creal.c', + 'generic/complex/casin.c', + 'generic/complex/conjf.c', + 'generic/complex/cpowf.c', + 'generic/complex/cacosf.c', + 'generic/complex/csinf.c', + 'generic/complex/ctanh.c', + 'generic/complex/ctanhf.c', + 'generic/complex/cargf.c', + 'generic/complex/cabsf.c', + 'generic/complex/cpow.c', + 'generic/complex/csin.c', + 'generic/complex/cprojf.c', + 'generic/complex/catan.c', + 'generic/complex/ctanf.c', + 'generic/complex/ctan.c', + 'generic/complex/clog.c', + 'generic/complex/catanf.c', + 'generic/complex/cacos.c', + 'generic/complex/cexpf.c', + 'generic/complex/ccosh.c', + 'generic/complex/cimagf.c', + 'generic/complex/cacoshf.c', + 'generic/complex/conj.c', + 'generic/complex/catanhf.c', + 'generic/complex/ccosf.c', + 'generic/complex/casinh.c', + + 'generic/ctype.cpp', + 'generic/environment.cpp', + 'generic/errno.cpp', + 'generic/fenv.cpp', + 'generic/file-io.cpp', + 'generic/inttypes.cpp', + 'generic/locale.cpp', + 'generic/signal.cpp', + 'generic/stdio.cpp', + 'generic/stdlib.cpp', + 'generic/string.cpp', + 'generic/threads.cpp', + 'generic/time.cpp', + 'generic/uchar.cpp', + 'generic/wchar.cpp', + 'generic/wctype.cpp', +) + +if not no_headers + install_headers( + 'include/alloca.h', + 'include/assert.h', + 'include/complex.h', + 'include/ctype.h', + 'include/errno.h', + 'include/fenv.h', + 'include/inttypes.h', + 'include/limits.h', + 'include/locale.h', + 'include/math.h', + 'include/setjmp.h', + 'include/signal.h', + 'include/stdc-predef.h', + 'include/stdio.h', + 'include/stdlib.h', + 'include/string.h', + 'include/threads.h', + 'include/time.h', + 'include/uchar.h', + 'include/wchar.h', + 'include/wctype.h', + ) + install_headers( + 'include/bits/ansi/timespec.h', + 'include/bits/ansi/time_t.h', + 'include/bits/ansi/fenv.h', + subdir: 'bits/ansi' + ) +endif + +if not headers_only + c_compiler = meson.get_compiler('c') + + if c_compiler.get_id() == 'gcc' + compiler_c_args = ['-Wno-unused', '-Wno-maybe-uninitialized'] + elif c_compiler.get_id() == 'clang' + compiler_c_args = ['-Wno-unused-parameter', '-Wno-unused-but-set-variable'] + endif + + libc_sublibs += static_library('mlibc-musl-math', + 'musl-generic-math/acos.c', + 'musl-generic-math/acosf.c', + 'musl-generic-math/acosh.c', + 'musl-generic-math/acoshf.c', + 'musl-generic-math/acoshl.c', + 'musl-generic-math/acosl.c', + 'musl-generic-math/asin.c', + 'musl-generic-math/asinf.c', + 'musl-generic-math/asinh.c', + 'musl-generic-math/asinhf.c', + 'musl-generic-math/asinhl.c', + 'musl-generic-math/asinl.c', + 'musl-generic-math/atan2.c', + 'musl-generic-math/atan2f.c', + 'musl-generic-math/atan2l.c', + 'musl-generic-math/atan.c', + 'musl-generic-math/atanf.c', + 'musl-generic-math/atanh.c', + 'musl-generic-math/atanhf.c', + 'musl-generic-math/atanhl.c', + 'musl-generic-math/atanl.c', + 'musl-generic-math/cbrt.c', + 'musl-generic-math/cbrtf.c', + 'musl-generic-math/cbrtl.c', + 'musl-generic-math/ceil.c', + 'musl-generic-math/ceilf.c', + 'musl-generic-math/ceill.c', + 'musl-generic-math/copysign.c', + 'musl-generic-math/copysignf.c', + 'musl-generic-math/copysignl.c', + 'musl-generic-math/__cos.c', + 'musl-generic-math/cos.c', + 'musl-generic-math/__cosdf.c', + 'musl-generic-math/cosf.c', + 'musl-generic-math/cosh.c', + 'musl-generic-math/coshf.c', + 'musl-generic-math/coshl.c', + 'musl-generic-math/__cosl.c', + 'musl-generic-math/cosl.c', + 'musl-generic-math/erf.c', + 'musl-generic-math/erff.c', + 'musl-generic-math/erfl.c', + 'musl-generic-math/exp10.c', + 'musl-generic-math/exp10f.c', + 'musl-generic-math/exp10l.c', + 'musl-generic-math/exp2.c', + 'musl-generic-math/exp2f.c', + 'musl-generic-math/exp2l.c', + 'musl-generic-math/exp.c', + 'musl-generic-math/expf.c', + 'musl-generic-math/expl.c', + 'musl-generic-math/expm1.c', + 'musl-generic-math/expm1f.c', + 'musl-generic-math/expm1l.c', + 'musl-generic-math/__expo2.c', + 'musl-generic-math/__expo2f.c', + 'musl-generic-math/fabs.c', + 'musl-generic-math/fabsf.c', + 'musl-generic-math/fabsl.c', + 'musl-generic-math/fdim.c', + 'musl-generic-math/fdimf.c', + 'musl-generic-math/fdiml.c', + 'musl-generic-math/finite.c', + 'musl-generic-math/finitef.c', + 'musl-generic-math/floor.c', + 'musl-generic-math/floorf.c', + 'musl-generic-math/floorl.c', + 'musl-generic-math/fma.c', + 'musl-generic-math/fmaf.c', + 'musl-generic-math/fmal.c', + 'musl-generic-math/fmax.c', + 'musl-generic-math/fmaxf.c', + 'musl-generic-math/fmaxl.c', + 'musl-generic-math/fmin.c', + 'musl-generic-math/fminf.c', + 'musl-generic-math/fminl.c', + 'musl-generic-math/fmod.c', + 'musl-generic-math/fmodf.c', + 'musl-generic-math/fmodl.c', + 'musl-generic-math/__fpclassify.c', + 'musl-generic-math/__fpclassifyf.c', + 'musl-generic-math/__fpclassifyl.c', + 'musl-generic-math/frexp.c', + 'musl-generic-math/frexpf.c', + 'musl-generic-math/frexpl.c', + 'musl-generic-math/hypot.c', + 'musl-generic-math/hypotf.c', + 'musl-generic-math/hypotl.c', + 'musl-generic-math/ilogb.c', + 'musl-generic-math/ilogbf.c', + 'musl-generic-math/ilogbl.c', + 'musl-generic-math/__invtrigl.c', + 'musl-generic-math/j0.c', + 'musl-generic-math/j0f.c', + 'musl-generic-math/j1.c', + 'musl-generic-math/j1f.c', + 'musl-generic-math/jn.c', + 'musl-generic-math/jnf.c', + 'musl-generic-math/ldexp.c', + 'musl-generic-math/ldexpf.c', + 'musl-generic-math/ldexpl.c', + 'musl-generic-math/lgamma.c', + 'musl-generic-math/lgammaf.c', + 'musl-generic-math/lgammaf_r.c', + 'musl-generic-math/lgammal.c', + 'musl-generic-math/lgamma_r.c', + 'musl-generic-math/llrint.c', + 'musl-generic-math/llrintf.c', + 'musl-generic-math/llrintl.c', + 'musl-generic-math/llround.c', + 'musl-generic-math/llroundf.c', + 'musl-generic-math/llroundl.c', + 'musl-generic-math/log10.c', + 'musl-generic-math/log10f.c', + 'musl-generic-math/log10l.c', + 'musl-generic-math/log1p.c', + 'musl-generic-math/log1pf.c', + 'musl-generic-math/log1pl.c', + 'musl-generic-math/log2.c', + 'musl-generic-math/log2f.c', + 'musl-generic-math/log2l.c', + 'musl-generic-math/logb.c', + 'musl-generic-math/logbf.c', + 'musl-generic-math/logbl.c', + 'musl-generic-math/log.c', + 'musl-generic-math/logf.c', + 'musl-generic-math/logl.c', + 'musl-generic-math/lrint.c', + 'musl-generic-math/lrintf.c', + 'musl-generic-math/lrintl.c', + 'musl-generic-math/lround.c', + 'musl-generic-math/lroundf.c', + 'musl-generic-math/lroundl.c', + 'musl-generic-math/modf.c', + 'musl-generic-math/modff.c', + 'musl-generic-math/modfl.c', + 'musl-generic-math/nan.c', + 'musl-generic-math/nanf.c', + 'musl-generic-math/nanl.c', + 'musl-generic-math/nearbyint.c', + 'musl-generic-math/nearbyintf.c', + 'musl-generic-math/nearbyintl.c', + 'musl-generic-math/nextafter.c', + 'musl-generic-math/nextafterf.c', + 'musl-generic-math/nextafterl.c', + 'musl-generic-math/nexttoward.c', + 'musl-generic-math/nexttowardf.c', + 'musl-generic-math/nexttowardl.c', + 'musl-generic-math/__polevll.c', + 'musl-generic-math/pow.c', + 'musl-generic-math/powf.c', + 'musl-generic-math/powl.c', + 'musl-generic-math/remainder.c', + 'musl-generic-math/remainderf.c', + 'musl-generic-math/remainderl.c', + 'musl-generic-math/__rem_pio2.c', + 'musl-generic-math/__rem_pio2f.c', + 'musl-generic-math/__rem_pio2_large.c', + 'musl-generic-math/__rem_pio2l.c', + 'musl-generic-math/remquo.c', + 'musl-generic-math/remquof.c', + 'musl-generic-math/remquol.c', + 'musl-generic-math/rint.c', + 'musl-generic-math/rintf.c', + 'musl-generic-math/rintl.c', + 'musl-generic-math/round.c', + 'musl-generic-math/roundf.c', + 'musl-generic-math/roundl.c', + 'musl-generic-math/scalb.c', + 'musl-generic-math/scalbf.c', + 'musl-generic-math/scalbln.c', + 'musl-generic-math/scalblnf.c', + 'musl-generic-math/scalblnl.c', + 'musl-generic-math/scalbn.c', + 'musl-generic-math/scalbnf.c', + 'musl-generic-math/scalbnl.c', + 'musl-generic-math/__signbit.c', + 'musl-generic-math/__signbitf.c', + 'musl-generic-math/__signbitl.c', + 'musl-generic-math/signgam.c', + 'musl-generic-math/significand.c', + 'musl-generic-math/significandf.c', + 'musl-generic-math/__sin.c', + 'musl-generic-math/sin.c', + 'musl-generic-math/sincos.c', + 'musl-generic-math/sincosf.c', + 'musl-generic-math/sincosl.c', + 'musl-generic-math/__sindf.c', + 'musl-generic-math/sinf.c', + 'musl-generic-math/sinh.c', + 'musl-generic-math/sinhf.c', + 'musl-generic-math/sinhl.c', + 'musl-generic-math/__sinl.c', + 'musl-generic-math/sinl.c', + 'musl-generic-math/sqrt.c', + 'musl-generic-math/sqrtf.c', + 'musl-generic-math/sqrtl.c', + 'musl-generic-math/__tan.c', + 'musl-generic-math/tan.c', + 'musl-generic-math/__tandf.c', + 'musl-generic-math/tanf.c', + 'musl-generic-math/tanh.c', + 'musl-generic-math/tanhf.c', + 'musl-generic-math/tanhl.c', + 'musl-generic-math/__tanl.c', + 'musl-generic-math/tanl.c', + 'musl-generic-math/tgamma.c', + 'musl-generic-math/tgammaf.c', + 'musl-generic-math/tgammal.c', + 'musl-generic-math/trunc.c', + 'musl-generic-math/truncf.c', + 'musl-generic-math/truncl.c', + pic: true, + include_directories: libc_include_dirs, + dependencies: libc_deps, + c_args: [compiler_c_args, '-Wno-implicit', '-Wno-parentheses', '-Wno-sign-compare', '-Wno-attributes', '-Wno-unknown-pragmas']) +endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__cos.c b/user/include/mlibc/options/ansi/musl-generic-math/__cos.c new file mode 100644 index 0000000..46cefb3 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__cos.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) ~ 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy, rearrange to + * cos(x+y) ~ w + (tmp + (r-x*y)) + * where w = 1 - x*x/2 and tmp is a tiny correction term + * (1 - x*x/2 == w + tmp exactly in infinite precision). + * The exactness of w + tmp in infinite precision depends on w + * and tmp having the same precision as x. If they have extra + * precision due to compiler bugs, then the extra precision is + * only good provided it is retained in all terms of the final + * expression for cos(). Retention happens in all cases tested + * under FreeBSD, so don't pessimize things by forcibly clipping + * any extra precision in w. + */ + +#include "libm.h" + +static const double +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +double __cos(double x, double y) +{ + double_t hz,z,r,w; + + z = x*x; + w = z*z; + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + w = 1.0-hz; + return w + (((1.0-w)-hz) + (z*r-x*y)); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__cosdf.c b/user/include/mlibc/options/ansi/musl-generic-math/__cosdf.c new file mode 100644 index 0000000..2124989 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__cosdf.c @@ -0,0 +1,35 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +static const double +C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ +C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ +C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ +C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + +float __cosdf(double x) +{ + double_t r, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((1.0+z*C0) + w*C1) + (w*z)*r; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__cosl.c b/user/include/mlibc/options/ansi/musl-generic-math/__cosl.c new file mode 100644 index 0000000..fa522dd --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__cosl.c @@ -0,0 +1,96 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_cosl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_cosl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __cos.c. See __cos.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-2.43e-23, 2.425e-23]: + * |cos(x) - c(x)| < 2**-75.1 + * + * The coefficients of c(x) were generated by a pari-gp script using + * a Remez algorithm that searches for the best higher coefficients + * after rounding leading coefficients to a specified precision. + * + * Simpler methods like Chebyshev or basic Remez barely suffice for + * cos() in 64-bit precision, because we want the coefficient of x^2 + * to be precisely -0.5 so that multiplying by it is exact, and plain + * rounding of the coefficients of a good polynomial approximation only + * gives this up to about 64-bit precision. Plain rounding also gives + * a mediocre approximation for the coefficient of x^4, but a rounding + * error of 0.5 ulps for this coefficient would only contribute ~0.01 + * ulps to the final error, so this is unimportant. Rounding errors in + * higher coefficients are even less important. + * + * In fact, coefficients above the x^4 one only need to have 53-bit + * precision, and this is more efficient. We get this optimization + * almost for free from the complications needed to search for the best + * higher coefficients. + */ +static const long double +C1 = 0.0416666666666666666136L; /* 0xaaaaaaaaaaaaaa9b.0p-68 */ +static const double +C2 = -0.0013888888888888874, /* -0x16c16c16c16c10.0p-62 */ +C3 = 0.000024801587301571716, /* 0x1a01a01a018e22.0p-68 */ +C4 = -0.00000027557319215507120, /* -0x127e4fb7602f22.0p-74 */ +C5 = 0.0000000020876754400407278, /* 0x11eed8caaeccf1.0p-81 */ +C6 = -1.1470297442401303e-11, /* -0x19393412bd1529.0p-89 */ +C7 = 4.7383039476436467e-14; /* 0x1aac9d9af5c43e.0p-97 */ +#define POLY(z) (z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*C7))))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __cos.c. See __cos.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.80e-37, 1.79e-37]: + * |cos(x) - c(x))| < 2**-122.0 + * + * 113-bit precision requires more care than 64-bit precision, since + * simple methods give a minimax polynomial with coefficient for x^2 + * that is 1 ulp below 0.5, but we want it to be precisely 0.5. See + * above for more details. + */ +static const long double +C1 = 0.04166666666666666666666666666666658424671L, +C2 = -0.001388888888888888888888888888863490893732L, +C3 = 0.00002480158730158730158730158600795304914210L, +C4 = -0.2755731922398589065255474947078934284324e-6L, +C5 = 0.2087675698786809897659225313136400793948e-8L, +C6 = -0.1147074559772972315817149986812031204775e-10L, +C7 = 0.4779477332386808976875457937252120293400e-13L; +static const double +C8 = -0.1561920696721507929516718307820958119868e-15, +C9 = 0.4110317413744594971475941557607804508039e-18, +C10 = -0.8896592467191938803288521958313920156409e-21, +C11 = 0.1601061435794535138244346256065192782581e-23; +#define POLY(z) (z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*(C7+ \ + z*(C8+z*(C9+z*(C10+z*C11))))))))))) +#endif + +long double __cosl(long double x, long double y) +{ + long double hz,z,r,w; + + z = x*x; + r = POLY(z); + hz = 0.5*z; + w = 1.0-hz; + return w + (((1.0-w)-hz) + (z*r-x*y)); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__expo2.c b/user/include/mlibc/options/ansi/musl-generic-math/__expo2.c new file mode 100644 index 0000000..740ac68 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__expo2.c @@ -0,0 +1,16 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ +static const int k = 2043; +static const double kln2 = 0x1.62066151add8bp+10; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +double __expo2(double x) +{ + double scale; + + /* note that k is odd and scale*scale overflows */ + INSERT_WORDS(scale, (uint32_t)(0x3ff + k/2) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__expo2f.c b/user/include/mlibc/options/ansi/musl-generic-math/__expo2f.c new file mode 100644 index 0000000..5163e41 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__expo2f.c @@ -0,0 +1,16 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +static const int k = 235; +static const float kln2 = 0x1.45c778p+7f; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +float __expo2f(float x) +{ + float scale; + + /* note that k is odd and scale*scale overflows */ + SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + return expf(x - kln2) * scale * scale; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__fpclassify.c b/user/include/mlibc/options/ansi/musl-generic-math/__fpclassify.c new file mode 100644 index 0000000..f7c0e2d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__fpclassify.c @@ -0,0 +1,11 @@ +#include +#include + +int __fpclassify(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__fpclassifyf.c b/user/include/mlibc/options/ansi/musl-generic-math/__fpclassifyf.c new file mode 100644 index 0000000..fd00eb1 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__fpclassifyf.c @@ -0,0 +1,11 @@ +#include +#include + +int __fpclassifyf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__fpclassifyl.c b/user/include/mlibc/options/ansi/musl-generic-math/__fpclassifyl.c new file mode 100644 index 0000000..fb62dd9 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__fpclassifyl.c @@ -0,0 +1,42 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __fpclassifyl(long double x) +{ + return __fpclassify(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int msb = u.i.m>>63; + if (!e && !msb) + return u.i.m ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7fff) { + /* The x86 variant of 80-bit extended precision only admits + * one representation of each infinity, with the mantissa msb + * necessarily set. The version with it clear is invalid/nan. + * The m68k variant, however, allows either, and tooling uses + * the version with it clear. */ + if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && !msb) + return FP_NAN; + return u.i.m << 1 ? FP_NAN : FP_INFINITE; + } + if (!msb) + return FP_NAN; + return FP_NORMAL; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + u.i.se = 0; + if (!e) + return u.i2.lo | u.i2.hi ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7fff) + return u.i2.lo | u.i2.hi ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__invtrigl.c b/user/include/mlibc/options/ansi/musl-generic-math/__invtrigl.c new file mode 100644 index 0000000..48f83aa --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__invtrigl.c @@ -0,0 +1,63 @@ +#include +#include "__invtrigl.h" + +#if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +pS0 = 1.66666666666666666631e-01L, +pS1 = -4.16313987993683104320e-01L, +pS2 = 3.69068046323246813704e-01L, +pS3 = -1.36213932016738603108e-01L, +pS4 = 1.78324189708471965733e-02L, +pS5 = -2.19216428382605211588e-04L, +pS6 = -7.10526623669075243183e-06L, +qS1 = -2.94788392796209867269e+00L, +qS2 = 3.27309890266528636716e+00L, +qS3 = -1.68285799854822427013e+00L, +qS4 = 3.90699412641738801874e-01L, +qS5 = -3.14365703596053263322e-02L; + +const long double pio2_hi = 1.57079632679489661926L; +const long double pio2_lo = -2.50827880633416601173e-20L; + +/* used in asinl() and acosl() */ +/* R(x^2) is a rational approximation of (asin(x)-x)/x^3 with Remez algorithm */ +long double __invtrigl_R(long double z) +{ + long double p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*(pS5+z*pS6)))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*(qS4+z*qS5)))); + return p/q; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +static const long double +pS0 = 1.66666666666666666666666666666700314e-01L, +pS1 = -7.32816946414566252574527475428622708e-01L, +pS2 = 1.34215708714992334609030036562143589e+00L, +pS3 = -1.32483151677116409805070261790752040e+00L, +pS4 = 7.61206183613632558824485341162121989e-01L, +pS5 = -2.56165783329023486777386833928147375e-01L, +pS6 = 4.80718586374448793411019434585413855e-02L, +pS7 = -4.42523267167024279410230886239774718e-03L, +pS8 = 1.44551535183911458253205638280410064e-04L, +pS9 = -2.10558957916600254061591040482706179e-07L, +qS1 = -4.84690167848739751544716485245697428e+00L, +qS2 = 9.96619113536172610135016921140206980e+00L, +qS3 = -1.13177895428973036660836798461641458e+01L, +qS4 = 7.74004374389488266169304117714658761e+00L, +qS5 = -3.25871986053534084709023539900339905e+00L, +qS6 = 8.27830318881232209752469022352928864e-01L, +qS7 = -1.18768052702942805423330715206348004e-01L, +qS8 = 8.32600764660522313269101537926539470e-03L, +qS9 = -1.99407384882605586705979504567947007e-04L; + +const long double pio2_hi = 1.57079632679489661923132169163975140L; +const long double pio2_lo = 4.33590506506189051239852201302167613e-35L; + +long double __invtrigl_R(long double z) +{ + long double p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*(pS5+z*(pS6+z*(pS7+z*(pS8+z*pS9))))))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*(qS4+z*(qS5+z*(qS6+z*(qS7+z*(qS8+z*qS9)))))))); + return p/q; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__invtrigl.h b/user/include/mlibc/options/ansi/musl-generic-math/__invtrigl.h new file mode 100644 index 0000000..6dedac3 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__invtrigl.h @@ -0,0 +1,11 @@ +/* shared by acosl, asinl and atan2l */ +#define pio2_hi __pio2_hi +#define pio2_lo __pio2_lo + +#ifndef __MLIBC_ABI_ONLY + +extern const long double pio2_hi, pio2_lo; + +long double __invtrigl_R(long double z); + +#endif /* !__MLIBC_ABI_ONLY */ diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__polevll.c b/user/include/mlibc/options/ansi/musl-generic-math/__polevll.c new file mode 100644 index 0000000..ce1a840 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__polevll.c @@ -0,0 +1,93 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/polevll.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* + * Evaluate polynomial + * + * + * SYNOPSIS: + * + * int N; + * long double x, y, coef[N+1], polevl[]; + * + * y = polevll( x, coef, N ); + * + * + * DESCRIPTION: + * + * Evaluates polynomial of degree N: + * + * 2 N + * y = C + C x + C x +...+ C x + * 0 1 2 N + * + * Coefficients are stored in reverse order: + * + * coef[0] = C , ..., coef[N] = C . + * N 0 + * + * The function p1evll() assumes that coef[N] = 1.0 and is + * omitted from the array. Its calling arguments are + * otherwise the same as polevll(). + * + * + * SPEED: + * + * In the interest of speed, there are no checks for out + * of bounds arithmetic. This routine is used by most of + * the functions in the library. Depending on available + * equipment features, the user may wish to rewrite the + * program in microcode or assembly language. + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#else +/* + * Polynomial evaluator: + * P[0] x^n + P[1] x^(n-1) + ... + P[n] + */ +long double __polevll(long double x, const long double *P, int n) +{ + long double y; + + y = *P++; + do { + y = y * x + *P++; + } while (--n); + + return y; +} + +/* + * Polynomial evaluator: + * x^n + P[0] x^(n-1) + P[1] x^(n-2) + ... + P[n] + */ +long double __p1evll(long double x, const long double *P, int n) +{ + long double y; + + n -= 1; + y = x + *P++; + do { + y = y * x + *P++; + } while (--n); + + return y; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2.c b/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2.c new file mode 100644 index 0000000..d403f81 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2.c @@ -0,0 +1,177 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double +toint = 1.5/EPS, +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +int __rem_pio2(double x, double *y) +{ + union {double f; uint64_t i;} u = {x}; + double_t z,w,t,r,fn; + double tx[3],ty[2]; + uint32_t ix; + int sign, n, ex, ey, i; + + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (!sign) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0]) - pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0]) + pio2_1t; + return -1; + } + } else { + if (!sign) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0]) - 2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0]) + 2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (!sign) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0]) - 3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0]) + 3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (!sign) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0]) - 4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0]) + 4*pio2_1t; + return -4; + } + } + } + if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + r = x - fn*pio2_1; + w = fn*pio2_1t; /* 1st round, good to 85 bits */ + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + ex = ix>>20; + if (ex - ey > 16) { /* 2nd round, good to 118 bits */ + t = r; + w = fn*pio2_2; + r = t - w; + w = fn*pio2_2t - ((t-r)-w); + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ + t = r; + w = fn*pio2_3; + r = t - w; + w = fn*pio2_3t - ((t-r)-w); + y[0] = r - w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ix >= 0x7ff00000) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + u.f = x; + u.i &= (uint64_t)-1>>12; + u.i |= (uint64_t)(0x3ff + 23)<<52; + z = u.f; + for (i=0; i < 2; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + /* skip zero terms, first term is non-zero */ + while (tx[i] == 0.0) + i--; + n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1); + if (sign) { + y[0] = -ty[0]; + y[1] = -ty[1]; + return -n; + } + y[0] = ty[0]; + y[1] = ty[1]; + return n; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2_large.c b/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2_large.c new file mode 100644 index 0000000..958f28c --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2_large.c @@ -0,0 +1,442 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __rem_pio2_large(x,y,e0,nx,prec) + * double x[],y[]; int e0,nx,prec; + * + * __rem_pio2_large return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0]. Must be <= 16360 or you need to + * expand the ipio2 table. + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The minimum and recommended value + * for jk is 3,4,4,6 for single, double, extended, and quad. + * jk+1 must be 2 larger than you might expect so that our + * recomputation test works. (Up to 24 bits in the integer + * part (the 24 bits of it that we compute) and 23 bits in + * the fraction part may be lost to cancelation before we + * recompute.) + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ +static const int32_t ipio2[] = { +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + +#if LDBL_MAX_EXP > 1024 +0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, +0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, +0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, +0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, +0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, +0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, +0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, +0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, +0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, +0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, +0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, +0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, +0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, +0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, +0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, +0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, +0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, +0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, +0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, +0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, +0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, +0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, +0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, +0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, +0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, +0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, +0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, +0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, +0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, +0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, +0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, +0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, +0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, +0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, +0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, +0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, +0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, +0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, +0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, +0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, +0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, +0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, +0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, +0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, +0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, +0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, +0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, +0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, +0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, +0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, +0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, +0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, +0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, +0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, +0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, +0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, +0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, +0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, +0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, +0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, +0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, +0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, +0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, +0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, +0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, +0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, +0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, +0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, +0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, +0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, +0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, +0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, +0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, +0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, +0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, +0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, +0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, +0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, +0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, +0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, +0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, +0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, +0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, +0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, +0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, +0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, +0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, +0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, +0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, +0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, +0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, +0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, +0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, +0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, +0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, +0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, +0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, +0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, +0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, +0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, +0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, +0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, +0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, +0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +#endif +}; + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec) +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for (i=0; i<=m; i++,j++) + f[i] = j<0 ? 0.0 : (double)ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0; i<=jk; i++) { + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for (i=0,j=jz,z=q[jz]; j>0; i++,j--) { + fw = (double)(int32_t)(0x1p-24*z); + iq[i] = (int32_t)(z - 0x1p24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t)z; + z -= (double)n; + ih = 0; + if (q0 > 0) { /* need iq[jz-1] to determine n */ + i = iq[jz-1]>>(24-q0); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if (q0 == 0) ih = iq[jz-1]>>23; + else if (z >= 0.5) ih = 2; + + if (ih > 0) { /* q > 0.5 */ + n += 1; carry = 0; + for (i=0; i 0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) + z -= scalbn(1.0,q0); + } + } + + /* check if recomputation is needed */ + if (z == 0.0) { + j = 0; + for (i=jz-1; i>=jk; i--) j |= iq[i]; + if (j == 0) { /* need recomputation */ + for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */ + + for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double)ipio2[jv+i]; + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if (z == 0.0) { + jz -= 1; + q0 -= 24; + while (iq[jz] == 0) { + jz--; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if (z >= 0x1p24) { + fw = (double)(int32_t)(0x1p-24*z); + iq[jz] = (int32_t)(z - 0x1p24*fw); + jz += 1; + q0 += 24; + iq[jz] = (int32_t)fw; + } else + iq[jz] = (int32_t)z; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1.0,q0); + for (i=jz; i>=0; i--) { + q[i] = fw*(double)iq[i]; + fw *= 0x1p-24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz; i>=0; i--) { + for (fw=0.0,k=0; k<=jp && k<=jz-i; k++) + fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + y[0] = ih==0 ? fw : -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + // TODO: drop excess precision here once double_t is used + fw = (double)fw; + y[0] = ih==0 ? fw : -fw; + fw = fq[0]-fw; + for (i=1; i<=jz; i++) + fw += fq[i]; + y[1] = ih==0 ? fw : -fw; + break; + case 3: /* painful */ + for (i=jz; i>0; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz; i>1; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz; i>=2; i--) + fw += fq[i]; + if (ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2f.c b/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2f.c new file mode 100644 index 0000000..4473c1c --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2f.c @@ -0,0 +1,75 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in *y + * use double precision for everything except passing x + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 25 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ +static const double +toint = 1.5/EPS, +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ +pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +int __rem_pio2f(float x, double *y) +{ + union {float f; uint32_t i;} u = {x}; + double tx[1],ty[1]; + double_t fn; + uint32_t ix; + int n, sign, e0; + + ix = u.i & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + *y = x - fn*pio2_1 - fn*pio2_1t; + return n; + } + if(ix>=0x7f800000) { /* x is inf or NaN */ + *y = x-x; + return 0; + } + /* scale x into [2^23, 2^24-1] */ + sign = u.i>>31; + e0 = (ix>>23) - (0x7f+23); /* e0 = ilogb(|x|)-23, positive */ + u.i = ix - (e0<<23); + tx[0] = u.f; + n = __rem_pio2_large(tx,ty,e0,1,0); + if (sign) { + *y = -ty[0]; + return -n; + } + *y = ty[0]; + return n; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2l.c b/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2l.c new file mode 100644 index 0000000..77255bd --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__rem_pio2l.c @@ -0,0 +1,141 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +#include "libm.h" +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +/* ld80 and ld128 version of __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +static const long double toint = 1.5/LDBL_EPSILON; + +#if LDBL_MANT_DIG == 64 +/* u ~< 0x1p25*pi/2 */ +#define SMALL(u) (((u.i.se & 0x7fffU)<<16 | u.i.m>>48) < ((0x3fff + 25)<<16 | 0x921f>>1 | 0x8000)) +#define QUOBITS(x) ((uint32_t)(int32_t)x & 0x7fffffff) +#define ROUND1 22 +#define ROUND2 61 +#define NX 3 +#define NY 2 +/* + * invpio2: 64 bits of 2/pi + * pio2_1: first 39 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 39 bits of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 39 bits of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double +pio2_1 = 1.57079632679597125389e+00, /* 0x3FF921FB, 0x54444000 */ +pio2_2 = -1.07463465549783099519e-12, /* -0x12e7b967674000.0p-92 */ +pio2_3 = 6.36831716351370313614e-25; /* 0x18a2e037074000.0p-133 */ +static const long double +invpio2 = 6.36619772367581343076e-01L, /* 0xa2f9836e4e44152a.0p-64 */ +pio2_1t = -1.07463465549719416346e-12L, /* -0x973dcb3b399d747f.0p-103 */ +pio2_2t = 6.36831716351095013979e-25L, /* 0xc51701b839a25205.0p-144 */ +pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */ +#elif LDBL_MANT_DIG == 113 +/* u ~< 0x1p45*pi/2 */ +#define SMALL(u) (((u.i.se & 0x7fffU)<<16 | u.i.top) < ((0x3fff + 45)<<16 | 0x921f)) +#define QUOBITS(x) ((uint32_t)(int64_t)x & 0x7fffffff) +#define ROUND1 51 +#define ROUND2 119 +#define NX 5 +#define NY 3 +static const long double +invpio2 = 6.3661977236758134307553505349005747e-01L, /* 0x145f306dc9c882a53f84eafa3ea6a.0p-113 */ +pio2_1 = 1.5707963267948966192292994253909555e+00L, /* 0x1921fb54442d18469800000000000.0p-112 */ +pio2_1t = 2.0222662487959507323996846200947577e-21L, /* 0x13198a2e03707344a4093822299f3.0p-181 */ +pio2_2 = 2.0222662487959507323994779168837751e-21L, /* 0x13198a2e03707344a400000000000.0p-181 */ +pio2_2t = 2.0670321098263988236496903051604844e-43L, /* 0x127044533e63a0105df531d89cd91.0p-254 */ +pio2_3 = 2.0670321098263988236499468110329591e-43L, /* 0x127044533e63a0105e00000000000.0p-254 */ +pio2_3t = -2.5650587247459238361625433492959285e-65L; /* -0x159c4ec64ddaeb5f78671cbfb2210.0p-327 */ +#endif + +int __rem_pio2l(long double x, long double *y) +{ + union ldshape u,uz; + long double z,w,t,r,fn; + double tx[NX],ty[NY]; + int ex,ey,n,i; + + u.f = x; + ex = u.i.se & 0x7fff; + if (SMALL(u)) { + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = x*invpio2 + toint - toint; + n = QUOBITS(fn); + r = x-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 102/180 bits (ld80/ld128) */ + y[0] = r-w; + u.f = y[0]; + ey = u.i.se & 0x7fff; + if (ex - ey > ROUND1) { /* 2nd iteration needed, good to 141/248 (ld80/ld128) */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + u.f = y[0]; + ey = u.i.se & 0x7fff; + if (ex - ey > ROUND2) { /* 3rd iteration, good to 180/316 bits */ + t = r; /* will cover all possible cases (not verified for ld128) */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ex == 0x7fff) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + uz.f = x; + uz.i.se = 0x3fff + 23; + z = uz.f; + for (i=0; i < NX - 1; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + while (tx[i] == 0) + i--; + n = __rem_pio2_large(tx, ty, ex-0x3fff-23, i+1, NY); + w = ty[1]; + if (NY == 3) + w += ty[2]; + r = ty[0] + w; + /* TODO: for ld128 this does not follow the recommendation of the + comments of __rem_pio2_large which seem wrong if |ty[0]| > |ty[1]+ty[2]| */ + w -= r - ty[0]; + if (u.i.se >> 15) { + y[0] = -r; + y[1] = -w; + return -n; + } + y[0] = r; + y[1] = w; + return n; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__signbit.c b/user/include/mlibc/options/ansi/musl-generic-math/__signbit.c new file mode 100644 index 0000000..e700b6b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__signbit.c @@ -0,0 +1,13 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbit(double x) +{ + union { + double d; + uint64_t i; + } y = { x }; + return y.i>>63; +} + + diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__signbitf.c b/user/include/mlibc/options/ansi/musl-generic-math/__signbitf.c new file mode 100644 index 0000000..40ad3cf --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__signbitf.c @@ -0,0 +1,11 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbitf(float x) +{ + union { + float f; + uint32_t i; + } y = { x }; + return y.i>>31; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__signbitl.c b/user/include/mlibc/options/ansi/musl-generic-math/__signbitl.c new file mode 100644 index 0000000..63b3dc5 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__signbitl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +int __signbitl(long double x) +{ + union ldshape u = {x}; + return u.i.se >> 15; +} +#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __signbitl(long double x) +{ + return __signbit(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__sin.c b/user/include/mlibc/options/ansi/musl-generic-math/__sin.c new file mode 100644 index 0000000..4030949 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__sin.c @@ -0,0 +1,64 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __sin( x, y, iy) + * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. Callers must return sin(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization sin(x) ~ x for tiny x. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include "libm.h" + +static const double +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +double __sin(double x, double y, int iy) +{ + double_t z,r,v,w; + + z = x*x; + w = z*z; + r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6); + v = z*x; + if (iy == 0) + return x + v*(S1 + z*r); + else + return x - ((z*(0.5*y - v*r) - y) - v*S1); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__sindf.c b/user/include/mlibc/options/ansi/musl-generic-math/__sindf.c new file mode 100644 index 0000000..8fec2a3 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__sindf.c @@ -0,0 +1,36 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +static const double +S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ +S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ +S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ +S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + +float __sindf(double x) +{ + double_t r, s, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = S3 + z*S4; + s = z*x; + return (x + s*(S1 + z*S2)) + s*w*r; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__sinl.c b/user/include/mlibc/options/ansi/musl-generic-math/__sinl.c new file mode 100644 index 0000000..2525bbe --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__sinl.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_sinl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_sinl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __sin.c. See __sin.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.89e-22, 1.915e-22] + * |sin(x)/x - s(x)| < 2**-72.1 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +S1 = -0.166666666666666666671L; /* -0xaaaaaaaaaaaaaaab.0p-66 */ +static const double +S2 = 0.0083333333333333332, /* 0x11111111111111.0p-59 */ +S3 = -0.00019841269841269427, /* -0x1a01a01a019f81.0p-65 */ +S4 = 0.0000027557319223597490, /* 0x171de3a55560f7.0p-71 */ +S5 = -0.000000025052108218074604, /* -0x1ae64564f16cad.0p-78 */ +S6 = 1.6059006598854211e-10, /* 0x161242b90243b5.0p-85 */ +S7 = -7.6429779983024564e-13, /* -0x1ae42ebd1b2e00.0p-93 */ +S8 = 2.6174587166648325e-15; /* 0x179372ea0b3f64.0p-101 */ +#define POLY(z) (S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*S8)))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __sin.c. See __sin.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.53e-37, 1.659e-37] + * |sin(x)/x - s(x)| < 2**-122.1 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +S1 = -0.16666666666666666666666666666666666606732416116558L, +S2 = 0.0083333333333333333333333333333331135404851288270047L, +S3 = -0.00019841269841269841269841269839935785325638310428717L, +S4 = 0.27557319223985890652557316053039946268333231205686e-5L, +S5 = -0.25052108385441718775048214826384312253862930064745e-7L, +S6 = 0.16059043836821614596571832194524392581082444805729e-9L, +S7 = -0.76471637318198151807063387954939213287488216303768e-12L, +S8 = 0.28114572543451292625024967174638477283187397621303e-14L; +static const double +S9 = -0.82206352458348947812512122163446202498005154296863e-17, +S10 = 0.19572940011906109418080609928334380560135358385256e-19, +S11 = -0.38680813379701966970673724299207480965452616911420e-22, +S12 = 0.64038150078671872796678569586315881020659912139412e-25; +#define POLY(z) (S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*(S8+ \ + z*(S9+z*(S10+z*(S11+z*S12)))))))))) +#endif + +long double __sinl(long double x, long double y, int iy) +{ + long double z,r,v; + + z = x*x; + v = z*x; + r = POLY(z); + if (iy == 0) + return x+v*(S1+z*r); + return x-((z*(0.5*y-v*r)-y)-v*S1); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__tan.c b/user/include/mlibc/options/ansi/musl-generic-math/__tan.c new file mode 100644 index 0000000..8019844 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__tan.c @@ -0,0 +1,110 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __tan( x, y, k ) + * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. + * + * Algorithm + * 1. Since tan(-x) = -tan(x), we need only to consider positive x. + * 2. Callers must return tan(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization tan(x) ~ x for tiny x. + * 3. tan(x) is approximated by a odd polynomial of degree 27 on + * [0,0.67434] + * 3 27 + * tan(x) ~ x + T1*x + ... + T13*x + * where + * + * |tan(x) 2 4 26 | -59.2 + * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 + * | x | + * + * Note: tan(x+y) = tan(x) + tan'(x)*y + * ~ tan(x) + (1+x*x)*y + * Therefore, for better accuracy in computing tan(x+y), let + * 3 2 2 2 2 + * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + * then + * 3 2 + * tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then + * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include "libm.h" + +static const double T[] = { + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +}, +pio4 = 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */ +pio4lo = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +double __tan(double x, double y, int odd) +{ + double_t z, r, v, w, s, a; + double w0, a0; + uint32_t hx; + int big, sign; + + GET_HIGH_WORD(hx,x); + big = (hx&0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if (big) { + sign = hx>>31; + if (sign) { + x = -x; + y = -y; + } + x = (pio4 - x) + (pio4lo - y); + y = 0.0; + } + z = x * x; + w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + r = T[1] + w*(T[3] + w*(T[5] + w*(T[7] + w*(T[9] + w*T[11])))); + v = z*(T[2] + w*(T[4] + w*(T[6] + w*(T[8] + w*(T[10] + w*T[12]))))); + s = z * x; + r = y + z*(s*(r + v) + y) + s*T[0]; + w = x + r; + if (big) { + s = 1 - 2*odd; + v = s - 2.0 * (x + (r - w*w/(w + s))); + return sign ? -v : v; + } + if (!odd) + return w; + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + w0 = w; + SET_LOW_WORD(w0, 0); + v = r - (w0 - x); /* w0+v = r+x */ + a0 = a = -1.0 / w; + SET_LOW_WORD(a0, 0); + return a0 + a*(1.0 + a0*w0 + a0*v); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__tandf.c b/user/include/mlibc/options/ansi/musl-generic-math/__tandf.c new file mode 100644 index 0000000..25047ee --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__tandf.c @@ -0,0 +1,54 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +static const double T[] = { + 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */ + 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */ + 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */ + 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */ + 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */ + 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ +}; + +float __tandf(double x, int odd) +{ + double_t z,r,w,s,t,u; + + z = x*x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + r = T[4] + z*T[5]; + t = T[2] + z*T[3]; + w = z*z; + s = z*x; + u = T[0] + z*T[1]; + r = (x + s*u) + (s*w)*(t + w*r); + return odd ? -1.0/r : r; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/__tanl.c b/user/include/mlibc/options/ansi/musl-generic-math/__tanl.c new file mode 100644 index 0000000..54abc3d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/__tanl.c @@ -0,0 +1,143 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_tanl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_tanl.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __tan.c. See __tan.c for most comments. + */ +/* + * Domain [-0.67434, 0.67434], range ~[-2.25e-22, 1.921e-22] + * |tan(x)/x - t(x)| < 2**-71.9 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +T3 = 0.333333333333333333180L, /* 0xaaaaaaaaaaaaaaa5.0p-65 */ +T5 = 0.133333333333333372290L, /* 0x88888888888893c3.0p-66 */ +T7 = 0.0539682539682504975744L, /* 0xdd0dd0dd0dc13ba2.0p-68 */ +pio4 = 0.785398163397448309628L, /* 0xc90fdaa22168c235.0p-64 */ +pio4lo = -1.25413940316708300586e-20L; /* -0xece675d1fc8f8cbb.0p-130 */ +static const double +T9 = 0.021869488536312216, /* 0x1664f4882cc1c2.0p-58 */ +T11 = 0.0088632355256619590, /* 0x1226e355c17612.0p-59 */ +T13 = 0.0035921281113786528, /* 0x1d6d3d185d7ff8.0p-61 */ +T15 = 0.0014558334756312418, /* 0x17da354aa3f96b.0p-62 */ +T17 = 0.00059003538700862256, /* 0x13559358685b83.0p-63 */ +T19 = 0.00023907843576635544, /* 0x1f56242026b5be.0p-65 */ +T21 = 0.000097154625656538905, /* 0x1977efc26806f4.0p-66 */ +T23 = 0.000038440165747303162, /* 0x14275a09b3ceac.0p-67 */ +T25 = 0.000018082171885432524, /* 0x12f5e563e5487e.0p-68 */ +T27 = 0.0000024196006108814377, /* 0x144c0d80cc6896.0p-71 */ +T29 = 0.0000078293456938132840, /* 0x106b59141a6cb3.0p-69 */ +T31 = -0.0000032609076735050182, /* -0x1b5abef3ba4b59.0p-71 */ +T33 = 0.0000023261313142559411; /* 0x13835436c0c87f.0p-71 */ +#define RPOLY(w) (T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + \ + w * (T25 + w * (T29 + w * T33))))))) +#define VPOLY(w) (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + \ + w * (T27 + w * T31)))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __tan.c. See __tan.c for most comments. + */ +/* + * Domain [-0.67434, 0.67434], range ~[-3.37e-36, 1.982e-37] + * |tan(x)/x - t(x)| < 2**-117.8 (XXX should be ~1e-37) + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +T3 = 0x1.5555555555555555555555555553p-2L, +T5 = 0x1.1111111111111111111111111eb5p-3L, +T7 = 0x1.ba1ba1ba1ba1ba1ba1ba1b694cd6p-5L, +T9 = 0x1.664f4882c10f9f32d6bbe09d8bcdp-6L, +T11 = 0x1.226e355e6c23c8f5b4f5762322eep-7L, +T13 = 0x1.d6d3d0e157ddfb5fed8e84e27b37p-9L, +T15 = 0x1.7da36452b75e2b5fce9ee7c2c92ep-10L, +T17 = 0x1.355824803674477dfcf726649efep-11L, +T19 = 0x1.f57d7734d1656e0aceb716f614c2p-13L, +T21 = 0x1.967e18afcb180ed942dfdc518d6cp-14L, +T23 = 0x1.497d8eea21e95bc7e2aa79b9f2cdp-15L, +T25 = 0x1.0b132d39f055c81be49eff7afd50p-16L, +T27 = 0x1.b0f72d33eff7bfa2fbc1059d90b6p-18L, +T29 = 0x1.5ef2daf21d1113df38d0fbc00267p-19L, +T31 = 0x1.1c77d6eac0234988cdaa04c96626p-20L, +T33 = 0x1.cd2a5a292b180e0bdd701057dfe3p-22L, +T35 = 0x1.75c7357d0298c01a31d0a6f7d518p-23L, +T37 = 0x1.2f3190f4718a9a520f98f50081fcp-24L, +pio4 = 0x1.921fb54442d18469898cc51701b8p-1L, +pio4lo = 0x1.cd129024e088a67cc74020bbea60p-116L; +static const double +T39 = 0.000000028443389121318352, /* 0x1e8a7592977938.0p-78 */ +T41 = 0.000000011981013102001973, /* 0x19baa1b1223219.0p-79 */ +T43 = 0.0000000038303578044958070, /* 0x107385dfb24529.0p-80 */ +T45 = 0.0000000034664378216909893, /* 0x1dc6c702a05262.0p-81 */ +T47 = -0.0000000015090641701997785, /* -0x19ecef3569ebb6.0p-82 */ +T49 = 0.0000000029449552300483952, /* 0x194c0668da786a.0p-81 */ +T51 = -0.0000000022006995706097711, /* -0x12e763b8845268.0p-81 */ +T53 = 0.0000000015468200913196612, /* 0x1a92fc98c29554.0p-82 */ +T55 = -0.00000000061311613386849674, /* -0x151106cbc779a9.0p-83 */ +T57 = 1.4912469681508012e-10; /* 0x147edbdba6f43a.0p-85 */ +#define RPOLY(w) (T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + \ + w * (T25 + w * (T29 + w * (T33 + w * (T37 + w * (T41 + \ + w * (T45 + w * (T49 + w * (T53 + w * T57))))))))))))) +#define VPOLY(w) (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + \ + w * (T27 + w * (T31 + w * (T35 + w * (T39 + w * (T43 + \ + w * (T47 + w * (T51 + w * T55)))))))))))) +#endif + +long double __tanl(long double x, long double y, int odd) { + long double z, r, v, w, s, a, t; + int big, sign; + + big = fabsl(x) >= 0.67434; + if (big) { + sign = 0; + if (x < 0) { + sign = 1; + x = -x; + y = -y; + } + x = (pio4 - x) + (pio4lo - y); + y = 0.0; + } + z = x * x; + w = z * z; + r = RPOLY(w); + v = z * VPOLY(w); + s = z * x; + r = y + z * (s * (r + v) + y) + T3 * s; + w = x + r; + if (big) { + s = 1 - 2*odd; + v = s - 2.0 * (x + (r - w * w / (w + s))); + return sign ? -v : v; + } + if (!odd) + return w; + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + z = w; + z = z + 0x1p32 - 0x1p32; + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + t = t + 0x1p32 - 0x1p32; + s = 1.0 + t * z; + return t + a * (s + t * v); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/acos.c b/user/include/mlibc/options/ansi/musl-generic-math/acos.c new file mode 100644 index 0000000..ea9c87b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/acos.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include "libm.h" + +static const double +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) +{ + double_t p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + return p/q; +} + +double acos(double x) +{ + double z,w,s,c,df; + uint32_t hx,ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + + GET_LOW_WORD(lx,x); + if ((ix-0x3ff00000 | lx) == 0) { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) + return 2*pio2_hi + 0x1p-120f; + return 0; + } + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + if (ix <= 0x3c600000) /* |x| < 2**-57 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo-x*R(x*x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1.0+x)*0.5; + s = sqrt(z); + w = R(z)*s-pio2_lo; + return 2*(pio2_hi - (s+w)); + } + /* x > 0.5 */ + z = (1.0-x)*0.5; + s = sqrt(z); + df = s; + SET_LOW_WORD(df,0); + c = (z-df*df)/(s+df); + w = R(z)*s+c; + return 2*(df+w); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/acosf.c b/user/include/mlibc/options/ansi/musl-generic-math/acosf.c new file mode 100644 index 0000000..8ee1a71 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/acosf.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ +pio2_lo = 7.5497894159e-08, /* 0x33a22168 */ +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +static float R(float z) +{ + float_t p, q; + p = z*(pS0+z*(pS1+z*pS2)); + q = 1.0f+z*qS1; + return p/q; +} + +float acosf(float x) +{ + float z,w,s,c,df; + uint32_t hx,ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3f800000) { + if (ix == 0x3f800000) { + if (hx >> 31) + return 2*pio2_hi + 0x1p-120f; + return 0; + } + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3f000000) { + if (ix <= 0x32800000) /* |x| < 2**-26 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo-x*R(x*x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1+x)*0.5f; + s = sqrtf(z); + w = R(z)*s-pio2_lo; + return 2*(pio2_hi - (s+w)); + } + /* x > 0.5 */ + z = (1-x)*0.5f; + s = sqrtf(z); + GET_FLOAT_WORD(hx,s); + SET_FLOAT_WORD(df,hx&0xfffff000); + c = (z-df*df)/(s+df); + w = R(z)*s+c; + return 2*(df+w); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/acosh.c b/user/include/mlibc/options/ansi/musl-generic-math/acosh.c new file mode 100644 index 0000000..badbf90 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/acosh.c @@ -0,0 +1,24 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrt +#define sqrt sqrtl +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +double acosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if (e < 0x3ff + 1) + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x-1 + sqrt((x-1)*(x-1)+2*(x-1))); + if (e < 0x3ff + 26) + /* |x| < 0x1p26 */ + return log(2*x - 1/(x+sqrt(x*x-1))); + /* |x| >= 0x1p26 or nan */ + return log(x) + 0.693147180559945309417232121458176568; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/acoshf.c b/user/include/mlibc/options/ansi/musl-generic-math/acoshf.c new file mode 100644 index 0000000..8a4ec4d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/acoshf.c @@ -0,0 +1,26 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrtf +#define sqrtf sqrtl +#elif FLT_EVAL_METHOD==1 +#undef sqrtf +#define sqrtf sqrt +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +float acoshf(float x) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t a = u.i & 0x7fffffff; + + if (a < 0x3f800000+(1<<23)) + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x-1 + sqrtf((x-1)*(x-1)+2*(x-1))); + if (a < 0x3f800000+(12<<23)) + /* |x| < 0x1p12 */ + return logf(2*x - 1/(x+sqrtf(x*x-1))); + /* x >= 0x1p12 */ + return logf(x) + 0.693147180559945309417232121458176568f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/acoshl.c b/user/include/mlibc/options/ansi/musl-generic-math/acoshl.c new file mode 100644 index 0000000..8d4b43f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/acoshl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acoshl(long double x) +{ + return acosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* acosh(x) = log(x + sqrt(x*x-1)) */ +long double acoshl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (e < 0x3fff + 1) + /* |x| < 2, invalid if x < 1 or nan */ + return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1))); + if (e < 0x3fff + 32) + /* |x| < 0x1p32 */ + return logl(2*x - 1/(x+sqrtl(x*x-1))); + return logl(x) + 0.693147180559945309417232121458176568L; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double acoshl(long double x) +{ + return acosh(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/acosl.c b/user/include/mlibc/options/ansi/musl-generic-math/acosl.c new file mode 100644 index 0000000..c03bdf0 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/acosl.c @@ -0,0 +1,67 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in acos.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acosl(long double x) +{ + return acos(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" +#if LDBL_MANT_DIG == 64 +#define CLEARBOTTOM(u) (u.i.m &= -1ULL << 32) +#elif LDBL_MANT_DIG == 113 +#define CLEARBOTTOM(u) (u.i.lo = 0) +#endif + +long double acosl(long double x) +{ + union ldshape u = {x}; + long double z, s, c, f; + uint16_t e = u.i.se & 0x7fff; + + /* |x| >= 1 or nan */ + if (e >= 0x3fff) { + if (x == 1) + return 0; + if (x == -1) + return 2*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + /* |x| < 0.5 */ + if (e < 0x3fff - 1) { + if (e < 0x3fff - LDBL_MANT_DIG - 1) + return pio2_hi + 0x1p-120f; + return pio2_hi - (__invtrigl_R(x*x)*x - pio2_lo + x); + } + /* x < -0.5 */ + if (u.i.se >> 15) { + z = (1 + x)*0.5; + s = sqrtl(z); + return 2*(pio2_hi - (__invtrigl_R(z)*s - pio2_lo + s)); + } + /* x > 0.5 */ + z = (1 - x)*0.5; + s = sqrtl(z); + u.f = s; + CLEARBOTTOM(u); + f = u.f; + c = (z - f*f)/(s + f); + return 2*(__invtrigl_R(z)*s + c + f); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/asin.c b/user/include/mlibc/options/ansi/musl-generic-math/asin.c new file mode 100644 index 0000000..c926b18 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/asin.c @@ -0,0 +1,107 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +#include "libm.h" + +static const double +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +/* coefficients for R(x^2) */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) +{ + double_t p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + return p/q; +} + +double asin(double x) +{ + double z,r,s; + uint32_t hx,ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + GET_LOW_WORD(lx, x); + if ((ix-0x3ff00000 | lx) == 0) + /* asin(1) = +-pi/2 with inexact */ + return x*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if (ix < 0x3e500000 && ix >= 0x00100000) + return x; + return x + x*R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1 - fabs(x))*0.5; + s = sqrt(z); + r = R(z); + if (ix >= 0x3fef3333) { /* if |x| > 0.975 */ + x = pio2_hi-(2*(s+s*r)-pio2_lo); + } else { + double f,c; + /* f+c = sqrt(z) */ + f = s; + SET_LOW_WORD(f,0); + c = (z-f*f)/(s+f); + x = 0.5*pio2_hi - (2*s*r - (pio2_lo-2*c) - (0.5*pio2_hi-2*f)); + } + if (hx >> 31) + return -x; + return x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/asinf.c b/user/include/mlibc/options/ansi/musl-generic-math/asinf.c new file mode 100644 index 0000000..bcd304a --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/asinf.c @@ -0,0 +1,61 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +#include "libm.h" + +static const double +pio2 = 1.570796326794896558e+00; + +static const float +/* coefficients for R(x^2) */ +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +static float R(float z) +{ + float_t p, q; + p = z*(pS0+z*(pS1+z*pS2)); + q = 1.0f+z*qS1; + return p/q; +} + +float asinf(float x) +{ + double s; + float z; + uint32_t hx,ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + if (ix >= 0x3f800000) { /* |x| >= 1 */ + if (ix == 0x3f800000) /* |x| == 1 */ + return x*pio2 + 0x1p-120f; /* asin(+-1) = +-pi/2 with inexact */ + return 0/(x-x); /* asin(|x|>1) is NaN */ + } + if (ix < 0x3f000000) { /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (ix < 0x39800000 && ix >= 0x00800000) + return x; + return x + x*R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1 - fabsf(x))*0.5f; + s = sqrt(z); + x = pio2 - 2*(s+s*R(z)); + if (hx >> 31) + return -x; + return x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/asinh.c b/user/include/mlibc/options/ansi/musl-generic-math/asinh.c new file mode 100644 index 0000000..0829f22 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/asinh.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +double asinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + + if (e >= 0x3ff + 26) { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + 0.693147180559945309417232121458176568; + } else if (e >= 0x3ff + 1) { + /* |x| >= 2 */ + x = log(2*x + 1/(sqrt(x*x+1)+x)); + } else if (e >= 0x3ff - 26) { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x*x/(sqrt(x*x+1)+1)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/asinhf.c b/user/include/mlibc/options/ansi/musl-generic-math/asinhf.c new file mode 100644 index 0000000..fc9f091 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/asinhf.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +float asinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t i = u.i & 0x7fffffff; + unsigned s = u.i >> 31; + + /* |x| */ + u.i = i; + x = u.f; + + if (i >= 0x3f800000 + (12<<23)) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + 0.693147180559945309417232121458176568f; + } else if (i >= 0x3f800000 + (1<<23)) { + /* |x| >= 2 */ + x = logf(2*x + 1/(sqrtf(x*x+1)+x)); + } else if (i >= 0x3f800000 - (12<<23)) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x*x/(sqrtf(x*x+1)+1)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/asinhl.c b/user/include/mlibc/options/ansi/musl-generic-math/asinhl.c new file mode 100644 index 0000000..8635f52 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/asinhl.c @@ -0,0 +1,41 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinhl(long double x) +{ + return asinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +long double asinhl(long double x) +{ + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e >= 0x3fff + 32) { + /* |x| >= 0x1p32 or inf or nan */ + x = logl(x) + 0.693147180559945309417232121458176568L; + } else if (e >= 0x3fff + 1) { + /* |x| >= 2 */ + x = logl(2*x + 1/(sqrtl(x*x+1)+x)); + } else if (e >= 0x3fff - 32) { + /* |x| >= 0x1p-32 */ + x = log1pl(x + x*x/(sqrtl(x*x+1)+1)); + } else { + /* |x| < 0x1p-32, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double asinhl(long double x) +{ + return asinh(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/asinl.c b/user/include/mlibc/options/ansi/musl-generic-math/asinl.c new file mode 100644 index 0000000..347c535 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/asinl.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in asin.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinl(long double x) +{ + return asin(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" +#if LDBL_MANT_DIG == 64 +#define CLOSETO1(u) (u.i.m>>56 >= 0xf7) +#define CLEARBOTTOM(u) (u.i.m &= -1ULL << 32) +#elif LDBL_MANT_DIG == 113 +#define CLOSETO1(u) (u.i.top >= 0xee00) +#define CLEARBOTTOM(u) (u.i.lo = 0) +#endif + +long double asinl(long double x) +{ + union ldshape u = {x}; + long double z, r, s; + uint16_t e = u.i.se & 0x7fff; + int sign = u.i.se >> 15; + + if (e >= 0x3fff) { /* |x| >= 1 or nan */ + /* asin(+-1)=+-pi/2 with inexact */ + if (x == 1 || x == -1) + return x*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + if (e < 0x3fff - 1) { /* |x| < 0.5 */ + if (e < 0x3fff - (LDBL_MANT_DIG+1)/2) { + /* return x with inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return x; + } + return x + x*__invtrigl_R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabsl(x))*0.5; + s = sqrtl(z); + r = __invtrigl_R(z); + if (CLOSETO1(u)) { + x = pio2_hi - (2*(s+s*r)-pio2_lo); + } else { + long double f, c; + u.f = s; + CLEARBOTTOM(u); + f = u.f; + c = (z - f*f)/(s + f); + x = 0.5*pio2_hi-(2*s*r - (pio2_lo-2*c) - (0.5*pio2_hi-2*f)); + } + return sign ? -x : x; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atan.c b/user/include/mlibc/options/ansi/musl-generic-math/atan.c new file mode 100644 index 0000000..63b0ab2 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atan.c @@ -0,0 +1,116 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + + +#include "libm.h" + +static const double atanhi[] = { + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +static const double atanlo[] = { + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +static const double aT[] = { + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + +double atan(double x) +{ + double_t w,s1,s2,z; + uint32_t ix,sign; + int id; + + GET_HIGH_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x44100000) { /* if |x| >= 2^66 */ + if (isnan(x)) + return x; + z = atanhi[3] + 0x1p-120f; + return sign ? -z : z; + } + if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e400000) { /* |x| < 2^-27 */ + if (ix < 0x00100000) + /* raise underflow for subnormal x */ + FORCE_EVAL((float)x); + return x; + } + id = -1; + } else { + x = fabs(x); + if (ix < 0x3ff30000) { /* |x| < 1.1875 */ + if (ix < 0x3fe60000) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0*x-1.0)/(2.0+x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x-1.0)/(x+1.0); + } + } else { + if (ix < 0x40038000) { /* |x| < 2.4375 */ + id = 2; + x = (x-1.5)/(1.0+1.5*x); + } else { /* 2.4375 <= |x| < 2^66 */ + id = 3; + x = -1.0/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); + s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - (x*(s1+s2) - atanlo[id] - x); + return sign ? -z : z; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atan2.c b/user/include/mlibc/options/ansi/musl-generic-math/atan2.c new file mode 100644 index 0000000..5a1903c --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atan2.c @@ -0,0 +1,107 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */ +pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +double atan2(double y, double x) +{ + double z; + uint32_t m,lx,ly,ix,iy; + + if (isnan(x) || isnan(y)) + return x+y; + EXTRACT_WORDS(ix, lx, x); + EXTRACT_WORDS(iy, ly, y); + if ((ix-0x3ff00000 | lx) == 0) /* x = 1.0 */ + return atan(y); + m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */ + ix = ix & 0x7fffffff; + iy = iy & 0x7fffffff; + + /* when y = 0 */ + if ((iy|ly) == 0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi; /* atan(+0,-anything) = pi */ + case 3: return -pi; /* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if ((ix|lx) == 0) + return m&1 ? -pi/2 : pi/2; + /* when x is INF */ + if (ix == 0x7ff00000) { + if (iy == 0x7ff00000) { + switch(m) { + case 0: return pi/4; /* atan(+INF,+INF) */ + case 1: return -pi/4; /* atan(-INF,+INF) */ + case 2: return 3*pi/4; /* atan(+INF,-INF) */ + case 3: return -3*pi/4; /* atan(-INF,-INF) */ + } + } else { + switch(m) { + case 0: return 0.0; /* atan(+...,+INF) */ + case 1: return -0.0; /* atan(-...,+INF) */ + case 2: return pi; /* atan(+...,-INF) */ + case 3: return -pi; /* atan(-...,-INF) */ + } + } + } + /* |y/x| > 0x1p64 */ + if (ix+(64<<20) < iy || iy == 0x7ff00000) + return m&1 ? -pi/2 : pi/2; + + /* z = atan(|y/x|) without spurious underflow */ + if ((m&2) && iy+(64<<20) < ix) /* |y/x| < 0x1p-64, x<0 */ + z = 0; + else + z = atan(fabs(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return pi - (z-pi_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo) - pi; /* atan(-,-) */ + } +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atan2f.c b/user/include/mlibc/options/ansi/musl-generic-math/atan2f.c new file mode 100644 index 0000000..c634d00 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atan2f.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +pi = 3.1415927410e+00, /* 0x40490fdb */ +pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */ + +float atan2f(float y, float x) +{ + float z; + uint32_t m,ix,iy; + + if (isnan(x) || isnan(y)) + return x+y; + GET_FLOAT_WORD(ix, x); + GET_FLOAT_WORD(iy, y); + if (ix == 0x3f800000) /* x=1.0 */ + return atanf(y); + m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy == 0) { + switch (m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi; /* atan(+0,-anything) = pi */ + case 3: return -pi; /* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if (ix == 0) + return m&1 ? -pi/2 : pi/2; + /* when x is INF */ + if (ix == 0x7f800000) { + if (iy == 0x7f800000) { + switch (m) { + case 0: return pi/4; /* atan(+INF,+INF) */ + case 1: return -pi/4; /* atan(-INF,+INF) */ + case 2: return 3*pi/4; /*atan(+INF,-INF)*/ + case 3: return -3*pi/4; /*atan(-INF,-INF)*/ + } + } else { + switch (m) { + case 0: return 0.0f; /* atan(+...,+INF) */ + case 1: return -0.0f; /* atan(-...,+INF) */ + case 2: return pi; /* atan(+...,-INF) */ + case 3: return -pi; /* atan(-...,-INF) */ + } + } + } + /* |y/x| > 0x1p26 */ + if (ix+(26<<23) < iy || iy == 0x7f800000) + return m&1 ? -pi/2 : pi/2; + + /* z = atan(|y/x|) with correct underflow */ + if ((m&2) && iy+(26<<23) < ix) /*|y/x| < 0x1p-26, x < 0 */ + z = 0.0; + else + z = atanf(fabsf(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return pi - (z-pi_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo) - pi; /* atan(-,-) */ + } +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atan2l.c b/user/include/mlibc/options/ansi/musl-generic-math/atan2l.c new file mode 100644 index 0000000..f0937a9 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atan2l.c @@ -0,0 +1,85 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2l.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* + * See comments in atan2.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atan2l(long double y, long double x) +{ + return atan2(y, x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" + +long double atan2l(long double y, long double x) +{ + union ldshape ux, uy; + long double z; + int m, ex, ey; + + if (isnan(x) || isnan(y)) + return x+y; + if (x == 1) + return atanl(y); + ux.f = x; + uy.f = y; + ex = ux.i.se & 0x7fff; + ey = uy.i.se & 0x7fff; + m = 2*(ux.i.se>>15) | uy.i.se>>15; + if (y == 0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return 2*pio2_hi; /* atan(+0,-anything) = pi */ + case 3: return -2*pio2_hi; /* atan(-0,-anything) =-pi */ + } + } + if (x == 0) + return m&1 ? -pio2_hi : pio2_hi; + if (ex == 0x7fff) { + if (ey == 0x7fff) { + switch(m) { + case 0: return pio2_hi/2; /* atan(+INF,+INF) */ + case 1: return -pio2_hi/2; /* atan(-INF,+INF) */ + case 2: return 1.5*pio2_hi; /* atan(+INF,-INF) */ + case 3: return -1.5*pio2_hi; /* atan(-INF,-INF) */ + } + } else { + switch(m) { + case 0: return 0.0; /* atan(+...,+INF) */ + case 1: return -0.0; /* atan(-...,+INF) */ + case 2: return 2*pio2_hi; /* atan(+...,-INF) */ + case 3: return -2*pio2_hi; /* atan(-...,-INF) */ + } + } + } + if (ex+120 < ey || ey == 0x7fff) + return m&1 ? -pio2_hi : pio2_hi; + /* z = atan(|y/x|) without spurious underflow */ + if ((m&2) && ey+120 < ex) /* |y/x| < 0x1p-120, x<0 */ + z = 0.0; + else + z = atanl(fabsl(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return 2*pio2_hi-(z-2*pio2_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-2*pio2_lo)-2*pio2_hi; /* atan(-,-) */ + } +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atanf.c b/user/include/mlibc/options/ansi/musl-generic-math/atanf.c new file mode 100644 index 0000000..178341b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atanf.c @@ -0,0 +1,94 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +#include "libm.h" + +static const float atanhi[] = { + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +}; + +static const float atanlo[] = { + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +}; + +static const float aT[] = { + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +}; + +float atanf(float x) +{ + float_t w,s1,s2,z; + uint32_t ix,sign; + int id; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x4c800000) { /* if |x| >= 2**26 */ + if (isnan(x)) + return x; + z = atanhi[3] + 0x1p-120f; + return sign ? -z : z; + } + if (ix < 0x3ee00000) { /* |x| < 0.4375 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + if (ix < 0x00800000) + /* raise underflow for subnormal x */ + FORCE_EVAL(x*x); + return x; + } + id = -1; + } else { + x = fabsf(x); + if (ix < 0x3f980000) { /* |x| < 1.1875 */ + if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0f*x - 1.0f)/(2.0f + x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x - 1.0f)/(x + 1.0f); + } + } else { + if (ix < 0x401c0000) { /* |x| < 2.4375 */ + id = 2; + x = (x - 1.5f)/(1.0f + 1.5f*x); + } else { /* 2.4375 <= |x| < 2**26 */ + id = 3; + x = -1.0f/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*aT[4])); + s2 = w*(aT[1]+w*aT[3]); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return sign ? -z : z; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atanh.c b/user/include/mlibc/options/ansi/musl-generic-math/atanh.c new file mode 100644 index 0000000..63a035d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atanh.c @@ -0,0 +1,29 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +double atanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + double_t y; + + /* |x| */ + u.i &= (uint64_t)-1/2; + y = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - 32) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)y); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5*log1p(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5*log1p(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atanhf.c b/user/include/mlibc/options/ansi/musl-generic-math/atanhf.c new file mode 100644 index 0000000..65f07c0 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atanhf.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +float atanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + unsigned s = u.i >> 31; + float_t y; + + /* |x| */ + u.i &= 0x7fffffff; + y = u.f; + + if (u.i < 0x3f800000 - (1<<23)) { + if (u.i < 0x3f800000 - (32<<23)) { + /* handle underflow */ + if (u.i < (1<<23)) + FORCE_EVAL((float)(y*y)); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5f*log1pf(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5f*log1pf(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atanhl.c b/user/include/mlibc/options/ansi/musl-generic-math/atanhl.c new file mode 100644 index 0000000..87cd1cd --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atanhl.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanhl(long double x) +{ + return atanh(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +long double atanhl(long double x) +{ + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - LDBL_MANT_DIG/2) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)x); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5*log1pl(2*x + 2*x*x/(1-x)); + } + } else { + /* avoid overflow */ + x = 0.5*log1pl(2*(x/(1-x))); + } + return s ? -x : x; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/atanl.c b/user/include/mlibc/options/ansi/musl-generic-math/atanl.c new file mode 100644 index 0000000..79a3edb --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/atanl.c @@ -0,0 +1,184 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in atan.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanl(long double x) +{ + return atan(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +#if LDBL_MANT_DIG == 64 +#define EXPMAN(u) ((u.i.se & 0x7fff)<<8 | (u.i.m>>55 & 0xff)) + +static const long double atanhi[] = { + 4.63647609000806116202e-01L, + 7.85398163397448309628e-01L, + 9.82793723247329067960e-01L, + 1.57079632679489661926e+00L, +}; + +static const long double atanlo[] = { + 1.18469937025062860669e-20L, + -1.25413940316708300586e-20L, + 2.55232234165405176172e-20L, + -2.50827880633416601173e-20L, +}; + +static const long double aT[] = { + 3.33333333333333333017e-01L, + -1.99999999999999632011e-01L, + 1.42857142857046531280e-01L, + -1.11111111100562372733e-01L, + 9.09090902935647302252e-02L, + -7.69230552476207730353e-02L, + 6.66661718042406260546e-02L, + -5.88158892835030888692e-02L, + 5.25499891539726639379e-02L, + -4.70119845393155721494e-02L, + 4.03539201366454414072e-02L, + -2.91303858419364158725e-02L, + 1.24822046299269234080e-02L, +}; + +static long double T_even(long double x) +{ + return aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + + x * (aT[8] + x * (aT[10] + x * aT[12]))))); +} + +static long double T_odd(long double x) +{ + return aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + + x * (aT[9] + x * aT[11])))); +} +#elif LDBL_MANT_DIG == 113 +#define EXPMAN(u) ((u.i.se & 0x7fff)<<8 | u.i.top>>8) + +const long double atanhi[] = { + 4.63647609000806116214256231461214397e-01L, + 7.85398163397448309615660845819875699e-01L, + 9.82793723247329067985710611014666038e-01L, + 1.57079632679489661923132169163975140e+00L, +}; + +const long double atanlo[] = { + 4.89509642257333492668618435220297706e-36L, + 2.16795253253094525619926100651083806e-35L, + -2.31288434538183565909319952098066272e-35L, + 4.33590506506189051239852201302167613e-35L, +}; + +const long double aT[] = { + 3.33333333333333333333333333333333125e-01L, + -1.99999999999999999999999999999180430e-01L, + 1.42857142857142857142857142125269827e-01L, + -1.11111111111111111111110834490810169e-01L, + 9.09090909090909090908522355708623681e-02L, + -7.69230769230769230696553844935357021e-02L, + 6.66666666666666660390096773046256096e-02L, + -5.88235294117646671706582985209643694e-02L, + 5.26315789473666478515847092020327506e-02L, + -4.76190476189855517021024424991436144e-02L, + 4.34782608678695085948531993458097026e-02L, + -3.99999999632663469330634215991142368e-02L, + 3.70370363987423702891250829918659723e-02L, + -3.44827496515048090726669907612335954e-02L, + 3.22579620681420149871973710852268528e-02L, + -3.03020767654269261041647570626778067e-02L, + 2.85641979882534783223403715930946138e-02L, + -2.69824879726738568189929461383741323e-02L, + 2.54194698498808542954187110873675769e-02L, + -2.35083879708189059926183138130183215e-02L, + 2.04832358998165364349957325067131428e-02L, + -1.54489555488544397858507248612362957e-02L, + 8.64492360989278761493037861575248038e-03L, + -2.58521121597609872727919154569765469e-03L, +}; + +static long double T_even(long double x) +{ + return (aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + x * (aT[8] + + x * (aT[10] + x * (aT[12] + x * (aT[14] + x * (aT[16] + + x * (aT[18] + x * (aT[20] + x * aT[22]))))))))))); +} + +static long double T_odd(long double x) +{ + return (aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + x * (aT[9] + + x * (aT[11] + x * (aT[13] + x * (aT[15] + x * (aT[17] + + x * (aT[19] + x * (aT[21] + x * aT[23]))))))))))); +} +#endif + +long double atanl(long double x) +{ + union ldshape u = {x}; + long double w, s1, s2, z; + int id; + unsigned e = u.i.se & 0x7fff; + unsigned sign = u.i.se >> 15; + unsigned expman; + + if (e >= 0x3fff + LDBL_MANT_DIG + 1) { /* if |x| is large, atan(x)~=pi/2 */ + if (isnan(x)) + return x; + return sign ? -atanhi[3] : atanhi[3]; + } + /* Extract the exponent and the first few bits of the mantissa. */ + expman = EXPMAN(u); + if (expman < ((0x3fff - 2) << 8) + 0xc0) { /* |x| < 0.4375 */ + if (e < 0x3fff - (LDBL_MANT_DIG+1)/2) { /* if |x| is small, atanl(x)~=x */ + /* raise underflow if subnormal */ + if (e == 0) + FORCE_EVAL((float)x); + return x; + } + id = -1; + } else { + x = fabsl(x); + if (expman < (0x3fff << 8) + 0x30) { /* |x| < 1.1875 */ + if (expman < ((0x3fff - 1) << 8) + 0x60) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0*x-1.0)/(2.0+x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x-1.0)/(x+1.0); + } + } else { + if (expman < ((0x3fff + 1) << 8) + 0x38) { /* |x| < 2.4375 */ + id = 2; + x = (x-1.5)/(1.0+1.5*x); + } else { /* 2.4375 <= |x| */ + id = 3; + x = -1.0/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum aT[i]z**(i+1) into odd and even poly */ + s1 = z*T_even(w); + s2 = w*T_odd(w); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return sign ? -z : z; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/cbrt.c b/user/include/mlibc/options/ansi/musl-generic-math/cbrt.c new file mode 100644 index 0000000..7599d3e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/cbrt.c @@ -0,0 +1,103 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* cbrt(x) + * Return cube root of x + */ + +#include +#include + +static const uint32_t +B1 = 715094163, /* B1 = (1023-1023/3-0.03306235651)*2**20 */ +B2 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +static const double +P0 = 1.87595182427177009643, /* 0x3ffe03e6, 0x0f61e692 */ +P1 = -1.88497979543377169875, /* 0xbffe28e0, 0x92f02420 */ +P2 = 1.621429720105354466140, /* 0x3ff9f160, 0x4a49d6c2 */ +P3 = -0.758397934778766047437, /* 0xbfe844cb, 0xbee751d9 */ +P4 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +double cbrt(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t r,s,t,w; + uint32_t hx = u.i>>32 & 0x7fffffff; + + if (hx >= 0x7ff00000) /* cbrt(NaN,INF) is itself */ + return x+x; + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if (hx < 0x00100000) { /* zero or subnormal? */ + u.f = x*0x1p54; + hx = u.i>>32 & 0x7fffffff; + if (hx == 0) + return x; /* cbrt(0) is itself */ + hx = hx/3 + B2; + } else + hx = hx/3 + B1; + u.i &= 1ULL<<63; + u.i |= (uint64_t)hx << 32; + t = u.f; + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in __tanf.c. + */ + r = (t*t)*(t/x); + t = t*((P0+r*(P1+r*P2))+((r*r)*r)*(P3+r*P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + u.f = t; + u.i = (u.i + 0x80000000) & 0xffffffffc0000000ULL; + t = u.f; + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s = t*t; /* t*t is exact */ + r = x/s; /* error <= 0.5 ulps; |r| < |t| */ + w = t+t; /* t+t is exact */ + r = (r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t = t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + return t; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/cbrtf.c b/user/include/mlibc/options/ansi/musl-generic-math/cbrtf.c new file mode 100644 index 0000000..89c2c86 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/cbrtf.c @@ -0,0 +1,66 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +#include +#include + +static const unsigned +B1 = 709958130, /* B1 = (127-127.0/3-0.03306235651)*2**23 */ +B2 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +float cbrtf(float x) +{ + double_t r,T; + union {float f; uint32_t i;} u = {x}; + uint32_t hx = u.i & 0x7fffffff; + + if (hx >= 0x7f800000) /* cbrt(NaN,INF) is itself */ + return x + x; + + /* rough cbrt to 5 bits */ + if (hx < 0x00800000) { /* zero or subnormal? */ + if (hx == 0) + return x; /* cbrt(+-0) is itself */ + u.f = x*0x1p24f; + hx = u.i & 0x7fffffff; + hx = hx/3 + B2; + } else + hx = hx/3 + B1; + u.i &= 0x80000000; + u.i |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + T = u.f; + r = T*T*T; + T = T*((double_t)x+x+r)/(x+r+r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = T*T*T; + T = T*((double_t)x+x+r)/(x+r+r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + return T; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/cbrtl.c b/user/include/mlibc/options/ansi/musl-generic-math/cbrtl.c new file mode 100644 index 0000000..ceff913 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/cbrtl.c @@ -0,0 +1,124 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtl.c */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * The argument reduction and testing for exceptional cases was + * written by Steven G. Kargl with input from Bruce D. Evans + * and David A. Schultz. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cbrtl(long double x) +{ + return cbrt(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +static const unsigned B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + +long double cbrtl(long double x) +{ + union ldshape u = {x}, v; + union {float f; uint32_t i;} uft; + long double r, s, t, w; + double_t dr, dt, dx; + float_t ft; + int e = u.i.se & 0x7fff; + int sign = u.i.se & 0x8000; + + /* + * If x = +-Inf, then cbrt(x) = +-Inf. + * If x = NaN, then cbrt(x) = NaN. + */ + if (e == 0x7fff) + return x + x; + if (e == 0) { + /* Adjust subnormal numbers. */ + u.f *= 0x1p120; + e = u.i.se & 0x7fff; + /* If x = +-0, then cbrt(x) = +-0. */ + if (e == 0) + return x; + e -= 120; + } + e -= 0x3fff; + u.i.se = 0x3fff; + x = u.f; + switch (e % 3) { + case 1: + case -2: + x *= 2; + e--; + break; + case 2: + case -1: + x *= 4; + e -= 2; + break; + } + v.f = 1.0; + v.i.se = sign | (0x3fff + e/3); + + /* + * The following is the guts of s_cbrtf, with the handling of + * special values removed and extra care for accuracy not taken, + * but with most of the extra accuracy not discarded. + */ + + /* ~5-bit estimate: */ + uft.f = x; + uft.i = (uft.i & 0x7fffffff)/3 + B1; + ft = uft.f; + + /* ~16-bit estimate: */ + dx = x; + dt = ft; + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + + /* ~47-bit estimate: */ + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + +#if LDBL_MANT_DIG == 64 + /* + * dt is cbrtl(x) to ~47 bits (after x has been reduced to 1 <= x < 8). + * Round it away from zero to 32 bits (32 so that t*t is exact, and + * away from zero for technical reasons). + */ + t = dt + (0x1.0p32L + 0x1.0p-31L) - 0x1.0p32; +#elif LDBL_MANT_DIG == 113 + /* + * Round dt away from zero to 47 bits. Since we don't trust the 47, + * add 2 47-bit ulps instead of 1 to round up. Rounding is slow and + * might be avoidable in this case, since on most machines dt will + * have been evaluated in 53-bit precision and the technical reasons + * for rounding up might not apply to either case in cbrtl() since + * dt is much more accurate than needed. + */ + t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60; +#endif + + /* + * Final step Newton iteration to 64 or 113 bits with + * error < 0.667 ulps + */ + s = t*t; /* t*t is exact */ + r = x/s; /* error <= 0.5 ulps; |r| < |t| */ + w = t+t; /* t+t is exact */ + r = (r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t = t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + + t *= v.f; + return t; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ceil.c b/user/include/mlibc/options/ansi/musl-generic-math/ceil.c new file mode 100644 index 0000000..b13e6f2 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ceil.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double ceil(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff-1) { + FORCE_EVAL(y); + return u.i >> 63 ? -0.0 : 1; + } + if (y < 0) + return x + y + 1; + return x + y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ceilf.c b/user/include/mlibc/options/ansi/musl-generic-math/ceilf.c new file mode 100644 index 0000000..869835f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ceilf.c @@ -0,0 +1,27 @@ +#include "libm.h" + +float ceilf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.f = -0.0; + else if (u.i << 1) + u.f = 1.0; + } + return u.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ceill.c b/user/include/mlibc/options/ansi/musl-generic-math/ceill.c new file mode 100644 index 0000000..60a8302 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ceill.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double ceill(long double x) +{ + return ceil(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double ceill(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i.se >> 15) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3fff-1) { + FORCE_EVAL(y); + return u.i.se >> 15 ? -0.0 : 1; + } + if (y < 0) + return x + y + 1; + return x + y; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/copysign.c b/user/include/mlibc/options/ansi/musl-generic-math/copysign.c new file mode 100644 index 0000000..b09331b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/copysign.c @@ -0,0 +1,8 @@ +#include "libm.h" + +double copysign(double x, double y) { + union {double f; uint64_t i;} ux={x}, uy={y}; + ux.i &= -1ULL/2; + ux.i |= uy.i & 1ULL<<63; + return ux.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/copysignf.c b/user/include/mlibc/options/ansi/musl-generic-math/copysignf.c new file mode 100644 index 0000000..0af6ae9 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/copysignf.c @@ -0,0 +1,10 @@ +#include +#include + +float copysignf(float x, float y) +{ + union {float f; uint32_t i;} ux={x}, uy={y}; + ux.i &= 0x7fffffff; + ux.i |= uy.i & 0x80000000; + return ux.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/copysignl.c b/user/include/mlibc/options/ansi/musl-generic-math/copysignl.c new file mode 100644 index 0000000..9dd933c --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/copysignl.c @@ -0,0 +1,16 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double copysignl(long double x, long double y) +{ + return copysign(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double copysignl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + ux.i.se &= 0x7fff; + ux.i.se |= uy.i.se & 0x8000; + return ux.f; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/cos.c b/user/include/mlibc/options/ansi/musl-generic-math/cos.c new file mode 100644 index 0000000..ee97f68 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/cos.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cos(x) + * Return cosine function of x. + * + * kernel function: + * __sin ... sine function on [-pi/4,pi/4] + * __cos ... cosine function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double cos(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */ + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0; + } + return __cos(x, 0); + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x-x; + + /* argument reduction */ + n = __rem_pio2(x, y); + switch (n&3) { + case 0: return __cos(y[0], y[1]); + case 1: return -__sin(y[0], y[1], 1); + case 2: return -__cos(y[0], y[1]); + default: + return __sin(y[0], y[1], 1); + } +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/cosf.c b/user/include/mlibc/options/ansi/musl-generic-math/cosf.c new file mode 100644 index 0000000..23f3e5b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/cosf.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float cosf(float x) +{ + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0f; + } + return __cosdf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ + return -__cosdf(sign ? x+c2pio2 : x-c2pio2); + else { + if (sign) + return __sindf(x + c1pio2); + else + return __sindf(c1pio2 - x); + } + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ + return __cosdf(sign ? x+c4pio2 : x-c4pio2); + else { + if (sign) + return __sindf(-x - c3pio2); + else + return __sindf(x - c3pio2); + } + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x-x; + + /* general argument reduction needed */ + n = __rem_pio2f(x,&y); + switch (n&3) { + case 0: return __cosdf(y); + case 1: return __sindf(-y); + case 2: return -__cosdf(y); + default: + return __sindf(y); + } +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/cosh.c b/user/include/mlibc/options/ansi/musl-generic-math/cosh.c new file mode 100644 index 0000000..100f823 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/cosh.c @@ -0,0 +1,40 @@ +#include "libm.h" + +/* cosh(x) = (exp(x) + 1/exp(x))/2 + * = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x) + * = 1 + x*x/2 + o(x^4) + */ +double cosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + /* |x| < log(2) */ + if (w < 0x3fe62e42) { + if (w < 0x3ff00000 - (26<<20)) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5*(t + 1/t); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = __expo2(x); + return t; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/coshf.c b/user/include/mlibc/options/ansi/musl-generic-math/coshf.c new file mode 100644 index 0000000..b09f2ee --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/coshf.c @@ -0,0 +1,33 @@ +#include "libm.h" + +float coshf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t; + + /* |x| */ + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + /* |x| < log(2) */ + if (w < 0x3f317217) { + if (w < 0x3f800000 - (12<<23)) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1f(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expf(x); + return 0.5f*(t + 1/t); + } + + /* |x| > log(FLT_MAX) or nan */ + t = __expo2f(x); + return t; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/coshl.c b/user/include/mlibc/options/ansi/musl-generic-math/coshl.c new file mode 100644 index 0000000..06a56fe --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/coshl.c @@ -0,0 +1,47 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double coshl(long double x) +{ + return cosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double coshl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + uint32_t w; + long double t; + + /* |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + /* |x| < log(2) */ + if (ex < 0x3fff-1 || (ex == 0x3fff-1 && w < 0xb17217f7)) { + if (ex < 0x3fff-32) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1l(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff+13 || (ex == 0x3fff+13 && w < 0xb17217f7)) { + t = expl(x); + return 0.5*(t + 1/t); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5*x); + return 0.5*t*t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double coshl(long double x) +{ + return cosh(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/cosl.c b/user/include/mlibc/options/ansi/musl-generic-math/cosl.c new file mode 100644 index 0000000..79c41c7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/cosl.c @@ -0,0 +1,39 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cosl(long double x) { + return cos(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double cosl(long double x) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], hi, lo; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + x = u.f; + if (x < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) + /* raise inexact if x!=0 */ + return 1.0 + x; + return __cosl(x, 0); + } + n = __rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + switch (n & 3) { + case 0: + return __cosl(hi, lo); + case 1: + return -__sinl(hi, lo, 1); + case 2: + return -__cosl(hi, lo); + case 3: + default: + return __sinl(hi, lo, 1); + } +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/erf.c b/user/include/mlibc/options/ansi/musl-generic-math/erf.c new file mode 100644 index 0000000..2f30a29 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/erf.c @@ -0,0 +1,273 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +#include "libm.h" + +static const double +erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx8 = 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */ +pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */ +pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */ +pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */ +pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */ +pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */ +qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */ +qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */ +qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */ +qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */ +qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */ +pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */ +pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */ +pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */ +pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */ +pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */ +pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */ +qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */ +qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */ +qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */ +qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */ +qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */ +qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */ +ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */ +ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */ +ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */ +ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */ +ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */ +ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */ +ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */ +sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */ +sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */ +sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */ +sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */ +sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */ +sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */ +sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */ +sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */ +rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */ +rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */ +rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */ +rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */ +rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */ +rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */ +sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */ +sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */ +sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */ +sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */ +sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */ +sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */ +sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +static double erfc1(double x) +{ + double_t s,P,Q; + + s = fabs(x) - 1; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = 1+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + return 1 - erx - P/Q; +} + +static double erfc2(uint32_t ix, double x) +{ + double_t s,R,S; + double z; + + if (ix < 0x3ff40000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabs(x); + s = 1/(x*x); + if (ix < 0x4006db6d) { /* |x| < 1/.35 ~ 2.85714 */ + R = ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S = 1.0+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| > 1/.35 */ + R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S = 1.0+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + z = x; + SET_LOW_WORD(z,0); + return exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S)/x; +} + +double erf(double x) +{ + double r,s,z,y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1-2*sign + 1/x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3e300000) { /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125*(8*x + efx8*x); + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if (ix < 0x40180000) /* 0.84375 <= |x| < 6 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-1022; + return sign ? -y : y; +} + +double erfc(double x) +{ + double r,s,z,y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2*sign + 1/x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3c700000) /* |x| < 2**-56 */ + return 1.0 - x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if (sign || ix < 0x3fd00000) { /* x < 1/4 */ + return 1.0 - (x+x*y); + } + return 0.5 - (x - 0.5 + x*y); + } + if (ix < 0x403c0000) { /* 0.84375 <= |x| < 28 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + } + return sign ? 2 - 0x1p-1022 : 0x1p-1022*0x1p-1022; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/erff.c b/user/include/mlibc/options/ansi/musl-generic-math/erff.c new file mode 100644 index 0000000..ed5f397 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/erff.c @@ -0,0 +1,183 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +erx = 8.4506291151e-01, /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx8 = 1.0270333290e+00, /* 0x3f8375d4 */ +pp0 = 1.2837916613e-01, /* 0x3e0375d4 */ +pp1 = -3.2504209876e-01, /* 0xbea66beb */ +pp2 = -2.8481749818e-02, /* 0xbce9528f */ +pp3 = -5.7702702470e-03, /* 0xbbbd1489 */ +pp4 = -2.3763017452e-05, /* 0xb7c756b1 */ +qq1 = 3.9791721106e-01, /* 0x3ecbbbce */ +qq2 = 6.5022252500e-02, /* 0x3d852a63 */ +qq3 = 5.0813062117e-03, /* 0x3ba68116 */ +qq4 = 1.3249473704e-04, /* 0x390aee49 */ +qq5 = -3.9602282413e-06, /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */ +pa1 = 4.1485610604e-01, /* 0x3ed46805 */ +pa2 = -3.7220788002e-01, /* 0xbebe9208 */ +pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */ +pa4 = -1.1089469492e-01, /* 0xbde31cc2 */ +pa5 = 3.5478305072e-02, /* 0x3d1151b3 */ +pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */ +qa1 = 1.0642088205e-01, /* 0x3dd9f331 */ +qa2 = 5.4039794207e-01, /* 0x3f0a5785 */ +qa3 = 7.1828655899e-02, /* 0x3d931ae7 */ +qa4 = 1.2617121637e-01, /* 0x3e013307 */ +qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */ +qa6 = 1.1984500103e-02, /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.8649440333e-03, /* 0xbc21a093 */ +ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */ +ra2 = -1.0558626175e+01, /* 0xc128f022 */ +ra3 = -6.2375331879e+01, /* 0xc2798057 */ +ra4 = -1.6239666748e+02, /* 0xc322658c */ +ra5 = -1.8460508728e+02, /* 0xc3389ae7 */ +ra6 = -8.1287437439e+01, /* 0xc2a2932b */ +ra7 = -9.8143291473e+00, /* 0xc11d077e */ +sa1 = 1.9651271820e+01, /* 0x419d35ce */ +sa2 = 1.3765776062e+02, /* 0x4309a863 */ +sa3 = 4.3456588745e+02, /* 0x43d9486f */ +sa4 = 6.4538726807e+02, /* 0x442158c9 */ +sa5 = 4.2900814819e+02, /* 0x43d6810b */ +sa6 = 1.0863500214e+02, /* 0x42d9451f */ +sa7 = 6.5702495575e+00, /* 0x40d23f7c */ +sa8 = -6.0424413532e-02, /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.8649431020e-03, /* 0xbc21a092 */ +rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */ +rb2 = -1.7757955551e+01, /* 0xc18e104b */ +rb3 = -1.6063638306e+02, /* 0xc320a2ea */ +rb4 = -6.3756646729e+02, /* 0xc41f6441 */ +rb5 = -1.0250950928e+03, /* 0xc480230b */ +rb6 = -4.8351919556e+02, /* 0xc3f1c275 */ +sb1 = 3.0338060379e+01, /* 0x41f2b459 */ +sb2 = 3.2579251099e+02, /* 0x43a2e571 */ +sb3 = 1.5367296143e+03, /* 0x44c01759 */ +sb4 = 3.1998581543e+03, /* 0x4547fdbb */ +sb5 = 2.5530502930e+03, /* 0x451f90ce */ +sb6 = 4.7452853394e+02, /* 0x43ed43a7 */ +sb7 = -2.2440952301e+01; /* 0xc1b38712 */ + +static float erfc1(float x) +{ + float_t s,P,Q; + + s = fabsf(x) - 1; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = 1+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + return 1 - erx - P/Q; +} + +static float erfc2(uint32_t ix, float x) +{ + float_t s,R,S; + float z; + + if (ix < 0x3fa00000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabsf(x); + s = 1/(x*x); + if (ix < 0x4036db6d) { /* |x| < 1/0.35 */ + R = ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S = 1.0f+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/0.35 */ + R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S = 1.0f+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + GET_FLOAT_WORD(ix, x); + SET_FLOAT_WORD(z, ix&0xffffe000); + return expf(-z*z - 0.5625f) * expf((z-x)*(z+x) + R/S)/x; +} + +float erff(float x) +{ + float r,s,z,y; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1-2*sign + 1/x; + } + if (ix < 0x3f580000) { /* |x| < 0.84375 */ + if (ix < 0x31800000) { /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125f*(8*x + efx8*x); + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if (ix < 0x40c00000) /* |x| < 6 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-120f; + return sign ? -y : y; +} + +float erfcf(float x) +{ + float r,s,z,y; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2*sign + 1/x; + } + + if (ix < 0x3f580000) { /* |x| < 0.84375 */ + if (ix < 0x23800000) /* |x| < 2**-56 */ + return 1.0f - x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0f+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if (sign || ix < 0x3e800000) /* x < 1/4 */ + return 1.0f - (x+x*y); + return 0.5f - (x - 0.5f + x*y); + } + if (ix < 0x41e00000) { /* |x| < 28 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + } + return sign ? 2 - 0x1p-120f : 0x1p-120f*0x1p-120f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/erfl.c b/user/include/mlibc/options/ansi/musl-generic-math/erfl.c new file mode 100644 index 0000000..e267c23 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/erfl.c @@ -0,0 +1,353 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_erfl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1(z)/S1(z)) + * z=1/x^2 + * erf(x) = 1 - erfc(x) + * + * 4. For x in [1/0.35,107] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2(z)/S2(z)) + * if -6.666 x >= 107 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double erfl(long double x) +{ + return erf(x); +} +long double erfcl(long double x) +{ + return erfc(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +erx = 0.845062911510467529296875L, + +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +/* 8 * (2/sqrt(pi) - 1) */ +efx8 = 1.0270333367641005911692712249723613735048E0L, +pp[6] = { + 1.122751350964552113068262337278335028553E6L, + -2.808533301997696164408397079650699163276E6L, + -3.314325479115357458197119660818768924100E5L, + -6.848684465326256109712135497895525446398E4L, + -2.657817695110739185591505062971929859314E3L, + -1.655310302737837556654146291646499062882E2L, +}, +qq[6] = { + 8.745588372054466262548908189000448124232E6L, + 3.746038264792471129367533128637019611485E6L, + 7.066358783162407559861156173539693900031E5L, + 7.448928604824620999413120955705448117056E4L, + 4.511583986730994111992253980546131408924E3L, + 1.368902937933296323345610240009071254014E2L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +/* erf(x+1) = 0.845062911510467529296875 + pa(x)/qa(x) + -0.15625 <= x <= +.25 + Peak relative error 8.5e-22 */ +pa[8] = { + -1.076952146179812072156734957705102256059E0L, + 1.884814957770385593365179835059971587220E2L, + -5.339153975012804282890066622962070115606E1L, + 4.435910679869176625928504532109635632618E1L, + 1.683219516032328828278557309642929135179E1L, + -2.360236618396952560064259585299045804293E0L, + 1.852230047861891953244413872297940938041E0L, + 9.394994446747752308256773044667843200719E-2L, +}, +qa[7] = { + 4.559263722294508998149925774781887811255E2L, + 3.289248982200800575749795055149780689738E2L, + 2.846070965875643009598627918383314457912E2L, + 1.398715859064535039433275722017479994465E2L, + 6.060190733759793706299079050985358190726E1L, + 2.078695677795422351040502569964299664233E1L, + 4.641271134150895940966798357442234498546E0L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + ra(x^2)/sa(x^2)) + 1/2.85711669921875 < 1/x < 1/1.25 + Peak relative error 3.1e-21 */ +ra[] = { + 1.363566591833846324191000679620738857234E-1L, + 1.018203167219873573808450274314658434507E1L, + 1.862359362334248675526472871224778045594E2L, + 1.411622588180721285284945138667933330348E3L, + 5.088538459741511988784440103218342840478E3L, + 8.928251553922176506858267311750789273656E3L, + 7.264436000148052545243018622742770549982E3L, + 2.387492459664548651671894725748959751119E3L, + 2.220916652813908085449221282808458466556E2L, +}, +sa[] = { + -1.382234625202480685182526402169222331847E1L, + -3.315638835627950255832519203687435946482E2L, + -2.949124863912936259747237164260785326692E3L, + -1.246622099070875940506391433635999693661E4L, + -2.673079795851665428695842853070996219632E4L, + -2.880269786660559337358397106518918220991E4L, + -1.450600228493968044773354186390390823713E4L, + -2.874539731125893533960680525192064277816E3L, + -1.402241261419067750237395034116942296027E2L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erfc in [1/.35,107] + */ +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rb(x^2)/sb(x^2)) + 1/6.6666259765625 < 1/x < 1/2.85711669921875 + Peak relative error 4.2e-22 */ +rb[] = { + -4.869587348270494309550558460786501252369E-5L, + -4.030199390527997378549161722412466959403E-3L, + -9.434425866377037610206443566288917589122E-2L, + -9.319032754357658601200655161585539404155E-1L, + -4.273788174307459947350256581445442062291E0L, + -8.842289940696150508373541814064198259278E0L, + -7.069215249419887403187988144752613025255E0L, + -1.401228723639514787920274427443330704764E0L, +}, +sb[] = { + 4.936254964107175160157544545879293019085E-3L, + 1.583457624037795744377163924895349412015E-1L, + 1.850647991850328356622940552450636420484E0L, + 9.927611557279019463768050710008450625415E0L, + 2.531667257649436709617165336779212114570E1L, + 2.869752886406743386458304052862814690045E1L, + 1.182059497870819562441683560749192539345E1L, + /* 1.000000000000000000000000000000000000000E0 */ +}, +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rc(x^2)/sc(x^2)) + 1/107 <= 1/x <= 1/6.6666259765625 + Peak relative error 1.1e-21 */ +rc[] = { + -8.299617545269701963973537248996670806850E-5L, + -6.243845685115818513578933902532056244108E-3L, + -1.141667210620380223113693474478394397230E-1L, + -7.521343797212024245375240432734425789409E-1L, + -1.765321928311155824664963633786967602934E0L, + -1.029403473103215800456761180695263439188E0L, +}, +sc[] = { + 8.413244363014929493035952542677768808601E-3L, + 2.065114333816877479753334599639158060979E-1L, + 1.639064941530797583766364412782135680148E0L, + 4.936788463787115555582319302981666347450E0L, + 5.005177727208955487404729933261347679090E0L, + /* 1.000000000000000000000000000000000000000E0 */ +}; + +static long double erfc1(long double x) +{ + long double s,P,Q; + + s = fabsl(x) - 1; + P = pa[0] + s * (pa[1] + s * (pa[2] + + s * (pa[3] + s * (pa[4] + s * (pa[5] + s * (pa[6] + s * pa[7])))))); + Q = qa[0] + s * (qa[1] + s * (qa[2] + + s * (qa[3] + s * (qa[4] + s * (qa[5] + s * (qa[6] + s)))))); + return 1 - erx - P / Q; +} + +static long double erfc2(uint32_t ix, long double x) +{ + union ldshape u; + long double s,z,R,S; + + if (ix < 0x3fffa000) /* 0.84375 <= |x| < 1.25 */ + return erfc1(x); + + x = fabsl(x); + s = 1 / (x * x); + if (ix < 0x4000b6db) { /* 1.25 <= |x| < 2.857 ~ 1/.35 */ + R = ra[0] + s * (ra[1] + s * (ra[2] + s * (ra[3] + s * (ra[4] + + s * (ra[5] + s * (ra[6] + s * (ra[7] + s * ra[8]))))))); + S = sa[0] + s * (sa[1] + s * (sa[2] + s * (sa[3] + s * (sa[4] + + s * (sa[5] + s * (sa[6] + s * (sa[7] + s * (sa[8] + s)))))))); + } else if (ix < 0x4001d555) { /* 2.857 <= |x| < 6.6666259765625 */ + R = rb[0] + s * (rb[1] + s * (rb[2] + s * (rb[3] + s * (rb[4] + + s * (rb[5] + s * (rb[6] + s * rb[7])))))); + S = sb[0] + s * (sb[1] + s * (sb[2] + s * (sb[3] + s * (sb[4] + + s * (sb[5] + s * (sb[6] + s)))))); + } else { /* 6.666 <= |x| < 107 (erfc only) */ + R = rc[0] + s * (rc[1] + s * (rc[2] + s * (rc[3] + + s * (rc[4] + s * rc[5])))); + S = sc[0] + s * (sc[1] + s * (sc[2] + s * (sc[3] + + s * (sc[4] + s)))); + } + u.f = x; + u.i.m &= -1ULL << 40; + z = u.f; + return expl(-z*z - 0.5625) * expl((z - x) * (z + x) + R / S) / x; +} + +long double erfl(long double x) +{ + long double r, s, z, y; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + + if (ix >= 0x7fff0000) + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1 - 2*sign + 1/x; + if (ix < 0x3ffed800) { /* |x| < 0.84375 */ + if (ix < 0x3fde8000) { /* |x| < 2**-33 */ + return 0.125 * (8 * x + efx8 * x); /* avoid underflow */ + } + z = x * x; + r = pp[0] + z * (pp[1] + + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + return x + x * y; + } + if (ix < 0x4001d555) /* |x| < 6.6666259765625 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-16382L; + return sign ? -y : y; +} + +long double erfcl(long double x) +{ + long double r, s, z, y; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + + if (ix >= 0x7fff0000) + /* erfc(nan) = nan, erfc(+-inf) = 0,2 */ + return 2*sign + 1/x; + if (ix < 0x3ffed800) { /* |x| < 0.84375 */ + if (ix < 0x3fbe0000) /* |x| < 2**-65 */ + return 1.0 - x; + z = x * x; + r = pp[0] + z * (pp[1] + + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + if (ix < 0x3ffd8000) /* x < 1/4 */ + return 1.0 - (x + x * y); + return 0.5 - (x - 0.5 + x * y); + } + if (ix < 0x4005d600) /* |x| < 107 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + y = 0x1p-16382L; + return sign ? 2 - y : y*y; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double erfl(long double x) +{ + return erf(x); +} +long double erfcl(long double x) +{ + return erfc(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/exp.c b/user/include/mlibc/options/ansi/musl-generic-math/exp.c new file mode 100644 index 0000000..9ea672f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/exp.c @@ -0,0 +1,134 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +#include "libm.h" + +static const double +half[2] = {0.5,-0.5}, +ln2hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ +ln2lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +double exp(double x) +{ + double_t hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_HIGH_WORD(hx, x); + sign = hx>>31; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x4086232b) { /* if |x| >= 708.39... */ + if (isnan(x)) + return x; + if (x > 709.782712893383973096) { + /* overflow if x!=inf */ + x *= 0x1p1023; + return x; + } + if (x < -708.39641853226410622) { + /* underflow if x!=-inf */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x < -745.13321910194110842) + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx >= 0x3ff0a2b2) /* if |x| >= 1.5 ln2 */ + k = (int)(invln2*x + half[sign]); + else + k = 1 - sign - sign; + hi = x - k*ln2hi; /* k*ln2hi is exact here */ + lo = k*ln2lo; + x = hi - lo; + } else if (hx > 0x3e300000) { /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0; + } else { + /* inexact if x!=0 */ + FORCE_EVAL(0x1p1023 + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x*x; + c = x - xx*(P1+xx*(P2+xx*(P3+xx*(P4+xx*P5)))); + y = 1 + (x*c/(2-c) - lo + hi); + if (k == 0) + return y; + return scalbn(y, k); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/exp10.c b/user/include/mlibc/options/ansi/musl-generic-math/exp10.c new file mode 100644 index 0000000..47b4dc7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/exp10.c @@ -0,0 +1,26 @@ +#define _GNU_SOURCE +#include +#include +#include "weak_alias.h" +//#include "libc.h" + +double exp10(double x) +{ + static const double p10[] = { + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, + 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 + }; + double n, y = modf(x, &n); + union {double f; uint64_t i;} u = {n}; + /* fabs(n) < 16 without raising invalid on nan */ + if ((u.i>>52 & 0x7ff) < 0x3ff+4) { + if (!y) return p10[(int)n+15]; + y = exp2(3.32192809488736234787031942948939 * y); + return y * p10[(int)n+15]; + } + return pow(10.0, x); +} + +weak_alias(exp10, pow10); diff --git a/user/include/mlibc/options/ansi/musl-generic-math/exp10f.c b/user/include/mlibc/options/ansi/musl-generic-math/exp10f.c new file mode 100644 index 0000000..74f8909 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/exp10f.c @@ -0,0 +1,24 @@ +#define _GNU_SOURCE +#include +#include +#include "weak_alias.h" +//#include "libc.h" + +float exp10f(float x) +{ + static const float p10[] = { + 1e-7f, 1e-6f, 1e-5f, 1e-4f, 1e-3f, 1e-2f, 1e-1f, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 + }; + float n, y = modff(x, &n); + union {float f; uint32_t i;} u = {n}; + /* fabsf(n) < 8 without raising invalid on nan */ + if ((u.i>>23 & 0xff) < 0x7f+3) { + if (!y) return p10[(int)n+7]; + y = exp2f(3.32192809488736234787031942948939f * y); + return y * p10[(int)n+7]; + } + return exp2(3.32192809488736234787031942948939 * x); +} + +weak_alias(exp10f, pow10f); diff --git a/user/include/mlibc/options/ansi/musl-generic-math/exp10l.c b/user/include/mlibc/options/ansi/musl-generic-math/exp10l.c new file mode 100644 index 0000000..f18e554 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/exp10l.c @@ -0,0 +1,34 @@ +#define _GNU_SOURCE +#include +#include +//#include "libc.h" +#include "libm.h" +#include "weak_alias.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp10l(long double x) +{ + return exp10(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double exp10l(long double x) +{ + static const long double p10[] = { + 1e-15L, 1e-14L, 1e-13L, 1e-12L, 1e-11L, 1e-10L, + 1e-9L, 1e-8L, 1e-7L, 1e-6L, 1e-5L, 1e-4L, 1e-3L, 1e-2L, 1e-1L, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 + }; + long double n, y = modfl(x, &n); + union ldshape u = {n}; + /* fabsl(n) < 16 without raising invalid on nan */ + if ((u.i.se & 0x7fff) < 0x3fff+4) { + if (!y) return p10[(int)n+15]; + y = exp2l(3.32192809488736234787031942948939L * y); + return y * p10[(int)n+15]; + } + return powl(10.0, x); +} +#endif + +weak_alias(exp10l, pow10l); diff --git a/user/include/mlibc/options/ansi/musl-generic-math/exp2.c b/user/include/mlibc/options/ansi/musl-generic-math/exp2.c new file mode 100644 index 0000000..e14adba --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/exp2.c @@ -0,0 +1,375 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +/*- + * Copyright (c) 2005 David Schultz + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include "libm.h" + +#define TBLSIZE 256 + +static const double +redux = 0x1.8p52 / TBLSIZE, +P1 = 0x1.62e42fefa39efp-1, +P2 = 0x1.ebfbdff82c575p-3, +P3 = 0x1.c6b08d704a0a6p-5, +P4 = 0x1.3b2ab88f70400p-7, +P5 = 0x1.5d88003875c74p-10; + +static const double tbl[TBLSIZE * 2] = { +/* exp2(z + eps) eps */ + 0x1.6a09e667f3d5dp-1, 0x1.9880p-44, + 0x1.6b052fa751744p-1, 0x1.8000p-50, + 0x1.6c012750bd9fep-1, -0x1.8780p-45, + 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46, + 0x1.6dfb23c651a29p-1, -0x1.8000p-50, + 0x1.6ef9298593ae3p-1, -0x1.c000p-52, + 0x1.6ff7df9519386p-1, -0x1.fd80p-45, + 0x1.70f7466f42da3p-1, -0x1.c880p-45, + 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46, + 0x1.72f8286eacf05p-1, -0x1.8300p-44, + 0x1.73f9a48a58152p-1, -0x1.0c00p-47, + 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45, + 0x1.75feb564267f1p-1, 0x1.3e00p-47, + 0x1.77024b1ab6d48p-1, -0x1.7d00p-45, + 0x1.780694fde5d38p-1, -0x1.d000p-50, + 0x1.790b938ac1d00p-1, 0x1.3000p-49, + 0x1.7a11473eb0178p-1, -0x1.d000p-49, + 0x1.7b17b0976d060p-1, 0x1.0400p-45, + 0x1.7c1ed0130c133p-1, 0x1.0000p-53, + 0x1.7d26a62ff8636p-1, -0x1.6900p-45, + 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47, + 0x1.7f3878491c3e8p-1, -0x1.4580p-45, + 0x1.80427543e1b4ep-1, 0x1.3000p-44, + 0x1.814d2add1071ap-1, 0x1.f000p-47, + 0x1.82589994ccd7ep-1, -0x1.1c00p-45, + 0x1.8364c1eb942d0p-1, 0x1.9d00p-45, + 0x1.8471a4623cab5p-1, 0x1.7100p-43, + 0x1.857f4179f5bbcp-1, 0x1.2600p-45, + 0x1.868d99b4491afp-1, -0x1.2c40p-44, + 0x1.879cad931a395p-1, -0x1.3000p-45, + 0x1.88ac7d98a65b8p-1, -0x1.a800p-45, + 0x1.89bd0a4785800p-1, -0x1.d000p-49, + 0x1.8ace5422aa223p-1, 0x1.3280p-44, + 0x1.8be05bad619fap-1, 0x1.2b40p-43, + 0x1.8cf3216b54383p-1, -0x1.ed00p-45, + 0x1.8e06a5e08664cp-1, -0x1.0500p-45, + 0x1.8f1ae99157807p-1, 0x1.8280p-45, + 0x1.902fed0282c0ep-1, -0x1.cb00p-46, + 0x1.9145b0b91ff96p-1, -0x1.5e00p-47, + 0x1.925c353aa2ff9p-1, 0x1.5400p-48, + 0x1.93737b0cdc64ap-1, 0x1.7200p-46, + 0x1.948b82b5f98aep-1, -0x1.9000p-47, + 0x1.95a44cbc852cbp-1, 0x1.5680p-45, + 0x1.96bdd9a766f21p-1, -0x1.6d00p-44, + 0x1.97d829fde4e2ap-1, -0x1.1000p-47, + 0x1.98f33e47a23a3p-1, 0x1.d000p-45, + 0x1.9a0f170ca0604p-1, -0x1.8a40p-44, + 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44, + 0x1.9c49182a3f15bp-1, 0x1.6b80p-45, + 0x1.9d674194bb8c5p-1, -0x1.c000p-49, + 0x1.9e86319e3238ep-1, 0x1.7d00p-46, + 0x1.9fa5e8d07f302p-1, 0x1.6400p-46, + 0x1.a0c667b5de54dp-1, -0x1.5000p-48, + 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47, + 0x1.a309bec4a2e27p-1, 0x1.ad80p-45, + 0x1.a42c980460a5dp-1, -0x1.af00p-46, + 0x1.a5503b23e259bp-1, 0x1.b600p-47, + 0x1.a674a8af46213p-1, 0x1.8880p-44, + 0x1.a799e1330b3a7p-1, 0x1.1200p-46, + 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47, + 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45, + 0x1.ab0e521356fb8p-1, 0x1.b700p-45, + 0x1.ac36bbfd3f381p-1, 0x1.9000p-50, + 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49, + 0x1.ae89f995ad2a3p-1, -0x1.c900p-45, + 0x1.afb4ce622f367p-1, 0x1.6500p-46, + 0x1.b0e07298db790p-1, 0x1.fd40p-45, + 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46, + 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43, + 0x1.b468415b747e7p-1, -0x1.8380p-44, + 0x1.b59728de5593ap-1, 0x1.8000p-54, + 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47, + 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50, + 0x1.b928cf22749b2p-1, -0x1.4c00p-47, + 0x1.ba5b030a10603p-1, -0x1.d700p-47, + 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47, + 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47, + 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46, + 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46, + 0x1.c06286141b2e9p-1, -0x1.1400p-46, + 0x1.c199bdd8552e0p-1, 0x1.be00p-47, + 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47, + 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47, + 0x1.c544778fafd15p-1, 0x1.9660p-44, + 0x1.c67f12e57d0cbp-1, -0x1.a100p-46, + 0x1.c7ba88988c1b6p-1, -0x1.8458p-42, + 0x1.c8f6d9406e733p-1, -0x1.a480p-46, + 0x1.ca3405751c4dfp-1, 0x1.b000p-51, + 0x1.cb720dcef9094p-1, 0x1.1400p-47, + 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48, + 0x1.cdf0b555dc412p-1, 0x1.3600p-48, + 0x1.cf3155b5bab3bp-1, -0x1.6900p-47, + 0x1.d072d4a0789bcp-1, 0x1.9a00p-47, + 0x1.d1b532b08c8fap-1, -0x1.5e00p-46, + 0x1.d2f87080d8a85p-1, 0x1.d280p-46, + 0x1.d43c8eacaa203p-1, 0x1.1a00p-47, + 0x1.d5818dcfba491p-1, 0x1.f000p-50, + 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47, + 0x1.d80e316c9834ep-1, -0x1.cd80p-47, + 0x1.d955d71ff6090p-1, 0x1.4c00p-48, + 0x1.da9e603db32aep-1, 0x1.f900p-48, + 0x1.dbe7cd63a8325p-1, 0x1.9800p-49, + 0x1.dd321f301b445p-1, -0x1.5200p-48, + 0x1.de7d5641c05bfp-1, -0x1.d700p-46, + 0x1.dfc97337b9aecp-1, -0x1.6140p-46, + 0x1.e11676b197d5ep-1, 0x1.b480p-47, + 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43, + 0x1.e3b333b16ee5cp-1, 0x1.c680p-47, + 0x1.e502ee78b3fb4p-1, -0x1.9300p-47, + 0x1.e653924676d68p-1, -0x1.5000p-49, + 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47, + 0x1.e8f7977cdb726p-1, -0x1.3700p-48, + 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49, + 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46, + 0x1.ecf482d8e680dp-1, 0x1.5500p-48, + 0x1.ee4aaa2188514p-1, 0x1.6400p-51, + 0x1.efa1bee615a13p-1, -0x1.e800p-49, + 0x1.f0f9c1cb64106p-1, -0x1.a880p-48, + 0x1.f252b376bb963p-1, -0x1.c900p-45, + 0x1.f3ac948dd7275p-1, 0x1.a000p-53, + 0x1.f50765b6e4524p-1, -0x1.4f00p-48, + 0x1.f6632798844fdp-1, 0x1.a800p-51, + 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48, + 0x1.f91d802243c82p-1, -0x1.4600p-50, + 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47, + 0x1.fbdba3692d511p-1, -0x1.0e00p-51, + 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46, + 0x1.fe9d96b2a23eep-1, 0x1.e430p-49, + 0x1.0000000000000p+0, 0x0.0000p+0, + 0x1.00b1afa5abcbep+0, -0x1.3400p-52, + 0x1.0163da9fb3303p+0, -0x1.2170p-46, + 0x1.02168143b0282p+0, 0x1.a400p-52, + 0x1.02c9a3e77806cp+0, 0x1.f980p-49, + 0x1.037d42e11bbcap+0, -0x1.7400p-51, + 0x1.04315e86e7f89p+0, 0x1.8300p-50, + 0x1.04e5f72f65467p+0, -0x1.a3f0p-46, + 0x1.059b0d315855ap+0, -0x1.2840p-47, + 0x1.0650a0e3c1f95p+0, 0x1.1600p-48, + 0x1.0706b29ddf71ap+0, 0x1.5240p-46, + 0x1.07bd42b72a82dp+0, -0x1.9a00p-49, + 0x1.0874518759bd0p+0, 0x1.6400p-49, + 0x1.092bdf66607c8p+0, -0x1.0780p-47, + 0x1.09e3ecac6f383p+0, -0x1.8000p-54, + 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48, + 0x1.0b5586cf988fcp+0, -0x1.ac80p-48, + 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50, + 0x1.0cc922b724816p+0, 0x1.5200p-47, + 0x1.0d83b23395dd8p+0, -0x1.ad00p-48, + 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46, + 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47, + 0x1.0fb66affed2f0p+0, -0x1.d300p-47, + 0x1.1073028d7234bp+0, 0x1.1500p-48, + 0x1.11301d0125b5bp+0, 0x1.c000p-49, + 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46, + 0x1.12abdc06c31d5p+0, 0x1.8400p-49, + 0x1.136a814f2047dp+0, -0x1.ed00p-47, + 0x1.1429aaea92de9p+0, 0x1.8e00p-49, + 0x1.14e95934f3138p+0, 0x1.b400p-49, + 0x1.15a98c8a58e71p+0, 0x1.5300p-47, + 0x1.166a45471c3dfp+0, 0x1.3380p-47, + 0x1.172b83c7d5211p+0, 0x1.8d40p-45, + 0x1.17ed48695bb9fp+0, -0x1.5d00p-47, + 0x1.18af9388c8d93p+0, -0x1.c880p-46, + 0x1.1972658375d66p+0, 0x1.1f00p-46, + 0x1.1a35beb6fcba7p+0, 0x1.0480p-46, + 0x1.1af99f81387e3p+0, -0x1.7390p-43, + 0x1.1bbe084045d54p+0, 0x1.4e40p-45, + 0x1.1c82f95281c43p+0, -0x1.a200p-47, + 0x1.1d4873168b9b2p+0, 0x1.3800p-49, + 0x1.1e0e75eb44031p+0, 0x1.ac00p-49, + 0x1.1ed5022fcd938p+0, 0x1.1900p-47, + 0x1.1f9c18438cdf7p+0, -0x1.b780p-46, + 0x1.2063b88628d8fp+0, 0x1.d940p-45, + 0x1.212be3578a81ep+0, 0x1.8000p-50, + 0x1.21f49917ddd41p+0, 0x1.b340p-45, + 0x1.22bdda2791323p+0, 0x1.9f80p-46, + 0x1.2387a6e7561e7p+0, -0x1.9c80p-46, + 0x1.2451ffb821427p+0, 0x1.2300p-47, + 0x1.251ce4fb2a602p+0, -0x1.3480p-46, + 0x1.25e85711eceb0p+0, 0x1.2700p-46, + 0x1.26b4565e27d16p+0, 0x1.1d00p-46, + 0x1.2780e341de00fp+0, 0x1.1ee0p-44, + 0x1.284dfe1f5633ep+0, -0x1.4c00p-46, + 0x1.291ba7591bb30p+0, -0x1.3d80p-46, + 0x1.29e9df51fdf09p+0, 0x1.8b00p-47, + 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45, + 0x1.2b87fd0dada3ap+0, 0x1.a340p-45, + 0x1.2c57e39771af9p+0, -0x1.0800p-46, + 0x1.2d285a6e402d9p+0, -0x1.ed00p-47, + 0x1.2df961f641579p+0, -0x1.4200p-48, + 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45, + 0x1.2f9d24abd8822p+0, -0x1.6300p-46, + 0x1.306fe0a31b625p+0, -0x1.2360p-44, + 0x1.31432edeea50bp+0, -0x1.0df8p-40, + 0x1.32170fc4cd7b8p+0, -0x1.2480p-45, + 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45, + 0x1.33c08b2641766p+0, 0x1.ed00p-46, + 0x1.3496266e3fa27p+0, -0x1.c000p-50, + 0x1.356c55f929f0fp+0, -0x1.0d80p-44, + 0x1.36431a2de88b9p+0, 0x1.2c80p-45, + 0x1.371a7373aaa39p+0, 0x1.0600p-45, + 0x1.37f26231e74fep+0, -0x1.6600p-46, + 0x1.38cae6d05d838p+0, -0x1.ae00p-47, + 0x1.39a401b713ec3p+0, -0x1.4720p-43, + 0x1.3a7db34e5a020p+0, 0x1.8200p-47, + 0x1.3b57fbfec6e95p+0, 0x1.e800p-44, + 0x1.3c32dc313a8f2p+0, 0x1.f800p-49, + 0x1.3d0e544ede122p+0, -0x1.7a00p-46, + 0x1.3dea64c1234bbp+0, 0x1.6300p-45, + 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43, + 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44, + 0x1.40822c367a0bbp+0, 0x1.5b80p-45, + 0x1.4160a21f72e95p+0, 0x1.ec00p-46, + 0x1.423fb27094646p+0, -0x1.3600p-46, + 0x1.431f5d950a920p+0, 0x1.3980p-45, + 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48, + 0x1.44e0860618919p+0, -0x1.6c00p-48, + 0x1.45c2042a7d201p+0, -0x1.bc00p-47, + 0x1.46a41ed1d0016p+0, -0x1.2800p-46, + 0x1.4786d668b3326p+0, 0x1.0e00p-44, + 0x1.486a2b5c13c00p+0, -0x1.d400p-45, + 0x1.494e1e192af04p+0, 0x1.c200p-47, + 0x1.4a32af0d7d372p+0, -0x1.e500p-46, + 0x1.4b17dea6db801p+0, 0x1.7800p-47, + 0x1.4bfdad53629e1p+0, -0x1.3800p-46, + 0x1.4ce41b817c132p+0, 0x1.0800p-47, + 0x1.4dcb299fddddbp+0, 0x1.c700p-45, + 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46, + 0x1.4f9b2769d2d02p+0, 0x1.9200p-46, + 0x1.508417f4531c1p+0, -0x1.8c00p-47, + 0x1.516daa2cf662ap+0, -0x1.a000p-48, + 0x1.5257de83f51eap+0, 0x1.a080p-43, + 0x1.5342b569d4edap+0, -0x1.6d80p-45, + 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44, + 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43, + 0x1.56070dde9116bp+0, 0x1.4b00p-45, + 0x1.56f4736b529dep+0, 0x1.15a0p-43, + 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45, + 0x1.58d12d497c76fp+0, -0x1.3080p-45, + 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43, + 0x1.5ab07dd485427p+0, -0x1.4000p-51, + 0x1.5ba11fba87af4p+0, 0x1.0080p-44, + 0x1.5c9268a59460bp+0, -0x1.6c80p-45, + 0x1.5d84590998e3fp+0, 0x1.69a0p-43, + 0x1.5e76f15ad20e1p+0, -0x1.b400p-46, + 0x1.5f6a320dcebcap+0, 0x1.7700p-46, + 0x1.605e1b976dcb8p+0, 0x1.6f80p-45, + 0x1.6152ae6cdf715p+0, 0x1.1000p-47, + 0x1.6247eb03a5531p+0, -0x1.5d00p-46, + 0x1.633dd1d1929b5p+0, -0x1.2d00p-46, + 0x1.6434634ccc313p+0, -0x1.a800p-49, + 0x1.652b9febc8efap+0, -0x1.8600p-45, + 0x1.6623882553397p+0, 0x1.1fe0p-40, + 0x1.671c1c708328ep+0, -0x1.7200p-44, + 0x1.68155d44ca97ep+0, 0x1.6800p-49, + 0x1.690f4b19e9471p+0, -0x1.9780p-45, +}; + +/* + * exp2(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.503 ulp for normalized results. + * + * Method: (accurate tables) + * + * Reduce x: + * x = k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-64. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are + * virtual tables, interleaved in the real table tbl[]. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +double exp2(double x) +{ + double_t r, t, z; + uint32_t ix, i0; + union {double f; uint64_t i;} u = {x}; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + ix = u.i>>32 & 0x7fffffff; + if (ix >= 0x408ff000) { /* |x| >= 1022 or nan */ + if (ix >= 0x40900000 && u.i>>63 == 0) { /* x >= 1024 or nan */ + /* overflow */ + x *= 0x1p1023; + return x; + } + if (ix >= 0x7ff00000) /* -inf or -nan */ + return -1/x; + if (u.i>>63) { /* x <= -1022 */ + /* underflow */ + if (x <= -1075 || x - 0x1p52 + 0x1p52 != x) + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -1075) + return 0; + } + } else if (ix < 0x3c900000) { /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[2*i0]; /* exp2t[i0] */ + z -= tbl[2*i0 + 1]; /* eps[i0] */ + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); + + return scalbn(r, k.i); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/exp2f.c b/user/include/mlibc/options/ansi/musl-generic-math/exp2f.c new file mode 100644 index 0000000..296b634 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/exp2f.c @@ -0,0 +1,126 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c */ +/*- + * Copyright (c) 2005 David Schultz + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include "libm.h" + +#define TBLSIZE 16 + +static const float +redux = 0x1.8p23f / TBLSIZE, +P1 = 0x1.62e430p-1f, +P2 = 0x1.ebfbe0p-3f, +P3 = 0x1.c6b348p-5f, +P4 = 0x1.3b2c9cp-7f; + +static const double exp2ft[TBLSIZE] = { + 0x1.6a09e667f3bcdp-1, + 0x1.7a11473eb0187p-1, + 0x1.8ace5422aa0dbp-1, + 0x1.9c49182a3f090p-1, + 0x1.ae89f995ad3adp-1, + 0x1.c199bdd85529cp-1, + 0x1.d5818dcfba487p-1, + 0x1.ea4afa2a490dap-1, + 0x1.0000000000000p+0, + 0x1.0b5586cf9890fp+0, + 0x1.172b83c7d517bp+0, + 0x1.2387a6e756238p+0, + 0x1.306fe0a31b715p+0, + 0x1.3dea64c123422p+0, + 0x1.4bfdad5362a27p+0, + 0x1.5ab07dd485429p+0, +}; + +/* + * exp2f(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = k + y, for integer k and |y| <= 1/2. + * Thus we have exp2f(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLSIZE+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. + * Using double precision for everything except the reduction makes + * roundoff error insignificant and simplifies the scaling step. + * + * This method is due to Tang, but I do not use his suggested parameters: + * + * Tang, P. Table-driven Implementation of the Exponential Function + * in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + */ +float exp2f(float x) +{ + double_t t, r, z; + union {float f; uint32_t i;} u = {x}; + union {double f; uint64_t i;} uk; + uint32_t ix, i0, k; + + /* Filter out exceptional cases. */ + ix = u.i & 0x7fffffff; + if (ix > 0x42fc0000) { /* |x| > 126 */ + if (ix > 0x7f800000) /* NaN */ + return x; + if (u.i >= 0x43000000 && u.i < 0x80000000) { /* x >= 128 */ + x *= 0x1p127f; + return x; + } + if (u.i >= 0x80000000) { /* x < -126 */ + if (u.i >= 0xc3160000 || (u.i & 0x0000ffff)) + FORCE_EVAL(-0x1p-149f/x); + if (u.i >= 0xc3160000) /* x <= -150 */ + return 0; + } + } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ + return 1.0f + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k = i0 / TBLSIZE; + uk.i = (uint64_t)(0x3ff + k)<<52; + i0 &= TBLSIZE - 1; + u.f -= redux; + z = x - u.f; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + r = exp2ft[i0]; + t = r * z; + r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); + + /* Scale by 2**k */ + return r * uk.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/exp2l.c b/user/include/mlibc/options/ansi/musl-generic-math/exp2l.c new file mode 100644 index 0000000..3565c1e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/exp2l.c @@ -0,0 +1,619 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/s_exp2l.c and /usr/src/lib/msun/ld128/s_exp2l.c */ +/*- + * Copyright (c) 2005-2008 David Schultz + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp2l(long double x) +{ + return exp2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const double +redux = 0x1.8p63 / TBLSIZE, +P1 = 0x1.62e42fefa39efp-1, +P2 = 0x1.ebfbdff82c58fp-3, +P3 = 0x1.c6b08d7049fap-5, +P4 = 0x1.3b2ab6fba4da5p-7, +P5 = 0x1.5d8804780a736p-10, +P6 = 0x1.430918835e33dp-13; + +static const double tbl[TBLSIZE * 2] = { + 0x1.6a09e667f3bcdp-1, -0x1.bdd3413b2648p-55, + 0x1.6c012750bdabfp-1, -0x1.2895667ff0cp-57, + 0x1.6dfb23c651a2fp-1, -0x1.bbe3a683c88p-58, + 0x1.6ff7df9519484p-1, -0x1.83c0f25860fp-56, + 0x1.71f75e8ec5f74p-1, -0x1.16e4786887bp-56, + 0x1.73f9a48a58174p-1, -0x1.0a8d96c65d5p-55, + 0x1.75feb564267c9p-1, -0x1.0245957316ep-55, + 0x1.780694fde5d3fp-1, 0x1.866b80a0216p-55, + 0x1.7a11473eb0187p-1, -0x1.41577ee0499p-56, + 0x1.7c1ed0130c132p-1, 0x1.f124cd1164ep-55, + 0x1.7e2f336cf4e62p-1, 0x1.05d02ba157ap-57, + 0x1.80427543e1a12p-1, -0x1.27c86626d97p-55, + 0x1.82589994cce13p-1, -0x1.d4c1dd41533p-55, + 0x1.8471a4623c7adp-1, -0x1.8d684a341cep-56, + 0x1.868d99b4492edp-1, -0x1.fc6f89bd4f68p-55, + 0x1.88ac7d98a6699p-1, 0x1.994c2f37cb5p-55, + 0x1.8ace5422aa0dbp-1, 0x1.6e9f156864bp-55, + 0x1.8cf3216b5448cp-1, -0x1.0d55e32e9e4p-57, + 0x1.8f1ae99157736p-1, 0x1.5cc13a2e397p-56, + 0x1.9145b0b91ffc6p-1, -0x1.dd6792e5825p-55, + 0x1.93737b0cdc5e5p-1, -0x1.75fc781b58p-58, + 0x1.95a44cbc8520fp-1, -0x1.64b7c96a5fp-57, + 0x1.97d829fde4e5p-1, -0x1.d185b7c1b86p-55, + 0x1.9a0f170ca07bap-1, -0x1.173bd91cee6p-55, + 0x1.9c49182a3f09p-1, 0x1.c7c46b071f2p-57, + 0x1.9e86319e32323p-1, 0x1.824ca78e64cp-57, + 0x1.a0c667b5de565p-1, -0x1.359495d1cd5p-55, + 0x1.a309bec4a2d33p-1, 0x1.6305c7ddc368p-55, + 0x1.a5503b23e255dp-1, -0x1.d2f6edb8d42p-55, + 0x1.a799e1330b358p-1, 0x1.bcb7ecac564p-55, + 0x1.a9e6b5579fdbfp-1, 0x1.0fac90ef7fdp-55, + 0x1.ac36bbfd3f37ap-1, -0x1.f9234cae76dp-56, + 0x1.ae89f995ad3adp-1, 0x1.7a1cd345dcc8p-55, + 0x1.b0e07298db666p-1, -0x1.bdef54c80e4p-55, + 0x1.b33a2b84f15fbp-1, -0x1.2805e3084d8p-58, + 0x1.b59728de5593ap-1, -0x1.c71dfbbba6ep-55, + 0x1.b7f76f2fb5e47p-1, -0x1.5584f7e54acp-57, + 0x1.ba5b030a1064ap-1, -0x1.efcd30e5429p-55, + 0x1.bcc1e904bc1d2p-1, 0x1.23dd07a2d9fp-56, + 0x1.bf2c25bd71e09p-1, -0x1.efdca3f6b9c8p-55, + 0x1.c199bdd85529cp-1, 0x1.11065895049p-56, + 0x1.c40ab5fffd07ap-1, 0x1.b4537e083c6p-55, + 0x1.c67f12e57d14bp-1, 0x1.2884dff483c8p-55, + 0x1.c8f6d9406e7b5p-1, 0x1.1acbc48805cp-57, + 0x1.cb720dcef9069p-1, 0x1.503cbd1e94ap-57, + 0x1.cdf0b555dc3fap-1, -0x1.dd83b53829dp-56, + 0x1.d072d4a07897cp-1, -0x1.cbc3743797a8p-55, + 0x1.d2f87080d89f2p-1, -0x1.d487b719d858p-55, + 0x1.d5818dcfba487p-1, 0x1.2ed02d75b37p-56, + 0x1.d80e316c98398p-1, -0x1.11ec18bedep-55, + 0x1.da9e603db3285p-1, 0x1.c2300696db5p-55, + 0x1.dd321f301b46p-1, 0x1.2da5778f019p-55, + 0x1.dfc97337b9b5fp-1, -0x1.1a5cd4f184b8p-55, + 0x1.e264614f5a129p-1, -0x1.7b627817a148p-55, + 0x1.e502ee78b3ff6p-1, 0x1.39e8980a9cdp-56, + 0x1.e7a51fbc74c83p-1, 0x1.2d522ca0c8ep-55, + 0x1.ea4afa2a490dap-1, -0x1.e9c23179c288p-55, + 0x1.ecf482d8e67f1p-1, -0x1.c93f3b411ad8p-55, + 0x1.efa1bee615a27p-1, 0x1.dc7f486a4b68p-55, + 0x1.f252b376bba97p-1, 0x1.3a1a5bf0d8e8p-55, + 0x1.f50765b6e454p-1, 0x1.9d3e12dd8a18p-55, + 0x1.f7bfdad9cbe14p-1, -0x1.dbb12d00635p-55, + 0x1.fa7c1819e90d8p-1, 0x1.74853f3a593p-56, + 0x1.fd3c22b8f71f1p-1, 0x1.2eb74966578p-58, + 0x1p+0, 0x0p+0, + 0x1.0163da9fb3335p+0, 0x1.b61299ab8cd8p-54, + 0x1.02c9a3e778061p+0, -0x1.19083535b08p-56, + 0x1.04315e86e7f85p+0, -0x1.0a31c1977c98p-54, + 0x1.059b0d3158574p+0, 0x1.d73e2a475b4p-55, + 0x1.0706b29ddf6dep+0, -0x1.c91dfe2b13cp-55, + 0x1.0874518759bc8p+0, 0x1.186be4bb284p-57, + 0x1.09e3ecac6f383p+0, 0x1.14878183161p-54, + 0x1.0b5586cf9890fp+0, 0x1.8a62e4adc61p-54, + 0x1.0cc922b7247f7p+0, 0x1.01edc16e24f8p-54, + 0x1.0e3ec32d3d1a2p+0, 0x1.03a1727c58p-59, + 0x1.0fb66affed31bp+0, -0x1.b9bedc44ebcp-57, + 0x1.11301d0125b51p+0, -0x1.6c51039449bp-54, + 0x1.12abdc06c31ccp+0, -0x1.1b514b36ca8p-58, + 0x1.1429aaea92dep+0, -0x1.32fbf9af1368p-54, + 0x1.15a98c8a58e51p+0, 0x1.2406ab9eeabp-55, + 0x1.172b83c7d517bp+0, -0x1.19041b9d78ap-55, + 0x1.18af9388c8deap+0, -0x1.11023d1970f8p-54, + 0x1.1a35beb6fcb75p+0, 0x1.e5b4c7b4969p-55, + 0x1.1bbe084045cd4p+0, -0x1.95386352ef6p-54, + 0x1.1d4873168b9aap+0, 0x1.e016e00a264p-54, + 0x1.1ed5022fcd91dp+0, -0x1.1df98027bb78p-54, + 0x1.2063b88628cd6p+0, 0x1.dc775814a85p-55, + 0x1.21f49917ddc96p+0, 0x1.2a97e9494a6p-55, + 0x1.2387a6e756238p+0, 0x1.9b07eb6c7058p-54, + 0x1.251ce4fb2a63fp+0, 0x1.ac155bef4f5p-55, + 0x1.26b4565e27cddp+0, 0x1.2bd339940eap-55, + 0x1.284dfe1f56381p+0, -0x1.a4c3a8c3f0d8p-54, + 0x1.29e9df51fdee1p+0, 0x1.612e8afad12p-55, + 0x1.2b87fd0dad99p+0, -0x1.10adcd6382p-59, + 0x1.2d285a6e4030bp+0, 0x1.0024754db42p-54, + 0x1.2ecafa93e2f56p+0, 0x1.1ca0f45d524p-56, + 0x1.306fe0a31b715p+0, 0x1.6f46ad23183p-55, + 0x1.32170fc4cd831p+0, 0x1.a9ce78e1804p-55, + 0x1.33c08b26416ffp+0, 0x1.327218436598p-54, + 0x1.356c55f929ff1p+0, -0x1.b5cee5c4e46p-55, + 0x1.371a7373aa9cbp+0, -0x1.63aeabf42ebp-54, + 0x1.38cae6d05d866p+0, -0x1.e958d3c99048p-54, + 0x1.3a7db34e59ff7p+0, -0x1.5e436d661f6p-56, + 0x1.3c32dc313a8e5p+0, -0x1.efff8375d2ap-54, + 0x1.3dea64c123422p+0, 0x1.ada0911f09fp-55, + 0x1.3fa4504ac801cp+0, -0x1.7d023f956fap-54, + 0x1.4160a21f72e2ap+0, -0x1.ef3691c309p-58, + 0x1.431f5d950a897p+0, -0x1.1c7dde35f7ap-55, + 0x1.44e086061892dp+0, 0x1.89b7a04ef8p-59, + 0x1.46a41ed1d0057p+0, 0x1.c944bd1648a8p-54, + 0x1.486a2b5c13cdp+0, 0x1.3c1a3b69062p-56, + 0x1.4a32af0d7d3dep+0, 0x1.9cb62f3d1be8p-54, + 0x1.4bfdad5362a27p+0, 0x1.d4397afec42p-56, + 0x1.4dcb299fddd0dp+0, 0x1.8ecdbbc6a78p-54, + 0x1.4f9b2769d2ca7p+0, -0x1.4b309d25958p-54, + 0x1.516daa2cf6642p+0, -0x1.f768569bd94p-55, + 0x1.5342b569d4f82p+0, -0x1.07abe1db13dp-55, + 0x1.551a4ca5d920fp+0, -0x1.d689cefede6p-55, + 0x1.56f4736b527dap+0, 0x1.9bb2c011d938p-54, + 0x1.58d12d497c7fdp+0, 0x1.295e15b9a1ep-55, + 0x1.5ab07dd485429p+0, 0x1.6324c0546478p-54, + 0x1.5c9268a5946b7p+0, 0x1.c4b1b81698p-60, + 0x1.5e76f15ad2148p+0, 0x1.ba6f93080e68p-54, + 0x1.605e1b976dc09p+0, -0x1.3e2429b56de8p-54, + 0x1.6247eb03a5585p+0, -0x1.383c17e40b48p-54, + 0x1.6434634ccc32p+0, -0x1.c483c759d89p-55, + 0x1.6623882552225p+0, -0x1.bb60987591cp-54, + 0x1.68155d44ca973p+0, 0x1.038ae44f74p-57, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.511 ulp. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2l(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLBITS+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-6 minimax polynomial with maximum error under 2**-69. + * The table entries each have 104 bits of accuracy, encoded as + * a pair of double precision values. + */ +long double exp2l(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z; + uint32_t i0; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 13) { /* |x| >= 8192 or x is NaN */ + if (u.i.se >= 0x3fff + 14 && u.i.se >> 15 == 0) + /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1/x; + if (x < -16382) { + if (x <= -16446 || x - 0x1p63 + 0x1p63 != x) + /* underflow */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -16446) + return 0; + } + } else if (e < 0x3fff - 64) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i.m + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2l(y) = exp2lt[i0] * p(z). */ + long double t_hi = tbl[2*i0]; + long double t_lo = tbl[2*i0 + 1]; + /* XXX This gives > 1 ulp errors outside of FE_TONEAREST mode */ + r = t_lo + (t_hi + t_lo) * z * (P1 + z * (P2 + z * (P3 + z * (P4 + + z * (P5 + z * P6))))) + t_hi; + + return scalbnl(r, k.i); +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const long double + P1 = 0x1.62e42fefa39ef35793c7673007e6p-1L, + P2 = 0x1.ebfbdff82c58ea86f16b06ec9736p-3L, + P3 = 0x1.c6b08d704a0bf8b33a762bad3459p-5L, + P4 = 0x1.3b2ab6fba4e7729ccbbe0b4f3fc2p-7L, + P5 = 0x1.5d87fe78a67311071dee13fd11d9p-10L, + P6 = 0x1.430912f86c7876f4b663b23c5fe5p-13L; + +static const double + P7 = 0x1.ffcbfc588b041p-17, + P8 = 0x1.62c0223a5c7c7p-20, + P9 = 0x1.b52541ff59713p-24, + P10 = 0x1.e4cf56a391e22p-28, + redux = 0x1.8p112 / TBLSIZE; + +static const long double tbl[TBLSIZE] = { + 0x1.6a09e667f3bcc908b2fb1366dfeap-1L, + 0x1.6c012750bdabeed76a99800f4edep-1L, + 0x1.6dfb23c651a2ef220e2cbe1bc0d4p-1L, + 0x1.6ff7df9519483cf87e1b4f3e1e98p-1L, + 0x1.71f75e8ec5f73dd2370f2ef0b148p-1L, + 0x1.73f9a48a58173bd5c9a4e68ab074p-1L, + 0x1.75feb564267c8bf6e9aa33a489a8p-1L, + 0x1.780694fde5d3f619ae02808592a4p-1L, + 0x1.7a11473eb0186d7d51023f6ccb1ap-1L, + 0x1.7c1ed0130c1327c49334459378dep-1L, + 0x1.7e2f336cf4e62105d02ba1579756p-1L, + 0x1.80427543e1a11b60de67649a3842p-1L, + 0x1.82589994cce128acf88afab34928p-1L, + 0x1.8471a4623c7acce52f6b97c6444cp-1L, + 0x1.868d99b4492ec80e41d90ac2556ap-1L, + 0x1.88ac7d98a669966530bcdf2d4cc0p-1L, + 0x1.8ace5422aa0db5ba7c55a192c648p-1L, + 0x1.8cf3216b5448bef2aa1cd161c57ap-1L, + 0x1.8f1ae991577362b982745c72eddap-1L, + 0x1.9145b0b91ffc588a61b469f6b6a0p-1L, + 0x1.93737b0cdc5e4f4501c3f2540ae8p-1L, + 0x1.95a44cbc8520ee9b483695a0e7fep-1L, + 0x1.97d829fde4e4f8b9e920f91e8eb6p-1L, + 0x1.9a0f170ca07b9ba3109b8c467844p-1L, + 0x1.9c49182a3f0901c7c46b071f28dep-1L, + 0x1.9e86319e323231824ca78e64c462p-1L, + 0x1.a0c667b5de564b29ada8b8cabbacp-1L, + 0x1.a309bec4a2d3358c171f770db1f4p-1L, + 0x1.a5503b23e255c8b424491caf88ccp-1L, + 0x1.a799e1330b3586f2dfb2b158f31ep-1L, + 0x1.a9e6b5579fdbf43eb243bdff53a2p-1L, + 0x1.ac36bbfd3f379c0db966a3126988p-1L, + 0x1.ae89f995ad3ad5e8734d17731c80p-1L, + 0x1.b0e07298db66590842acdfc6fb4ep-1L, + 0x1.b33a2b84f15faf6bfd0e7bd941b0p-1L, + 0x1.b59728de559398e3881111648738p-1L, + 0x1.b7f76f2fb5e46eaa7b081ab53ff6p-1L, + 0x1.ba5b030a10649840cb3c6af5b74cp-1L, + 0x1.bcc1e904bc1d2247ba0f45b3d06cp-1L, + 0x1.bf2c25bd71e088408d7025190cd0p-1L, + 0x1.c199bdd85529c2220cb12a0916bap-1L, + 0x1.c40ab5fffd07a6d14df820f17deap-1L, + 0x1.c67f12e57d14b4a2137fd20f2a26p-1L, + 0x1.c8f6d9406e7b511acbc48805c3f6p-1L, + 0x1.cb720dcef90691503cbd1e949d0ap-1L, + 0x1.cdf0b555dc3f9c44f8958fac4f12p-1L, + 0x1.d072d4a07897b8d0f22f21a13792p-1L, + 0x1.d2f87080d89f18ade123989ea50ep-1L, + 0x1.d5818dcfba48725da05aeb66dff8p-1L, + 0x1.d80e316c98397bb84f9d048807a0p-1L, + 0x1.da9e603db3285708c01a5b6d480cp-1L, + 0x1.dd321f301b4604b695de3c0630c0p-1L, + 0x1.dfc97337b9b5eb968cac39ed284cp-1L, + 0x1.e264614f5a128a12761fa17adc74p-1L, + 0x1.e502ee78b3ff6273d130153992d0p-1L, + 0x1.e7a51fbc74c834b548b2832378a4p-1L, + 0x1.ea4afa2a490d9858f73a18f5dab4p-1L, + 0x1.ecf482d8e67f08db0312fb949d50p-1L, + 0x1.efa1bee615a27771fd21a92dabb6p-1L, + 0x1.f252b376bba974e8696fc3638f24p-1L, + 0x1.f50765b6e4540674f84b762861a6p-1L, + 0x1.f7bfdad9cbe138913b4bfe72bd78p-1L, + 0x1.fa7c1819e90d82e90a7e74b26360p-1L, + 0x1.fd3c22b8f71f10975ba4b32bd006p-1L, + 0x1.0000000000000000000000000000p+0L, + 0x1.0163da9fb33356d84a66ae336e98p+0L, + 0x1.02c9a3e778060ee6f7caca4f7a18p+0L, + 0x1.04315e86e7f84bd738f9a20da442p+0L, + 0x1.059b0d31585743ae7c548eb68c6ap+0L, + 0x1.0706b29ddf6ddc6dc403a9d87b1ep+0L, + 0x1.0874518759bc808c35f25d942856p+0L, + 0x1.09e3ecac6f3834521e060c584d5cp+0L, + 0x1.0b5586cf9890f6298b92b7184200p+0L, + 0x1.0cc922b7247f7407b705b893dbdep+0L, + 0x1.0e3ec32d3d1a2020742e4f8af794p+0L, + 0x1.0fb66affed31af232091dd8a169ep+0L, + 0x1.11301d0125b50a4ebbf1aed9321cp+0L, + 0x1.12abdc06c31cbfb92bad324d6f84p+0L, + 0x1.1429aaea92ddfb34101943b2588ep+0L, + 0x1.15a98c8a58e512480d573dd562aep+0L, + 0x1.172b83c7d517adcdf7c8c50eb162p+0L, + 0x1.18af9388c8de9bbbf70b9a3c269cp+0L, + 0x1.1a35beb6fcb753cb698f692d2038p+0L, + 0x1.1bbe084045cd39ab1e72b442810ep+0L, + 0x1.1d4873168b9aa7805b8028990be8p+0L, + 0x1.1ed5022fcd91cb8819ff61121fbep+0L, + 0x1.2063b88628cd63b8eeb0295093f6p+0L, + 0x1.21f49917ddc962552fd29294bc20p+0L, + 0x1.2387a6e75623866c1fadb1c159c0p+0L, + 0x1.251ce4fb2a63f3582ab7de9e9562p+0L, + 0x1.26b4565e27cdd257a673281d3068p+0L, + 0x1.284dfe1f5638096cf15cf03c9fa0p+0L, + 0x1.29e9df51fdee12c25d15f5a25022p+0L, + 0x1.2b87fd0dad98ffddea46538fca24p+0L, + 0x1.2d285a6e4030b40091d536d0733ep+0L, + 0x1.2ecafa93e2f5611ca0f45d5239a4p+0L, + 0x1.306fe0a31b7152de8d5a463063bep+0L, + 0x1.32170fc4cd8313539cf1c3009330p+0L, + 0x1.33c08b26416ff4c9c8610d96680ep+0L, + 0x1.356c55f929ff0c94623476373be4p+0L, + 0x1.371a7373aa9caa7145502f45452ap+0L, + 0x1.38cae6d05d86585a9cb0d9bed530p+0L, + 0x1.3a7db34e59ff6ea1bc9299e0a1fep+0L, + 0x1.3c32dc313a8e484001f228b58cf0p+0L, + 0x1.3dea64c12342235b41223e13d7eep+0L, + 0x1.3fa4504ac801ba0bf701aa417b9cp+0L, + 0x1.4160a21f72e29f84325b8f3dbacap+0L, + 0x1.431f5d950a896dc704439410b628p+0L, + 0x1.44e086061892d03136f409df0724p+0L, + 0x1.46a41ed1d005772512f459229f0ap+0L, + 0x1.486a2b5c13cd013c1a3b69062f26p+0L, + 0x1.4a32af0d7d3de672d8bcf46f99b4p+0L, + 0x1.4bfdad5362a271d4397afec42e36p+0L, + 0x1.4dcb299fddd0d63b36ef1a9e19dep+0L, + 0x1.4f9b2769d2ca6ad33d8b69aa0b8cp+0L, + 0x1.516daa2cf6641c112f52c84d6066p+0L, + 0x1.5342b569d4f81df0a83c49d86bf4p+0L, + 0x1.551a4ca5d920ec52ec620243540cp+0L, + 0x1.56f4736b527da66ecb004764e61ep+0L, + 0x1.58d12d497c7fd252bc2b7343d554p+0L, + 0x1.5ab07dd48542958c93015191e9a8p+0L, + 0x1.5c9268a5946b701c4b1b81697ed4p+0L, + 0x1.5e76f15ad21486e9be4c20399d12p+0L, + 0x1.605e1b976dc08b076f592a487066p+0L, + 0x1.6247eb03a5584b1f0fa06fd2d9eap+0L, + 0x1.6434634ccc31fc76f8714c4ee122p+0L, + 0x1.66238825522249127d9e29b92ea2p+0L, + 0x1.68155d44ca973081c57227b9f69ep+0L, +}; + +static const float eps[TBLSIZE] = { + -0x1.5c50p-101, + -0x1.5d00p-106, + 0x1.8e90p-102, + -0x1.5340p-103, + 0x1.1bd0p-102, + -0x1.4600p-105, + -0x1.7a40p-104, + 0x1.d590p-102, + -0x1.d590p-101, + 0x1.b100p-103, + -0x1.0d80p-105, + 0x1.6b00p-103, + -0x1.9f00p-105, + 0x1.c400p-103, + 0x1.e120p-103, + -0x1.c100p-104, + -0x1.9d20p-103, + 0x1.a800p-108, + 0x1.4c00p-106, + -0x1.9500p-106, + 0x1.6900p-105, + -0x1.29d0p-100, + 0x1.4c60p-103, + 0x1.13a0p-102, + -0x1.5b60p-103, + -0x1.1c40p-103, + 0x1.db80p-102, + 0x1.91a0p-102, + 0x1.dc00p-105, + 0x1.44c0p-104, + 0x1.9710p-102, + 0x1.8760p-103, + -0x1.a720p-103, + 0x1.ed20p-103, + -0x1.49c0p-102, + -0x1.e000p-111, + 0x1.86a0p-103, + 0x1.2b40p-103, + -0x1.b400p-108, + 0x1.1280p-99, + -0x1.02d8p-102, + -0x1.e3d0p-103, + -0x1.b080p-105, + -0x1.f100p-107, + -0x1.16c0p-105, + -0x1.1190p-103, + -0x1.a7d2p-100, + 0x1.3450p-103, + -0x1.67c0p-105, + 0x1.4b80p-104, + -0x1.c4e0p-103, + 0x1.6000p-108, + -0x1.3f60p-105, + 0x1.93f0p-104, + 0x1.5fe0p-105, + 0x1.6f80p-107, + -0x1.7600p-106, + 0x1.21e0p-106, + -0x1.3a40p-106, + -0x1.40c0p-104, + -0x1.9860p-105, + -0x1.5d40p-108, + -0x1.1d70p-106, + 0x1.2760p-105, + 0x0.0000p+0, + 0x1.21e2p-104, + -0x1.9520p-108, + -0x1.5720p-106, + -0x1.4810p-106, + -0x1.be00p-109, + 0x1.0080p-105, + -0x1.5780p-108, + -0x1.d460p-105, + -0x1.6140p-105, + 0x1.4630p-104, + 0x1.ad50p-103, + 0x1.82e0p-105, + 0x1.1d3cp-101, + 0x1.6100p-107, + 0x1.ec30p-104, + 0x1.f200p-108, + 0x1.0b40p-103, + 0x1.3660p-102, + 0x1.d9d0p-103, + -0x1.02d0p-102, + 0x1.b070p-103, + 0x1.b9c0p-104, + -0x1.01c0p-103, + -0x1.dfe0p-103, + 0x1.1b60p-104, + -0x1.ae94p-101, + -0x1.3340p-104, + 0x1.b3d8p-102, + -0x1.6e40p-105, + -0x1.3670p-103, + 0x1.c140p-104, + 0x1.1840p-101, + 0x1.1ab0p-102, + -0x1.a400p-104, + 0x1.1f00p-104, + -0x1.7180p-103, + 0x1.4ce0p-102, + 0x1.9200p-107, + -0x1.54c0p-103, + 0x1.1b80p-105, + -0x1.1828p-101, + 0x1.5720p-102, + -0x1.a060p-100, + 0x1.9160p-102, + 0x1.a280p-104, + 0x1.3400p-107, + 0x1.2b20p-102, + 0x1.7800p-108, + 0x1.cfd0p-101, + 0x1.2ef0p-102, + -0x1.2760p-99, + 0x1.b380p-104, + 0x1.0048p-101, + -0x1.60b0p-102, + 0x1.a1ccp-100, + -0x1.a640p-104, + -0x1.08a0p-101, + 0x1.7e60p-102, + 0x1.22c0p-103, + -0x1.7200p-106, + 0x1.f0f0p-102, + 0x1.eb4ep-99, + 0x1.c6e0p-103, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.502 ulp. + * + * Method: (accurate tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-8 + 2**-98 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-10 minimax polynomial with maximum error under 2**-120. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-122. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +long double +exp2l(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z, t; + uint32_t i0; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 14) { /* |x| >= 16384 or x is NaN */ + if (u.i.se >= 0x3fff + 15 && u.i.se >> 15 == 0) + /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1/x; + if (x < -16382) { + if (x <= -16495 || x - 0x1p112 + 0x1p112 != x) + /* underflow */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -16446) + return 0; + } + } else if (e < 0x3fff - 114) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i2.lo + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[i0]; + z -= eps[i0]; + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * (P5 + z * (P6 + + z * (P7 + z * (P8 + z * (P9 + z * P10))))))))); + + return scalbnl(r, k.i); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/expf.c b/user/include/mlibc/options/ansi/musl-generic-math/expf.c new file mode 100644 index 0000000..feee2b0 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/expf.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +half[2] = {0.5,-0.5}, +ln2hi = 6.9314575195e-1f, /* 0x3f317200 */ +ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */ +invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */ +P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */ + +float expf(float x) +{ + float_t hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_FLOAT_WORD(hx, x); + sign = hx >> 31; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */ + /* overflow */ + x *= 0x1p127f; + return x; + } + if (sign) { + /* underflow */ + FORCE_EVAL(-0x1p-149f/x); + if (hx >= 0x42cff1b5) /* x <= -103.972084f */ + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */ + k = invln2*x + half[sign]; + else + k = 1 - sign - sign; + hi = x - k*ln2hi; /* k*ln2hi is exact here */ + lo = k*ln2lo; + x = hi - lo; + } else if (hx > 0x39000000) { /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0; + } else { + /* raise inexact */ + FORCE_EVAL(0x1p127f + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x*x; + c = x - xx*(P1+xx*P2); + y = 1 + (x*c/(2-c) - lo + hi); + if (k == 0) + return y; + return scalbnf(y, k); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/expl.c b/user/include/mlibc/options/ansi/musl-generic-math/expl.c new file mode 100644 index 0000000..0a7f44f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/expl.c @@ -0,0 +1,128 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* + * Exponential function, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expl(); + * + * y = expl( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * A Pade' form of degree 5/6 is used to approximate exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE +-10000 50000 1.12e-19 2.81e-20 + * + * + * Error amplification in the exponential function can be + * a serious matter. The error propagation involves + * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ), + * which shows that a 1 lsb error in representing X produces + * a relative error of X times 1 lsb in the function. + * While the routine gives an accurate result for arguments + * that are exactly represented by a long double precision + * computer number, the result contains amplified roundoff + * error for large arguments not exactly represented. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * exp underflow x < MINLOG 0.0 + * exp overflow x > MAXLOG MAXNUM + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expl(long double x) +{ + return exp(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +static const long double P[3] = { + 1.2617719307481059087798E-4L, + 3.0299440770744196129956E-2L, + 9.9999999999999999991025E-1L, +}; +static const long double Q[4] = { + 3.0019850513866445504159E-6L, + 2.5244834034968410419224E-3L, + 2.2726554820815502876593E-1L, + 2.0000000000000000000897E0L, +}; +static const long double +LN2HI = 6.9314575195312500000000E-1L, +LN2LO = 1.4286068203094172321215E-6L, +LOG2E = 1.4426950408889634073599E0L; + +long double expl(long double x) +{ + long double px, xx; + int k; + + if (isnan(x)) + return x; + if (x > 11356.5234062941439488L) /* x > ln(2^16384 - 0.5) */ + return x * 0x1p16383L; + if (x < -11399.4985314888605581L) /* x < ln(2^-16446) */ + return -0x1p-16445L/x; + + /* Express e**x = e**f 2**k + * = e**(f + k ln(2)) + */ + px = floorl(LOG2E * x + 0.5); + k = px; + x -= px * LN2HI; + x -= px * LN2LO; + + /* rational approximation of the fractional part: + * e**x = 1 + 2x P(x**2)/(Q(x**2) - x P(x**2)) + */ + xx = x * x; + px = x * __polevll(xx, P, 2); + x = px/(__polevll(xx, Q, 3) - px); + x = 1.0 + 2.0 * x; + return scalbnl(x, k); +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expl(long double x) +{ + return exp(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/expm1.c b/user/include/mlibc/options/ansi/musl-generic-math/expm1.c new file mode 100644 index 0000000..ac1e61e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/expm1.c @@ -0,0 +1,201 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Remez algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */ +Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ +Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ +Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ +Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +double expm1(double x) +{ + double_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {double f; uint64_t i;} u = {x}; + uint32_t hx = u.i>>32 & 0x7fffffff; + int k, sign = u.i>>63; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */ + if (isnan(x)) + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p1023; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5 : 0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */ + if (hx < 0x00100000) + FORCE_EVAL((float)x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5*x; + hxs = x*hfx; + r1 = 1.0+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); + t = 3.0-r1*hfx; + e = hxs*((r1-t)/(6.0 - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5*(x-e) - 0.5; + if (k == 1) { + if (x < -0.25) + return -2.0*(e-(x+0.5)); + return 1.0+2.0*(x-e); + } + u.i = (uint64_t)(0x3ff + k)<<52; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if (k == 1024) + y = y*2.0*0x1p1023; + else + y = y*twopk; + return y - 1.0; + } + u.i = (uint64_t)(0x3ff - k)<<52; /* 2^-k */ + if (k < 20) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/expm1f.c b/user/include/mlibc/options/ansi/musl-generic-math/expm1f.c new file mode 100644 index 0000000..297e0b4 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/expm1f.c @@ -0,0 +1,111 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +o_threshold = 8.8721679688e+01, /* 0x42b17180 */ +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ +Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +float expm1f(float x) +{ + float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {float f; uint32_t i;} u = {x}; + uint32_t hx = u.i & 0x7fffffff; + int k, sign = u.i >> 31; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p127f; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5f : 0.5f); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x33000000) { /* when |x|<2**-25, return x */ + if (hx < 0x00800000) + FORCE_EVAL(x*x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5f*x; + hxs = x*hfx; + r1 = 1.0f+hxs*(Q1+hxs*Q2); + t = 3.0f - r1*hfx; + e = hxs*((r1-t)/(6.0f - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5f*(x-e) - 0.5f; + if (k == 1) { + if (x < -0.25f) + return -2.0f*(e-(x+0.5f)); + return 1.0f + 2.0f*(x-e); + } + u.i = (0x7f+k)<<23; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0f; + if (k == 128) + y = y*2.0f*0x1p127f; + else + y = y*twopk; + return y - 1.0f; + } + u.i = (0x7f-k)<<23; /* 2^-k */ + if (k < 23) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/expm1l.c b/user/include/mlibc/options/ansi/musl-generic-math/expm1l.c new file mode 100644 index 0000000..d171507 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/expm1l.c @@ -0,0 +1,123 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expm1l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* + * Exponential function, minus 1 + * Long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expm1l(); + * + * y = expm1l( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power, minus 1. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -45,+maxarg 200,000 1.2e-19 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expm1l(long double x) +{ + return expm1(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x) + -.5 ln 2 < x < .5 ln 2 + Theoretical peak relative error = 3.4e-22 */ +static const long double +P0 = -1.586135578666346600772998894928250240826E4L, +P1 = 2.642771505685952966904660652518429479531E3L, +P2 = -3.423199068835684263987132888286791620673E2L, +P3 = 1.800826371455042224581246202420972737840E1L, +P4 = -5.238523121205561042771939008061958820811E-1L, +Q0 = -9.516813471998079611319047060563358064497E4L, +Q1 = 3.964866271411091674556850458227710004570E4L, +Q2 = -7.207678383830091850230366618190187434796E3L, +Q3 = 7.206038318724600171970199625081491823079E2L, +Q4 = -4.002027679107076077238836622982900945173E1L, +/* Q5 = 1.000000000000000000000000000000000000000E0 */ +/* C1 + C2 = ln 2 */ +C1 = 6.93145751953125E-1L, +C2 = 1.428606820309417232121458176568075500134E-6L, +/* ln 2^-65 */ +minarg = -4.5054566736396445112120088E1L, +/* ln 2^16384 */ +maxarg = 1.1356523406294143949492E4L; + +long double expm1l(long double x) +{ + long double px, qx, xx; + int k; + + if (isnan(x)) + return x; + if (x > maxarg) + return x*0x1p16383L; /* overflow, unless x==inf */ + if (x == 0.0) + return x; + if (x < minarg) + return -1.0; + + xx = C1 + C2; + /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */ + px = floorl(0.5 + x / xx); + k = px; + /* remainder times ln 2 */ + x -= px * C1; + x -= px * C2; + + /* Approximate exp(remainder ln 2).*/ + px = (((( P4 * x + P3) * x + P2) * x + P1) * x + P0) * x; + qx = (((( x + Q4) * x + Q3) * x + Q2) * x + Q1) * x + Q0; + xx = x * x; + qx = x + (0.5 * xx + xx * px / qx); + + /* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2). + We have qx = exp(remainder ln 2) - 1, so + exp(x) - 1 = 2^k (qx + 1) - 1 = 2^k qx + 2^k - 1. */ + px = scalbnl(1.0, k); + x = px * qx + (px - 1.0); + return x; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expm1l(long double x) +{ + return expm1(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fabs.c b/user/include/mlibc/options/ansi/musl-generic-math/fabs.c new file mode 100644 index 0000000..e8258cf --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fabs.c @@ -0,0 +1,9 @@ +#include +#include + +double fabs(double x) +{ + union {double f; uint64_t i;} u = {x}; + u.i &= -1ULL/2; + return u.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fabsf.c b/user/include/mlibc/options/ansi/musl-generic-math/fabsf.c new file mode 100644 index 0000000..4efc8d6 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fabsf.c @@ -0,0 +1,9 @@ +#include +#include + +float fabsf(float x) +{ + union {float f; uint32_t i;} u = {x}; + u.i &= 0x7fffffff; + return u.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fabsl.c b/user/include/mlibc/options/ansi/musl-generic-math/fabsl.c new file mode 100644 index 0000000..c4f36ec --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fabsl.c @@ -0,0 +1,15 @@ +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fabsl(long double x) +{ + return fabs(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fabsl(long double x) +{ + union ldshape u = {x}; + + u.i.se &= 0x7fff; + return u.f; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fdim.c b/user/include/mlibc/options/ansi/musl-generic-math/fdim.c new file mode 100644 index 0000000..9585460 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fdim.c @@ -0,0 +1,10 @@ +#include + +double fdim(double x, double y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fdimf.c b/user/include/mlibc/options/ansi/musl-generic-math/fdimf.c new file mode 100644 index 0000000..543c364 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fdimf.c @@ -0,0 +1,10 @@ +#include + +float fdimf(float x, float y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fdiml.c b/user/include/mlibc/options/ansi/musl-generic-math/fdiml.c new file mode 100644 index 0000000..62e29b7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fdiml.c @@ -0,0 +1,18 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fdiml(long double x, long double y) +{ + return fdim(x, y); +} +#else +long double fdiml(long double x, long double y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/finite.c b/user/include/mlibc/options/ansi/musl-generic-math/finite.c new file mode 100644 index 0000000..25a0575 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/finite.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +int finite(double x) +{ + return isfinite(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/finitef.c b/user/include/mlibc/options/ansi/musl-generic-math/finitef.c new file mode 100644 index 0000000..2c4c771 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/finitef.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +int finitef(float x) +{ + return isfinite(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/floor.c b/user/include/mlibc/options/ansi/musl-generic-math/floor.c new file mode 100644 index 0000000..14a31cd --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/floor.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double floor(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff-1) { + FORCE_EVAL(y); + return u.i >> 63 ? -1 : 0; + } + if (y > 0) + return x + y - 1; + return x + y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/floorf.c b/user/include/mlibc/options/ansi/musl-generic-math/floorf.c new file mode 100644 index 0000000..dceec73 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/floorf.c @@ -0,0 +1,27 @@ +#include "libm.h" + +float floorf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i = 0; + else if (u.i << 1) + u.f = -1.0; + } + return u.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/floorl.c b/user/include/mlibc/options/ansi/musl-generic-math/floorl.c new file mode 100644 index 0000000..16aaec4 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/floorl.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double floorl(long double x) +{ + return floor(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double floorl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i.se >> 15) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3fff-1) { + FORCE_EVAL(y); + return u.i.se >> 15 ? -1 : 0; + } + if (y > 0) + return x + y - 1; + return x + y; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fma.c b/user/include/mlibc/options/ansi/musl-generic-math/fma.c new file mode 100644 index 0000000..f65eab7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fma.c @@ -0,0 +1,194 @@ +#include +#include +#include + +static inline int a_clz_64(uint64_t x) +{ + uint32_t y; + int r; + if (x>>32) y=x>>32, r=0; else y=x, r=32; + if (y>>16) y>>=16; else r |= 16; + if (y>>8) y>>=8; else r |= 8; + if (y>>4) y>>=4; else r |= 4; + if (y>>2) y>>=2; else r |= 2; + return r | !(y>>1); +} + +#define ASUINT64(x) ((union {double f; uint64_t i;}){x}).i +#define ZEROINFNAN (0x7ff-0x3ff-52-1) + +struct num { uint64_t m; int e; int sign; }; + +static struct num normalize(double x) +{ + uint64_t ix = ASUINT64(x); + int e = ix>>52; + int sign = e & 0x800; + e &= 0x7ff; + if (!e) { + ix = ASUINT64(x*0x1p63); + e = ix>>52 & 0x7ff; + e = e ? e-63 : 0x800; + } + ix &= (1ull<<52)-1; + ix |= 1ull<<52; + ix <<= 1; + e -= 0x3ff + 52 + 1; + return (struct num){ix,e,sign}; +} + +static void mul(uint64_t *hi, uint64_t *lo, uint64_t x, uint64_t y) +{ + uint64_t t1,t2,t3; + uint64_t xlo = (uint32_t)x, xhi = x>>32; + uint64_t ylo = (uint32_t)y, yhi = y>>32; + + t1 = xlo*ylo; + t2 = xlo*yhi + xhi*ylo; + t3 = xhi*yhi; + *lo = t1 + (t2<<32); + *hi = t3 + (t2>>32) + (t1 > *lo); +} + +double fma(double x, double y, double z) +{ + #pragma STDC FENV_ACCESS ON + + /* normalize so top 10bits and last bit are 0 */ + struct num nx, ny, nz; + nx = normalize(x); + ny = normalize(y); + nz = normalize(z); + + if (nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN) + return x*y + z; + if (nz.e >= ZEROINFNAN) { + if (nz.e > ZEROINFNAN) /* z==0 */ + return x*y + z; + return z; + } + + /* mul: r = x*y */ + uint64_t rhi, rlo, zhi, zlo; + mul(&rhi, &rlo, nx.m, ny.m); + /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ + + /* align exponents */ + int e = nx.e + ny.e; + int d = nz.e - e; + /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + if (d > 0) { + if (d < 64) { + zlo = nz.m<>64-d; + } else { + zlo = 0; + zhi = nz.m; + e = nz.e - 64; + d -= 64; + if (d == 0) { + } else if (d < 64) { + rlo = rhi<<64-d | rlo>>d | !!(rlo<<64-d); + rhi = rhi>>d; + } else { + rlo = 1; + rhi = 0; + } + } + } else { + zhi = 0; + d = -d; + if (d == 0) { + zlo = nz.m; + } else if (d < 64) { + zlo = nz.m>>d | !!(nz.m<<64-d); + } else { + zlo = 1; + } + } + + /* add */ + int sign = nx.sign^ny.sign; + int samesign = !(sign^nz.sign); + int nonzero = 1; + if (samesign) { + /* r += z */ + rlo += zlo; + rhi += zhi + (rlo < zlo); + } else { + /* r -= z */ + uint64_t t = rlo; + rlo -= zlo; + rhi = rhi - zhi - (t < rlo); + if (rhi>>63) { + rlo = -rlo; + rhi = -rhi-!!rlo; + sign = !sign; + } + nonzero = !!rhi; + } + + /* set rhi to top 63bit of the result (last bit is sticky) */ + if (nonzero) { + e += 64; + d = a_clz_64(rhi)-1; + /* note: d > 0 */ + rhi = rhi<>64-d | !!(rlo<>1 | (rlo&1); + else + rhi = rlo<>1 | (rhi&1) | 1ull<<62; + if (sign) + i = -i; + r = i; + r = 2*r - c; /* remove top bit */ + + /* raise underflow portably, such that it + cannot be optimized away */ + { + double_t tiny = DBL_MIN/FLT_MIN * r; + r += (double)(tiny*tiny) * (r-r); + } + } + } else { + /* only round once when scaled */ + d = 10; + i = ( rhi>>d | !!(rhi<<64-d) ) << d; + if (sign) + i = -i; + r = i; + } + } + return scalbn(r, e); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmaf.c b/user/include/mlibc/options/ansi/musl-generic-math/fmaf.c new file mode 100644 index 0000000..aa57feb --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmaf.c @@ -0,0 +1,93 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +#include +#include + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +float fmaf(float x, float y, float z) +{ + #pragma STDC FENV_ACCESS ON + double xy, result; + union {double f; uint64_t i;} u; + int e; + + xy = (double)x * y; + result = xy + z; + u.f = result; + e = u.i>>52 & 0x7ff; + /* Common case: The double precision result is fine. */ + if ((u.i & 0x1fffffff) != 0x10000000 || /* not a halfway case */ + e == 0x7ff || /* NaN */ + result - xy == z || /* exact */ + fegetround() != FE_TONEAREST) /* not round-to-nearest */ + { + /* + underflow may not be raised correctly, example: + fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) + */ +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (e < 0x3ff-126 && e >= 0x3ff-149 && fetestexcept(FE_INEXACT)) { + feclearexcept(FE_INEXACT); + /* TODO: gcc and clang bug workaround */ + volatile float vz = z; + result = xy + vz; + if (fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else + feraiseexcept(FE_INEXACT); + } +#endif + z = result; + return z; + } + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ +#ifdef FE_TOWARDZERO + fesetround(FE_TOWARDZERO); +#endif + volatile double vxy = xy; /* XXX work around gcc CSE bug */ + double adjusted_result = vxy + z; + fesetround(FE_TONEAREST); + if (result == adjusted_result) { + u.f = adjusted_result; + u.i++; + adjusted_result = u.f; + } + z = adjusted_result; + return z; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmal.c b/user/include/mlibc/options/ansi/musl-generic-math/fmal.c new file mode 100644 index 0000000..4506aac --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmal.c @@ -0,0 +1,293 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmal.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + + +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmal(long double x, long double y, long double z) +{ + return fma(x, y, z); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include +#if LDBL_MANT_DIG == 64 +#define LASTBIT(u) (u.i.m & 1) +#define SPLIT (0x1p32L + 1) +#elif LDBL_MANT_DIG == 113 +#define LASTBIT(u) (u.i.lo & 1) +#define SPLIT (0x1p57L + 1) +#endif + +/* + * A struct dd represents a floating-point number with twice the precision + * of a long double. We maintain the invariant that "hi" stores the high-order + * bits of the result. + */ +struct dd { + long double hi; + long double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd dd_add(long double a, long double b) +{ + struct dd ret; + long double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline long double add_adjusted(long double a, long double b) +{ + struct dd sum; + union ldshape u; + + sum = dd_add(a, b); + if (sum.lo != 0) { + u.f = sum.hi; + if (!LASTBIT(u)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline long double add_and_denormalize(long double a, long double b, int scale) +{ + struct dd sum; + int bits_lost; + union ldshape u; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + u.f = sum.hi; + bits_lost = -u.i.se - scale + 1; + if ((bits_lost != 1) ^ LASTBIT(u)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return scalbnl(sum.hi, scale); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd dd_mul(long double a, long double b) +{ + struct dd ret; + long double ha, hb, la, lb, p, q; + + p = a * SPLIT; + ha = a - p; + ha += p; + la = a - ha; + + p = b * SPLIT; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + */ +long double fmal(long double x, long double y, long double z) +{ + #pragma STDC FENV_ACCESS ON + long double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + + xs = frexpl(x, &ex); + ys = frexpl(y, &ey); + zs = frexpl(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -LDBL_MANT_DIG) { +#ifdef FE_INEXACT + feraiseexcept(FE_INEXACT); +#endif +#ifdef FE_UNDERFLOW + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); +#endif + switch (oround) { + default: /* FE_TONEAREST */ + return (z); +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafterl(z, 0)); +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafterl(z, -INFINITY)); +#endif +#ifdef FE_UPWARD + case FE_UPWARD: + if (x > 0.0 ^ y < 0.0) + return (nextafterl(z, INFINITY)); + else + return (z); +#endif + } + } + if (spread <= LDBL_MANT_DIG * 2) + zs = scalbnl(zs, -spread); + else + zs = copysignl(LDBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ + return xy.hi + vzs + scalbnl(xy.lo, spread); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + * But underflow may not be raised correctly, example in downward rounding: + * fmal(0x1.0000000001p-16000L, 0x1.0000000001p-400L, -0x1p-16440L) + */ + long double ret; +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + fesetround(oround); + adj = r.lo + xy.lo; + ret = scalbnl(r.hi + adj, spread); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (ilogbl(ret) < -16382 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + return ret; + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogbl(r.hi) > -16383) + return scalbnl(r.hi + adj, spread); + else + return add_and_denormalize(r.hi, adj, spread); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmax.c b/user/include/mlibc/options/ansi/musl-generic-math/fmax.c new file mode 100644 index 0000000..94f0caa --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmax.c @@ -0,0 +1,13 @@ +#include + +double fmax(double x, double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmaxf.c b/user/include/mlibc/options/ansi/musl-generic-math/fmaxf.c new file mode 100644 index 0000000..695d817 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmaxf.c @@ -0,0 +1,13 @@ +#include + +float fmaxf(float x, float y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeroes, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmaxl.c b/user/include/mlibc/options/ansi/musl-generic-math/fmaxl.c new file mode 100644 index 0000000..4b03158 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmaxl.c @@ -0,0 +1,21 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmaxl(long double x, long double y) +{ + return fmax(x, y); +} +#else +long double fmaxl(long double x, long double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmin.c b/user/include/mlibc/options/ansi/musl-generic-math/fmin.c new file mode 100644 index 0000000..08a8fd1 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmin.c @@ -0,0 +1,13 @@ +#include + +double fmin(double x, double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fminf.c b/user/include/mlibc/options/ansi/musl-generic-math/fminf.c new file mode 100644 index 0000000..3573c7d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fminf.c @@ -0,0 +1,13 @@ +#include + +float fminf(float x, float y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fminl.c b/user/include/mlibc/options/ansi/musl-generic-math/fminl.c new file mode 100644 index 0000000..69bc24a --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fminl.c @@ -0,0 +1,21 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fminl(long double x, long double y) +{ + return fmin(x, y); +} +#else +long double fminl(long double x, long double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmod.c b/user/include/mlibc/options/ansi/musl-generic-math/fmod.c new file mode 100644 index 0000000..6849722 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmod.c @@ -0,0 +1,68 @@ +#include +#include + +double fmod(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>52 & 0x7ff; + int ey = uy.i>>52 & 0x7ff; + int sx = ux.i>>63; + uint64_t i; + + /* in the followings uxi should be ux.i, but then gcc wrongly adds */ + /* float load/store to inner loops ruining performance and code size */ + uint64_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>52 == 0; uxi <<= 1, ex--); + + /* scale result */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (uint64_t)sx << 63; + ux.i = uxi; + return ux.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmodf.c b/user/include/mlibc/options/ansi/musl-generic-math/fmodf.c new file mode 100644 index 0000000..ff58f93 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmodf.c @@ -0,0 +1,65 @@ +#include +#include + +float fmodf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + uint32_t sx = ux.i & 0x80000000; + uint32_t i; + uint32_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>23 == 0; uxi <<= 1, ex--); + + /* scale result up */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + ux.i = uxi; + return ux.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/fmodl.c b/user/include/mlibc/options/ansi/musl-generic-math/fmodl.c new file mode 100644 index 0000000..9f5b873 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/fmodl.c @@ -0,0 +1,105 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmodl(long double x, long double y) +{ + return fmod(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fmodl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se & 0x8000; + + if (y == 0 || isnan(y) || ex == 0x7fff) + return (x*y)/(x*y); + ux.i.se = ex; + uy.i.se = ey; + if (ux.f <= uy.f) { + if (ux.f == uy.f) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + + /* x mod y */ +#if LDBL_MANT_DIG == 64 + uint64_t i, mx, my; + mx = ux.i.m; + my = uy.i.m; + for (; ex > ey; ex--) { + i = mx - my; + if (mx >= my) { + if (i == 0) + return 0*x; + mx = 2*i; + } else if (2*mx < mx) { + mx = 2*mx - my; + } else { + mx = 2*mx; + } + } + i = mx - my; + if (mx >= my) { + if (i == 0) + return 0*x; + mx = i; + } + for (; mx >> 63 == 0; mx *= 2, ex--); + ux.i.m = mx; +#elif LDBL_MANT_DIG == 113 + uint64_t hi, lo, xhi, xlo, yhi, ylo; + xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48; + yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; + xlo = ux.i2.lo; + ylo = uy.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + if ((hi|lo) == 0) + return 0*x; + xhi = 2*hi + (lo>>63); + xlo = 2*lo; + } else { + xhi = 2*xhi + (xlo>>63); + xlo = 2*xlo; + } + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + if ((hi|lo) == 0) + return 0*x; + xhi = hi; + xlo = lo; + } + for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + + /* scale result */ + if (ex <= 0) { + ux.i.se = (ex+120)|sx; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex|sx; + return ux.f; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/frexp.c b/user/include/mlibc/options/ansi/musl-generic-math/frexp.c new file mode 100644 index 0000000..abac0ea --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/frexp.c @@ -0,0 +1,24 @@ +#include +#include + +double frexp(double x, int *e) +{ + union { double d; uint64_t i; } y = { x }; + int ee = y.i>>52 & 0x7ff; + + if (!ee) { + if (x) { + x = frexp(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0x7ff) { + *e = 0; + return x; + } + + *e = ee - 0x3fe; + y.i &= 0x800fffffffffffffull; + y.i |= 0x3fe0000000000000ull; + return y.d; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/frexpf.c b/user/include/mlibc/options/ansi/musl-generic-math/frexpf.c new file mode 100644 index 0000000..2dabe37 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/frexpf.c @@ -0,0 +1,24 @@ +#include +#include + +float frexpf(float x, int *e) +{ + union { float f; uint32_t i; } y = { x }; + int ee = y.i>>23 & 0xff; + + if (!ee) { + if (x) { + x = frexpf(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0xff) { + *e = 0; + return x; + } + + *e = ee - 0x7e; + y.i &= 0x807ffffful; + y.i |= 0x3f000000ul; + return y.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/frexpl.c b/user/include/mlibc/options/ansi/musl-generic-math/frexpl.c new file mode 100644 index 0000000..e05cf75 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/frexpl.c @@ -0,0 +1,30 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double frexpl(long double x, int *e) +{ + return frexp(x, e); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double frexpl(long double x, int *e) +{ + union ldshape u = {x}; + int ee = u.i.se & 0x7fff; + + if (!ee) { + if (x) { + x = frexpl(x*0x1p120, e); + *e -= 120; + } else *e = 0; + return x; + } else if (ee == 0x7fff) { + *e = 0; + return x; + } + + *e = ee - 0x3ffe; + u.i.se &= 0x8000; + u.i.se |= 0x3ffe; + return u.f; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/hypot.c b/user/include/mlibc/options/ansi/musl-generic-math/hypot.c new file mode 100644 index 0000000..6071bf1 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/hypot.c @@ -0,0 +1,67 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD > 1U && LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32 + 1) +#else +#define SPLIT (0x1p27 + 1) +#endif + +static void sq(double_t *hi, double_t *lo, double x) +{ + double_t xh, xl, xc; + + xc = (double_t)x*SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = (double_t)x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; +} + +double hypot(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}, ut; + int ex, ey; + double_t hx, lx, hy, ly, z; + + /* arrange |x| >= |y| */ + ux.i &= -1ULL>>1; + uy.i &= -1ULL>>1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + /* special cases */ + ex = ux.i>>52; + ey = uy.i>>52; + x = ux.f; + y = uy.f; + /* note: hypot(inf,nan) == inf */ + if (ey == 0x7ff) + return y; + if (ex == 0x7ff || uy.i == 0) + return x; + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if (ex - ey > 64) + return x + y; + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1; + if (ex > 0x3ff+510) { + z = 0x1p700; + x *= 0x1p-700; + y *= 0x1p-700; + } else if (ey < 0x3ff-450) { + z = 0x1p-700; + x *= 0x1p700; + y *= 0x1p700; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z*sqrt(ly+lx+hy+hx); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/hypotf.c b/user/include/mlibc/options/ansi/musl-generic-math/hypotf.c new file mode 100644 index 0000000..2fc214b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/hypotf.c @@ -0,0 +1,35 @@ +#include +#include + +float hypotf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}, ut; + float_t z; + + ux.i &= -1U>>1; + uy.i &= -1U>>1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + x = ux.f; + y = uy.f; + if (uy.i == 0xff<<23) + return y; + if (ux.i >= 0xff<<23 || uy.i == 0 || ux.i - uy.i >= 25<<23) + return x + y; + + z = 1; + if (ux.i >= (0x7f+60)<<23) { + z = 0x1p90f; + x *= 0x1p-90f; + y *= 0x1p-90f; + } else if (uy.i < (0x7f-60)<<23) { + z = 0x1p-90f; + x *= 0x1p90f; + y *= 0x1p90f; + } + return z*sqrtf((double)x*x + (double)y*y); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/hypotl.c b/user/include/mlibc/options/ansi/musl-generic-math/hypotl.c new file mode 100644 index 0000000..479aa92 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/hypotl.c @@ -0,0 +1,66 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double hypotl(long double x, long double y) +{ + return hypot(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32L+1) +#elif LDBL_MANT_DIG == 113 +#define SPLIT (0x1p57L+1) +#endif + +static void sq(long double *hi, long double *lo, long double x) +{ + long double xh, xl, xc; + xc = x*SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; +} + +long double hypotl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + int ex, ey; + long double hx, lx, hy, ly, z; + + ux.i.se &= 0x7fff; + uy.i.se &= 0x7fff; + if (ux.i.se < uy.i.se) { + ex = uy.i.se; + ey = ux.i.se; + x = uy.f; + y = ux.f; + } else { + ex = ux.i.se; + ey = uy.i.se; + x = ux.f; + y = uy.f; + } + + if (ex == 0x7fff && isinf(y)) + return y; + if (ex == 0x7fff || y == 0) + return x; + if (ex - ey > LDBL_MANT_DIG) + return x + y; + + z = 1; + if (ex > 0x3fff+8000) { + z = 0x1p10000L; + x *= 0x1p-10000L; + y *= 0x1p-10000L; + } else if (ey < 0x3fff-8000) { + z = 0x1p-10000L; + x *= 0x1p10000L; + y *= 0x1p10000L; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z*sqrtl(ly+lx+hy+hx); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ilogb.c b/user/include/mlibc/options/ansi/musl-generic-math/ilogb.c new file mode 100644 index 0000000..64d4015 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ilogb.c @@ -0,0 +1,26 @@ +#include +#include "libm.h" + +int ilogb(double x) +{ + #pragma STDC FENV_ACCESS ON + union {double f; uint64_t i;} u = {x}; + uint64_t i = u.i; + int e = i>>52 & 0x7ff; + + if (!e) { + i <<= 12; + if (i == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3ff; i>>63 == 0; e--, i<<=1); + return e; + } + if (e == 0x7ff) { + FORCE_EVAL(0/0.0f); + return i<<12 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3ff; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ilogbf.c b/user/include/mlibc/options/ansi/musl-generic-math/ilogbf.c new file mode 100644 index 0000000..e23ba20 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ilogbf.c @@ -0,0 +1,26 @@ +#include +#include "libm.h" + +int ilogbf(float x) +{ + #pragma STDC FENV_ACCESS ON + union {float f; uint32_t i;} u = {x}; + uint32_t i = u.i; + int e = i>>23 & 0xff; + + if (!e) { + i <<= 9; + if (i == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x7f; i>>31 == 0; e--, i<<=1); + return e; + } + if (e == 0xff) { + FORCE_EVAL(0/0.0f); + return i<<9 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x7f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ilogbl.c b/user/include/mlibc/options/ansi/musl-generic-math/ilogbl.c new file mode 100644 index 0000000..7b1a9cf --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ilogbl.c @@ -0,0 +1,55 @@ +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int ilogbl(long double x) +{ + return ilogb(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) +{ + #pragma STDC FENV_ACCESS ON + union ldshape u = {x}; + uint64_t m = u.i.m; + int e = u.i.se & 0x7fff; + + if (!e) { + if (m == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3fff+1; m>>63 == 0; e--, m<<=1); + return e; + } + if (e == 0x7fff) { + FORCE_EVAL(0/0.0f); + return m<<1 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) +{ + #pragma STDC FENV_ACCESS ON + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (!e) { + if (x == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + x *= 0x1p120; + return ilogbl(x) - 120; + } + if (e == 0x7fff) { + FORCE_EVAL(0/0.0f); + u.i.se = 0; + return u.f ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/j0.c b/user/include/mlibc/options/ansi/musl-generic-math/j0.c new file mode 100644 index 0000000..d722d94 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/j0.c @@ -0,0 +1,375 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +#include "libm.h" + +static double pzero(double), qzero(double); + +static const double +invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +static double common(uint32_t ix, double x, int y0) +{ + double s,c,ss,cc,z; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if (y0) + c = -c; + cc = s+c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if (ix < 0x7fe00000) { + ss = s-c; + z = -cos(2*x); + if (s*c < 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x48000000) { + if (y0) + ss = -ss; + cc = pzero(x)*cc-qzero(x)*ss; + } + } + return invsqrtpi*cc/sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +static const double +R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */ +R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */ +R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */ +R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */ +S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */ +S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */ +S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */ +S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +double j0(double x) +{ + double z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if (ix >= 0x7ff00000) + return 1/(x*x); + x = fabs(x); + + if (ix >= 0x40000000) { /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix,x,0); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if (ix >= 0x3f200000) { /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1+z*(S01+z*(S02+z*(S03+z*S04))); + return (1+x/2)*(1-x/2) + z*(r/s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if (ix >= 0x38000000) /* |x| >= 2**-127 */ + x = 0.25*x*x; + return 1 - x; +} + +static const double +u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */ +u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */ +u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */ +u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */ +u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */ +u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */ +u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */ +v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */ +v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */ +v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */ +v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +double y0(double x) +{ + double z,u,v; + uint32_t ix,lx; + + EXTRACT_WORDS(ix, lx, x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix<<1 | lx) == 0) + return -1/0.0; + if (ix>>31) + return 0/0.0; + if (ix >= 0x7ff00000) + return 1/x; + + if (ix >= 0x40000000) { /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix,x,1); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if (ix >= 0x3e400000) { /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = 1.0+z*(v01+z*(v02+z*(v03+z*v04))); + return u/v + tpi*(j0(x)*log(x)); + } + return u00 + tpi*log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +}; +static const double pS8[5] = { + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +}; + +static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +}; +static const double pS5[5] = { + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +}; + +static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +}; +static const double pS3[5] = { + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +}; + +static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +}; +static const double pS2[5] = { + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +}; + +static double pzero(double x) +{ + const double *p,*q; + double_t z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = pR8; q = pS8;} + else if (ix >= 0x40122E8B){p = pR5; q = pS5;} + else if (ix >= 0x4006DB6D){p = pR3; q = pS3;} + else /*ix >= 0x40000000*/ {p = pR2; q = pS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +}; +static const double qS8[6] = { + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +}; + +static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +}; +static const double qS5[6] = { + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +}; + +static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +}; +static const double qS3[6] = { + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +}; + +static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +}; +static const double qS2[6] = { + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +}; + +static double qzero(double x) +{ + const double *p,*q; + double_t s,r,z; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = qR8; q = qS8;} + else if (ix >= 0x40122E8B){p = qR5; q = qS5;} + else if (ix >= 0x4006DB6D){p = qR3; q = qS3;} + else /*ix >= 0x40000000*/ {p = qR2; q = qS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-.125 + r/s)/x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/j0f.c b/user/include/mlibc/options/ansi/musl-generic-math/j0f.c new file mode 100644 index 0000000..fab554a --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/j0f.c @@ -0,0 +1,314 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +static float pzerof(float), qzerof(float); + +static const float +invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y0) +{ + float z,s,c,ss,cc; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if (y0) + c = -c; + cc = s+c; + if (ix < 0x7f000000) { + ss = s-c; + z = -cosf(2*x); + if (s*c < 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x58800000) { + if (y0) + ss = -ss; + cc = pzerof(x)*cc-qzerof(x)*ss; + } + } + return invsqrtpi*cc/sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +static const float +R02 = 1.5625000000e-02, /* 0x3c800000 */ +R03 = -1.8997929874e-04, /* 0xb947352e */ +R04 = 1.8295404516e-06, /* 0x35f58e88 */ +R05 = -4.6183270541e-09, /* 0xb19eaf3c */ +S01 = 1.5619102865e-02, /* 0x3c7fe744 */ +S02 = 1.1692678527e-04, /* 0x38f53697 */ +S03 = 5.1354652442e-07, /* 0x3509daa6 */ +S04 = 1.1661400734e-09; /* 0x30a045e8 */ + +float j0f(float x) +{ + float z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x7f800000) + return 1/(x*x); + x = fabsf(x); + + if (ix >= 0x40000000) { /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, 0); + } + if (ix >= 0x3a000000) { /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1+z*(S01+z*(S02+z*(S03+z*S04))); + return (1+x/2)*(1-x/2) + z*(r/s); + } + if (ix >= 0x21800000) /* |x| >= 2**-60 */ + x = 0.25f*x*x; + return 1 - x; +} + +static const float +u00 = -7.3804296553e-02, /* 0xbd9726b5 */ +u01 = 1.7666645348e-01, /* 0x3e34e80d */ +u02 = -1.3818567619e-02, /* 0xbc626746 */ +u03 = 3.4745343146e-04, /* 0x39b62a69 */ +u04 = -3.8140706238e-06, /* 0xb67ff53c */ +u05 = 1.9559013964e-08, /* 0x32a802ba */ +u06 = -3.9820518410e-11, /* 0xae2f21eb */ +v01 = 1.2730483897e-02, /* 0x3c509385 */ +v02 = 7.6006865129e-05, /* 0x389f65e0 */ +v03 = 2.5915085189e-07, /* 0x348b216c */ +v04 = 4.4111031494e-10; /* 0x2ff280c2 */ + +float y0f(float x) +{ + float z,u,v; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + if ((ix & 0x7fffffff) == 0) + return -1/0.0f; + if (ix>>31) + return 0/0.0f; + if (ix >= 0x7f800000) + return 1/x; + if (ix >= 0x40000000) { /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix,x,1); + } + if (ix >= 0x39000000) { /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = 1+z*(v01+z*(v02+z*(v03+z*v04))); + return u/v + tpi*(j0f(x)*logf(x)); + } + return u00 + tpi*logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const float pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +}; +static const float pS8[5] = { + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +}; +static const float pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +}; +static const float pS5[5] = { + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +}; + +static const float pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +}; +static const float pS3[5] = { + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +}; + +static const float pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +}; +static const float pS2[5] = { + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +}; + +static float pzerof(float x) +{ + const float *p,*q; + float_t z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = pR8; q = pS8;} + else if (ix >= 0x409173eb){p = pR5; q = pS5;} + else if (ix >= 0x4036d917){p = pR3; q = pS3;} + else /*ix >= 0x40000000*/ {p = pR2; q = pS2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0f + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const float qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +}; +static const float qS8[6] = { + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +}; + +static const float qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +}; +static const float qS5[6] = { + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +}; + +static const float qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +}; +static const float qS3[6] = { + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +}; + +static const float qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +}; +static const float qS2[6] = { + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +}; + +static float qzerof(float x) +{ + const float *p,*q; + float_t s,r,z; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = qR8; q = qS8;} + else if (ix >= 0x409173eb){p = qR5; q = qS5;} + else if (ix >= 0x4036d917){p = qR3; q = qS3;} + else /*ix >= 0x40000000*/ {p = qR2; q = qS2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-.125f + r/s)/x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/j1.c b/user/include/mlibc/options/ansi/musl-generic-math/j1.c new file mode 100644 index 0000000..df724d1 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/j1.c @@ -0,0 +1,362 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +#include "libm.h" + +static double pone(double), qone(double); + +static const double +invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +static double common(uint32_t ix, double x, int y1, int sign) +{ + double z,s,c,ss,cc; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if (y1) + s = -s; + c = cos(x); + cc = s-c; + if (ix < 0x7fe00000) { + /* avoid overflow in 2*x */ + ss = -s-c; + z = cos(2*x); + if (s*c > 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x48000000) { + if (y1) + ss = -ss; + cc = pone(x)*cc-qone(x)*ss; + } + } + if (sign) + cc = -cc; + return invsqrtpi*cc/sqrt(x); +} + +/* R0/S0 on [0,2] */ +static const double +r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */ +r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */ +r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */ +r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */ +s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */ +s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */ +s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */ +s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */ +s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +double j1(double x) +{ + double z,r,s; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) + return 1/(x*x); + if (ix >= 0x40000000) /* |x| >= 2 */ + return common(ix, fabs(x), 0, sign); + if (ix >= 0x38000000) { /* |x| >= 2**-127 */ + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = 1+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + z = r/s; + } else + /* avoid underflow, raise inexact if x!=0 */ + z = x; + return (0.5 + z)*x; +} + +static const double U0[5] = { + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +}; +static const double V0[5] = { + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +}; + +double y1(double x) +{ + double z,u,v; + uint32_t ix,lx; + + EXTRACT_WORDS(ix, lx, x); + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if ((ix<<1 | lx) == 0) + return -1/0.0; + if (ix>>31) + return 0/0.0; + if (ix >= 0x7ff00000) + return 1/x; + + if (ix >= 0x40000000) /* x >= 2 */ + return common(ix, x, 1, 0); + if (ix < 0x3c900000) /* x < 2**-54 */ + return -tpi/x; + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + tpi*(j1(x)*log(x)-1/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +}; +static const double ps8[5] = { + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +}; + +static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +}; +static const double ps5[5] = { + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +}; + +static const double pr3[6] = { + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +}; +static const double ps3[5] = { + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +}; + +static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +}; +static const double ps2[5] = { + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +}; + +static double pone(double x) +{ + const double *p,*q; + double_t z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = pr8; q = ps8;} + else if (ix >= 0x40122E8B){p = pr5; q = ps5;} + else if (ix >= 0x4006DB6D){p = pr3; q = ps3;} + else /*ix >= 0x40000000*/ {p = pr2; q = ps2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0+ r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +}; +static const double qs8[6] = { + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +}; + +static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +}; +static const double qs5[6] = { + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +}; + +static const double qr3[6] = { + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +}; +static const double qs3[6] = { + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +}; + +static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +}; +static const double qs2[6] = { + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +}; + +static double qone(double x) +{ + const double *p,*q; + double_t s,r,z; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = qr8; q = qs8;} + else if (ix >= 0x40122E8B){p = qr5; q = qs5;} + else if (ix >= 0x4006DB6D){p = qr3; q = qs3;} + else /*ix >= 0x40000000*/ {p = qr2; q = qs2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (.375 + r/s)/x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/j1f.c b/user/include/mlibc/options/ansi/musl-generic-math/j1f.c new file mode 100644 index 0000000..3434c53 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/j1f.c @@ -0,0 +1,310 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +static float ponef(float), qonef(float); + +static const float +invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y1, int sign) +{ + double z,s,c,ss,cc; + + s = sinf(x); + if (y1) + s = -s; + c = cosf(x); + cc = s-c; + if (ix < 0x7f000000) { + ss = -s-c; + z = cosf(2*x); + if (s*c > 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x58800000) { + if (y1) + ss = -ss; + cc = ponef(x)*cc-qonef(x)*ss; + } + } + if (sign) + cc = -cc; + return invsqrtpi*cc/sqrtf(x); +} + +/* R0/S0 on [0,2] */ +static const float +r00 = -6.2500000000e-02, /* 0xbd800000 */ +r01 = 1.4070566976e-03, /* 0x3ab86cfd */ +r02 = -1.5995563444e-05, /* 0xb7862e36 */ +r03 = 4.9672799207e-08, /* 0x335557d2 */ +s01 = 1.9153760746e-02, /* 0x3c9ce859 */ +s02 = 1.8594678841e-04, /* 0x3942fab6 */ +s03 = 1.1771846857e-06, /* 0x359dffc2 */ +s04 = 5.0463624390e-09, /* 0x31ad6446 */ +s05 = 1.2354227016e-11; /* 0x2d59567e */ + +float j1f(float x) +{ + float z,r,s; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) + return 1/(x*x); + if (ix >= 0x40000000) /* |x| >= 2 */ + return common(ix, fabsf(x), 0, sign); + if (ix >= 0x39000000) { /* |x| >= 2**-13 */ + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = 1+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + z = 0.5f + r/s; + } else + z = 0.5f; + return z*x; +} + +static const float U0[5] = { + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +}; +static const float V0[5] = { + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +}; + +float y1f(float x) +{ + float z,u,v; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + if ((ix & 0x7fffffff) == 0) + return -1/0.0f; + if (ix>>31) + return 0/0.0f; + if (ix >= 0x7f800000) + return 1/x; + if (ix >= 0x40000000) /* |x| >= 2.0 */ + return common(ix,x,1,0); + if (ix < 0x33000000) /* x < 2**-25 */ + return -tpi/x; + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1.0f+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + tpi*(j1f(x)*logf(x)-1.0f/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const float pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +}; +static const float ps8[5] = { + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +}; + +static const float pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +}; +static const float ps5[5] = { + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +}; + +static const float pr3[6] = { + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +}; +static const float ps3[5] = { + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +}; + +static const float pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +}; +static const float ps2[5] = { + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +}; + +static float ponef(float x) +{ + const float *p,*q; + float_t z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = pr8; q = ps8;} + else if (ix >= 0x409173eb){p = pr5; q = ps5;} + else if (ix >= 0x4036d917){p = pr3; q = ps3;} + else /*ix >= 0x40000000*/ {p = pr2; q = ps2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0f + r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const float qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +}; +static const float qs8[6] = { + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +}; + +static const float qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +}; +static const float qs5[6] = { + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +}; + +static const float qr3[6] = { + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +}; +static const float qs3[6] = { + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +}; + +static const float qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +}; +static const float qs2[6] = { + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +}; + +static float qonef(float x) +{ + const float *p,*q; + float_t s,r,z; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = qr8; q = qs8;} + else if (ix >= 0x409173eb){p = qr5; q = qs5;} + else if (ix >= 0x4036d917){p = qr3; q = qs3;} + else /*ix >= 0x40000000*/ {p = qr2; q = qs2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (.375f + r/s)/x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/jn.c b/user/include/mlibc/options/ansi/musl-generic-math/jn.c new file mode 100644 index 0000000..4878a54 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/jn.c @@ -0,0 +1,280 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +#include "libm.h" + +static const double invsqrtpi = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +double jn(int n, double x) +{ + uint32_t ix, lx; + int nm1, i, sign; + double a, b, temp; + + EXTRACT_WORDS(ix, lx, x); + sign = ix>>31; + ix &= 0x7fffffff; + + if ((ix | (lx|-lx)>>31) > 0x7ff00000) /* nan */ + return x; + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if (n == 0) + return j0(x); + if (n < 0) { + nm1 = -(n+1); + x = -x; + sign ^= 1; + } else + nm1 = n-1; + if (nm1 == 0) + return j1(x); + + sign &= n; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if ((ix|lx) == 0 || ix == 0x7ff00000) /* if x is 0 or inf */ + b = 0.0; + else if (nm1 < x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if (ix >= 0x52d00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(nm1&3) { + case 0: temp = -cos(x)+sin(x); break; + case 1: temp = -cos(x)-sin(x); break; + case 2: temp = cos(x)-sin(x); break; + default: + case 3: temp = cos(x)+sin(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + a = j0(x); + b = j1(x); + for (i=0; i 32) /* underflow */ + b = 0.0; + else { + temp = x*0.5; + b = temp; + a = 1.0; + for (i=2; i<=nm1+1; i++) { + a *= (double)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + double t,q0,q1,w,h,z,tmp,nf; + int k; + + nf = nm1 + 1.0; + w = 2*nf/x; + h = 2/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0; + k = 1; + while (q1 < 1.0e9) { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + for (t=0.0, i=k; i>=0; i--) + t = 1/(2*(i+nf)/x - t); + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*log(fabs(w)); + if (tmp < 7.09782712893383973096e+02) { + for (i=nm1; i>0; i--) { + temp = b; + b = b*(2.0*i)/x - a; + a = temp; + } + } else { + for (i=nm1; i>0; i--) { + temp = b; + b = b*(2.0*i)/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + if (b > 0x1p500) { + a /= b; + t /= b; + b = 1.0; + } + } + } + z = j0(x); + w = j1(x); + if (fabs(z) >= fabs(w)) + b = t*z/b; + else + b = t*w/a; + } + } + return sign ? -b : b; +} + + +double yn(int n, double x) +{ + uint32_t ix, lx, ib; + int nm1, sign, i; + double a, b, temp; + + EXTRACT_WORDS(ix, lx, x); + sign = ix>>31; + ix &= 0x7fffffff; + + if ((ix | (lx|-lx)>>31) > 0x7ff00000) /* nan */ + return x; + if (sign && (ix|lx)!=0) /* x < 0 */ + return 0/0.0; + if (ix == 0x7ff00000) + return 0.0; + + if (n == 0) + return y0(x); + if (n < 0) { + nm1 = -(n+1); + sign = n&1; + } else { + nm1 = n-1; + sign = 0; + } + if (nm1 == 0) + return sign ? -y1(x) : y1(x); + + if (ix >= 0x52d00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(nm1&3) { + case 0: temp = -sin(x)-cos(x); break; + case 1: temp = -sin(x)+cos(x); break; + case 2: temp = sin(x)+cos(x); break; + default: + case 3: temp = sin(x)-cos(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + GET_HIGH_WORD(ib, b); + for (i=0; i>31; + ix &= 0x7fffffff; + if (ix > 0x7f800000) /* nan */ + return x; + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if (n == 0) + return j0f(x); + if (n < 0) { + nm1 = -(n+1); + x = -x; + sign ^= 1; + } else + nm1 = n-1; + if (nm1 == 0) + return j1f(x); + + sign &= n; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if (ix == 0 || ix == 0x7f800000) /* if x is 0 or inf */ + b = 0.0f; + else if (nm1 < x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + for (i=0; i 8) /* underflow */ + nm1 = 8; + temp = 0.5f * x; + b = temp; + a = 1.0f; + for (i=2; i<=nm1+1; i++) { + a *= (float)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + float t,q0,q1,w,h,z,tmp,nf; + int k; + + nf = nm1+1.0f; + w = 2*nf/x; + h = 2/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0f; + k = 1; + while (q1 < 1.0e4f) { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + for (t=0.0f, i=k; i>=0; i--) + t = 1.0f/(2*(i+nf)/x-t); + a = t; + b = 1.0f; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*logf(fabsf(w)); + if (tmp < 88.721679688f) { + for (i=nm1; i>0; i--) { + temp = b; + b = 2.0f*i*b/x - a; + a = temp; + } + } else { + for (i=nm1; i>0; i--){ + temp = b; + b = 2.0f*i*b/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + if (b > 0x1p60f) { + a /= b; + t /= b; + b = 1.0f; + } + } + } + z = j0f(x); + w = j1f(x); + if (fabsf(z) >= fabsf(w)) + b = t*z/b; + else + b = t*w/a; + } + } + return sign ? -b : b; +} + +float ynf(int n, float x) +{ + uint32_t ix, ib; + int nm1, sign, i; + float a, b, temp; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix > 0x7f800000) /* nan */ + return x; + if (sign && ix != 0) /* x < 0 */ + return 0/0.0f; + if (ix == 0x7f800000) + return 0.0f; + + if (n == 0) + return y0f(x); + if (n < 0) { + nm1 = -(n+1); + sign = n&1; + } else { + nm1 = n-1; + sign = 0; + } + if (nm1 == 0) + return sign ? -y1f(x) : y1f(x); + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + GET_FLOAT_WORD(ib,b); + for (i = 0; i < nm1 && ib != 0xff800000; ) { + i++; + temp = b; + b = (2.0f*i/x)*b - a; + GET_FLOAT_WORD(ib, b); + a = temp; + } + return sign ? -b : b; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ldexp.c b/user/include/mlibc/options/ansi/musl-generic-math/ldexp.c new file mode 100644 index 0000000..f4d1cd6 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ldexp.c @@ -0,0 +1,6 @@ +#include + +double ldexp(double x, int n) +{ + return scalbn(x, n); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ldexpf.c b/user/include/mlibc/options/ansi/musl-generic-math/ldexpf.c new file mode 100644 index 0000000..3bad5f3 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ldexpf.c @@ -0,0 +1,6 @@ +#include + +float ldexpf(float x, int n) +{ + return scalbnf(x, n); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/ldexpl.c b/user/include/mlibc/options/ansi/musl-generic-math/ldexpl.c new file mode 100644 index 0000000..fd145cc --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/ldexpl.c @@ -0,0 +1,6 @@ +#include + +long double ldexpl(long double x, int n) +{ + return scalbnl(x, n); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lgamma.c b/user/include/mlibc/options/ansi/musl-generic-math/lgamma.c new file mode 100644 index 0000000..e25ec8e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lgamma.c @@ -0,0 +1,9 @@ +#include + +extern int __signgam; +double __lgamma_r(double, int *); + +double lgamma(double x) +{ + return __lgamma_r(x, &__signgam); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lgamma_r.c b/user/include/mlibc/options/ansi/musl-generic-math/lgamma_r.c new file mode 100644 index 0000000..84596a3 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lgamma_r.c @@ -0,0 +1,285 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +#include "libm.h" +#include "weak_alias.h" +//#include "libc.h" + +static const double +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */ +a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */ +a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */ +a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */ +a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */ +a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */ +a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */ +a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */ +a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */ +a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */ +a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */ +a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */ +tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */ +tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of tf) */ +tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */ +t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */ +t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */ +t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */ +t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */ +t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */ +t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */ +t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */ +t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */ +t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */ +t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */ +t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */ +t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */ +t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */ +t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */ +t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */ +u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */ +u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */ +u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */ +u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */ +u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */ +v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */ +v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */ +v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */ +v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */ +v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */ +s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */ +s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */ +s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */ +s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */ +s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */ +s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */ +r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */ +r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */ +r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */ +r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */ +r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */ +r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */ +w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */ +w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */ +w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */ +w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */ +w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */ +w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */ +w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sin_pi(double x) +{ + int n; + + /* spurious inexact if odd int */ + x = 2.0*(x*0.5 - floor(x*0.5)); /* x mod 2.0 */ + + n = (int)(x*4.0); + n = (n+1)/2; + x -= n*0.5f; + x *= pi; + + switch (n) { + default: /* case 4: */ + case 0: return __sin(x, 0.0, 0); + case 1: return __cos(x, 0.0); + case 2: return __sin(-x, 0.0, 0); + case 3: return -__cos(x, 0.0); + } +} + +double __lgamma_r(double x, int *signgamp) +{ + union {double f; uint64_t i;} u = {x}; + double_t t,y,z,nadj,p,p1,p2,p3,q,r,w; + uint32_t ix; + int sign,i; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix >= 0x7ff00000) + return x*x; + if (ix < (0x3ff-70)<<20) { /* |x|<2**-70, return -log(|x|) */ + if(sign) { + x = -x; + *signgamp = -1; + } + return -log(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0) /* -integer */ + return 1.0/(x-x); + if (t > 0.0) + *signgamp = -1; + else + t = -t; + nadj = log(pi/(t*x)); + } + + /* purge off 1 and 2 */ + if ((ix == 0x3ff00000 || ix == 0x40000000) && (uint32_t)u.i == 0) + r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if (ix >= 0x3FE76944) { + y = 1.0 - x; + i = 0; + } else if (ix >= 0x3FCDA661) { + y = x - (tc-1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3FFBB4C3) { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if(ix >= 0x3FF3B4C4) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-0.5*y); + break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += tf + p; + break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = 1.0+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += -0.5*y + p1/p2; + } + } else if (ix < 0x40200000) { /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = 1.0+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5*y+p/q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: z *= y + 6.0; /* FALLTHRU */ + case 6: z *= y + 5.0; /* FALLTHRU */ + case 5: z *= y + 4.0; /* FALLTHRU */ + case 4: z *= y + 3.0; /* FALLTHRU */ + case 3: z *= y + 2.0; /* FALLTHRU */ + r += log(z); + break; + } + } else if (ix < 0x43900000) { /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-0.5)*(t-1.0)+w; + } else /* 2**58 <= x <= inf */ + r = x*(log(x)-1.0); + if (sign) + r = nadj - r; + return r; +} + +weak_alias(__lgamma_r, lgamma_r); diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lgammaf.c b/user/include/mlibc/options/ansi/musl-generic-math/lgammaf.c new file mode 100644 index 0000000..badb6df --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lgammaf.c @@ -0,0 +1,9 @@ +#include + +extern int __signgam; +float __lgammaf_r(float, int *); + +float lgammaf(float x) +{ + return __lgammaf_r(x, &__signgam); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lgammaf_r.c b/user/include/mlibc/options/ansi/musl-generic-math/lgammaf_r.c new file mode 100644 index 0000000..f73e89d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lgammaf_r.c @@ -0,0 +1,220 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" +#include "weak_alias.h" +//#include "libc.h" + +static const float +pi = 3.1415927410e+00, /* 0x40490fdb */ +a0 = 7.7215664089e-02, /* 0x3d9e233f */ +a1 = 3.2246702909e-01, /* 0x3ea51a66 */ +a2 = 6.7352302372e-02, /* 0x3d89f001 */ +a3 = 2.0580807701e-02, /* 0x3ca89915 */ +a4 = 7.3855509982e-03, /* 0x3bf2027e */ +a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ +a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ +a7 = 5.1006977446e-04, /* 0x3a05b634 */ +a8 = 2.2086278477e-04, /* 0x39679767 */ +a9 = 1.0801156895e-04, /* 0x38e28445 */ +a10 = 2.5214456400e-05, /* 0x37d383a2 */ +a11 = 4.4864096708e-05, /* 0x383c2c75 */ +tc = 1.4616321325e+00, /* 0x3fbb16c3 */ +tf = -1.2148628384e-01, /* 0xbdf8cdcd */ +/* tt = -(tail of tf) */ +tt = 6.6971006518e-09, /* 0x31e61c52 */ +t0 = 4.8383611441e-01, /* 0x3ef7b95e */ +t1 = -1.4758771658e-01, /* 0xbe17213c */ +t2 = 6.4624942839e-02, /* 0x3d845a15 */ +t3 = -3.2788541168e-02, /* 0xbd064d47 */ +t4 = 1.7970675603e-02, /* 0x3c93373d */ +t5 = -1.0314224288e-02, /* 0xbc28fcfe */ +t6 = 6.1005386524e-03, /* 0x3bc7e707 */ +t7 = -3.6845202558e-03, /* 0xbb7177fe */ +t8 = 2.2596477065e-03, /* 0x3b141699 */ +t9 = -1.4034647029e-03, /* 0xbab7f476 */ +t10 = 8.8108185446e-04, /* 0x3a66f867 */ +t11 = -5.3859531181e-04, /* 0xba0d3085 */ +t12 = 3.1563205994e-04, /* 0x39a57b6b */ +t13 = -3.1275415677e-04, /* 0xb9a3f927 */ +t14 = 3.3552918467e-04, /* 0x39afe9f7 */ +u0 = -7.7215664089e-02, /* 0xbd9e233f */ +u1 = 6.3282704353e-01, /* 0x3f2200f4 */ +u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ +u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ +u4 = 2.2896373272e-01, /* 0x3e6a7578 */ +u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ +v1 = 2.4559779167e+00, /* 0x401d2ebe */ +v2 = 2.1284897327e+00, /* 0x4008392d */ +v3 = 7.6928514242e-01, /* 0x3f44efdf */ +v4 = 1.0422264785e-01, /* 0x3dd572af */ +v5 = 3.2170924824e-03, /* 0x3b52d5db */ +s0 = -7.7215664089e-02, /* 0xbd9e233f */ +s1 = 2.1498242021e-01, /* 0x3e5c245a */ +s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ +s3 = 1.4635047317e-01, /* 0x3e15dce6 */ +s4 = 2.6642270386e-02, /* 0x3cda40e4 */ +s5 = 1.8402845599e-03, /* 0x3af135b4 */ +s6 = 3.1947532989e-05, /* 0x3805ff67 */ +r1 = 1.3920053244e+00, /* 0x3fb22d3b */ +r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ +r3 = 1.7193385959e-01, /* 0x3e300f6e */ +r4 = 1.8645919859e-02, /* 0x3c98bf54 */ +r5 = 7.7794247773e-04, /* 0x3a4beed6 */ +r6 = 7.3266842264e-06, /* 0x36f5d7bd */ +w0 = 4.1893854737e-01, /* 0x3ed67f1d */ +w1 = 8.3333335817e-02, /* 0x3daaaaab */ +w2 = -2.7777778450e-03, /* 0xbb360b61 */ +w3 = 7.9365057172e-04, /* 0x3a500cfd */ +w4 = -5.9518753551e-04, /* 0xba1c065c */ +w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ +w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static float sin_pi(float x) +{ + double_t y; + int n; + + /* spurious inexact if odd int */ + x = 2*(x*0.5f - floorf(x*0.5f)); /* x mod 2.0 */ + + n = (int)(x*4); + n = (n+1)/2; + y = x - n*0.5f; + y *= 3.14159265358979323846; + switch (n) { + default: /* case 4: */ + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + case 3: return -__cosdf(y); + } +} + +float __lgammaf_r(float x, int *signgamp) +{ + union {float f; uint32_t i;} u = {x}; + float t,y,z,nadj,p,p1,p2,p3,q,r,w; + uint32_t ix; + int i,sign; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + sign = u.i>>31; + ix = u.i & 0x7fffffff; + if (ix >= 0x7f800000) + return x*x; + if (ix < 0x35000000) { /* |x| < 2**-21, return -log(|x|) */ + if (sign) { + *signgamp = -1; + x = -x; + } + return -logf(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0f) /* -integer */ + return 1.0f/(x-x); + if (t > 0.0f) + *signgamp = -1; + else + t = -t; + nadj = logf(pi/(t*x)); + } + + /* purge off 1 and 2 */ + if (ix == 0x3f800000 || ix == 0x40000000) + r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if (ix >= 0x3f3b4a20) { + y = 1.0f - x; + i = 0; + } else if (ix >= 0x3e6d3308) { + y = x - (tc-1.0f); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0f; + if (ix >= 0x3fdda618) { /* [1.7316,2] */ + y = 2.0f - x; + i = 0; + } else if (ix >= 0x3F9da620) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0f; + i = 2; + } + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += p - 0.5f*y; + break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); + break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = 1.0f+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += -0.5f*y + p1/p2; + } + } else if (ix < 0x41000000) { /* x < 8.0 */ + i = (int)x; + y = x - (float)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = 1.0f+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5f*y+p/q; + z = 1.0f; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: z *= y + 6.0f; /* FALLTHRU */ + case 6: z *= y + 5.0f; /* FALLTHRU */ + case 5: z *= y + 4.0f; /* FALLTHRU */ + case 4: z *= y + 3.0f; /* FALLTHRU */ + case 3: z *= y + 2.0f; /* FALLTHRU */ + r += logf(z); + break; + } + } else if (ix < 0x5c800000) { /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0f/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-0.5f)*(t-1.0f)+w; + } else /* 2**58 <= x <= inf */ + r = x*(logf(x)-1.0f); + if (sign) + r = nadj - r; + return r; +} + +weak_alias(__lgammaf_r, lgammaf_r); diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lgammal.c b/user/include/mlibc/options/ansi/musl-generic-math/lgammal.c new file mode 100644 index 0000000..f0bea36 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lgammal.c @@ -0,0 +1,361 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_lgammal.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* lgammal(x) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1)=lgamma(2)=0 + * lgamma(x) ~ -log(x) for tiny x + * lgamma(0) = lgamma(inf) = inf + * lgamma(-integer) = +-inf + * + */ + +#define _GNU_SOURCE +#include "libm.h" +#include "weak_alias.h" +//#include "libc.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +double __lgamma_r(double x, int *sg); + +long double __lgammal_r(long double x, int *sg) +{ + return __lgamma_r(x, sg); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +pi = 3.14159265358979323846264L, + +/* lgam(1+x) = 0.5 x + x a(x)/b(x) + -0.268402099609375 <= x <= 0 + peak relative error 6.6e-22 */ +a0 = -6.343246574721079391729402781192128239938E2L, +a1 = 1.856560238672465796768677717168371401378E3L, +a2 = 2.404733102163746263689288466865843408429E3L, +a3 = 8.804188795790383497379532868917517596322E2L, +a4 = 1.135361354097447729740103745999661157426E2L, +a5 = 3.766956539107615557608581581190400021285E0L, + +b0 = 8.214973713960928795704317259806842490498E3L, +b1 = 1.026343508841367384879065363925870888012E4L, +b2 = 4.553337477045763320522762343132210919277E3L, +b3 = 8.506975785032585797446253359230031874803E2L, +b4 = 6.042447899703295436820744186992189445813E1L, +/* b5 = 1.000000000000000000000000000000000000000E0 */ + + +tc = 1.4616321449683623412626595423257213284682E0L, +tf = -1.2148629053584961146050602565082954242826E-1, /* double precision */ +/* tt = (tail of tf), i.e. tf + tt has extended precision. */ +tt = 3.3649914684731379602768989080467587736363E-18L, +/* lgam ( 1.4616321449683623412626595423257213284682E0 ) = +-1.2148629053584960809551455717769158215135617312999903886372437313313530E-1 */ + +/* lgam (x + tc) = tf + tt + x g(x)/h(x) + -0.230003726999612341262659542325721328468 <= x + <= 0.2699962730003876587373404576742786715318 + peak relative error 2.1e-21 */ +g0 = 3.645529916721223331888305293534095553827E-18L, +g1 = 5.126654642791082497002594216163574795690E3L, +g2 = 8.828603575854624811911631336122070070327E3L, +g3 = 5.464186426932117031234820886525701595203E3L, +g4 = 1.455427403530884193180776558102868592293E3L, +g5 = 1.541735456969245924860307497029155838446E2L, +g6 = 4.335498275274822298341872707453445815118E0L, + +h0 = 1.059584930106085509696730443974495979641E4L, +h1 = 2.147921653490043010629481226937850618860E4L, +h2 = 1.643014770044524804175197151958100656728E4L, +h3 = 5.869021995186925517228323497501767586078E3L, +h4 = 9.764244777714344488787381271643502742293E2L, +h5 = 6.442485441570592541741092969581997002349E1L, +/* h6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam (x+1) = -0.5 x + x u(x)/v(x) + -0.100006103515625 <= x <= 0.231639862060546875 + peak relative error 1.3e-21 */ +u0 = -8.886217500092090678492242071879342025627E1L, +u1 = 6.840109978129177639438792958320783599310E2L, +u2 = 2.042626104514127267855588786511809932433E3L, +u3 = 1.911723903442667422201651063009856064275E3L, +u4 = 7.447065275665887457628865263491667767695E2L, +u5 = 1.132256494121790736268471016493103952637E2L, +u6 = 4.484398885516614191003094714505960972894E0L, + +v0 = 1.150830924194461522996462401210374632929E3L, +v1 = 3.399692260848747447377972081399737098610E3L, +v2 = 3.786631705644460255229513563657226008015E3L, +v3 = 1.966450123004478374557778781564114347876E3L, +v4 = 4.741359068914069299837355438370682773122E2L, +v5 = 4.508989649747184050907206782117647852364E1L, +/* v6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam (x+2) = .5 x + x s(x)/r(x) + 0 <= x <= 1 + peak relative error 7.2e-22 */ +s0 = 1.454726263410661942989109455292824853344E6L, +s1 = -3.901428390086348447890408306153378922752E6L, +s2 = -6.573568698209374121847873064292963089438E6L, +s3 = -3.319055881485044417245964508099095984643E6L, +s4 = -7.094891568758439227560184618114707107977E5L, +s5 = -6.263426646464505837422314539808112478303E4L, +s6 = -1.684926520999477529949915657519454051529E3L, + +r0 = -1.883978160734303518163008696712983134698E7L, +r1 = -2.815206082812062064902202753264922306830E7L, +r2 = -1.600245495251915899081846093343626358398E7L, +r3 = -4.310526301881305003489257052083370058799E6L, +r4 = -5.563807682263923279438235987186184968542E5L, +r5 = -3.027734654434169996032905158145259713083E4L, +r6 = -4.501995652861105629217250715790764371267E2L, +/* r6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x w(1/x^2) + x >= 8 + Peak relative error 1.51e-21 +w0 = LS2PI - 0.5 */ +w0 = 4.189385332046727417803e-1L, +w1 = 8.333333333333331447505E-2L, +w2 = -2.777777777750349603440E-3L, +w3 = 7.936507795855070755671E-4L, +w4 = -5.952345851765688514613E-4L, +w5 = 8.412723297322498080632E-4L, +w6 = -1.880801938119376907179E-3L, +w7 = 4.885026142432270781165E-3L; + +/* sin(pi*x) assuming x > 2^-1000, if sin(pi*x)==0 the sign is arbitrary */ +static long double sin_pi(long double x) +{ + int n; + + /* spurious inexact if odd int */ + x *= 0.5; + x = 2.0*(x - floorl(x)); /* x mod 2.0 */ + + n = (int)(x*4.0); + n = (n+1)/2; + x -= n*0.5f; + x *= pi; + + switch (n) { + default: /* case 4: */ + case 0: return __sinl(x, 0.0, 0); + case 1: return __cosl(x, 0.0); + case 2: return __sinl(-x, 0.0, 0); + case 3: return -__cosl(x, 0.0); + } +} + +long double __lgammal_r(long double x, int *sg) { + long double t, y, z, nadj, p, p1, p2, q, r, w; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + int i; + + *sg = 1; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + if (ix >= 0x7fff0000) + return x * x; + if (ix < 0x3fc08000) { /* |x|<2**-63, return -log(|x|) */ + if (sign) { + *sg = -1; + x = -x; + } + return -logl(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0) + return 1.0 / (x-x); /* -integer */ + if (t > 0.0) + *sg = -1; + else + t = -t; + nadj = logl(pi / (t * x)); + } + + /* purge off 1 and 2 (so the sign is ok with downward rounding) */ + if ((ix == 0x3fff8000 || ix == 0x40008000) && u.i.m == 0) { + r = 0; + } else if (ix < 0x40008000) { /* x < 2.0 */ + if (ix <= 0x3ffee666) { /* 8.99993896484375e-1 */ + /* lgamma(x) = lgamma(x+1) - log(x) */ + r = -logl(x); + if (ix >= 0x3ffebb4a) { /* 7.31597900390625e-1 */ + y = x - 1.0; + i = 0; + } else if (ix >= 0x3ffced33) { /* 2.31639862060546875e-1 */ + y = x - (tc - 1.0); + i = 1; + } else { /* x < 0.23 */ + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3fffdda6) { /* 1.73162841796875 */ + /* [1.7316,2] */ + y = x - 2.0; + i = 0; + } else if (ix >= 0x3fff9da6) { /* 1.23162841796875 */ + /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + /* [0.9, 1.23] */ + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + p1 = a0 + y * (a1 + y * (a2 + y * (a3 + y * (a4 + y * a5)))); + p2 = b0 + y * (b1 + y * (b2 + y * (b3 + y * (b4 + y)))); + r += 0.5 * y + y * p1/p2; + break; + case 1: + p1 = g0 + y * (g1 + y * (g2 + y * (g3 + y * (g4 + y * (g5 + y * g6))))); + p2 = h0 + y * (h1 + y * (h2 + y * (h3 + y * (h4 + y * (h5 + y))))); + p = tt + y * p1/p2; + r += (tf + p); + break; + case 2: + p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * (u5 + y * u6)))))); + p2 = v0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * (v5 + y))))); + r += (-0.5 * y + p1 / p2); + } + } else if (ix < 0x40028000) { /* 8.0 */ + /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6)))))); + q = r0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * (r6 + y)))))); + r = 0.5 * y + p / q; + z = 1.0; + /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: + z *= (y + 6.0); /* FALLTHRU */ + case 6: + z *= (y + 5.0); /* FALLTHRU */ + case 5: + z *= (y + 4.0); /* FALLTHRU */ + case 4: + z *= (y + 3.0); /* FALLTHRU */ + case 3: + z *= (y + 2.0); /* FALLTHRU */ + r += logl(z); + break; + } + } else if (ix < 0x40418000) { /* 2^66 */ + /* 8.0 <= x < 2**66 */ + t = logl(x); + z = 1.0 / x; + y = z * z; + w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * (w6 + y * w7)))))); + r = (x - 0.5) * (t - 1.0) + w; + } else /* 2**66 <= x <= inf */ + r = x * (logl(x) - 1.0); + if (sign) + r = nadj - r; + return r; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +double __lgamma_r(double x, int *sg); + +long double __lgammal_r(long double x, int *sg) +{ + return __lgamma_r(x, sg); +} +#endif + +extern int __signgam; + +long double lgammal(long double x) +{ + return __lgammal_r(x, &__signgam); +} + +weak_alias(__lgammal_r, lgammal_r); diff --git a/user/include/mlibc/options/ansi/musl-generic-math/libm.h b/user/include/mlibc/options/ansi/musl-generic-math/libm.h new file mode 100644 index 0000000..21ebd45 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/libm.h @@ -0,0 +1,197 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef _LIBM_H +#define _LIBM_H + +#include +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +union ldshape { + long double f; + struct { + uint64_t m; + uint16_t se; + } i; +}; +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +/* This is the m68k variant of 80-bit long double, and this definition only works + * on archs where the alignment requirement of uint64_t is <= 4. */ +union ldshape { + long double f; + struct { + uint16_t se; + uint16_t pad; + uint64_t m; + } i; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +union ldshape { + long double f; + struct { + uint64_t lo; + uint32_t mid; + uint16_t top; + uint16_t se; + } i; + struct { + uint64_t lo; + uint64_t hi; + } i2; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +union ldshape { + long double f; + struct { + uint16_t se; + uint16_t top; + uint32_t mid; + uint64_t lo; + } i; + struct { + uint64_t hi; + uint64_t lo; + } i2; +}; +#else +#error Unsupported long double representation +#endif + +#define FORCE_EVAL(x) do { \ + if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ + } else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ + } else { \ + volatile long double __x; \ + __x = (x); \ + } \ +} while(0) + +/* Get two 32 bit ints from a double. */ +#define EXTRACT_WORDS(hi,lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ +#define GET_HIGH_WORD(hi,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD(lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +/* Set a double from two 32 bit ints. */ +#define INSERT_WORDS(d,hi,lo) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.i = ((uint64_t)(hi)<<32) | (uint32_t)(lo); \ + (d) = __u.f; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ +#define SET_HIGH_WORD(d,hi) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff; \ + __u.i |= (uint64_t)(hi) << 32; \ + (d) = __u.f; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ +#define SET_LOW_WORD(d,lo) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff00000000ull; \ + __u.i |= (uint32_t)(lo); \ + (d) = __u.f; \ +} while (0) + +/* Get a 32 bit int from a float. */ +#define GET_FLOAT_WORD(w,d) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.f = (d); \ + (w) = __u.i; \ +} while (0) + +/* Set a float from a 32 bit int. */ +#define SET_FLOAT_WORD(d,w) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.i = (w); \ + (d) = __u.f; \ +} while (0) + +#undef __CMPLX +#undef CMPLX +#undef CMPLXF +#undef CMPLXL + +#define __CMPLX(x, y, t) \ + ((union { _Complex t __z; t __xy[2]; }){.__xy = {(x),(y)}}.__z) + +#define CMPLX(x, y) __CMPLX(x, y, double) +#define CMPLXF(x, y) __CMPLX(x, y, float) +#define CMPLXL(x, y) __CMPLX(x, y, long double) + +#ifndef __MLIBC_ABI_ONLY + +/* fdlibm kernel functions */ + +int __rem_pio2_large(double*,double*,int,int,int); + +int __rem_pio2(double,double*); +double __sin(double,double,int); +double __cos(double,double); +double __tan(double,double,int); +double __expo2(double); +/*double complex __ldexp_cexp(double complex,int); */ + +int __rem_pio2f(float,double*); +float __sindf(double); +float __cosdf(double); +float __tandf(double,int); +float __expo2f(float); +/*float complex __ldexp_cexpf(float complex,int); */ + +int __rem_pio2l(long double, long double *); +long double __sinl(long double, long double, int); +long double __cosl(long double, long double); +long double __tanl(long double, long double, int); + +/* polynomial evaluation */ +long double __polevll(long double, const long double *, int); +long double __p1evll(long double, const long double *, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/llrint.c b/user/include/mlibc/options/ansi/musl-generic-math/llrint.c new file mode 100644 index 0000000..4f583ae --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/llrint.c @@ -0,0 +1,8 @@ +#include + +/* uses LLONG_MAX > 2^53, see comments in lrint.c */ + +long long llrint(double x) +{ + return rint(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/llrintf.c b/user/include/mlibc/options/ansi/musl-generic-math/llrintf.c new file mode 100644 index 0000000..96949a0 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/llrintf.c @@ -0,0 +1,8 @@ +#include + +/* uses LLONG_MAX > 2^24, see comments in lrint.c */ + +long long llrintf(float x) +{ + return rintf(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/llrintl.c b/user/include/mlibc/options/ansi/musl-generic-math/llrintl.c new file mode 100644 index 0000000..3449f6f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/llrintl.c @@ -0,0 +1,36 @@ +#include +#include +#include "libm.h" + + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long long llrintl(long double x) +{ + return llrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LLONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long long llrintl(long double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LLONG_MAX || x < LLONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long long llrintl(long double x) +{ + return rintl(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/llround.c b/user/include/mlibc/options/ansi/musl-generic-math/llround.c new file mode 100644 index 0000000..4d94787 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/llround.c @@ -0,0 +1,6 @@ +#include + +long long llround(double x) +{ + return round(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/llroundf.c b/user/include/mlibc/options/ansi/musl-generic-math/llroundf.c new file mode 100644 index 0000000..19eb77e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/llroundf.c @@ -0,0 +1,6 @@ +#include + +long long llroundf(float x) +{ + return roundf(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/llroundl.c b/user/include/mlibc/options/ansi/musl-generic-math/llroundl.c new file mode 100644 index 0000000..2c2ee5e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/llroundl.c @@ -0,0 +1,6 @@ +#include + +long long llroundl(long double x) +{ + return roundl(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log.c b/user/include/mlibc/options/ansi/musl-generic-math/log.c new file mode 100644 index 0000000..e61e113 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log.c @@ -0,0 +1,118 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,dk; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + dk = k; + return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log10.c b/user/include/mlibc/options/ansi/musl-generic-math/log10.c new file mode 100644 index 0000000..8102687 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log10.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + +#include +#include + +static const double +ivln10hi = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */ +ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */ +log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ +log10_2lo = 3.69423907715893078616e-13, /* 0x3D59FEF3, 0x11F12B36 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log10(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,dk,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi*ivln10hi; + dk = k; + y = dk*log10_2hi; + val_lo = dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log10f.c b/user/include/mlibc/options/ansi/musl-generic-math/log10f.c new file mode 100644 index 0000000..9ca2f01 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log10f.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + +#include +#include + +static const float +ivln10hi = 4.3432617188e-01, /* 0x3ede6000 */ +ivln10lo = -3.1689971365e-05, /* 0xb804ead9 */ +log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ +log10_2lo = 7.9034151668e-07, /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log10f(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,dk,hi,lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + dk = k; + return dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + dk*log10_2hi; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log10l.c b/user/include/mlibc/options/ansi/musl-generic-math/log10l.c new file mode 100644 index 0000000..63dcc28 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log10l.c @@ -0,0 +1,191 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log10l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* + * Common logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log10l(); + * + * y = log10l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 10 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.0e-20 2.6e-20 + * IEEE exp(+-10000) 30000 6.0e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns MINLOG + * log domain: x < 0; returns MINLOG + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log10l(long double x) +{ + return log10(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log10(2) */ +#define L102A 0.3125L +#define L102B -1.1470004336018804786261e-2L +/* log10(e) */ +#define L10EA 0.5L +#define L10EB -6.5705518096748172348871e-2L + +#define SQRTH 0.70710678118654752440L + +long double log10l(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if(x <= 0.0) { + if(x == 0.0) + return -1.0 / (x*x); + return (x - x) / 0.0; + } + if (x == INFINITY) + return INFINITY; + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5*z; + +done: + /* Multiply log of fraction by log10(e) + * and base 2 exponent by log10(2). + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * (L10EB); + z += x * (L10EB); + z += e * (L102B); + z += y * (L10EA); + z += x * (L10EA); + z += e * (L102A); + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log10l(long double x) +{ + return log10(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log1p.c b/user/include/mlibc/options/ansi/musl-generic-math/log1p.c new file mode 100644 index 0000000..0097134 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log1p.c @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +#include "libm.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log1p(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t hx,hu; + int k; + + hx = u.i>>32; + k = 1; + if (hx < 0x3fda827a || hx>>31) { /* 1+x < sqrt(2)+ */ + if (hx >= 0xbff00000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0; /* log1p(-1) = -inf */ + return (x-x)/0.0; /* log1p(x<-1) = NaN */ + } + if (hx<<1 < 0x3ca00000<<1) { /* |x| < 2**-53 */ + /* underflow if subnormal */ + if ((hx&0x7ff00000) == 0) + FORCE_EVAL((float)x); + return x; + } + if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (hx >= 0x7ff00000) + return x; + if (k) { + u.f = 1 + x; + hu = u.i>>32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (int)(hu>>20) - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 54) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hu<<32 | (u.i&0xffffffff); + f = u.f - 1; + } + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log1pf.c b/user/include/mlibc/options/ansi/musl-generic-math/log1pf.c new file mode 100644 index 0000000..23985c3 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log1pf.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log1pf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t ix,iu; + int k; + + ix = u.i; + k = 1; + if (ix < 0x3ed413d0 || ix>>31) { /* 1+x < sqrt(2)+ */ + if (ix >= 0xbf800000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0f; /* log1p(-1)=+inf */ + return (x-x)/0.0f; /* log1p(x<-1)=NaN */ + } + if (ix<<1 < 0x33800000<<1) { /* |x| < 2**-24 */ + /* underflow if subnormal */ + if ((ix&0x7f800000) == 0) + FORCE_EVAL(x*x); + return x; + } + if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (ix >= 0x7f800000) + return x; + if (k) { + u.f = 1 + x; + iu = u.i; + iu += 0x3f800000 - 0x3f3504f3; + k = (int)(iu>>23) - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 25) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu&0x007fffff) + 0x3f3504f3; + u.i = iu; + f = u.f - 1; + } + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log1pl.c b/user/include/mlibc/options/ansi/musl-generic-math/log1pl.c new file mode 100644 index 0000000..141b5f0 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log1pl.c @@ -0,0 +1,177 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/s_log1pl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* + * Relative error logarithm + * Natural logarithm of 1+x, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log1pl(); + * + * y = log1pl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of 1+x. + * + * The argument 1+x is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z^3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log1pl(long double x) +{ + return log1p(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double log1pl(long double xm1) +{ + long double x, y, z; + int e; + + if (isnan(xm1)) + return xm1; + if (xm1 == INFINITY) + return xm1; + if (xm1 == 0.0) + return xm1; + + x = xm1 + 1.0; + + /* Test for domain errors. */ + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* Separate mantissa from exponent. + Use frexp so that denormal numbers will be handled properly. */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z^3 P(z)/Q(z), + where z = 2(x-1)/x+1) */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + if (e != 0) + x = 2.0 * x - 1.0; + else + x = xm1; + } else { + if (e != 0) + x = x - 1.0; + else + x = xm1; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5 * z; + z = z + x; + z = z + e * C1; + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log1pl(long double x) +{ + return log1p(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log2.c b/user/include/mlibc/options/ansi/musl-generic-math/log2.c new file mode 100644 index 0000000..0aafad4 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log2.c @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + +#include +#include + +static const double +ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ +ivln2lo = 1.67517131648865118353e-10, /* 0x3de705fc, 0x2eefa200 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log2(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + val_hi = hi*ivln2hi; + val_lo = (lo+hi)*ivln2lo + lo*ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k; + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log2f.c b/user/include/mlibc/options/ansi/musl-generic-math/log2f.c new file mode 100644 index 0000000..b3e305f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log2f.c @@ -0,0 +1,74 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + +#include +#include + +static const float +ivln2hi = 1.4428710938e+00, /* 0x3fb8b000 */ +ivln2lo = -1.7605285393e-04, /* 0xb9389ad4 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log2f(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,hi,lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + k; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/log2l.c b/user/include/mlibc/options/ansi/musl-generic-math/log2l.c new file mode 100644 index 0000000..722b451 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/log2l.c @@ -0,0 +1,182 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log2l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* + * Base 2 logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log2l(); + * + * y = log2l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 2 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the (natural) + * logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.8e-20 2.7e-20 + * IEEE exp(+-10000) 70000 5.4e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log2l(long double x) +{ + return log2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log2(e) - 1 */ +#define LOG2EA 4.4269504088896340735992e-1L + +#define SQRTH 0.70710678118654752440L + +long double log2l(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if (x == INFINITY) + return x; + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5*z; + +done: + /* Multiply log of fraction by log2(e) + * and base 2 exponent by 1 + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * LOG2EA; + z += x * LOG2EA; + z += y; + z += x; + z += e; + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log2l(long double x) +{ + return log2(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/logb.c b/user/include/mlibc/options/ansi/musl-generic-math/logb.c new file mode 100644 index 0000000..7f8bdfa --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/logb.c @@ -0,0 +1,17 @@ +#include + +/* +special cases: + logb(+-0) = -inf, and raise divbyzero + logb(+-inf) = +inf + logb(nan) = nan +*/ + +double logb(double x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogb(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/logbf.c b/user/include/mlibc/options/ansi/musl-generic-math/logbf.c new file mode 100644 index 0000000..a0a0b5e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/logbf.c @@ -0,0 +1,10 @@ +#include + +float logbf(float x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogbf(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/logbl.c b/user/include/mlibc/options/ansi/musl-generic-math/logbl.c new file mode 100644 index 0000000..962973a --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/logbl.c @@ -0,0 +1,16 @@ +#include +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logbl(long double x) +{ + return logb(x); +} +#else +long double logbl(long double x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogbl(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/logf.c b/user/include/mlibc/options/ansi/musl-generic-math/logf.c new file mode 100644 index 0000000..52230a1 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/logf.c @@ -0,0 +1,69 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float logf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,dk; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/logl.c b/user/include/mlibc/options/ansi/musl-generic-math/logl.c new file mode 100644 index 0000000..5d53659 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/logl.c @@ -0,0 +1,175 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_logl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* + * Natural logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, logl(); + * + * y = logl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/(x+1), + * + * log(x) = log(1+z/2) - log(1-z/2) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 150000 8.71e-20 2.75e-20 + * IEEE exp(+-10000) 100000 5.39e-20 2.34e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logl(long double x) +{ + return log(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double logl(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if (x == INFINITY) + return x; + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/(x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5*z; + /* Note, the sum of above terms does not exceed x/4, + * so it contributes at most about 1/4 lsb to the error. + */ + z = z + x; + z = z + e * C1; /* This sum has an error of 1/2 lsb. */ + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double logl(long double x) +{ + return log(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lrint.c b/user/include/mlibc/options/ansi/musl-generic-math/lrint.c new file mode 100644 index 0000000..bdca8b7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lrint.c @@ -0,0 +1,46 @@ +#include +#include +#include "libm.h" + +/* +If the result cannot be represented (overflow, nan), then +lrint raises the invalid exception. + +Otherwise if the input was not an integer then the inexact +exception is raised. + +C99 is a bit vague about whether inexact exception is +allowed to be raised when invalid is raised. +(F.9 explicitly allows spurious inexact exceptions, F.9.6.5 +does not make it clear if that rule applies to lrint, but +IEEE 754r 7.8 seems to forbid spurious inexact exception in +the ineger conversion functions) + +So we try to make sure that no spurious inexact exception is +raised in case of an overflow. + +If the bit size of long > precision of double, then there +cannot be inexact rounding in case the result overflows, +otherwise LONG_MAX and LONG_MIN can be represented exactly +as a double. +*/ + +#if LONG_MAX < 1U<<53 && defined(FE_INEXACT) +long lrint(double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rint(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrint(double x) +{ + return rint(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lrintf.c b/user/include/mlibc/options/ansi/musl-generic-math/lrintf.c new file mode 100644 index 0000000..ca0b6a4 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lrintf.c @@ -0,0 +1,8 @@ +#include + +/* uses LONG_MAX > 2^24, see comments in lrint.c */ + +long lrintf(float x) +{ + return rintf(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lrintl.c b/user/include/mlibc/options/ansi/musl-generic-math/lrintl.c new file mode 100644 index 0000000..b2a8106 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lrintl.c @@ -0,0 +1,36 @@ +#include +#include +#include "libm.h" + + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long lrintl(long double x) +{ + return lrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long lrintl(long double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrintl(long double x) +{ + return rintl(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lround.c b/user/include/mlibc/options/ansi/musl-generic-math/lround.c new file mode 100644 index 0000000..b8b7954 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lround.c @@ -0,0 +1,6 @@ +#include + +long lround(double x) +{ + return round(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lroundf.c b/user/include/mlibc/options/ansi/musl-generic-math/lroundf.c new file mode 100644 index 0000000..c4707e7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lroundf.c @@ -0,0 +1,6 @@ +#include + +long lroundf(float x) +{ + return roundf(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/lroundl.c b/user/include/mlibc/options/ansi/musl-generic-math/lroundl.c new file mode 100644 index 0000000..094fdf6 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/lroundl.c @@ -0,0 +1,6 @@ +#include + +long lroundl(long double x) +{ + return roundl(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/modf.c b/user/include/mlibc/options/ansi/musl-generic-math/modf.c new file mode 100644 index 0000000..1c8a1db --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/modf.c @@ -0,0 +1,34 @@ +#include "libm.h" + +double modf(double x, double *iptr) +{ + union {double f; uint64_t i;} u = {x}; + uint64_t mask; + int e = (int)(u.i>>52 & 0x7ff) - 0x3ff; + + /* no fractional part */ + if (e >= 52) { + *iptr = x; + if (e == 0x400 && u.i<<12 != 0) /* nan */ + return x; + u.i &= 1ULL<<63; + return u.f; + } + + /* no integral part*/ + if (e < 0) { + u.i &= 1ULL<<63; + *iptr = u.f; + return x; + } + + mask = -1ULL>>12>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 1ULL<<63; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/modff.c b/user/include/mlibc/options/ansi/musl-generic-math/modff.c new file mode 100644 index 0000000..639514e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/modff.c @@ -0,0 +1,34 @@ +#include "libm.h" + +float modff(float x, float *iptr) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t mask; + int e = (int)(u.i>>23 & 0xff) - 0x7f; + + /* no fractional part */ + if (e >= 23) { + *iptr = x; + if (e == 0x80 && u.i<<9 != 0) { /* nan */ + return x; + } + u.i &= 0x80000000; + return u.f; + } + /* no integral part */ + if (e < 0) { + u.i &= 0x80000000; + *iptr = u.f; + return x; + } + + mask = 0x007fffff>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 0x80000000; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/modfl.c b/user/include/mlibc/options/ansi/musl-generic-math/modfl.c new file mode 100644 index 0000000..a47b192 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/modfl.c @@ -0,0 +1,53 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double modfl(long double x, long double *iptr) +{ + double d; + long double r; + + r = modf(x, &d); + *iptr = d; + return r; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double modfl(long double x, long double *iptr) +{ + union ldshape u = {x}; + int e = (u.i.se & 0x7fff) - 0x3fff; + int s = u.i.se >> 15; + long double absx; + long double y; + + /* no fractional part */ + if (e >= LDBL_MANT_DIG-1) { + *iptr = x; + if (isnan(x)) + return x; + return s ? -0.0 : 0.0; + } + + /* no integral part*/ + if (e < 0) { + *iptr = s ? -0.0 : 0.0; + return x; + } + + /* raises spurious inexact */ + absx = s ? -x : x; + y = absx + toint - toint - absx; + if (y == 0) { + *iptr = x; + return s ? -0.0 : 0.0; + } + if (y > 0) + y -= 1; + if (s) + y = -y; + *iptr = x + y; + return -y; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nan.c b/user/include/mlibc/options/ansi/musl-generic-math/nan.c new file mode 100644 index 0000000..9e0826c --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nan.c @@ -0,0 +1,6 @@ +#include + +double nan(const char *s) +{ + return NAN; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nanf.c b/user/include/mlibc/options/ansi/musl-generic-math/nanf.c new file mode 100644 index 0000000..752ce54 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nanf.c @@ -0,0 +1,6 @@ +#include + +float nanf(const char *s) +{ + return NAN; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nanl.c b/user/include/mlibc/options/ansi/musl-generic-math/nanl.c new file mode 100644 index 0000000..969af56 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nanl.c @@ -0,0 +1,6 @@ +#include + +long double nanl(const char *s) +{ + return NAN; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nearbyint.c b/user/include/mlibc/options/ansi/musl-generic-math/nearbyint.c new file mode 100644 index 0000000..f4e8aac --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nearbyint.c @@ -0,0 +1,20 @@ +#include +#include + +/* nearbyint is the same as rint, but it must not raise the inexact exception */ + +double nearbyint(double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rint(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nearbyintf.c b/user/include/mlibc/options/ansi/musl-generic-math/nearbyintf.c new file mode 100644 index 0000000..092e9ff --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nearbyintf.c @@ -0,0 +1,18 @@ +#include +#include + +float nearbyintf(float x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintf(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nearbyintl.c b/user/include/mlibc/options/ansi/musl-generic-math/nearbyintl.c new file mode 100644 index 0000000..8285249 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nearbyintl.c @@ -0,0 +1,26 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nearbyintl(long double x) +{ + return nearbyint(x); +} +#else +#include +long double nearbyintl(long double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintl(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nextafter.c b/user/include/mlibc/options/ansi/musl-generic-math/nextafter.c new file mode 100644 index 0000000..ab5795a --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nextafter.c @@ -0,0 +1,31 @@ +#include "libm.h" + +double nextafter(double x, double y) +{ + union {double f; uint64_t i;} ux={x}, uy={y}; + uint64_t ax, ay; + int e; + + if (isnan(x) || isnan(y)) + return x + y; + if (ux.i == uy.i) + return y; + ax = ux.i & -1ULL/2; + ay = uy.i & -1ULL/2; + if (ax == 0) { + if (ay == 0) + return y; + ux.i = (uy.i & 1ULL<<63) | 1; + } else if (ax > ay || ((ux.i ^ uy.i) & 1ULL<<63)) + ux.i--; + else + ux.i++; + e = ux.i >> 52 & 0x7ff; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7ff) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nextafterf.c b/user/include/mlibc/options/ansi/musl-generic-math/nextafterf.c new file mode 100644 index 0000000..75a09f7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nextafterf.c @@ -0,0 +1,30 @@ +#include "libm.h" + +float nextafterf(float x, float y) +{ + union {float f; uint32_t i;} ux={x}, uy={y}; + uint32_t ax, ay, e; + + if (isnan(x) || isnan(y)) + return x + y; + if (ux.i == uy.i) + return y; + ax = ux.i & 0x7fffffff; + ay = uy.i & 0x7fffffff; + if (ax == 0) { + if (ay == 0) + return y; + ux.i = (uy.i & 0x80000000) | 1; + } else if (ax > ay || ((ux.i ^ uy.i) & 0x80000000)) + ux.i--; + else + ux.i++; + e = ux.i & 0x7f800000; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7f800000) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nextafterl.c b/user/include/mlibc/options/ansi/musl-generic-math/nextafterl.c new file mode 100644 index 0000000..37e858f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nextafterl.c @@ -0,0 +1,75 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nextafterl(long double x, long double y) +{ + return nextafter(x, y); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double nextafterl(long double x, long double y) +{ + union ldshape ux, uy; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + ux.f = x; + if (x == 0) { + uy.f = y; + ux.i.m = 1; + ux.i.se = uy.i.se & 0x8000; + } else if ((x < y) == !(ux.i.se & 0x8000)) { + ux.i.m++; + if (ux.i.m << 1 == 0) { + ux.i.m = 1ULL << 63; + ux.i.se++; + } + } else { + if (ux.i.m << 1 == 0) { + ux.i.se--; + if (ux.i.se) + ux.i.m = 0; + } + ux.i.m--; + } + /* raise overflow if ux is infinite and x is finite */ + if ((ux.i.se & 0x7fff) == 0x7fff) + return x + x; + /* raise underflow if ux is subnormal or zero */ + if ((ux.i.se & 0x7fff) == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +long double nextafterl(long double x, long double y) +{ + union ldshape ux, uy; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + ux.f = x; + if (x == 0) { + uy.f = y; + ux.i.lo = 1; + ux.i.se = uy.i.se & 0x8000; + } else if ((x < y) == !(ux.i.se & 0x8000)) { + ux.i2.lo++; + if (ux.i2.lo == 0) + ux.i2.hi++; + } else { + if (ux.i2.lo == 0) + ux.i2.hi--; + ux.i2.lo--; + } + /* raise overflow if ux is infinite and x is finite */ + if ((ux.i.se & 0x7fff) == 0x7fff) + return x + x; + /* raise underflow if ux is subnormal or zero */ + if ((ux.i.se & 0x7fff) == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nexttoward.c b/user/include/mlibc/options/ansi/musl-generic-math/nexttoward.c new file mode 100644 index 0000000..827ee5c --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nexttoward.c @@ -0,0 +1,42 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +double nexttoward(double x, long double y) +{ + return nextafter(x, y); +} +#else +double nexttoward(double x, long double y) +{ + union {double f; uint64_t i;} ux = {x}; + int e; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + if (x == 0) { + ux.i = 1; + if (signbit(y)) + ux.i |= 1ULL<<63; + } else if (x < y) { + if (signbit(x)) + ux.i--; + else + ux.i++; + } else { + if (signbit(x)) + ux.i++; + else + ux.i--; + } + e = ux.i>>52 & 0x7ff; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7ff) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nexttowardf.c b/user/include/mlibc/options/ansi/musl-generic-math/nexttowardf.c new file mode 100644 index 0000000..bbf172f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nexttowardf.c @@ -0,0 +1,35 @@ +#include "libm.h" + +float nexttowardf(float x, long double y) +{ + union {float f; uint32_t i;} ux = {x}; + uint32_t e; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + if (x == 0) { + ux.i = 1; + if (signbit(y)) + ux.i |= 0x80000000; + } else if (x < y) { + if (signbit(x)) + ux.i--; + else + ux.i++; + } else { + if (signbit(x)) + ux.i++; + else + ux.i--; + } + e = ux.i & 0x7f800000; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7f800000) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/nexttowardl.c b/user/include/mlibc/options/ansi/musl-generic-math/nexttowardl.c new file mode 100644 index 0000000..67a6340 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/nexttowardl.c @@ -0,0 +1,6 @@ +#include + +long double nexttowardl(long double x, long double y) +{ + return nextafterl(x, y); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/pow.c b/user/include/mlibc/options/ansi/musl-generic-math/pow.c new file mode 100644 index 0000000..6cc4b58 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/pow.c @@ -0,0 +1,328 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. 1 ** (anything) is 1 + * 3. (anything except 1) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. -1 ** +-INF is 1 + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + * 14. -0 ** (+odd integer) is -0 + * 15. -0 ** (-odd integer) is -INF, raise divbyzero + * 16. +INF ** (+anything except 0,NAN) is +INF + * 17. +INF ** (-anything except 0,NAN) is +0 + * 18. -INF ** (+odd integer) is -INF + * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + * 20. (anything) ** 1 is (anything) + * 21. (anything) ** -1 is 1/(anything) + * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 23. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, +/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +double pow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy; + uint32_t lx,ly; + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if ((iy|ly) == 0) + return 1.0; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3ff00000 && lx == 0) + return 1.0; + /* NaN if either arg is NaN */ + if (ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || + iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0)) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x43400000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3ff00000) { + k = (iy>>20) - 0x3ff; /* exponent */ + if (k > 20) { + uint32_t j = ly>>(52-k); + if ((j<<(52-k)) == ly) + yisint = 2 - (j&1); + } else if (ly == 0) { + uint32_t j = iy>>(20-k); + if ((j<<(20-k)) == iy) + yisint = 2 - (j&1); + } + } + } + + /* special value of y */ + if (ly == 0) { + if (iy == 0x7ff00000) { /* y is +-inf */ + if (((ix-0x3ff00000)|lx) == 0) /* (-1)**+-inf is 1 */ + return 1.0; + else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0; + else /* (|x|<1)**+-inf = 0,inf */ + return hy >= 0 ? 0.0 : -y; + } + if (iy == 0x3ff00000) { /* y is +-1 */ + if (hy >= 0) + return x; + y = 1/x; +#if FLT_EVAL_METHOD!=0 + { + union {double f; uint64_t i;} u = {y}; + uint64_t i = u.i & -1ULL/2; + if (i>>52 == 0 && (i&(i-1))) + FORCE_EVAL((float)y); + } +#endif + return y; + } + if (hy == 0x40000000) /* y is 2 */ + return x*x; + if (hy == 0x3fe00000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if (lx == 0) { + if (ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0/z; + if (hx < 0) { + if (((ix-0x3ff00000)|yisint) == 0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + s = 1.0; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + s = -1.0; + } + + /* |y| is huge */ + if (iy > 0x41e00000) { /* if |y| > 2**31 */ + if (iy > 0x43f00000) { /* if |y| > 2**64, must o/uflow */ + if (ix <= 0x3fefffff) + return hy < 0 ? huge*huge : tiny*tiny; + if (ix >= 0x3ff00000) + return hy > 0 ? huge*huge : tiny*tiny; + } + /* over/underflow if x is not close to one */ + if (ix < 0x3fefffff) + return hy < 0 ? s*huge*huge : s*tiny*tiny; + if (ix > 0x3ff00000) + return hy > 0 ? s*huge*huge : s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.0; /* t has 20 trailing zeros */ + w = (t*t)*(0.5 - t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l - w*ivln2; + t1 = u + v; + SET_LOW_WORD(t1, 0); + t2 = v - (t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00100000) { + ax *= two53; + n -= 53; + GET_HIGH_WORD(ix,ax); + } + n += ((ix)>>20) - 0x3ff; + j = ix & 0x000fffff; + /* determine interval */ + ix = j | 0x3ff00000; /* normalize ix */ + if (j <= 0x3988E) /* |x|>1)|0x20000000) + 0x00080000 + (k<<18)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0 + s2 + r; + SET_LOW_WORD(t_h, 0); + t_l = r - ((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h + t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u + v; + SET_LOW_WORD(p_h, 0); + p_l = v - (p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp + dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = ((z_h + z_l) + dp_h[k]) + t; + SET_LOW_WORD(t1, 0); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1, 0); + p_l = (y-y1)*t1 + y*t2; + p_h = y1*t1; + z = p_l + p_h; + EXTRACT_WORDS(j, i, z); + if (j >= 0x40900000) { /* z >= 1024 */ + if (((j-0x40900000)|i) != 0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + if (p_l + ovt > z - p_h) + return s*huge*huge; /* overflow */ + } else if ((j&0x7fffffff) >= 0x4090cc00) { /* z <= -1075 */ // FIXME: instead of abs(j) use unsigned j + if (((j-0xc090cc00)|i) != 0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + if (p_l <= z - p_h) + return s*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i>>20) - 0x3ff; + n = 0; + if (i > 0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20) - 0x3ff; /* new k for n */ + t = 0.0; + SET_HIGH_WORD(t, n & ~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if (j < 0) + n = -n; + p_h -= t; + } + t = p_l + p_h; + SET_LOW_WORD(t, 0); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2 + t*lg2_l; + z = u + v; + w = v - (z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-2.0) - (w + z*w); + z = 1.0 - (r-z); + GET_HIGH_WORD(j, z); + j += (int32_t) ((uint32_t)n<<20); + if ((j>>20) <= 0) /* subnormal output */ + z = scalbn(z,n); + else + SET_HIGH_WORD(z, j); + return s*z; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/powf.c b/user/include/mlibc/options/ansi/musl-generic-math/powf.c new file mode 100644 index 0000000..427c896 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/powf.c @@ -0,0 +1,259 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ +dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ +two24 = 16777216.0, /* 0x4b800000 */ +huge = 1.0e30, +tiny = 1.0e-30, +/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 6.0000002384e-01, /* 0x3f19999a */ +L2 = 4.2857143283e-01, /* 0x3edb6db7 */ +L3 = 3.3333334327e-01, /* 0x3eaaaaab */ +L4 = 2.7272811532e-01, /* 0x3e8ba305 */ +L5 = 2.3066075146e-01, /* 0x3e6c3255 */ +L6 = 2.0697501302e-01, /* 0x3e53f142 */ +P1 = 1.6666667163e-01, /* 0x3e2aaaab */ +P2 = -2.7777778450e-03, /* 0xbb360b61 */ +P3 = 6.6137559770e-05, /* 0x388ab355 */ +P4 = -1.6533901999e-06, /* 0xb5ddea0e */ +P5 = 4.1381369442e-08, /* 0x3331bb4c */ +lg2 = 6.9314718246e-01, /* 0x3f317218 */ +lg2_h = 6.93145752e-01, /* 0x3f317200 */ +lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ +ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ +cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ +cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */ +cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */ +ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ +ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ +ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +float powf(float x, float y) +{ + float z,ax,z_h,z_l,p_h,p_l; + float y1,t1,t2,r,s,sn,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy,is; + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if (iy == 0) + return 1.0f; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3f800000) + return 1.0f; + /* NaN if either arg is NaN */ + if (ix > 0x7f800000 || iy > 0x7f800000) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x4b800000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3f800000) { + k = (iy>>23) - 0x7f; /* exponent */ + j = iy>>(23-k); + if ((j<<(23-k)) == iy) + yisint = 2 - (j & 1); + } + } + + /* special value of y */ + if (iy == 0x7f800000) { /* y is +-inf */ + if (ix == 0x3f800000) /* (-1)**+-inf is 1 */ + return 1.0f; + else if (ix > 0x3f800000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0f; + else /* (|x|<1)**+-inf = 0,inf */ + return hy >= 0 ? 0.0f: -y; + } + if (iy == 0x3f800000) /* y is +-1 */ + return hy >= 0 ? x : 1.0f/x; + if (hy == 0x40000000) /* y is 2 */ + return x*x; + if (hy == 0x3f000000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if (ix == 0x7f800000 || ix == 0 || ix == 0x3f800000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0f/z; + if (hx < 0) { + if (((ix-0x3f800000)|yisint) == 0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + + sn = 1.0f; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + sn = -1.0f; + } + + /* |y| is huge */ + if (iy > 0x4d000000) { /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if (ix < 0x3f7ffff8) + return hy < 0 ? sn*huge*huge : sn*tiny*tiny; + if (ix > 0x3f800007) + return hy > 0 ? sn*huge*huge : sn*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1; /* t has 20 trailing zeros */ + w = (t*t)*(0.5f - t*(0.333333333333f - t*0.25f)); + u = ivln2_h*t; /* ivln2_h has 16 sig. bits */ + v = t*ivln2_l - w*ivln2; + t1 = u + v; + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = v - (t1-u); + } else { + float s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00800000) { + ax *= two24; + n -= 24; + GET_FLOAT_WORD(ix, ax); + } + n += ((ix)>>23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if (j <= 0x1cc471) /* |x|>1) & 0xfffff000) | 0x20000000; + SET_FLOAT_WORD(t_h, is + 0x00400000 + (k<<21)); + t_l = ax - (t_h - bp[k]); + s_l = v*((u - s_h*t_h) - s_h*t_l); + /* compute log(ax) */ + s2 = s*s; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+s); + s2 = s_h*s_h; + t_h = 3.0f + s2 + r; + GET_FLOAT_WORD(is, t_h); + SET_FLOAT_WORD(t_h, is & 0xfffff000); + t_l = r - ((t_h - 3.0f) - s2); + /* u+v = s*(1+...) */ + u = s_h*t_h; + v = s_l*t_h + t_l*s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + GET_FLOAT_WORD(is, p_h); + SET_FLOAT_WORD(p_h, is & 0xfffff000); + p_l = v - (p_h - u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h + p_l*cp+dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (float)n; + t1 = (((z_h + z_l) + dp_h[k]) + t); + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + GET_FLOAT_WORD(is, y); + SET_FLOAT_WORD(y1, is & 0xfffff000); + p_l = (y-y1)*t1 + y*t2; + p_h = y1*t1; + z = p_l + p_h; + GET_FLOAT_WORD(j, z); + if (j > 0x43000000) /* if z > 128 */ + return sn*huge*huge; /* overflow */ + else if (j == 0x43000000) { /* if z == 128 */ + if (p_l + ovt > z - p_h) + return sn*huge*huge; /* overflow */ + } else if ((j&0x7fffffff) > 0x43160000) /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn*tiny*tiny; /* underflow */ + else if (j == 0xc3160000) { /* z == -150 */ + if (p_l <= z-p_h) + return sn*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i>>23) - 0x7f; + n = 0; + if (i > 0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000>>(k+1)); + k = ((n&0x7fffffff)>>23) - 0x7f; /* new k for n */ + SET_FLOAT_WORD(t, n & ~(0x007fffff>>k)); + n = ((n&0x007fffff)|0x00800000)>>(23-k); + if (j < 0) + n = -n; + p_h -= t; + } + t = p_l + p_h; + GET_FLOAT_WORD(is, t); + SET_FLOAT_WORD(t, is & 0xffff8000); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2 + t*lg2_l; + z = u + v; + w = v - (z - u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-2.0f) - (w+z*w); + z = 1.0f - (r - z); + GET_FLOAT_WORD(j, z); + j += n<<23; + if ((j>>23) <= 0) /* subnormal output */ + z = scalbnf(z, n); + else + SET_FLOAT_WORD(z, j); + return sn*z; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/powl.c b/user/include/mlibc/options/ansi/musl-generic-math/powl.c new file mode 100644 index 0000000..5b6da07 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/powl.c @@ -0,0 +1,522 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_powl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* powl.c + * + * Power function, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, z, powl(); + * + * z = powl( x, y ); + * + * + * DESCRIPTION: + * + * Computes x raised to the yth power. Analytically, + * + * x**y = exp( y log(x) ). + * + * Following Cody and Waite, this program uses a lookup table + * of 2**-i/32 and pseudo extended precision arithmetic to + * obtain several extra bits of accuracy in both the logarithm + * and the exponential. + * + * + * ACCURACY: + * + * The relative error of pow(x,y) can be estimated + * by y dl ln(2), where dl is the absolute error of + * the internally computed base 2 logarithm. At the ends + * of the approximation interval the logarithm equal 1/32 + * and its relative error is about 1 lsb = 1.1e-19. Hence + * the predicted relative error in the result is 2.3e-21 y . + * + * Relative error: + * arithmetic domain # trials peak rms + * + * IEEE +-1000 40000 2.8e-18 3.7e-19 + * .001 < x < 1000, with log(x) uniformly distributed. + * -1000 < y < 1000, y uniformly distributed. + * + * IEEE 0,8700 60000 6.5e-18 1.0e-18 + * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * pow overflow x**y > MAXNUM INFINITY + * pow underflow x**y < 1/MAXNUM 0.0 + * pow domain x<0 and y noninteger 0.0 + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double powl(long double x, long double y) +{ + return pow(x, y); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* Table size */ +#define NXT 32 + +/* log(1+x) = x - .5x^2 + x^3 * P(z)/Q(z) + * on the domain 2^(-1/32) - 1 <= x <= 2^(1/32) - 1 + */ +static const long double P[] = { + 8.3319510773868690346226E-4L, + 4.9000050881978028599627E-1L, + 1.7500123722550302671919E0L, + 1.4000100839971580279335E0L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0L,*/ + 5.2500282295834889175431E0L, + 8.4000598057587009834666E0L, + 4.2000302519914740834728E0L, +}; +/* A[i] = 2^(-i/32), rounded to IEEE long double precision. + * If i is even, A[i] + B[i/2] gives additional accuracy. + */ +static const long double A[33] = { + 1.0000000000000000000000E0L, + 9.7857206208770013448287E-1L, + 9.5760328069857364691013E-1L, + 9.3708381705514995065011E-1L, + 9.1700404320467123175367E-1L, + 8.9735453750155359320742E-1L, + 8.7812608018664974155474E-1L, + 8.5930964906123895780165E-1L, + 8.4089641525371454301892E-1L, + 8.2287773907698242225554E-1L, + 8.0524516597462715409607E-1L, + 7.8799042255394324325455E-1L, + 7.7110541270397041179298E-1L, + 7.5458221379671136985669E-1L, + 7.3841307296974965571198E-1L, + 7.2259040348852331001267E-1L, + 7.0710678118654752438189E-1L, + 6.9195494098191597746178E-1L, + 6.7712777346844636413344E-1L, + 6.6261832157987064729696E-1L, + 6.4841977732550483296079E-1L, + 6.3452547859586661129850E-1L, + 6.2092890603674202431705E-1L, + 6.0762367999023443907803E-1L, + 5.9460355750136053334378E-1L, + 5.8186242938878875689693E-1L, + 5.6939431737834582684856E-1L, + 5.5719337129794626814472E-1L, + 5.4525386633262882960438E-1L, + 5.3357020033841180906486E-1L, + 5.2213689121370692017331E-1L, + 5.1094857432705833910408E-1L, + 5.0000000000000000000000E-1L, +}; +static const long double B[17] = { + 0.0000000000000000000000E0L, + 2.6176170809902549338711E-20L, +-1.0126791927256478897086E-20L, + 1.3438228172316276937655E-21L, + 1.2207982955417546912101E-20L, +-6.3084814358060867200133E-21L, + 1.3164426894366316434230E-20L, +-1.8527916071632873716786E-20L, + 1.8950325588932570796551E-20L, + 1.5564775779538780478155E-20L, + 6.0859793637556860974380E-21L, +-2.0208749253662532228949E-20L, + 1.4966292219224761844552E-20L, + 3.3540909728056476875639E-21L, +-8.6987564101742849540743E-22L, +-1.2327176863327626135542E-20L, + 0.0000000000000000000000E0L, +}; + +/* 2^x = 1 + x P(x), + * on the interval -1/32 <= x <= 0 + */ +static const long double R[] = { + 1.5089970579127659901157E-5L, + 1.5402715328927013076125E-4L, + 1.3333556028915671091390E-3L, + 9.6181291046036762031786E-3L, + 5.5504108664798463044015E-2L, + 2.4022650695910062854352E-1L, + 6.9314718055994530931447E-1L, +}; + +#define MEXP (NXT*16384.0L) +/* The following if denormal numbers are supported, else -MEXP: */ +#define MNEXP (-NXT*(16384.0L+64.0L)) +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340735992L + +#define F W +#define Fa Wa +#define Fb Wb +#define G W +#define Ga Wa +#define Gb u +#define H W +#define Ha Wb +#define Hb Wb + +static const long double MAXLOGL = 1.1356523406294143949492E4L; +static const long double MINLOGL = -1.13994985314888605586758E4L; +static const long double LOGE2L = 6.9314718055994530941723E-1L; +static const long double huge = 0x1p10000L; +/* XXX Prevent gcc from erroneously constant folding this. */ +static const volatile long double twom10000 = 0x1p-10000L; + +static long double reducl(long double); +static long double powil(long double, int); + +long double powl(long double x, long double y) +{ + /* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */ + int i, nflg, iyflg, yoddint; + long e; + volatile long double z=0; + long double w=0, W=0, Wa=0, Wb=0, ya=0, yb=0, u=0; + + /* make sure no invalid exception is raised by nan comparision */ + if (isnan(x)) { + if (!isnan(y) && y == 0.0) + return 1.0; + return x; + } + if (isnan(y)) { + if (x == 1.0) + return 1.0; + return y; + } + if (x == 1.0) + return 1.0; /* 1**y = 1, even if y is nan */ + if (x == -1.0 && !isfinite(y)) + return 1.0; /* -1**inf = 1 */ + if (y == 0.0) + return 1.0; /* x**0 = 1, even if x is nan */ + if (y == 1.0) + return x; + if (y >= LDBL_MAX) { + if (x > 1.0 || x < -1.0) + return INFINITY; + if (x != 0.0) + return 0.0; + } + if (y <= -LDBL_MAX) { + if (x > 1.0 || x < -1.0) + return 0.0; + if (x != 0.0 || y == -INFINITY) + return INFINITY; + } + if (x >= LDBL_MAX) { + if (y > 0.0) + return INFINITY; + return 0.0; + } + + w = floorl(y); + + /* Set iyflg to 1 if y is an integer. */ + iyflg = 0; + if (w == y) + iyflg = 1; + + /* Test for odd integer y. */ + yoddint = 0; + if (iyflg) { + ya = fabsl(y); + ya = floorl(0.5 * ya); + yb = 0.5 * fabsl(w); + if( ya != yb ) + yoddint = 1; + } + + if (x <= -LDBL_MAX) { + if (y > 0.0) { + if (yoddint) + return -INFINITY; + return INFINITY; + } + if (y < 0.0) { + if (yoddint) + return -0.0; + return 0.0; + } + } + nflg = 0; /* (x<0)**(odd int) */ + if (x <= 0.0) { + if (x == 0.0) { + if (y < 0.0) { + if (signbit(x) && yoddint) + /* (-0.0)**(-odd int) = -inf, divbyzero */ + return -1.0/0.0; + /* (+-0.0)**(negative) = inf, divbyzero */ + return 1.0/0.0; + } + if (signbit(x) && yoddint) + return -0.0; + return 0.0; + } + if (iyflg == 0) + return (x - x) / (x - x); /* (x<0)**(non-int) is NaN */ + /* (x<0)**(integer) */ + if (yoddint) + nflg = 1; /* negate result */ + x = -x; + } + /* (+integer)**(integer) */ + if (iyflg && floorl(x) == x && fabsl(y) < 32768.0) { + w = powil(x, (int)y); + return nflg ? -w : w; + } + + /* separate significand from exponent */ + x = frexpl(x, &i); + e = i; + + /* find significand in antilog table A[] */ + i = 1; + if (x <= A[17]) + i = 17; + if (x <= A[i+8]) + i += 8; + if (x <= A[i+4]) + i += 4; + if (x <= A[i+2]) + i += 2; + if (x >= A[1]) + i = -1; + i += 1; + + /* Find (x - A[i])/A[i] + * in order to compute log(x/A[i]): + * + * log(x) = log( a x/a ) = log(a) + log(x/a) + * + * log(x/a) = log(1+v), v = x/a - 1 = (x-a)/a + */ + x -= A[i]; + x -= B[i/2]; + x /= A[i]; + + /* rational approximation for log(1+v): + * + * log(1+v) = v - v**2/2 + v**3 P(v) / Q(v) + */ + z = x*x; + w = x * (z * __polevll(x, P, 3) / __p1evll(x, Q, 3)); + w = w - 0.5*z; + + /* Convert to base 2 logarithm: + * multiply by log2(e) = 1 + LOG2EA + */ + z = LOG2EA * w; + z += w; + z += LOG2EA * x; + z += x; + + /* Compute exponent term of the base 2 logarithm. */ + w = -i; + w /= NXT; + w += e; + /* Now base 2 log of x is w + z. */ + + /* Multiply base 2 log by y, in extended precision. */ + + /* separate y into large part ya + * and small part yb less than 1/NXT + */ + ya = reducl(y); + yb = y - ya; + + /* (w+z)(ya+yb) + * = w*ya + w*yb + z*y + */ + F = z * y + w * yb; + Fa = reducl(F); + Fb = F - Fa; + + G = Fa + w * ya; + Ga = reducl(G); + Gb = G - Ga; + + H = Fb + Gb; + Ha = reducl(H); + w = (Ga + Ha) * NXT; + + /* Test the power of 2 for overflow */ + if (w > MEXP) + return huge * huge; /* overflow */ + if (w < MNEXP) + return twom10000 * twom10000; /* underflow */ + + e = w; + Hb = H - Ha; + + if (Hb > 0.0) { + e += 1; + Hb -= 1.0/NXT; /*0.0625L;*/ + } + + /* Now the product y * log2(x) = Hb + e/NXT. + * + * Compute base 2 exponential of Hb, + * where -0.0625 <= Hb <= 0. + */ + z = Hb * __polevll(Hb, R, 6); /* z = 2**Hb - 1 */ + + /* Express e/NXT as an integer plus a negative number of (1/NXT)ths. + * Find lookup table entry for the fractional power of 2. + */ + if (e < 0) + i = 0; + else + i = 1; + i = e/NXT + i; + e = NXT*i - e; + w = A[e]; + z = w * z; /* 2**-e * ( 1 + (2**Hb-1) ) */ + z = z + w; + z = scalbnl(z, i); /* multiply by integer power of 2 */ + + if (nflg) + z = -z; + return z; +} + + +/* Find a multiple of 1/NXT that is within 1/NXT of x. */ +static long double reducl(long double x) +{ + long double t; + + t = x * NXT; + t = floorl(t); + t = t / NXT; + return t; +} + +/* + * Positive real raised to integer power, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, powil(); + * int n; + * + * y = powil( x, n ); + * + * + * DESCRIPTION: + * + * Returns argument x>0 raised to the nth power. + * The routine efficiently decomposes n as a sum of powers of + * two. The desired power is a product of two-to-the-kth + * powers of x. Thus to compute the 32767 power of x requires + * 28 multiplications instead of 32767 multiplications. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic x domain n domain # trials peak rms + * IEEE .001,1000 -1022,1023 50000 4.3e-17 7.8e-18 + * IEEE 1,2 -1022,1023 20000 3.9e-17 7.6e-18 + * IEEE .99,1.01 0,8700 10000 3.6e-16 7.2e-17 + * + * Returns MAXNUM on overflow, zero on underflow. + */ + +static long double powil(long double x, int nn) +{ + long double ww, y; + long double s; + int n, e, sign, lx; + + if (nn == 0) + return 1.0; + + if (nn < 0) { + sign = -1; + n = -nn; + } else { + sign = 1; + n = nn; + } + + /* Overflow detection */ + + /* Calculate approximate logarithm of answer */ + s = x; + s = frexpl( s, &lx); + e = (lx - 1)*n; + if ((e == 0) || (e > 64) || (e < -64)) { + s = (s - 7.0710678118654752e-1L) / (s + 7.0710678118654752e-1L); + s = (2.9142135623730950L * s - 0.5 + lx) * nn * LOGE2L; + } else { + s = LOGE2L * e; + } + + if (s > MAXLOGL) + return huge * huge; /* overflow */ + + if (s < MINLOGL) + return twom10000 * twom10000; /* underflow */ + /* Handle tiny denormal answer, but with less accuracy + * since roundoff error in 1.0/x will be amplified. + * The precise demarcation should be the gradual underflow threshold. + */ + if (s < -MAXLOGL+2.0) { + x = 1.0/x; + sign = -sign; + } + + /* First bit of the power */ + if (n & 1) + y = x; + else + y = 1.0; + + ww = x; + n >>= 1; + while (n) { + ww = ww * ww; /* arg to the 2-to-the-kth power */ + if (n & 1) /* if that bit is set, then include in product */ + y *= ww; + n >>= 1; + } + + if (sign < 0) + y = 1.0/y; + return y; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double powl(long double x, long double y) +{ + return pow(x, y); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/remainder.c b/user/include/mlibc/options/ansi/musl-generic-math/remainder.c new file mode 100644 index 0000000..e4abcd7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/remainder.c @@ -0,0 +1,11 @@ +#include +#include "weak_alias.h" +//#include "libc.h" + +double remainder(double x, double y) +{ + int q; + return remquo(x, y, &q); +} + +weak_alias(remainder, drem); diff --git a/user/include/mlibc/options/ansi/musl-generic-math/remainderf.c b/user/include/mlibc/options/ansi/musl-generic-math/remainderf.c new file mode 100644 index 0000000..e1fcdaa --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/remainderf.c @@ -0,0 +1,11 @@ +#include +#include "weak_alias.h" +//#include "libc.h" + +float remainderf(float x, float y) +{ + int q; + return remquof(x, y, &q); +} + +weak_alias(remainderf, dremf); diff --git a/user/include/mlibc/options/ansi/musl-generic-math/remainderl.c b/user/include/mlibc/options/ansi/musl-generic-math/remainderl.c new file mode 100644 index 0000000..2a13c1d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/remainderl.c @@ -0,0 +1,15 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remainderl(long double x, long double y) +{ + return remainder(x, y); +} +#else +long double remainderl(long double x, long double y) +{ + int q; + return remquol(x, y, &q); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/remquo.c b/user/include/mlibc/options/ansi/musl-generic-math/remquo.c new file mode 100644 index 0000000..59d5ad5 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/remquo.c @@ -0,0 +1,82 @@ +#include +#include + +double remquo(double x, double y, int *quo) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>52 & 0x7ff; + int ey = uy.i>>52 & 0x7ff; + int sx = ux.i>>63; + int sy = uy.i>>63; + uint32_t q; + uint64_t i; + uint64_t uxi = ux.i; + + *quo = 0; + if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) + return (x*y)/(x*y); + if (ux.i<<1 == 0) + return x; + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + q = 0; + if (ex < ey) { + if (ex+1 == ey) + goto end; + return x; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + uxi = i; + q++; + } + uxi <<= 1; + q <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + uxi = i; + q++; + } + if (uxi == 0) + ex = -60; + else + for (; uxi>>52 == 0; uxi <<= 1, ex--); +end: + /* scale result and decide between |x| and |x|-|y| */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + ux.i = uxi; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/remquof.c b/user/include/mlibc/options/ansi/musl-generic-math/remquof.c new file mode 100644 index 0000000..2f41ff7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/remquof.c @@ -0,0 +1,82 @@ +#include +#include + +float remquof(float x, float y, int *quo) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + int sx = ux.i>>31; + int sy = uy.i>>31; + uint32_t q; + uint32_t i; + uint32_t uxi = ux.i; + + *quo = 0; + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + return (x*y)/(x*y); + if (ux.i<<1 == 0) + return x; + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + q = 0; + if (ex < ey) { + if (ex+1 == ey) + goto end; + return x; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + uxi = i; + q++; + } + uxi <<= 1; + q <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + uxi = i; + q++; + } + if (uxi == 0) + ex = -30; + else + for (; uxi>>23 == 0; uxi <<= 1, ex--); +end: + /* scale result and decide between |x| and |x|-|y| */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + ux.i = uxi; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/remquol.c b/user/include/mlibc/options/ansi/musl-generic-math/remquol.c new file mode 100644 index 0000000..9b065c0 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/remquol.c @@ -0,0 +1,124 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remquol(long double x, long double y, int *quo) +{ + return remquo(x, y, quo); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double remquol(long double x, long double y, int *quo) +{ + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se >> 15; + int sy = uy.i.se >> 15; + uint32_t q; + + *quo = 0; + if (y == 0 || isnan(y) || ex == 0x7fff) + return (x*y)/(x*y); + if (x == 0) + return x; + + /* normalize x and y */ + if (!ex) { + ux.i.se = ex; + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.i.se = ey; + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + + q = 0; + if (ex >= ey) { + /* x mod y */ +#if LDBL_MANT_DIG == 64 + uint64_t i, mx, my; + mx = ux.i.m; + my = uy.i.m; + for (; ex > ey; ex--) { + i = mx - my; + if (mx >= my) { + mx = 2*i; + q++; + q <<= 1; + } else if (2*mx < mx) { + mx = 2*mx - my; + q <<= 1; + q++; + } else { + mx = 2*mx; + q <<= 1; + } + } + i = mx - my; + if (mx >= my) { + mx = i; + q++; + } + if (mx == 0) + ex = -120; + else + for (; mx >> 63 == 0; mx *= 2, ex--); + ux.i.m = mx; +#elif LDBL_MANT_DIG == 113 + uint64_t hi, lo, xhi, xlo, yhi, ylo; + xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48; + yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; + xlo = ux.i2.lo; + ylo = ux.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + xhi = 2*hi + (lo>>63); + xlo = 2*lo; + q++; + } else { + xhi = 2*xhi + (xlo>>63); + xlo = 2*xlo; + } + q <<= 1; + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + xhi = hi; + xlo = lo; + q++; + } + if ((xhi|xlo) == 0) + ex = -120; + else + for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + } + + /* scale result and decide between |x| and |x|-|y| */ + if (ex <= 0) { + ux.i.se = ex + 120; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/rint.c b/user/include/mlibc/options/ansi/musl-generic-math/rint.c new file mode 100644 index 0000000..fbba390 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/rint.c @@ -0,0 +1,28 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double rint(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + int s = u.i>>63; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return s ? -0.0 : 0; + return y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/rintf.c b/user/include/mlibc/options/ansi/musl-generic-math/rintf.c new file mode 100644 index 0000000..9047688 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/rintf.c @@ -0,0 +1,30 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD==0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1/EPS; + +float rintf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + int s = u.i>>31; + float_t y; + + if (e >= 0x7f+23) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return s ? -0.0f : 0.0f; + return y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/rintl.c b/user/include/mlibc/options/ansi/musl-generic-math/rintl.c new file mode 100644 index 0000000..374327d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/rintl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double rintl(long double x) +{ + return rint(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double rintl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return 0*x; + return y; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/round.c b/user/include/mlibc/options/ansi/musl-generic-math/round.c new file mode 100644 index 0000000..130d58d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/round.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double round(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (u.i >> 63) + x = -x; + if (e < 0x3ff-1) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i >> 63) + y = -y; + return y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/roundf.c b/user/include/mlibc/options/ansi/musl-generic-math/roundf.c new file mode 100644 index 0000000..e8210af --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/roundf.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1/EPS; + +float roundf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i >> 23 & 0xff; + float_t y; + + if (e >= 0x7f+23) + return x; + if (u.i >> 31) + x = -x; + if (e < 0x7f-1) { + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5f) + y = y + x - 1; + else if (y <= -0.5f) + y = y + x + 1; + else + y = y + x; + if (u.i >> 31) + y = -y; + return y; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/roundl.c b/user/include/mlibc/options/ansi/musl-generic-math/roundl.c new file mode 100644 index 0000000..f4ff682 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/roundl.c @@ -0,0 +1,37 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double roundl(long double x) +{ + return round(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double roundl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (u.i.se >> 15) + x = -x; + if (e < 0x3fff-1) { + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i.se >> 15) + y = -y; + return y; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/scalb.c b/user/include/mlibc/options/ansi/musl-generic-math/scalb.c new file mode 100644 index 0000000..efe69e6 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/scalb.c @@ -0,0 +1,35 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_scalb.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * scalb(x, fn) is provide for + * passing various standard test suite. One + * should use scalbn() instead. + */ + +#define _GNU_SOURCE +#include + +double scalb(double x, double fn) +{ + if (isnan(x) || isnan(fn)) + return x*fn; + if (!isfinite(fn)) { + if (fn > 0.0) + return x*fn; + else + return x/(-fn); + } + if (rint(fn) != fn) return (fn-fn)/(fn-fn); + if ( fn > 65000.0) return scalbn(x, 65000); + if (-fn > 65000.0) return scalbn(x,-65000); + return scalbn(x,(int)fn); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/scalbf.c b/user/include/mlibc/options/ansi/musl-generic-math/scalbf.c new file mode 100644 index 0000000..f44ed5b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/scalbf.c @@ -0,0 +1,32 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_scalbf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include + +float scalbf(float x, float fn) +{ + if (isnan(x) || isnan(fn)) return x*fn; + if (!isfinite(fn)) { + if (fn > 0.0f) + return x*fn; + else + return x/(-fn); + } + if (rintf(fn) != fn) return (fn-fn)/(fn-fn); + if ( fn > 65000.0f) return scalbnf(x, 65000); + if (-fn > 65000.0f) return scalbnf(x,-65000); + return scalbnf(x,(int)fn); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/scalbln.c b/user/include/mlibc/options/ansi/musl-generic-math/scalbln.c new file mode 100644 index 0000000..4fb3d06 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/scalbln.c @@ -0,0 +1,12 @@ +#include +#include +#include "libm.h" + +double scalbln(double x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbn(x, n); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/scalblnf.c b/user/include/mlibc/options/ansi/musl-generic-math/scalblnf.c new file mode 100644 index 0000000..b6bdeed --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/scalblnf.c @@ -0,0 +1,12 @@ +#include +#include +#include "libm.h" + +float scalblnf(float x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbnf(x, n); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/scalblnl.c b/user/include/mlibc/options/ansi/musl-generic-math/scalblnl.c new file mode 100644 index 0000000..b1a0f7f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/scalblnl.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalblnl(long double x, long n) +{ + return scalbln(x, n); +} +#else +long double scalblnl(long double x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbnl(x, n); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/scalbn.c b/user/include/mlibc/options/ansi/musl-generic-math/scalbn.c new file mode 100644 index 0000000..182f561 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/scalbn.c @@ -0,0 +1,33 @@ +#include +#include + +double scalbn(double x, int n) +{ + union {double f; uint64_t i;} u; + double_t y = x; + + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) + n = 1023; + } + } else if (n < -1022) { + /* make sure final n < -53 to avoid double + rounding in the subnormal range */ + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) { + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) + n = -1022; + } + } + u.i = (uint64_t)(0x3ff+n)<<52; + x = y * u.f; + return x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/scalbnf.c b/user/include/mlibc/options/ansi/musl-generic-math/scalbnf.c new file mode 100644 index 0000000..a5ad208 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/scalbnf.c @@ -0,0 +1,31 @@ +#include +#include + +float scalbnf(float x, int n) +{ + union {float f; uint32_t i;} u; + float_t y = x; + + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) + n = 127; + } + } else if (n < -126) { + y *= 0x1p-126f * 0x1p24f; + n += 126 - 24; + if (n < -126) { + y *= 0x1p-126f * 0x1p24f; + n += 126 - 24; + if (n < -126) + n = -126; + } + } + u.i = (uint32_t)(0x7f+n)<<23; + x = y * u.f; + return x; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/scalbnl.c b/user/include/mlibc/options/ansi/musl-generic-math/scalbnl.c new file mode 100644 index 0000000..db44dab --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/scalbnl.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalbnl(long double x, int n) +{ + return scalbn(x, n); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double scalbnl(long double x, int n) +{ + union ldshape u; + + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) + n = 16383; + } + } else if (n < -16382) { + x *= 0x1p-16382L * 0x1p113L; + n += 16382 - 113; + if (n < -16382) { + x *= 0x1p-16382L * 0x1p113L; + n += 16382 - 113; + if (n < -16382) + n = -16382; + } + } + u.f = 1.0; + u.i.se = 0x3fff + n; + return x * u.f; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/signgam.c b/user/include/mlibc/options/ansi/musl-generic-math/signgam.c new file mode 100644 index 0000000..3a5b9f7 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/signgam.c @@ -0,0 +1,5 @@ +#include +#include "weak_alias.h" +//#include "libc.h" + +int signgam = 0; diff --git a/user/include/mlibc/options/ansi/musl-generic-math/significand.c b/user/include/mlibc/options/ansi/musl-generic-math/significand.c new file mode 100644 index 0000000..40d9aa9 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/significand.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +double significand(double x) +{ + return scalbn(x, -ilogb(x)); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/significandf.c b/user/include/mlibc/options/ansi/musl-generic-math/significandf.c new file mode 100644 index 0000000..8a697e1 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/significandf.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +float significandf(float x) +{ + return scalbnf(x, -ilogbf(x)); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sin.c b/user/include/mlibc/options/ansi/musl-generic-math/sin.c new file mode 100644 index 0000000..055e215 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sin.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sin(x) + * Return sine function of x. + * + * kernel function: + * __sin ... sine function on [-pi/4,pi/4] + * __cos ... cose function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double sin(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + /* High word of x. */ + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e500000) { /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x - x; + + /* argument reduction needed */ + n = __rem_pio2(x, y); + switch (n&3) { + case 0: return __sin(y[0], y[1], 1); + case 1: return __cos(y[0], y[1]); + case 2: return -__sin(y[0], y[1], 1); + default: + return -__cos(y[0], y[1]); + } +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sincos.c b/user/include/mlibc/options/ansi/musl-generic-math/sincos.c new file mode 100644 index 0000000..35b2d92 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sincos.c @@ -0,0 +1,69 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +void sincos(double x, double *sin, double *cos) +{ + double y[2], s, c; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + /* if |x| < 2**-27 * sqrt(2) */ + if (ix < 0x3e46a09e) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0; + return; + } + *sin = __sin(x, 0.0, 0); + *cos = __cos(x, 0.0); + return; + } + + /* sincos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) { + *sin = *cos = x - x; + return; + } + + /* argument reduction needed */ + n = __rem_pio2(x, y); + s = __sin(y[0], y[1], 1); + c = __cos(y[0], y[1]); + switch (n&3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sincosf.c b/user/include/mlibc/options/ansi/musl-generic-math/sincosf.c new file mode 100644 index 0000000..f8ca723 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sincosf.c @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +void sincosf(float x, float *sin, float *cos) +{ + double y; + float_t s, c; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if (ix <= 0x3f490fda) { + /* |x| < 2**-12 */ + if (ix < 0x39800000) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0f; + return; + } + *sin = __sindf(x); + *cos = __cosdf(x); + return; + } + + /* |x| ~<= 5*pi/4 */ + if (ix <= 0x407b53d1) { + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) { + *sin = -__cosdf(x + s1pio2); + *cos = __sindf(x + s1pio2); + } else { + *sin = __cosdf(s1pio2 - x); + *cos = __sindf(s1pio2 - x); + } + return; + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + *sin = -__sindf(sign ? x + s2pio2 : x - s2pio2); + *cos = -__cosdf(sign ? x + s2pio2 : x - s2pio2); + return; + } + + /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40e231d5) { + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) { + *sin = __cosdf(x + s3pio2); + *cos = -__sindf(x + s3pio2); + } else { + *sin = -__cosdf(x - s3pio2); + *cos = __sindf(x - s3pio2); + } + return; + } + *sin = __sindf(sign ? x + s4pio2 : x - s4pio2); + *cos = __cosdf(sign ? x + s4pio2 : x - s4pio2); + return; + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) { + *sin = *cos = x - x; + return; + } + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + s = __sindf(y); + c = __cosdf(y); + switch (n&3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sincosl.c b/user/include/mlibc/options/ansi/musl-generic-math/sincosl.c new file mode 100644 index 0000000..d3ac1c4 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sincosl.c @@ -0,0 +1,60 @@ +#define _GNU_SOURCE +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +void sincosl(long double x, long double *sin, long double *cos) +{ + double sind, cosd; + sincos(x, &sind, &cosd); + *sin = sind; + *cos = cosd; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +void sincosl(long double x, long double *sin, long double *cos) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], s, c; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) { + *sin = *cos = x - x; + return; + } + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) { + /* raise underflow if subnormal */ + if (u.i.se == 0) FORCE_EVAL(x*0x1p-120f); + *sin = x; + /* raise inexact if x!=0 */ + *cos = 1.0 + x; + return; + } + *sin = __sinl(x, 0, 0); + *cos = __cosl(x, 0); + return; + } + n = __rem_pio2l(x, y); + s = __sinl(y[0], y[1], 1); + c = __cosl(y[0], y[1]); + switch (n & 3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sinf.c b/user/include/mlibc/options/ansi/musl-generic-math/sinf.c new file mode 100644 index 0000000..64e39f5 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sinf.c @@ -0,0 +1,76 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float sinf(float x) +{ + double y; + uint32_t ix; + int n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sindf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) + return -__cosdf(x + s1pio2); + else + return __cosdf(x - s1pio2); + } + return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) + return __cosdf(x + s3pio2); + else + return -__cosdf(x - s3pio2); + } + return __sindf(sign ? x + s4pio2 : x - s4pio2); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + switch (n&3) { + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + default: + return -__cosdf(y); + } +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sinh.c b/user/include/mlibc/options/ansi/musl-generic-math/sinh.c new file mode 100644 index 0000000..00022c4 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sinh.c @@ -0,0 +1,39 @@ +#include "libm.h" + +/* sinh(x) = (exp(x) - 1/exp(x))/2 + * = (exp(x)-1 + (exp(x)-1)/exp(x))/2 + * = x + x^3/6 + o(x^5) + */ +double sinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t, h, absx; + + h = 0.5; + if (u.i >> 63) + h = -h; + /* |x| */ + u.i &= (uint64_t)-1/2; + absx = u.f; + w = u.i >> 32; + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = expm1(absx); + if (w < 0x3ff00000) { + if (w < 0x3ff00000 - (26<<20)) + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + return h*(2*t - t*t/(t+1)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h*(t + t/(t+1)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2*h*__expo2(absx); + return t; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sinhf.c b/user/include/mlibc/options/ansi/musl-generic-math/sinhf.c new file mode 100644 index 0000000..6ad19ea --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sinhf.c @@ -0,0 +1,31 @@ +#include "libm.h" + +float sinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t, h, absx; + + h = 0.5; + if (u.i >> 31) + h = -h; + /* |x| */ + u.i &= 0x7fffffff; + absx = u.f; + w = u.i; + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expm1f(absx); + if (w < 0x3f800000) { + if (w < 0x3f800000 - (12<<23)) + return x; + return h*(2*t - t*t/(t+1)); + } + return h*(t + t/(t+1)); + } + + /* |x| > logf(FLT_MAX) or nan */ + t = 2*h*__expo2f(absx); + return t; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sinhl.c b/user/include/mlibc/options/ansi/musl-generic-math/sinhl.c new file mode 100644 index 0000000..b305d4d --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sinhl.c @@ -0,0 +1,43 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinhl(long double x) +{ + return sinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double sinhl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + long double h, t, absx; + + h = 0.5; + if (u.i.se & 0x8000) + h = -h; + /* |x| */ + u.i.se = ex; + absx = u.f; + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff+13 || (ex == 0x3fff+13 && u.i.m>>32 < 0xb17217f7)) { + t = expm1l(absx); + if (ex < 0x3fff) { + if (ex < 0x3fff-32) + return x; + return h*(2*t - t*t/(1+t)); + } + return h*(t + t/(t+1)); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5*absx); + return h*t*t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double sinhl(long double x) +{ + return sinh(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sinl.c b/user/include/mlibc/options/ansi/musl-generic-math/sinl.c new file mode 100644 index 0000000..9c0b16e --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sinl.c @@ -0,0 +1,41 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinl(long double x) +{ + return sin(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double sinl(long double x) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], hi, lo; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG/2) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(u.i.se == 0 ? x*0x1p-120f : x+0x1p120f); + return x; + } + return __sinl(x, 0.0, 0); + } + n = __rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + switch (n & 3) { + case 0: + return __sinl(hi, lo, 1); + case 1: + return __cosl(hi, lo); + case 2: + return -__sinl(hi, lo, 1); + case 3: + default: + return -__cosl(hi, lo); + } +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sqrt.c b/user/include/mlibc/options/ansi/musl-generic-math/sqrt.c new file mode 100644 index 0000000..b277567 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sqrt.c @@ -0,0 +1,185 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + */ + +#include "libm.h" + +static const double tiny = 1.0e-300; + +double sqrt(double x) +{ + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + uint32_t r,t1,s1,ix1,q1; + + EXTRACT_WORDS(ix0, ix1, x); + + /* take care of Inf and NaN */ + if ((ix0&0x7ff00000) == 0x7ff00000) { + return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if (ix0 <= 0) { + if (((ix0&~sign)|ix1) == 0) + return x; /* sqrt(+-0) = +-0 */ + if (ix0 < 0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = ix0>>20; + if (m == 0) { /* subnormal x */ + while (ix0 == 0) { + m -= 21; + ix0 |= (ix1>>11); + ix1 <<= 21; + } + for (i=0; (ix0&0x00100000) == 0; i++) + ix0<<=1; + m -= i - 1; + ix0 |= ix1>>(32-i); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if (m & 1) { /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s0 + r; + if (t <= ix0) { + s0 = t + r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r >>= 1; + } + + r = sign; + while (r != 0) { + t1 = s1 + r; + t = s0; + if (t < ix0 || (t == ix0 && t1 <= ix1)) { + s1 = t1 + r; + if ((t1&sign) == sign && (s1&sign) == 0) + s0++; + ix0 -= t; + if (ix1 < t1) + ix0--; + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if ((ix0|ix1) != 0) { + z = 1.0 - tiny; /* raise inexact flag */ + if (z >= 1.0) { + z = 1.0 + tiny; + if (q1 == (uint32_t)0xffffffff) { + q1 = 0; + q++; + } else if (z > 1.0) { + if (q1 == (uint32_t)0xfffffffe) + q++; + q1 += 2; + } else + q1 += q1 & 1; + } + } + ix0 = (q>>1) + 0x3fe00000; + ix1 = q1>>1; + if (q&1) + ix1 |= sign; + ix0 += m << 20; + INSERT_WORDS(z, ix0, ix1); + return z; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sqrtf.c b/user/include/mlibc/options/ansi/musl-generic-math/sqrtf.c new file mode 100644 index 0000000..28cb4ad --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sqrtf.c @@ -0,0 +1,84 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float tiny = 1.0e-30; + +float sqrtf(float x) +{ + float z; + int32_t sign = (int)0x80000000; + int32_t ix,s,q,m,t,i; + uint32_t r; + + GET_FLOAT_WORD(ix, x); + + /* take care of Inf and NaN */ + if ((ix&0x7f800000) == 0x7f800000) + return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + + /* take care of zero */ + if (ix <= 0) { + if ((ix&~sign) == 0) + return x; /* sqrt(+-0) = +-0 */ + if (ix < 0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = ix>>23; + if (m == 0) { /* subnormal x */ + for (i = 0; (ix&0x00800000) == 0; i++) + ix<<=1; + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix&0x007fffff)|0x00800000; + if (m&1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s + r; + if (t <= ix) { + s = t+r; + ix -= t; + q += r; + } + ix += ix; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if (ix != 0) { + z = 1.0f - tiny; /* raise inexact flag */ + if (z >= 1.0f) { + z = 1.0f + tiny; + if (z > 1.0f) + q += 2; + else + q += q & 1; + } + } + ix = (q>>1) + 0x3f000000; + ix += m << 23; + SET_FLOAT_WORD(z, ix); + return z; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/sqrtl.c b/user/include/mlibc/options/ansi/musl-generic-math/sqrtl.c new file mode 100644 index 0000000..83a8f80 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/sqrtl.c @@ -0,0 +1,7 @@ +#include + +long double sqrtl(long double x) +{ + /* FIXME: implement in C, this is for LDBL_MANT_DIG == 64 only */ + return sqrt(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tan.c b/user/include/mlibc/options/ansi/musl-generic-math/tan.c new file mode 100644 index 0000000..9c724a4 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tan.c @@ -0,0 +1,70 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* tan(x) + * Return tangent function of x. + * + * kernel function: + * __tan ... tangent function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double tan(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e400000) { /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x - x; + + /* argument reduction */ + n = __rem_pio2(x, y); + return __tan(y[0], y[1], n&1); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tanf.c b/user/include/mlibc/options/ansi/musl-generic-math/tanf.c new file mode 100644 index 0000000..aba1977 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tanf.c @@ -0,0 +1,64 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +t1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float tanf(float x) +{ + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tandf(x, 0); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) /* |x| ~<= 3pi/4 */ + return __tandf((sign ? x+t1pio2 : x-t1pio2), 1); + else + return __tandf((sign ? x+t2pio2 : x-t2pio2), 0); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) /* |x| ~<= 7*pi/4 */ + return __tandf((sign ? x+t3pio2 : x-t3pio2), 1); + else + return __tandf((sign ? x+t4pio2 : x-t4pio2), 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* argument reduction */ + n = __rem_pio2f(x, &y); + return __tandf(y, n&1); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tanh.c b/user/include/mlibc/options/ansi/musl-generic-math/tanh.c new file mode 100644 index 0000000..20d6dbc --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tanh.c @@ -0,0 +1,45 @@ +#include "libm.h" + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ +double tanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + int sign; + double_t t; + + /* x = |x| */ + sign = u.i >> 63; + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + if (w > 0x3fe193ea) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x40340000) { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1 - 0/x; + } else { + t = expm1(2*x); + t = 1 - 2/(t+2); + } + } else if (w > 0x3fd058ae) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2*x); + t = t/(t+2); + } else if (w >= 0x00100000) { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2*x); + t = -t/(t+2); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + FORCE_EVAL((float)x); + t = x; + } + return sign ? -t : t; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tanhf.c b/user/include/mlibc/options/ansi/musl-generic-math/tanhf.c new file mode 100644 index 0000000..10636fb --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tanhf.c @@ -0,0 +1,39 @@ +#include "libm.h" + +float tanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + int sign; + float t; + + /* x = |x| */ + sign = u.i >> 31; + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + if (w > 0x3f0c9f54) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x41200000) { + /* |x| > 10 */ + t = 1 + 0/x; + } else { + t = expm1f(2*x); + t = 1 - 2/(t+2); + } + } else if (w > 0x3e82c578) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1f(2*x); + t = t/(t+2); + } else if (w >= 0x00800000) { + /* |x| >= 0x1p-126 */ + t = expm1f(-2*x); + t = -t/(t+2); + } else { + /* |x| is subnormal */ + FORCE_EVAL(x*x); + t = x; + } + return sign ? -t : t; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tanhl.c b/user/include/mlibc/options/ansi/musl-generic-math/tanhl.c new file mode 100644 index 0000000..4e1aa9f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tanhl.c @@ -0,0 +1,48 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanhl(long double x) +{ + return tanh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double tanhl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + unsigned sign = u.i.se & 0x8000; + uint32_t w; + long double t; + + /* x = |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + if (ex > 0x3ffe || (ex == 0x3ffe && w > 0x8c9f53d5)) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (ex >= 0x3fff+5) { + /* |x| >= 32 */ + t = 1 + 0/(x + 0x1p-120f); + } else { + t = expm1l(2*x); + t = 1 - 2/(t+2); + } + } else if (ex > 0x3ffd || (ex == 0x3ffd && w > 0x82c577d4)) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1l(2*x); + t = t/(t+2); + } else { + /* |x| is small */ + t = expm1l(-2*x); + t = -t/(t+2); + } + return sign ? -t : t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tanhl(long double x) +{ + return tanh(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tanl.c b/user/include/mlibc/options/ansi/musl-generic-math/tanl.c new file mode 100644 index 0000000..6af0671 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tanl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanl(long double x) +{ + return tan(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double tanl(long double x) +{ + union ldshape u = {x}; + long double y[2]; + unsigned n; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG/2) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(u.i.se == 0 ? x*0x1p-120f : x+0x1p120f); + return x; + } + return __tanl(x, 0, 0); + } + n = __rem_pio2l(x, y); + return __tanl(y[0], y[1], n&1); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tgamma.c b/user/include/mlibc/options/ansi/musl-generic-math/tgamma.c new file mode 100644 index 0000000..28f6e0f --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tgamma.c @@ -0,0 +1,222 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +#include "libm.h" + +static const double pi = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sinpi(double x) +{ + int n; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = 4 * x; + n = (n+1)/2; + x -= n * 0.5; + + x *= pi; + switch (n) { + default: /* case 4 */ + case 0: + return __sin(x, 0, 0); + case 1: + return __cos(x, 0); + case 2: + return __sin(-x, 0, 0); + case 3: + return -__cos(x, 0); + } +} + +#define N 12 +//static const double g = 6.024680040776729583740234375; +static const double gmhalf = 5.524680040776729583740234375; +static const double Snum[N+1] = { + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +}; +static const double Sden[N+1] = { + 0, 39916800, 120543840, 150917976, 105258076, 45995730, 13339535, + 2637558, 357423, 32670, 1925, 66, 1, +}; +/* n! for small integer n */ +static const double fact[] = { + 1, 1, 2, 6, 24, 120, 720, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, + 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, + 355687428096000.0, 6402373705728000.0, 121645100408832000.0, + 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, +}; + +/* S(x) rational function for positive x */ +static double S(double x) +{ + double_t num = 0, den = 0; + int i; + + /* to avoid overflow handle large x differently */ + if (x < 8) + for (i = N; i >= 0; i--) { + num = num * x + Snum[i]; + den = den * x + Sden[i]; + } + else + for (i = 0; i <= N; i++) { + num = num / x + Snum[i]; + den = den / x + Sden[i]; + } + return num/den; +} + +double tgamma(double x) +{ + union {double f; uint64_t i;} u = {x}; + double absx, y; + double_t dy, z, r; + uint32_t ix = u.i>>32 & 0x7fffffff; + int sign = u.i>>63; + + /* special cases */ + if (ix >= 0x7ff00000) + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + INFINITY; + if (ix < (0x3ff-54)<<20) + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1/x; + + /* integer arguments */ + /* raise inexact when non-integer */ + if (x == floor(x)) { + if (sign) + return 0/0.0; + if (x <= sizeof fact/sizeof *fact) + return fact[(int)x - 1]; + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if (ix >= 0x40670000) { /* |x| >= 184 */ + if (sign) { + FORCE_EVAL((float)(0x1p-126/x)); + if (floor(x) * 0.5 == floor(x * 0.5)) + return 0; + return -0.0; + } + x *= 0x1p1023; + return x; + } + + absx = sign ? -x : x; + + /* handle the error of x + g - 0.5 */ + y = absx + gmhalf; + if (absx > gmhalf) { + dy = y - absx; + dy -= gmhalf; + } else { + dy = y - gmhalf; + dy -= absx; + } + + z = absx - 0.5; + r = S(absx) * exp(-y); + if (x < 0) { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -pi / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (gmhalf+0.5) * r / y; + z = pow(y, 0.5*z); + y = r * z * z; + return y; +} + +#if 0 +double __lgamma_r(double x, int *sign) +{ + double r, absx; + + *sign = 1; + + /* special cases */ + if (!isfinite(x)) + /* lgamma(nan)=nan, lgamma(+-inf)=inf */ + return x*x; + + /* integer arguments */ + if (x == floor(x) && x <= 2) { + /* n <= 0: lgamma(n)=inf with divbyzero */ + /* n == 1,2: lgamma(n)=0 */ + if (x <= 0) + return 1/0.0; + return 0; + } + + absx = fabs(x); + + /* lgamma(x) ~ -log(|x|) for tiny |x| */ + if (absx < 0x1p-54) { + *sign = 1 - 2*!!signbit(x); + return -log(absx); + } + + /* use tgamma for smaller |x| */ + if (absx < 128) { + x = tgamma(x); + *sign = 1 - 2*!!signbit(x); + return log(fabs(x)); + } + + /* second term (log(S)-g) could be more precise here.. */ + /* or with stirling: (|x|-0.5)*(log(|x|)-1) + poly(1/|x|) */ + r = (absx-0.5)*(log(absx+gmhalf)-1) + (log(S(absx)) - (gmhalf+0.5)); + if (x < 0) { + /* reflection formula for negative x */ + x = sinpi(absx); + *sign = 2*!!signbit(x) - 1; + r = log(pi/(fabs(x)*absx)) - r; + } + return r; +} + +weak_alias(__lgamma_r, lgamma_r); +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tgammaf.c b/user/include/mlibc/options/ansi/musl-generic-math/tgammaf.c new file mode 100644 index 0000000..b4ca51c --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tgammaf.c @@ -0,0 +1,6 @@ +#include + +float tgammaf(float x) +{ + return tgamma(x); +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/tgammal.c b/user/include/mlibc/options/ansi/musl-generic-math/tgammal.c new file mode 100644 index 0000000..5336c5b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/tgammal.c @@ -0,0 +1,281 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_tgammal.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and 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. + */ +/* + * Gamma function + * + * + * SYNOPSIS: + * + * long double x, y, tgammal(); + * + * y = tgammal( x ); + * + * + * DESCRIPTION: + * + * Returns gamma function of the argument. The result is + * correctly signed. + * + * Arguments |x| <= 13 are reduced by recurrence and the function + * approximated by a rational function of degree 7/8 in the + * interval (2,3). Large arguments are handled by Stirling's + * formula. Large negative arguments are made positive using + * a reflection formula. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -40,+40 10000 3.6e-19 7.9e-20 + * IEEE -1755,+1755 10000 4.8e-18 6.5e-19 + * + * Accuracy for large arguments is dominated by error in powl(). + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tgammal(long double x) +{ + return tgamma(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* +tgamma(x+2) = tgamma(x+2) P(x)/Q(x) +0 <= x <= 1 +Relative error +n=7, d=8 +Peak error = 1.83e-20 +Relative error spread = 8.4e-23 +*/ +static const long double P[8] = { + 4.212760487471622013093E-5L, + 4.542931960608009155600E-4L, + 4.092666828394035500949E-3L, + 2.385363243461108252554E-2L, + 1.113062816019361559013E-1L, + 3.629515436640239168939E-1L, + 8.378004301573126728826E-1L, + 1.000000000000000000009E0L, +}; +static const long double Q[9] = { +-1.397148517476170440917E-5L, + 2.346584059160635244282E-4L, +-1.237799246653152231188E-3L, +-7.955933682494738320586E-4L, + 2.773706565840072979165E-2L, +-4.633887671244534213831E-2L, +-2.243510905670329164562E-1L, + 4.150160950588455434583E-1L, + 9.999999999999999999908E-1L, +}; + +/* +static const long double P[] = { +-3.01525602666895735709e0L, +-3.25157411956062339893e1L, +-2.92929976820724030353e2L, +-1.70730828800510297666e3L, +-7.96667499622741999770e3L, +-2.59780216007146401957e4L, +-5.99650230220855581642e4L, +-7.15743521530849602425e4L +}; +static const long double Q[] = { + 1.00000000000000000000e0L, +-1.67955233807178858919e1L, + 8.85946791747759881659e1L, + 5.69440799097468430177e1L, +-1.98526250512761318471e3L, + 3.31667508019495079814e3L, + 1.60577839621734713377e4L, +-2.97045081369399940529e4L, +-7.15743521530849602412e4L +}; +*/ +#define MAXGAML 1755.455L +/*static const long double LOGPI = 1.14472988584940017414L;*/ + +/* Stirling's formula for the gamma function +tgamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) +z(x) = x +13 <= x <= 1024 +Relative error +n=8, d=0 +Peak error = 9.44e-21 +Relative error spread = 8.8e-4 +*/ +static const long double STIR[9] = { + 7.147391378143610789273E-4L, +-2.363848809501759061727E-5L, +-5.950237554056330156018E-4L, + 6.989332260623193171870E-5L, + 7.840334842744753003862E-4L, +-2.294719747873185405699E-4L, +-2.681327161876304418288E-3L, + 3.472222222230075327854E-3L, + 8.333333333333331800504E-2L, +}; + +#define MAXSTIR 1024.0L +static const long double SQTPI = 2.50662827463100050242E0L; + +/* 1/tgamma(x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 4.2e-23 + */ +static const long double S[9] = { +-1.193945051381510095614E-3L, + 7.220599478036909672331E-3L, +-9.622023360406271645744E-3L, +-4.219773360705915470089E-2L, + 1.665386113720805206758E-1L, +-4.200263503403344054473E-2L, +-6.558780715202540684668E-1L, + 5.772156649015328608253E-1L, + 1.000000000000000000000E0L, +}; + +/* 1/tgamma(-x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 5.16e-23 + * Relative error spread = 2.5e-24 + */ +static const long double SN[9] = { + 1.133374167243894382010E-3L, + 7.220837261893170325704E-3L, + 9.621911155035976733706E-3L, +-4.219773343731191721664E-2L, +-1.665386113944413519335E-1L, +-4.200263503402112910504E-2L, + 6.558780715202536547116E-1L, + 5.772156649015328608727E-1L, +-1.000000000000000000000E0L, +}; + +static const long double PIL = 3.1415926535897932384626L; + +/* Gamma function computed by Stirling's formula. + */ +static long double stirf(long double x) +{ + long double y, w, v; + + w = 1.0/x; + /* For large x, use rational coefficients from the analytical expansion. */ + if (x > 1024.0) + w = (((((6.97281375836585777429E-5L * w + + 7.84039221720066627474E-4L) * w + - 2.29472093621399176955E-4L) * w + - 2.68132716049382716049E-3L) * w + + 3.47222222222222222222E-3L) * w + + 8.33333333333333333333E-2L) * w + + 1.0; + else + w = 1.0 + w * __polevll(w, STIR, 8); + y = expl(x); + if (x > MAXSTIR) { /* Avoid overflow in pow() */ + v = powl(x, 0.5L * x - 0.25L); + y = v * (v / y); + } else { + y = powl(x, x - 0.5L) / y; + } + y = SQTPI * y * w; + return y; +} + +long double tgammal(long double x) +{ + long double p, q, z; + + if (!isfinite(x)) + return x + INFINITY; + + q = fabsl(x); + if (q > 13.0) { + if (x < 0.0) { + p = floorl(q); + z = q - p; + if (z == 0) + return 0 / z; + if (q > MAXGAML) { + z = 0; + } else { + if (z > 0.5) { + p += 1.0; + z = q - p; + } + z = q * sinl(PIL * z); + z = fabsl(z) * stirf(q); + z = PIL/z; + } + if (0.5 * p == floorl(q * 0.5)) + z = -z; + } else if (x > MAXGAML) { + z = x * 0x1p16383L; + } else { + z = stirf(x); + } + return z; + } + + z = 1.0; + while (x >= 3.0) { + x -= 1.0; + z *= x; + } + while (x < -0.03125L) { + z /= x; + x += 1.0; + } + if (x <= 0.03125L) + goto small; + while (x < 2.0) { + z /= x; + x += 1.0; + } + if (x == 2.0) + return z; + + x -= 2.0; + p = __polevll(x, P, 7); + q = __polevll(x, Q, 8); + z = z * p / q; + return z; + +small: + /* z==1 if x was originally +-0 */ + if (x == 0 && z != 1) + return x / x; + if (x < 0.0) { + x = -x; + q = z / (x * __polevll(x, SN, 8)); + } else + q = z / (x * __polevll(x, S, 8)); + return q; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tgammal(long double x) +{ + return tgamma(x); +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/trunc.c b/user/include/mlibc/options/ansi/musl-generic-math/trunc.c new file mode 100644 index 0000000..d13711b --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/trunc.c @@ -0,0 +1,19 @@ +#include "libm.h" + +double trunc(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12; + uint64_t m; + + if (e >= 52 + 12) + return x; + if (e < 12) + e = 1; + m = -1ULL >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/truncf.c b/user/include/mlibc/options/ansi/musl-generic-math/truncf.c new file mode 100644 index 0000000..1a7d03c --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/truncf.c @@ -0,0 +1,19 @@ +#include "libm.h" + +float truncf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9; + uint32_t m; + + if (e >= 23 + 9) + return x; + if (e < 9) + e = 1; + m = -1U >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/user/include/mlibc/options/ansi/musl-generic-math/truncl.c b/user/include/mlibc/options/ansi/musl-generic-math/truncl.c new file mode 100644 index 0000000..f07b193 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/truncl.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double truncl(long double x) +{ + return trunc(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double truncl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (e <= 0x3fff-1) { + FORCE_EVAL(x + 0x1p120f); + return x*0; + } + /* y = int(|x|) - |x|, where int(|x|) is an integer neighbor of |x| */ + if (s) + x = -x; + y = x + toint - toint - x; + if (y > 0) + y -= 1; + x += y; + return s ? -x : x; +} +#endif diff --git a/user/include/mlibc/options/ansi/musl-generic-math/weak_alias.h b/user/include/mlibc/options/ansi/musl-generic-math/weak_alias.h new file mode 100644 index 0000000..785f9d1 --- /dev/null +++ b/user/include/mlibc/options/ansi/musl-generic-math/weak_alias.h @@ -0,0 +1,7 @@ +#ifndef _WEAK_ALIAS_H +#define _WEAK_ALIAS_H + +#define weak_alias(name, alias_to) \ + extern __typeof (name) alias_to __attribute__((__weak__, __alias__(#name))); + +#endif diff --git a/user/include/mlibc/options/bsd/generic/arpa-nameser.cpp b/user/include/mlibc/options/bsd/generic/arpa-nameser.cpp new file mode 100644 index 0000000..e89f2bb --- /dev/null +++ b/user/include/mlibc/options/bsd/generic/arpa-nameser.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +// The ns_get* and ns_put* functions are taken from musl. +unsigned ns_get16(const unsigned char *cp) { + return cp[0] << 8 | cp[1]; +} + +unsigned long ns_get32(const unsigned char *cp) { + return (unsigned)cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; +} + +void ns_put16(unsigned s, unsigned char *cp) { + *cp++ = s >> 8; + *cp++ = s; +} + +void ns_put32(unsigned long l, unsigned char *cp) { + *cp++ = l >> 24; + *cp++ = l >> 16; + *cp++ = l >> 8; + *cp++ = l; +} + +int ns_initparse(const unsigned char *, int, ns_msg *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int ns_parserr(ns_msg *, ns_sect, int, ns_rr *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int ns_name_uncompress(const unsigned char *, const unsigned char *, + const unsigned char *, char *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/bsd/generic/bsd_stdlib.cpp b/user/include/mlibc/options/bsd/generic/bsd_stdlib.cpp new file mode 100644 index 0000000..5cd2329 --- /dev/null +++ b/user/include/mlibc/options/bsd/generic/bsd_stdlib.cpp @@ -0,0 +1,27 @@ + +#include +#include + +#include + +#include + +int getloadavg(double *samples, int nsample) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getloadavg, -1); + if (nsample < 0) { + errno = EINVAL; + return -1; + } + if (nsample > 3) { + nsample = 3; + } + double s[3]; + if (int e = sysdep(s); e) { + errno = e; + return -1; + } + for (int i = 0; i < nsample; i++) { + samples[i] = s[i]; + } + return nsample; +} diff --git a/user/include/mlibc/options/bsd/generic/ether.cpp b/user/include/mlibc/options/bsd/generic/ether.cpp new file mode 100644 index 0000000..0ff0cd9 --- /dev/null +++ b/user/include/mlibc/options/bsd/generic/ether.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +char *ether_ntoa(const struct ether_addr *addr) { + static char x[18]; + return ether_ntoa_r (addr, x); +} + +char *ether_ntoa_r(const struct ether_addr *addr, char *buf) { + char *orig_ptr = buf; + + for(int i = 0; i < ETH_ALEN; i++) { + buf += sprintf(buf, i == 0 ? "%.2X" : ":%.2X", addr->ether_addr_octet[i]); + } + + return orig_ptr; +} + +struct ether_addr *ether_aton(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/bsd/generic/getopt.cpp b/user/include/mlibc/options/bsd/generic/getopt.cpp new file mode 100644 index 0000000..cc124ef --- /dev/null +++ b/user/include/mlibc/options/bsd/generic/getopt.cpp @@ -0,0 +1,8 @@ +#include + +#if __MLIBC_GLIBC_OPTION + +int __optreset = 0; +extern int optreset __attribute__((__weak__, __alias__("__optreset"))); + +#endif //__MLIBC_GLIBC_OPTION diff --git a/user/include/mlibc/options/bsd/generic/pty.cpp b/user/include/mlibc/options/bsd/generic/pty.cpp new file mode 100644 index 0000000..c52c70e --- /dev/null +++ b/user/include/mlibc/options/bsd/generic/pty.cpp @@ -0,0 +1,110 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int openpty(int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win) { + if(mlibc::sys_openpty) { + if(int e = mlibc::sys_openpty(mfd, sfd, name, ios, win); e) { + errno = e; + return -1; + } + return 0; + } + + int ptmx_fd; + if(int e = mlibc::sys_open("/dev/ptmx", O_RDWR | O_NOCTTY, 0, &ptmx_fd); e) { + errno = e; + goto fail; + } + + char spath[32]; + if(!name) + name = spath; + if(ptsname_r(ptmx_fd, name, 32)) + goto fail; + + int pts_fd; + unlockpt(ptmx_fd); + if(int e = mlibc::sys_open(name, O_RDWR | O_NOCTTY, 0, &pts_fd); e) { + errno = e; + goto fail; + } + + if(ios) + tcsetattr(ptmx_fd, TCSAFLUSH, ios); + + if(win) + ioctl(ptmx_fd, TIOCSWINSZ, (void*)win); + + *mfd = ptmx_fd; + *sfd = pts_fd; + return 0; + +fail: + mlibc::sys_close(ptmx_fd); + return -1; +} + +int login_tty(int fd) { + if(setsid() == -1) + return -1; + if(ioctl(fd, TIOCSCTTY, 0)) + return -1; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup2, -1); + if(int e = mlibc::sys_dup2(fd, 0, STDIN_FILENO); e) { + errno = e; + return -1; + } + if(int e = mlibc::sys_dup2(fd, 0, STDOUT_FILENO); e) { + errno = e; + return -1; + } + if(int e = mlibc::sys_dup2(fd, 0, STDERR_FILENO); e) { + errno = e; + return -1; + } + + if(int e = mlibc::sys_close(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int forkpty(int *mfd, char *name, const struct termios *ios, const struct winsize *win) { + int sfd; + if(openpty(mfd, &sfd, name, ios, win)) + return -1; + + pid_t child; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork, -1); + if(int e = mlibc::sys_fork(&child); e) { + errno = e; + return -1; + } + + if(!child) { + if(login_tty(sfd)) + mlibc::panicLogger() << "mlibc: TTY login fail in forkpty() child" << frg::endlog; + }else{ + if(int e = mlibc::sys_close(sfd); e) { + errno = e; + return -1; + } + } + + return child; +} + diff --git a/user/include/mlibc/options/bsd/include/arpa/nameser.h b/user/include/mlibc/options/bsd/include/arpa/nameser.h new file mode 100644 index 0000000..7e2e9f1 --- /dev/null +++ b/user/include/mlibc/options/bsd/include/arpa/nameser.h @@ -0,0 +1,266 @@ +#ifndef _ARPA_NAMESER_H +#define _ARPA_NAMESER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NS_PACKETSZ 512 +#define NS_MAXDNAME 1025 +#define NS_MAXLABEL 63 + +typedef enum __ns_rcode { + ns_r_noerror = 0, + ns_r_formerr = 1, + ns_r_servfail = 2, + ns_r_nxdomain = 3, + ns_r_notimpl = 4, + ns_r_refused = 5, + ns_r_yxdomain = 6, + ns_r_yxrrset = 7, + ns_r_nxrrset = 8, + ns_r_notauth = 9, + ns_r_notzone = 10, + ns_r_max = 11, + ns_r_badvers = 16, + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +typedef enum __ns_type { + ns_t_invalid = 0, + ns_t_a = 1, + ns_t_ns = 2, + ns_t_md = 3, + ns_t_mf = 4, + ns_t_cname = 5, + ns_t_soa = 6, + ns_t_mb = 7, + ns_t_mg = 8, + ns_t_mr = 9, + ns_t_null = 10, + ns_t_wks = 11, + ns_t_ptr = 12, + ns_t_hinfo = 13, + ns_t_minfo = 14, + ns_t_mx = 15, + ns_t_txt = 16, + ns_t_rp = 17, + ns_t_afsdb = 18, + ns_t_x25 = 19, + ns_t_isdn = 20, + ns_t_rt = 21, + ns_t_nsap = 22, + ns_t_nsap_ptr = 23, + ns_t_sig = 24, + ns_t_key = 25, + ns_t_px = 26, + ns_t_gpos = 27, + ns_t_aaaa = 28, + ns_t_loc = 29, + ns_t_nxt = 30, + ns_t_eid = 31, + ns_t_nimloc = 32, + ns_t_srv = 33, + ns_t_atma = 34, + ns_t_naptr = 35, + ns_t_kx = 36, + ns_t_cert = 37, + ns_t_a6 = 38, + ns_t_dname = 39, + ns_t_sink = 40, + ns_t_opt = 41, + ns_t_apl = 42, + ns_t_tkey = 249, + ns_t_tsig = 250, + ns_t_ixfr = 251, + ns_t_axfr = 252, + ns_t_mailb = 253, + ns_t_maila = 254, + ns_t_any = 255, + ns_t_zxfr = 256, + ns_t_max = 65536 +} ns_type; + +typedef enum __ns_class { + ns_c_invalid = 0, + ns_c_in = 1, + ns_c_2 = 2, + ns_c_chaos = 3, + ns_c_hs = 4, + ns_c_none = 254, + ns_c_any = 255, + ns_c_max = 65536 +} ns_class; + +typedef enum __ns_sect { + ns_s_qd = 0, + ns_s_zn = 0, + ns_s_an = 1, + ns_s_pr = 1, + ns_s_ns = 2, + ns_s_ud = 2, + ns_s_ar = 3, + ns_s_max = 4 +} ns_sect; + +typedef struct __ns_msg { + const unsigned char *_msg, *_eom; + uint16_t _id, _flags, _counts[ns_s_max]; + const unsigned char *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const unsigned char *_msg_ptr; +} ns_msg; + +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) + +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + uint16_t type; + uint16_t rr_class; + uint32_t ttl; + uint16_t rdlength; + const unsigned char *rdata; +} ns_rr; + +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr) ((rr).ttl + 0) +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +#ifndef __MLIBC_ABI_ONLY + +#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp) += 2) - 2)) +#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp) += 4) - 4)) +#define NS_PUT16(s, cp) ns_put16((s), ((cp) += 2) - 2) +#define NS_PUT32(l, cp) ns_put32((l), ((cp) += 4) - 4) + +unsigned ns_get16(const unsigned char *__src); +unsigned long ns_get32(const unsigned char *__src); +void ns_put16(unsigned int __value, unsigned char *__src); +void ns_put32(unsigned long __value, unsigned char *__src); + +int ns_initparse(const unsigned char *__msg, int __msglen, ns_msg *__handle); +int ns_parserr(ns_msg *__msg, ns_sect __section, int __rrnum, ns_rr *__rr); +int ns_name_uncompress(const unsigned char *__msg, const unsigned char *__eom, + const unsigned char *__src, char *__dst, size_t __dstsize); + +#endif /* !__MLIBC_ABI_ONLY */ + +typedef struct { + unsigned id :16; +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned qr: 1; + unsigned opcode: 4; + unsigned aa: 1; + unsigned tc: 1; + unsigned rd: 1; + unsigned ra: 1; + unsigned unused :1; + unsigned ad: 1; + unsigned cd: 1; + unsigned rcode :4; +#else + unsigned rd :1; + unsigned tc :1; + unsigned aa :1; + unsigned opcode :4; + unsigned qr :1; + unsigned rcode :4; + unsigned cd: 1; + unsigned ad: 1; + unsigned unused :1; + unsigned ra :1; +#endif + unsigned qdcount :16; + unsigned ancount :16; + unsigned nscount :16; + unsigned arcount :16; +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_A6 ns_t_a6 +#define T_DNAME ns_t_dname +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +#ifdef __cplusplus +} +#endif + +#endif /* _ARPA_NAMESER_H */ diff --git a/user/include/mlibc/options/bsd/include/arpa/nameser_compat.h b/user/include/mlibc/options/bsd/include/arpa/nameser_compat.h new file mode 100644 index 0000000..ee3b1a9 --- /dev/null +++ b/user/include/mlibc/options/bsd/include/arpa/nameser_compat.h @@ -0,0 +1 @@ +#include diff --git a/user/include/mlibc/options/bsd/include/bits/bsd/bsd_stdlib.h b/user/include/mlibc/options/bsd/include/bits/bsd/bsd_stdlib.h new file mode 100644 index 0000000..bb7c9a4 --- /dev/null +++ b/user/include/mlibc/options/bsd/include/bits/bsd/bsd_stdlib.h @@ -0,0 +1,20 @@ + +#ifndef MLIBC_BSD_STDLIB_H +#define MLIBC_BSD_STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int getloadavg(double *__loadavg, int __count); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_BSD_STDLIB_H */ + diff --git a/user/include/mlibc/options/bsd/include/bits/bsd/bsd_unistd.h b/user/include/mlibc/options/bsd/include/bits/bsd/bsd_unistd.h new file mode 100644 index 0000000..3d2de25 --- /dev/null +++ b/user/include/mlibc/options/bsd/include/bits/bsd/bsd_unistd.h @@ -0,0 +1,20 @@ +#ifndef _BSD_UNISTD_H +#define _BSD_UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +void *sbrk(intptr_t __increment); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSD_UNISTD_H */ diff --git a/user/include/mlibc/options/bsd/include/fstab.h b/user/include/mlibc/options/bsd/include/fstab.h new file mode 100644 index 0000000..2a445f0 --- /dev/null +++ b/user/include/mlibc/options/bsd/include/fstab.h @@ -0,0 +1,23 @@ +#ifndef _FSTAB_H +#define _FSTAB_H + +#define _PATH_FSTAB "/etc/fstab" +#define FSTAB "/etc/fstab" + +#define FSTAB_RW "rw" +#define FSTAB_RQ "rq" +#define FSTAB_RO "ro" +#define FSTAB_SW "sw" +#define FSTAB_XX "xx" + +struct fstab { + char *fs_spec; + char *fs_file; + char *fs_vfstype; + char *fs_mntops; + const char *fs_type; + int fs_freq; + int fs_passno; +}; + +#endif /* _FSTAB_H */ diff --git a/user/include/mlibc/options/bsd/include/mlibc/bsd-sysdeps.hpp b/user/include/mlibc/options/bsd/include/mlibc/bsd-sysdeps.hpp new file mode 100644 index 0000000..1ad202f --- /dev/null +++ b/user/include/mlibc/options/bsd/include/mlibc/bsd-sysdeps.hpp @@ -0,0 +1,16 @@ +#ifndef MLIBC_BSD_SYSDEPS +#define MLIBC_BSD_SYSDEPS + +#include + +namespace [[gnu::visibility("hidden")]] mlibc { + +[[gnu::weak]] int sys_brk(void **out); + +[[gnu::weak]] int sys_getloadavg(double *samples); + +[[gnu::weak]] int sys_openpty(int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win); + +} // namespace mlibc + +#endif // MLIBC_BSD_SYSDEPS diff --git a/user/include/mlibc/options/bsd/include/netinet/ether.h b/user/include/mlibc/options/bsd/include/netinet/ether.h new file mode 100644 index 0000000..c9add31 --- /dev/null +++ b/user/include/mlibc/options/bsd/include/netinet/ether.h @@ -0,0 +1,24 @@ +#ifndef _NETINET_ETHER_H +#define _NETINET_ETHER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *ether_ntoa(const struct ether_addr *__addr); +char *ether_ntoa_r(const struct ether_addr *__p_a, char *__x); + +struct ether_addr *ether_aton(const char *__asc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /*_NETINET_ETHER_H */ diff --git a/user/include/mlibc/options/bsd/include/pty.h b/user/include/mlibc/options/bsd/include/pty.h new file mode 100644 index 0000000..6379ae7 --- /dev/null +++ b/user/include/mlibc/options/bsd/include/pty.h @@ -0,0 +1,23 @@ + +#ifndef _PTY_H +#define _PTY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int openpty(int *__mfd, int *__sfd, char *__name, const struct termios *__ios, const struct winsize *__win); +int forkpty(int *__mfd, char *__name, const struct termios *__ios, const struct winsize *__win); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PTY_H */ + diff --git a/user/include/mlibc/options/bsd/include/sys/queue.h b/user/include/mlibc/options/bsd/include/sys/queue.h new file mode 100644 index 0000000..219066b --- /dev/null +++ b/user/include/mlibc/options/bsd/include/sys/queue.h @@ -0,0 +1,574 @@ +/* + * Copyright (c) 1991, 1993 + * 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (0) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* _SYS_QUEUE_H_ */ diff --git a/user/include/mlibc/options/bsd/include/utmp.h b/user/include/mlibc/options/bsd/include/utmp.h new file mode 100644 index 0000000..101d4d7 --- /dev/null +++ b/user/include/mlibc/options/bsd/include/utmp.h @@ -0,0 +1,24 @@ +#ifndef _UTMP_H +#define _UTMP_H + +#include + +#if __MLIBC_LINUX_OPTION +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int login_tty(int __fd); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UTMP_H */ diff --git a/user/include/mlibc/options/bsd/meson.build b/user/include/mlibc/options/bsd/meson.build new file mode 100644 index 0000000..f3e9fe8 --- /dev/null +++ b/user/include/mlibc/options/bsd/meson.build @@ -0,0 +1,37 @@ +if not bsd_option + subdir_done() +endif + +libc_sources += files( + 'generic/arpa-nameser.cpp', + 'generic/ether.cpp', + 'generic/getopt.cpp', + 'generic/bsd_stdlib.cpp', + 'generic/pty.cpp', +) + +if not no_headers + install_headers( + 'include/fstab.h', + 'include/pty.h', + 'include/utmp.h', + ) + install_headers( + 'include/arpa/nameser.h', + 'include/arpa/nameser_compat.h', + subdir: 'arpa' + ) + install_headers( + 'include/sys/queue.h', + subdir: 'sys' + ) + install_headers( + 'include/netinet/ether.h', + subdir: 'netinet' + ) + install_headers( + 'include/bits/bsd/bsd_stdlib.h', + 'include/bits/bsd/bsd_unistd.h', + subdir: 'bits/bsd' + ) +endif diff --git a/user/include/mlibc/options/elf/generic/phdr.cpp b/user/include/mlibc/options/elf/generic/phdr.cpp new file mode 100644 index 0000000..334d52c --- /dev/null +++ b/user/include/mlibc/options/elf/generic/phdr.cpp @@ -0,0 +1,10 @@ +#include + +#include +#include + +extern "C" int __dlapi_iterate_phdr(int (*)(struct dl_phdr_info*, size_t, void*), void *); + +int dl_iterate_phdr(int (*callback)(struct dl_phdr_info*, size_t, void*), void *data) { + return __dlapi_iterate_phdr(callback, data); +} diff --git a/user/include/mlibc/options/elf/generic/startup.cpp b/user/include/mlibc/options/elf/generic/startup.cpp new file mode 100644 index 0000000..e45a197 --- /dev/null +++ b/user/include/mlibc/options/elf/generic/startup.cpp @@ -0,0 +1,60 @@ + +#include +#include +#include +#include +#include +#include +#include + +extern "C" size_t __init_array_start[]; +extern "C" size_t __init_array_end[]; +extern "C" size_t __preinit_array_start[]; +extern "C" size_t __preinit_array_end[]; + +extern "C" uintptr_t *__dlapi_entrystack(); + +namespace mlibc { + +exec_stack_data entry_stack; + +[[gnu::constructor]] +void init_libc() { + mlibc::parse_exec_stack(__dlapi_entrystack(), &entry_stack); + mlibc::set_startup_data(entry_stack.argc, entry_stack.argv, entry_stack.envp); +} + +void parse_exec_stack(void *opaque_sp, exec_stack_data *data) { + auto sp = reinterpret_cast(opaque_sp); + data->argc = *sp++; + data->argv = reinterpret_cast(sp); + sp += data->argc; // Skip all arguments. + __ensure(!*sp); // Skip the terminating null element. + sp++; + data->envp = reinterpret_cast(sp); +} + +// TODO: This does not have to be here; we could also move it to options/internal. +void set_startup_data(int argc, char **argv, char **envp) { + if(argc) { + program_invocation_name = argv[0]; + + if(auto slash = strrchr(argv[0], '/'); slash) { + program_invocation_short_name = slash + 1; + }else{ + program_invocation_short_name = argv[0]; + } + } + + // Initialize environ. + // TODO: Copy the arguments instead of pointing to them? + auto ev = envp; + while(*ev) { + auto fail = mlibc::putenv(*ev); + __ensure(!fail); + ev++; + } +} + +} // namespace mlibc + diff --git a/user/include/mlibc/options/elf/include/elf.h b/user/include/mlibc/options/elf/include/elf.h new file mode 100644 index 0000000..78c6be8 --- /dev/null +++ b/user/include/mlibc/options/elf/include/elf.h @@ -0,0 +1,722 @@ +#ifndef _ELF_H +#define _ELF_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* TODO: Convert the enums to #defines so that they work with #ifdef. */ + +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define ELFOSABI_SYSV 0 +#define EM_X86_64 62 + +#define SHF_WRITE 1 +#define SHF_ALLOC 2 +#define SHF_EXECINSTR 4 +#define SHF_STRINGS 32 +#define SHF_INFO_LINK 64 +#define SHF_TLS 1024 + +#define NT_AUXV 6 + +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint16_t Elf64_Section; +typedef Elf64_Half Elf64_Versym; + +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint16_t Elf32_Section; +typedef Elf32_Half Elf32_Versym; + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Machine type */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point address */ + Elf32_Off e_phoff; /* Program header offset */ + Elf32_Off e_shoff; /* Section header offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* Size of program header entry */ + Elf32_Half e_phnum; /* Number of program header entries */ + Elf32_Half e_shentsize; /* Size of section header entry */ + Elf32_Half e_shnum; /* Number of section header entries */ + Elf32_Half e_shstrndx; /* Section name string table index */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Machine type */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point address */ + Elf64_Off e_phoff; /* Program header offset */ + Elf64_Off e_shoff; /* Section header offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size */ + Elf64_Half e_phentsize; /* Size of program header entry */ + Elf64_Half e_phnum; /* Number of program header entries */ + Elf64_Half e_shentsize; /* Size of section header entry */ + Elf64_Half e_shnum; /* Number of section header entries */ + Elf64_Half e_shstrndx; /* Section name string table index */ +} Elf64_Ehdr; + +typedef struct { + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef entry */ +} Elf32_Verdef; + +typedef struct { + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ +} Elf64_Verdef; + +typedef struct { + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux entry */ +} Elf32_Verdaux; + +typedef struct { + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */ +} Elf64_Verdaux; + +typedef struct { + Elf32_Half vn_version; + Elf32_Half vn_cnt; + Elf32_Word vn_file; + Elf32_Word vn_aux; + Elf32_Word vn_next; +} Elf32_Verneed; + +typedef struct { + Elf64_Half vn_version; + Elf64_Half vn_cnt; + Elf64_Word vn_file; + Elf64_Word vn_aux; + Elf64_Word vn_next; +} Elf64_Verneed; + +typedef struct { + Elf32_Word vna_hash; + Elf32_Half vna_flags; + Elf32_Half vna_other; + Elf32_Word vna_name; + Elf32_Word vna_next; +} Elf32_Vernaux; + +typedef struct { + Elf64_Word vna_hash; + Elf64_Half vna_flags; + Elf64_Half vna_other; + Elf64_Word vna_name; + Elf64_Word vna_next; +} Elf64_Vernaux; + +typedef struct { + Elf64_Xword m_value; + Elf64_Xword m_info; + Elf64_Xword m_poffset; + Elf64_Half m_repeat; + Elf64_Half m_stride; +} Elf64_Move; + +typedef struct { + Elf64_Word l_name; + Elf64_Word l_time_stamp; + Elf64_Word l_checksum; + Elf64_Word l_version; + Elf64_Word l_flags; +} Elf64_Lib; + +enum { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4 +}; + +enum { + SHN_UNDEF = 0, + SHN_ABS = 0xFFF1 +}; + +enum { + STN_UNDEF = 0 +}; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Section st_shndx; +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_BIND(unsigned char info) { + return info >> 4; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_TYPE(unsigned char info) { + return info & 0x0F; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_INFO(unsigned char bind, unsigned char type) { + return (bind << 4) | type; +} + +typedef struct { + Elf64_Half si_boundto; + Elf64_Half si_flags; +} Elf64_Syminfo; + +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_BIND(unsigned char info) { + return info >> 4; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_TYPE(unsigned char info) { + return info & 0xF; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_INFO(unsigned char bind, unsigned char type) { + return (bind << 4) | (type & 0xF); +} + +enum { + STB_GLOBAL = 1, + STB_WEAK = 2, + STB_GNU_UNIQUE = 10, + STB_LOPROC = 13, + STB_HIPROC = 15 +}; + +enum { + STT_OBJECT = 1, + STT_FUNC = 2, + STT_TLS = 6, + STT_GNU_IFUNC = 10, + STT_LOPROC = 13, + STT_HIPROC = 15 +}; + +enum { + R_X86_64_NONE = 0, + R_X86_64_64 = 1, + R_X86_64_PC32 = 2, + R_X86_64_PLT32 = 4, + R_X86_64_COPY = 5, + R_X86_64_GLOB_DAT = 6, + R_X86_64_JUMP_SLOT = 7, + R_X86_64_RELATIVE = 8, + R_X86_64_GOTPCREL = 9, + R_X86_64_32 = 10, + R_X86_64_32S = 11, + R_X86_64_PC16 = 13, + R_X86_64_PC8 = 15, + R_X86_64_DTPMOD64 = 16, + R_X86_64_DTPOFF64 = 17, + R_X86_64_TPOFF64 = 18, + R_X86_64_PC64 = 24, + R_X86_64_GOTPC32 = 26, + R_X86_64_TLSDESC = 36, + R_X86_64_IRELATIVE = 37 +}; + +enum { + R_386_NONE = 0, + R_386_32 = 1, + R_386_PC32 = 2, + R_386_COPY = 5, + R_386_GLOB_DAT = 6, + R_386_JMP_SLOT = 7, + R_386_RELATIVE = 8, + R_386_TLS_TPOFF = 14, + R_386_TLS_DTPMOD32 = 35, + R_386_TLS_DTPOFF32 = 36, + R_386_TLS_DESC = 41, + R_386_IRELATIVE = 42 +}; + +enum { + R_AARCH64_NONE = 0, + R_AARCH64_ABS64 = 257, + R_AARCH64_COPY = 1024, + R_AARCH64_GLOB_DAT = 1025, + R_AARCH64_JUMP_SLOT = 1026, + R_AARCH64_RELATIVE = 1027, + R_AARCH64_TLS_DTPMOD64 = 1028, + R_AARCH64_TLS_DTPREL64 = 1029, + R_AARCH64_TLS_TPREL64 = 1030, + R_AARCH64_TLSDESC = 1031, + R_AARCH64_IRELATIVE = 1032 +}; + +#define R_AARCH64_TLS_DTPREL R_AARCH64_TLS_DTPREL64 +#define R_AARCH64_TLS_DTPMOD R_AARCH64_TLS_DTPMOD64 +#define R_AARCH64_TLS_TPREL R_AARCH64_TLS_TPREL64 + +enum { + R_RISCV_NONE = 0, + R_RISCV_32 = 1, + R_RISCV_64 = 2, + R_RISCV_RELATIVE = 3, + R_RISCV_COPY = 4, + R_RISCV_JUMP_SLOT = 5, + R_RISCV_TLS_DTPMOD32 = 6, + R_RISCV_TLS_DTPMOD64 = 7, + R_RISCV_TLS_DTPREL32 = 8, + R_RISCV_TLS_DTPREL64 = 9, + R_RISCV_TLS_TPREL32 = 10, + R_RISCV_TLS_TPREL64 = 11, + R_RISCV_TLSDESC = 12, /* currently a draft but looking good */ + R_RISCV_IRELATIVE = 58 +}; + +enum { + R_68K_NONE = 0, + R_68K_32 = 1, + R_68K_PC32 = 4, + R_68K_COPY = 19, + R_68K_GLOB_DAT = 20, + R_68K_JMP_SLOT = 21, + R_68K_RELATIVE = 22, + + R_68K_TLS_DTPMOD32 = 40, + R_68K_TLS_DTPREL32= 41, + R_68K_TLS_TPREL32= 42 +}; + +enum { + R_LARCH_NONE = 0, + R_LARCH_32 = 1, + R_LARCH_64 = 2, + R_LARCH_RELATIVE = 3, + R_LARCH_COPY = 4, + R_LARCH_JUMP_SLOT = 5, + R_LARCH_TLS_DTPMOD32 = 6, + R_LARCH_TLS_DTPMOD64 = 7, + R_LARCH_TLS_DTPREL32 = 8, + R_LARCH_TLS_DTPREL64 = 9, + R_LARCH_TLS_TPREL32 = 10, + R_LARCH_TLS_TPREL64 = 11, + R_LARCH_IRELATIVE = 12 +}; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf64_Addr r_offset; + uint64_t r_info; +} Elf64_Rel; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +typedef Elf32_Word Elf32_Relr; +typedef Elf64_Xword Elf64_Relr; + +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_SYM(Elf64_Xword info) { + return info >> 32; +} +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_TYPE(Elf64_Xword info) { + return info & 0xFFFFFFFF; +} +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_INFO(Elf64_Xword sym, Elf64_Xword type) { + return ((((Elf64_Xword)(sym)) << 32) + (type)); +} + +__MLIBC_INLINE_DEFINITION Elf32_Word ELF32_R_SYM(Elf32_Word info) { + return info >> 8; +} +__MLIBC_INLINE_DEFINITION Elf32_Word ELF32_R_TYPE(Elf32_Word info) { + return info & 0xFF; +} + +enum { + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_TLS = 7, + PT_NUM = 8, + PT_LOOS = 0x60000000, + PT_GNU_EH_FRAME = 0x6474E550, + PT_GNU_STACK = 0x6474E551, + PT_GNU_RELRO = 0x6474E552, + PT_GNU_PROPERTY = 0x6474E553, + PT_SUNWBSS = 0x6ffffffa, + PT_SUNWSTACK = 0x6ffffffb, + PT_HISUNW = 0x6fffffff, + PT_HIOS = 0x6fffffff, + PT_LOPROC = 0x70000000, + PT_ARM_EXIDX = 0x70000001, + PT_RISCV_ATTRIBUTES = 0x70000003, + PT_HIPROC = 0x7fffffff +}; + +enum { + PF_X = 1, + PF_W = 2, + PF_R = 4 +}; + +typedef struct { + Elf32_Word p_type; /* Type of segment */ + Elf32_Off p_offset; /* Offset in file */ + Elf32_Addr p_vaddr; /* Virtual address in memory */ + Elf32_Addr p_paddr; /* Reserved */ + Elf32_Word p_filesz; /* Size of segment in file */ + Elf32_Word p_memsz; /* Size of segment in memory */ + Elf32_Word p_flags; /* Segment attributes */ + Elf32_Word p_align; /* Alignment of segment */ +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; /* Type of segment */ + Elf64_Word p_flags; /* Segment attributes */ + Elf64_Off p_offset; /* Offset in file */ + Elf64_Addr p_vaddr; /* Virtual address in memory */ + Elf64_Addr p_paddr; /* Reserved */ + Elf64_Xword p_filesz; /* Size of segment in file */ + Elf64_Xword p_memsz; /* Size of segment in memory */ + Elf64_Xword p_align; /* Alignment of segment */ +} Elf64_Phdr; + +enum { + DT_NULL = 0, + DT_NEEDED = 1, + DT_PLTRELSZ = 2, + DT_PLTGOT = 3, + DT_HASH = 4, + DT_STRTAB = 5, + DT_SYMTAB = 6, + DT_RELA = 7, + DT_RELASZ = 8, + DT_RELAENT = 9, + DT_STRSZ = 10, + DT_SYMENT = 11, + DT_INIT = 12, + DT_FINI = 13, + DT_SONAME = 14, + DT_RPATH = 15, + DT_SYMBOLIC = 16, + DT_REL = 17, + DT_RELSZ = 18, + DT_RELENT = 19, + DT_TEXTREL = 22, + DT_BIND_NOW = 24, + DT_INIT_ARRAY = 25, + DT_FINI_ARRAY = 26, + DT_INIT_ARRAYSZ = 27, + DT_FINI_ARRAYSZ = 28, + DT_RUNPATH = 29, + DT_PLTREL = 20, + DT_DEBUG = 21, + DT_JMPREL = 23, + DT_FLAGS = 30, + DT_PREINIT_ARRAY = 32, + DT_PREINIT_ARRAYSZ = 33, + DT_RELRSZ = 35, + DT_RELR = 36, + DT_RELRENT = 37, + DT_LOOS = 0x6000000d, + DT_HIOS = 0x6ffff000, + DT_GNU_HASH = 0x6ffffef5, + DT_TLSDESC_PLT = 0x6ffffef6, + DT_TLSDESC_GOT = 0x6ffffef7, + DT_VERSYM = 0x6ffffff0, + DT_RELACOUNT = 0x6ffffff9, + DT_RELCOUNT = 0x6ffffffa, + DT_FLAGS_1 = 0x6ffffffb, + DT_VERDEF = 0x6ffffffc, + DT_VERDEFNUM = 0x6ffffffd, + DT_VERNEED = 0x6ffffffe, + DT_VERNEEDNUM = 0x6fffffff, + DT_LOPROC = 0x70000000, + DT_HIPROC = 0x7fffffff +}; + +enum { + /* For DT_FLAGS. */ + DF_SYMBOLIC = 0x02, + DF_TEXTREL = 0x04, + DF_BIND_NOW = 0x08, + DF_STATIC_TLS = 0x10, + + /* For DT_FLAGS_1. */ + DF_1_NOW = 0x00000001, + DF_1_NODELETE = 0x00000008, + DF_1_PIE = 0x08000000 +}; + +/* Valid values for note segment descriptor files for core files */ +#define NT_PRSTATUS 1 +#define NT_FPREGSET 2 +#define NT_PRPSINFO 3 + +/* Build ID bits as generated by ld --build-id */ +#define NT_GNU_BUILD_ID 3 + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + +typedef struct { + uint64_t a_type; + union { + uint64_t a_val; + } a_un; +} Elf64_auxv_t; + +typedef struct { + uint32_t a_type; + union { + uint32_t a_val; + } a_un; +} Elf32_auxv_t; + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + +/* ST_TYPE (subfield of st_info) values (symbol type) */ +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +/* ST_BIND (subfield of st_info) values (symbol binding) */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +/* sh_type (section type) values */ +#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_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_SYMTAB_SHNDX 18 + +/* special section indices */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff +#define SHN_HIRESERVE 0xff00 + +/* values for e_machine */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_MIPS 8 +#define EM_PARISC 15 +#define EM_PPC 20 +#define EM_PPC64 21 +#define EM_S390 22 +#define EM_ARM 40 +#define EM_SH 42 +#define EM_SPARCV9 43 +#define EM_IA_64 50 +#define EM_X86_64 62 +#define EM_BLACKFIN 106 +#define EM_AARCH64 183 +#define EM_RISCV 243 +#define EM_LOONGARCH 258 + +/* Linux notes this value as being interim; however applications are using this (Qt6), so we define it here. */ +#define EM_ALPHA 0x9026 + +/* values for e_version */ +#define EV_NONE 0 +#define EV_CURRENT 1 +#define EV_NUM 2 + +/* e_indent constants */ +#define EI_MAG0 0 +#define ELFMAG0 0x7f + +#define EI_MAG1 1 +#define ELFMAG1 'E' + +#define EI_MAG2 2 +#define ELFMAG2 'L' + +#define EI_MAG3 3 +#define ELFMAG3 'F' + +#define ELFMAG "\177ELF" +#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_HPUX 1 +#define ELFOSABI_NETBSD 2 +#define ELFOSABI_GNU 3 +#define ELFOSABI_LINUX ELFOSABI_GNU +#define ELFOSABI_SOLARIS 6 +#define ELFOSABI_AIX 7 +#define ELFOSABI_IRIX 8 +#define ELFOSABI_FREEBSD 9 +#define ELFOSABI_OPENBSD 12 + +#define EI_ABIVERSION 8 + +#define ELF_NOTE_GNU "GNU" + +/* Values for a_type + * these are standard values and shared across at least glibc, musl and freebsd + */ + +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_NOTELF 10 +#define AT_UID 11 +#define AT_EUID 12 +#define AT_GID 13 +#define AT_EGID 14 + +/* Values for Elfxx_Verdef::vd_flags and Elfxx_Vernaux::vna_flags */ +#define VER_FLG_BASE 1 /* Version definition of the file itself */ +#define VER_FLG_WEAK 2 /* Weak version identifier */ + +/* rtld requires presence of some a_type (AT_*) values that are not standardized in the ELF spec */ +#if !defined(AT_EXECFN) || !defined(AT_RANDOM) || !defined(AT_SECURE) +#error "sysdeps' auxv.h is missing some defines that are required for rtld operation" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ELF_H */ diff --git a/user/include/mlibc/options/elf/include/link.h b/user/include/mlibc/options/elf/include/link.h new file mode 100644 index 0000000..91a5fb6 --- /dev/null +++ b/user/include/mlibc/options/elf/include/link.h @@ -0,0 +1,58 @@ +#ifndef _LINK_H +#define _LINK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#if defined(__x86_64__) || defined(__aarch64__) \ + || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +# define ElfW(type) Elf64_ ## type +#elif defined(__i386__) || defined(__m68k__) +# define ElfW(type) Elf32_ ## type +#else +# error Unknown architecture +#endif + +struct dl_phdr_info { + ElfW(Addr) dlpi_addr; + const char *dlpi_name; + const ElfW(Phdr) *dlpi_phdr; + ElfW(Half) dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + size_t dlpi_tls_modid; + void *dlpi_tls_data; +}; + +struct link_map { + Elf64_Addr l_addr; + char *l_name; + ElfW(Dyn) *l_ld; + struct link_map *l_next, *l_prev; +}; + +struct r_debug { + int r_version; + struct link_map *r_map; + Elf64_Addr r_brk; + enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state; + Elf64_Addr r_ldbase; +}; + +#ifndef __MLIBC_ABI_ONLY + +int dl_iterate_phdr(int (*__callback)(struct dl_phdr_info* __info, size_t __size, void* __data), void* __data); + +extern ElfW(Dyn) _DYNAMIC[]; + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LINK_H */ diff --git a/user/include/mlibc/options/elf/include/mlibc/elf/startup.h b/user/include/mlibc/options/elf/include/mlibc/elf/startup.h new file mode 100644 index 0000000..b7db485 --- /dev/null +++ b/user/include/mlibc/options/elf/include/mlibc/elf/startup.h @@ -0,0 +1,24 @@ +#ifndef MLIBC_ELF_STARTUP +#define MLIBC_ELF_STARTUP + +namespace mlibc { + +struct exec_stack_data { + int argc; + char **argv; + char **envp; +}; + +extern exec_stack_data entry_stack; + +#ifndef __MLIBC_ABI_ONLY + +void parse_exec_stack(void *sp, exec_stack_data *data); + +void set_startup_data(int argc, char **argv, char **envp); + +#endif /* !__MLIBC_ABI_ONLY */ + +} /* namespace mlibc */ + +#endif /* MLIBC_ELF_STARTUP */ diff --git a/user/include/mlibc/options/elf/meson.build b/user/include/mlibc/options/elf/meson.build new file mode 100644 index 0000000..b096801 --- /dev/null +++ b/user/include/mlibc/options/elf/meson.build @@ -0,0 +1,11 @@ +libc_sources += files( + 'generic/startup.cpp', + 'generic/phdr.cpp', +) + +if not no_headers + install_headers( + 'include/elf.h', + 'include/link.h', + ) +endif diff --git a/user/include/mlibc/options/glibc/generic/err.cpp b/user/include/mlibc/options/glibc/generic/err.cpp new file mode 100644 index 0000000..3d79545 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/err.cpp @@ -0,0 +1,64 @@ +#include + +#include +#include +#include + +// va_list + +void vwarn(const char *fmt, va_list params) { + fprintf(stderr, "%s: ", program_invocation_short_name); + if (fmt) { + vfprintf(stderr, fmt, params); + fwrite(": ", 1, 2, stderr); + } + perror(nullptr); +} + +void vwarnx(const char *fmt, va_list params) { + fprintf(stderr, "%s: ", program_invocation_short_name); + if (fmt) { + vfprintf(stderr, fmt, params); + } + putc('\n', stderr); +} + +__attribute__((__noreturn__)) void verr(int status, const char *fmt, va_list params) { + vwarn(fmt, params); + exit(status); +} + +__attribute__((__noreturn__)) void verrx(int status, const char *fmt, va_list params) { + vwarnx(fmt, params); + exit(status); +} + +// variadic + +void warn(const char *fmt, ...) { + va_list params; + va_start(params, fmt); + vwarn(fmt, params); + va_end(params); +} + +void warnx(const char *fmt, ...) { + va_list params; + va_start(params, fmt); + vwarnx(fmt, params); + va_end(params); +} + +__attribute__((__noreturn__)) void err(int status, const char *fmt, ...) { + va_list params; + va_start(params, fmt); + verr(status, fmt, params); + va_end(params); +} + +__attribute__((__noreturn__)) void errx(int status, const char *fmt, ...) { + va_list params; + va_start(params, fmt); + verrx(status, fmt, params); + va_end(params); +} diff --git a/user/include/mlibc/options/glibc/generic/error.cpp b/user/include/mlibc/options/glibc/generic/error.cpp new file mode 100644 index 0000000..e92cae4 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/error.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +unsigned int error_message_count = 0; +int error_one_per_line = 0; +void (*error_print_progname)(void) = nullptr; + +void error(int status, int errnum, const char *format, ...) { + va_list args; + va_start(args, format); + + error_message_count++; + + fflush(stdout); + if(error_print_progname) { + error_print_progname(); + } else { + fprintf(stderr, "%s: ", program_invocation_name); + } + vfprintf(stderr, format, args); + va_end(args); + + if(errnum) { + fprintf(stderr, ": %s\n", strerror(errnum)); + } + + if(status) { + exit(status); + } +} + +void error_at_line(int status, int errnum, const char *filename, unsigned int linenum, const char *format, ...) { + va_list args; + va_start(args, format); + + static bool first_call = true; + static unsigned int last_line = 0; + if(!(last_line == linenum && error_one_per_line && !first_call)) { + first_call = false; + last_line = linenum; + error_message_count++; + + fflush(stdout); + if(error_print_progname) { + error_print_progname(); + } else { + fprintf(stderr, "%s:", program_invocation_name); + } + fprintf(stderr, "%s:%u: ", filename, linenum); + vfprintf(stderr, format, args); + + if(errnum) { + fprintf(stderr, ": %s\n", strerror(errnum)); + } + } + va_end(args); + + if(status) { + exit(status); + } +} diff --git a/user/include/mlibc/options/glibc/generic/execinfo.cpp b/user/include/mlibc/options/glibc/generic/execinfo.cpp new file mode 100644 index 0000000..119574e --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/execinfo.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + +using UnwindBacktrace = _Unwind_Reason_Code (*)(_Unwind_Trace_Fn, void *); +using UnwindGetIP = _Unwind_Ptr (*)(_Unwind_Context *); + +frg::optional libgccHandle = frg::null_opt; + +UnwindBacktrace unwindBacktrace = nullptr; +UnwindGetIP unwindGetIP = nullptr; + +struct UnwindState { + void **frames; + int count; + int current_frame = 0; +}; + +_Unwind_Reason_Code trace(_Unwind_Context *context, void *arg) { + UnwindState *state = static_cast(arg); + + if (state->current_frame >= state->count) + return _URC_END_OF_STACK; + + uintptr_t ip = unwindGetIP(context); + + if (ip) { +#if defined(__x86_64__) || defined(__i386__) + ip--; +#elif defined(__aarch64__) || defined(__loongarch64) + ip -= 4; +#elif defined(__riscv) || defined(__m68k__) + ip -= 2; +#else +#warning "Missing support for architecture" + ip--; +#endif + } + + state->frames[state->current_frame++] = reinterpret_cast(ip); + return _URC_NO_REASON; +} + +} // namespace + +int backtrace(void **buffer, int size) { + if (size <= 0) + return 0; + + if (!libgccHandle) { + libgccHandle = dlopen("libgcc_s.so.1", RTLD_LAZY | RTLD_LOCAL); + if (!libgccHandle || libgccHandle.value() == nullptr) { + mlibc::infoLogger() << "Failed to load libgcc_s.so.1: " << (dlerror() ? dlerror() : "") << frg::endlog; + return 0; + } + + unwindBacktrace = reinterpret_cast(dlsym(libgccHandle.value(), "_Unwind_Backtrace")); + unwindGetIP = reinterpret_cast(dlsym(libgccHandle.value(), "_Unwind_GetIP")); + + if (!unwindBacktrace || !unwindGetIP) { + mlibc::infoLogger() << "Failed to find unwind functions in libgcc_s.so.1: " << dlerror() << frg::endlog; + return 0; + } + } + + UnwindState state{buffer, size}; + unwindBacktrace(trace, &state); + return state.current_frame; +} + +char **backtrace_symbols(void *const *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void backtrace_symbols_fd(void *const *buffer, int size, int fd) { + if (size <= 0 || fd < 0) + return; + + for (int frame_num = 0; frame_num < size; frame_num++) { + Dl_info info; + if (dladdr(buffer[frame_num], &info) != 0) { + if (info.dli_fname != nullptr) + write(fd, info.dli_fname, strlen(info.dli_fname)); + + if (info.dli_sname != nullptr) + dprintf(fd, "(%s+0x%" PRIxPTR ") ", info.dli_sname, + reinterpret_cast(buffer[frame_num]) - reinterpret_cast(info.dli_saddr)); + else if(info.dli_saddr) + dprintf(fd, "(+%p) ", info.dli_saddr); + else + dprintf(fd, "() "); + } + + dprintf(fd, "[%p]\n", buffer[frame_num]); + } +} diff --git a/user/include/mlibc/options/glibc/generic/getopt.cpp b/user/include/mlibc/options/glibc/generic/getopt.cpp new file mode 100644 index 0000000..d04f063 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/getopt.cpp @@ -0,0 +1,12 @@ +#include +#include + +int getopt_long(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int *longindex) { + return getopt_common(argc, argv, optstring, longopts, longindex, mlibc::GetoptMode::Long); +} + +int getopt_long_only(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int *longindex) { + return getopt_common(argc, argv, optstring, longopts, longindex, mlibc::GetoptMode::LongOnly); +} diff --git a/user/include/mlibc/options/glibc/generic/glibc-assert.cpp b/user/include/mlibc/options/glibc/generic/glibc-assert.cpp new file mode 100644 index 0000000..77cd498 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/glibc-assert.cpp @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +#include + +[[gnu::noreturn]] void __assert_fail_perror(int errno, const char *file, unsigned int line, + const char *function) { + char *errormsg = strerror(errno); + fprintf(stderr, "In function %s, file %s:%d: Errno '%s' failed!\n", + function, file, line, errormsg); + abort(); +} diff --git a/user/include/mlibc/options/glibc/generic/glibc-signal.cpp b/user/include/mlibc/options/glibc/generic/glibc-signal.cpp new file mode 100644 index 0000000..41bc455 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/glibc-signal.cpp @@ -0,0 +1,14 @@ +#include +#include +#include +#include +#include + +int tgkill(int tgid, int tid, int sig) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tgkill, -1); + if(int e = mlibc::sys_tgkill(tgid, tid, sig); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/glibc/generic/gshadow.cpp b/user/include/mlibc/options/glibc/generic/gshadow.cpp new file mode 100644 index 0000000..f93a47d --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/gshadow.cpp @@ -0,0 +1,7 @@ +#include +#include + +int getsgnam_r(const char *, struct sgrp *, char *, size_t, struct sgrp **) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/glibc/generic/malloc.cpp b/user/include/mlibc/options/glibc/generic/malloc.cpp new file mode 100644 index 0000000..b5a4daf --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/malloc.cpp @@ -0,0 +1,6 @@ +#include +#include + +size_t malloc_usable_size(void *p) { + return getAllocator().get_size(p); +} diff --git a/user/include/mlibc/options/glibc/generic/personality.cpp b/user/include/mlibc/options/glibc/generic/personality.cpp new file mode 100644 index 0000000..3bfd9aa --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/personality.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +int personality(unsigned long persona) { + int out = 0; + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_personality, -1); + + if(int e = sysdep(persona, &out); e) { + errno = e; + return -1; + } + return out; +} diff --git a/user/include/mlibc/options/glibc/generic/printf.cpp b/user/include/mlibc/options/glibc/generic/printf.cpp new file mode 100644 index 0000000..4abb00d --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/printf.cpp @@ -0,0 +1,7 @@ +#include +#include + +size_t parse_printf_format(const char * __restrict, size_t, int * __restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/glibc/generic/resolv.cpp b/user/include/mlibc/options/glibc/generic/resolv.cpp new file mode 100644 index 0000000..2699777 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/resolv.cpp @@ -0,0 +1,41 @@ +#include +#include +#include + +int dn_expand(const unsigned char *, const unsigned char *, + const unsigned char *, char *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int res_query(const char *, int, int, unsigned char *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int res_init() { + mlibc::infoLogger() << "mlibc: res_init is a stub!" << frg::endlog; + return 0; +} + +int res_ninit(res_state) { + mlibc::infoLogger() << "mlibc: res_ninit is a stub!" << frg::endlog; + return 0; +} + +void res_nclose(res_state) { + mlibc::infoLogger() << "mlibc: res_nclose is a stub!" << frg::endlog; + return; +} + +int dn_comp(const char *, unsigned char *, int, unsigned char **, unsigned char **) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +/* This is completely unused, and exists purely to satisfy broken apps. */ + +struct __res_state *__res_state() { + static struct __res_state res; + return &res; +} diff --git a/user/include/mlibc/options/glibc/generic/search.cpp b/user/include/mlibc/options/glibc/generic/search.cpp new file mode 100644 index 0000000..52a578f --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/search.cpp @@ -0,0 +1,14 @@ +#include +#include + +int hcreate_r(size_t num_entries, hsearch_data *htab) { + return mlibc::hcreate_r(num_entries, htab); +} + +void hdestroy_r(hsearch_data *htab) { + mlibc::hdestroy_r(htab); +} + +int hsearch_r(ENTRY item, ACTION action, ENTRY **ret, hsearch_data *htab) { + return mlibc::hsearch_r(item, action, ret, htab); +} diff --git a/user/include/mlibc/options/glibc/generic/shadow.cpp b/user/include/mlibc/options/glibc/generic/shadow.cpp new file mode 100644 index 0000000..38fdb77 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/shadow.cpp @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * The code in this file is largely based on or taken from musl. + * This includes: + * - xatol + * - __parsespent + * - cleanup + * - getspnam_r + * - getspnam + */ +#define NUM(n) ((n) == -1 ? 0 : -1), ((n) == -1 ? 0 : (n)) + +int putspent(const struct spwd *sp, FILE *f) { + auto str = [] (char *s) { + return ((s) ? (s) : ""); + }; + return fprintf(f, "%s:%s:%.*ld:%.*ld:%.*ld:%.*ld:%.*ld:%.*ld:%.*u\n", + str(sp->sp_namp), str(sp->sp_pwdp), NUM(sp->sp_lstchg), + NUM(sp->sp_min), NUM(sp->sp_max), NUM(sp->sp_warn), + NUM(sp->sp_inact), NUM(sp->sp_expire), NUM((int)sp->sp_flag)) < 0 ? -1 : 0; +} +#undef NUM + +static long xatol(char **s) { + long x; + if(**s == ':' || **s == '\n') { + return -1; + } + for(x = 0; (unsigned int)**s - '0' < 10U; ++*s) { + x = 10 * x + (**s - '0'); + } + return x; +} + +static int __parsespent(char *s, struct spwd *sp) { + sp->sp_namp = s; + if(!(s = strchr(s, ':'))) { + return -1; + } + *s = 0; + + sp->sp_pwdp = ++s; + if(!(s = strchr(s, ':'))) { + return -1; + } + *s = 0; + + s++; + sp->sp_lstchg = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_min = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_max = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_warn = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_inact = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_expire = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_flag = xatol(&s); + if(*s != '\n') { + return -1; + } + return 0; +} + +static void cleanup(void *p) { + fclose((FILE *)p); +} + +int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res) { + char path[20 + NAME_MAX]; + FILE *f = nullptr; + int rv = 0; + int fd; + size_t k, l = strlen(name); + int skip = 0; + int cs; + int orig_errno = errno; + + *res = nullptr; + + /* Disallow potentially-malicious user names */ + if(*name=='.' || strchr(name, '/') || !l) { + return errno = EINVAL; + } + + /* Buffer size must at least be able to hold name, plus some.. */ + if(size < l + 100) { + return errno = ERANGE; + } + + /* Protect against truncation */ + if(snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= (int)sizeof path) { + return errno = EINVAL; + } + + fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC); + if(fd >= 0) { + struct stat st = {}; + errno = EINVAL; + if(fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) { + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + close(fd); + pthread_setcancelstate(cs, nullptr); + return errno; + } + } else { + if(errno != ENOENT && errno != ENOTDIR) { + return errno; + } + f = fopen("/etc/shadow", "rbe"); + if(!f) { + if(errno != ENOENT && errno != ENOTDIR) { + return errno; + } + return 0; + } + } + + pthread_cleanup_push(cleanup, f); + while(fgets(buf, size, f) && (k = strlen(buf)) > 0) { + if(skip || strncmp(name, buf, l) || buf[l] != ':') { + skip = buf[k - 1] != '\n'; + continue; + } + if(buf[k - 1] != '\n') { + rv = ERANGE; + break; + } + + if(__parsespent(buf, sp) < 0) { + continue; + } + *res = sp; + break; + } + pthread_cleanup_pop(1); + errno = rv ? rv : orig_errno; + return rv; +} + +int lckpwdf(void) { + mlibc::infoLogger() << "mlibc: lckpwdf is unimplemented like musl" << frg::endlog; + return 0; +} + +int ulckpwdf(void) { + mlibc::infoLogger() << "mlibc: ulckpwdf is unimplemented like musl" << frg::endlog; + return 0; +} + +// Musl defines LINE_LIM to 256 +#define LINE_LIM 256 + +struct spwd *getspnam(const char *name) { + static struct spwd sp; + static char *line; + struct spwd *res; + int e; + int orig_errno = errno; + + if(!line) { + line = (char *)malloc(LINE_LIM); + } + if(!line) { + return nullptr; + } + e = getspnam_r(name, &sp, line, LINE_LIM, &res); + errno = e ? e : orig_errno; + return res; +} + +struct spwd *fgetspent(FILE *f) { + static struct spwd sp; + static char *line; + struct spwd *res = nullptr; + size_t size = 0; + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + if(getline(&line, &size, f) >= 0 && __parsespent(line, &sp) >= 0) { + res = &sp; + } + pthread_setcancelstate(cs, nullptr); + return res; +} + +void endspent(void) { + mlibc::infoLogger() << "mlibc: endspent is a stub" << frg::endlog; +} + +struct spwd *sgetspent(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/glibc/generic/stdio_ext.cpp b/user/include/mlibc/options/glibc/generic/stdio_ext.cpp new file mode 100644 index 0000000..be8a861 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/stdio_ext.cpp @@ -0,0 +1,84 @@ + +#include +#include +#include +#include + +size_t __fbufsize(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +size_t __fpending(FILE *file_base) { + __ensure(file_base->__dirty_end >= file_base->__dirty_begin); + return file_base->__dirty_end - file_base->__dirty_begin; +} + +int __flbf(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +int __freadable(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +int __fwritable(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int __freading(FILE *file_base) { + return file_base->__io_mode == 0; +} + +int __fwriting(FILE *file_base) { + return file_base->__io_mode == 1; +} + +int __fsetlocking(FILE *file_base, int state) { + auto file = static_cast(file_base); + bool oldstate = file->_lock.uselock; + if (state != FSETLOCKING_QUERY) { + if (state == FSETLOCKING_BYCALLER) { + file->_lock.uselock = false; + } else { + file->_lock.uselock = true; + } + } + if (oldstate) { + return FSETLOCKING_INTERNAL; + } else { + return FSETLOCKING_BYCALLER; + } +} + +void _flushlbf(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// The following functions are defined by musl. + +size_t __freadahead(FILE *file_base) { + if(file_base->__io_mode != 0) { + mlibc::infoLogger() << "mlibc: __freadahead() called but file is not open for reading" << frg::endlog; + return 0; + } + return file_base->__valid_limit - file_base->__offset; +} + +const char *__freadptr(FILE *, size_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void __freadptrinc(FILE *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void __fseterr(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + diff --git a/user/include/mlibc/options/glibc/generic/stdlib.cpp b/user/include/mlibc/options/glibc/generic/stdlib.cpp new file mode 100644 index 0000000..bb1d071 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/stdlib.cpp @@ -0,0 +1,11 @@ +#include + +int rpmatch(const char *resp) { + if(!resp || resp[0] == '\0') + return -1; + if(resp[0] == 'y' || resp[0] == 'Y') + return 1; + if(resp[0] == 'n' || resp[0] == 'N') + return 0; + return -1; +} diff --git a/user/include/mlibc/options/glibc/generic/string.cpp b/user/include/mlibc/options/glibc/generic/string.cpp new file mode 100644 index 0000000..19f77c7 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/string.cpp @@ -0,0 +1,32 @@ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include +#include + +/* This is a bit of a weird detail of the GNU implementation and C's lack of + * overloading and strictness: GNU takes const char * and returns a char * so + * that it autocasts to your desired constness, this function never actually + * modifies the string. + */ +char *__mlibc_gnu_basename_c(const char *path) { + char *basename_component = strrchr(path, '/'); + if (!basename_component) { + return const_cast(path); + } + return basename_component + 1; +} + + +/* GNU exposes these overloads, and as a result, we should probably have them + * checked, to make sure we actually match expectations. + */ +static_assert( + std::is_same_v, + "C++ overloads broken" +); + +static_assert( + std::is_same_v, + "C++ overloads broken" +); diff --git a/user/include/mlibc/options/glibc/generic/sys-cachectl.cpp b/user/include/mlibc/options/glibc/generic/sys-cachectl.cpp new file mode 100644 index 0000000..a57dac9 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/sys-cachectl.cpp @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +#ifdef __riscv +int __riscv_flush_icache(void *start, void *end, unsigned long flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_riscv_flush_icache, -1); + + if(int e = sysdep(start, end, flags); e) { + errno = e; + return -1; + } + return 0; +} +#endif diff --git a/user/include/mlibc/options/glibc/generic/sys-io.cpp b/user/include/mlibc/options/glibc/generic/sys-io.cpp new file mode 100644 index 0000000..fbd9070 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/sys-io.cpp @@ -0,0 +1,25 @@ +#include +#include + +#include +#include + +int ioperm(unsigned long int from, unsigned long int num, int turn_on) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ioperm, -1); + + if(int e = sysdep(from, num, turn_on); e) { + errno = e; + return -1; + } + return 0; +} + +int iopl(int level) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_iopl, -1); + + if(int e = sysdep(level); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/glibc/generic/sys-ioctl.cpp b/user/include/mlibc/options/glibc/generic/sys-ioctl.cpp new file mode 100644 index 0000000..021d2a3 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/sys-ioctl.cpp @@ -0,0 +1,21 @@ + +#include +#include + +#include +#include +#include + +int ioctl(int fd, unsigned long request, ...) { + va_list args; + va_start(args, request); + int result; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ioctl, -1); + void *arg = va_arg(args, void *); + if(int e = mlibc::sys_ioctl(fd, request, arg, &result); e) { + errno = e; + return -1; + } + return result; +} + diff --git a/user/include/mlibc/options/glibc/generic/sys-timex.cpp b/user/include/mlibc/options/glibc/generic/sys-timex.cpp new file mode 100644 index 0000000..6173399 --- /dev/null +++ b/user/include/mlibc/options/glibc/generic/sys-timex.cpp @@ -0,0 +1,17 @@ +#include +#include + +int adjtimex(struct timex *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int clock_adjtime(clockid_t, struct timex *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int ntp_adjtime(struct timex *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/glibc/include/ar.h b/user/include/mlibc/options/glibc/include/ar.h new file mode 100644 index 0000000..c7a9f38 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/ar.h @@ -0,0 +1,27 @@ + +#ifndef _AR_H +#define _AR_H + +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6]; + char ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/glibc/include/bits/glibc/glibc_assert.h b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_assert.h new file mode 100644 index 0000000..9165d29 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_assert.h @@ -0,0 +1,32 @@ +#ifndef MLIBC_GLIBC_ASSERT_H +#define MLIBC_GLIBC_ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +__attribute__ ((__noreturn__)) void __assert_fail_perror(int __errno, const char *__file, unsigned int __line, + const char *__function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_GLIBC_ASSERT_H */ + +#ifdef NDEBUG + +#undef assert_perror +#define assert_perror(ignore) ((void)0) + +#else /* NDEBUG */ + +#undef assert_perror +#define assert_perror(errno) (!(errno) \ + || (__assert_fail_perror((errno), __FILE__, __LINE__, __func__), 0)) + +#endif /* NDEBUG */ diff --git a/user/include/mlibc/options/glibc/include/bits/glibc/glibc_icmp6.h b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_icmp6.h new file mode 100644 index 0000000..eafde16 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_icmp6.h @@ -0,0 +1,21 @@ +#ifndef _GLIBC_NETINET_ICMP6_H +#define _GLIBC_NETINET_ICMP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define ND_OPT_PREFIX_INFORMATION 3 +#define ND_OPT_REDIRECTED_HEADER 4 +#define ND_OPT_MTU 5 +#define ND_OPT_RTR_ADV_INTERVAL 7 +#define ND_OPT_HOME_AGENT_INFO 8 + +#ifdef __cplusplus +} +#endif + +#endif /* _GLIBC_NETINET_ICMP6_H */ + diff --git a/user/include/mlibc/options/glibc/include/bits/glibc/glibc_malloc.h b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_malloc.h new file mode 100644 index 0000000..62cf009 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_malloc.h @@ -0,0 +1,17 @@ +#ifndef _GLIBC_MALLOC_H +#define _GLIBC_MALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +size_t malloc_usable_size(void *__ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* _GLIBC_MALLOC_H */ + diff --git a/user/include/mlibc/options/glibc/include/bits/glibc/glibc_search.h b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_search.h new file mode 100644 index 0000000..338bb28 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_search.h @@ -0,0 +1,22 @@ +#ifndef _GLIBC_SEARCH_H +#define _GLIBC_SEARCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int hcreate_r(size_t __num_entries, struct hsearch_data *__htab); +void hdestroy_r(struct hsearch_data *__htab); +int hsearch_r(ENTRY __item, ACTION __action, ENTRY **__ret, struct hsearch_data *__htab); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _GLIBC_SEARCH_H */ diff --git a/user/include/mlibc/options/glibc/include/bits/glibc/glibc_signal.h b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_signal.h new file mode 100644 index 0000000..4761aba --- /dev/null +++ b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_signal.h @@ -0,0 +1,24 @@ +#ifndef MLIBC_GLIBC_SIGNAL_H +#define MLIBC_GLIBC_SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int tgkill(int __tgid, int __tid, int __sig); + +#if defined(_GNU_SOURCE) + +typedef void (*sighandler_t)(int __signo); + +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_GLIBC_SIGNAL_H */ diff --git a/user/include/mlibc/options/glibc/include/bits/glibc/glibc_stdlib.h b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_stdlib.h new file mode 100644 index 0000000..99724b7 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/bits/glibc/glibc_stdlib.h @@ -0,0 +1,20 @@ +#ifndef MLIBC_GLIBC_STDLIB_H +#define MLIBC_GLIBC_STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*comparison_fn_t) (const void *__a, const void *__b); + +#ifndef __MLIBC_ABI_ONLY + +int rpmatch(const char *__resp); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_GLIBC_STDLIB_H */ diff --git a/user/include/mlibc/options/glibc/include/endian.h b/user/include/mlibc/options/glibc/include/endian.h new file mode 100644 index 0000000..129af98 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/endian.h @@ -0,0 +1,54 @@ +#ifndef _ENDIAN_H +#define _ENDIAN_H + +#include + +#ifdef __GNUC__ +# define BYTE_ORDER __BYTE_ORDER__ +# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +# define BIG_ENDIAN __ORDER_BIG_ENDIAN__ +# define PDP_ENDIAN __ORDER_PDP_ENDIAN__ + +# define __BYTE_ORDER __BYTE_ORDER__ +#ifndef __LITTLE_ENDIAN /* Linux kernel headers define this already */ +# define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif +# define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +# define __PDP_ENDIAN __ORDER_PDP_ENDIAN__ +#else +# error "Unsupported compiler" +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +# define htobe16(x) __bswap_16(x) +# define htole16(x) (uint16_t)(x) +# define be16toh(x) __bswap_16(x) +# define le16toh(x) (uint16_t)(x) + +# define htobe32(x) __bswap_32(x) +# define htole32(x) (uint32_t)(x) +# define be32toh(x) __bswap_32(x) +# define le32toh(x) (uint32_t)(x) + +# define htobe64(x) __bswap_64(x) +# define htole64(x) (uint64_t)(x) +# define be64toh(x) __bswap_64(x) +# define le64toh(x) (uint64_t)(x) +#else +# define htobe16(x) (uint16_t)(x) +# define htole16(x) __bswap_16(x) +# define be16toh(x) (uint16_t)(x) +# define le16toh(x) __bswap_16(x) + +# define htobe32(x) (uint32_t)(x) +# define htole32(x) __bswap_32(x) +# define be32toh(x) (uint32_t)(x) +# define le32toh(x) __bswap_32(x) + +# define htobe64(x) (uint64_t)(x) +# define htole64(x) __bswap_64(x) +# define be64toh(x) (uint64_t)(x) +# define le64toh(x) __bswap_64(x) +#endif + +#endif /* _ENDIAN_H */ diff --git a/user/include/mlibc/options/glibc/include/err.h b/user/include/mlibc/options/glibc/include/err.h new file mode 100644 index 0000000..88341e9 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/err.h @@ -0,0 +1,33 @@ +#ifndef _ERR_H +#define _ERR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +__attribute__((__format__(__printf__, 1, 2))) void warn(const char *__format, ...); +__attribute__((__format__(__printf__, 1, 0))) void vwarn(const char *__format, va_list __args); +__attribute__((__format__(__printf__, 1, 2))) void warnx(const char *__format, ...); +__attribute__((__format__(__printf__, 1, 0))) void vwarnx(const char *__format, va_list __args); + +__attribute__((__noreturn__, __format__(__printf__, 2, 3))) +void err(int __errnum, const char *__format, ...); +__attribute__((__noreturn__, __format__(__printf__, 2, 0))) +void verr(int __errnum, const char *__format, va_list __args); +__attribute__((__noreturn__, , __format__(__printf__, 2, 3))) +void errx(int __errnum, const char *__format, ...); +__attribute__((__noreturn__, __format__(__printf__, 2, 0))) +void verrx(int __errnum, const char *__format, va_list __args); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ERR_H */ + diff --git a/user/include/mlibc/options/glibc/include/error.h b/user/include/mlibc/options/glibc/include/error.h new file mode 100644 index 0000000..8c68295 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/error.h @@ -0,0 +1,27 @@ +#ifndef _ERROR_H +#define _ERROR_H + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef __MLIBC_ABI_ONLY + +__attribute__((__format__(__printf__, 3, 4))) +void error(int __status, int __errnum, const char *__format, ...); +__attribute__((__format__(__printf__, 5, 6))) +void error_at_line(int __status, int __errnum, const char *__filename, unsigned int __linenum, const char *__format, ...); + +extern unsigned int error_message_count; +extern int error_one_per_line; +extern void (*error_print_progname)(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ERROR_H */ diff --git a/user/include/mlibc/options/glibc/include/execinfo.h b/user/include/mlibc/options/glibc/include/execinfo.h new file mode 100644 index 0000000..0d0d49d --- /dev/null +++ b/user/include/mlibc/options/glibc/include/execinfo.h @@ -0,0 +1,20 @@ +#ifndef _EXECINFO_H +#define _EXECINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int backtrace(void **__buffer, int __size); +char **backtrace_symbols(void *const *__buffer, int __size); +void backtrace_symbols_fd(void *const *__buffer, int __size, int __fd); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/glibc/include/features.h b/user/include/mlibc/options/glibc/include/features.h new file mode 100644 index 0000000..d700f10 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/features.h @@ -0,0 +1,6 @@ +#ifndef FEATURES_H +#define FEATURES_H + +/* This header is a stub */ + +#endif diff --git a/user/include/mlibc/options/glibc/include/getopt.h b/user/include/mlibc/options/glibc/include/getopt.h new file mode 100644 index 0000000..d3e868b --- /dev/null +++ b/user/include/mlibc/options/glibc/include/getopt.h @@ -0,0 +1,37 @@ + +#ifndef _GETOPT_H +#define _GETOPT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +extern char **environ; +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; +#if __MLIBC_BSD_OPTION +extern int optreset; +#endif /*__MLIBC_BSD_OPTION */ + +int getopt(int __argc, char *const __argv[], const char *__optstring); +int getopt_long(int __argc, char *const __argv[], const char *__optstring, + const struct option *__longopts, int *__longindex); +int getopt_long_only(int __argc, char *const __argv[], const char *__optstring, + const struct option *__longopts, int *__longindex); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ + diff --git a/user/include/mlibc/options/glibc/include/gshadow.h b/user/include/mlibc/options/glibc/include/gshadow.h new file mode 100644 index 0000000..4517700 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/gshadow.h @@ -0,0 +1,30 @@ +#ifndef _GSHADOW_H +#define _GSHADOW_H + +#include +#include + +#define GSHADOW _PATH_GSHADOW + +struct sgrp { + char *sg_namp; + char *sg_passwd; + char **sg_adm; + char **sg_mem; +}; + +#ifndef __MLIBC_ABI_ONLY + +#ifdef __cplusplus +extern "C" { +#endif + +int getsgnam_r(const char *__name, struct sgrp *__result_buf, char *__buffer, size_t __len, struct sgrp **__result); + +#ifdef __cplusplus +} +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif diff --git a/user/include/mlibc/options/glibc/include/memory.h b/user/include/mlibc/options/glibc/include/memory.h new file mode 100644 index 0000000..39adee7 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/memory.h @@ -0,0 +1,6 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#include + +#endif diff --git a/user/include/mlibc/options/glibc/include/mlibc/glibc-sysdeps.hpp b/user/include/mlibc/options/glibc/include/mlibc/glibc-sysdeps.hpp new file mode 100644 index 0000000..29b6c1a --- /dev/null +++ b/user/include/mlibc/options/glibc/include/mlibc/glibc-sysdeps.hpp @@ -0,0 +1,20 @@ +#ifndef MLIBC_GLIBC_SYSDEPS +#define MLIBC_GLIBC_SYSDEPS + +namespace [[gnu::visibility("hidden")]] mlibc { + +[[gnu::weak]] int sys_ioctl(int fd, unsigned long request, void *arg, int *result); +[[gnu::weak]] int sys_tgkill(int tgid, int tid, int sig); + +[[gnu::weak]] int sys_personality(unsigned long persona, int *out); + +[[gnu::weak]] int sys_ioperm(unsigned long int from, unsigned long int num, int turn_on); +[[gnu::weak]] int sys_iopl(int level); + +#ifdef __riscv +[[gnu::weak]] int sys_riscv_flush_icache(void *start, void *end, unsigned long flags); +#endif + +} // namespace mlibc + +#endif // MLIBC_GLIBC_SYSDEPS diff --git a/user/include/mlibc/options/glibc/include/net/ethernet.h b/user/include/mlibc/options/glibc/include/net/ethernet.h new file mode 100644 index 0000000..b9358e9 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/net/ethernet.h @@ -0,0 +1,46 @@ +#ifndef _NET_ETHERNET_H +#define _NET_ETHERNET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if __MLIBC_LINUX_OPTION +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#pragma GCC diagnostic ignored "-Wpedantic" +# include +#pragma GCC diagnostic pop +#endif /* __MLIBC_LINUX_OPTION */ + +#define ETHERTYPE_PUP 0x0200 +#define ETHERTYPE_SPRITE 0x0500 +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_REVARP 0x8035 +#define ETHERTYPE_AT 0x809B +#define ETHERTYPE_AARP 0x80F3 +#define ETHERTYPE_VLAN 0x8100 +#define ETHERTYPE_IPX 0x8137 +#define ETHERTYPE_IPV6 0x86dd +#define ETHERTYPE_LOOPBACK 0x9000 + +struct ether_header { + uint8_t ether_dhost[6]; + uint8_t ether_shost[6]; + uint16_t ether_type; +}; + +#define ETHER_ADDR_LEN 6 + +#define ETHERTYPE_IP 0x0800 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/glibc/include/net/if_ppp.h b/user/include/mlibc/options/glibc/include/net/if_ppp.h new file mode 100644 index 0000000..55f46b5 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/net/if_ppp.h @@ -0,0 +1,23 @@ +#ifndef _NET_IF_PPP_H +#define _NET_IF_PPP_H + +#include + +#if __MLIBC_LINUX_OPTION +#include +#include + +#define PPPIOCGFLAGS _IOR('t', 90, int) +#define PPPIOCSFLAGS _IOW('t', 89, int) +#define PPPIOCGASYNCMAP _IOR('t', 88, int) +#define PPPIOCSASYNCMAP _IOW('t', 87, int) +#define PPPIOCGUNIT _IOR('t', 86, int) +#define PPPIOCSMRU _IOW('t', 82, int) +#define PPPIOCSMAXCID _IOW('t', 81, int) +#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) +#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) +#define PPPIOCGDEBUG _IOR('t', 65, int) +#define PPPIOCSDEBUG _IOW('t', 64, int) +#endif + +#endif /* _NET_IF_PPP_H */ diff --git a/user/include/mlibc/options/glibc/include/net/route.h b/user/include/mlibc/options/glibc/include/net/route.h new file mode 100644 index 0000000..7537241 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/net/route.h @@ -0,0 +1,35 @@ +#ifndef _NET_ROUTE_H +#define _NET_ROUTE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTF_HOST 0x0004 +#define RTF_REJECT 0x0200 + +struct rtentry { + unsigned long int rt_pad1; + struct sockaddr rt_dst; + struct sockaddr rt_gateway; + struct sockaddr rt_genmask; + unsigned short int rt_flags; + short int rt_pad2; + unsigned long int rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short int rt_pad4[3]; + short int rt_metric; + char *rt_dev; + unsigned long int rt_mtu; + unsigned long int rt_window; + unsigned short int rt_irtt; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NET_ROUTE_H */ diff --git a/user/include/mlibc/options/glibc/include/netax25/ax25.h b/user/include/mlibc/options/glibc/include/netax25/ax25.h new file mode 100644 index 0000000..3fb82da --- /dev/null +++ b/user/include/mlibc/options/glibc/include/netax25/ax25.h @@ -0,0 +1,51 @@ +#ifndef _NETAX25_AX25_H +#define _NETAX25_AX25_H + +#include +#include + +#define AX25_VALUES_IPDEFMODE 0 +#define AX25_VALUES_AXDEFMODE 1 +#define AX25_VALUES_NETROM 2 +#define AX25_VALUES_TEXT 3 +#define AX25_VALUES_BACKOFF 4 +#define AX25_VALUES_CONMODE 5 +#define AX25_VALUES_WINDOW 6 +#define AX25_VALUES_EWINDOW 7 +#define AX25_VALUES_T1 8 +#define AX25_VALUES_T2 9 +#define AX25_VALUES_T3 10 +#define AX25_VALUES_N2 11 +#define AX25_VALUES_DIGI 12 +#define AX25_VALUES_IDLE 13 +#define AX25_VALUES_PACLEN 14 +#define AX25_VALUES_IPMAXQUEUE 15 +#define AX25_MAX_VALUES 20 + +typedef struct { + char ax25_call[7]; +} ax25_address; + +struct sockaddr_ax25 { + sa_family_t sax25_family; + ax25_address sax25_call; + int sax25_ndigis; +}; + +struct ax25_parms_struct { + ax25_address port_addr; + unsigned short values[AX25_MAX_VALUES]; +}; + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCAX25GETUID (SIOCPROTOPRIVATE) +#define SIOCAX25ADDUID (SIOCPROTOPRIVATE + 1) +#define SIOCAX25DELUID (SIOCPROTOPRIVATE + 2) +#define SIOCAX25NOUID (SIOCPROTOPRIVATE + 3) +#define SIOCAX25GETPARMS (SIOCPROTOPRIVATE + 5) +#define SIOCAX25SETPARMS (SIOCPROTOPRIVATE + 6) +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _NETAX25_AX25_H */ diff --git a/user/include/mlibc/options/glibc/include/netinet/in_systm.h b/user/include/mlibc/options/glibc/include/netinet/in_systm.h new file mode 100644 index 0000000..131de89 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/netinet/in_systm.h @@ -0,0 +1,7 @@ + +#ifndef _NETINET_IN_SYSTM_H +#define _NETINET_IN_SYSTM_H + + + +#endif /* _NETINET_IN_SYSTM_H */ diff --git a/user/include/mlibc/options/glibc/include/netipx/ipx.h b/user/include/mlibc/options/glibc/include/netipx/ipx.h new file mode 100644 index 0000000..7b5c774 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/netipx/ipx.h @@ -0,0 +1,35 @@ +#ifndef _NETIPX_IPX_H +#define _NETIPX_IPX_H + +#include +#include +#include + +typedef struct ipx_config_data { + unsigned char ipxcfg_auto_select_primary; + unsigned char ipxcfg_auto_create_interfaces; +} ipx_config_data; + +#define IPX_TYPE 1 +#define IPX_NODE_LEN 6 + +struct sockaddr_ipx { + sa_family_t sipx_family; + uint16_t sipx_port; + uint32_t sipx_network; + unsigned char sipx_node[IPX_NODE_LEN]; + uint8_t sipx_type; + unsigned char sipx_zero; +}; + +#define SOL_IPX 256 + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCAIPXITFCRT (SIOCPROTOPRIVATE) +#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE + 1) +#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE + 2) +#endif + +#endif /* _NETIPX_IPX_H */ diff --git a/user/include/mlibc/options/glibc/include/netrom/netrom.h b/user/include/mlibc/options/glibc/include/netrom/netrom.h new file mode 100644 index 0000000..69497d9 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/netrom/netrom.h @@ -0,0 +1,27 @@ +#ifndef _NETROM_NETROM_H +#define _NETROM_NETROM_H + +#include + +struct nr_parms_struct { + unsigned int quality; + unsigned int obs_count; + unsigned int ttl; + unsigned int timeout; + unsigned int ack_delay; + unsigned int busy_delay; + unsigned int tries; + unsigned int window; + unsigned int paclen; +}; + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCNRGETPARMS (SIOCPROTOPRIVATE) +#define SIOCNRSETPARMS (SIOCPROTOPRIVATE + 1) +#define SIOCNRDECOBS (SIOCPROTOPRIVATE + 2) +#define SIOCNRRTCTL (SIOCPROTOPRIVATE + 3) +#endif + +#endif /* _NETROM_NETROM_H */ diff --git a/user/include/mlibc/options/glibc/include/paths.h b/user/include/mlibc/options/glibc/include/paths.h new file mode 100644 index 0000000..81d354a --- /dev/null +++ b/user/include/mlibc/options/glibc/include/paths.h @@ -0,0 +1,41 @@ +/* This file is taken from musl */ +/* Path to original: include/paths.h */ + +#ifndef _PATHS_H +#define _PATHS_H + +#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" +#define _PATH_STDPATH "/bin:/usr/bin:/sbin:/usr/sbin" + +#define _PATH_BSHELL "/bin/sh" +#define _PATH_CONSOLE "/dev/console" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_GSHADOW "/etc/gshadow" +#define _PATH_KLOG "/proc/kmsg" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_MAILDIR "/var/mail" +#define _PATH_MAN "/usr/share/man" +#define _PATH_MNTTAB "/etc/fstab" +#define _PATH_MOUNTED "/etc/mtab" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_PRESERVE "/var/lib" +#define _PATH_SENDMAIL "/usr/sbin/sendmail" +#define _PATH_SHADOW "/etc/shadow" +#define _PATH_SHELLS "/etc/shells" +#define _PATH_TTY "/dev/tty" +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_VI "/usr/bin/vi" +#define _PATH_WTMP "/var/log/wtmp" + +#define _PATH_DEV "/dev/" +#define _PATH_TMP "/tmp/" +#define _PATH_VARDB "/var/lib/misc/" +#define _PATH_VARRUN "/var/run/" +#define _PATH_VARTMP "/var/tmp/" + +#ifdef _GNU_SOURCE +#define _PATH_UTMPX _PATH_UTMP +#define _PATH_WTMPX _PATH_WTMP +#endif + +#endif /* _PATHS_H */ diff --git a/user/include/mlibc/options/glibc/include/printf.h b/user/include/mlibc/options/glibc/include/printf.h new file mode 100644 index 0000000..b6b86b9 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/printf.h @@ -0,0 +1,41 @@ +#ifndef _PRINTF_H +#define _PRINTF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +/* This seems to be a glibc thing, so constants are from glibc */ +size_t parse_printf_format(const char * __restrict __format, size_t __size, int * __restrict __argtypes); + +#endif /* !__MLIBC_ABI_ONLY */ + +enum { + PA_INT, + PA_CHAR, + PA_WCHAR, + PA_STRING, + PA_WSTRING, + PA_POINTER, + PA_FLOAT, + PA_DOUBLE, + PA_LAST +}; + +#define PA_FLAG_MASK 0xff00 +#define PA_FLAG_LONG_LONG (1 << 8) +#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG +#define PA_FLAG_LONG (1 << 9) +#define PA_FLAG_SHORT (1 << 10) +#define PA_FLAG_PTR (1 << 11) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/glibc/include/resolv.h b/user/include/mlibc/options/glibc/include/resolv.h new file mode 100644 index 0000000..05176fd --- /dev/null +++ b/user/include/mlibc/options/glibc/include/resolv.h @@ -0,0 +1,78 @@ +#ifndef _RESOLV_H +#define _RESOLV_H + +#include + +#define RES_INIT 0x00000001 +#define RES_DEBUG 0x00000002 +#define RES_USEVC 0x00000008 +#define RES_IGNTC 0x00000020 +#define RES_RECURSE 0x00000040 +#define RES_DEFNAMES 0x00000080 +#define RES_STAYOPEN 0x00000100 +#define RES_DNSRCH 0x00000200 + +#define MAXNS 3 +#define MAXDNSRCH 6 + +#define _PATH_RESCONF "/etc/resolv.conf" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int dn_expand(const unsigned char *__msg, const unsigned char *__eomorig, + const unsigned char *__comp_dn, char *__exp_dn, int __size); + +int res_query(const char *__dname, int __class, int __type, + unsigned char *__answer, int __anslen); + +int res_init(void); + +int dn_comp(const char *, unsigned char *, int, unsigned char **, unsigned char **); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* From musl: Unused; purely for broken apps + * To avoid an massive struct, only add the items requested. */ +typedef struct __res_state { + int retrans; + int retry; + unsigned long options; + int nscount; + struct sockaddr_in nsaddr_list[MAXNS]; + char *dnsrch[MAXDNSRCH + 1]; + char defdname[256]; + unsigned ndots:4; + unsigned nsort:4; + union { + char pad[52]; + struct { + uint16_t nscount; + uint16_t nsmap[MAXNS]; + int nssocks[MAXNS]; + uint16_t nscount6; + uint16_t nsinit; + struct sockaddr_in6 *nsaddrs[MAXNS]; + unsigned int _initstamp[2]; + } _ext; + } _u; +} *res_state; + +#ifndef __MLIBC_ABI_ONLY + +struct __res_state *__res_state(void); +#define _res (*__res_state()) + +int res_ninit(res_state __state); +void res_nclose(res_state __state); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _RESOLV_H */ diff --git a/user/include/mlibc/options/glibc/include/shadow.h b/user/include/mlibc/options/glibc/include/shadow.h new file mode 100644 index 0000000..6d16857 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/shadow.h @@ -0,0 +1,43 @@ +#ifndef _SHADOW_H +#define _SHADOW_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spwd { + char *sp_namp; + char *sp_pwdp; + long sp_lstchg; + long sp_min; + long sp_max; + long sp_warn; + long sp_inact; + long sp_expire; + unsigned long sp_flag; +}; + +#define SHADOW _PATH_SHADOW + +#ifndef __MLIBC_ABI_ONLY + +int putspent(const struct spwd *__sp, FILE *__f); +int lckpwdf(void); +int ulckpwdf(void); +struct spwd *getspnam(const char *__name); +int getspnam_r(const char *__name, struct spwd *__sp, char *__buf, size_t __size, struct spwd **__res); +struct spwd *fgetspent(FILE *__f); +void endspent(void); +struct spwd *sgetspent(const char *__s); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/glibc/include/stdio_ext.h b/user/include/mlibc/options/glibc/include/stdio_ext.h new file mode 100644 index 0000000..867c07a --- /dev/null +++ b/user/include/mlibc/options/glibc/include/stdio_ext.h @@ -0,0 +1,42 @@ +#ifndef _STDIO_EXT_H +#define _STDIO_EXT_H + +#include +#include + +#define FSETLOCKING_INTERNAL 1 +#define FSETLOCKING_BYCALLER 2 +#define FSETLOCKING_QUERY 3 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +size_t __fbufsize(FILE *__stream); +size_t __fpending(FILE *__stream); +int __flbf(FILE *__stream); +int __freadable(FILE *__stream); +int __fwritable(FILE *__stream); +int __freading(FILE *__stream); +int __fwriting(FILE *__stream); +int __fsetlocking(FILE *__stream, int __type); +void __fpurge(FILE *__stream); + +void _flushlbf(void); + +/* The following functions are defined by musl. */ + +size_t __freadahead(FILE *__stream); +const char *__freadptr(FILE *__stream, size_t *__size); +void __freadptrinc(FILE *, size_t); +void __fseterr(FILE *__stream); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _STDIO_EXT_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/cachectl.h b/user/include/mlibc/options/glibc/include/sys/cachectl.h new file mode 100644 index 0000000..f6b2d8c --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/cachectl.h @@ -0,0 +1,16 @@ +#ifndef _SYS_CACHECTL_H +#define _SYS_CACHECTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __riscv +int __riscv_flush_icache(void *, void *, unsigned long); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/glibc/include/sys/dir.h b/user/include/mlibc/options/glibc/include/sys/dir.h new file mode 100644 index 0000000..eff112c --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/dir.h @@ -0,0 +1,8 @@ +#ifndef _SYS_DIR_H +#define _SYS_DIR_H + +#include + +#define direct dirent + +#endif diff --git a/user/include/mlibc/options/glibc/include/sys/endian.h b/user/include/mlibc/options/glibc/include/sys/endian.h new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/options/glibc/include/sys/errno.h b/user/include/mlibc/options/glibc/include/sys/errno.h new file mode 100644 index 0000000..339f4fc --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/errno.h @@ -0,0 +1 @@ +#include diff --git a/user/include/mlibc/options/glibc/include/sys/io.h b/user/include/mlibc/options/glibc/include/sys/io.h new file mode 100644 index 0000000..1ee22f2 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/io.h @@ -0,0 +1,108 @@ +#ifndef _SYS_IO_H +#define _SYS_IO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int ioperm(unsigned long int __from, unsigned long int __num, int __turn_on); + +__attribute__((deprecated)) int iopl(int __level); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __x86_64__ +__MLIBC_INLINE_DEFINITION unsigned char inb(unsigned short int __port) { + unsigned char __value; + __asm__ __volatile__ ("inb %w1,%0":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned char inb_p(unsigned short int __port) { + unsigned char __value; + __asm__ __volatile__ ("inb %w1,%0\noutb %%al,$0x80":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned short int inw(unsigned short int __port) { + unsigned short __value; + __asm__ __volatile__ ("inw %w1,%0":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned short int inw_p(unsigned short int __port) { + unsigned short int __value; + __asm__ __volatile__ ("inw %w1,%0\noutb %%al,$0x80":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned int inl(unsigned short int __port) { + unsigned int __value; + __asm__ __volatile__ ("inl %w1,%0":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION unsigned int inl_p(unsigned short int __port) { + unsigned int __value; + __asm__ __volatile__ ("inl %w1,%0\noutb %%al,$0x80":"=a" (__value):"Nd" (__port)); + return __value; +} + +__MLIBC_INLINE_DEFINITION void outb(unsigned char value, unsigned short int __port) { + __asm__ __volatile__ ("outb %b0,%w1": :"a" (value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outb_p(unsigned char __value, unsigned short int __port) { + __asm__ __volatile__ ("outb %b0,%w1\noutb %%al,$0x80": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outw(unsigned short int __value, unsigned short int __port) { + __asm__ __volatile__ ("outw %w0,%w1": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outw_p(unsigned short int __value, unsigned short int __port) { + __asm__ __volatile__ ("outw %w0,%w1\noutb %%al,$0x80": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outl(unsigned int __value, unsigned short int __port) { + __asm__ __volatile__ ("outl %0,%w1": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void outl_p(unsigned int __value, unsigned short int __port) { + __asm__ __volatile__ ("outl %0,%w1\noutb %%al,$0x80": :"a" (__value), "Nd" (__port)); +} + +__MLIBC_INLINE_DEFINITION void insb(unsigned short int __port, void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; insb":"=D" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void insw(unsigned short int __port, void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; insw":"=D" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void insl(unsigned short int __port, void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; insl":"=D" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void outsb(unsigned short int __port, const void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; outsb":"=S" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void outsw(unsigned short int __port, const void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; outsw":"=S" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} + +__MLIBC_INLINE_DEFINITION void outsl(unsigned short int __port, const void *__addr, unsigned long int __count) { + __asm__ __volatile__ ("cld ; rep ; outsl":"=S" (__addr), "=c" (__count) :"d" (__port), "0" (__addr), "1" (__count)); +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_IO_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/ioctl.h b/user/include/mlibc/options/glibc/include/sys/ioctl.h new file mode 100644 index 0000000..f9707b8 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/ioctl.h @@ -0,0 +1,48 @@ +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +#include +#include + +/* On Linux, sys/ioctl.h includes the termios ioctls. */ +#if __MLIBC_LINUX_OPTION +# include +# include +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int ioctl(int __fd, unsigned long __request, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 + +#define FIONREAD 0x541B +#define FIONBIO 0x5421 +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 + +#define SIOCGIFNAME 0x8910 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFMTU 0x8921 +#define SIOCSIFMTU 0x8922 +#define SIOCGIFINDEX 0x8933 + +#define SIOCPROTOPRIVATE 0x89E0 +#define SIOCDEVPRIVATE 0x89F0 + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_IOCTL_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/kd.h b/user/include/mlibc/options/glibc/include/sys/kd.h new file mode 100644 index 0000000..285c694 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/kd.h @@ -0,0 +1,17 @@ +#ifndef _SYS_KD_H +#define _SYS_KD_H + +/* Make sure the header is not loaded. */ +#ifndef _LINUX_TYPES_H +# define _LINUX_TYPES_H 1 +# define __undef_LINUX_TYPES_H +#endif + +#include + +#ifdef __undef_LINUX_TYPES_H +# undef _LINUX_TYPES_H +# undef __undef_LINUX_TYPES_H +#endif + +#endif /* _SYS_KD_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/mtio.h b/user/include/mlibc/options/glibc/include/sys/mtio.h new file mode 100644 index 0000000..2ee4873 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/mtio.h @@ -0,0 +1,102 @@ +#ifndef _SYS_MTIO_H +#define _SYS_MTIO_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct mtop { + short int mt_op; + int mt_count; +}; + +struct mtget { + long int mt_type; + long int mt_resid; + long int mt_dsreg; + long int mt_gstat; + long int mt_erreg; + int mt_fileno; + int mt_blkno; +}; + +struct mtpos { + long int mt_blkno; +}; + +struct mtconfiginfo { + long int mt_type; + long int ifc_type; + unsigned short int irqnr; + unsigned short int dmanr; + unsigned short int port; + + unsigned long int debug; + + unsigned have_dens:1; + unsigned have_bsf:1; + unsigned have_fsr:1; + unsigned have_bsr:1; + unsigned have_eod:1; + unsigned have_seek:1; + unsigned have_tell:1; + unsigned have_ras1:1; + unsigned have_ras2:1; + unsigned have_ras3:1; + unsigned have_qfa:1; + + unsigned pad1:5; + char reserved[10]; +}; + +#define MTRESET 0 +#define MTFSF 1 +#define MTBSF 2 +#define MTFSR 3 +#define MTBSR 4 +#define MTWEOF 5 +#define MTREW 6 +#define MTOFFL 7 +#define MTNOP 8 +#define MTRETEN 9 +#define MTBSFM 10 +#define MTFSFM 11 +#define MTEOM 12 +#define MTERASE 13 +#define MTRAS1 14 +#define MTRAS2 15 +#define MTRAS3 16 +#define MTSETBLK 20 +#define MTSETDENSITY 21 +#define MTSEEK 22 +#define MTTELL 23 +#define MTSETDRVBUFFER 24 +#define MTFSS 25 +#define MTBSS 26 +#define MTWSM 27 +#define MTLOCK 28 +#define MTUNLOCK 29 +#define MTLOAD 30 +#define MTUNLOAD 31 +#define MTCOMPRESSION 32 +#define MTSETPART 33 +#define MTMKPART 34 + +#define GMT_WR_PROT(x) ((x) & 0x04000000) + +#if __MLIBC_LINUX_OPTION +#define MTIOCTOP _IOR('m', 1, struct mtop) +#define MTIOCGET _IOR('m', 2, struct mtget) +#define MTIOCPOS _IOR('m', 3, struct mtpos) +#define MTIOCGETCONFIG _IOR('m', 4, struct mtconfiginfo) +#define MTIOCSETCONFIG _IOR('m', 5, struct mtconfiginfo) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MTIO_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/personality.h b/user/include/mlibc/options/glibc/include/sys/personality.h new file mode 100644 index 0000000..f4173ee --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/personality.h @@ -0,0 +1,58 @@ +#ifndef _SYS_PERSONALITY_H +#define _SYS_PERSONALITY_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + UNAME26 = 0x0020000, + ADDR_NO_RANDOMIZE = 0x0040000, + FDPIC_FUNCPTRS = 0x0080000, + MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, + READ_IMPLIES_EXEC = 0x0400000, + ADDR_LIMIT_32BIT = 0x0800000, + SHORT_INODE = 0x1000000, + WHOLE_SECONDS = 0x2000000, + STICKY_TIMEOUTS = 0x4000000, + ADDR_LIMIT_3GB = 0x8000000 +}; + +enum { + PER_LINUX = 0x0000, + PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, + PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, + PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, + PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE, + PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, + PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, + PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, + PER_BSD = 0x0006, + PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, + PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, + PER_LINUX32 = 0x0008, + PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, + PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS, + PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS, + PER_IRIX64 = 0x000b | STICKY_TIMEOUTS, + PER_RISCOS = 0x000c, + PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, + PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_OSF4 = 0x000f, + PER_HPUX = 0x0010, + PER_MASK = 0x00ff +}; + +#ifndef __MLIBC_ABI_ONLY + +int personality(unsigned long __persona); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PERSONALITY_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/procfs.h b/user/include/mlibc/options/glibc/include/sys/procfs.h new file mode 100644 index 0000000..739b702 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/procfs.h @@ -0,0 +1,75 @@ +#ifndef _SYS_PROCFS_H +#define _SYS_PROCFS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof (elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_fpregs_struct elf_fpregset_t; +typedef elf_gregset_t prgregset_t; +typedef struct user_fpregs_struct prfpregset_t; + +#define ELF_PRARGSZ 80 + +struct elf_siginfo { + int si_signo; + int si_code; + int si_errno; +}; + +struct elf_prstatus { + struct elf_siginfo pr_info; + short int pr_cursig; + unsigned long int pr_sigpend; + unsigned long int pr_sighold; + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct timeval pr_utime; + struct timeval pr_stime; + struct timeval pr_cutime; + struct timeval pr_cstime; + elf_gregset_t pr_reg; + int pr_fpvalid; +}; + +struct elf_prpsinfo { + char pr_state; + char pr_sname; + char pr_zomb; + char pr_nice; + unsigned long pr_flag; +#if __INTPTR_WIDTH__ == 32 + unsigned short int pr_uid; + unsigned short int pr_gid; +#else + unsigned int pr_uid; + unsigned int pr_gid; +#endif + int pr_pid; + int pr_ppid; + int pr_pgrp; + int pr_sid; + char pr_fname[16]; + char pr_psargs[ELF_PRARGSZ]; +}; + +typedef pid_t lwpid_t; +typedef void *psaddr_t; +typedef struct elf_prstatus prstatus_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/glibc/include/sys/reg.h b/user/include/mlibc/options/glibc/include/sys/reg.h new file mode 100644 index 0000000..7e5cf6f --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/reg.h @@ -0,0 +1,36 @@ +#ifndef _SYS_REG_H +#define _SYS_REG_H + +#ifdef __x86_64__ +#define R15 0 +#define R14 1 +#define R13 2 +#define R12 3 +#define RBP 4 +#define RBX 5 +#define R11 6 +#define R10 7 +#define R9 8 +#define R8 9 +#define RAX 10 +#define RCX 11 +#define RDX 12 +#define RSI 13 +#define RDI 14 +#define ORIG_RAX 15 +#define RIP 16 +#define CS 17 +#define EFLAGS 18 +#define RSP 19 +#define SS 20 +#define FS_BASE 21 +#define GS_BASE 22 +#define DS 23 +#define ES 24 +#define FS 25 +#define GS 26 +#elif !(defined(__i386__) || defined(__riscv) || defined(__aarch64__) || defined(__m68k__) || defined(__loongarch64)) +#error "Missing architecture specific code." +#endif + +#endif diff --git a/user/include/mlibc/options/glibc/include/sys/signal.h b/user/include/mlibc/options/glibc/include/sys/signal.h new file mode 100644 index 0000000..2e602da --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/signal.h @@ -0,0 +1 @@ +#include diff --git a/user/include/mlibc/options/glibc/include/sys/timeb.h b/user/include/mlibc/options/glibc/include/sys/timeb.h new file mode 100644 index 0000000..bf6d718 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/timeb.h @@ -0,0 +1,14 @@ +#ifndef _SYS_TIMEB_H +#define _SYS_TIMEB_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIMEB_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/timex.h b/user/include/mlibc/options/glibc/include/sys/timex.h new file mode 100644 index 0000000..ebbb8a0 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/timex.h @@ -0,0 +1,80 @@ +#ifndef _SYS_TIMEX_H +#define _SYS_TIMEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +struct timex { + int modes; + long offset; + long freq; + long maxerror; + long esterror; + int status; + long constant; + long precision; + long tolerance; + struct timeval time; + long tick; + long ppsfreq; + long jitter; + int shift; + long stabil; + long jitcnt; + long calcnt; + long errcnt; + long stbcnt; + int tai; + int __padding[11]; +}; + +#define ADJ_OFFSET 0x0001 +#define ADJ_FREQUENCY 0x0002 +#define ADJ_MAXERROR 0x0004 +#define ADJ_ESTERROR 0x0008 +#define ADJ_STATUS 0x0010 +#define ADJ_TIMECONST 0x0020 +#define ADJ_TAI 0x0080 +#define ADJ_SETOFFSET 0x0100 +#define ADJ_MICRO 0x1000 +#define ADJ_NANO 0x2000 +#define ADJ_TICK 0x4000 +#define ADJ_OFFSET_SINGLESHOT 0x8001 +#define ADJ_OFFSET_SS_READ 0xa001 + +#define STA_PLL 0x0001 +#define STA_PPSFREQ 0x0002 +#define STA_PPSTIME 0x0004 +#define STA_FLL 0x0008 +#define STA_INS 0x0010 +#define STA_DEL 0x0020 +#define STA_UNSYNC 0x0040 +#define STA_FREQHOLD 0x0080 +#define STA_PPSSIGNAL 0x0100 +#define STA_PPSJITTER 0x0200 +#define STA_PPSWANDER 0x0400 +#define STA_PPSERROR 0x0800 +#define STA_CLOCKERR 0x1000 +#define STA_NANO 0x2000 +#define STA_MODE 0x4000 +#define STA_CLK 0x8000 + +#define TIME_ERROR 5 + +#ifndef __MLIBC_ABI_ONLY + +int adjtimex(struct timex *__buf); +int clock_adjtime(clockid_t __clockid, struct timex *__buf); +int ntp_adjtime(struct timex *__buf); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIMEX_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/ucontext.h b/user/include/mlibc/options/glibc/include/sys/ucontext.h new file mode 100644 index 0000000..cae57f0 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/ucontext.h @@ -0,0 +1,14 @@ +#ifndef _SYS_UCONTEXT_H +#define _SYS_UCONTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_UCONTEXT_H */ diff --git a/user/include/mlibc/options/glibc/include/sys/user.h b/user/include/mlibc/options/glibc/include/sys/user.h new file mode 100644 index 0000000..7963e68 --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sys/user.h @@ -0,0 +1,51 @@ +#ifndef _SYS_USER_H +#define _SYS_USER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* TODO: This assumes x86-64. */ + +struct user_fpregs_struct { + uint16_t cwd, swd, ftw, fop; + uint64_t rip, rdp; + uint32_t mxcsr, mxcr_mask; + uint32_t st_space[32], xmm_space[64], padding[24]; +}; + +struct user_regs_struct { + unsigned long r15, r14, r13, r12, rbp, rbx, r11, r10, r9, r8; + unsigned long rax, rcx, rdx, rsi, rdi, orig_rax, rip; + unsigned long cs, eflags, rsp, ss, fs_base, gs_base, ds, es, fs, gs; +}; + +struct user { + struct user_regs_struct regs; + int u_fpvalid; + struct user_fpregs_struct i387; + unsigned long u_tsize; + unsigned long u_dsize; + unsigned long u_ssize; + unsigned long start_code; + unsigned long start_stack; + long signal; + int reserved; + struct user_regs_struct *u_ar0; + struct user_fpregs_struct *u_fpstate; + unsigned long magic; + char u_comm[32]; + unsigned long u_debugreg[8]; +}; + +#ifdef __cplusplus +} +#endif + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) + +#endif diff --git a/user/include/mlibc/options/glibc/include/sysexits.h b/user/include/mlibc/options/glibc/include/sysexits.h new file mode 100644 index 0000000..b2969da --- /dev/null +++ b/user/include/mlibc/options/glibc/include/sysexits.h @@ -0,0 +1,24 @@ +#ifndef _SYSEXITS_H +#define _SYSEXITS_H + +#define EX_OK 0 +#define EX_USAGE 64 +#define EX_DATAERR 65 +#define EX_NOINPUT 66 +#define EX_NOUSER 67 +#define EX_NOHOST 68 +#define EX_UNAVAILABLE 69 +#define EX_SOFTWARE 70 +#define EX_OSERR 71 +#define EX_OSFILE 72 +#define EX_CANTCREAT 73 +#define EX_IOERR 74 +#define EX_TEMPFAIL 75 +#define EX_PROTOCOL 76 +#define EX_NOPERM 77 +#define EX_CONFIG 78 + +#define EX__BASE 64 +#define EX__MAX 78 + +#endif /* _SYSEXITS_H */ diff --git a/user/include/mlibc/options/glibc/meson.build b/user/include/mlibc/options/glibc/meson.build new file mode 100644 index 0000000..8c6fb68 --- /dev/null +++ b/user/include/mlibc/options/glibc/meson.build @@ -0,0 +1,96 @@ +if not glibc_option + subdir_done() +endif +libc_sources += files( + 'generic/getopt.cpp', + 'generic/stdio_ext.cpp', + 'generic/sys-ioctl.cpp', + 'generic/err.cpp', + 'generic/error.cpp', + 'generic/resolv.cpp', + 'generic/shadow.cpp', + 'generic/printf.cpp', + 'generic/glibc-signal.cpp', + 'generic/execinfo.cpp', + 'generic/string.cpp', + 'generic/personality.cpp', + 'generic/gshadow.cpp', + 'generic/sys-timex.cpp', + 'generic/glibc-assert.cpp', + 'generic/malloc.cpp', + 'generic/sys-cachectl.cpp', + 'generic/sys-io.cpp', + 'generic/search.cpp', + 'generic/stdlib.cpp' +) + +if not no_headers + install_headers( + 'include/getopt.h', + 'include/stdio_ext.h', + 'include/err.h', + 'include/error.h', + 'include/paths.h', + 'include/sysexits.h', + 'include/resolv.h', + 'include/endian.h', + 'include/ar.h', + 'include/shadow.h', + 'include/memory.h', + 'include/printf.h', + 'include/gshadow.h', + 'include/execinfo.h', + 'include/features.h' + ) + install_headers( + 'include/sys/cachectl.h', + 'include/sys/dir.h', + 'include/sys/ioctl.h', + 'include/sys/user.h', + 'include/sys/procfs.h', + 'include/sys/reg.h', + 'include/sys/errno.h', + 'include/sys/signal.h', + 'include/sys/ucontext.h', + 'include/sys/personality.h', + 'include/sys/timeb.h', + 'include/sys/mtio.h', + 'include/sys/endian.h', + 'include/sys/timex.h', + 'include/sys/kd.h', + 'include/sys/io.h', + subdir: 'sys' + ) + install_headers( + 'include/net/ethernet.h', + 'include/net/route.h', + 'include/net/if_ppp.h', + subdir: 'net' + ) + install_headers( + 'include/netax25/ax25.h', + subdir: 'netax25' + ) + install_headers( + 'include/netipx/ipx.h', + subdir: 'netipx' + ) + install_headers( + 'include/netrom/netrom.h', + subdir: 'netrom' + ) + install_headers( + 'include/netinet/in_systm.h', + subdir: 'netinet' + ) + install_headers( + 'include/bits/glibc/glibc_signal.h', + 'include/bits/glibc/glibc_assert.h', + 'include/bits/glibc/glibc_malloc.h', + 'include/bits/glibc/glibc_icmp6.h', + 'include/bits/glibc/glibc_search.h', + 'include/bits/glibc/glibc_stdlib.h', + subdir: 'bits/glibc' + ) +endif + diff --git a/user/include/mlibc/options/internal/aarch64-include/mlibc/arch-defs.hpp b/user/include/mlibc/options/internal/aarch64-include/mlibc/arch-defs.hpp new file mode 100644 index 0000000..0a4789f --- /dev/null +++ b/user/include/mlibc/options/internal/aarch64-include/mlibc/arch-defs.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP diff --git a/user/include/mlibc/options/internal/aarch64-include/mlibc/thread.hpp b/user/include/mlibc/options/internal/aarch64-include/mlibc/thread.hpp new file mode 100644 index 0000000..1e5b305 --- /dev/null +++ b/user/include/mlibc/options/internal/aarch64-include/mlibc/thread.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + // On AArch64, TPIDR_EL0 points to 0x10 bytes before the first TLS block. + uintptr_t ptr; + asm volatile ("mrs %0, tpidr_el0" : "=r"(ptr)); + return reinterpret_cast(ptr + 0x10 - sizeof(Tcb)); +} + +inline uintptr_t get_sp() { + uintptr_t sp; + asm volatile ("mov %0, sp" : "=r"(sp)); + return sp; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/aarch64/fenv.S b/user/include/mlibc/options/internal/aarch64/fenv.S new file mode 100644 index 0000000..1b02e87 --- /dev/null +++ b/user/include/mlibc/options/internal/aarch64/fenv.S @@ -0,0 +1,69 @@ +# The functions below are taken from musl. +.global fegetround +.type fegetround,%function +fegetround: + mrs x0, fpcr + and w0, w0, #0xc00000 + ret + +.global __fesetround +.hidden __fesetround +.type __fesetround,%function +__fesetround: + mrs x1, fpcr + bic w1, w1, #0xc00000 + orr w1, w1, w0 + msr fpcr, x1 + mov w0, #0 + ret + +.global fetestexcept +.type fetestexcept,%function +fetestexcept: + and w0, w0, #0x1f + mrs x1, fpsr + and w0, w0, w1 + ret + +.global feclearexcept +.type feclearexcept,%function +feclearexcept: + and w0, w0, #0x1f + mrs x1, fpsr + bic w1, w1, w0 + msr fpsr, x1 + mov w0, #0 + ret + +.global feraiseexcept +.type feraiseexcept,%function +feraiseexcept: + and w0, w0, #0x1f + mrs x1, fpsr + orr w1, w1, w0 + msr fpsr, x1 + mov w0, #0 + ret + +.global fegetenv +.type fegetenv,%function +fegetenv: + mrs x1, fpcr + mrs x2, fpsr + stp w1, w2, [x0] + mov w0, #0 + ret + +// TODO preserve some bits +.global fesetenv +.type fesetenv,%function +fesetenv: + mov x1, #0 + mov x2, #0 + cmn x0, #1 + b.eq 1f + ldp w1, w2, [x0] +1: msr fpcr, x1 + msr fpsr, x2 + mov w0, #0 + ret diff --git a/user/include/mlibc/options/internal/aarch64/setjmp.S b/user/include/mlibc/options/internal/aarch64/setjmp.S new file mode 100644 index 0000000..f76df31 --- /dev/null +++ b/user/include/mlibc/options/internal/aarch64/setjmp.S @@ -0,0 +1,67 @@ +// vim: ft=arm64asm + +.extern __sigsetjmp + +.type __setjmp, "function" +__setjmp: + stp x19, x20, [x0, #0] + stp x21, x22, [x0, #16] + stp x23, x24, [x0, #32] + stp x25, x26, [x0, #48] + stp x27, x28, [x0, #64] + stp x29, x30, [x0, #80] + mov x4, sp + str x4, [x0, #96] + + stp d8, d9, [x0, #112] + stp d10, d11, [x0, #128] + stp d12, d13, [x0, #144] + stp d14, d15, [x0, #160] + + cbnz x2, 1f + + mov x0, xzr + ret +1: + b __sigsetjmp + +.global setjmp +.type setjmp, "function" +.global _setjmp +.type _setjmp, "function" +setjmp: +_setjmp: + mov x2, xzr + b __setjmp + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + mov x2, #1 + b __setjmp + +.global longjmp +.type longjmp, "function" +.global _longjmp +.type _longjmp, "function" +longjmp: +_longjmp: + ldp x19, x20, [x0, #0] + ldp x21, x22, [x0, #16] + ldp x23, x24, [x0, #32] + ldp x25, x26, [x0, #48] + ldp x27, x28, [x0, #64] + ldp x29, x30, [x0, #80] + ldr x4, [x0, #96] + mov sp, x4 + + ldp d8, d9, [x0, #112] + ldp d10, d11, [x0, #128] + ldp d12, d13, [x0, #144] + ldp d14, d15, [x0, #160] + + cmp w1, 0 + csinc w0, w1, wzr, ne + br x30 +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/internal/gcc-extra/cxxabi.cpp b/user/include/mlibc/options/internal/gcc-extra/cxxabi.cpp new file mode 100644 index 0000000..dff7d94 --- /dev/null +++ b/user/include/mlibc/options/internal/gcc-extra/cxxabi.cpp @@ -0,0 +1,20 @@ + +#include + +// The cxxabi needs operator delete for *deleting* destructors, i.e., destructors that +// are called by delete expressions. We never use such expressions in mlibc. +// Note that G++ complains if we make the operator hidden, +// thus we use it's mangled name as a workaround. +#if defined(__clang__) + extern "C" [[gnu::visibility("hidden")]] void _ZdlPv() { // operator delete (void *, size_t) + __ensure(!"operator delete called! delete expressions cannot be used in mlibc."); + } +#endif + +extern "C" [[gnu::visibility("hidden")]] void _ZdlPvj() { // operator delete (void *, unsigned int) + __ensure(!"operator delete called! delete expressions cannot be used in mlibc."); +} + +extern "C" [[gnu::visibility("hidden")]] void _ZdlPvm() { // operator delete (void *, size_t) + __ensure(!"operator delete called! delete expressions cannot be used in mlibc."); +} diff --git a/user/include/mlibc/options/internal/gcc/guard-abi.cpp b/user/include/mlibc/options/internal/gcc/guard-abi.cpp new file mode 100644 index 0000000..eace339 --- /dev/null +++ b/user/include/mlibc/options/internal/gcc/guard-abi.cpp @@ -0,0 +1,70 @@ + +#include +#include +#include + +#include +#include + +namespace { + +// Itanium ABI static initialization guard. +struct Guard { + // bit of the mutex member variable. + // indicates that the mutex is locked. + static constexpr int32_t locked = 1; + + void lock() { + uint32_t v = 0; + if(__atomic_compare_exchange_n(&mutex, &v, Guard::locked, false, + __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + return; + + mlibc::sys_libc_log("__cxa_guard_acquire contention"); + __builtin_trap(); + } + + void unlock() { + __atomic_store_n(&mutex, 0, __ATOMIC_RELEASE); + } + + // the first byte's meaning is fixed by the ABI. + // it indicates whether initialization has already been completed. + uint8_t complete; + // padding to ensure correct alignment on certain platforms. + uint8_t padding[3]; + + // we use some of the remaining bytes to implement a mutex. + uint32_t mutex; +}; + +static_assert(sizeof(Guard) == sizeof(int64_t)); + +} // namespace + +extern "C" [[ gnu::visibility("hidden") ]] void __cxa_pure_virtual() { + mlibc::panicLogger() << "mlibc: Pure virtual function called from IP " + << (void *)__builtin_return_address(0) << frg::endlog; +} + +extern "C" [[ gnu::visibility("hidden") ]] int __cxa_guard_acquire(int64_t *ptr) { + auto guard = reinterpret_cast(ptr); + guard->lock(); + // relaxed ordering is sufficient because + // Guard::complete is only modified while the mutex is held. + if(__atomic_load_n(&guard->complete, __ATOMIC_RELAXED)) { + guard->unlock(); + return 0; + }else{ + return 1; + } +} + +extern "C" [[ gnu::visibility("hidden") ]] void __cxa_guard_release(int64_t *ptr) { + auto guard = reinterpret_cast(ptr); + // do a store-release so that compiler generated code can skip calling + // __cxa_guard_acquire by doing a load-acquire on Guard::complete. + __atomic_store_n(&guard->complete, 1, __ATOMIC_RELEASE); + guard->unlock(); +} + diff --git a/user/include/mlibc/options/internal/gcc/stack_protector.cpp b/user/include/mlibc/options/internal/gcc/stack_protector.cpp new file mode 100644 index 0000000..e5e50f0 --- /dev/null +++ b/user/include/mlibc/options/internal/gcc/stack_protector.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +uintptr_t __stack_chk_guard = 0; + +namespace mlibc { + +void initStackGuard(void *entropy) { + if(entropy != nullptr) { + memcpy(&__stack_chk_guard, entropy, sizeof(__stack_chk_guard)); + } else { + // If no entropy is available, set it to the terminator canary + __stack_chk_guard = 0; + __stack_chk_guard |= ('\n' << 16); + __stack_chk_guard |= (255 << 24); + } +} + +} // namespace mlibc + +extern "C" [[noreturn]] void __stack_chk_fail() { + mlibc::panicLogger() << "Stack smashing detected!" << frg::endlog; + __builtin_unreachable(); +} + +extern "C" [[noreturn, gnu::visibility("hidden")]] void __stack_chk_fail_local() { + __stack_chk_fail(); +}; + diff --git a/user/include/mlibc/options/internal/generic/allocator.cpp b/user/include/mlibc/options/internal/generic/allocator.cpp new file mode 100644 index 0000000..8b61fd5 --- /dev/null +++ b/user/include/mlibc/options/internal/generic/allocator.cpp @@ -0,0 +1,209 @@ + +#include + +#include +#include +#include +#include +#include + +#if !MLIBC_DEBUG_ALLOCATOR + +// -------------------------------------------------------- +// Globals +// -------------------------------------------------------- + +MemoryAllocator &getAllocator() { + // use frg::eternal to prevent a call to __cxa_atexit(). + // this is necessary because __cxa_atexit() call this function. + static frg::eternal virtualAllocator; + static frg::eternal heap{virtualAllocator.get()}; + static frg::eternal singleton{&heap.get()}; + return singleton.get(); +} + +// -------------------------------------------------------- +// VirtualAllocator +// -------------------------------------------------------- + +uintptr_t VirtualAllocator::map(size_t length) { + void *ptr; + __ensure(!mlibc::sys_anon_allocate(length, &ptr)); + return (uintptr_t)ptr; +} + +void VirtualAllocator::unmap(uintptr_t address, size_t length) { + __ensure(!mlibc::sys_anon_free((void *)address, length)); +} + +#else + +namespace { + struct AllocatorMeta { + size_t allocatedSize; + size_t pagesSize; + frg::array magic; + }; + + constexpr frg::array allocatorMagic { + 0x6d4bbb9f3446e83f, 0x25e213a7a7f9f954, + 0x1a3c667586538bef, 0x994f34ff71c090bc + }; +} // namespace anonymous + +// Turn vm_unmap calls in free into vm_map(..., PROT_NONE, ...) calls to prevent +// those addresses from being reused. This is useful for detecting situations like this: +// 1. Allocate object X at address Y +// 2. Do some computation using object X +// 3. Free object X at address Y +// 4. Allocate object Z at address W, and it so happens that W == Y +// 5. Try to use object X, but the memory which was backing it now contains object Z +constexpr bool neverReleaseVa = false; +constexpr bool logAllocations = false; + +// Area before the returned allocated block (which exists due to us offseting +// the block to be as close to the edge of a page). +constexpr uint8_t offsetAreaValue = 'A'; +// Area which we return a pointer to in allocate and reallocate. +constexpr uint8_t allocatedAreaValue = 'B'; +// Area after the allocated block, which exists due to the alignment constraints. +constexpr uint8_t alignmentAreaValue = 'C'; +// Remaining area within the metadata page after the metadata. +constexpr uint8_t metaAreaValue = 'D'; + +// Alignment of the returned memory. +// TODO(qookie): Eventually accept alignment as an argument of allocate. +constexpr size_t pointerAlignment = 16; + +// TODO(qookie): Support this. Perhaps by overallocating by 2x and then picking +// an offset that guarantees the desired alignment. +static_assert(pointerAlignment <= 4096, "Pointer aligment of more than 4096 bytes is unsupported"); +static_assert(!(pointerAlignment & (pointerAlignment - 1)), + "Pointer aligment must be a power of 2"); + +constexpr size_t pageSize = 0x1000; + +void *MemoryAllocator::allocate(size_t size) { + size_t pg_size = (size + size_t{pageSize - 1}) & ~size_t{pageSize - 1}; + size_t offset = (pg_size - size) & ~size_t{pointerAlignment - 1}; + + void *ptr; + + // Two extra pages for metadata in front and guard page at the end + // Reserve the whole region as PROT_NONE... + if (int e = mlibc::sys_vm_map(nullptr, pg_size + pageSize * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0, &ptr)) + mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::allocate (errno " << e << ")" << frg::endlog; + + // ...Then replace pages to make them accessible, excluding the guard page + if (int e = mlibc::sys_vm_map(ptr, pg_size + pageSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0, &ptr)) + mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::allocate (errno " << e << ")" << frg::endlog; + + void *meta = ptr; + void *out_page = reinterpret_cast(reinterpret_cast(ptr) + pageSize); + void *out = reinterpret_cast(reinterpret_cast(out_page) + offset); + void *out_align_area = reinterpret_cast(reinterpret_cast(out) + size); + + AllocatorMeta metaData{size, pg_size, allocatorMagic}; + + memset(meta, metaAreaValue, pageSize); + memcpy(meta, &metaData, sizeof(AllocatorMeta)); + + memset(out_page, offsetAreaValue, offset); + memset(out, allocatedAreaValue, size); + memset(out_align_area, alignmentAreaValue, pg_size - offset - size); + + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::allocate(" << size << ") = " << out << frg::endlog; + + return out; +} + +void MemoryAllocator::free(void *ptr) { + if (!ptr) + return; + + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::free(" << ptr << ")" << frg::endlog; + + uintptr_t page_addr = reinterpret_cast(ptr) & ~size_t{pageSize - 1}; + AllocatorMeta *meta = reinterpret_cast(page_addr - pageSize); + + if (meta->magic != allocatorMagic) + mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::free" << frg::endlog; + + deallocate(ptr, meta->allocatedSize); +} + +void MemoryAllocator::deallocate(void *ptr, size_t size) { + if (!ptr) + return; + + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::deallocate(" << ptr << ", " << size << ")" << frg::endlog; + + uintptr_t page_addr = reinterpret_cast(ptr) & ~size_t{pageSize - 1}; + AllocatorMeta *meta = reinterpret_cast(page_addr - pageSize); + + if (meta->magic != allocatorMagic) + mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::deallocate" << frg::endlog; + + if (size != meta->allocatedSize) + mlibc::panicLogger() << "Invalid allocated size in metadata in MemoryAllocator::deallocate (given " << size << ", stored " << meta->allocatedSize << ")" << frg::endlog; + + if constexpr (neverReleaseVa) { + void *unused; + if (int e = mlibc::sys_vm_map(meta, meta->pagesSize + pageSize * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0, &unused)) + mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::deallocate (errno " << e << ")" << frg::endlog; + } else { + if (int e = mlibc::sys_vm_unmap(meta, meta->pagesSize + pageSize * 2)) + mlibc::panicLogger() << "sys_vm_unmap failed in MemoryAllocator::deallocate (errno " << e << ")" << frg::endlog; + } +} + +void *MemoryAllocator::reallocate(void *ptr, size_t size) { + if (!size) { + free(ptr); + return nullptr; + } + + void *newArea = allocate(size); + + if (ptr) { + uintptr_t page_addr = reinterpret_cast(ptr) & ~size_t{pageSize - 1}; + AllocatorMeta *meta = reinterpret_cast(page_addr - pageSize); + + if (meta->magic != allocatorMagic) + mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::reallocate" << frg::endlog; + + memcpy(newArea, ptr, frg::min(meta->allocatedSize, size)); + + deallocate(ptr, meta->allocatedSize); + } + + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::reallocate(" << ptr << ", " << size << ") = " << newArea << frg::endlog; + + return newArea; +} + +size_t MemoryAllocator::get_size(void *ptr) { + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::get_size(" << ptr << ")" << frg::endlog; + + uintptr_t page_addr = reinterpret_cast(ptr) & ~size_t{pageSize - 1}; + AllocatorMeta *meta = reinterpret_cast(page_addr - pageSize); + + if (meta->magic != allocatorMagic) + mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::get_size" << frg::endlog; + + return meta->allocatedSize; +} + +MemoryAllocator &getAllocator() { + // use frg::eternal to prevent a call to __cxa_atexit(). + // this is necessary because __cxa_atexit() call this function. + static frg::eternal singleton{}; + return singleton.get(); +} + +#endif /* !MLIBC_DEBUG_ALLOCATOR */ diff --git a/user/include/mlibc/options/internal/generic/charcode.cpp b/user/include/mlibc/options/internal/generic/charcode.cpp new file mode 100644 index 0000000..03415ed --- /dev/null +++ b/user/include/mlibc/options/internal/generic/charcode.cpp @@ -0,0 +1,268 @@ + +#include +#include +#include +#include + +namespace mlibc { + +struct utf8_charcode { + static constexpr bool preserves_7bit_units = true; + static constexpr bool has_shift_states = false; + + struct decode_state { + decode_state() + : _progress{0}, _cpoint{0} { } + + auto progress() { return _progress; } + auto cpoint() { return _cpoint; } + + charcode_error operator() (code_seq &seq) { + auto uc = static_cast(*seq.it); + if(!_progress) { + if(!(uc & 0b1000'0000)) { + // ASCII-compatible. + _cpoint = uc; + }else if((uc & 0b1110'0000) == 0b1100'0000) { + _cpoint = uc & 0b1'1111; + _progress = 1; + }else if((uc & 0b1111'0000) == 0b1110'0000) { + _cpoint = uc & 0b1111; + _progress = 2; + }else if((uc & 0b1111'1000) == 0b1111'0000) { + _cpoint = uc & 0b111; + _progress = 3; + }else{ + // If the highest two bits are 0b10, this is the second (or later) unit. + // Units with highest five bits = 0b11111 do not occur in valid UTF-8. + __ensure((uc & 0b1100'0000) == 0b1000'0000 + || (uc & 0b1111'1000) == 0b1111'1000); + return charcode_error::illegal_input; + } + }else{ + // TODO: Return an error. + __ensure((uc & 0b1100'0000) == 0b1000'0000); + _cpoint = (_cpoint << 6) | (uc & 0x3F); + --_progress; + } + ++seq.it; + return charcode_error::null; + } + + private: + int _progress; + codepoint _cpoint; + }; + +#define NSEQ_STORE(VAL) do { \ + if (!static_cast(nseq)) { \ + return charcode_error::output_overflow; \ + } \ + *nseq.it = (VAL); \ + ++nseq.it; \ +} while (0) + + struct encode_state { + // Encodes a single character from wseq + the current state and stores it in nseq. + // TODO: Convert decode_state to the same strategy. + charcode_error operator() (code_seq &nseq, code_seq &wseq) { + auto wc = *wseq.it; + if (wc <= 0x7F) { + NSEQ_STORE(wc); + } else if (wc <= 0x7FF) { + NSEQ_STORE(0xC0 | (wc >> 6)); + NSEQ_STORE(0x80 | (wc & 0x3f)); + } else if (wc <= 0xFFFF) { + NSEQ_STORE(0xE0 | (wc >> 12)); + NSEQ_STORE(0x80 | ((wc >> 6) & 0x3f)); + NSEQ_STORE(0x80 | (wc & 0x3f)); + } else if (wc <= 0x10FFFF) { + NSEQ_STORE(0xF0 | (wc >> 18)); + NSEQ_STORE(0x80 | ((wc >> 12) & 0x3f)); + NSEQ_STORE(0x80 | ((wc >> 6) & 0x3f)); + NSEQ_STORE(0x80 | (wc & 0x3f)); + } else { + return charcode_error::illegal_input; + } + ++wseq.it; + return charcode_error::null; + } + }; + +#undef NSEQ_STORE +}; + +polymorphic_charcode::~polymorphic_charcode() = default; + +// For *decoding, this class assumes that: +// - G::decode_state has members progress() and cpoint(). +// - G::decode_state::progress() >= 0 at all times. +// TODO: This will be needed on platforms like Windows, where wchar_t is UTF-16. +// TODO: There, we can use negative __mlibc_mbstate::progress to represent encoding to UTF-16. +// - If G::decode_state::progress() == 0, the code point (given by cpoint()) +// was decoded successfully. +template +struct polymorphic_charcode_adapter : polymorphic_charcode { + polymorphic_charcode_adapter() + : polymorphic_charcode{G::preserves_7bit_units, G::has_shift_states} { } + + charcode_error decode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint(). + + code_seq decode_nseq = nseq; + typename G::decode_state ds; + + while(decode_nseq && wseq) { + // Consume the next code unit. + if(auto e = ds(decode_nseq); e != charcode_error::null) + return e; + + // Produce a new code point. + if(!ds.progress()) { + // "Commit" consumed code units (as there was no decode error). + nseq.it = decode_nseq.it; + if(!ds.cpoint()) // Stop on null characters. + return charcode_error::null; + *wseq.it = ds.cpoint(); + ++wseq.it; + } + } + + if(ds.progress()) + return charcode_error::input_underflow; + return charcode_error::null; + } + + charcode_error decode_wtranscode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint(). + + code_seq decode_nseq = nseq; + typename G::decode_state ds; + + while(decode_nseq && wseq) { + // Consume the next code unit. + if(auto e = ds(decode_nseq); e != charcode_error::null) + return e; + + // Produce a new code point. + if(!ds.progress()) { + nseq.it = decode_nseq.it; + // "Commit" consumed code units (as there was no decode error). + if(!ds.cpoint()) // Stop on null characters. + return charcode_error::null; + *wseq.it = ds.cpoint(); + ++wseq.it; + } + } + + if(ds.progress()) + return charcode_error::input_underflow; + return charcode_error::null; + } + + charcode_error decode_wtranscode_length(code_seq &nseq, size_t *n, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint(). + + code_seq decode_nseq = nseq; + typename G::decode_state ds; + + *n = 0; + while(decode_nseq) { + // Consume the next code unit. + if(auto e = ds(decode_nseq); e != charcode_error::null) + return e; + + if(!ds.progress()) { + nseq.it = decode_nseq.it; + // "Commit" consumed code units (as there was no decode error). + if(!ds.cpoint()) // Stop on null code points. + return charcode_error::null; + ++(*n); + } + } + + if(ds.progress()) + return charcode_error::input_underflow; + return charcode_error::null; + } + + charcode_error encode_wtranscode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with es.progress() and es.cpoint(). + + code_seq encode_nseq = nseq; + typename G::encode_state es; + + while(encode_nseq && wseq) { + codepoint cp = *wseq.it; + if(!cp) + return charcode_error::null; + + code_seq cps{&cp, &cp + 1}; + if(auto e = es(encode_nseq, cps); e == charcode_error::dirty) { + continue; + }else if(e != charcode_error::null) { + return e; + } + __ensure(cps.it == cps.end); + ++wseq.it; + + // "Commit" produced code units (as there was no encode error). + nseq.it = encode_nseq.it; + } + + if(encode_nseq.it != nseq.it) + return charcode_error::output_overflow; + return charcode_error::null; + } + + charcode_error encode_wtranscode_length(code_seq &wseq, size_t *n, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with es.progress() and es.cpoint(). + + typename G::encode_state es; + + *n = 0; + while(wseq) { + char temp[4]; + code_seq encode_nseq{temp, temp + 4}; + codepoint cp = *wseq.it; + if(!cp) + return charcode_error::null; + // Consume the next code unit. + code_seq cps{&cp, &cp + 1}; + if(auto e = es(encode_nseq, cps); e == charcode_error::dirty) { + continue; + }else if(e != charcode_error::null) { + return e; + } + + ++(*n); + ++wseq.it; + } + + return charcode_error::null; + } +}; + +polymorphic_charcode *current_charcode() { + static polymorphic_charcode_adapter global_charcode; + return &global_charcode; +} + +charcode_error wide_charcode::promote(wchar_t nc, codepoint &wc) { + // TODO: Allow non-identity encodings of wchar_t. + wc = nc; + return charcode_error::null; +} + +wide_charcode *platform_wide_charcode() { + static wide_charcode global_wide_charcode; + return &global_wide_charcode; +} + +} // namespace mlibc + diff --git a/user/include/mlibc/options/internal/generic/charset.cpp b/user/include/mlibc/options/internal/generic/charset.cpp new file mode 100644 index 0000000..c42b4f4 --- /dev/null +++ b/user/include/mlibc/options/internal/generic/charset.cpp @@ -0,0 +1,144 @@ + +#include +#include +#include + +namespace mlibc { + +bool charset::is_ascii_superset() { + // TODO: For locales that change the meaning of ASCII chars, this needs to be changed. + return true; +} + +bool charset::is_alpha(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_alpha() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_digit(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c >= '0' && c <= '9'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_digit() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_xdigit(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_xdigit() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_alnum(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_alnum() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_punct(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c == '!' || c == '"' || c == '#' || c == '$' || c == '%' || c == '&' + || c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || c == ',' + || c == '-' || c == '.' || c == '/' + || c == ':' || c == ';' || c == '<' || c == '=' || c == '>' || c == '?' + || c == '@' + || c == '[' || c == '\\' || c == ']' || c == '^' || c == '_' || c == '`' + || c == '{' || c == '|' || c == '}' || c == '~'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_punct() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_graph(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c >= 0x21 && c <= 0x7E; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_graph() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_blank(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c == ' ' || c == '\t'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_blank() is not implemented" + " for the full Unicode charset " << c << frg::endlog; + return false; +} + +bool charset::is_space(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_space() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_print(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c >= 0x20 && c <= 0x7E; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_lower(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= 'a' && c <= 'z'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_upper(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= 'A' && c <= 'Z'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +codepoint charset::to_lower(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + if(c >= 'A' && c <= 'Z') + return c - 'A' + 'a'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::to_lower() is not implemented" + " for the full Unicode charset" << frg::endlog; + return c; +} + +codepoint charset::to_upper(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + if(c >= 'a' && c <= 'z') + return c - 'a' + 'A'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::to_upper() is not implemented" + " for the full Unicode charset" << frg::endlog; + return c; +} + +charset *current_charset() { + static charset global_charset; + return &global_charset; +} + +} // namespace mlibc + diff --git a/user/include/mlibc/options/internal/generic/debug.cpp b/user/include/mlibc/options/internal/generic/debug.cpp new file mode 100644 index 0000000..19427c8 --- /dev/null +++ b/user/include/mlibc/options/internal/generic/debug.cpp @@ -0,0 +1,22 @@ + +#include +#include +#include + +namespace mlibc { + +frg::stack_buffer_logger infoLogger; +frg::stack_buffer_logger panicLogger; + +void InfoSink::operator() (const char *message) { + sys_libc_log(message); +} + +void PanicSink::operator() (const char *message) { +// sys_libc_log("mlibc: Write to PanicSink"); + sys_libc_log(message); + sys_libc_panic(); +} + +} // namespace mlibc + diff --git a/user/include/mlibc/options/internal/generic/ensure.cpp b/user/include/mlibc/options/internal/generic/ensure.cpp new file mode 100644 index 0000000..57c953a --- /dev/null +++ b/user/include/mlibc/options/internal/generic/ensure.cpp @@ -0,0 +1,18 @@ + +#include +#include + +void __ensure_fail(const char *assertion, const char *file, unsigned int line, + const char *function) { + mlibc::panicLogger() << "In function " << function + << ", file " << file << ":" << line << "\n" + << "__ensure(" << assertion << ") failed" << frg::endlog; +} + +void __ensure_warn(const char *assertion, const char *file, unsigned int line, + const char *function) { + mlibc::infoLogger() << "In function " << function + << ", file " << file << ":" << line << "\n" + << "__ensure(" << assertion << ") failed" << frg::endlog; +} + diff --git a/user/include/mlibc/options/internal/generic/essential.cpp b/user/include/mlibc/options/internal/generic/essential.cpp new file mode 100644 index 0000000..bbf5d7a --- /dev/null +++ b/user/include/mlibc/options/internal/generic/essential.cpp @@ -0,0 +1,215 @@ +#include +#include + +namespace { + template + [[gnu::always_inline]] + inline T alias_load(const unsigned char *&p) { + T value; + __builtin_memcpy(&value, p, sizeof(value)); + p += sizeof(T); + return value; + } + + template + [[gnu::always_inline]] + inline void alias_store(unsigned char *&p, T value) { + __builtin_memcpy(p, &value, sizeof(value)); + p += sizeof(T); + } + +#if defined(__LP64__) && !defined(__riscv) + void *forward_copy(void *__restrict dest, const void *__restrict src, size_t n) { + auto curDest = reinterpret_cast(dest); + auto curSrc = reinterpret_cast(src); + + while(n >= 8 * 8) { + auto w1 = alias_load(curSrc); + auto w2 = alias_load(curSrc); + auto w3 = alias_load(curSrc); + auto w4 = alias_load(curSrc); + auto w5 = alias_load(curSrc); + auto w6 = alias_load(curSrc); + auto w7 = alias_load(curSrc); + auto w8 = alias_load(curSrc); + alias_store(curDest, w1); + alias_store(curDest, w2); + alias_store(curDest, w3); + alias_store(curDest, w4); + alias_store(curDest, w5); + alias_store(curDest, w6); + alias_store(curDest, w7); + alias_store(curDest, w8); + n -= 8 * 8; + } + if(n >= 4 * 8) { + auto w1 = alias_load(curSrc); + auto w2 = alias_load(curSrc); + auto w3 = alias_load(curSrc); + auto w4 = alias_load(curSrc); + alias_store(curDest, w1); + alias_store(curDest, w2); + alias_store(curDest, w3); + alias_store(curDest, w4); + n -= 4 * 8; + } + if(n >= 2 * 8) { + auto w1 = alias_load(curSrc); + auto w2 = alias_load(curSrc); + alias_store(curDest, w1); + alias_store(curDest, w2); + n -= 2 * 8; + } + if(n >= 8) { + auto w = alias_load(curSrc); + alias_store(curDest, w); + n -= 8; + } + if(n >= 4) { + auto w = alias_load(curSrc); + alias_store(curDest, w); + n -= 4; + } + if(n >= 2) { + auto w = alias_load(curSrc); + alias_store(curDest, w); + n -= 2; + } + if(n) + *curDest = *curSrc; + return dest; + } +#else // !__LP64__ + void *forward_copy(void *dest, const void *src, size_t n) { + for(size_t i = 0; i < n; i++) + ((char *)dest)[i] = ((const char *)src)[i]; + return dest; + } +#endif // __LP64__ / !__LP64__ +} // namespace + +// -------------------------------------------------------------------------------------- +// memcpy() implementation. +// -------------------------------------------------------------------------------------- + + +void *memcpy(void *__restrict dest, const void *__restrict src, size_t n) { + return forward_copy(dest, src, n); +} + + +// -------------------------------------------------------------------------------------- +// memset() implementation. +// -------------------------------------------------------------------------------------- + +#ifdef __LP64__ + +void *memset(void *dest, int val, size_t n) { + auto curDest = reinterpret_cast(dest); + unsigned char byte = val; + + // Get rid of misalignment. + while(n && (uintptr_t(curDest) & 7)) { + *curDest++ = byte; + --n; + } + + auto pattern64 = static_cast( + static_cast(byte) + | (static_cast(byte) << 8) + | (static_cast(byte) << 16) + | (static_cast(byte) << 24) + | (static_cast(byte) << 32) + | (static_cast(byte) << 40) + | (static_cast(byte) << 48) + | (static_cast(byte) << 56)); + + auto pattern32 = static_cast( + static_cast(byte) + | (static_cast(byte) << 8) + | (static_cast(byte) << 16) + | (static_cast(byte) << 24)); + + auto pattern16 = static_cast( + static_cast(byte) + | (static_cast(byte) << 8)); + + while(n >= 8 * 8) { + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + n -= 8 * 8; + } + if(n >= 4 * 8) { + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + n -= 4 * 8; + } + if(n >= 2 * 8) { + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + n -= 2 * 8; + } + if(n >= 8) { + alias_store(curDest, pattern64); + n -= 8; + } + if(n >= 4) { + alias_store(curDest, pattern32); + n -= 4; + } + if(n >= 2) { + alias_store(curDest, pattern16); + n -= 2; + } + if(n) + *curDest = byte; + return dest; +} + +#else // !__LP64__ + +void *memset(void *dest, int byte, size_t count) { + for(size_t i = 0; i < count; i++) + ((char *)dest)[i] = (char)byte; + return dest; +} + +#endif // __LP64__ / !__LP64__ + +// -------------------------------------------------------------------------------------- +// "Non-optimized" functions. +// -------------------------------------------------------------------------------------- + +void *memmove(void *dest, const void *src, size_t size) { + // Use uintptr_t for pointer comparisons because otherwise it's undefined behaviour + // when dest and src point to different objects. + uintptr_t udest = reinterpret_cast(dest); + uintptr_t usrc = reinterpret_cast(src); + + if(udest < usrc || usrc + size <= udest) { + return forward_copy(dest, src, size); + } else if(udest > usrc) { + char *dest_bytes = (char *)dest; + char *src_bytes = (char *)src; + + for(size_t i = 0; i < size; i++) + dest_bytes[size - i - 1] = src_bytes[size - i - 1]; + } + + return dest; +} + +size_t strlen(const char *s) { + size_t len = 0; + for(size_t i = 0; s[i]; i++) + len++; + return len; +} diff --git a/user/include/mlibc/options/internal/generic/frigg.cpp b/user/include/mlibc/options/internal/generic/frigg.cpp new file mode 100644 index 0000000..7575c9c --- /dev/null +++ b/user/include/mlibc/options/internal/generic/frigg.cpp @@ -0,0 +1,14 @@ + +#include +#include +#include + +extern "C" void frg_panic(const char *mstr) { +// mlibc::sys_libc_log("mlibc: Call to frg_panic"); + mlibc::sys_libc_log(mstr); + mlibc::sys_libc_panic(); +} + +extern "C" void frg_log(const char *mstr) { + mlibc::sys_libc_log(mstr); +} diff --git a/user/include/mlibc/options/internal/generic/getopt.cpp b/user/include/mlibc/options/internal/generic/getopt.cpp new file mode 100644 index 0000000..bf8126b --- /dev/null +++ b/user/include/mlibc/options/internal/generic/getopt.cpp @@ -0,0 +1,393 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *optarg; +int optind = 1; +int opterr = 1; +int optopt; + +namespace { + +int __optpos = 1; + +int getopt_common_internal(int argc, char * const argv[], const char *optstring, const struct option *longopts, + int *longindex, enum mlibc::GetoptMode mode) { + // find a matching longopt for an `arg` of length `n` + // returns a size_t of the index of the matched longopt, preferring an exact over a partial match + // returns a char of the error that getopt should return if multiple matches were available + // returns a std::monostate if no longopt resulted in a exact or partial match + auto longopt_find = [&](const char *arg, size_t n) -> std::variant { + assert(mode != mlibc::GetoptMode::Short); + + frg::optional i = frg::null_opt; + + // first, attempt to find exactly one exact match + for(size_t longopt = 0; longopts[longopt].name; longopt++) { + if(strncmp(arg, longopts[longopt].name, n) || longopts[longopt].name[n]) + continue; + + if(i) { + if(opterr) + fprintf(stderr, "Multiple option declaration detected: %s\n", arg); + optind++; + return '?'; + } + + i = longopt; + } + + if(i) + return *i; + + // because no exact match was found, we now search for longopts with partial matches + for(size_t longopt = 0; longopts[longopt].name; longopt++) { + if(strncmp(arg, longopts[longopt].name, n)) + continue; + + if(i) { + if(opterr) + fprintf(stderr, "Multiple option declaration detected: %s\n", arg); + optind++; + return '?'; + } + + i = longopt; + } + + if(i) + return *i; + + return std::monostate{}; + }; + + auto longopt_consume = [&](const char *arg, char *s, int k, bool colon) -> frg::optional { + assert(mode != mlibc::GetoptMode::Short); + + // Consume the option and its argument. + if(longopts[k].has_arg == required_argument) { + if(s) { + // Consume the long option and its argument. + optarg = s + 1; + optind++; + }else if(optind + 1 < argc && argv[optind + 1]) { + // Consume the long option. + optind++; + + // Consume the option's argument. + optarg = argv[optind]; + optind++; + }else{ + /* If an error was detected, and the first character of optstring is not a colon, + and the external variable opterr is nonzero (which is the default), + getopt() prints an error message. */ + if(!colon && opterr) + fprintf(stderr, "--%s requires an argument.\n", arg); + + optopt = longopts[k].val; + optind++; + + /* If the first character of optstring is a colon (':'), then getopt() + returns ':' instead of '?' to indicate a missing option argument. */ + return colon ? ':' : '?'; + } + }else if(longopts[k].has_arg == optional_argument) { + if(s) { + // Consume the long option and its argument. + optarg = s + 1; + optind++; + }else{ + // Consume the long option. + optarg = nullptr; + optind++; + } + }else{ + __ensure(longopts[k].has_arg == no_argument); + + // did we get passed a value? + if(s && strlen(s)) { + optind++; + return colon ? ':' : '?'; + } + + // Consume the long option. + optind++; + optarg = nullptr; + } + + return frg::null_opt; + }; + + bool colon = optstring[0] == ':'; + bool stop_at_first_nonarg = (optstring[0] == '+' || getenv("POSIXLY_CORRECT")); + + // if optstring contains "W;", then "-W foo" is treated as the long option "--foo". + bool w_long_options = [&]{ + if(mode == mlibc::GetoptMode::Short) + return false; + + const char *W = strchr(optstring, 'W'); + if (!W) + return false; + return W[1] == ';'; + }(); + + auto isOptionArg = [](char *arg){ + // If the first character of arg '-', and the arg is not exactly + // equal to "-" or "--", then the arg is an option argument. + return arg[0] == '-' && strcmp(arg, "-") && strcmp(arg, "--"); + }; + + while(optind < argc) { + char *arg = argv[optind]; + if(!isOptionArg(arg)) { + if(!strcmp(arg, "--")) { + optind++; + return -1; + } + + if(stop_at_first_nonarg) { + optarg = nullptr; + return -1; + } + + bool further_options = false; + int skip = optind; + + for(; skip < argc; ++skip) { + if(isOptionArg(argv[skip])) { + further_options = true; + break; + } + } + + if(further_options) { + optind += skip - optind; + continue; + } else { + optarg = nullptr; + return -1; + } + } + + if(arg[1] == '-' && mode != mlibc::GetoptMode::Short) { + arg += 2; + + // Determine the end of the option name (vs. the start of the argument). + auto s = strchr(arg, '='); + size_t n = s ? (s - arg) : strlen(arg); + + auto k = longopt_find(arg, n); + if(std::holds_alternative(k)) { + if(opterr) + fprintf(stderr, "--%s is not a valid option.\n", arg); + optind++; + return '?'; + } else if(std::holds_alternative(k)) { + return std::get(k); + } + + if(longindex) + *longindex = std::get(k); + + if(auto r = longopt_consume(arg, s, std::get(k), colon); r) + return r.value(); + + if(!longopts[std::get(k)].flag) { + return longopts[std::get(k)].val; + }else{ + *longopts[std::get(k)].flag = longopts[std::get(k)].val; + return 0; + } + }else{ + /* handle short options, i.e. options with only one dash prefixed; e.g. `program -s` */ + unsigned int i = __optpos; + while(true) { + if(mode == mlibc::GetoptMode::LongOnly) { + const char *lo_arg = &arg[1]; + auto s = strchr(lo_arg, '='); + size_t n = s ? (s - lo_arg) : strlen(lo_arg); + + auto longopt_res = longopt_find(lo_arg, n); + + if(std::holds_alternative(longopt_res)) { + return std::get(longopt_res); + } else if(std::holds_alternative(longopt_res)) { + auto k = std::get(longopt_res); + if(auto r = longopt_consume(lo_arg, s, k, colon); r) + return r.value(); + + if(!longopts[k].flag) { + return longopts[k].val; + }else{ + *longopts[k].flag = longopts[k].val; + return 0; + } + } + } + + auto opt = strchr(optstring, arg[i]); + if(opt) { + if(opt[0] == 'W' && w_long_options) { + const char *lo_arg = [&]() { + if(opt[1]) { + return &arg[i] + 1; + } else { + return &arg[i + 1]; + } + }(); + + auto s = strchr(lo_arg, '='); + size_t n = s ? (s - lo_arg) : strlen(lo_arg); + + if(!n) { + optopt = 'W'; + optind++; + return colon ? ':' : '?'; + } + + auto longopt_res = longopt_find(lo_arg, n); + + if(std::holds_alternative(longopt_res)) { + return std::get(longopt_res); + } else if(std::holds_alternative(longopt_res)) { + auto k = std::get(longopt_res); + if(auto r = longopt_consume(lo_arg, s, k, colon); r) + return r.value(); + + if(!longopts[k].flag) { + return longopts[k].val; + }else{ + *longopts[k].flag = longopts[k].val; + return 0; + } + } else { + optind++; + return colon ? ':' : '?'; + } + } else if(opt[1] == ':') { + // one colon means the option requires an argument + // two colons mean the option takes an optional argument as part of the + // same argv element (in the same word as the option name itself) + bool required = (opt[2] != ':'); + + if(arg[i+1]) { + optarg = arg + i + 1; + } else if(optind + 1 < argc && argv[optind + 1] && required && argv[optind + 1][0] != '-') { + /* there is an argument to this short option, separated by a space, + * and the shortopt specification does not specify an optional arg */ + optarg = argv[optind + 1]; + optind++; + __optpos = 1; + } else if(!required) { + optarg = nullptr; + } else { + __optpos = 1; + optopt = arg[i]; + return colon ? ':' : '?'; + } + optind++; + } else { + if(arg[i+1]) { + __optpos++; + } else if(arg[i]) { + optind++; + } else { + optarg = nullptr; + return -1; + } + } + + return arg[i]; + } else { + /* If getopt() does not recognize an option character, it prints an error message to stderr, + stores the character in optopt, and returns '?'. The calling program may prevent + the error message by setting opterr to 0. */ + optopt = arg[1]; + if(opterr) + fprintf(stderr, "%s is not a valid option.\n", arg); + optind++; + return '?'; + } + } + } + } + + optarg = nullptr; + return -1; +} + +void permute(char **argv, int dest, int src) { + assert(src > dest); + char *tmp = argv[src]; + for(int i = src; i > dest; i--) { + argv[i] = argv[i - 1]; + } + argv[dest] = tmp; +} + +} // namespace + +#if __MLIBC_BSD_OPTION +extern "C" int optreset; +#endif /*__MLIBC_BSD_OPTION */ + +namespace mlibc { + +int getopt_common(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int *longindex, enum GetoptMode mode) { + // glibc extension: Setting optind to zero causes a full reset. + // TODO: Should we really reset opterr and the other flags? + if(!optind +#if __MLIBC_BSD_OPTION + || optreset +#endif //__MLIBC_BSD_OPTION + ) { + optarg = nullptr; + optind = 1; + optopt = 0; + __optpos = 1; +#if __MLIBC_BSD_OPTION + optreset = 0; +#endif //__MLIBC_BSD_OPTION + } + + int skipped = optind; + + if(optstring[0] != '+' && optstring[0] != '-') { + int i = optind; + + for(;; i++) { + if(i >= argc || !argv[i]) { + optarg = nullptr; + return -1; + } + if(argv[i][0] == '-' && argv[i][1]) + break; + } + + optind = i; + } + + int resumed = optind; + auto ret = getopt_common_internal(argc, argv, optstring, longopts, longindex, mode); + + if(resumed > skipped) { + for(int i = 0; i < (optind - resumed); i++) { + permute(const_cast(argv), skipped, optind - 1); + } + optind = skipped + (optind - resumed); + } + + return ret; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/generic/global-config.cpp b/user/include/mlibc/options/internal/generic/global-config.cpp new file mode 100644 index 0000000..e0d5952 --- /dev/null +++ b/user/include/mlibc/options/internal/generic/global-config.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +namespace mlibc { + +struct GlobalConfigGuard { + GlobalConfigGuard(); +}; + +GlobalConfigGuard guard; + +GlobalConfigGuard::GlobalConfigGuard() { + // Force the config to be created during initialization of libc.so. + mlibc::globalConfig(); +} + +static bool envEnabled(const char *env) { + auto value = getenv(env); + return value && *value && *value != '0'; +} + +GlobalConfig::GlobalConfig() { + debugMalloc = envEnabled("MLIBC_DEBUG_MALLOC"); +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/generic/inline-emitter.cpp b/user/include/mlibc/options/internal/generic/inline-emitter.cpp new file mode 100644 index 0000000..5fa71fa --- /dev/null +++ b/user/include/mlibc/options/internal/generic/inline-emitter.cpp @@ -0,0 +1,16 @@ +// This translation unit provides symbols for functions marked with __MLIBC_INLINE_DEFINITION. +// All headers with such functions must be included here. + +#define __MLIBC_EMIT_INLINE_DEFINITIONS + +#include + +#include + +#if __MLIBC_LINUX_OPTION +#include +#endif /* __MLIBC_LINUX_OPTION */ + +#ifndef MLIBC_BUILDING_RTLD +#include +#endif diff --git a/user/include/mlibc/options/internal/generic/locale.cpp b/user/include/mlibc/options/internal/generic/locale.cpp new file mode 100644 index 0000000..1939d33 --- /dev/null +++ b/user/include/mlibc/options/internal/generic/locale.cpp @@ -0,0 +1,99 @@ +#include +#include +#include + +namespace mlibc { + +char *nl_langinfo(nl_item item) { + if(item == CODESET) { + return const_cast("UTF-8"); + } else if(item >= ABMON_1 && item <= ABMON_12) { + switch(item) { + case ABMON_1: return const_cast("Jan"); + case ABMON_2: return const_cast("Feb"); + case ABMON_3: return const_cast("Mar"); + case ABMON_4: return const_cast("Apr"); + case ABMON_5: return const_cast("May"); + case ABMON_6: return const_cast("Jun"); + case ABMON_7: return const_cast("Jul"); + case ABMON_8: return const_cast("Aug"); + case ABMON_9: return const_cast("Sep"); + case ABMON_10: return const_cast("Oct"); + case ABMON_11: return const_cast("Nov"); + case ABMON_12: return const_cast("Dec"); + default: + __ensure(!"ABMON_* constants don't seem to be contiguous!"); + __builtin_unreachable(); + } + } else if(item >= MON_1 && item <= MON_12) { + switch(item) { + case MON_1: return const_cast("January"); + case MON_2: return const_cast("Feburary"); + case MON_3: return const_cast("March"); + case MON_4: return const_cast("April"); + case MON_5: return const_cast("May"); + case MON_6: return const_cast("June"); + case MON_7: return const_cast("July"); + case MON_8: return const_cast("August"); + case MON_9: return const_cast("September"); + case MON_10: return const_cast("October"); + case MON_11: return const_cast("November"); + case MON_12: return const_cast("December"); + default: + __ensure(!"MON_* constants don't seem to be contiguous!"); + __builtin_unreachable(); + } + } else if(item == AM_STR) { + return const_cast("AM"); + } else if(item == PM_STR) { + return const_cast("PM"); + } else if(item >= DAY_1 && item <= DAY_7) { + switch(item) { + case DAY_1: return const_cast("Sunday"); + case DAY_2: return const_cast("Monday"); + case DAY_3: return const_cast("Tuesday"); + case DAY_4: return const_cast("Wednesday"); + case DAY_5: return const_cast("Thursday"); + case DAY_6: return const_cast("Friday"); + case DAY_7: return const_cast("Saturday"); + default: + __ensure(!"DAY_* constants don't seem to be contiguous!"); + __builtin_unreachable(); + } + } else if(item >= ABDAY_1 && item <= ABDAY_7) { + switch(item) { + case ABDAY_1: return const_cast("Sun"); + case ABDAY_2: return const_cast("Mon"); + case ABDAY_3: return const_cast("Tue"); + case ABDAY_4: return const_cast("Wed"); + case ABDAY_5: return const_cast("Thu"); + case ABDAY_6: return const_cast("Fri"); + case ABDAY_7: return const_cast("Sat"); + default: + __ensure(!"ABDAY_* constants don't seem to be contiguous!"); + __builtin_unreachable(); + } + }else if(item == D_FMT) { + return const_cast("%m/%d/%y"); + }else if(item == T_FMT) { + return const_cast("%H:%M:%S"); + }else if(item == T_FMT_AMPM) { + return const_cast("%I:%M:%S %p"); + }else if(item == D_T_FMT) { + return const_cast("%a %b %e %T %Y"); + } else if (item == RADIXCHAR) { + return const_cast("."); + } else if (item == THOUSEP) { + return const_cast(""); + }else if(item == YESEXPR) { + return const_cast("^[yY]"); + }else if(item == NOEXPR) { + return const_cast("^[nN]"); + }else{ + mlibc::infoLogger() << "mlibc: nl_langinfo item " + << item << " is not implemented properly" << frg::endlog; + return const_cast(""); + } +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/generic/search.cpp b/user/include/mlibc/options/internal/generic/search.cpp new file mode 100644 index 0000000..4a9747a --- /dev/null +++ b/user/include/mlibc/options/internal/generic/search.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + +struct _ENTRY { + ENTRY entry; + bool used; +}; + +namespace mlibc { + +int hcreate_r(size_t num_entries, struct hsearch_data *htab) { + if(!htab) { + errno = EINVAL; + return 0; + } + + htab->table = static_cast<_ENTRY*>(calloc(num_entries, sizeof(_ENTRY))); + if(!htab->table) { + errno = ENOMEM; + return 0; + } + htab->filled = 0; + htab->size = num_entries; + return 1; +} + +void hdestroy_r(struct hsearch_data *htab) { + if(!htab) { + errno = EINVAL; + return; + } + free(htab->table); + htab->table = nullptr; + htab->size = 0; + htab->filled = 0; +} + + +int hsearch_r(ENTRY item, ACTION action, ENTRY **ret, struct hsearch_data *htab) { + auto key = frg::string_view{item.key}; + auto hash = frg::hash{}(key); + + size_t bucket_index = hash % htab->size; + size_t start = bucket_index; + while(true) { + auto &bucket = htab->table[bucket_index]; + + if(bucket.used) { + if(bucket.entry.key == key) { + *ret = &bucket.entry; + return 1; + } + } else if(action == FIND) { + errno = ESRCH; + *ret = nullptr; + return 0; + } + + bucket_index = (bucket_index + 1) % htab->size; + + if(bucket_index == start) { + if(action == FIND) { + errno = ESRCH; + *ret = nullptr; + return 0; + } else { + break; + } + } + } + + // insert a new entry. + if(htab->size == htab->filled) { + errno = ENOMEM; + return 0; + } + ++htab->filled; + + bucket_index = start; + while(true) { + auto &bucket = htab->table[bucket_index]; + if(!bucket.used) { + bucket.used = true; + bucket.entry = item; + *ret = &bucket.entry; + break; + } + + bucket_index = (bucket_index + 1) % htab->size; + } + + return 1; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/generic/sigset.cpp b/user/include/mlibc/options/internal/generic/sigset.cpp new file mode 100644 index 0000000..f3434bc --- /dev/null +++ b/user/include/mlibc/options/internal/generic/sigset.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include + +namespace { + +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +// Assume that the struct has a member named 'sig'. +template +struct sigset_type_helper { + using type = typename remove_reference::type; + static_assert(offsetof(T, sig) == 0); +}; + +template<> +struct sigset_type_helper { using type = unsigned long; }; + +template<> +struct sigset_type_helper { using type = unsigned long long; }; + +template<> +struct sigset_type_helper { using type = long; }; + +template<> +struct sigset_type_helper { using type = long long; }; + +// Some ABIs define sigset_t as a simple integer (e.g unsigned long), +// while others define it as a struct containing an array of integers. +using sigset_underlying_type = sigset_type_helper::type; + +size_t signo_to_field(int signo) { + return signo / (sizeof(sigset_underlying_type) * CHAR_BIT); +} + +size_t signo_to_bit(int signo) { + return signo % (sizeof(sigset_underlying_type) * CHAR_BIT); +} + +} // namespace + +int sigemptyset(sigset_t *sigset) { + memset(sigset, 0, sizeof(*sigset)); + return 0; +} + +int sigfillset(sigset_t *sigset) { + memset(sigset, ~0, sizeof(*sigset)); + return 0; +} + +int sigaddset(sigset_t *sigset, int sig) { + int signo = sig - 1; + if(signo < 0 || static_cast(signo) >= (sizeof(sigset_t) * CHAR_BIT)) { + errno = EINVAL; + return -1; + } + auto ptr = reinterpret_cast(sigset); + auto field = signo_to_field(signo); + auto bit = signo_to_bit(signo); + ptr[field] |= (1UL << bit); + return 0; +} + +int sigdelset(sigset_t *sigset, int sig) { + int signo = sig - 1; + if(signo < 0 || static_cast(signo) >= (sizeof(sigset_t) * CHAR_BIT)) { + errno = EINVAL; + return -1; + } + auto ptr = reinterpret_cast(sigset); + auto field = signo_to_field(signo); + auto bit = signo_to_bit(signo); + ptr[field] &= ~(1UL << bit); + return 0; +} + +int sigismember(const sigset_t *sigset, int sig) { + int signo = sig - 1; + if(signo < 0 || static_cast(signo) >= (sizeof(sigset_t) * CHAR_BIT)) { + errno = EINVAL; + return -1; + } + auto ptr = reinterpret_cast(sigset); + auto field = signo_to_field(signo); + auto bit = signo_to_bit(signo); + return (ptr[field] & (1UL << bit)) != 0; +} diff --git a/user/include/mlibc/options/internal/generic/strings.cpp b/user/include/mlibc/options/internal/generic/strings.cpp new file mode 100644 index 0000000..323fbf2 --- /dev/null +++ b/user/include/mlibc/options/internal/generic/strings.cpp @@ -0,0 +1,22 @@ +#include + +#include + +namespace mlibc { + +int strncasecmp(const char *a, const char *b, size_t size) { + for(size_t i = 0; i < size; i++) { + unsigned char a_byte = tolower(a[i]); + unsigned char b_byte = tolower(b[i]); + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + } + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/generic/threads.cpp b/user/include/mlibc/options/internal/generic/threads.cpp new file mode 100644 index 0000000..2b535fc --- /dev/null +++ b/user/include/mlibc/options/internal/generic/threads.cpp @@ -0,0 +1,346 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" Tcb *__rtld_allocateTcb(); + +namespace mlibc { + +int thread_create(struct __mlibc_thread_data **__restrict thread, const struct __mlibc_threadattr *__restrict attrp, void *entry, void *__restrict user_arg, bool returns_int) { + auto new_tcb = __rtld_allocateTcb(); + pid_t tid; + struct __mlibc_threadattr attr = {}; + if (!attrp) + thread_attr_init(&attr); + else + attr = *attrp; + + if (attr.__mlibc_cpuset) + mlibc::infoLogger() << "pthread_create(): cpuset is ignored!" << frg::endlog; + if (attr.__mlibc_sigmaskset) + mlibc::infoLogger() << "pthread_create(): sigmask is ignored!" << frg::endlog; + + // TODO: due to alignment guarantees, the stackaddr and stacksize might change + // when the stack is allocated. Currently this isn't propagated to the TCB, + // but it should be. + void *stack = attr.__mlibc_stackaddr; + if (!mlibc::sys_prepare_stack) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + int ret = mlibc::sys_prepare_stack(&stack, entry, + user_arg, new_tcb, &attr.__mlibc_stacksize, &attr.__mlibc_guardsize, &new_tcb->stackAddr); + if (ret) + return ret; + + if (!mlibc::sys_clone) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + new_tcb->stackSize = attr.__mlibc_stacksize; + new_tcb->guardSize = attr.__mlibc_guardsize; + new_tcb->returnValueType = (returns_int) ? TcbThreadReturnValue::Integer : TcbThreadReturnValue::Pointer; + new_tcb->isJoinable = (attr.__mlibc_detachstate == __MLIBC_THREAD_CREATE_JOINABLE); + mlibc::sys_clone(new_tcb, &tid, stack); + *thread = reinterpret_cast(new_tcb); + + __atomic_store_n(&new_tcb->tid, tid, __ATOMIC_RELAXED); + mlibc::sys_futex_wake(&new_tcb->tid); + + return 0; +} + +int thread_join(struct __mlibc_thread_data *thread, void *ret) { + auto tcb = reinterpret_cast(thread); + + if(!tcb->isJoinable) { + mlibc::infoLogger() << "mlibc: pthread_join() called on a detached thread" << frg::endlog; + return EINVAL; + } + + if (!__atomic_load_n(&tcb->isJoinable, __ATOMIC_ACQUIRE)) + return EINVAL; + + while (!__atomic_load_n(&tcb->didExit, __ATOMIC_ACQUIRE)) { + mlibc::sys_futex_wait(&tcb->didExit, 0, nullptr); + } + + if(ret && tcb->returnValueType == TcbThreadReturnValue::Pointer) + *reinterpret_cast(ret) = tcb->returnValue.voidPtr; + else if(ret && tcb->returnValueType == TcbThreadReturnValue::Integer) + *reinterpret_cast(ret) = tcb->returnValue.intVal; + + // FIXME: destroy tcb here, currently we leak it + + return 0; +} + +static constexpr size_t default_stacksize = 0x200000; +static constexpr size_t default_guardsize = 4096; + +int thread_attr_init(struct __mlibc_threadattr *attr) { + *attr = __mlibc_threadattr{}; + attr->__mlibc_stacksize = default_stacksize; + attr->__mlibc_guardsize = default_guardsize; + attr->__mlibc_detachstate = __MLIBC_THREAD_CREATE_JOINABLE; + return 0; +} + +static constexpr unsigned int mutexRecursive = 1; +static constexpr unsigned int mutexErrorCheck = 2; + +// TODO: either use uint32_t or determine the bit based on sizeof(int). +static constexpr unsigned int mutex_owner_mask = (static_cast(1) << 30) - 1; +static constexpr unsigned int mutex_waiters_bit = static_cast(1) << 31; + +int thread_mutex_init(struct __mlibc_mutex *__restrict mutex, + const struct __mlibc_mutexattr *__restrict attr) { + auto type = attr ? attr->__mlibc_type : __MLIBC_THREAD_MUTEX_DEFAULT; + auto robust = attr ? attr->__mlibc_robust : __MLIBC_THREAD_MUTEX_STALLED; + auto protocol = attr ? attr->__mlibc_protocol : __MLIBC_THREAD_PRIO_NONE; + auto pshared = attr ? attr->__mlibc_pshared : __MLIBC_THREAD_PROCESS_PRIVATE; + + mutex->__mlibc_state = 0; + mutex->__mlibc_recursion = 0; + mutex->__mlibc_flags = 0; + mutex->__mlibc_prioceiling = 0; // TODO: We don't implement this. + + if(type == __MLIBC_THREAD_MUTEX_RECURSIVE) { + mutex->__mlibc_flags |= mutexRecursive; + }else if(type == __MLIBC_THREAD_MUTEX_ERRORCHECK) { + mutex->__mlibc_flags |= mutexErrorCheck; + }else{ + __ensure(type == __MLIBC_THREAD_MUTEX_NORMAL); + } + + // TODO: Other values aren't supported yet. + __ensure(robust == __MLIBC_THREAD_MUTEX_STALLED); + __ensure(protocol == __MLIBC_THREAD_PRIO_NONE); + __ensure(pshared == __MLIBC_THREAD_PROCESS_PRIVATE); + + return 0; +} + +int thread_mutex_destroy(struct __mlibc_mutex *mutex) { + __ensure(!mutex->__mlibc_state); + return 0; +} + +int thread_mutex_lock(struct __mlibc_mutex *mutex) { + unsigned int this_tid = mlibc::this_tid(); + unsigned int expected = 0; + while(true) { + if(!expected) { + // Try to take the mutex here. + if(__atomic_compare_exchange_n(&mutex->__mlibc_state, + &expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + __ensure(!mutex->__mlibc_recursion); + mutex->__mlibc_recursion = 1; + return 0; + } + }else{ + // If this (recursive) mutex is already owned by us, increment the recursion level. + if((expected & mutex_owner_mask) == this_tid) { + if(!(mutex->__mlibc_flags & mutexRecursive)) { + if (mutex->__mlibc_flags & mutexErrorCheck) + return EDEADLK; + else + mlibc::panicLogger() << "mlibc: pthread_mutex deadlock detected!" + << frg::endlog; + } + ++mutex->__mlibc_recursion; + return 0; + } + + // Wait on the futex if the waiters flag is set. + if(expected & mutex_waiters_bit) { + int e = mlibc::sys_futex_wait((int *)&mutex->__mlibc_state, expected, nullptr); + + // If the wait returns EAGAIN, that means that the mutex_waiters_bit was just unset by + // some other thread. In this case, we should loop back around. + // Also do so in case of a signal being caught. + if (e && e != EAGAIN && e != EINTR) + mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog; + + // Opportunistically try to take the lock after we wake up. + expected = 0; + }else{ + // Otherwise we have to set the waiters flag first. + unsigned int desired = expected | mutex_waiters_bit; + if(__atomic_compare_exchange_n((int *)&mutex->__mlibc_state, + reinterpret_cast(&expected), desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + expected = desired; + } + } + } +} + +int thread_mutex_unlock(struct __mlibc_mutex *mutex) { + // Decrement the recursion level and unlock if we hit zero. + __ensure(mutex->__mlibc_recursion); + if(--mutex->__mlibc_recursion) + return 0; + + auto flags = mutex->__mlibc_flags; + + // Reset the mutex to the unlocked state. + auto state = __atomic_exchange_n(&mutex->__mlibc_state, 0, __ATOMIC_RELEASE); + + // After this point the mutex is unlocked, and therefore we cannot access its contents as it + // may have been destroyed by another thread. + + unsigned int this_tid = mlibc::this_tid(); + if ((flags & mutexErrorCheck) && (state & mutex_owner_mask) != this_tid) + return EPERM; + + if ((flags & mutexErrorCheck) && !(state & mutex_owner_mask)) + return EINVAL; + + __ensure((state & mutex_owner_mask) == this_tid); + + if(state & mutex_waiters_bit) { + // Wake the futex if there were waiters. Since the mutex might not exist at this location + // anymore, we must conservatively ignore EACCES and EINVAL which may occur as a result. + int e = mlibc::sys_futex_wake((int *)&mutex->__mlibc_state); + __ensure(e >= 0 || e == EACCES || e == EINVAL); + } + + return 0; +} + +int thread_mutexattr_init(struct __mlibc_mutexattr *attr) { + attr->__mlibc_type = __MLIBC_THREAD_MUTEX_DEFAULT; + attr->__mlibc_robust = __MLIBC_THREAD_MUTEX_STALLED; + attr->__mlibc_pshared = __MLIBC_THREAD_PROCESS_PRIVATE; + attr->__mlibc_protocol = __MLIBC_THREAD_PRIO_NONE; + return 0; +} + +int thread_mutexattr_destroy(struct __mlibc_mutexattr *attr) { + memset(attr, 0, sizeof(*attr)); + return 0; +} + +int thread_mutexattr_gettype(const struct __mlibc_mutexattr *__restrict attr, int *__restrict type) { + *type = attr->__mlibc_type; + return 0; +} + +int thread_mutexattr_settype(struct __mlibc_mutexattr *attr, int type) { + if (type != __MLIBC_THREAD_MUTEX_NORMAL && type != __MLIBC_THREAD_MUTEX_ERRORCHECK + && type != __MLIBC_THREAD_MUTEX_RECURSIVE) + return EINVAL; + + attr->__mlibc_type = type; + return 0; +} + +int thread_cond_init(struct __mlibc_cond *__restrict cond, const struct __mlibc_condattr *__restrict attr) { + auto clock = attr ? attr->__mlibc_clock : CLOCK_REALTIME; + auto pshared = attr ? attr->__mlibc_pshared : __MLIBC_THREAD_PROCESS_PRIVATE; + + cond->__mlibc_clock = clock; + cond->__mlibc_flags = pshared; + + __atomic_store_n(&cond->__mlibc_seq, 1, __ATOMIC_RELAXED); + + return 0; +} + +int thread_cond_destroy(struct __mlibc_cond *) { + return 0; +} + +int thread_cond_broadcast(struct __mlibc_cond *cond) { + __atomic_fetch_add(&cond->__mlibc_seq, 1, __ATOMIC_RELEASE); + if(int e = mlibc::sys_futex_wake((int *)&cond->__mlibc_seq); e) + __ensure(!"sys_futex_wake() failed"); + + return 0; +} + +int thread_cond_timedwait(struct __mlibc_cond *__restrict cond, __mlibc_mutex *__restrict mutex, + const struct timespec *__restrict abstime) { + // TODO: pshared isn't supported yet. + __ensure(cond->__mlibc_flags == 0); + + constexpr long nanos_per_second = 1'000'000'000; + if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= nanos_per_second)) + return EINVAL; + + auto seq = __atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE); + + // TODO: handle locking errors and cancellation properly. + while (true) { + if (thread_mutex_unlock(mutex)) + __ensure(!"Failed to unlock the mutex"); + + int e; + if (abstime) { + // Adjust for the fact that sys_futex_wait accepts a *timeout*, but + // pthread_cond_timedwait accepts an *absolute time*. + // Note: mlibc::sys_clock_get is available unconditionally. + struct timespec now; + if (mlibc::sys_clock_get(cond->__mlibc_clock, &now.tv_sec, &now.tv_nsec)) + __ensure(!"sys_clock_get() failed"); + + struct timespec timeout; + timeout.tv_sec = abstime->tv_sec - now.tv_sec; + timeout.tv_nsec = abstime->tv_nsec - now.tv_nsec; + + // Check if abstime has already passed. + if (timeout.tv_sec < 0 || (timeout.tv_sec == 0 && timeout.tv_nsec < 0)) { + if (thread_mutex_lock(mutex)) + __ensure(!"Failed to lock the mutex"); + return ETIMEDOUT; + } else if (timeout.tv_nsec >= nanos_per_second) { + timeout.tv_nsec -= nanos_per_second; + timeout.tv_sec++; + __ensure(timeout.tv_nsec < nanos_per_second); + } else if (timeout.tv_nsec < 0) { + timeout.tv_nsec += nanos_per_second; + timeout.tv_sec--; + __ensure(timeout.tv_nsec >= 0); + } + + e = mlibc::sys_futex_wait((int *)&cond->__mlibc_seq, seq, &timeout); + } else { + e = mlibc::sys_futex_wait((int *)&cond->__mlibc_seq, seq, nullptr); + } + + if (thread_mutex_lock(mutex)) + __ensure(!"Failed to lock the mutex"); + + // There are four cases to handle: + // 1. e == 0: this indicates a (potentially spurious) wakeup. The value of + // seq *must* be checked to distinguish these two cases. + // 2. e == EAGAIN: this indicates that the value of seq changed before we + // went to sleep. We don't need to check seq in this case. + // 3. e == EINTR: a signal was delivered. The man page allows us to choose + // whether to go to sleep again or to return 0, but we do the former + // to match other libcs. + // 4. e == ETIMEDOUT: this should only happen if abstime is set. + if (e == 0) { + auto cur_seq = __atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE); + if (cur_seq > seq) + return 0; + } else if (e == EAGAIN) { + __ensure(__atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE) > seq); + return 0; + } else if (e == EINTR) { + continue; + } else if (e == ETIMEDOUT) { + __ensure(abstime); + return ETIMEDOUT; + } else { + mlibc::panicLogger() << "sys_futex_wait() failed with error " << e << frg::endlog; + } + } +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/generic/ubsan.cpp b/user/include/mlibc/options/internal/generic/ubsan.cpp new file mode 100644 index 0000000..581a762 --- /dev/null +++ b/user/include/mlibc/options/internal/generic/ubsan.cpp @@ -0,0 +1,282 @@ +#include +#include + +#define FMT(obj) format_object((obj), opts, formatter) + +#define LOG_NAME_LOC(name, loc) "ubsan: " name " at " << loc << "\n " +#define LOG_LHS_RHS(lhs, rhs) "LHS = " << (lhs) << ", RHS = " << (rhs) + +struct SourceLocation { + const char *filename; + uint32_t line; + uint32_t column; +}; + +template +void format_object(const SourceLocation &loc, frg::format_options opts, F &formatter) { + FMT(loc.filename); + FMT(":"); + FMT(loc.line); + FMT(":"); + FMT(loc.column); +} + +using ValueHandle = uintptr_t; + +struct TypeDescriptor { + enum class Kind : uint16_t { + Integer = 0x0000, + Float = 0x0001, + Unknown = 0xffff + } kind; + + uint16_t info; + char name[]; + + unsigned bitWidthInt() const { + return 1 << (info >> 1); + } + + bool isInlineInt() const { + if (kind != Kind::Integer) + return false; + + auto inlineBits = sizeof(ValueHandle) * CHAR_BIT; + auto valueBits = bitWidthInt(); + return inlineBits <= valueBits; + } + + bool isSigned() const { + return info & 1; + } +}; + +template +void format_object(const TypeDescriptor &type, frg::format_options opts, F &formatter) { + FMT(type.name); +} + +struct Value { + const TypeDescriptor &type; + ValueHandle val; + + Value(const TypeDescriptor &type, ValueHandle val) : type(type), val(val) {} +}; + +template +void format_object(const Value &val, frg::format_options opts, F &formatter) { + if (val.type.isInlineInt() && val.type.isSigned()) { + auto signedValue = static_cast(val.val); + FMT(signedValue); + } else if (val.type.isInlineInt() && !val.type.isSigned()) { + auto unsignedValue = static_cast(val.val); + FMT(unsignedValue); + } + + FMT(" ("); + FMT(val.type); + FMT(")"); +} + + +// --- Hook implementations --- + +struct TypeMismatch { + SourceLocation loc; + const TypeDescriptor &type; + unsigned char logAlignment; + unsigned char kind; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_type_mismatch_v1(TypeMismatch *tm, ValueHandle pointer) { + // TODO: Make this print more information. + mlibc::panicLogger() + << LOG_NAME_LOC("type mismatch", tm->loc) + << "accessed address " << (void *)pointer << " but type " + << tm->type << " requires alignment " << (1 << tm->logAlignment) + << frg::endlog; +} + +struct PointerOverflowData { + SourceLocation loc; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_pointer_overflow(PointerOverflowData *pod, ValueHandle base, ValueHandle result) { + (void)base; + (void)result; + mlibc::panicLogger() + << LOG_NAME_LOC("pointer overflow", pod->loc) + << frg::endlog; +} + +struct InvalidValueData { + SourceLocation loc; + const TypeDescriptor &type; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_load_invalid_value(InvalidValueData *ivd, ValueHandle value) { + (void)value; + mlibc::panicLogger() + << LOG_NAME_LOC("load of invalid value", ivd->loc) + << frg::endlog; +} + +struct OverflowData { + SourceLocation loc; + const TypeDescriptor &type; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_add_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("add overflowed ", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_sub_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("sub overflowed", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_mul_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("mul overflowed", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_divrem_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("divrem overflowed", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_negate_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("negate overflowed", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +struct ShiftOutOfBoundsData { + SourceLocation loc; + const TypeDescriptor &lhsType; + const TypeDescriptor &rhsType; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *soob, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("shift out of bounds", soob->loc) + << LOG_LHS_RHS(Value(soob->lhsType, lhs), Value(soob->rhsType, rhs)) + << frg::endlog; +} + +struct OutOfBoundsData { + SourceLocation loc; + const TypeDescriptor &arrayType; + const TypeDescriptor &indexType; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_out_of_bounds(OutOfBoundsData *oobd, ValueHandle data) { + (void)data; + mlibc::panicLogger() + << LOG_NAME_LOC("out of bounds access", oobd->loc) + << frg::endlog; +} + +struct UnreachableData { + SourceLocation loc; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_builtin_unreachable(UnreachableData *ubd) { + mlibc::panicLogger() + << LOG_NAME_LOC("reached __builtin_unreachable()", ubd->loc) + << frg::endlog; +} + +struct InvalidBuiltinData { + SourceLocation loc; + unsigned char kind; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_invalid_builtin(InvalidBuiltinData *ibd) { + mlibc::panicLogger() + << LOG_NAME_LOC("reached invalid builtin", ibd->loc) + << frg::endlog; +} + +struct VLABoundData { + SourceLocation loc; + const TypeDescriptor &type; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_vla_bound_not_positive(VLABoundData *vlabd) { + mlibc::panicLogger() + << LOG_NAME_LOC("VLA bound not positive", vlabd->loc) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_missing_return(UnreachableData *data) { + mlibc::panicLogger() + << LOG_NAME_LOC("reached end of a value-returning function without returning a value", data->loc) + << frg::endlog; +} + +struct NonNullArgData { + SourceLocation loc; + SourceLocation attr_loc; + int arg_index; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_nonnull_arg(NonNullArgData *data) { + mlibc::panicLogger() + << LOG_NAME_LOC("null pointer passed to non-null argument", data->loc) + << "argument " << data->arg_index << " is required to be non-null in " + << data->attr_loc << frg::endlog; +} + +struct FloatCastOverflowData { + SourceLocation loc; + const TypeDescriptor &from_type; + const TypeDescriptor &to_type; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_float_cast_overflow(FloatCastOverflowData *data, ValueHandle from) { + (void) from; + mlibc::panicLogger() + << LOG_NAME_LOC("float cast overflow", data->loc) + << "from " << data->from_type << " to " + << data->to_type << frg::endlog; +} + +struct FunctionTypeMismatchData { + SourceLocation loc; + const TypeDescriptor &type; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *data, ValueHandle from) { + (void) from; + mlibc::panicLogger() + << LOG_NAME_LOC("function type mismatch", data->loc) + << frg::endlog; +} diff --git a/user/include/mlibc/options/internal/include/bits/cpu_set.h b/user/include/mlibc/options/internal/include/bits/cpu_set.h new file mode 100644 index 0000000..69f6923 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/cpu_set.h @@ -0,0 +1,13 @@ +#ifndef _MLIBC_INTERNAL_CPU_SET_H +#define _MLIBC_INTERNAL_CPU_SET_H + +typedef unsigned long __cpu_mask; + +#define CPU_SETSIZE 1024 +#define __NCPUBITS (8 * sizeof(__cpu_mask)) + +typedef struct { + __cpu_mask __bits[CPU_SETSIZE / __NCPUBITS]; +} cpu_set_t; + +#endif /* _MLIBC_INTERNAL_CPU_SET_H */ diff --git a/user/include/mlibc/options/internal/include/bits/ensure.h b/user/include/mlibc/options/internal/include/bits/ensure.h new file mode 100644 index 0000000..7bea3e2 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/ensure.h @@ -0,0 +1,45 @@ + +#ifndef MLIBC_ENSURE_H +#define MLIBC_ENSURE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +void __ensure_fail(const char *assertion, const char *file, unsigned int line, + const char *function); + +void __ensure_warn(const char *assertion, const char *file, unsigned int line, + const char *function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define __ensure(assertion) do { if(!(assertion)) \ + __ensure_fail(#assertion, __FILE__, __LINE__, __func__); } while(0) + +#define MLIBC_UNIMPLEMENTED() __ensure_fail("Functionality is not implemented", \ + __FILE__, __LINE__, __func__) + +#define MLIBC_MISSING_SYSDEP() __ensure_warn("Library function fails due to missing sysdep", \ + __FILE__, __LINE__, __func__) + +#define MLIBC_CHECK_OR_ENOSYS(sysdep, ret) ({ \ + if (!(sysdep)) { \ + __ensure_warn("Library function fails due to missing sysdep", \ + __FILE__, __LINE__, __func__); \ + errno = ENOSYS; \ + return (ret); \ + } \ + sysdep; \ + }) + +#define MLIBC_STUB_BODY ({ MLIBC_UNIMPLEMENTED(); __builtin_unreachable(); }) + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_ENSURE_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/ether_addr.h b/user/include/mlibc/options/internal/include/bits/ether_addr.h new file mode 100644 index 0000000..3c8f595 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/ether_addr.h @@ -0,0 +1,10 @@ +#ifndef MLIBC_ETHER_ADDR_H +#define MLIBC_ETHER_ADDR_H + +#include + +struct ether_addr { + uint8_t ether_addr_octet[6]; +} __attribute__((__packed__)); + +#endif /* MLIBC_ETHER_ADDR_H */ diff --git a/user/include/mlibc/options/internal/include/bits/file.h b/user/include/mlibc/options/internal/include/bits/file.h new file mode 100644 index 0000000..44566f7 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/file.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_FILE_T_H +#define MLIBC_FILE_T_H + +typedef struct __mlibc_file_base FILE; + +#endif /* MLIBC_FILE_T_H */ diff --git a/user/include/mlibc/options/internal/include/bits/getopt.h b/user/include/mlibc/options/internal/include/bits/getopt.h new file mode 100644 index 0000000..c2ae35f --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/getopt.h @@ -0,0 +1,15 @@ +#ifndef MLIBC_BITS_GETOPT +#define MLIBC_BITS_GETOPT + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#endif /* MLIBC_BITS_GETOPT */ diff --git a/user/include/mlibc/options/internal/include/bits/inline-definition.h b/user/include/mlibc/options/internal/include/bits/inline-definition.h new file mode 100644 index 0000000..939059a --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/inline-definition.h @@ -0,0 +1,19 @@ +#ifndef MLIBC_INLINE_DEFINITION_H +#define MLIBC_INLINE_DEFINITION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __MLIBC_EMIT_INLINE_DEFINITIONS +#define __MLIBC_INLINE_DEFINITION +#else +#define __MLIBC_INLINE_DEFINITION __attribute__((__gnu_inline__)) extern __inline__ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_INLINE_DEFINITION_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/machine.h b/user/include/mlibc/options/internal/include/bits/machine.h new file mode 100644 index 0000000..ad000f6 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/machine.h @@ -0,0 +1,126 @@ + +#ifndef MLIBC_MACHINE_H +#define MLIBC_MACHINE_H + +#include + +#if defined (__i386__) +struct __mlibc_jmpbuf_register_state { + uint32_t ebx; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t esp; + uint32_t eip; +}; +#elif defined (__x86_64__) +struct __mlibc_jmpbuf_register_state { + uint64_t rbx; + uint64_t rbp; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rsp; + uint64_t rip; +}; +#elif defined (__aarch64__) +struct __mlibc_jmpbuf_register_state { + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + uint64_t x23; + uint64_t x24; + uint64_t x25; + uint64_t x26; + uint64_t x27; + uint64_t x28; + uint64_t x29; + uint64_t x30; + uint64_t sp; + uint64_t pad; + uint64_t d8; + uint64_t d9; + uint64_t d10; + uint64_t d11; + uint64_t d12; + uint64_t d13; + uint64_t d14; + uint64_t d15; +}; +#elif defined (__riscv) && __riscv_xlen == 64 +struct __mlibc_jmpbuf_register_state { + uint64_t ra; + uint64_t s0; + uint64_t s1; + uint64_t s2; + uint64_t s3; + uint64_t s4; + uint64_t s5; + uint64_t s6; + uint64_t s7; + uint64_t s8; + uint64_t s9; + uint64_t s10; + uint64_t s11; + uint64_t sp; + double fs0; + double fs1; + double fs2; + double fs3; + double fs4; + double fs5; + double fs6; + double fs7; + double fs8; + double fs9; + double fs10; + double fs11; +}; +#elif defined (__m68k__) +struct __mlibc_jmpbuf_register_state { + uint32_t d2; + uint32_t d3; + uint32_t d4; + uint32_t d5; + uint32_t d6; + uint32_t d7; + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + uint32_t sp; + uint32_t pc; +}; +#elif defined (__loongarch64) +struct __mlibc_jmpbuf_register_state { + uint64_t ra; + uint64_t sp; + uint64_t u0; + uint64_t s0; + uint64_t s1; + uint64_t s2; + uint64_t s3; + uint64_t s4; + uint64_t s5; + uint64_t s6; + uint64_t s7; + uint64_t s8; + double fs0; + double fs1; + double fs2; + double fs3; + double fs4; + double fs5; + double fs6; + double fs7; +}; +#else +# error "Missing architecture specific code" +#endif + +#endif /* MLIBC_MACHINE_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/mbstate.h b/user/include/mlibc/options/internal/include/bits/mbstate.h new file mode 100644 index 0000000..e65604b --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/mbstate.h @@ -0,0 +1,12 @@ +#ifndef MLIBC_MBSTATE_H +#define MLIBC_MBSTATE_H + +typedef struct __mlibc_mbstate { + short __progress; + short __shift; + unsigned int __cpoint; +} mbstate_t; + +#define __MLIBC_MBSTATE_INITIALIZER {0, 0, 0} + +#endif /* MLIBC_MBSTATE_H */ diff --git a/user/include/mlibc/options/internal/include/bits/nl_item.h b/user/include/mlibc/options/internal/include/bits/nl_item.h new file mode 100644 index 0000000..12e25b0 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/nl_item.h @@ -0,0 +1,84 @@ + +#ifndef _NL_ITEM_H +#define _NL_ITEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int nl_item; + +#define ABDAY_1 0x60000 +#define ABDAY_2 0x60001 +#define ABDAY_3 0x60002 +#define ABDAY_4 0x60003 +#define ABDAY_5 0x60004 +#define ABDAY_6 0x60005 +#define ABDAY_7 0x60006 + +#define DAY_1 0x60007 +#define DAY_2 0x60008 +#define DAY_3 0x60009 +#define DAY_4 0x6000A +#define DAY_5 0x6000B +#define DAY_6 0x6000C +#define DAY_7 0x6000D + +#define ABMON_1 0x6000E +#define ABMON_2 0x6000F +#define ABMON_3 0x60010 +#define ABMON_4 0x60011 +#define ABMON_5 0x60012 +#define ABMON_6 0x60013 +#define ABMON_7 0x60014 +#define ABMON_8 0x60015 +#define ABMON_9 0x60016 +#define ABMON_10 0x60017 +#define ABMON_11 0x60018 +#define ABMON_12 0x60019 + +#define MON_1 0x6001A +#define MON_2 0x6001B +#define MON_3 0x6001C +#define MON_4 0x6001D +#define MON_5 0x6001E +#define MON_6 0x6001F +#define MON_7 0x60020 +#define MON_8 0x60021 +#define MON_9 0x60022 +#define MON_10 0x60023 +#define MON_11 0x60024 +#define MON_12 0x60025 + +#define AM_STR 0x60026 +#define PM_STR 0x60027 + +#define D_T_FMT 0x60028 +#define D_FMT 0x60029 +#define T_FMT 0x6002A +#define T_FMT_AMPM 0x6002B + +#define ERA 0x6002C +#define ERA_D_FMT 0x6002D +#define ALT_DIGITS 0x6002E +#define ERA_D_T_FMT 0x6002F +#define ERA_T_FMT 0x60030 + +#define CODESET 0x30000 + +#define CRNCYSTR 0x40000 + +#define RADIXCHAR 0x50000 +#define DECIMAL_POINT RADIXCHAR +#define THOUSEP 0x50001 +#define THOUSANDS_SEP THOUSEP + +#define YESEXPR 0x70000 +#define NOEXPR 0x70001 + +#ifdef __cplusplus +} +#endif + +#endif /* _NL_ITEM_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/null.h b/user/include/mlibc/options/internal/include/bits/null.h new file mode 100644 index 0000000..176008f --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/null.h @@ -0,0 +1,16 @@ + +#ifndef MLIBC_NULL_H +#define MLIBC_NULL_H + +#ifdef NULL +#undef NULL +#endif + +#ifndef __cplusplus +# define NULL ((void *)0) +#else +# define NULL 0 +#endif + +#endif /* MLIBC_NULL_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/off_t.h b/user/include/mlibc/options/internal/include/bits/off_t.h new file mode 100644 index 0000000..43dcd9e --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/off_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_OFF_T_H +#define MLIBC_OFF_T_H + +/* TODO: use something like int64_t instead? */ +typedef long off_t; +typedef long off64_t; + +#endif /* MLIBC_OFF_T_H */ diff --git a/user/include/mlibc/options/internal/include/bits/search.h b/user/include/mlibc/options/internal/include/bits/search.h new file mode 100644 index 0000000..8e650a0 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/search.h @@ -0,0 +1,24 @@ +#ifndef _MLIBC_INTERNAL_SEARCH_H +#define _MLIBC_INTERNAL_SEARCH_H + +#include + +typedef enum { + FIND, + ENTER +} ACTION; + +typedef struct entry { + char *key; + void *data; +} ENTRY; + +struct _ENTRY; + +struct hsearch_data { + struct _ENTRY *table; + unsigned int size; + unsigned int filled; +}; + +#endif /* _MLIBC_INTERNAL_SEARCH_H */ diff --git a/user/include/mlibc/options/internal/include/bits/sigset_t.h b/user/include/mlibc/options/internal/include/bits/sigset_t.h new file mode 100644 index 0000000..b3d18a3 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/sigset_t.h @@ -0,0 +1,25 @@ +#ifndef MLIBC_BITS_SIGSET_T_H +#define MLIBC_BITS_SIGSET_T_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* functions to manage sigset_t */ +int sigemptyset(sigset_t *__sigset); +int sigfillset(sigset_t *__sigset); +int sigaddset(sigset_t *__sigset, int __sig); +int sigdelset(sigset_t *__sigset, int __sig); +int sigismember(const sigset_t *__sigset, int __sig); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /*MLIBC_BITS_SIGSET_T_H */ diff --git a/user/include/mlibc/options/internal/include/bits/size_t.h b/user/include/mlibc/options/internal/include/bits/size_t.h new file mode 100644 index 0000000..125875c --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/size_t.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_SIZE_T_H +#define MLIBC_SIZE_T_H + +typedef __SIZE_TYPE__ size_t; + +#endif /* MLIBC_SIZE_T_H */ diff --git a/user/include/mlibc/options/internal/include/bits/ssize_t.h b/user/include/mlibc/options/internal/include/bits/ssize_t.h new file mode 100644 index 0000000..a1a8471 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/ssize_t.h @@ -0,0 +1,15 @@ + +#ifndef MLIBC_SSIZE_T_H +#define MLIBC_SSIZE_T_H + +/* TODO: use ptrdiff_t instead? */ +#if __UINTPTR_MAX__ == __UINT64_MAX__ +typedef long ssize_t; +#elif __UINTPTR_MAX__ == __UINT32_MAX__ +typedef int ssize_t; +#else +#error "unsupported architecture" +#endif + +#endif /* MLIBC_SSIZE_T_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/threads.h b/user/include/mlibc/options/internal/include/bits/threads.h new file mode 100644 index 0000000..defc9c4 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/threads.h @@ -0,0 +1,81 @@ +#ifndef _INTERNAL_THREADS_H +#define _INTERNAL_THREADS_H + +#include +#include +#include +#include + +/* values for pthread_attr_{get,set}detachstate(). */ +#define __MLIBC_THREAD_CREATE_JOINABLE 0 +#define __MLIBC_THREAD_CREATE_DETACHED 1 + +/* values for pthread_mutexattr_{get,set}type(). */ +#define __MLIBC_THREAD_MUTEX_DEFAULT 0 +#define __MLIBC_THREAD_MUTEX_NORMAL 0 +#define __MLIBC_THREAD_MUTEX_ERRORCHECK 1 +#define __MLIBC_THREAD_MUTEX_RECURSIVE 2 + +/* values for pthread_mutexattr_{get,set}pshared(). */ +#define __MLIBC_THREAD_PROCESS_PRIVATE 0 +#define __MLIBC_THREAD_PROCESS_SHARED 1 + +/* values for pthread_mutexattr_{get,set}robust(). */ +#define __MLIBC_THREAD_MUTEX_STALLED 0 +#define __MLIBC_THREAD_MUTEX_ROBUST 1 + +/* Values for pthread_mutexattr_{get,set}protocol() */ +#define __MLIBC_THREAD_PRIO_NONE 0 +#define __MLIBC_THREAD_PRIO_INHERIT 1 +#define __MLIBC_THREAD_PRIO_PROTECT 2 + +#define __MLIBC_THREAD_MUTEX_INITIALIZER {0, 0, 0, 0} + +struct sched_param { + int sched_priority; +}; + +struct __mlibc_thread_data; + +struct __mlibc_threadattr { + size_t __mlibc_guardsize; + size_t __mlibc_stacksize; + void *__mlibc_stackaddr; + int __mlibc_detachstate; + int __mlibc_scope; + int __mlibc_inheritsched; + struct sched_param __mlibc_schedparam; + int __mlibc_schedpolicy; + cpu_set_t *__mlibc_cpuset; + size_t __mlibc_cpusetsize; + sigset_t __mlibc_sigmask; + int __mlibc_sigmaskset; +}; + +struct __mlibc_mutex { + unsigned int __mlibc_state; + unsigned int __mlibc_recursion; + unsigned int __mlibc_flags; + int __mlibc_prioceiling; +}; + +struct __mlibc_mutexattr { + int __mlibc_type; + int __mlibc_robust; + int __mlibc_protocol; + int __mlibc_pshared; + int __mlibc_prioceiling; +}; + +struct __mlibc_cond { + unsigned int __mlibc_seq; + unsigned int __mlibc_flags; + clockid_t __mlibc_clock; +}; + +struct __mlibc_condattr { + int __mlibc_pshared; + clockid_t __mlibc_clock; +}; + +#endif /* _INTERNAL_THREADS_H */ diff --git a/user/include/mlibc/options/internal/include/bits/types.h b/user/include/mlibc/options/internal/include/bits/types.h new file mode 100644 index 0000000..ee8b2ee --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/types.h @@ -0,0 +1,408 @@ +#ifndef _MLIBC_INTERNAL_TYPES_H +#define _MLIBC_INTERNAL_TYPES_H + +typedef __UINT8_TYPE__ __mlibc_uint8; +typedef __UINT16_TYPE__ __mlibc_uint16; +typedef __UINT32_TYPE__ __mlibc_uint32; +typedef __UINT64_TYPE__ __mlibc_uint64; + +typedef __INT8_TYPE__ __mlibc_int8; +typedef __INT16_TYPE__ __mlibc_int16; +typedef __INT32_TYPE__ __mlibc_int32; +typedef __INT64_TYPE__ __mlibc_int64; + +/* Clang and GCC have different mechanisms for INT32_C and friends. */ +#ifdef __clang__ +# define __MLIBC_C_EXPAND_JOIN(x, suffix) x ## suffix +# define __MLIBC_C_JOIN(x, suffix) __MLIBC_C_EXPAND_JOIN(x, suffix) + +# define __MLIBC_INT8_C(x) __MLIBC_C_JOIN(x, __INT8_C_SUFFIX__) +# define __MLIBC_INT16_C(x) __MLIBC_C_JOIN(x, __INT16_C_SUFFIX__) +# define __MLIBC_INT32_C(x) __MLIBC_C_JOIN(x, __INT32_C_SUFFIX__) +# define __MLIBC_INT64_C(x) __MLIBC_C_JOIN(x, __INT64_C_SUFFIX__) + +# define __MLIBC_UINT8_C(x) __MLIBC_C_JOIN(x, __UINT8_C_SUFFIX__) +# define __MLIBC_UINT16_C(x) __MLIBC_C_JOIN(x, __UINT16_C_SUFFIX__) +# define __MLIBC_UINT32_C(x) __MLIBC_C_JOIN(x, __UINT32_C_SUFFIX__) +# define __MLIBC_UINT64_C(x) __MLIBC_C_JOIN(x, __UINT64_C_SUFFIX__) + +# define __MLIBC_INTMAX_C(x) __MLIBC_C_JOIN(x, __INTMAX_C_SUFFIX__) +# define __MLIBC_UINTMAX_C(x) __MLIBC_C_JOIN(x, __UINTMAX_C_SUFFIX__) +#else +# define __MLIBC_INT8_C(x) __INT8_C(x) +# define __MLIBC_INT16_C(x) __INT16_C(x) +# define __MLIBC_INT32_C(x) __INT32_C(x) +# define __MLIBC_INT64_C(x) __INT64_C(x) + +# define __MLIBC_UINT8_C(x) __UINT8_C(x) +# define __MLIBC_UINT16_C(x) __UINT16_C(x) +# define __MLIBC_UINT32_C(x) __UINT32_C(x) +# define __MLIBC_UINT64_C(x) __UINT64_C(x) + +# define __MLIBC_INTMAX_C(x) __INTMAX_C(x) +# define __MLIBC_UINTMAX_C(x) __UINTMAX_C(x) +#endif + +#define __MLIBC_INT8_MAX __INT8_MAX__ +#define __MLIBC_INT16_MAX __INT16_MAX__ +#define __MLIBC_INT32_MAX __INT32_MAX__ +#define __MLIBC_INT64_MAX __INT64_MAX__ + +#define __MLIBC_INT8_MIN (-__MLIBC_INT8_MAX - 1) +#define __MLIBC_INT16_MIN (-__MLIBC_INT16_MAX - 1) +#define __MLIBC_INT32_MIN (-__MLIBC_INT32_MAX - 1) +#define __MLIBC_INT64_MIN (-__MLIBC_INT64_MAX - 1) + +#define __MLIBC_UINT8_MAX __UINT8_MAX__ +#define __MLIBC_UINT16_MAX __UINT16_MAX__ +#define __MLIBC_UINT32_MAX __UINT32_MAX__ +#define __MLIBC_UINT64_MAX __UINT64_MAX__ + +/* Fast types (signed). */ + +#if defined (__i386__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int32 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT32_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT32_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT32_MIN + +typedef __mlibc_int32 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT32_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT32_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT32_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__x86_64__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__aarch64__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__riscv) && __riscv_xlen == 64 + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__m68k__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int32 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT16_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT16_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT16_MIN + +typedef __mlibc_int32 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT32_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT32_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT32_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__loongarch64) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#else +# error "Missing architecture specific code" +#endif + +/* Fast types (unsigned). */ + +#if defined (__i386__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT32_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT32_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT32_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT32_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT32_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT32_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__x86_64__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__aarch64__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__riscv) && __riscv_xlen == 64 + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__m68k__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT16_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT16_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT16_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT32_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT32_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT32_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__loongarch64) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#else +# error "Missing architecture specific code" +#endif + +/* Special types. */ + +typedef __INTMAX_TYPE__ __mlibc_intmax; +typedef __INTPTR_TYPE__ __mlibc_intptr; +typedef __PTRDIFF_TYPE__ __mlibc_ptrdiff; +#define __MLIBC_INTMAX_MAX __INTMAX_MAX__ +#define __MLIBC_INTMAX_MIN (-__INTMAX_MAX__ - 1) +#define __MLIBC_INTPTR_MAX __INTPTR_MAX__ +#define __MLIBC_INTPTR_MIN (-__INTPTR_MAX__ - 1) +#define __MLIBC_PTRDIFF_MAX __PTRDIFF_MAX__ +#define __MLIBC_PTRDIFF_MIN (-__PTRDIFF_MAX__ - 1) + +typedef __UINTMAX_TYPE__ __mlibc_uintmax; +typedef __UINTPTR_TYPE__ __mlibc_uintptr; +typedef __SIZE_TYPE__ __mlibc_size; +#define __MLIBC_UINTMAX_MAX __UINTMAX_MAX__ +#define __MLIBC_UINTPTR_MAX __UINTPTR_MAX__ +#define __MLIBC_SIZE_MAX __SIZE_MAX__ + +/* Other limits. */ + +#define __MLIBC_WCHAR_MAX __WCHAR_MAX__ +#define __MLIBC_WCHAR_MIN __WCHAR_MIN__ + +#define __MLIBC_WINT_MAX __WINT_MAX__ +#define __MLIBC_WINT_MIN __WINT_MIN__ + +#define __MLIBC_SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ +#define __MLIBC_SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__ + +/* ---------------------------------------------------------------------------- */ +/* Sanity checking. Make sure that we agree with the compiler's ABI. */ +/* ---------------------------------------------------------------------------- */ + +#if defined(__cplusplus) && defined(__cpp_static_assert) && __cpp_static_assert >= 200410L +# define __MLIBC_STATIC_ASSERT(c, text) static_assert(c, text) +#elif !defined(__cplusplus) +/* _Static_assert is an extension in C89/C99. */ +# define __MLIBC_STATIC_ASSERT(c, text) __extension__ _Static_assert(c, text) +#else +# define __MLIBC_STATIC_ASSERT(c, text) extern int __static_assert_unavailable +#endif + +#define __MLIBC_CHECK_TYPE(T1, T2) __MLIBC_STATIC_ASSERT(sizeof(T1) == sizeof(T2),\ + #T1 " != " #T2) + +/* Least-width. */ +__MLIBC_CHECK_TYPE(__mlibc_int8, __INT_LEAST8_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int16, __INT_LEAST16_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int32, __INT_LEAST32_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int64, __INT_LEAST64_TYPE__); + +__MLIBC_CHECK_TYPE(__mlibc_uint8, __UINT_LEAST8_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint16, __UINT_LEAST16_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint32, __UINT_LEAST32_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint64, __UINT_LEAST64_TYPE__); + +/* Fast-width. */ +/* Unfortunately, GCC and Clang disagree about fast types. */ +#ifndef __clang__ + __MLIBC_CHECK_TYPE(__mlibc_int_fast8, __INT_FAST8_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast16, __INT_FAST16_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast32, __INT_FAST32_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast64, __INT_FAST64_TYPE__); + + __MLIBC_CHECK_TYPE(__mlibc_uint_fast8, __UINT_FAST8_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast16, __UINT_FAST16_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast32, __UINT_FAST32_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast64, __UINT_FAST64_TYPE__); +#endif + +#endif /* _MLIBC_INTERNAL_TYPES_H */ diff --git a/user/include/mlibc/options/internal/include/bits/wchar.h b/user/include/mlibc/options/internal/include/bits/wchar.h new file mode 100644 index 0000000..478eb90 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/wchar.h @@ -0,0 +1,9 @@ +#ifndef MLIBC_WCHAR_H +#define MLIBC_WCHAR_H + +#include + +#define WCHAR_MAX __MLIBC_WCHAR_MAX +#define WCHAR_MIN __MLIBC_WCHAR_MIN + +#endif /* MLIBC_WCHAR_H */ diff --git a/user/include/mlibc/options/internal/include/bits/wchar_t.h b/user/include/mlibc/options/internal/include/bits/wchar_t.h new file mode 100644 index 0000000..83aa5e5 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/wchar_t.h @@ -0,0 +1,12 @@ + +#ifndef MLIBC_WCHAR_T_H +#define MLIBC_WCHAR_T_H + +#ifndef __cplusplus + +typedef __WCHAR_TYPE__ wchar_t; + +#endif + +#endif /* MLIBC_WCHAR_T_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/wctrans_t.h b/user/include/mlibc/options/internal/include/bits/wctrans_t.h new file mode 100644 index 0000000..acd5878 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/wctrans_t.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_WCTRANS_T_H +#define MLIBC_WCTRANS_T_H + +typedef unsigned long wctrans_t; + +#endif /* MLIBC_WCTRANS_T_H */ diff --git a/user/include/mlibc/options/internal/include/bits/wctype_t.h b/user/include/mlibc/options/internal/include/bits/wctype_t.h new file mode 100644 index 0000000..7cb6de4 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/wctype_t.h @@ -0,0 +1,7 @@ +#ifndef MLIBC_WCTYPE_T_H +#define MLIBC_WCTYPE_T_H + +typedef unsigned long wctype_t; + +#endif /* MLIBC_WCTYPE_T_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/winsize.h b/user/include/mlibc/options/internal/include/bits/winsize.h new file mode 100644 index 0000000..3edbcd4 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/winsize.h @@ -0,0 +1,13 @@ + +#ifndef MLIBC_WINSIZE_H +#define MLIBC_WINSIZE_H + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#endif /* MLIBC_WINSIZE_H */ + diff --git a/user/include/mlibc/options/internal/include/bits/wint_t.h b/user/include/mlibc/options/internal/include/bits/wint_t.h new file mode 100644 index 0000000..f5aaea3 --- /dev/null +++ b/user/include/mlibc/options/internal/include/bits/wint_t.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_WINT_T_H +#define MLIBC_WINT_T_H + +typedef __WINT_TYPE__ wint_t; + +#endif /* MLIBC_WINT_T_H */ diff --git a/user/include/mlibc/options/internal/include/mlibc-asm/dwarf-helpers.h b/user/include/mlibc/options/internal/include/mlibc-asm/dwarf-helpers.h new file mode 100644 index 0000000..ee1346e --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc-asm/dwarf-helpers.h @@ -0,0 +1,127 @@ +#pragma once + +// DWARF expressions +#define DW_OP_deref 0x06 +#define DW_OP_breg0 0x70 + +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 + +#if defined(__x86_64__) + +#define DWARF_REG_RAX 0 +#define DWARF_REG_RDX 1 +#define DWARF_REG_RCX 2 +#define DWARF_REG_RBX 3 +#define DWARF_REG_RSI 4 +#define DWARF_REG_RDI 5 +#define DWARF_REG_RBP 6 +#define DWARF_REG_RSP 7 +#define DWARF_REG_R8 8 +#define DWARF_REG_R9 9 +#define DWARF_REG_R10 10 +#define DWARF_REG_R11 11 +#define DWARF_REG_R12 12 +#define DWARF_REG_R13 13 +#define DWARF_REG_R14 14 +#define DWARF_REG_R15 15 +#define DWARF_REG_RETURN_ADDRESS 16 + +#define DWARF_REG_XMM0 17 +#define DWARF_REG_XMM1 18 +#define DWARF_REG_XMM2 19 +#define DWARF_REG_XMM3 20 +#define DWARF_REG_XMM4 21 +#define DWARF_REG_XMM5 22 +#define DWARF_REG_XMM6 23 +#define DWARF_REG_XMM7 24 +#define DWARF_REG_XMM8 25 +#define DWARF_REG_XMM9 26 +#define DWARF_REG_XMM10 27 +#define DWARF_REG_XMM11 28 +#define DWARF_REG_XMM12 29 +#define DWARF_REG_XMM13 30 +#define DWARF_REG_XMM14 31 +#define DWARF_REG_XMM15 32 + +#define DWARF_REG_ST0 33 +#define DWARF_REG_ST1 34 +#define DWARF_REG_ST2 35 +#define DWARF_REG_ST3 36 +#define DWARF_REG_ST4 37 +#define DWARF_REG_ST5 38 +#define DWARF_REG_ST6 39 +#define DWARF_REG_ST7 40 + +#define DWARF_REG_MM0 41 +#define DWARF_REG_MM1 42 +#define DWARF_REG_MM2 43 +#define DWARF_REG_MM3 44 +#define DWARF_REG_MM4 45 +#define DWARF_REG_MM5 46 +#define DWARF_REG_MM6 47 +#define DWARF_REG_MM7 48 + +#define DWARF_REG_RFLAGS 49 +#define DWARF_REG_ES 50 +#define DWARF_REG_CS 51 +#define DWARF_REG_SS 52 +#define DWARF_REG_DS 53 +#define DWARF_REG_FS 54 +#define DWARF_REG_GS 55 + +#define DWARF_REG_TR 62 +#define DWARF_REG_LDTR 63 +#define DWARF_REG_MXCSR 64 +#define DWARF_REG_FCW 65 +#define DWARF_REG_FSW 66 + +#endif // defined(__x86_64__) + +#if defined(__ASSEMBLER__) + +#define DWARF_ULEB128_14BIT_SIZE(n) (1 + (((n) > 0x7f) & 1)) +#define DWARF_SLEB128_14BIT_SIZE(n) (1 + (((n) < -0x40) & 1) + (((n) > 0x3f) & 1)) + +// write an up to 2-byte signed leb128 value +.macro cfi_emit_sleb128 val + .if (\val) < -0x2000 || (\val) > 0x1fff // doesn't fit in 2 bytes + .error "cfi_emit_sleb128 value is out of range (\val)" + .elseif (\val) < -0x40 || (\val) > 0x3f // doesn't fit in 1 byte + .cfi_escape ((\val) & 0x7f) | 0x80 + .cfi_escape ((\val) >> 7) & 0x7f + .else // fits in 1 byte + .cfi_escape (\val) & 0x7f + .endif +.endm + +// write an up to 2-byte unsigned leb128 value +.macro cfi_emit_uleb128 val + .if (\val) < 0 || (\val) > 0x3fff // doesn't fit in 2 bytes + .error "cfi_emit_uleb128 value is out of range (\val)" + .elseif (\val) > 0x7f // doesn't fit in 1 byte + .cfi_escape ((\val) & 0x7f) | 0x80 + .cfi_escape (\val) >> 7 + .else + .cfi_escape (\val) + .endif +.endm + +.macro cfi_set_cfa_to_ptr_with_offset target_reg, offset + .cfi_escape DW_CFA_def_cfa_expression + cfi_emit_uleb128 (1 + DWARF_SLEB128_14BIT_SIZE(\offset) + 1) + .cfi_escape DW_OP_breg0 + (\target_reg) + cfi_emit_sleb128 (\offset) + .cfi_escape DW_OP_deref +.endm + +// Set previous value of the register 'target_reg' to (context_reg + offset) +.macro cfi_set_prev_reg_value target_reg, context_reg, offset + .cfi_escape DW_CFA_expression + cfi_emit_uleb128 (\target_reg) + cfi_emit_uleb128 (1 + DWARF_SLEB128_14BIT_SIZE(\offset)) + .cfi_escape DW_OP_breg0 + (\context_reg) + cfi_emit_sleb128 (\offset) +.endm + +#endif // defined(__ASSEMBLER__) diff --git a/user/include/mlibc/options/internal/include/mlibc-asm/helpers.h b/user/include/mlibc/options/internal/include/mlibc-asm/helpers.h new file mode 100644 index 0000000..03453e2 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc-asm/helpers.h @@ -0,0 +1,36 @@ +#pragma once + +#if !defined(__ASSEMBLER__) +#error "This file can only be used by assembly files." +#endif + +#define PROC_START(name) \ + .global name; \ + .type name, @function; \ + .cfi_startproc; \ + name: + +#define PROC_START_NOCFI(name) \ + .global name; \ + .type name, @function; \ + name: + +#define PROC_END(name) \ + .cfi_endproc; \ + .size name, . - name + +#define PROC_END_NOCFI(name) \ + .size name, . - name + +#define PROC_ALIAS(name, alias) \ + .global alias; \ + .type alias, @function; \ + .set alias, name + +#define PROC_HIDDEN_ALIAS(name, alias) \ + .hidden alias; \ + .type alias, @function; \ + .set alias, name + +#define GNU_STACK_NOTE() \ + .section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/options/internal/include/mlibc/all-sysdeps.hpp b/user/include/mlibc/options/internal/include/mlibc/all-sysdeps.hpp new file mode 100644 index 0000000..d34fd60 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/all-sysdeps.hpp @@ -0,0 +1,32 @@ +#ifndef MLIBC_ALL_SYSDEPS +#define MLIBC_ALL_SYSDEPS + +#include +#include + +/* The ANSI option is always enabled. */ +#include + +#if __MLIBC_POSIX_OPTION +# include +#endif /* __MLIBC_POSIX_OPTION */ + +#if __MLIBC_LINUX_OPTION +# include +#endif /* __MLIBC_LINUX_OPTION */ + +#if __MLIBC_GLIBC_OPTION +# include +#endif /* __MLIBC_GLIBC_OPTION */ + +#if __MLIBC_BSD_OPTION +# include +#endif /* __MLIBC_BSD_OPTION */ + +#if MLIBC_BUILDING_RTLD +# include +#endif /* MLIBC_BUILDING_RTLD */ + +#include + +#endif /* MLIBC_ALL_SYSDEPS */ diff --git a/user/include/mlibc/options/internal/include/mlibc/allocator.hpp b/user/include/mlibc/options/internal/include/mlibc/allocator.hpp new file mode 100644 index 0000000..852620a --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/allocator.hpp @@ -0,0 +1,38 @@ +#ifndef MLIBC_FRIGG_ALLOC +#define MLIBC_FRIGG_ALLOC + +#include +#include +#include +#include + +#if !MLIBC_DEBUG_ALLOCATOR + +struct VirtualAllocator { +public: + uintptr_t map(size_t length); + + void unmap(uintptr_t address, size_t length); +}; + +typedef frg::slab_pool MemoryPool; + +typedef frg::slab_allocator MemoryAllocator; + +MemoryAllocator &getAllocator(); + +#else + +struct MemoryAllocator { + void *allocate(size_t size); + void free(void *ptr); + void deallocate(void *ptr, size_t size); + void *reallocate(void *ptr, size_t size); + size_t get_size(void *ptr); +}; + +MemoryAllocator &getAllocator(); + +#endif // !MLIBC_DEBUG_ALLOCATOR + +#endif // MLIBC_FRIGG_ALLOC diff --git a/user/include/mlibc/options/internal/include/mlibc/bitutil.hpp b/user/include/mlibc/options/internal/include/mlibc/bitutil.hpp new file mode 100644 index 0000000..6d2b25e --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/bitutil.hpp @@ -0,0 +1,34 @@ +#ifndef MLIBC_BITUTIL +#define MLIBC_BITUTIL + +#include + +namespace mlibc { + +template +struct bit_util; + +template<> +struct bit_util { + static uint64_t byteswap(uint64_t x) { + return __builtin_bswap64(x); + } +}; + +template<> +struct bit_util { + static uint32_t byteswap(uint32_t x) { + return __builtin_bswap32(x); + } +}; + +template<> +struct bit_util { + static uint16_t byteswap(uint16_t x) { + return __builtin_bswap16(x); + } +}; + +} // namespace mlibc + +#endif // MLIBC_BITUTIL diff --git a/user/include/mlibc/options/internal/include/mlibc/charcode.hpp b/user/include/mlibc/options/internal/include/mlibc/charcode.hpp new file mode 100644 index 0000000..67bd03d --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/charcode.hpp @@ -0,0 +1,124 @@ +#ifndef MLIBC_CHARCODE_HPP +#define MLIBC_CHARCODE_HPP + +#include +#include +#include +#include +#include + +namespace mlibc { + +enum class charcode_error { + null, + dirty, + illegal_input, + input_underflow, + output_overflow +}; + +template +struct code_seq { + C *it; + const C *end; + + explicit operator bool () { + return it != end; + } +}; + +// Some encodings (e.g. the one defined in RFC 1843) have "shift states", +// i.e. escape sequences that switch between different encodings (e.g. between single-byte ASCII +// and 2-byte encoding of Chinese characters). +// TODO: Implement that using the __shift member of __mlibc_mbstate. + +typedef uint32_t codepoint; + +// The following class deals with decoding/encoding "code units" (of type char) +// to "code points" that are defined by unicode (of type codepoint). +// It also offers convenience functions to transcode to wchar_t, char16_t and char32_t. +// We assume that the encoding of wchar_t (and char16_t, char32_t) is fixed. +// char is allowed to have an arbitrary encoding. +// TODO: char16_t and char32_t variants are missing. +// TODO: For iconv(), first decode and then encode to the destination encoding. +struct polymorphic_charcode { + virtual ~polymorphic_charcode(); + + // Helper function to decode a single char. + charcode_error promote(char nc, codepoint &wc) { + auto uc = static_cast(nc); + if(uc <= 0x7F && preserves_7bit_units) { + wc = uc; + return charcode_error::null; + } + + code_seq nseq{&nc, &nc + 1}; + code_seq wseq{&wc, &wc + 1}; + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + + if(auto e = decode(nseq, wseq, st); e != charcode_error::null) + return e; + // This should have read/written exactly one code unit/code point. + __ensure(nseq.it == nseq.end); + __ensure(wseq.it == wseq.end); + return charcode_error::null; + } + + // Helper function to decode a single char. + charcode_error promote_wtranscode(char nc, wchar_t &wc) { + auto uc = static_cast(nc); + if(uc <= 0x7F && preserves_7bit_units) { // TODO: Use "wtranscode_preserves_7bit_units". + wc = uc; + return charcode_error::null; + } + + code_seq nseq{&nc, &nc + 1}; + code_seq wseq{&wc, &wc + 1}; + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + + if(auto e = decode_wtranscode(nseq, wseq, st); e != charcode_error::null) + return e; + // This should have read/written exactly one code unit/code point. + __ensure(nseq.it == nseq.end); + __ensure(wseq.it == wseq.end); + return charcode_error::null; + } + + polymorphic_charcode(bool preserves_7bit_units_, bool has_shift_states_) + : preserves_7bit_units{preserves_7bit_units_}, has_shift_states{has_shift_states_} { } + + virtual charcode_error decode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) = 0; + + virtual charcode_error decode_wtranscode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) = 0; + + virtual charcode_error decode_wtranscode_length(code_seq &nseq, size_t *n, + __mlibc_mbstate &st) = 0; + + virtual charcode_error encode_wtranscode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) = 0; + + virtual charcode_error encode_wtranscode_length(code_seq &wseq, size_t *n, + __mlibc_mbstate &st) = 0; + + // True if promotion only zero-extends units below 0x7F. + const bool preserves_7bit_units; + + // Whether the encoding has shift states. + const bool has_shift_states; +}; + +polymorphic_charcode *current_charcode(); + +// Similar to polymorphic_charcode but for wchar_t. Note that this encoding is fixed per-platform; +// thus, it does not need to be polymorphic. +struct wide_charcode { + charcode_error promote(wchar_t nc, codepoint &wc); +}; + +wide_charcode *platform_wide_charcode(); + +} // namespace mlibc + +#endif // MLIBC_CHARCODE_HPP diff --git a/user/include/mlibc/options/internal/include/mlibc/charset.hpp b/user/include/mlibc/options/internal/include/mlibc/charset.hpp new file mode 100644 index 0000000..a068f05 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/charset.hpp @@ -0,0 +1,40 @@ +#ifndef MLIBC_CHARSET_HPP +#define MLIBC_CHARSET_HPP + +#include + +namespace mlibc { + +// Represents the charset of a certain locale. We define the charset as +// a set of characters, together with their properties and conversion rules +// *but not* their encoding (e.g. to UTF-8 or UTF-16). +struct charset { + // Returns true iif the meaning of the first 0x7F characters matches ASCII. + bool is_ascii_superset(); + + bool is_alpha(codepoint c); + bool is_digit(codepoint c); + bool is_xdigit(codepoint c); + bool is_alnum(codepoint c); + bool is_punct(codepoint c); + bool is_graph(codepoint c); + bool is_blank(codepoint c); + bool is_space(codepoint c); + bool is_print(codepoint c); + + bool is_lower(codepoint c); + bool is_upper(codepoint c); + codepoint to_lower(codepoint c); + codepoint to_upper(codepoint c); +}; + +charset *current_charset(); + +// The property if a character is a control character is locale-independent. +inline bool generic_is_control(codepoint c) { + return (c <= 0x1F) || (c == 0x7F) || (c >= 0x80 && c <= 0x9F); +} + +} // namespace mlibc + +#endif // MLIBC_CHARSET_HPP diff --git a/user/include/mlibc/options/internal/include/mlibc/debug.hpp b/user/include/mlibc/options/internal/include/mlibc/debug.hpp new file mode 100644 index 0000000..7067039 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/debug.hpp @@ -0,0 +1,27 @@ +#ifndef MLIBC_DEBUG_HPP +#define MLIBC_DEBUG_HPP + +#include + +namespace mlibc { + +struct InfoSink { + // constexpr so that this can be initialized statically. + constexpr InfoSink() = default; + + void operator() (const char *message); +}; + +struct PanicSink { + // constexpr so that this can be initialized statically. + constexpr PanicSink() = default; + + void operator() (const char *message); +}; + +extern frg::stack_buffer_logger infoLogger; +extern frg::stack_buffer_logger panicLogger; + +} // namespace mlibc + +#endif // MLIBC_DEBUG_HPP diff --git a/user/include/mlibc/options/internal/include/mlibc/file-window.hpp b/user/include/mlibc/options/internal/include/mlibc/file-window.hpp new file mode 100644 index 0000000..509f047 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/file-window.hpp @@ -0,0 +1,64 @@ +#ifndef MLIBC_FILE_WINDOW +#define MLIBC_FILE_WINDOW + +#include +#include +#include +#include +#include + +struct file_window { + file_window(const char *path) { + int fd; + if(mlibc::sys_open(path, O_RDONLY, 0, &fd)) + mlibc::panicLogger() << "mlibc: Error opening file_window to " + << path << frg::endlog; + + if(!mlibc::sys_stat) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"cannot proceed without sys_stat"); + } + struct stat info; + if(mlibc::sys_stat(mlibc::fsfd_target::fd, fd, "", 0, &info)) + mlibc::panicLogger() << "mlibc: Error getting stats for " << path << frg::endlog; + +#if MLIBC_MAP_FILE_WINDOWS + if(mlibc::sys_vm_map(nullptr, (size_t)info.st_size, PROT_READ, MAP_PRIVATE, + fd, 0, &_ptr)) + mlibc::panicLogger() << "mlibc: Error mapping file_window to " << path << frg::endlog; +#else + _ptr = getAllocator().allocate(info.st_size); + __ensure(_ptr); + + size_t progress = 0; + size_t st_size = static_cast(info.st_size); + while(progress < st_size) { + ssize_t chunk; + if(int e = mlibc::sys_read(fd, reinterpret_cast(_ptr) + progress, + st_size - progress, &chunk); e) + mlibc::panicLogger() << "mlibc: Read from file_window failed" << frg::endlog; + if(!chunk) + break; + progress += chunk; + } + if(progress != st_size) + mlibc::panicLogger() << "stat reports " << info.st_size << " but we only read " + << progress << " bytes" << frg::endlog; +#endif + + if(mlibc::sys_close(fd)) + mlibc::panicLogger() << "mlibc: Error closing file_window to " << path << frg::endlog; + } + + // TODO: Write destructor to deallocate/unmap memory. + + void *get() { + return _ptr; + } + +private: + void *_ptr; +}; + +#endif // MLIBC_FILE_WINDOW + diff --git a/user/include/mlibc/options/internal/include/mlibc/fsfd_target.hpp b/user/include/mlibc/options/internal/include/mlibc/fsfd_target.hpp new file mode 100644 index 0000000..b577325 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/fsfd_target.hpp @@ -0,0 +1,15 @@ +#ifndef MLIBC_FSFD_TARGET +#define MLIBC_FSFD_TARGET + +namespace mlibc { + +enum class fsfd_target { + none, + path, + fd, + fd_path +}; + +} // namespace mlibc + +#endif // MLIBC_FSFD_TARGET diff --git a/user/include/mlibc/options/internal/include/mlibc/getopt.hpp b/user/include/mlibc/options/internal/include/mlibc/getopt.hpp new file mode 100644 index 0000000..c79e1b9 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/getopt.hpp @@ -0,0 +1,19 @@ +#ifndef MLIBC_GETOPT +#define MLIBC_GETOPT + +struct option; + +namespace mlibc { + +enum GetoptMode { + Short, + Long, + LongOnly, +}; + +int getopt_common(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int *longindex, enum GetoptMode mode); + +} // namespace mlibc + +#endif // MLIBC_GETOPT diff --git a/user/include/mlibc/options/internal/include/mlibc/global-config.hpp b/user/include/mlibc/options/internal/include/mlibc/global-config.hpp new file mode 100644 index 0000000..7eaed3c --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/global-config.hpp @@ -0,0 +1,19 @@ +#ifndef MLIBC_GLOBAL_CONFIG +#define MLIBC_GLOBAL_CONFIG + +namespace mlibc { + +struct GlobalConfig { + GlobalConfig(); + + bool debugMalloc; +}; + +inline const GlobalConfig &globalConfig() { + static GlobalConfig cached; + return cached; +} + +} + +#endif // MLIBC_GLOBAL_CONFIG diff --git a/user/include/mlibc/options/internal/include/mlibc/internal-sysdeps.hpp b/user/include/mlibc/options/internal/include/mlibc/internal-sysdeps.hpp new file mode 100644 index 0000000..8c058cf --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/internal-sysdeps.hpp @@ -0,0 +1,50 @@ +#ifndef MLIBC_INTERNAL_SYSDEPS +#define MLIBC_INTERNAL_SYSDEPS + +#include + +#include +#include +#include +#include +#include +#include + +#if defined(__riscv) +#include +#include +#endif + +namespace [[gnu::visibility("hidden")]] mlibc { + +void sys_libc_log(const char *message); +[[noreturn]] void sys_libc_panic(); + +int sys_tcb_set(void *pointer); + +[[gnu::weak]] int sys_futex_tid(); +int sys_futex_wait(int *pointer, int expected, const struct timespec *time); +int sys_futex_wake(int *pointer); + +int sys_anon_allocate(size_t size, void **pointer); +int sys_anon_free(void *pointer, size_t size); + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset); +int sys_close(int fd); + +[[gnu::weak]] int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf); +// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window); +int sys_vm_unmap(void *pointer, size_t size); +[[gnu::weak]] int sys_vm_protect(void *pointer, size_t size, int prot); + +#if defined(__riscv) +[[gnu::weak]] int sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags); +#endif + +} //namespace mlibc + +#endif // MLIBC_INTERNAL_SYSDEPS diff --git a/user/include/mlibc/options/internal/include/mlibc/locale.hpp b/user/include/mlibc/options/internal/include/mlibc/locale.hpp new file mode 100644 index 0000000..a46a2c3 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/locale.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_LOCALE +#define MLIBC_LOCALE + +#include + +namespace mlibc { + +char *nl_langinfo(nl_item item); + +} // namespace mlibc + +#endif // MLIBC_LOCALE diff --git a/user/include/mlibc/options/internal/include/mlibc/lock.hpp b/user/include/mlibc/options/internal/include/mlibc/lock.hpp new file mode 100644 index 0000000..85ceb4e --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/lock.hpp @@ -0,0 +1,129 @@ +#ifndef MLIBC_LOCK_HPP +#define MLIBC_LOCK_HPP + +#include +#include +#include +#include +#include +#include + +// alignas(4) is specified for the benefit of m68k, where default alignment is +// 2 bytes for a uint32_t, while the futex syscall requires 4-byte alignment. +// It is a no-op on any other architecture. + +template +struct alignas(4) FutexLockImpl { + FutexLockImpl() : _state{0}, _recursion{0} { } + + FutexLockImpl(const FutexLockImpl &) = delete; + + FutexLockImpl &operator= (const FutexLockImpl &) = delete; + + static constexpr uint32_t waitersBit = (1 << 31); + static constexpr uint32_t ownerMask = (static_cast(1) << 30) - 1; + + void lock() { + unsigned int this_tid = mlibc::this_tid(); + unsigned int expected = 0; + + while(true) { + if(!expected) { + // Try to take the mutex here. + if(__atomic_compare_exchange_n(&_state, + &expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + if constexpr (Recursive) { + __ensure(!_recursion); + _recursion = 1; + } + return; + } + }else{ + // If this (recursive) mutex is already owned by us, increment the recursion level. + if((expected & ownerMask) == this_tid) { + if constexpr (Recursive) + ++_recursion; + else + mlibc::panicLogger() << "mlibc: FutexLock deadlock detected!" << frg::endlog; + return; + } + + // Wait on the futex if the waiters flag is set. + if(expected & waitersBit) { + int e = mlibc::sys_futex_wait((int *)&_state, expected, nullptr); + + // If the wait returns EAGAIN, that means that the waitersBit was just unset by + // some other thread. In this case, we should loop back around. + // Also loop around in case of a signal interrupting the wait + if (e && e != EAGAIN && e != EINTR) + mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog; + + // Opportunistically try to take the lock after we wake up. + expected = 0; + }else{ + // Otherwise we have to set the waiters flag first. + unsigned int desired = expected | waitersBit; + if(__atomic_compare_exchange_n((int *)&_state, + reinterpret_cast(&expected), desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + expected = desired; + } + } + } + } + + bool try_lock() { + unsigned int this_tid = mlibc::this_tid(); + unsigned int expected = __atomic_load_n(&_state, __ATOMIC_RELAXED); + + if(!expected) { + // Try to take the mutex here. + if(__atomic_compare_exchange_n(&_state, + &expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + if constexpr (Recursive) + _recursion = 1; + return true; + } + } else { + // If this (recursive) mutex is already owned by us, increment the recursion level. + if((expected & ownerMask) == this_tid) { + if constexpr (Recursive) { + __ensure(!_recursion); + ++_recursion; + return true; + } else { + return false; + } + } + } + + return false; + } + + void unlock() { + // Decrement the recursion level and unlock if we hit zero. + if constexpr (Recursive) { + __ensure(_recursion); + if(--_recursion) + return; + } + + // Reset the mutex to the unlocked state. + auto state = __atomic_exchange_n(&_state, 0, __ATOMIC_RELEASE); + __ensure((state & ownerMask) == mlibc::this_tid()); + + if(state & waitersBit) { + // Wake the futex if there were waiters. Since the mutex might not exist at this location + // anymore, we must conservatively ignore EACCES and EINVAL which may occur as a result. + int e = mlibc::sys_futex_wake((int *)&_state); + __ensure(e >= 0 || e == EACCES || e == EINVAL); + } + } +private: + uint32_t _state; + uint32_t _recursion; +}; + +using FutexLock = FutexLockImpl; +using RecursiveFutexLock = FutexLockImpl; + +#endif diff --git a/user/include/mlibc/options/internal/include/mlibc/search.hpp b/user/include/mlibc/options/internal/include/mlibc/search.hpp new file mode 100644 index 0000000..548220d --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/search.hpp @@ -0,0 +1,14 @@ +#ifndef MLIBC_SEARCH +#define MLIBC_SEARCH + +#include + +namespace mlibc { + +int hcreate_r(size_t num_entries, struct hsearch_data *htab); +void hdestroy_r(struct hsearch_data *htab); +int hsearch_r(ENTRY item, ACTION action, ENTRY **ret, struct hsearch_data *htab); + +} // namespace mlibc + +#endif // MLIBC_SEARCH diff --git a/user/include/mlibc/options/internal/include/mlibc/stack_protector.hpp b/user/include/mlibc/options/internal/include/mlibc/stack_protector.hpp new file mode 100644 index 0000000..47290fc --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/stack_protector.hpp @@ -0,0 +1,10 @@ +#ifndef MLIBC_STACK_PROTECTOR_HPP +#define MLIBC_STACK_PROTECTOR_HPP + +namespace mlibc { + +void initStackGuard(void *); + +} // namespace mlibc + +#endif // MLIBC_STACK_PROTECTOR_HPP diff --git a/user/include/mlibc/options/internal/include/mlibc/strings.hpp b/user/include/mlibc/options/internal/include/mlibc/strings.hpp new file mode 100644 index 0000000..5a93c7c --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/strings.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_STRINGS +#define MLIBC_STRINGS + +#include + +namespace mlibc { + +int strncasecmp(const char *a, const char *b, size_t size); + +} // namespace mlibc + +#endif // MLIBC_STRINGS diff --git a/user/include/mlibc/options/internal/include/mlibc/strtofp.hpp b/user/include/mlibc/options/internal/include/mlibc/strtofp.hpp new file mode 100644 index 0000000..f9c5e20 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/strtofp.hpp @@ -0,0 +1,165 @@ +#ifndef MLIBC_STRTOFP_HPP +#define MLIBC_STRTOFP_HPP + +#include +#include +#include + +namespace mlibc { + +template +T strtofp(const char *str, char **endptr) { + if (strcmp(str, "INF") == 0 || strcmp(str, "inf") == 0) { + if (endptr) + *endptr = (char *)str + 3; + if constexpr (std::is_same_v) + return __builtin_inff(); + else if constexpr (std::is_same_v) + return __builtin_inf(); + else + return __builtin_infl(); + } else if (strcmp(str, "INFINITY") == 0 || strcmp(str, "infinity") == 0) { + if (endptr) + *endptr = (char *)str + 8; + if constexpr (std::is_same_v) + return __builtin_inff(); + else if constexpr (std::is_same_v) + return __builtin_inf(); + else + return __builtin_infl(); + } else if (strncmp(str, "NAN", 3) == 0 || strncmp(str, "nan", 3) == 0) { + if (endptr) + *endptr = (char *)str + 3; + if constexpr (std::is_same_v) + return __builtin_nanf(""); + else if constexpr (std::is_same_v) + return __builtin_nan(""); + else + return __builtin_nanl(""); + } + + bool negative = *str == '-'; + if (*str == '+' || *str == '-') + str++; + + bool hex = false; + if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) { + str += 2; + hex = true; + } + + T result = static_cast(0); + + const char *tmp = str; + + if (!hex) { + while (true) { + if (!isdigit(*tmp)) + break; + result *= static_cast(10); + result += static_cast(*tmp - '0'); + tmp++; + } + } else { + while (true) { + if (!isxdigit(*tmp)) + break; + result *= static_cast(16); + result += static_cast(*tmp <= '9' ? (*tmp - '0') : (tolower(*tmp) - 'a' + 10)); + tmp++; + } + } + + if (*tmp == '.') { + tmp++; + + if (!hex) { + T d = static_cast(10); + + while (true) { + if (!isdigit(*tmp)) + break; + result += static_cast(*tmp - '0') / d; + d *= static_cast(10); + tmp++; + } + } else { + T d = static_cast(16); + + while (true) { + if (!isxdigit(*tmp)) + break; + result += static_cast(*tmp <= '9' ? (*tmp - '0') : (tolower(*tmp) - 'a' + 10)) / d; + d *= static_cast(16); + tmp++; + } + } + } + + if (!hex) { + if (*tmp == 'e' || *tmp == 'E') { + tmp++; + + bool exp_negative = *tmp == '-'; + if (*tmp == '+' || *tmp == '-') + tmp++; + + int exp = 0; + while (true) { + if (!isdigit(*tmp)) + break; + exp *= 10; + exp += *tmp - '0'; + tmp++; + } + + if (!exp_negative) { + for (int i = 0; i < exp; ++i) { + result *= static_cast(10); + } + } else { + for (int i = 0; i < exp; ++i) { + result /= static_cast(10); + } + } + } + } else { + if (*tmp == 'p' || *tmp == 'P') { + tmp++; + + bool exp_negative = *tmp == '-'; + if (*tmp == '+' || *tmp == '-') + tmp++; + + int exp = 0; + while (true) { + if (!isdigit(*tmp)) + break; + exp *= 10; + exp += *tmp - '0'; + tmp++; + } + + if (!exp_negative) { + for (int i = 0; i < exp; ++i) { + result *= static_cast(2); + } + } else { + for (int i = 0; i < exp; ++i) { + result /= static_cast(2); + } + } + } + } + + if (endptr) + *endptr = const_cast(tmp); + if (negative) + result = -result; + + return result; +} + +} + +#endif // MLIBC_STRTOFP_HPP diff --git a/user/include/mlibc/options/internal/include/mlibc/strtol.hpp b/user/include/mlibc/options/internal/include/mlibc/strtol.hpp new file mode 100644 index 0000000..2dab276 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/strtol.hpp @@ -0,0 +1,163 @@ +#ifndef MLIBC_STRTOL_HPP +#define MLIBC_STRTOL_HPP + +#include +#include +#include +#include + +namespace mlibc { + +template struct int_limits {}; + +template<> +struct int_limits { + static long max() { return LONG_MAX; } + static long min() { return LONG_MIN; } +}; + +template<> +struct int_limits { + static unsigned long max() { return ULONG_MAX; } + static unsigned long min() { return 0; } +}; + +template<> +struct int_limits { + static long long max() { return LLONG_MAX; } + static long long min() { return LLONG_MIN; } +}; + +template<> +struct int_limits { + static unsigned long long max() { return ULLONG_MAX; } + static unsigned long long min() { return 0; } +}; + +template struct char_detail {}; + +template<> +struct char_detail { + static bool isSpace(char c) { return isspace(c); } + static bool isDigit(char c) { return isdigit(c); } + static bool isHexDigit(char c) { return isxdigit(c); } + static bool isLower(char c) { return islower(c); } + static bool isUpper(char c) { return isupper(c); } +}; + +template<> +struct char_detail { + static bool isSpace(wchar_t c) { return iswspace(c); } + static bool isDigit(wchar_t c) { return iswdigit(c); } + static bool isHexDigit(wchar_t c) { return iswxdigit(c); } + static bool isLower(wchar_t c) { return iswlower(c); } + static bool isUpper(wchar_t c) { return iswupper(c); } +}; + +template Char widen(char c) { return static_cast(c); } + +template +Return stringToInteger(const Char *__restrict nptr, Char **__restrict endptr, int baseInt) { + using UnsignedReturn = std::make_unsigned_t; + + auto base = static_cast(baseInt); + auto s = nptr; + + if (base < 0 || base == 1) { + if (endptr) + *endptr = const_cast(nptr); + return 0; + } + + while (char_detail::isSpace(*s)) + s++; + + bool negative = false; + if (*s == widen('-')) { + negative = true; + s++; + } else if (*s == widen('+')) { + s++; + } + + + bool hasOctalPrefix = s[0] == widen('0'); + bool hasHexPrefix = hasOctalPrefix && (s[1] == widen('x') || s[1] == widen('X')); + bool hasBinPrefix = hasOctalPrefix && (s[1] == widen('b') || s[1] == widen('B')); + + // There's two tricky cases we need to keep in mind here: + // 1. We should interpret "0x5" as hex 5 rather than octal 0. + // 2. We should interpret "0x" as octal 0 (and set endptr correctly). + // To deal with 2, we check the charcacter following the hex prefix. + if ((base == 0 || base == 16) && hasHexPrefix && char_detail::isHexDigit(s[2])) { + s += 2; + base = 16; + } else if ((base == 0 || base == 2) && hasBinPrefix) { + s += 2; + base = 2; + } else if ((base == 0 || base == 8) && hasOctalPrefix) { + base = 8; + } else if (base == 0) { + base = 10; + } + + // Compute the range of acceptable values. + UnsignedReturn cutoff, cutlim; + if (std::is_unsigned_v) { + cutoff = int_limits::max() / base; + cutlim = int_limits::max() % base; + } else { + Return co = negative ? int_limits::min() : int_limits::max(); + cutlim = negative ? -(co % base) : co % base; + co /= negative ? -base : base; + cutoff = co; + } + + UnsignedReturn totalValue = 0; + bool convertedAny = false; + bool outOfRange = false; + for (Char c = *s; c != widen('\0'); c = *++s) { + UnsignedReturn digitValue; + if (char_detail::isDigit(c)) + digitValue = c - widen('0'); + else if (char_detail::isUpper(c)) + digitValue = c - widen('A') + 10; + else if (char_detail::isLower(c)) + digitValue = c - widen('a') + 10; + else + break; + + if (digitValue >= static_cast(base)) + break; + + if (outOfRange) { + // The value is already known to be out of range, but we need to keep + // consuming characters until we can't (to set endptr correctly). + } else if (totalValue > cutoff || (totalValue == cutoff && digitValue > cutlim)) { + // The value will be out of range if we accumulate digitValue. + outOfRange = true; + } else { + totalValue = (totalValue * base) + digitValue; + convertedAny = true; + } + } + + if (endptr) + *endptr = const_cast(convertedAny ? s : nptr); + + if (outOfRange) { + errno = ERANGE; + + if (std::is_unsigned_v) { + return int_limits::max(); + } else { + return negative ? int_limits::min() : int_limits::max(); + } + } + + return negative ? -totalValue : totalValue; +} + +} + +#endif // MLIBC_STRTOL_HPP diff --git a/user/include/mlibc/options/internal/include/mlibc/sysdep-signatures.hpp b/user/include/mlibc/options/internal/include/mlibc/sysdep-signatures.hpp new file mode 100644 index 0000000..db3309d --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/sysdep-signatures.hpp @@ -0,0 +1,370 @@ +#ifndef MLIBC_SYSDEP_SIGNATURES +#define MLIBC_SYSDEP_SIGNATURES + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace mlibc { + +template +struct SysdepImpl; + +struct NoImpl {}; + +template +using SysdepOf = std::conditional_t< + std::derived_from, + mlibc::SysdepImpl, + NoImpl +>; + +#define SYSDEP_FUNC(name, ...) template <> struct SysdepImpl { static int operator()(__VA_ARGS__); } +#define SYSDEP_FUNC_RET(rettype, name, ...) template <> struct SysdepImpl { static rettype operator()(__VA_ARGS__); } +#define SYSDEP_FUNC_NORETURN(name, ...) template <> struct SysdepImpl { [[noreturn]] static void operator()(__VA_ARGS__); } + +SYSDEP_FUNC_RET(void, LibcLog, const char *message); +SYSDEP_FUNC_NORETURN(LibcPanic); + +SYSDEP_FUNC_RET(pid_t, FutexTid); +SYSDEP_FUNC(AnonAllocate, size_t size, void **pointer); +SYSDEP_FUNC(AnonFree, void *pointer, size_t size); +SYSDEP_FUNC(Stat, mlibc::fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf); +SYSDEP_FUNC(VmMap, void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window); +SYSDEP_FUNC(VmUnmap, void *pointer, size_t size); +SYSDEP_FUNC(VmProtect, void *pointer, size_t size, int prot); +SYSDEP_FUNC(TcbSet, void *pointer); +#if defined(__riscv) +SYSDEP_FUNC(RiscvHwprobe, struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags); +#endif + +// ANSI option sysdeps +SYSDEP_FUNC_NORETURN(Exit, int status); +SYSDEP_FUNC_NORETURN(ThreadExit); +SYSDEP_FUNC(PrepareStack, void **stack, void *entry, void *user_arg, void* tcb, size_t *stack_size, size_t *guard_size, void **stack_base); +SYSDEP_FUNC(Clone, void *tcb, pid_t *pid_out, void *stack); +SYSDEP_FUNC(FutexWait, int *pointer, int expected, const struct timespec *time); +SYSDEP_FUNC(FutexWake, int *pointer, bool all); +SYSDEP_FUNC(Open, const char *pathname, int flags, mode_t mode, int *fd); +SYSDEP_FUNC(Flock, int fd, int options); +SYSDEP_FUNC(OpenDir, const char *path, int *handle); +SYSDEP_FUNC(ReadEntries, int handle, void *buffer, size_t max_size, size_t *bytes_read); +SYSDEP_FUNC(Read, int fd, void *buf, size_t count, ssize_t *bytes_read); +SYSDEP_FUNC(Write, int fd, const void *buf, size_t count, ssize_t *bytes_written); +SYSDEP_FUNC(Pread, int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read); +SYSDEP_FUNC(Seek, int fd, off_t offset, int whence, off_t *new_offset); +SYSDEP_FUNC(Close, int fd); +SYSDEP_FUNC(ClockGet, int clock, time_t *secs, long *nanos); +SYSDEP_FUNC(ClockSet, int clock, time_t secs, long nanos); +SYSDEP_FUNC(ClockGetres, int clock, time_t *secs, long *nanos); +SYSDEP_FUNC(Sleep, time_t *secs, long *nanos); +SYSDEP_FUNC(Isatty, int fd); +SYSDEP_FUNC(Rmdir, const char *path); +SYSDEP_FUNC(Unlinkat, int dirfd, const char *path, int flags); +SYSDEP_FUNC(Rename, const char *path, const char *new_path); +SYSDEP_FUNC(FdToPath, int fd, char **out); +SYSDEP_FUNC(Sigprocmask, int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve); +SYSDEP_FUNC(Sigaction, int, const struct sigaction *__restrict, struct sigaction *__restrict); +SYSDEP_FUNC(Fork, pid_t *child); +SYSDEP_FUNC(Waitpid, pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid); +SYSDEP_FUNC(Execve, const char *path, char *const argv[], char *const envp[]); +SYSDEP_FUNC_RET(void, Yield); +SYSDEP_FUNC_RET(pid_t, GetPid); +SYSDEP_FUNC(Kill, pid_t, int); + +#if MLIBC_BUILDING_RTLD +SYSDEP_FUNC(VmReadahead, void *pointer, size_t size); +#endif /* MLIBC_BUILDING_RTLD */ + +#if __MLIBC_POSIX_OPTION +SYSDEP_FUNC(Readv, int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read); +SYSDEP_FUNC(Writev, int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written); +SYSDEP_FUNC(Pwrite, int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_read); +SYSDEP_FUNC(Access, const char *path, int mode); +SYSDEP_FUNC(Faccessat, int dirfd, const char *pathname, int mode, int flags); +SYSDEP_FUNC(Dup, int fd, int flags, int *newfd); +SYSDEP_FUNC(Dup2, int fd, int flags, int newfd); +SYSDEP_FUNC(Statvfs, const char *path, struct statvfs *out); +SYSDEP_FUNC(Fstatvfs, int fd, struct statvfs *out); +SYSDEP_FUNC(Readlink, const char *path, void *buffer, size_t max_size, ssize_t *length); +SYSDEP_FUNC(Readlinkat, int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length); +SYSDEP_FUNC(Truncate, const char *path, off_t length); +SYSDEP_FUNC(Ftruncate, int fd, size_t size); +SYSDEP_FUNC(Fallocate, int fd, off_t offset, size_t size); +SYSDEP_FUNC(Openat, int dirfd, const char *path, int flags, mode_t mode, int *fd); +SYSDEP_FUNC(Socket, int family, int type, int protocol, int *fd); +SYSDEP_FUNC(MsgSend, int fd, const struct msghdr *hdr, int flags, ssize_t *length); +SYSDEP_FUNC(Sendto, int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length); +SYSDEP_FUNC(MsgRecv, int fd, struct msghdr *hdr, int flags, ssize_t *length); +SYSDEP_FUNC(Recvfrom, int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length); +SYSDEP_FUNC(Listen, int fd, int backlog); +SYSDEP_FUNC_RET(gid_t, GetGid); +SYSDEP_FUNC_RET(gid_t, GetEgid); +SYSDEP_FUNC_RET(uid_t, GetUid); +SYSDEP_FUNC_RET(uid_t, GetEuid); +SYSDEP_FUNC_RET(pid_t, GetTid); +SYSDEP_FUNC_RET(pid_t, GetPpid); +SYSDEP_FUNC(GetPgid, pid_t pid, pid_t *pgid); +SYSDEP_FUNC(GetSid, pid_t pid, pid_t *sid); +SYSDEP_FUNC(SetPgid, pid_t pid, pid_t pgid); +SYSDEP_FUNC(SetUid, uid_t uid); +SYSDEP_FUNC(SetEuid, uid_t euid); +SYSDEP_FUNC(SetGid, gid_t gid); +SYSDEP_FUNC(SetEgid, gid_t egid); +SYSDEP_FUNC(GetGroups, size_t size, gid_t *list, int *ret); +SYSDEP_FUNC(Fexecve, int fd, char *const argv[], char *const envp[]); +SYSDEP_FUNC(Pselect, int num_fds, fd_set *read_set, fd_set *write_set, fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events); +SYSDEP_FUNC(GetRusage, int scope, struct rusage *usage); +SYSDEP_FUNC(GetRlimit, int resource, struct rlimit *limit); +SYSDEP_FUNC(SetRlimit, int resource, const struct rlimit *limit); +SYSDEP_FUNC(GetPriority, int which, id_t who, int *value); +SYSDEP_FUNC(SetPriority, int which, id_t who, int prio); +SYSDEP_FUNC(GetSchedparam, void *tcb, int *policy, struct sched_param *param); +SYSDEP_FUNC(SetSchedparam, void *tcb, int policy, const struct sched_param *param); +SYSDEP_FUNC(GetScheduler, pid_t pid, int *policy); +SYSDEP_FUNC(SetScheduler, pid_t pid, int policy, const struct sched_param *param); +SYSDEP_FUNC(GetParam, pid_t pid, struct sched_param *param); +SYSDEP_FUNC(SetParam, pid_t pid, const struct sched_param *param); +SYSDEP_FUNC(GetMaxPriority, int policy, int *out); +SYSDEP_FUNC(GetMinPriority, int policy, int *out); +SYSDEP_FUNC(GetCwd, char *buffer, size_t size); +SYSDEP_FUNC(Chdir, const char *path); +SYSDEP_FUNC(Fchdir, int fd); +SYSDEP_FUNC(Chroot, const char *path); +SYSDEP_FUNC(Mkdir, const char *path, mode_t mode); +SYSDEP_FUNC(Mkdirat, int dirfd, const char *path, mode_t mode); +SYSDEP_FUNC(Link, const char *old_path, const char *new_path); +SYSDEP_FUNC(Linkat, int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags); +SYSDEP_FUNC(Symlink, const char *target_path, const char *link_path); +SYSDEP_FUNC(Symlinkat, const char *target_path, int dirfd, const char *link_path); +SYSDEP_FUNC(Renameat, int olddirfd, const char *old_path, int newdirfd, const char *new_path); +SYSDEP_FUNC(Fcntl, int fd, int request, va_list args, int *result); +SYSDEP_FUNC(Ttyname, int fd, char *buf, size_t size); +SYSDEP_FUNC(Fadvise, int fd, off_t offset, off_t length, int advice); +SYSDEP_FUNC_RET(void, Sync); +SYSDEP_FUNC(Fsync, int fd); +SYSDEP_FUNC(Fdatasync, int fd); +SYSDEP_FUNC(Chmod, const char *pathname, mode_t mode); +SYSDEP_FUNC(Fchmod, int fd, mode_t mode); +SYSDEP_FUNC(Fchmodat, int fd, const char *pathname, mode_t mode, int flags); +SYSDEP_FUNC(Utimensat, int dirfd, const char *pathname, const struct timespec times[2], int flags); +SYSDEP_FUNC(Mlock, const void *addr, size_t length); +SYSDEP_FUNC(Munlock, const void *addr, size_t length); +SYSDEP_FUNC(Mlockall, int flags); +SYSDEP_FUNC(Munlockall); +SYSDEP_FUNC(Mincore, void *addr, size_t length, unsigned char *vec); +SYSDEP_FUNC(VmRemap, void *pointer, size_t size, size_t new_size, void **window); +SYSDEP_FUNC(SetSid, pid_t *sid); +SYSDEP_FUNC(Tcgetattr, int fd, struct termios *attr); +SYSDEP_FUNC(Tcsetattr, int, int, const struct termios *attr); +SYSDEP_FUNC(Tcsendbreak, int fd, int dur); +SYSDEP_FUNC(Tcflow, int, int); +SYSDEP_FUNC(Tcflush, int fd, int queue); +SYSDEP_FUNC(Tcdrain, int); +SYSDEP_FUNC(Tcgetwinsize, int fd, struct winsize *winsz); +SYSDEP_FUNC(Tcsetwinsize, int fd, const struct winsize *winsz); +SYSDEP_FUNC(Pipe, int *fds, int flags); +SYSDEP_FUNC(Socketpair, int domain, int type_and_flags, int proto, int *fds); +SYSDEP_FUNC(Poll, struct pollfd *fds, nfds_t count, int timeout, int *num_events); +SYSDEP_FUNC(Ppoll, struct pollfd *fds, nfds_t count, const struct timespec *ts, const sigset_t *mask, int *num_events); +SYSDEP_FUNC(Ioctl, int fd, unsigned long request, void *arg, int *result); +SYSDEP_FUNC(PosixDevctl, int fd, int dcmd, void *__restrict dev_data_ptr, size_t nbyte, int *__restrict dev_info_ptr); +SYSDEP_FUNC(GetSockopt, int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size); +SYSDEP_FUNC(SetSockopt, int fd, int layer, int number, const void *buffer, socklen_t size); +SYSDEP_FUNC(Shutdown, int sockfd, int how); +SYSDEP_FUNC(Sockatmark, int sockfd, int *out); +SYSDEP_FUNC(ThreadSigmask, int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve); +SYSDEP_FUNC(Sigtimedwait, const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal); +SYSDEP_FUNC(Accept, int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags); +SYSDEP_FUNC(Bind, int fd, const struct sockaddr *addr_ptr, socklen_t addr_length); +SYSDEP_FUNC(Connect, int fd, const struct sockaddr *addr_ptr, socklen_t addr_length); +SYSDEP_FUNC(Sockname, int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length); +SYSDEP_FUNC(Peername, int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length); +SYSDEP_FUNC(GetHostname, char *buffer, size_t bufsize); +SYSDEP_FUNC(SetHostname, const char *buffer, size_t bufsize); +SYSDEP_FUNC(Mkfifoat, int dirfd, const char *path, mode_t mode); +SYSDEP_FUNC(GetEntropy, void *buffer, size_t length); +SYSDEP_FUNC(Mknodat, int dirfd, const char *path, int mode, int dev); +SYSDEP_FUNC(Umask, mode_t mode, mode_t *old); +SYSDEP_FUNC(BeforeCancellableSyscall, ucontext_t *uctx); +SYSDEP_FUNC(Tgkill, int tgid, int tid, int sig); +SYSDEP_FUNC(Fchownat, int dirfd, const char *pathname, uid_t owner, gid_t group, int flags); +SYSDEP_FUNC(Sigaltstack, const stack_t *ss, stack_t *oss); +SYSDEP_FUNC(Sigsuspend, const sigset_t *set); +SYSDEP_FUNC(Sigpending, sigset_t *set); +SYSDEP_FUNC(Sigqueue, pid_t pid, int sig, const union sigval val); +SYSDEP_FUNC(SetGroups, size_t size, const gid_t *list); +SYSDEP_FUNC(MemfdCreate, const char *name, int flags, int *fd); +SYSDEP_FUNC(Madvise, void *addr, size_t length, int advice); +SYSDEP_FUNC(PosixMadvise, void *addr, size_t length, int advice); +SYSDEP_FUNC(Msync, void *addr, size_t length, int flags); +SYSDEP_FUNC(GetItimer, int which, struct itimerval *curr_value); +SYSDEP_FUNC(SetItimer, int which, const struct itimerval *new_value, struct itimerval *old_value); +SYSDEP_FUNC(TimerCreate, clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res); +SYSDEP_FUNC(TimerSettime, timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old); +SYSDEP_FUNC(TimerGettime, timer_t t, struct itimerspec *val); +SYSDEP_FUNC(TimerDelete, timer_t t); +SYSDEP_FUNC(TimerGetoverrun, timer_t t, int *out); +SYSDEP_FUNC(Times, struct tms *tms, clock_t *out); +SYSDEP_FUNC(Uname, struct utsname *buf); +SYSDEP_FUNC(Pause); +SYSDEP_FUNC(SetResuid, uid_t ruid, uid_t euid, uid_t suid); +SYSDEP_FUNC(SetResgid, gid_t rgid, gid_t egid, gid_t sgid); +SYSDEP_FUNC(GetResuid, uid_t *ruid, uid_t *euid, uid_t *suid); +SYSDEP_FUNC(GetResgid, gid_t *rgid, gid_t *egid, gid_t *sgid); +SYSDEP_FUNC(SetReuid, uid_t ruid, uid_t euid); +SYSDEP_FUNC(SetRegid, gid_t rgid, gid_t egid); +SYSDEP_FUNC(GetLoginR, char *name, size_t name_len); +SYSDEP_FUNC(IfIndextoname, unsigned int index, char *name); +SYSDEP_FUNC(IfNametoindex, const char *name, unsigned int *ret); +SYSDEP_FUNC(Ptsname, int fd, char *buffer, size_t length); +SYSDEP_FUNC(Unlockpt, int fd); +SYSDEP_FUNC(ThreadSetname, void *tcb, const char *name); +SYSDEP_FUNC(ThreadGetname, void *tcb, char *name, size_t size); +SYSDEP_FUNC(Sysconf, int num, long *ret); +SYSDEP_FUNC(Semget, key_t key, int n, int fl, int *id); +SYSDEP_FUNC(Semctl, int semid, int semnum, int cmd, void *semun, int *ret); +SYSDEP_FUNC(GetAffinity, pid_t pid, size_t cpusetsize, cpu_set_t *mask); +SYSDEP_FUNC(GetThreadaffinity, pid_t tid, size_t cpusetsize, cpu_set_t *mask); +SYSDEP_FUNC(SetAffinity, pid_t pid, size_t cpusetsize, const cpu_set_t *mask); +SYSDEP_FUNC(SetThreadaffinity, pid_t tid, size_t cpusetsize, const cpu_set_t *mask); +SYSDEP_FUNC(GetCurrentStackInfo, void **stack_base, size_t *stack_size); +SYSDEP_FUNC(Waitid, idtype_t idtype, id_t id, siginfo_t *info, int options); +SYSDEP_FUNC(NameToHandleAt, int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags); +SYSDEP_FUNC(Splice, int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags, ssize_t *out); +SYSDEP_FUNC(Shmat, void **seg_start, int shmid, const void *shmaddr, int shmflg); +SYSDEP_FUNC(Shmctl, int *idx, int shmid, int cmd, struct shmid_ds *buf); +SYSDEP_FUNC(Shmdt, const void *shmaddr); +SYSDEP_FUNC(Shmget, int *shm_id, key_t key, size_t size, int shmflg); +SYSDEP_FUNC(InetConfigured, bool *ipv4, bool *ipv6); +SYSDEP_FUNC(Nice, int nice, int *new_nice); +SYSDEP_FUNC(Openpt, int oflags, int *fd); +SYSDEP_FUNC(Msgctl, int q, int cmd, struct msqid_ds *buf); +SYSDEP_FUNC(Msgget, key_t k, int flag, int *out); +SYSDEP_FUNC(Msgrcv, int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg, ssize_t *out); +SYSDEP_FUNC(Msgsnd, int msqid, const void *msgp, size_t msgsz, int msgflg); +SYSDEP_FUNC(MqOpen, const char *name, int oflag, mode_t mode, mq_attr *attr, mqd_t *out); +SYSDEP_FUNC(MqUnlink, const char *name); +SYSDEP_FUNC(MqReceive, mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); +SYSDEP_FUNC(MqGetAttr, mqd_t mqdes, mq_attr *mqstat); +SYSDEP_FUNC(MqSetAttr, mqd_t mqdes, const mq_attr *mqstat, mq_attr *omqstat); +#endif // __MLIBC_POSIX_OPTION + +#if __MLIBC_LINUX_OPTION +SYSDEP_FUNC(InotifyCreate, int flags, int *fd); +SYSDEP_FUNC(InotifyAddWatch, int ifd, const char *path, uint32_t mask, int *wd); +SYSDEP_FUNC(InotifyRmWatch, int ifd, int wd); +SYSDEP_FUNC(Mount, const char *source, const char *target, const char *fstype, unsigned long flags, const void *data); +SYSDEP_FUNC(Umount2, const char *target, int flags); +SYSDEP_FUNC(Ptrace, long req, pid_t pid, void *addr, void *data, long *out); +SYSDEP_FUNC(Capget, cap_user_header_t hdrp, cap_user_data_t datap); +SYSDEP_FUNC(Capset, cap_user_header_t hdrp, const cap_user_data_t datap); +SYSDEP_FUNC(Prctl, int option, va_list va, int *out); +SYSDEP_FUNC(InitModule, void *module, unsigned long length, const char *args); +SYSDEP_FUNC(DeleteModule, const char *name, unsigned flags); +SYSDEP_FUNC(Klogctl, int type, char *bufp, int len, int *out); +SYSDEP_FUNC(Getcpu, int *cpu); +SYSDEP_FUNC(Sysinfo, struct sysinfo *info); +SYSDEP_FUNC(Swapon, const char *path, int flags); +SYSDEP_FUNC(Swapoff, const char *path); +SYSDEP_FUNC(Setxattr, const char *path, const char *name, const void *val, size_t size, int flags); +SYSDEP_FUNC(Lsetxattr, const char *path, const char *name, const void *val, size_t size, int flags); +SYSDEP_FUNC(Fsetxattr, int fd, const char *name, const void *val, size_t size, int flags); +SYSDEP_FUNC(Getxattr, const char *path, const char *name, void *val, size_t size, ssize_t *nread); +SYSDEP_FUNC(Lgetxattr, const char *path, const char *name, void *val, size_t size, ssize_t *nread); +SYSDEP_FUNC(Fgetxattr, int fd, const char *name, void *val, size_t size, ssize_t *nread); +SYSDEP_FUNC(Listxattr, const char *path, char *list, size_t size, ssize_t *nread); +SYSDEP_FUNC(Llistxattr, const char *path, char *list, size_t size, ssize_t *nread); +SYSDEP_FUNC(Flistxattr, int fd, char *list, size_t size, ssize_t *nread); +SYSDEP_FUNC(Removexattr, const char *path, const char *name); +SYSDEP_FUNC(Lremovexattr, const char *path, const char *name); +SYSDEP_FUNC(Fremovexattr, int fd, const char *name); +SYSDEP_FUNC(Statfs, const char *path, struct statfs *buf); +SYSDEP_FUNC(Fstatfs, int fd, struct statfs *buf); +SYSDEP_FUNC(Statx, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf); +SYSDEP_FUNC(Getifaddrs, struct ifaddrs **); +SYSDEP_FUNC(Sendfile, int outfd, int infd, off_t *offset, size_t count, ssize_t *out); +SYSDEP_FUNC(Syncfs, int fd); +SYSDEP_FUNC(Unshare, int flags); +SYSDEP_FUNC(SetNs, int fd, int nstype); +SYSDEP_FUNC(PidfdOpen, pid_t pid, unsigned int flags, int *outfd); +SYSDEP_FUNC(PidfdGetpid, int fd, pid_t *outpid); +SYSDEP_FUNC(PidfdSendSignal, int pidfd, int sig, siginfo_t *info, unsigned int flags); +SYSDEP_FUNC(ProcessVmReadv, pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags, ssize_t *out); +SYSDEP_FUNC(ProcessVmWritev, pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags, ssize_t *out); +SYSDEP_FUNC(Fsopen, const char *fsname, unsigned int flags, int *outfd); +SYSDEP_FUNC(Fsmount, int fsfd, unsigned int flags, unsigned int mountflags, int *outfd); +SYSDEP_FUNC(Fsconfig, int fd, unsigned int cmd, const char *key, const void *val, int aux); +SYSDEP_FUNC(MoveMount, int from_dirfd, const char *from_path, int to_dirfd, const char *to_path, unsigned int flags); +SYSDEP_FUNC(OpenTree, int dirfd, const char *path, unsigned int flags, int *outfd); +SYSDEP_FUNC(CopyFileRange, int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t count, unsigned int flags, ssize_t *bytes_copied); +#endif // __MLIBC_LINUX_OPTION + +#if __MLIBC_LINUX_EPOLL_OPTION +SYSDEP_FUNC(EpollCreate, int flags, int *fd); +SYSDEP_FUNC(EpollCtl, int epfd, int mode, int fd, struct epoll_event *ev); +SYSDEP_FUNC(EpollPwait, int epfd, struct epoll_event *ev, int n, int timeout, const sigset_t *sigmask, int *raised); +#endif // __MLIBC_LINUX_EPOLL_OPTION + +#if __MLIBC_LINUX_TIMERFD_OPTION +SYSDEP_FUNC(TimerfdCreate, int clockid, int flags, int *fd); +SYSDEP_FUNC(TimerfdSettime, int fd, int flags, const struct itimerspec *value, struct itimerspec *oldvalue); +SYSDEP_FUNC(TimerfdGettime, int fd, struct itimerspec *its); +#endif // __MLIBC_LINUX_TIMERFD_OPTION + +#if __MLIBC_LINUX_SIGNALFD_OPTION +SYSDEP_FUNC(SignalfdCreate, const sigset_t *, int flags, int *fd); +#endif // __MLIBC_LINUX_SIGNALFD_OPTION + +#if __MLIBC_LINUX_EVENTFD_OPTION +SYSDEP_FUNC(EventfdCreate, unsigned int initval, int flags, int *fd); +#endif // __MLIBC_LINUX_EVENTFD_OPTION + +#if __MLIBC_LINUX_REBOOT_OPTION +SYSDEP_FUNC(Reboot, int cmd); +#endif // __MLIBC_LINUX_REBOOT_OPTION + +#if __MLIBC_LINUX_WRAPPERS_OPTION +SYSDEP_FUNC(RtSigqueueinfo, pid_t tgid, int sig, siginfo_t *uinfo); +SYSDEP_FUNC(RtTgSigqueueinfo, pid_t tgid, pid_t tid, int sig, siginfo_t *uinfo); +#endif // __MLIBC_LINUX_WRAPPERS_OPTION + +#if __MLIBC_BSD_OPTION +SYSDEP_FUNC(Brk, void **out); +SYSDEP_FUNC(GetLoadavg, double *samples); +SYSDEP_FUNC(Openpty, int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win); +#endif // __MLIBC_BSD_OPTION + +#if __MLIBC_GLIBC_OPTION +SYSDEP_FUNC(Personality, unsigned long persona, int *out); +SYSDEP_FUNC(Ioperm, unsigned long int from, unsigned long int num, int turn_on); +SYSDEP_FUNC(Iopl, int level); +#ifdef __riscv +SYSDEP_FUNC(RiscvFlushIcache, void *start, void *end, unsigned long flags); +#endif // __riscv +#endif // __MLIBC_GLIBC_OPTION + +#undef SYSDEP_FUNC +#undef SYSDEP_FUNC_RET +#undef SYSDEP_FUNC_NORETURN + +} // namespace mlibc + +#endif /* MLIBC_SYSDEP_SIGNATURES */ \ No newline at end of file diff --git a/user/include/mlibc/options/internal/include/mlibc/sysdep-tags.hpp b/user/include/mlibc/options/internal/include/mlibc/sysdep-tags.hpp new file mode 100644 index 0000000..fbf1b06 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/sysdep-tags.hpp @@ -0,0 +1,703 @@ +#ifndef MLIBC_SYSDEP_TAGS +#define MLIBC_SYSDEP_TAGS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// [[noreturn]] void sys_exit(int status); +struct Exit { static constexpr bool is_noreturn = true; }; +// [[noreturn]] void sys_thread_exit(); +struct ThreadExit { static constexpr bool is_noreturn = true; }; + +// If *stack is not null, it should point to the lowest addressable byte of the stack. +// Returns the new stack pointer in *stack and the stack base in *stack_base. +// int sys_prepare_stack(void **stack, void *entry, void *user_arg, void* tcb, size_t *stack_size, size_t *guard_size, void **stack_base); +struct PrepareStack {}; + +// int sys_clone(void *tcb, pid_t *pid_out, void *stack); +struct Clone {}; + +// int sys_futex_wait(int *pointer, int expected, const struct timespec *time); +struct FutexWait {}; +// int sys_futex_wake(int *pointer, bool all); +struct FutexWake {}; + +// int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +struct Open {}; +// int sys_flock(int fd, int options); +struct Flock {}; + +// int sys_open_dir(const char *path, int *handle); +struct OpenDir {}; +// int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read); +struct ReadEntries {}; + +// int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); +struct Read {}; + +// int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written); +struct Write {}; +// int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read); +struct Pread {}; + +// int sys_seek(int fd, off_t offset, int whence, off_t *new_offset); +struct Seek {}; +// int sysdep(int fd); +struct Close {}; + +// int sys_clock_get(int clock, time_t *secs, long *nanos); +struct ClockGet {}; +// int sys_clock_set(int clock, time_t secs, long nanos); +struct ClockSet {}; +// int sys_clock_getres(int clock, time_t *secs, long *nanos); +struct ClockGetres {}; +// int sys_sleep(time_t *secs, long *nanos); +struct Sleep {}; +// // In contrast to the isatty() library function, the sysdep function uses return value +// // zero (and not one) to indicate that the file is a terminal. +// int sys_isatty(int fd); +struct Isatty {}; +// int sys_rmdir(const char *path); +struct Rmdir {}; +// int sys_unlinkat(int dirfd, const char *path, int flags); +struct Unlinkat {}; +// int sys_rename(const char *path, const char *new_path); +struct Rename {}; +// int sys_fd_to_path(int fd, char **path); +struct FdToPath {}; + +// int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve); +struct Sigprocmask {}; +// int sys_sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict); +struct Sigaction {}; + +// int sys_fork(pid_t *child); +struct Fork {}; +// int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid); +struct Waitpid {}; +// int sys_execve(const char *path, char *const argv[], char *const envp[]); +struct Execve {}; +// void sys_yield(); +struct Yield {}; + +// pid_t sys_getpid(); +struct GetPid {}; +// int sys_kill(pid_t, int); +struct Kill {}; + +// int sys_tcb_set(void *pointer); +struct TcbSet {}; + +#if MLIBC_BUILDING_RTLD +// int sys_vm_readahead(void *pointer, size_t size); +struct VmReadahead {}; +#endif /* MLIBC_BUILDING_RTLD */ + +// void sys_libc_log(const char *message); +struct LibcLog {}; +// [[noreturn]] void sys_libc_panic(); +struct LibcPanic { static constexpr bool is_noreturn = true; }; + +// int sys_futex_tid(); +struct FutexTid {}; + +// int sys_anon_allocate(size_t size, void **pointer); +struct AnonAllocate {}; +// int sys_anon_free(void *pointer, size_t size); +struct AnonFree {}; + +// int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf); +struct Stat {}; + +// int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window); +struct VmMap {}; +// int sys_vm_unmap(void *pointer, size_t size); +struct VmUnmap {}; +// int sys_vm_protect(void *pointer, size_t size, int prot); +struct VmProtect {}; + +#if defined(__riscv) +#include + +// int sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags); +struct RiscvHwprobe {}; +#endif + +#if __MLIBC_BSD_OPTION +#include + +// int sys_brk(void **out); +struct Brk {}; +// int sys_getloadavg(double *samples); +struct GetLoadavg {}; +// int sys_openpty(int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win); +struct Openpty {}; +#endif // __MLIBC_BSD_OPTION + +#if __MLIBC_GLIBC_OPTION +// int sys_personality(unsigned long persona, int *out); +struct Personality {}; +// int sys_ioperm(unsigned long int from, unsigned long int num, int turn_on); +struct Ioperm {}; +// int sys_iopl(int level); +struct Iopl {}; + +#ifdef __riscv +// int sys_riscv_flush_icache(void *start, void *end, unsigned long flags); +struct RiscvFlushIcache {}; +#endif +#endif // __MLIBC_GLIBC_OPTION + +#if __MLIBC_POSIX_OPTION +#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 + +// int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read); +struct Readv {}; +// int sys_writev(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written); +struct Writev {}; +// int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_read); +struct Pwrite {}; +// int sys_access(const char *path, int mode); +struct Access {}; +// int sys_faccessat(int dirfd, const char *pathname, int mode, int flags); +struct Faccessat {}; +// int sys_dup(int fd, int flags, int *newfd); +struct Dup {}; +// int sys_dup2(int fd, int flags, int newfd); +struct Dup2 {}; +// int sys_statvfs(const char *path, struct statvfs *out); +struct Statvfs {}; +// int sys_fstatvfs(int fd, struct statvfs *out); +struct Fstatvfs {}; +// int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length); +struct Readlink {}; +// int sys_readlinkat(int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length); +struct Readlinkat {}; +// int sys_truncate(const char *path, off_t length); +struct Truncate {}; +// int sys_ftruncate(int fd, size_t size); +struct Ftruncate {}; +// int sys_fallocate(int fd, off_t offset, size_t size); +struct Fallocate {}; +// int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd); +struct Openat {}; +// int sys_socket(int family, int type, int protocol, int *fd); +struct Socket {}; +// int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length); +struct MsgSend {}; +// int sys_sendto(int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length); +struct Sendto {}; +// int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length); +struct MsgRecv {}; +// int sys_recvfrom(int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length); +struct Recvfrom {}; +// int sys_listen(int fd, int backlog); +struct Listen {}; +// gid_t sys_getgid(); +struct GetGid {}; +// gid_t sys_getegid(); +struct GetEgid {}; +// uid_t sys_getuid(); +struct GetUid {}; +// uid_t sys_geteuid(); +struct GetEuid {}; +// pid_t sys_gettid(); +struct GetTid {}; +// pid_t sys_getppid(); +struct GetPpid {}; +// int sys_getpgid(pid_t pid, pid_t *pgid); +struct GetPgid {}; +// int sys_getsid(pid_t pid, pid_t *sid); +struct GetSid {}; +// int sys_setpgid(pid_t pid, pid_t pgid); +struct SetPgid {}; +// int sys_setuid(uid_t uid); +struct SetUid {}; +// int sys_seteuid(uid_t euid); +struct SetEuid {}; +// int sys_setgid(gid_t gid); +struct SetGid {}; +// int sys_setegid(gid_t egid); +struct SetEgid {}; +// int sys_getgroups(size_t size, gid_t *list, int *ret); +struct GetGroups {}; +// int sys_fexecve(int fd, char *const argv[], char *const envp[]); +struct Fexecve {}; +// int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events); +struct Pselect {}; +// int sys_getrusage(int scope, struct rusage *usage); +struct GetRusage {}; +// int sys_getrlimit(int resource, struct rlimit *limit); +struct GetRlimit {}; +// int sys_setrlimit(int resource, const struct rlimit *limit); +struct SetRlimit {}; +// int sys_getpriority(int which, id_t who, int *value); +struct GetPriority {}; +// int sys_setpriority(int which, id_t who, int prio); +struct SetPriority {}; +// int sys_getschedparam(void *tcb, int *policy, struct sched_param *param); +struct GetSchedparam {}; +// int sys_setschedparam(void *tcb, int policy, const struct sched_param *param); +struct SetSchedparam {}; +// int sys_getscheduler(pid_t pid, int *policy); +struct GetScheduler {}; +// int sys_setscheduler(pid_t pid, int policy, const struct sched_param *param); +struct SetScheduler {}; +// int sys_getparam(pid_t pid, struct sched_param *param); +struct GetParam {}; +// int sys_setparam(pid_t pid, const struct sched_param *param); +struct SetParam {}; +// int sys_get_max_priority(int policy, int *out); +struct GetMaxPriority {}; +// int sys_get_min_priority(int policy, int *out); +struct GetMinPriority {}; +// int sys_getcwd(char *buffer, size_t size); +struct GetCwd {}; +// int sys_chdir(const char *path); +struct Chdir {}; +// int sys_fchdir(int fd); +struct Fchdir {}; +// int sys_chroot(const char *path); +struct Chroot {}; +// int sys_mkdir(const char *path, mode_t mode); +struct Mkdir {}; +// int sys_mkdirat(int dirfd, const char *path, mode_t mode); +struct Mkdirat {}; +// int sys_link(const char *old_path, const char *new_path); +struct Link {}; +// int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags); +struct Linkat {}; +// int sys_symlink(const char *target_path, const char *link_path); +struct Symlink {}; +// int sys_symlinkat(const char *target_path, int dirfd, const char *link_path); +struct Symlinkat {}; +// int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path); +struct Renameat {}; +// int sys_fcntl(int fd, int request, va_list args, int *result); +struct Fcntl {}; +// int sys_ttyname(int fd, char *buf, size_t size); +struct Ttyname {}; +// int sys_fadvise(int fd, off_t offset, off_t length, int advice); +struct Fadvise {}; +// void sys_sync(); +struct Sync {}; +// int sys_fsync(int fd); +struct Fsync {}; +// int sys_fdatasync(int fd); +struct Fdatasync {}; +// int sys_chmod(const char *pathname, mode_t mode); +struct Chmod {}; +// int sys_fchmod(int fd, mode_t mode); +struct Fchmod {}; +// int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags); +struct Fchmodat {}; +// int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags); +struct Utimensat {}; +// int sys_mlock(const void *addr, size_t length); +struct Mlock {}; +// int sys_munlock(const void *addr, size_t length); +struct Munlock {}; +// int sys_mlockall(int flags); +struct Mlockall {}; +// int sys_munlockall(void); +struct Munlockall {}; +// int sys_mincore(void *addr, size_t length, unsigned char *vec); +struct Mincore {}; +// int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window); +struct VmRemap {}; +// int sys_setsid(pid_t *sid); +struct SetSid {}; +// int sys_tcgetattr(int fd, struct termios *attr); +struct Tcgetattr {}; +// int sys_tcsetattr(int, int, const struct termios *attr); +struct Tcsetattr {}; +// int sys_tcsendbreak(int fd, int dur); +struct Tcsendbreak {}; +// int sys_tcflow(int, int); +struct Tcflow {}; +// int sys_tcflush(int fd, int queue); +struct Tcflush {}; +// int sys_tcdrain(int); +struct Tcdrain {}; +// int sys_tcgetwinsize(int fd, struct winsize *winsz); +struct Tcgetwinsize {}; +// int sys_tcsetwinsize(int fd, const struct winsize *winsz); +struct Tcsetwinsize {}; +// int sys_pipe(int *fds, int flags); +struct Pipe {}; +// int sys_socketpair(int domain, int type_and_flags, int proto, int *fds); +struct Socketpair {}; +// int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events); +struct Poll {}; +// int sys_ppoll(struct pollfd *fds, nfds_t count, const struct timespec *ts, const sigset_t *mask, int *num_events); +struct Ppoll {}; +// int sys_ioctl(int fd, unsigned long request, void *arg, int *result); +struct Ioctl {}; +// int sys_posix_devctl(int fd, int dcmd, void *__restrict dev_data_ptr, size_t nbyte, int *__restrict dev_info_ptr); +struct PosixDevctl {}; +// int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size); +struct GetSockopt {}; +// int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size); +struct SetSockopt {}; +// int sys_shutdown(int sockfd, int how); +struct Shutdown {}; +// int sys_sockatmark(int sockfd, int *out); +struct Sockatmark {}; +// int sys_thread_sigmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve); +struct ThreadSigmask {}; +// NOTE: POSIX says that behavior of timeout = nullptr is unspecified. We treat this case +// as an infinite timeout, making sigtimedwait(..., nullptr) equivalent to sigwaitinfo(...) +// int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal); +struct Sigtimedwait {}; +// int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags); +struct Accept {}; +// int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length); +struct Bind {}; +// int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length); +struct Connect {}; +// int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length); +struct Sockname {}; +// int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length); +struct Peername {}; +// int sys_gethostname(char *buffer, size_t bufsize); +struct GetHostname {}; +// int sys_sethostname(const char *buffer, size_t bufsize); +struct SetHostname {}; +// int sys_mkfifoat(int dirfd, const char *path, mode_t mode); +struct Mkfifoat {}; +// int sys_getentropy(void *buffer, size_t length); +struct GetEntropy {}; +// int sys_mknodat(int dirfd, const char *path, int mode, int dev); +struct Mknodat {}; +// int sys_umask(mode_t mode, mode_t *old); +struct Umask {}; +// int sys_before_cancellable_syscall(ucontext_t *uctx); +struct BeforeCancellableSyscall {}; +// int sys_tgkill(int tgid, int tid, int sig); +struct Tgkill {}; +// int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags); +struct Fchownat {}; +// int sys_sigaltstack(const stack_t *ss, stack_t *oss); +struct Sigaltstack {}; +// int sys_sigsuspend(const sigset_t *set); +struct Sigsuspend {}; +// int sys_sigpending(sigset_t *set); +struct Sigpending {}; +// int sys_sigqueue(pid_t pid, int sig, const union sigval val); +struct Sigqueue {}; +// int sys_setgroups(size_t size, const gid_t *list); +struct SetGroups {}; +// int sys_memfd_create(const char *name, int flags, int *fd); +struct MemfdCreate {}; +// int sys_madvise(void *addr, size_t length, int advice); +struct Madvise {}; +// int sys_posix_madvise(void *addr, size_t length, int advice); +struct PosixMadvise {}; +// int sys_msync(void *addr, size_t length, int flags); +struct Msync {}; +// int sys_getitimer(int which, struct itimerval *curr_value); +struct GetItimer {}; +// int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value); +struct SetItimer {}; +// int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res); +struct TimerCreate {}; +// int sys_timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old); +struct TimerSettime {}; +// int sys_timer_gettime(timer_t t, struct itimerspec *val); +struct TimerGettime {}; +// int sys_timer_delete(timer_t t); +struct TimerDelete {}; +// int sys_timer_getoverrun(timer_t t, int *out); +struct TimerGetoverrun {}; +// int sys_times(struct tms *tms, clock_t *out); +struct Times {}; +// int sys_uname(struct utsname *buf); +struct Uname {}; +// int sys_pause(); +struct Pause {}; +// int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); +struct SetResuid {}; +// int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); +struct SetResgid {}; +// int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +struct GetResuid {}; +// int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +struct GetResgid {}; +// int sys_setreuid(uid_t ruid, uid_t euid); +struct SetReuid {}; +// int sys_setregid(gid_t rgid, gid_t egid); +struct SetRegid {}; +// int sys_getlogin_r(char *name, size_t name_len); +struct GetLoginR {}; +// int sys_if_indextoname(unsigned int index, char *name); +struct IfIndextoname {}; +// int sys_if_nametoindex(const char *name, unsigned int *ret); +struct IfNametoindex {}; +// int sys_ptsname(int fd, char *buffer, size_t length); +struct Ptsname {}; +// int sys_unlockpt(int fd); +struct Unlockpt {}; +// int sys_thread_setname(void *tcb, const char *name); +struct ThreadSetname {}; +// int sys_thread_getname(void *tcb, char *name, size_t size); +struct ThreadGetname {}; +// int sys_sysconf(int num, long *ret); +struct Sysconf {}; +// int sys_semget(key_t key, int n, int fl, int *id); +struct Semget {}; +// int sys_semctl(int semid, int semnum, int cmd, void *semun, int *ret); +struct Semctl {}; +// int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); +struct GetAffinity {}; +// int sys_getthreadaffinity(pid_t tid, size_t cpusetsize, cpu_set_t *mask); +struct GetThreadaffinity {}; +// int sys_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask); +struct SetAffinity {}; +// int sys_setthreadaffinity(pid_t tid, size_t cpusetsize, const cpu_set_t *mask); +struct SetThreadaffinity {}; +// int sys_get_current_stack_info(void **stack_base, size_t *stack_size); +struct GetCurrentStackInfo {}; +// int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options); +struct Waitid {}; +// int sys_name_to_handle_at(int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags); +struct NameToHandleAt {}; +// int sys_splice(int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags, ssize_t *out); +struct Splice {}; +// int sys_shmat(void **seg_start, int shmid, const void *shmaddr, int shmflg); +struct Shmat {}; +// int sys_shmctl(int *idx, int shmid, int cmd, struct shmid_ds *buf); +struct Shmctl {}; +// int sys_shmdt(const void *shmaddr); +struct Shmdt {}; +// int sys_shmget(int *shm_id, key_t key, size_t size, int shmflg); +struct Shmget {}; +// int sys_inet_configured(bool *ipv4, bool *ipv6); +struct InetConfigured {}; +// int sys_nice(int nice, int *new_nice); +struct Nice {}; +// int sys_openpt(int oflags, int *fd); +struct Openpt {}; +// int sys_msgctl(int q, int cmd, struct msqid_ds *buf); +struct Msgctl {}; +// int sys_msgget(key_t k, int flag, int *out); +struct Msgget {}; +// int sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg, ssize_t *out); +struct Msgrcv {}; +// int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); +struct Msgsnd {}; +// int sys_mq_open(const char *name, int oflag, mode_t mode, mq_attr *attr, mqd_t *out); +struct MqOpen {}; +// int sys_mq_unlink(const char *name); +struct MqUnlink {}; +// int sys_mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); +struct MqReceive {}; +// int sys_mq_get_attr(mqd_t mqdes, mq_attr *mqstat); +struct MqGetAttr {}; +// int sys_mq_set_attr(mqd_t mqdes, mq_attr *mqstat, mq_attr *omqstat); +struct MqSetAttr {}; +#endif // __MLIBC_POSIX_OPTION + +#if __MLIBC_LINUX_OPTION +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// int sys_inotify_create(int flags, int *fd); +struct InotifyCreate {}; +// int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd); +struct InotifyAddWatch {}; +// int sys_inotify_rm_watch(int ifd, int wd); +struct InotifyRmWatch {}; +// int sys_mount(const char *source, const char *target, const char *fstype, unsigned long flags, const void *data); +struct Mount {}; +// int sys_umount2(const char *target, int flags); +struct Umount2 {}; +// int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out); +struct Ptrace {}; +// int sys_capget(cap_user_header_t hdrp, cap_user_data_t datap); +struct Capget {}; +// int sys_capset(cap_user_header_t hdrp, const cap_user_data_t datap); +struct Capset {}; +// int sys_prctl(int option, va_list va, int *out); +struct Prctl {}; +// int sys_init_module(void *module, unsigned long length, const char *args); +struct InitModule {}; +// int sys_delete_module(const char *name, unsigned flags); +struct DeleteModule {}; +// int sys_klogctl(int type, char *bufp, int len, int *out); +struct Klogctl {}; +// int sys_getcpu(int *cpu); +struct Getcpu {}; +// int sys_sysinfo(struct sysinfo *info); +struct Sysinfo {}; +// int sys_swapon(const char *path, int flags); +struct Swapon {}; +// int sys_swapoff(const char *path); +struct Swapoff {}; +// int sys_setxattr(const char *path, const char *name, const void *val, size_t size, int flags); +struct Setxattr {}; +// int sys_lsetxattr(const char *path, const char *name, const void *val, size_t size, int flags); +struct Lsetxattr {}; +// int sys_fsetxattr(int fd, const char *name, const void *val, size_t size, int flags); +struct Fsetxattr {}; +// int sys_getxattr(const char *path, const char *name, void *val, size_t size, ssize_t *nread); +struct Getxattr {}; +// int sys_lgetxattr(const char *path, const char *name, void *val, size_t size, ssize_t *nread); +struct Lgetxattr {}; +// int sys_fgetxattr(int fd, const char *name, void *val, size_t size, ssize_t *nread); +struct Fgetxattr {}; +// int sys_listxattr(const char *path, char *list, size_t size, ssize_t *nread); +struct Listxattr {}; +// int sys_llistxattr(const char *path, char *list, size_t size, ssize_t *nread); +struct Llistxattr {}; +// int sys_flistxattr(int fd, char *list, size_t size, ssize_t *nread); +struct Flistxattr {}; +// int sys_removexattr(const char *path, const char *name); +struct Removexattr {}; +// int sys_lremovexattr(const char *path, const char *name); +struct Lremovexattr {}; +// int sys_fremovexattr(int fd, const char *name); +struct Fremovexattr {}; +// int sys_statfs(const char *path, struct statfs *buf); +struct Statfs {}; +// int sys_fstatfs(int fd, struct statfs *buf); +struct Fstatfs {}; +// int sys_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf); +struct Statx {}; +// int sys_getifaddrs(struct ifaddrs **); +struct Getifaddrs {}; +// int sys_sendfile(int outfd, int infd, off_t *offset, size_t count, ssize_t *out); +struct Sendfile {}; +// int sys_syncfs(int fd); +struct Syncfs {}; +// int sys_unshare(int flags); +struct Unshare {}; +// int sys_setns(int fd, int nstype); +struct SetNs {}; +// int sys_pidfd_open(pid_t pid, unsigned int flags, int *outfd); +struct PidfdOpen {}; +// int sys_pidfd_getpid(int fd, pid_t *outpid); +struct PidfdGetpid {}; +// int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags); +struct PidfdSendSignal {}; +// int sys_process_vm_readv(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags, ssize_t *out); +struct ProcessVmReadv {}; +// int sys_process_vm_writev(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags, ssize_t *out); +struct ProcessVmWritev {}; +// int sys_fsopen(const char *fsname, unsigned int flags, int *outfd); +struct Fsopen {}; +// int sys_fsmount(int fsfd, unsigned int flags, unsigned int mountflags, int *outfd); +struct Fsmount {}; +// int sys_fsconfig(int fd, unsigned int cmd, const char *key, const void *val, int aux); +struct Fsconfig {}; +// int sys_move_mount(int from_dirfd, const char *from_path, int to_dirfd, const char *to_path, unsigned int flags); +struct MoveMount {}; +// int sys_open_tree(int dirfd, const char *path, unsigned int flags, int *outfd); +struct OpenTree {}; +// int sys_copy_file_range(int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t count, unsigned int flags, ssize_t *bytes_copied); +struct CopyFileRange {}; +#endif // __MLIBC_LINUX_OPTION + +#if __MLIBC_LINUX_EPOLL_OPTION +#include + +// int sys_epoll_create(int flags, int *fd); +struct EpollCreate {}; +// int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev); +struct EpollCtl {}; +// int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, const sigset_t *sigmask, int *raised); +struct EpollPwait {}; +#endif // __MLIBC_LINUX_EPOLL_OPTION + +#if __MLIBC_LINUX_TIMERFD_OPTION +#include + +// int sys_timerfd_create(int clockid, int flags, int *fd); +struct TimerfdCreate {}; +// int sys_timerfd_settime(int fd, int flags, const struct itimerspec *value, struct itimerspec *oldvalue); +struct TimerfdSettime {}; +// int sys_timerfd_gettime(int fd, struct itimerspec *its); +struct TimerfdGettime {}; +#endif // __MLIBC_LINUX_TIMERFD_OPTION + +#if __MLIBC_LINUX_SIGNALFD_OPTION +#include + +// int sys_signalfd_create(const sigset_t *, int flags, int *fd); +struct SignalfdCreate {}; +#endif // __MLIBC_LINUX_SIGNALFD_OPTION + +#if __MLIBC_LINUX_EVENTFD_OPTION +#include + +// int sys_eventfd_create(unsigned int initval, int flags, int *fd); +struct EventfdCreate {}; +#endif // __MLIBC_LINUX_EVENTFD_OPTION + +#if __MLIBC_LINUX_REBOOT_OPTION +#include + +// int sys_reboot(int cmd); +struct Reboot {}; +#endif // __MLIBC_LINUX_REBOOT_OPTION + +#if __MLIBC_LINUX_WRAPPERS_OPTION +// int sys_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *uinfo); +struct RtSigqueueinfo {}; +// int sys_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *uinfo); +struct RtTgSigqueueinfo {}; +#endif // __MLIBC_LINUX_WRAPPERS_OPTION + +#endif /* MLIBC_SYSDEP_TAGS */ \ No newline at end of file diff --git a/user/include/mlibc/options/internal/include/mlibc/tcb.hpp b/user/include/mlibc/options/internal/include/mlibc/tcb.hpp new file mode 100644 index 0000000..90cfab6 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/tcb.hpp @@ -0,0 +1,189 @@ +#pragma once + +#include +#include +#include +#include + +#include "elf.hpp" + +/* + * Explanation of cancellation bits: + * + * tcbCancelEnableBit and tcbCancelAsyncBit should be self-explanatory, + * they are set if cancellation is enabled, or asynchronous, respectively. + * + * tcbCancelTriggerBit is set whenever a cancellation is triggered, which is + * in pthread_cancel() or in the signal handler. This bit is used by + * pthread_testcancel() to check whether a cancellation has been requested, + * and also by cancellable syscalls. + * + * tcbCancelingBit is set when a cancellation is currently being handled. This + * is to avoid a situation in which a cancellation handler gets interrupted by + * a SIGCANCEL and a second cancellation handler gets executed on top of the + * previous one. Right now this cannot happen, since we stay in signal handler + * context when canceling/exiting. In the future this might be done outside + * of a signal handler, in which case we shouldn't restart the cancellation process. + * + * tcbExitingBit is set when the thread starts the exit procedure. Currently + * this is just an exit, but in the future this will be a stack unwinding + * procedure, which shouldn't be reentered. Not currently set anywhere, + * may be done so in the future. + * + * TODO(geert): update this comment when we do unwinding in the exit procedure. + */ + +namespace { + // Set when the cancellation is enabled + constexpr unsigned int tcbCancelEnableBit = 1 << 0; + // 1 - cancellation is asynchronous, 0 - cancellation is deferred + constexpr unsigned int tcbCancelAsyncBit = 1 << 1; + // Set when the thread has been cancelled + constexpr unsigned int tcbCancelTriggerBit = 1 << 2; + // Set when the thread is in the process of being cancelled. + constexpr unsigned int tcbCancelingBit = 1 << 3; + // Set when the thread is exiting. + constexpr unsigned int tcbExitingBit = 1 << 4; +} + +namespace mlibc { + // Returns true when bitmask indicates thread has been asynchronously + // cancelled. + static constexpr bool tcb_async_cancelled(int value) { + return (value & (tcbCancelEnableBit | tcbCancelAsyncBit + | tcbCancelTriggerBit)) == (tcbCancelEnableBit + | tcbCancelAsyncBit | tcbCancelTriggerBit); + } + + // Returns true when bitmask indicates async cancellation is enabled. + static constexpr bool tcb_async_cancel(int value) { + return (value & (tcbCancelEnableBit | tcbCancelAsyncBit)) + == (tcbCancelEnableBit | tcbCancelAsyncBit); + } + + // Returns true when bitmask indicates cancellation is enabled. + static constexpr bool tcb_cancel_enabled(int value) { + return (value & tcbCancelEnableBit); + } + + // Returns true when bitmask indicates threas has been cancelled. + static constexpr bool tcb_cancelled(int value) { + return (value & (tcbCancelEnableBit | tcbCancelTriggerBit)) + == (tcbCancelEnableBit | tcbCancelTriggerBit); + } + +#if !MLIBC_STATIC_BUILD && !MLIBC_BUILDING_RTLD + // In non-static builds, libc.so always has a TCB available. + constexpr bool tcb_available_flag = true; +#else + // Otherwise this will be set to true after RTLD has initialized the TCB. + extern bool tcb_available_flag; +#endif +} + +enum class TcbThreadReturnValue { + Pointer, + Integer, +}; + +struct Tcb { + Tcb *selfPointer; + size_t dtvSize; + void **dtvPointers; + int tid; + int didExit; +#if defined(__x86_64__) + uint8_t padding[8]; +#endif + uintptr_t stackCanary; + int cancelBits; + + union { + void *voidPtr; + int intVal; + } returnValue; + TcbThreadReturnValue returnValueType; + + struct AtforkHandler { + void (*prepare)(void); + void (*parent)(void); + void (*child)(void); + + AtforkHandler *next; + AtforkHandler *prev; + }; + + AtforkHandler *atforkBegin; + AtforkHandler *atforkEnd; + + struct CleanupHandler { + void (*func)(void *); + void *arg; + + CleanupHandler *next; + CleanupHandler *prev; + }; + + CleanupHandler *cleanupBegin; + CleanupHandler *cleanupEnd; + int isJoinable; + + struct LocalKey { + void *value; + uint64_t generation; + }; + frg::array *localKeys; + + size_t stackSize; + void *stackAddr; + size_t guardSize; + + inline void invokeThreadFunc(void *entry, void *user_arg) { + if(returnValueType == TcbThreadReturnValue::Pointer) { + auto func = reinterpret_cast(entry); + returnValue.voidPtr = func(user_arg); + } else { + auto func = reinterpret_cast(entry); + returnValue.intVal = func(user_arg); + } + } +}; + +// There are a few places where we assume the layout of the TCB: +#if defined(__x86_64__) +// GCC expects the stack canary to be at fs:0x28. +static_assert(offsetof(Tcb, stackCanary) == 0x28); +// sysdeps/linux/x86_64/cp_syscall.S uses the offset of cancelBits. +static_assert(offsetof(Tcb, cancelBits) == 0x30); +// options/linker/x86_64/runtime.S uses the offset of dtvPointers. +static_assert(offsetof(Tcb, dtvPointers) == 16); +#elif defined(__i386__) +// GCC expects the stack canary to be at gs:0x14. +// The offset differs from x86_64 due to the change in the pointer size +// and removed padding before the stack canary. +static_assert(offsetof(Tcb, stackCanary) == 0x14); +// sysdeps/linux/x86/cp_syscall.S uses the offset of cancelBits. +// It differs from x86_64 for the same reasons as the stack canary. +static_assert(offsetof(Tcb, cancelBits) == 0x18); +#elif defined(__aarch64__) +// The thread pointer on AArch64 points to 16 bytes before the end of the TCB. +// options/linker/aarch64/runtime.S uses the offset of dtvPointers. +static_assert(sizeof(Tcb) - offsetof(Tcb, dtvPointers) - TP_TCB_OFFSET == 104); +// sysdeps/linux/aarch64/cp_syscall.S uses the offset of cancelBits. +static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) - TP_TCB_OFFSET == 80); +#elif defined(__riscv) && __riscv_xlen == 64 +// The thread pointer on RISC-V points to *after* the TCB, and since +// we need to access specific fields that means that the value in +// sysdeps/linux/riscv64/cp_syscall.S needs to be updated whenever +// the struct is expanded. +static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) == 96); +#elif defined (__m68k__) +// The thread pointer on m68k points to 0x7000 bytes *after* the end of the +// TCB, so similarly to as on RISC-V, we need to keep the value in +// sysdeps/linux/m68k/cp_syscall.S up-to-date. +static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) == 0x30); +#elif defined(__loongarch64) +static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) == 96); +#else +#error "Missing architecture specific code." +#endif diff --git a/user/include/mlibc/options/internal/include/mlibc/threads.hpp b/user/include/mlibc/options/internal/include/mlibc/threads.hpp new file mode 100644 index 0000000..989a8e5 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/threads.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace mlibc { + +int thread_create(struct __mlibc_thread_data **__restrict thread, const struct __mlibc_threadattr *__restrict attrp, void *entry, void *__restrict user_arg, bool returns_int); +int thread_attr_init(struct __mlibc_threadattr *attr); +int thread_join(struct __mlibc_thread_data *thread, void *res); + +int thread_mutex_init(struct __mlibc_mutex *__restrict mutex, const struct __mlibc_mutexattr *__restrict attr); +int thread_mutex_destroy(struct __mlibc_mutex *mutex); +int thread_mutex_lock(struct __mlibc_mutex *mutex); +int thread_mutex_unlock(struct __mlibc_mutex *mutex); + +int thread_mutexattr_init(struct __mlibc_mutexattr *attr); +int thread_mutexattr_destroy(struct __mlibc_mutexattr *attr); +int thread_mutexattr_gettype(const struct __mlibc_mutexattr *__restrict attr, int *__restrict type); +int thread_mutexattr_settype(struct __mlibc_mutexattr *attr, int type); + +int thread_cond_init(struct __mlibc_cond *__restrict cond, const struct __mlibc_condattr *__restrict attr); +int thread_cond_destroy(struct __mlibc_cond *cond); +int thread_cond_broadcast(struct __mlibc_cond *cond); +int thread_cond_timedwait(struct __mlibc_cond *__restrict cond, __mlibc_mutex *__restrict mutex, const struct timespec *__restrict abstime); + +} diff --git a/user/include/mlibc/options/internal/include/mlibc/tid.hpp b/user/include/mlibc/options/internal/include/mlibc/tid.hpp new file mode 100644 index 0000000..9cae787 --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/tid.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +namespace mlibc { + inline unsigned int this_tid() { + // During RTLD initialization, we don't have a TCB. + if (mlibc::tcb_available_flag) { + auto tcb = get_current_tcb(); + return tcb->tid; + } else if (mlibc::sys_futex_tid) { + return mlibc::sys_futex_tid(); + } else { + return 1; + } + } +} diff --git a/user/include/mlibc/options/internal/include/mlibc/utmp.hpp b/user/include/mlibc/options/internal/include/mlibc/utmp.hpp new file mode 100644 index 0000000..27d8d3e --- /dev/null +++ b/user/include/mlibc/options/internal/include/mlibc/utmp.hpp @@ -0,0 +1,115 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +template +concept UtmpStruct = requires(S s) { + std::is_same_v; + std::is_same_v; + std::is_same_v; + std::is_same_v; + std::is_same_v; + std::is_same_v; +}; + +template +int getUtmpEntry(int fd, U *res) { + ssize_t progress = 0; + ssize_t read = 0; + char *ptr = reinterpret_cast(res); + + int err = mlibc::sys_read(fd, ptr, sizeof(U), &read); + if(err) + return err; + + if(read == sizeof(U)) + return 0; + else if(read == 0) + return ESRCH; + + progress = read; + + while(read) { + err = mlibc::sys_read(fd, ptr + progress, sizeof(U) - progress, &read); + if(err) + return err; + + progress += read; + + if(progress == sizeof(U)) + return 0; + } + + return ESRCH; +} + +template +int getUtmpEntryById(int fd, const U *id, U *res) { + while(true) { + U tmp; + if(int e = getUtmpEntry(fd, &tmp); e) + return e; + + if(id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME + || id->ut_type == NEW_TIME || id->ut_type == OLD_TIME) { + if(tmp.ut_type == id->ut_type) { + memcpy(res, &tmp, sizeof(U)); + return 0; + } + } else if(id->ut_type == INIT_PROCESS || id->ut_type == LOGIN_PROCESS + || id->ut_type == USER_PROCESS || id->ut_type == DEAD_PROCESS) { + if(!memcmp(tmp.ut_id, id->ut_id, sizeof(U::ut_id))) { + memcpy(res, &tmp, sizeof(U)); + return 0; + } + } + } +} + +template +int getUtmpEntryByType(int fd, const U *id, U *res) { + while(true) { + U tmp; + if(int e = getUtmpEntry(fd, &tmp); e) + return e; + + if(id->ut_type == USER_PROCESS || id->ut_type == LOGIN_PROCESS) { + if(!strncmp(tmp.ut_line, id->ut_line, sizeof(U::ut_line))) { + memcpy(res, &tmp, sizeof(U)); + return 0; + } + } + } +} + +template +int putUtmpEntry(int fd, const U *ut) { + size_t progress = 0; + char *ptr = (char *) ut; + + off_t discard; + if(int e = mlibc::sys_seek(fd, 0, SEEK_END, &discard); e) + return e; + + while(progress < sizeof(U)) { + ssize_t written = 0; + if(int e = mlibc::sys_write(fd, ptr + progress, sizeof(U) - progress, &written); e) + return e; + progress += written; + } + + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/include/stdint.h b/user/include/mlibc/options/internal/include/stdint.h new file mode 100644 index 0000000..36ec413 --- /dev/null +++ b/user/include/mlibc/options/internal/include/stdint.h @@ -0,0 +1,150 @@ +#ifndef _MLIBC_STDINT_H +#define _MLIBC_STDINT_H + +#include +#include + +/* ---------------------------------------------------------------------------- */ +/* Type definitions. */ +/* ---------------------------------------------------------------------------- */ + +/* Fixed-width (signed). */ +typedef __mlibc_int8 int8_t; +typedef __mlibc_int16 int16_t; +typedef __mlibc_int32 int32_t; +typedef __mlibc_int64 int64_t; + +/* Fixed-width (unsigned). */ +typedef __mlibc_uint8 uint8_t; +typedef __mlibc_uint16 uint16_t; +typedef __mlibc_uint32 uint32_t; +typedef __mlibc_uint64 uint64_t; + +/* Least-width (signed). */ +typedef __mlibc_int8 int_least8_t; +typedef __mlibc_int16 int_least16_t; +typedef __mlibc_int32 int_least32_t; +typedef __mlibc_int64 int_least64_t; + +/* Least-width (unsigned). */ +typedef __mlibc_uint8 uint_least8_t; +typedef __mlibc_uint16 uint_least16_t; +typedef __mlibc_uint32 uint_least32_t; +typedef __mlibc_uint64 uint_least64_t; + +/* Fast-width (signed). */ +typedef __mlibc_int_fast8 int_fast8_t; +typedef __mlibc_int_fast16 int_fast16_t; +typedef __mlibc_int_fast32 int_fast32_t; +typedef __mlibc_int_fast64 int_fast64_t; + +/* Fast-width (unsigned). */ +typedef __mlibc_uint_fast8 uint_fast8_t; +typedef __mlibc_uint_fast16 uint_fast16_t; +typedef __mlibc_uint_fast32 uint_fast32_t; +typedef __mlibc_uint_fast64 uint_fast64_t; + +/* Miscellaneous (signed). */ +typedef __mlibc_intmax intmax_t; +typedef __mlibc_intptr intptr_t; + +/* Miscellaneous (unsigned). */ +typedef __mlibc_uintmax uintmax_t; +typedef __mlibc_uintptr uintptr_t; + +/* ---------------------------------------------------------------------------- */ +/* Constants. */ +/* ---------------------------------------------------------------------------- */ + +/* Fixed-width (signed). */ +#define INT8_C(x) __MLIBC_INT8_C(x) +#define INT16_C(x) __MLIBC_INT16_C(x) +#define INT32_C(x) __MLIBC_INT32_C(x) +#define INT64_C(x) __MLIBC_INT64_C(x) +#define INTMAX_C(x) __MLIBC_INTMAX_C(x) + +/* Fixed-width (unsigned). */ +#define UINT8_C(x) __MLIBC_UINT8_C(x) +#define UINT16_C(x) __MLIBC_UINT16_C(x) +#define UINT32_C(x) __MLIBC_UINT32_C(x) +#define UINT64_C(x) __MLIBC_UINT64_C(x) +#define UINTMAX_C(x) __MLIBC_UINTMAX_C(x) + +/* ---------------------------------------------------------------------------- */ +/* Limits. */ +/* ---------------------------------------------------------------------------- */ + +/* Fixed-width (signed). */ +#define INT8_MAX __MLIBC_INT8_MAX +#define INT16_MAX __MLIBC_INT16_MAX +#define INT32_MAX __MLIBC_INT32_MAX +#define INT64_MAX __MLIBC_INT64_MAX + +#define INT8_MIN __MLIBC_INT8_MIN +#define INT16_MIN __MLIBC_INT16_MIN +#define INT32_MIN __MLIBC_INT32_MIN +#define INT64_MIN __MLIBC_INT64_MIN + +/* Fixed-width (unsigned). */ +#define UINT8_MAX __MLIBC_UINT8_MAX +#define UINT16_MAX __MLIBC_UINT16_MAX +#define UINT32_MAX __MLIBC_UINT32_MAX +#define UINT64_MAX __MLIBC_UINT64_MAX + +/* Least-width (signed). */ +#define INT_LEAST8_MAX __MLIBC_INT8_MAX +#define INT_LEAST16_MAX __MLIBC_INT16_MAX +#define INT_LEAST32_MAX __MLIBC_INT32_MAX +#define INT_LEAST64_MAX __MLIBC_INT64_MAX + +#define INT_LEAST8_MIN __MLIBC_INT8_MIN +#define INT_LEAST16_MIN __MLIBC_INT16_MIN +#define INT_LEAST32_MIN __MLIBC_INT32_MIN +#define INT_LEAST64_MIN __MLIBC_INT64_MIN + +/* Least-width (unsigned). */ +#define UINT_LEAST8_MAX __MLIBC_UINT8_MAX +#define UINT_LEAST16_MAX __MLIBC_UINT16_MAX +#define UINT_LEAST32_MAX __MLIBC_UINT32_MAX +#define UINT_LEAST64_MAX __MLIBC_UINT64_MAX + +/* Fast-width (signed). */ +#define INT_FAST8_MAX __MLIBC_INT_FAST8_MAX +#define INT_FAST16_MAX __MLIBC_INT_FAST16_MAX +#define INT_FAST32_MAX __MLIBC_INT_FAST32_MAX +#define INT_FAST64_MAX __MLIBC_INT_FAST64_MAX + +#define INT_FAST8_MIN __MLIBC_INT_FAST8_MIN +#define INT_FAST16_MIN __MLIBC_INT_FAST16_MIN +#define INT_FAST32_MIN __MLIBC_INT_FAST32_MIN +#define INT_FAST64_MIN __MLIBC_INT_FAST64_MIN + +/* Fast-width (unsigned). */ +#define UINT_FAST8_MAX __MLIBC_UINT_FAST8_MAX +#define UINT_FAST16_MAX __MLIBC_UINT_FAST16_MAX +#define UINT_FAST32_MAX __MLIBC_UINT_FAST32_MAX +#define UINT_FAST64_MAX __MLIBC_UINT_FAST64_MAX + +/* Miscellaneous (signed). */ +#define INTMAX_MAX __MLIBC_INTMAX_MAX +#define INTPTR_MAX __MLIBC_INTPTR_MAX + +#define INTMAX_MIN __MLIBC_INTMAX_MIN +#define INTPTR_MIN __MLIBC_INTPTR_MIN + +/* Miscellaneous (unsigned). */ +#define UINTMAX_MAX __MLIBC_UINTMAX_MAX +#define UINTPTR_MAX __MLIBC_UINTPTR_MAX + +/* Other limits (signed). */ +#define PTRDIFF_MAX __MLIBC_PTRDIFF_MAX +#define PTRDIFF_MIN __MLIBC_PTRDIFF_MIN +#define SIG_ATOMIC_MAX __MLIBC_SIG_ATOMIC_MAX +#define SIG_ATOMIC_MIN __MLIBC_SIG_ATOMIC_MIN +#define WINT_MAX __MLIBC_WINT_MAX +#define WINT_MIN __MLIBC_WINT_MIN + +/* Other limits (unsigned). */ +#define SIZE_MAX __MLIBC_SIZE_MAX + +#endif /* _MLIBC_STDINT_H */ diff --git a/user/include/mlibc/options/internal/loongarch64-include/mlibc/arch-defs.hpp b/user/include/mlibc/options/internal/loongarch64-include/mlibc/arch-defs.hpp new file mode 100644 index 0000000..0a4789f --- /dev/null +++ b/user/include/mlibc/options/internal/loongarch64-include/mlibc/arch-defs.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP diff --git a/user/include/mlibc/options/internal/loongarch64-include/mlibc/thread.hpp b/user/include/mlibc/options/internal/loongarch64-include/mlibc/thread.hpp new file mode 100644 index 0000000..76f66fd --- /dev/null +++ b/user/include/mlibc/options/internal/loongarch64-include/mlibc/thread.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + // On LoongArch, the TCB is below the thread pointer. + uintptr_t tp = (uintptr_t)__builtin_thread_pointer(); + auto tcb = reinterpret_cast(tp - sizeof(Tcb)); + __ensure(tcb == tcb->selfPointer); + return tcb; +} + +inline uintptr_t get_sp() { + uintptr_t sp; + asm volatile ("move %0, $sp" : "=r"(sp)); + return sp; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/loongarch64/fenv.S b/user/include/mlibc/options/internal/loongarch64/fenv.S new file mode 100644 index 0000000..e37a1cc --- /dev/null +++ b/user/include/mlibc/options/internal/loongarch64/fenv.S @@ -0,0 +1,67 @@ +.global feclearexcept +.type feclearexcept, %function +feclearexcept: + li.w $t0, 0x1f0000 + and $a0, $a0, $t0 + movfcsr2gr $t1, $fcsr0 + andn $t1, $t1, $a0 + movgr2fcsr $fcsr0, $t1 + li.w $a0, 0 + jr $ra + +.global feraiseexcept +.type feraiseexcept, %function +feraiseexcept: + li.w $t0, 0x1f0000 + and $a0, $a0, $t0 + movfcsr2gr $t1, $fcsr0 + or $t1, $t1, $a0 + movgr2fcsr $fcsr0, $t1 + li.w $a0, 0 + jr $ra + +.global fetestexcept +.type fetestexcept, %function +fetestexcept: + li.w $t0, 0x1f0000 + and $a0, $a0, $t0 + movfcsr2gr $t1, $fcsr0 + and $a0, $t1, $a0 + jr $ra + +.global fegetround +.type fegetround, %function +fegetround: + movfcsr2gr $t0, $fcsr0 + andi $a0, $t0, 0x300 + jr $ra + +.global __fesetround +.type __fesetround, %function +__fesetround: + li.w $t0, 0x300 + and $a0, $a0, $t0 + movfcsr2gr $t1, $fcsr0 + andn $t1, $t1, $t0 + or $t1, $t1, $a0 + movgr2fcsr $fcsr0, $t1 + li.w $a0, 0 + jr $ra + +.global fegetenv +.type fegetenv, %function +fegetenv: + movfcsr2gr $t0, $fcsr0 + st.w $t0, $a0, 0 + li.w $a0, 0 + jr $ra + +.global fesetenv +.type fesetenv, %function +fesetenv: + addi.d $t0, $a0, 1 + beq $t0, $r0, 1f + ld.w $t0, $a0, 0 +1: movgr2fcsr $fcsr0, $t0 + li.w $a0, 0 + jr $ra \ No newline at end of file diff --git a/user/include/mlibc/options/internal/loongarch64/setjmp.S b/user/include/mlibc/options/internal/loongarch64/setjmp.S new file mode 100644 index 0000000..a4389d6 --- /dev/null +++ b/user/include/mlibc/options/internal/loongarch64/setjmp.S @@ -0,0 +1,68 @@ +.global setjmp +.type setjmp, "function" +.global _setjmp +.type _setjmp, "function" +setjmp: +_setjmp: + st.d $ra, $a0, 0 + st.d $sp, $a0, 8 + st.d $r21, $a0, 16 + st.d $fp, $a0, 24 + st.d $s0, $a0, 32 + st.d $s1, $a0, 40 + st.d $s2, $a0, 48 + st.d $s3, $a0, 56 + st.d $s4, $a0, 64 + st.d $s5, $a0, 72 + st.d $s6, $a0, 80 + st.d $s7, $a0, 88 + st.d $s8, $a0, 96 + fst.d $fs0, $a0, 104 + fst.d $fs1, $a0, 112 + fst.d $fs2, $a0, 120 + fst.d $fs3, $a0, 128 + fst.d $fs4, $a0, 136 + fst.d $fs5, $a0, 144 + fst.d $fs6, $a0, 152 + fst.d $fs7, $a0, 160 + move $a0, $r0 + ret + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + break 0 // TODO + +.global longjmp +.type longjmp, "function" +.global _longjmp +.type _longjmp, "function" +longjmp: +_longjmp: + ld.d $ra, $a0, 0 + ld.d $sp, $a0, 8 + ld.d $r21, $a0, 16 + ld.d $fp, $a0, 24 + ld.d $s0, $a0, 32 + ld.d $s1, $a0, 40 + ld.d $s2, $a0, 48 + ld.d $s3, $a0, 56 + ld.d $s4, $a0, 64 + ld.d $s5, $a0, 72 + ld.d $s6, $a0, 80 + ld.d $s7, $a0, 88 + ld.d $s8, $a0, 96 + fld.d $fs0, $a0, 104 + fld.d $fs1, $a0, 112 + fld.d $fs2, $a0, 120 + fld.d $fs3, $a0, 128 + fld.d $fs4, $a0, 136 + fld.d $fs5, $a0, 144 + fld.d $fs6, $a0, 152 + fld.d $fs7, $a0, 160 + sltui $a0, $a1, 1 + add.d $a0, $a0, $a1 + jr $ra + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/internal/m68k-include/mlibc/arch-defs.hpp b/user/include/mlibc/options/internal/m68k-include/mlibc/arch-defs.hpp new file mode 100644 index 0000000..5e9f1ee --- /dev/null +++ b/user/include/mlibc/options/internal/m68k-include/mlibc/arch-defs.hpp @@ -0,0 +1,13 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +// not strictly true, can be 4 or 8k on 68040/68060, and many more on others +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP diff --git a/user/include/mlibc/options/internal/m68k-include/mlibc/thread.hpp b/user/include/mlibc/options/internal/m68k-include/mlibc/thread.hpp new file mode 100644 index 0000000..26cb187 --- /dev/null +++ b/user/include/mlibc/options/internal/m68k-include/mlibc/thread.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include +#include + +namespace mlibc { + +extern "C" void *__m68k_read_tp(); + +inline Tcb *get_current_tcb() { + // On m68k, the end of the TCB is 0x7000 below the thread pointer. + void *ptr = __m68k_read_tp(); + return reinterpret_cast((uintptr_t)ptr - 0x7000 - sizeof(Tcb)); +} + +inline uintptr_t get_sp() { + uintptr_t sp; + asm volatile ("move.l %%sp, %0" : "=r"(sp)); + return sp; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/m68k/fenv.S b/user/include/mlibc/options/internal/m68k/fenv.S new file mode 100644 index 0000000..bcff214 --- /dev/null +++ b/user/include/mlibc/options/internal/m68k/fenv.S @@ -0,0 +1,111 @@ +#include + +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + move.l 4(%sp), %d0 + andi.l #~FE_ALL_EXCEPT, %d0 + bne 1f + + fmove.l %fpsr, %d1 + movel 4(%sp), %d0 + not.l %d0 + and.l %d0, %d1 + fmove.l %d1, %fpsr + + moveq.l #0, %d0 + rts + +1: + moveq.l #-1, %d0 + rts + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + move.l 4(%sp), %d0 + andi.l #~FE_ALL_EXCEPT, %d0 + bne 1f + + fmove.l %fpsr, %d1 + or.l 4(%sp), %d1 + fmove.l %d1, %fpsr + + moveq.l #0, %d0 + rts + +1: + moveq.l #-1, %d0 + rts + +.global __fesetround +.hidden __fesetround +.type __fesetround,@function +__fesetround: + fmove.l %fpcr, %d1 + andi.l #~FE_UPWARD, %d1 + or.l 4(%sp), %d1 + fmove.l %d1, %fpcr + moveq.l #0, %d0 + rts + +.global fegetround +.type fegetround,@function +fegetround: + fmove.l %fpcr, %d0 + andi.l #FE_UPWARD, %d0 + rts + +.global fegetenv +.type fegetenv,@function +fegetenv: + move.l 4(%sp), %a0 + + fmove.l %fpcr, %d0 + move.l %d0, (%a0) + + fmove.l %fpsr, %d0 + move.l %d0, 4(%a0) + + fmove.l %fpiar, %d0 + move.l %d0, 8(%a0) + + moveq.l #0, %d0 + rts + +.global fesetenv +.type fesetenv,@function +fesetenv: + move.l 4(%sp), %a0 + + cmp.l #-1, %a0 + beq 1f + + move.l (%a0), %d0 + fmove.l %d0, %fpcr + + move.l 4(%a0), %d0 + fmove.l %d0, %fpsr + + move.l 8(%a0), %d0 + fmove.l %d0, %fpiar + + moveq.l #0, %d0 + rts + +1: + clr.l %d0 + fmove.l %d0, %fpcr + fmove.l %d0, %fpsr + fmove.l %d0, %fpiar + moveq.l #0, %d0 + rts + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + fmove.l %fpsr, %d0 + and.l 4(%sp), %d0 + rts + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/options/internal/m68k/setjmp.S b/user/include/mlibc/options/internal/m68k/setjmp.S new file mode 100644 index 0000000..81a577e --- /dev/null +++ b/user/include/mlibc/options/internal/m68k/setjmp.S @@ -0,0 +1,52 @@ +.type __setjmp, "function" +__setjmp: + movea.l 4(%sp), %a0 + movem.l %d2-%d7/%a2-%a7, (%a0) + move.l (%sp), 48(%a0) + tst.l %d0 + bne 1f + + clr.l %d0 + rts + +1: + move.l #1, -(%sp) + move.l %a0, -(%sp) + jbsr __sigsetjmp@PLTPC + addq.l #8, %sp + rts + + +.global setjmp +.type setjmp, "function" +.global _setjmp +.type _setjmp, "function" +setjmp: +_setjmp: + clr.l %d0 + jmp __setjmp + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + move.l #1, %d0 + jmp __setjmp + +.global longjmp +.type longjmp, "function" +.global _longjmp +.type _longjmp, "function" +longjmp: +_longjmp: + movea.l 4(%sp),%a0 + move.l 8(%sp),%d0 + bne 1f + + move.l #1,%d0 + +1: + movem.l (%a0), %d2-%d7/%a2-%a7 + move.l 48(%a0), (%sp) + rts + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/options/internal/riscv64-include/mlibc/arch-defs.hpp b/user/include/mlibc/options/internal/riscv64-include/mlibc/arch-defs.hpp new file mode 100644 index 0000000..0a4789f --- /dev/null +++ b/user/include/mlibc/options/internal/riscv64-include/mlibc/arch-defs.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP diff --git a/user/include/mlibc/options/internal/riscv64-include/mlibc/thread.hpp b/user/include/mlibc/options/internal/riscv64-include/mlibc/thread.hpp new file mode 100644 index 0000000..3efec9e --- /dev/null +++ b/user/include/mlibc/options/internal/riscv64-include/mlibc/thread.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + // On RISC-V, the TCB is below the thread pointer. + uintptr_t tp = (uintptr_t)__builtin_thread_pointer(); + auto tcb = reinterpret_cast(tp - sizeof(Tcb)); + __ensure(tcb == tcb->selfPointer); + return tcb; +} + +inline uintptr_t get_sp() { + uintptr_t sp; + asm volatile ("mv %0, sp" : "=r"(sp)); + return sp; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/riscv64-include/sys/hwprobe.h b/user/include/mlibc/options/internal/riscv64-include/sys/hwprobe.h new file mode 100644 index 0000000..4a33d71 --- /dev/null +++ b/user/include/mlibc/options/internal/riscv64-include/sys/hwprobe.h @@ -0,0 +1,22 @@ +#ifndef _MLIBC_SYS_HWPROBE_H +#define _MLIBC_SYS_HWPROBE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, + unsigned int flags); + +typedef int (*__riscv_hwprobe_t)(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpusetsize, cpu_set_t *cpus, unsigned int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* _MLIBC_SYS_HWPROBE_H */ diff --git a/user/include/mlibc/options/internal/riscv64/fenv.S b/user/include/mlibc/options/internal/riscv64/fenv.S new file mode 100644 index 0000000..c62ea36 --- /dev/null +++ b/user/include/mlibc/options/internal/riscv64/fenv.S @@ -0,0 +1,57 @@ + +#ifdef __riscv_flen + +.global feclearexcept +.type feclearexcept, %function +feclearexcept: + csrc fflags, a0 + li a0, 0 + ret + +.global feraiseexcept +.type feraiseexcept, %function +feraiseexcept: + csrs fflags, a0 + li a0, 0 + ret + +.global fetestexcept +.type fetestexcept, %function +fetestexcept: + frflags t0 + and a0, t0, a0 + ret + +.global fegetround +.type fegetround, %function +fegetround: + frrm a0 + ret + +.global __fesetround +.type __fesetround, %function +__fesetround: + fsrm t0, a0 + li a0, 0 + ret + +.global fegetenv +.type fegetenv, %function +fegetenv: + frcsr t0 + sw t0, 0(a0) + li a0, 0 + ret + +.global fesetenv +.type fesetenv, %function +fesetenv: + li t2, -1 + li t1, 0 + beq a0, t2, 1f + lw t1, 0(a0) +1: fscsr t1 + li a0, 0 + ret + +#endif \ No newline at end of file diff --git a/user/include/mlibc/options/internal/riscv64/hwprobe.cpp b/user/include/mlibc/options/internal/riscv64/hwprobe.cpp new file mode 100644 index 0000000..a18ccab --- /dev/null +++ b/user/include/mlibc/options/internal/riscv64/hwprobe.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags) { + if (!mlibc::sys_riscv_hwprobe) { + MLIBC_MISSING_SYSDEP(); + return -ENOSYS; + } + + int ret = mlibc::sys_riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags); + + if (ret) + return -ret; + + return 0; +} diff --git a/user/include/mlibc/options/internal/riscv64/setjmp.S b/user/include/mlibc/options/internal/riscv64/setjmp.S new file mode 100644 index 0000000..7ce9cfb --- /dev/null +++ b/user/include/mlibc/options/internal/riscv64/setjmp.S @@ -0,0 +1,77 @@ +.global setjmp +.type setjmp, "function" +.global _setjmp +.type _setjmp, "function" +setjmp: +_setjmp: + sd ra, 0(a0) + sd s0, 8(a0) + sd s1, 16(a0) + sd s2, 24(a0) + sd s3, 32(a0) + sd s4, 40(a0) + sd s5, 48(a0) + sd s6, 56(a0) + sd s7, 64(a0) + sd s8, 72(a0) + sd s9, 80(a0) + sd s10, 88(a0) + sd s11, 96(a0) + sd sp, 104(a0) + fsd fs0, 112(a0) + fsd fs1, 120(a0) + fsd fs2, 128(a0) + fsd fs3, 136(a0) + fsd fs4, 144(a0) + fsd fs5, 152(a0) + fsd fs6, 160(a0) + fsd fs7, 168(a0) + fsd fs8, 176(a0) + fsd fs9, 184(a0) + fsd fs10, 192(a0) + fsd fs11, 200(a0) + li a0, 0 + ret + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + unimp // TODO + +.global longjmp +.type longjmp, "function" +.global _longjmp +.type _longjmp, "function" +longjmp: +_longjmp: + ld ra,0(a0) + ld s0,8(a0) + ld s1,16(a0) + ld s2,24(a0) + ld s3,32(a0) + ld s4,40(a0) + ld s5,48(a0) + ld s6,56(a0) + ld s7,64(a0) + ld s8,72(a0) + ld s9,80(a0) + ld s10,88(a0) + ld s11,96(a0) + ld sp,104(a0) + fld fs0,112(a0) + fld fs1,120(a0) + fld fs2,128(a0) + fld fs3,136(a0) + fld fs4,144(a0) + fld fs5,152(a0) + fld fs6,160(a0) + fld fs7,168(a0) + fld fs8,176(a0) + fld fs9,184(a0) + fld fs10,192(a0) + fld fs11,200(a0) + seqz a0,a1 + add a0,a0,a1 + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/internal/x86-include/mlibc/arch-defs.hpp b/user/include/mlibc/options/internal/x86-include/mlibc/arch-defs.hpp new file mode 100755 index 0000000..aa8fe38 --- /dev/null +++ b/user/include/mlibc/options/internal/x86-include/mlibc/arch-defs.hpp @@ -0,0 +1,13 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP + diff --git a/user/include/mlibc/options/internal/x86-include/mlibc/thread.hpp b/user/include/mlibc/options/internal/x86-include/mlibc/thread.hpp new file mode 100755 index 0000000..8727db0 --- /dev/null +++ b/user/include/mlibc/options/internal/x86-include/mlibc/thread.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + uintptr_t ptr; + asm volatile ("movl %%gs:0, %0" : "=r"(ptr)); + return reinterpret_cast(ptr); +} + +inline uintptr_t get_sp() { + uintptr_t esp; + asm volatile ("mov %%esp, %0" : "=r"(esp)); + return esp; +} + +} // namespace mlibc + diff --git a/user/include/mlibc/options/internal/x86/fenv.S b/user/include/mlibc/options/internal/x86/fenv.S new file mode 100644 index 0000000..a46b5fa --- /dev/null +++ b/user/include/mlibc/options/internal/x86/fenv.S @@ -0,0 +1,168 @@ +# The functions below are taken from musl. + +.hidden __hwcap + +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + mov 4(%esp),%ecx + and $0x3f,%ecx + fnstsw %ax + # consider sse fenv as well if the cpu has XMM capability + call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 2f + # maintain exceptions in the sse mxcsr, clear x87 exceptions + test %eax,%ecx + jz 1f + fnclex +1: push %edx + stmxcsr (%esp) + pop %edx + and $0x3f,%eax + or %eax,%edx + test %edx,%ecx + jz 1f + not %ecx + and %ecx,%edx + push %edx + ldmxcsr (%esp) + pop %edx +1: xor %eax,%eax + ret + # only do the expensive x87 fenv load/store when needed +2: test %eax,%ecx + jz 1b + not %ecx + and %ecx,%eax + test $0x3f,%eax + jz 1f + fnclex + jmp 1b +1: sub $32,%esp + fnstenv (%esp) + mov %al,4(%esp) + fldenv (%esp) + add $32,%esp + xor %eax,%eax + ret + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + mov 4(%esp),%eax + and $0x3f,%eax + sub $32,%esp + fnstenv (%esp) + or %al,4(%esp) + fldenv (%esp) + add $32,%esp + xor %eax,%eax + ret + +.global __fesetround +.hidden __fesetround +.type __fesetround,@function +__fesetround: + mov 4(%esp),%ecx + push %eax + xor %eax,%eax + fnstcw (%esp) + andb $0xf3,1(%esp) + or %ch,1(%esp) + fldcw (%esp) + # consider sse fenv as well if the cpu has XMM capability + call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 1f + stmxcsr (%esp) + shl $3,%ch + andb $0x9f,1(%esp) + or %ch,1(%esp) + ldmxcsr (%esp) +1: pop %ecx + ret + +.global fegetround +.type fegetround,@function +fegetround: + push %eax + fnstcw (%esp) + pop %eax + and $0xc00,%eax + ret + +.global fegetenv +.type fegetenv,@function +fegetenv: + mov 4(%esp),%ecx + xor %eax,%eax + fnstenv (%ecx) + # consider sse fenv as well if the cpu has XMM capability + call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 1f + push %eax + stmxcsr (%esp) + pop %edx + and $0x3f,%edx + or %edx,4(%ecx) +1: ret + +.global fesetenv +.type fesetenv,@function +fesetenv: + mov 4(%esp),%ecx + xor %eax,%eax + inc %ecx + jz 1f + fldenv -1(%ecx) + movl -1(%ecx),%ecx + jmp 2f +1: push %eax + push %eax + push %eax + push %eax + pushl $0xffff + push %eax + pushl $0x37f + fldenv (%esp) + add $28,%esp + # consider sse fenv as well if the cpu has XMM capability +2: call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 1f + # mxcsr := same rounding mode, cleared exceptions, default mask + and $0xc00,%ecx + shl $3,%ecx + or $0x1f80,%ecx + mov %ecx,4(%esp) + ldmxcsr 4(%esp) +1: ret + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + mov 4(%esp),%ecx + and $0x3f,%ecx + fnstsw %ax + # consider sse fenv as well if the cpu has XMM capability + call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 1f + stmxcsr 4(%esp) + or 4(%esp),%eax +1: and %ecx,%eax + ret + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/options/internal/x86/setjmp.S b/user/include/mlibc/options/internal/x86/setjmp.S new file mode 100644 index 0000000..d2cd348 --- /dev/null +++ b/user/include/mlibc/options/internal/x86/setjmp.S @@ -0,0 +1,59 @@ + +.type __setjmp, "function" +__setjmp: + mov 4(%esp), %eax # Save argument (buffer) in edi + mov %ebx, 0x00(%eax) + mov %ebp, 0x04(%eax) + mov %esi, 0x08(%eax) + mov %edi, 0x0c(%eax) + + lea 4(%esp), %ecx # esp before return eip is pushed + mov %ecx, 0x10(%eax) + mov (%esp), %ecx # Return eip + mov %ecx, 0x14(%eax) + + test %edx, %edx + jnz 1f + xor %eax, %eax + ret + +1: + jmp __sigsetjmp@PLT + +.global setjmp +.type setjmp, "function" +.global _setjmp +.type _setjmp, "function" +setjmp: +_setjmp: + xor %edx, %edx + jmp __setjmp + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + mov $1, %edx + jmp __setjmp + +.global longjmp +.type longjmp, "function" +.global _longjmp +.type _longjmp, "function" +longjmp: +_longjmp: + mov 4(%esp), %ecx + mov 0x00(%ecx), %ebx + mov 0x04(%ecx), %ebp + mov 0x08(%ecx), %esi + mov 0x0c(%ecx), %edi + + mov 8(%esp), %eax + test %eax, %eax + jnz 1f + inc %eax +1: + mov 0x10(%ecx), %esp + jmp *0x14(%ecx) + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/internal/x86_64-include/mlibc/arch-defs.hpp b/user/include/mlibc/options/internal/x86_64-include/mlibc/arch-defs.hpp new file mode 100644 index 0000000..0a4789f --- /dev/null +++ b/user/include/mlibc/options/internal/x86_64-include/mlibc/arch-defs.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP diff --git a/user/include/mlibc/options/internal/x86_64-include/mlibc/thread.hpp b/user/include/mlibc/options/internal/x86_64-include/mlibc/thread.hpp new file mode 100644 index 0000000..474f562 --- /dev/null +++ b/user/include/mlibc/options/internal/x86_64-include/mlibc/thread.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + uintptr_t ptr; + asm volatile ("movq %%fs:0, %0" : "=r"(ptr)); + return reinterpret_cast(ptr); +} + +inline uintptr_t get_sp() { + uintptr_t rsp; + asm volatile ("mov %%rsp, %0" : "=r"(rsp)); + return rsp; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/internal/x86_64/fenv.S b/user/include/mlibc/options/internal/x86_64/fenv.S new file mode 100644 index 0000000..3748988 --- /dev/null +++ b/user/include/mlibc/options/internal/x86_64/fenv.S @@ -0,0 +1,102 @@ +# The functions below are taken from musl. +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + # maintain exceptions in the sse mxcsr, clear x87 exceptions + mov %edi,%ecx + and $0x3f,%ecx + fnstsw %ax + test %eax,%ecx + jz 1f + fnclex +1: stmxcsr -8(%rsp) + and $0x3f,%eax + or %eax,-8(%rsp) + test %ecx,-8(%rsp) + jz 1f + not %ecx + and %ecx,-8(%rsp) + ldmxcsr -8(%rsp) +1: xor %eax,%eax + ret + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + and $0x3f,%edi + stmxcsr -8(%rsp) + or %edi,-8(%rsp) + ldmxcsr -8(%rsp) + xor %eax,%eax + ret + +.global __fesetround +.hidden __fesetround +.type __fesetround,@function +__fesetround: + push %rax + xor %eax,%eax + mov %edi,%ecx + fnstcw (%rsp) + andb $0xf3,1(%rsp) + or %ch,1(%rsp) + fldcw (%rsp) + stmxcsr (%rsp) + shl $3,%ch + andb $0x9f,1(%rsp) + or %ch,1(%rsp) + ldmxcsr (%rsp) + pop %rcx + ret + +.global fegetround +.type fegetround,@function +fegetround: + push %rax + stmxcsr (%rsp) + pop %rax + shr $3,%eax + and $0xc00,%eax + ret + +.global fegetenv +.type fegetenv,@function +fegetenv: + xor %eax,%eax + fnstenv (%rdi) + stmxcsr 28(%rdi) + ret + +.global fesetenv +.type fesetenv,@function +fesetenv: + xor %eax,%eax + inc %rdi + jz 1f + fldenv -1(%rdi) + ldmxcsr 27(%rdi) + ret +1: push %rax + push %rax + pushq $0xffff + pushq $0x37f + fldenv (%rsp) + pushq $0x1f80 + ldmxcsr (%rsp) + add $40,%rsp + ret + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + and $0x3f,%edi + push %rax + stmxcsr (%rsp) + pop %rsi + fnstsw %ax + or %esi,%eax + and %edi,%eax + ret + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/internal/x86_64/setjmp.S b/user/include/mlibc/options/internal/x86_64/setjmp.S new file mode 100644 index 0000000..98acb99 --- /dev/null +++ b/user/include/mlibc/options/internal/x86_64/setjmp.S @@ -0,0 +1,60 @@ + +.type __setjmp, "function" +__setjmp: + mov %rbx, 0x00(%rdi) + mov %rbp, 0x08(%rdi) + mov %r12, 0x10(%rdi) + mov %r13, 0x18(%rdi) + mov %r14, 0x20(%rdi) + mov %r15, 0x28(%rdi) + + lea 8(%rsp), %rax # rsp before return rip is pushed + mov %rax, 0x30(%rdi) + mov (%rsp), %rax # return rip + mov %rax, 0x38(%rdi) + + test %rdx, %rdx + jnz 1f + xor %rax, %rax + ret + +1: + jmp __sigsetjmp + +.global setjmp +.type setjmp, "function" +.global _setjmp +.type _setjmp, "function" +setjmp: +_setjmp: + xor %rdx, %rdx + jmp __setjmp + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + mov $1, %rdx + jmp __setjmp + +.global longjmp +.type longjmp, "function" +.global _longjmp +.type _longjmp, "function" +longjmp: +_longjmp: + mov 0x00(%rdi), %rbx + mov 0x08(%rdi), %rbp + mov 0x10(%rdi), %r12 + mov 0x18(%rdi), %r13 + mov 0x20(%rdi), %r14 + mov 0x28(%rdi), %r15 + + mov %rsi, %rax + test %rax, %rax + jnz 1f + inc %rax +1: + mov 0x30(%rdi), %rsp + jmp *0x38(%rdi) +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/linux/generic/capabilities.cpp b/user/include/mlibc/options/linux/generic/capabilities.cpp new file mode 100644 index 0000000..871822a --- /dev/null +++ b/user/include/mlibc/options/linux/generic/capabilities.cpp @@ -0,0 +1,19 @@ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int capset(void *, void *) { + mlibc::infoLogger() << "mlibc: capset is a no-op!" << frg::endlog; + return 0; +} + +int capget(void *, void *) { + mlibc::infoLogger() << "mlibc: capget is a no-op!" << frg::endlog; + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/user/include/mlibc/options/linux/generic/cpuset.cpp b/user/include/mlibc/options/linux/generic/cpuset.cpp new file mode 100644 index 0000000..d0292b7 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/cpuset.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +cpu_set_t *__mlibc_cpu_alloc(int num_cpus) { + return reinterpret_cast(calloc(1, CPU_ALLOC_SIZE(num_cpus))); +} + +#define CPU_MASK_BITS (CHAR_BIT * sizeof(__cpu_mask)) + +size_t __mlibc_cpu_alloc_size(int num_cpus) { + /* calculate the (unaligned) remainder that doesn't neatly fit in one __cpu_mask; 0 or 1 */ + size_t remainder = ((num_cpus % CPU_MASK_BITS) + CPU_MASK_BITS - 1) / CPU_MASK_BITS; + return sizeof(__cpu_mask) * (num_cpus / CPU_MASK_BITS + remainder); +} + +void __mlibc_cpu_zero(const size_t setsize, cpu_set_t *set) { + memset(set, 0, CPU_ALLOC_SIZE(setsize)); +} + +void __mlibc_cpu_set(const int cpu, const size_t setsize, cpu_set_t *set) { + if(cpu >= static_cast(setsize * CHAR_BIT)) { + return; + } + + unsigned char *ptr = reinterpret_cast(set); + size_t off = cpu / CHAR_BIT; + size_t mask = 1 << (cpu % CHAR_BIT); + + ptr[off] |= mask; +} + +void __mlibc_cpu_clear(const int cpu, const size_t setsize, cpu_set_t *set) { + if(cpu >= static_cast(setsize * CHAR_BIT)) { + return; + } + + unsigned char *ptr = reinterpret_cast(set); + size_t off = cpu / CHAR_BIT; + size_t mask = 1 << (cpu % CHAR_BIT); + + ptr[off] &= ~mask; +} + + +int __mlibc_cpu_isset(const int cpu, const size_t setsize, const cpu_set_t *set) { + if(cpu >= static_cast(setsize * CHAR_BIT)) { + return false; + } + + const unsigned char *ptr = reinterpret_cast(set); + size_t off = cpu / CHAR_BIT; + size_t mask = 1 << (cpu % CHAR_BIT); + + return (ptr[off] & mask); +} + +int __mlibc_cpu_count(const size_t setsize, const cpu_set_t *set) { + size_t count = 0; + const unsigned char *ptr = reinterpret_cast(set); + + for(size_t i = 0; i < setsize; i++) { + for(size_t bit = 0; bit < CHAR_BIT; bit++) { + if((1 << bit) & ptr[i]) + count++; + } + } + + return count; +} diff --git a/user/include/mlibc/options/linux/generic/ifaddrs.cpp b/user/include/mlibc/options/linux/generic/ifaddrs.cpp new file mode 100644 index 0000000..85565c0 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/ifaddrs.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +int getifaddrs(struct ifaddrs **ifap) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getifaddrs, -1); + if(int e = sysdep(ifap); e) { + errno = e; + return -1; + } + + return 0; +} + +void freeifaddrs(struct ifaddrs *ifa) { + while (ifa != nullptr) { + ifaddrs *current = ifa; + ifa = ifa->ifa_next; + getAllocator().free(current); + } +} diff --git a/user/include/mlibc/options/linux/generic/linux-unistd.cpp b/user/include/mlibc/options/linux/generic/linux-unistd.cpp new file mode 100644 index 0000000..264d30c --- /dev/null +++ b/user/include/mlibc/options/linux/generic/linux-unistd.cpp @@ -0,0 +1,38 @@ +#include +#include + +#include +#include +#include +#include + +int dup3(int oldfd, int newfd, int flags) { + if(oldfd == newfd) { + errno = EINVAL; + return -1; + } + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup2, -1); + if(int e = mlibc::sys_dup2(oldfd, flags, newfd); e) { + errno = e; + return -1; + } + return newfd; +} + +int vhangup(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getdtablesize(void){ + return sysconf(_SC_OPEN_MAX); +} + +int syncfs(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_syncfs, -1); + if(int e = mlibc::sys_syncfs(fd); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/linux/generic/malloc.cpp b/user/include/mlibc/options/linux/generic/malloc.cpp new file mode 100644 index 0000000..065de6c --- /dev/null +++ b/user/include/mlibc/options/linux/generic/malloc.cpp @@ -0,0 +1,7 @@ +#include +#include + +void *memalign(size_t, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/linux/generic/mntent.cpp b/user/include/mlibc/options/linux/generic/mntent.cpp new file mode 100644 index 0000000..586a198 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/mntent.cpp @@ -0,0 +1,98 @@ + +#include +#include +#include +#include +#include +#include + +namespace { + +char *internal_buf; +size_t internal_bufsize; + +} // namespace + +#define SENTINEL (char *)&internal_buf + +FILE *setmntent(const char *name, const char *mode) { + return fopen(name, mode); +} + +struct mntent *getmntent(FILE *f) { + static struct mntent mnt; + return getmntent_r(f, &mnt, SENTINEL, 0); +} + +int addmntent(FILE *f, const struct mntent *mnt) { + if(fseek(f, 0, SEEK_END)) { + return 1; + } + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", + mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, + mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +int endmntent(FILE *f) { + if(f) { + fclose(f); + } + return 1; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) { + return strstr(mnt->mnt_opts, opt); +} + +/* Adapted from musl */ +struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { + int n[8]; + bool use_internal = (linebuf == SENTINEL); + int len; + size_t i; + + mnt->mnt_freq = 0; + mnt->mnt_passno = 0; + + do { + if(use_internal) { + getline(&internal_buf, &internal_bufsize, f); + linebuf = internal_buf; + } else { + fgets(linebuf, buflen, f); + } + if(feof(f) || ferror(f)) { + return nullptr; + } + if(!strchr(linebuf, '\n')) { + fscanf(f, "%*[^\n]%*[\n]"); + errno = ERANGE; + return nullptr; + } + + len = strlen(linebuf); + if(len > INT_MAX) { + continue; + } + + for(i = 0; i < sizeof n / sizeof *n; i++) { + n[i] = len; + } + + sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + n, n + 1, n + 2, n + 3, n + 4, n + 5, n + 6, n + 7, + &mnt->mnt_freq, &mnt->mnt_passno); + } while(linebuf[n[0]] == '#' || n[1] == len); + + linebuf[n[1]] = 0; + linebuf[n[3]] = 0; + linebuf[n[5]] = 0; + linebuf[n[7]] = 0; + + mnt->mnt_fsname = linebuf + n[0]; + mnt->mnt_dir = linebuf + n[2]; + mnt->mnt_type = linebuf + n[4]; + mnt->mnt_opts = linebuf + n[6]; + + return mnt; +} diff --git a/user/include/mlibc/options/linux/generic/module.cpp b/user/include/mlibc/options/linux/generic/module.cpp new file mode 100644 index 0000000..53b6dc8 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/module.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include +#include +#include + +int init_module(void *module, unsigned long length, const char *args) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_init_module, -1); + if(int e = mlibc::sys_init_module(module, length, args); e) { + errno = e; + return -1; + } + return 0; +} + +int delete_module(const char *name, unsigned flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_delete_module, -1); + if(int e = mlibc::sys_delete_module(name, flags); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/linux/generic/sched.cpp b/user/include/mlibc/options/linux/generic/sched.cpp new file mode 100644 index 0000000..10e159e --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sched.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +#include +#include + +int sched_getcpu(void) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getcpu, -1); + int cpu; + if(int e = mlibc::sys_getcpu(&cpu); e) { + errno = e; + return -1; + } + return cpu; +} + +int setns(int fd, int nstype) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setns, -1); + if(int e = mlibc::sys_setns(fd, nstype); e) { + errno = e; + return -1; + } + return 0; +} + +int sched_getscheduler(pid_t pid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getscheduler, -1); + int policy; + if(int e = mlibc::sys_getscheduler(pid, &policy); e) { + errno = e; + return -1; + } + return policy; +} + +int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getaffinity, -1); + if(int e = mlibc::sys_getaffinity(pid, cpusetsize, mask); e) { + errno = e; + return -1; + } + return 0; +} + +int unshare(int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unshare, -1); + if(int e = mlibc::sys_unshare(flags); e) { + errno = e; + return -1; + } + return 0; +} + +int sched_setaffinity(pid_t, size_t, const cpu_set_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int clone(int (*)(void *), void *, int, void *, ...) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/linux/generic/sys-epoll.cpp b/user/include/mlibc/options/linux/generic/sys-epoll.cpp new file mode 100644 index 0000000..c90478d --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-epoll.cpp @@ -0,0 +1,58 @@ + +#include +#include + +#include +#include +#include + +int epoll_create(int) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_create, -1); + if(int e = mlibc::sys_epoll_create(0, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int epoll_pwait(int epfd, struct epoll_event *evnts, int n, int timeout, + const sigset_t *sigmask) { + int raised; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_pwait, -1); + if(int e = mlibc::sys_epoll_pwait(epfd, evnts, n, timeout, sigmask, &raised)) { + errno = e; + return -1; + } + return raised; +} + +int epoll_create1(int flags) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_create, -1); + if(int e = mlibc::sys_epoll_create(flags, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_ctl, -1); + if(int e = mlibc::sys_epoll_ctl(epfd, mode, fd, ev); e) { + errno = e; + return -1; + } + return 0; +} + +int epoll_wait(int epfd, struct epoll_event *evnts, int n, int timeout) { + int raised; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_pwait, -1); + if(int e = mlibc::sys_epoll_pwait(epfd, evnts, n, timeout, nullptr, &raised)) { + errno = e; + return -1; + } + return raised; +} + diff --git a/user/include/mlibc/options/linux/generic/sys-eventfd.cpp b/user/include/mlibc/options/linux/generic/sys-eventfd.cpp new file mode 100644 index 0000000..1d83d8c --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-eventfd.cpp @@ -0,0 +1,45 @@ +#include +#include + +#include +#include + +int eventfd(unsigned int initval, int flags) { + int fd = 0; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_eventfd_create, -1); + if (int e = mlibc::sys_eventfd_create(initval, flags, &fd); e) { + errno = e; + return -1; + } + + return fd; +} + +int eventfd_read(int fd, eventfd_t *value) { + ssize_t bytes_read; + if (int e = mlibc::sys_read(fd, value, 8, &bytes_read); e) { + errno = e; + return -1; + } + + if (bytes_read != 8) { + return -1; + } + + return 0; +} + +int eventfd_write(int fd, eventfd_t value) { + ssize_t bytes_written; + if (int e = mlibc::sys_write(fd, &value, 8, &bytes_written); e) { + errno = e; + return -1; + } + + if (bytes_written != 8) { + return -1; + } + + return 0; +} diff --git a/user/include/mlibc/options/linux/generic/sys-fsuid.cpp b/user/include/mlibc/options/linux/generic/sys-fsuid.cpp new file mode 100644 index 0000000..653456c --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-fsuid.cpp @@ -0,0 +1,12 @@ +#include +#include + +int setfsuid(uid_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int setfsgid(gid_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/linux/generic/sys-inotify.cpp b/user/include/mlibc/options/linux/generic/sys-inotify.cpp new file mode 100644 index 0000000..0bc25c9 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-inotify.cpp @@ -0,0 +1,47 @@ + +#include +#include + +#include +#include +#include + +int inotify_init(void) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_inotify_create, -1); + if(int e = mlibc::sys_inotify_create(0, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int inotify_init1(int flags) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_inotify_create, -1); + if(int e = mlibc::sys_inotify_create(flags, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int inotify_add_watch(int ifd, const char *path, uint32_t mask) { + int wd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_inotify_add_watch, -1); + if(int e = mlibc::sys_inotify_add_watch(ifd, path, mask, &wd); e) { + errno = e; + return -1; + } + return wd; +} + +int inotify_rm_watch(int ifd, int wd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_inotify_rm_watch, -1); + if(int e = mlibc::sys_inotify_rm_watch(ifd, wd); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/user/include/mlibc/options/linux/generic/sys-klog.cpp b/user/include/mlibc/options/linux/generic/sys-klog.cpp new file mode 100644 index 0000000..059e292 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-klog.cpp @@ -0,0 +1,16 @@ +#include +#include + +#include + +#include + +int klogctl(int type, char *bufp, int len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_klogctl, -1); + int out; + if (int e = mlibc::sys_klogctl(type, bufp, len, &out); e) { + errno = e; + return -1; + } + return out; +} diff --git a/user/include/mlibc/options/linux/generic/sys-mount.cpp b/user/include/mlibc/options/linux/generic/sys-mount.cpp new file mode 100644 index 0000000..4783183 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-mount.cpp @@ -0,0 +1,29 @@ + +#include +#include + +#include +#include + +int mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mount, -1); + if(int e = mlibc::sys_mount(source, target, fstype, flags, data); e) { + errno = e; + return -1; + } + return 0; +} + +int umount(const char *target) { + return umount2(target, 0); +} + +int umount2(const char *target, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_umount2, -1); + if(int e = mlibc::sys_umount2(target, flags); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/linux/generic/sys-pidfd.cpp b/user/include/mlibc/options/linux/generic/sys-pidfd.cpp new file mode 100644 index 0000000..ef1a0d4 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-pidfd.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +int pidfd_open(pid_t pid, unsigned int flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pidfd_open, -1); + int fd = 0; + + if(int e = sysdep(pid, flags, &fd); e) { + errno = e; + return -1; + } + + return fd; +} + +pid_t pidfd_getpid(int fd) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pidfd_getpid, -1); + pid_t pid = 0; + + if(int e = sysdep(fd, &pid); e) { + errno = e; + return -1; + } + + return pid; +} + +int pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pidfd_send_signal, -1); + + if(int e = sysdep(pidfd, sig, info, flags); e) { + errno = e; + return -1; + } + + return 0; +} diff --git a/user/include/mlibc/options/linux/generic/sys-prctl.cpp b/user/include/mlibc/options/linux/generic/sys-prctl.cpp new file mode 100644 index 0000000..5280332 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-prctl.cpp @@ -0,0 +1,25 @@ + +#include +#include +#include +#include + +#include + +#include "mlibc/linux-sysdeps.hpp" + +int prctl(int op, ...) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_prctl, -1); + + int val; + va_list ap; + va_start(ap, op); + if(int e = mlibc::sys_prctl(op, ap, &val); e) { + errno = e; + return -1; + } + va_end(ap); + + return val; +} + diff --git a/user/include/mlibc/options/linux/generic/sys-ptrace.cpp b/user/include/mlibc/options/linux/generic/sys-ptrace.cpp new file mode 100644 index 0000000..8c836c5 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-ptrace.cpp @@ -0,0 +1,36 @@ + +#include +#include +#include + +#include +#include +#include + +long ptrace(int req, ...) { + va_list ap; + + va_start(ap, req); + auto pid = va_arg(ap, pid_t); + auto addr = va_arg(ap, void *); + auto data = va_arg(ap, void *); + va_end(ap); + + long ret; + if(req > 0 && req < 4) { + data = &ret; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ptrace, -1); + long out; + if(int e = mlibc::sys_ptrace(req, pid, addr, data, &out); e) { + errno = e; + return -1; + } else if(req > 0 && req < 4) { + errno = 0; + return ret; + } + + return out; +} + diff --git a/user/include/mlibc/options/linux/generic/sys-quota.cpp b/user/include/mlibc/options/linux/generic/sys-quota.cpp new file mode 100644 index 0000000..27c0e6d --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-quota.cpp @@ -0,0 +1,7 @@ +#include +#include + +int quotactl(int, const char *, int, caddr_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/linux/generic/sys-random.cpp b/user/include/mlibc/options/linux/generic/sys-random.cpp new file mode 100644 index 0000000..5e5057f --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-random.cpp @@ -0,0 +1,21 @@ + +#include +#include + +#include +#include + +#include + +ssize_t getrandom(void *buffer, size_t max_size, unsigned int flags) { + if(flags & ~(GRND_RANDOM | GRND_NONBLOCK)) { + errno = EINVAL; + return -1; + } + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getentropy, -1); + if(int e = mlibc::sys_getentropy(buffer, max_size); e) { + errno = e; + return -1; + } + return max_size; +} diff --git a/user/include/mlibc/options/linux/generic/sys-reboot.cpp b/user/include/mlibc/options/linux/generic/sys-reboot.cpp new file mode 100644 index 0000000..c9b503f --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-reboot.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +int reboot(int what) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_reboot, -1); + if (int e = mlibc::sys_reboot(what); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/linux/generic/sys-sendfile.cpp b/user/include/mlibc/options/linux/generic/sys-sendfile.cpp new file mode 100644 index 0000000..bc164ea --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-sendfile.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +ssize_t sendfile(int outfd, int infd, off_t *offset, size_t size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sendfile, -1); + ssize_t out; + if(int e = mlibc::sys_sendfile(outfd, infd, offset, size, &out); e) { + errno = e; + return -1; + } + return out; +} + diff --git a/user/include/mlibc/options/linux/generic/sys-signalfd.cpp b/user/include/mlibc/options/linux/generic/sys-signalfd.cpp new file mode 100644 index 0000000..d3dd0da --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-signalfd.cpp @@ -0,0 +1,17 @@ + +#include +#include + +#include +#include +#include + +int signalfd(int fd, const sigset_t *mask, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_signalfd_create, -1); + if(int e = mlibc::sys_signalfd_create(mask, flags, &fd); e) { + errno = e; + return -1; + } + return fd; +} + diff --git a/user/include/mlibc/options/linux/generic/sys-statfs.cpp b/user/include/mlibc/options/linux/generic/sys-statfs.cpp new file mode 100644 index 0000000..853c808 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-statfs.cpp @@ -0,0 +1,28 @@ + +#include +#include +#include + +#include +#include + +int statfs(const char *path, struct statfs *buf) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_statfs, -1); + if(int e = mlibc::sys_statfs(path, buf); e) { + errno = e; + return -1; + } + return 0; +} + +int fstatfs(int fd, struct statfs *buf) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fstatfs, -1); + if (int e = mlibc::sys_fstatfs(fd, buf); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("fstatfs")]] int fstatfs64(int, struct statfs64 *); + diff --git a/user/include/mlibc/options/linux/generic/sys-statx.cpp b/user/include/mlibc/options/linux/generic/sys-statx.cpp new file mode 100644 index 0000000..67a972d --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-statx.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +#include +#include +#include + +int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf) { + if(!mlibc::sys_statx) { + struct stat statbuf; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + + if (!(flags & AT_NO_AUTOMOUNT)) { + mlibc::infoLogger() + << "mlibc: sys_statx is unavailable, and stat does not support not specifying AT_NO_MOUNTPOINT" + << frg::endlog; + } + + // AT_STATX_SYNC_AS_STAT is the default and behaves like good old stat + if ((flags & AT_STATX_FORCE_SYNC) || (flags & AT_STATX_DONT_SYNC)) { + mlibc::infoLogger() + << "mlibc: sys_statx is unavailable, and stat does not support modes other than AT_STATX_SYNC_AS_STAT" + << frg::endlog; + } + + // Mask out flags not appropriate for regular stat + flags &= ~(AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT | AT_STATX_FORCE_SYNC | AT_STATX_DONT_SYNC); + + if(int e = mlibc::sys_stat(mlibc::fsfd_target::fd_path, dirfd, pathname, flags, &statbuf); e) { + errno = e; + return -1; + } + + memset(statxbuf, 0, sizeof(struct statx)); + statxbuf->stx_blksize = statbuf.st_blksize; + statxbuf->stx_blocks = statbuf.st_blocks; + statxbuf->stx_gid = statbuf.st_gid; + statxbuf->stx_ino = statbuf.st_ino; + statxbuf->stx_mode = statbuf.st_mode; + statxbuf->stx_nlink = statbuf.st_nlink; + statxbuf->stx_size = statbuf.st_size; + statxbuf->stx_uid = statbuf.st_uid; + + statxbuf->stx_atime.tv_sec = statbuf.st_atim.tv_sec; + statxbuf->stx_atime.tv_nsec = statbuf.st_atim.tv_nsec; + statxbuf->stx_btime.tv_sec = statbuf.st_mtim.tv_sec; + statxbuf->stx_btime.tv_nsec = statbuf.st_mtim.tv_nsec; + statxbuf->stx_ctime.tv_sec = statbuf.st_ctim.tv_sec; + statxbuf->stx_ctime.tv_nsec = statbuf.st_ctim.tv_nsec; + statxbuf->stx_mtime.tv_sec = statbuf.st_mtim.tv_sec; + statxbuf->stx_mtime.tv_nsec = statbuf.st_mtim.tv_nsec; + + statxbuf->stx_rdev_major = major(statbuf.st_rdev); + statxbuf->stx_rdev_minor = minor(statbuf.st_rdev); + statxbuf->stx_dev_major = major(statbuf.st_dev); + statxbuf->stx_dev_minor = minor(statbuf.st_dev); + statxbuf->stx_mask = STATX_BASIC_STATS | STATX_BTIME; + + return 0; + } + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_statx, -1); + if(int e = sysdep(dirfd, pathname, flags, mask, statxbuf); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/user/include/mlibc/options/linux/generic/sys-swap.cpp b/user/include/mlibc/options/linux/generic/sys-swap.cpp new file mode 100644 index 0000000..44ddf98 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-swap.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include +#include +#include + +int swapon(const char *path, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_swapon, -1); + if(int e = mlibc::sys_swapon(path, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int swapoff(const char *path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_swapoff, -1); + if(int e = mlibc::sys_swapoff(path); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/linux/generic/sys-sysinfo.cpp b/user/include/mlibc/options/linux/generic/sys-sysinfo.cpp new file mode 100644 index 0000000..3b861c8 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-sysinfo.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include +#include +#include +#include + +int sysinfo(struct sysinfo *info) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sysinfo, -1); + if(int e = mlibc::sys_sysinfo(info); e) { + errno = e; + return -1; + } + return 0; +} + +int get_nprocs(void) { + return sysconf(_SC_NPROCESSORS_ONLN); +} + +int get_nprocs_conf(void) { + return sysconf(_SC_NPROCESSORS_CONF); +} diff --git a/user/include/mlibc/options/linux/generic/sys-timerfd.cpp b/user/include/mlibc/options/linux/generic/sys-timerfd.cpp new file mode 100644 index 0000000..9bba4dd --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-timerfd.cpp @@ -0,0 +1,37 @@ + +#include +#include + +#include +#include +#include + +int timerfd_create(int clockid, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timerfd_create, -1); + int fd; + if(int e = mlibc::sys_timerfd_create(clockid, flags, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int timerfd_settime(int fd, int flags, const struct itimerspec *value, + struct itimerspec *oldvalue) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timerfd_settime, -1); + if(int e = mlibc::sys_timerfd_settime(fd, flags, value, oldvalue); e) { + errno = e; + return -1; + } + return 0; +} + +int timerfd_gettime(int fd, struct itimerspec *its) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timerfd_gettime, -1); + if(int e = sysdep(fd, its); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/user/include/mlibc/options/linux/generic/sys-uio.cpp b/user/include/mlibc/options/linux/generic/sys-uio.cpp new file mode 100644 index 0000000..0c13373 --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-uio.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include +#include + +ssize_t process_vm_readv(pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_process_vm_readv, -1); + ssize_t bytes_read; + if(int e = mlibc::sys_process_vm_readv(pid, local_iov, liovcnt, + remote_iov, riovcnt, flags, &bytes_read); e) { + errno = e; + return -1; + } + return bytes_read; +} + +ssize_t process_vm_writev(pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_process_vm_writev, -1); + ssize_t bytes_written; + if(int e = mlibc::sys_process_vm_writev(pid, local_iov, liovcnt, + remote_iov, riovcnt, flags, &bytes_written); e) { + errno = e; + return -1; + } + return bytes_written; +} diff --git a/user/include/mlibc/options/linux/generic/sys-xattr.cpp b/user/include/mlibc/options/linux/generic/sys-xattr.cpp new file mode 100644 index 0000000..c8d598f --- /dev/null +++ b/user/include/mlibc/options/linux/generic/sys-xattr.cpp @@ -0,0 +1,122 @@ +#include +#include + +#include +#include + +int setxattr(const char *path, const char *name, const void *val, size_t size, + int flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setxattr, -1); + + if (int e = sysdep(path, name, val, size, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int lsetxattr(const char *path, const char *name, const void *val, size_t size, + int flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_lsetxattr, -1); + + if (int e = sysdep(path, name, val, size, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int fsetxattr(int fd, const char *name, const void *val, size_t size, + int flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fsetxattr, -1); + + if (int e = sysdep(fd, name, val, size, flags); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t getxattr(const char *path, const char *name, void *val, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getxattr, -1); + + ssize_t nread; + if (int e = sysdep(path, name, val, size, &nread); e) { + errno = e; + return -1; + } + + return nread; +} + +ssize_t lgetxattr(const char *path, const char *name, void *val, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_lgetxattr, -1); + + ssize_t nread; + if (int e = sysdep(path, name, val, size, &nread); e) { + errno = e; + return -1; + } + + return nread; +} + +ssize_t fgetxattr(int fd, const char *name, void *val, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fgetxattr, -1); + + ssize_t nread; + if (int e = sysdep(fd, name, val, size, &nread); e) { + errno = e; + return -1; + } + + return nread; +} + +int removexattr(const char *path, const char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_removexattr, -1); + return sysdep(path, name); +} + +int lremovexattr(const char *path, const char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_lremovexattr, -1); + return sysdep(path, name); +} + +int fremovexattr(int fd, const char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fremovexattr, -1); + return sysdep(fd, name); +} + +ssize_t listxattr(const char *path, char *list, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_listxattr, -1); + + ssize_t nread; + if (int e = sysdep(path, list, size, &nread); e) { + errno = e; + return -1; + } + return nread; +} + +ssize_t llistxattr(const char *path, char *list, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_llistxattr, -1); + + ssize_t nread; + if (int e = sysdep(path, list, size, &nread); e) { + errno = e; + return -1; + } + return nread; +} + +ssize_t flistxattr(int fd, char *list, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_flistxattr, -1); + + ssize_t nread; + if (int e = sysdep(fd, list, size, &nread); e) { + errno = e; + return -1; + } + return nread; +} diff --git a/user/include/mlibc/options/linux/generic/utmp.cpp b/user/include/mlibc/options/linux/generic/utmp.cpp new file mode 100644 index 0000000..d6a6a0d --- /dev/null +++ b/user/include/mlibc/options/linux/generic/utmp.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace { + +constexpr const char *defaultUtmpPath = UTMP_FILE; + +const char *utmpPath = defaultUtmpPath; +frg::ticket_spinlock utmpMutex; + +frg::optional utmpFd = frg::null_opt; + +utmp returned; + +} // namespace + +void setutent(void) { + frg::unique_lock lock{utmpMutex}; + + if(!utmpFd) { + int fd; + int err = mlibc::sys_open(utmpPath, O_RDWR | O_CREAT | O_CLOEXEC, 0644, &fd); + if(err) { + mlibc::infoLogger() << "\e[31mmlibc: setutent() failed to open " << utmpPath << ": " + << strerror(err) << "\e[39m" << frg::endlog; + utmpFd = frg::null_opt; + } else { + utmpFd = fd; + } + } else { + off_t discard; + mlibc::sys_seek(utmpFd.value(), 0, SEEK_SET, &discard); + } +} + +struct utmp *getutent(void) { + frg::unique_lock lock{utmpMutex}; + + if(!utmpFd) + setutent(); + if(!utmpFd) { + errno = ENOENT; + return nullptr; + } + + if(int e = mlibc::getUtmpEntry(*utmpFd, &returned); e) { + errno = e; + return nullptr; + } + + return &returned; +} + +int getutent_r(struct utmp *buf, struct utmp **res) { + frg::unique_lock lock{utmpMutex}; + + if(!utmpFd) + setutent(); + if(!utmpFd) { + *res = nullptr; + errno = ENOENT; + return -1; + } + + if(int e = mlibc::getUtmpEntry(*utmpFd, buf); e) { + *res = nullptr; + errno = e; + return -1; + } + + *res = buf; + return 0; +} + +void endutent(void) { + frg::unique_lock lock{utmpMutex}; + + if(utmpFd) { + mlibc::sys_close(utmpFd.value()); + utmpFd = frg::null_opt; + } +} + +struct utmp *pututline(const struct utmp *ut) { + frg::unique_lock lock{utmpMutex}; + + if(!utmpFd) + setutent(); + if(!utmpFd) { + errno = ENOENT; + return nullptr; + } + + if(int e = mlibc::putUtmpEntry(*utmpFd, ut); e) { + errno = e; + return nullptr; + } + + return (utmp *) ut; +} + +struct utmp *getutline(const struct utmp *ut) { + frg::unique_lock lock{utmpMutex}; + + if(!utmpFd) + setutent(); + if(!utmpFd) { + errno = ENOENT; + return nullptr; + } + + if(int e = mlibc::getUtmpEntryByType(*utmpFd, ut, &returned); e) { + errno = e; + return nullptr; + } + + return &returned; +} + +int utmpname(const char *file) { + frg::unique_lock lock{utmpMutex}; + + if(strcmp(file, utmpPath)) { + if(!strcmp(file, defaultUtmpPath)) { + free((void *) utmpPath); + utmpPath = defaultUtmpPath; + } else { + char *name = strdup(file); + if(!name) + return -1; + + if(utmpPath != defaultUtmpPath) + free((void *) utmpPath); + + utmpPath = name; + } + } + + return 0; +} + +struct utmp *getutid(const struct utmp *ut) { + frg::unique_lock lock{utmpMutex}; + + if(!utmpFd) + setutent(); + if(!utmpFd) { + errno = ENOENT; + return nullptr; + } + + if(int e = mlibc::getUtmpEntryById(*utmpFd, ut, &returned); e) { + errno = e; + return nullptr; + } + + return &returned; +} + +void updwtmp(const char *file, const struct utmp *ut) { + int fd; + int err = mlibc::sys_open(file, O_RDWR | O_CREAT | O_CLOEXEC | O_APPEND, 0644, &fd); + if(err) { + mlibc::infoLogger() << "\e[31mmlibc: updwtmp() failed to open " << file << ": " + << strerror(err) << "\e[39m" << frg::endlog; + return; + } + + mlibc::putUtmpEntry(fd, ut); + mlibc::sys_close(fd); +} diff --git a/user/include/mlibc/options/linux/include/bits/linux/cpu_set.h b/user/include/mlibc/options/linux/include/bits/linux/cpu_set.h new file mode 100644 index 0000000..0eff228 --- /dev/null +++ b/user/include/mlibc/options/linux/include/bits/linux/cpu_set.h @@ -0,0 +1,49 @@ +#ifndef _BITS_LINUX_CPU_SET_H +#define _BITS_LINUX_CPU_SET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +cpu_set_t *__mlibc_cpu_alloc(int __num_cpus); +size_t __mlibc_cpu_alloc_size(int __num_cpus); + +void __mlibc_cpu_zero(const size_t __setsize, cpu_set_t *__set); +void __mlibc_cpu_set(const int __cpu, const size_t __setsize, cpu_set_t *__set); +void __mlibc_cpu_clear(const int __cpu, const size_t __setsize, cpu_set_t *__set); +int __mlibc_cpu_isset(const int __cpu, const size_t __setsize, const cpu_set_t *__set); +int __mlibc_cpu_count(const size_t __setsize, const cpu_set_t *__set); + +#define CPU_ALLOC_SIZE(n) __mlibc_cpu_alloc_size((n)) +#define CPU_ALLOC(n) __mlibc_cpu_alloc((n)) +#define CPU_FREE(set) free((set)) + +#define CPU_ZERO_S(setsize, set) __mlibc_cpu_zero((setsize), (set)) +#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t), set) + +#define CPU_SET_S(cpu, setsize, set) __mlibc_cpu_set((cpu), (setsize), (set)) +#define CPU_SET(cpu, set) CPU_SET_S(cpu, sizeof(cpu_set_t), set) + +#define CPU_CLR_S(cpu, setsize, set) __mlibc_cpu_clear((cpu), (setsize), (set)) +#define CPU_CLR(cpu, set) CPU_CLR_S(cpu, sizeof(cpu_set_t), set) + +#define CPU_ISSET_S(cpu, setsize, set) __mlibc_cpu_isset((cpu), (setsize), (set)) +#define CPU_ISSET(cpu, set) CPU_ISSET_S(cpu, sizeof(cpu_set_t), set) + +#define CPU_COUNT_S(setsize, set) __mlibc_cpu_count((setsize), (set)) +#define CPU_COUNT(set) CPU_COUNT_S(sizeof(cpu_set_t), set) + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BITS_LINUX_CPU_SET_H */ diff --git a/user/include/mlibc/options/linux/include/bits/linux/linux_sched.h b/user/include/mlibc/options/linux/include/bits/linux/linux_sched.h new file mode 100644 index 0000000..05f8eca --- /dev/null +++ b/user/include/mlibc/options/linux/include/bits/linux/linux_sched.h @@ -0,0 +1,63 @@ + +#ifndef _BITS_LINUX_SCHED_H +#define _BITS_LINUX_SCHED_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define CLONE_VM 0x00000100 +#define CLONE_FS 0x00000200 +#define CLONE_FILES 0x00000400 +#define CLONE_SIGHAND 0x00000800 +#define CLONE_PIDFD 0x00001000 +#define CLONE_PTRACE 0x00002000 +#define CLONE_VFORK 0x00004000 +#define CLONE_PARENT 0x00008000 +#define CLONE_THREAD 0x00010000 +#define CLONE_NEWNS 0x00020000 +#define CLONE_SYSVSEM 0x00040000 +#define CLONE_SETTLS 0x00080000 +#define CLONE_PARENT_SETTID 0x00100000 +#define CLONE_CHILD_CLEARTID 0x00200000 +#define CLONE_DETACHED 0x00400000 +#define CLONE_UNTRACED 0x00800000 +#define CLONE_CHILD_SETTID 0x01000000 +#define CLONE_NEWCGROUP 0x02000000 +#define CLONE_NEWUTS 0x04000000 +#define CLONE_NEWIPC 0x08000000 +#define CLONE_NEWUSER 0x10000000 +#define CLONE_NEWPID 0x20000000 +#define CLONE_NEWNET 0x40000000 +#define CLONE_IO 0x80000000 + +#define CLONE_CLEAR_SIGHAND 0x100000000ULL +#define CLONE_INTO_CGROUP 0x200000000ULL + +#ifndef __MLIBC_ABI_ONLY + +int sched_getscheduler(pid_t __pid); +int sched_setaffinity(pid_t __pid, size_t __cpusetsize, const cpu_set_t *__mask); +int sched_getaffinity(pid_t __pid, size_t __cpusetsize, cpu_set_t *__mask); + +int unshare(int flags); +int clone(int (*)(void *), void *, int, void *, ...); + +/* Glibc extension */ +int sched_getcpu(void); + +#if defined(_GNU_SOURCE) +int setns(int fd, int nstype); +#endif /* _GNU_SOURCE */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BITS_LINUX_SCHED_H */ diff --git a/user/include/mlibc/options/linux/include/bits/linux/linux_stat.h b/user/include/mlibc/options/linux/include/bits/linux/linux_stat.h new file mode 100644 index 0000000..eeaaeff --- /dev/null +++ b/user/include/mlibc/options/linux/include/bits/linux/linux_stat.h @@ -0,0 +1,20 @@ +#ifndef _BITS_LINUX_STAT_H +#define _BITS_LINUX_STAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int statx(int __dirfd, const char *__pathname, int __flags, unsigned int __mask, struct statx *__statxbuf); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BITS_LINUX_STAT_H */ diff --git a/user/include/mlibc/options/linux/include/bits/linux/linux_uio.h b/user/include/mlibc/options/linux/include/bits/linux/linux_uio.h new file mode 100644 index 0000000..9a90b58 --- /dev/null +++ b/user/include/mlibc/options/linux/include/bits/linux/linux_uio.h @@ -0,0 +1,30 @@ +#ifndef _BITS_LINUX_UIO_H +#define _BITS_LINUX_UIO_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +ssize_t process_vm_readv(pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags); +ssize_t process_vm_writev(pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BITS_LINUX_UIO_H */ diff --git a/user/include/mlibc/options/linux/include/bits/linux/linux_unistd.h b/user/include/mlibc/options/linux/include/bits/linux/linux_unistd.h new file mode 100644 index 0000000..7aa4103 --- /dev/null +++ b/user/include/mlibc/options/linux/include/bits/linux/linux_unistd.h @@ -0,0 +1,21 @@ +#ifndef _BITS_LINUX_UNISTD_H +#define _BITS_LINUX_UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int dup3(int __fd, int __newfd, int __flags); +int vhangup(void); +int getdtablesize(void); +int syncfs(int __fd); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BITS_LINUX_UNISTD_H */ diff --git a/user/include/mlibc/options/linux/include/bits/linux/linux_utmp.h b/user/include/mlibc/options/linux/include/bits/linux/linux_utmp.h new file mode 100644 index 0000000..40ea2c6 --- /dev/null +++ b/user/include/mlibc/options/linux/include/bits/linux/linux_utmp.h @@ -0,0 +1,71 @@ +#ifndef _BITS_LINUX_UTMP_H +#define _BITS_LINUX_UTMP_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UT_LINESIZE 32 +#define UT_NAMESIZE 32 +#define UT_HOSTSIZE 256 + +#define UTMP_FILENAME UTMP_FILE +#define WTMP_FILENAME WTMP_FILE + +struct exit_status { + short int e_termination; + short int e_exit; +}; + +struct utmp { + short ut_type; + pid_t ut_pid; + char ut_line[UT_LINESIZE]; + char ut_id[4]; + char ut_user[UT_NAMESIZE]; + char ut_host[UT_HOSTSIZE]; + struct exit_status ut_exit; + long ut_session; + struct timeval ut_tv; + __mlibc_int32 ut_addr_v6[4]; + char __unused[20]; +}; + +struct lastlog { + time_t ll_time; + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; +}; + +/* Hacks for compability reasons */ +#define ut_name ut_user +#ifndef _NO_UT_TIME +#define ut_time ut_tv.tv_sec +#endif +#define ut_xtime ut_tv.tv_sec +#define ut_addr ut_addr_v6[0] + +#ifndef __MLIBC_ABI_ONLY + +void setutent(void); +struct utmp *getutent(void); +int getutent_r(struct utmp *__buf, struct utmp **__res); +void endutent(void); +struct utmp *pututline(const struct utmp *__line); +struct utmp *getutline(const struct utmp *__line); +struct utmp *getutid(const struct utmp *__id); +int utmpname(const char *__file); +void updwtmp(const char *wtmp_file, const struct utmp *ut); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BITS_LINUX_UTMP_H */ diff --git a/user/include/mlibc/options/linux/include/ifaddrs.h b/user/include/mlibc/options/linux/include/ifaddrs.h new file mode 100644 index 0000000..c57ff3d --- /dev/null +++ b/user/include/mlibc/options/linux/include/ifaddrs.h @@ -0,0 +1,37 @@ + +#ifndef _IFADDRS_H +#define _IFADDRS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* Struct definitions taken from musl */ +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + /* the man page (and glibc) place `ifa_broadaddr` and `ifa_dstaddr` in a union */ + /* TODO: decide whether we should do it, too */ + struct sockaddr *ifa_broadaddr; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +#ifndef __MLIBC_ABI_ONLY + +int getifaddrs(struct ifaddrs **__ifap); +void freeifaddrs(struct ifaddrs *__ifa); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _IFADDRS_H */ diff --git a/user/include/mlibc/options/linux/include/lastlog.h b/user/include/mlibc/options/linux/include/lastlog.h new file mode 100644 index 0000000..a10b0bb --- /dev/null +++ b/user/include/mlibc/options/linux/include/lastlog.h @@ -0,0 +1,2 @@ +/* Maches glibc */ +#include \ No newline at end of file diff --git a/user/include/mlibc/options/linux/include/malloc.h b/user/include/mlibc/options/linux/include/malloc.h new file mode 100644 index 0000000..382dac2 --- /dev/null +++ b/user/include/mlibc/options/linux/include/malloc.h @@ -0,0 +1,32 @@ + +#ifndef _MALLOC_H +#define _MALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +/* [7.22.3] Memory management functions */ +void *calloc(size_t __count, size_t __size); +void free(void *__pointer); +void *malloc(size_t __size); +void *realloc(void *__pointer, size_t __size); +void *memalign(size_t __alignment, size_t __size); + +#if __MLIBC_GLIBC_OPTION +#include +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MALLOC_H */ + diff --git a/user/include/mlibc/options/linux/include/memory.h b/user/include/mlibc/options/linux/include/memory.h new file mode 100644 index 0000000..296f8ad --- /dev/null +++ b/user/include/mlibc/options/linux/include/memory.h @@ -0,0 +1,9 @@ + +#ifndef _MEMORY_H +#define _MEMORY_H + +/* This is a linux extension */ +#include + +#endif /* _MEMORY_H */ + diff --git a/user/include/mlibc/options/linux/include/mlibc/linux-sysdeps.hpp b/user/include/mlibc/options/linux/include/mlibc/linux-sysdeps.hpp new file mode 100644 index 0000000..7aacb24 --- /dev/null +++ b/user/include/mlibc/options/linux/include/mlibc/linux-sysdeps.hpp @@ -0,0 +1,110 @@ +#ifndef MLIBC_LINUX_SYSDEPS +#define MLIBC_LINUX_SYSDEPS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace [[gnu::visibility("hidden")]] mlibc { + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +int sys_close(int fd); +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written); +int sys_ioctl(int fd, unsigned long request, void *arg, int *result); + +[[gnu::weak]] int sys_dup2(int fd, int flags, int newfd); +[[gnu::weak]] int sys_fork(pid_t *child); +[[gnu::weak]] int sys_inotify_create(int flags, int *fd); +[[gnu::weak]] int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd); +[[gnu::weak]] int sys_inotify_rm_watch(int ifd, int wd); +[[gnu::weak]] int sys_epoll_create(int flags, int *fd); +[[gnu::weak]] int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev); +[[gnu::weak]] int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, + int timeout, const sigset_t *sigmask, int *raised); +[[gnu::weak]] int sys_ppoll(struct pollfd *fds, nfds_t count, const struct timespec *ts, + const sigset_t *mask, int *num_events); +[[gnu::weak]] int sys_mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data); +[[gnu::weak]] int sys_umount2(const char *target, int flags); +[[gnu::weak]] int sys_eventfd_create(unsigned int initval, int flags, int *fd); +[[gnu::weak]] int sys_timerfd_create(int clockid, int flags, int *fd); +[[gnu::weak]] int sys_timerfd_settime(int fd, int flags, + const struct itimerspec *value, struct itimerspec *oldvalue); +[[gnu::weak]] int sys_timerfd_gettime(int fd, struct itimerspec *its); +[[gnu::weak]] int sys_signalfd_create(const sigset_t *, int flags, int *fd); +[[gnu::weak]] int sys_reboot(int cmd); +[[gnu::weak]] int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out); +[[gnu::weak]] int sys_prctl(int option, va_list va, int *out); +[[gnu::weak]] int sys_init_module(void *module, unsigned long length, const char *args); +[[gnu::weak]] int sys_delete_module(const char *name, unsigned flags); +[[gnu::weak]] int sys_klogctl(int type, char *bufp, int len, int *out); +[[gnu::weak]] int sys_getcpu(int *cpu); + +[[gnu::weak]] int sys_sysinfo(struct sysinfo *info); +[[gnu::weak]] int sys_swapon(const char *path, int flags); +[[gnu::weak]] int sys_swapoff(const char *path); + +[[gnu::weak]] int sys_setxattr(const char *path, const char *name, + const void *val, size_t size, int flags); +[[gnu::weak]] int sys_lsetxattr(const char *path, const char *name, + const void *val, size_t size, int flags); +[[gnu::weak]] int sys_fsetxattr(int fd, const char *name, const void *val, + size_t size, int flags); + +[[gnu::weak]] int sys_getxattr(const char *path, const char *name, + void *val, size_t size, ssize_t *nread); +[[gnu::weak]] int sys_lgetxattr(const char *path, const char *name, + void *val, size_t size, ssize_t *nread); +[[gnu::weak]] int sys_fgetxattr(int fd, const char *name, void *val, + size_t size, ssize_t *nread); + +[[gnu::weak]] int sys_listxattr(const char *path, char *list, size_t size, + ssize_t *nread); +[[gnu::weak]] int sys_llistxattr(const char *path, char *list, size_t size, + ssize_t *nread); +[[gnu::weak]] int sys_flistxattr(int fd, char *list, size_t size, + ssize_t *nread); + +[[gnu::weak]] int sys_removexattr(const char *path, const char *name); +[[gnu::weak]] int sys_lremovexattr(const char *path, const char *name); +[[gnu::weak]] int sys_fremovexattr(int fd, const char *name); + +[[gnu::weak]] int sys_statfs(const char *path, struct statfs *buf); +[[gnu::weak]] int sys_fstatfs(int fd, struct statfs *buf); + +[[gnu::weak]] int sys_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf); + +[[gnu::weak]] int sys_getifaddrs(struct ifaddrs **); + +[[gnu::weak]] int sys_sendfile(int outfd, int infd, off_t *offset, size_t count, ssize_t *out); +[[gnu::weak]] int sys_syncfs(int fd); +[[gnu::weak]] int sys_unshare(int flags); +[[gnu::weak]] int sys_setns(int fd, int nstype); + +[[gnu::weak]] int sys_pidfd_open(pid_t pid, unsigned int flags, int *outfd); +[[gnu::weak]] int sys_pidfd_getpid(int fd, pid_t *outpid); +[[gnu::weak]] int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags); + +[[gnu::weak]] int sys_process_vm_readv(pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags, ssize_t *out); +[[gnu::weak]] int sys_process_vm_writev(pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags, ssize_t *out); + +} // namespace mlibc + +#endif // MLIBX_LINUX_SYSDEPS diff --git a/user/include/mlibc/options/linux/include/mntent.h b/user/include/mlibc/options/linux/include/mntent.h new file mode 100644 index 0000000..284c4b6 --- /dev/null +++ b/user/include/mlibc/options/linux/include/mntent.h @@ -0,0 +1,50 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#include + +/* TODO: Refer to _PATH_MOUNTED */ +#define MOUNTED "/etc/mtab" + +/* Generic mount options */ +#define MNTOPT_DEFAULTS "defaults" /* Use all default options. */ +#define MNTOPT_RO "ro" /* Read only. */ +#define MNTOPT_RW "rw" /* Read/write. */ +#define MNTOPT_SUID "suid" /* Set uid allowed. */ +#define MNTOPT_NOSUID "nosuid" /* No set uid allowed. */ +#define MNTOPT_NOAUTO "noauto" /* Do not auto mount. */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +#ifndef __MLIBC_ABI_ONLY + +FILE *setmntent(const char *__filename, const char *__type); + +struct mntent *getmntent(FILE *__f); + +int addmntent(FILE *__f, const struct mntent *__mnt); + +int endmntent(FILE *__f); + +char *hasmntopt(const struct mntent *__mnt, const char *__opt); + +struct mntent *getmntent_r(FILE *__f, struct mntent *__mnt, char *__linebuf, int __buflen); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MNTENT_H */ diff --git a/user/include/mlibc/options/linux/include/module.h b/user/include/mlibc/options/linux/include/module.h new file mode 100644 index 0000000..5d84f72 --- /dev/null +++ b/user/include/mlibc/options/linux/include/module.h @@ -0,0 +1,25 @@ +#ifndef _MODULE_H +#define _MODULE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* + * Musl adds these, even though they aren't specified, but doesn't export them. + * See https://github.com/bminor/musl/commit/2169265ec6c902cd460bf96a1a0b5103657a4954 + * for more information and the rationale behind it. + * For our infrastructure, we expose them, and make it call into the sysdeps. + */ +int init_module(void *__module, unsigned long __len, const char *__args); +int delete_module(const char *__name, unsigned __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MODULE_H */ diff --git a/user/include/mlibc/options/linux/include/netpacket/packet.h b/user/include/mlibc/options/linux/include/netpacket/packet.h new file mode 100644 index 0000000..495760f --- /dev/null +++ b/user/include/mlibc/options/linux/include/netpacket/packet.h @@ -0,0 +1,40 @@ +#ifndef _NETPACKET_PACKET_H +#define _NETPACKET_PACKET_H + +#include + +/* Packet types */ +#define PACKET_HOST 0 +#define PACKET_BROADCAST 1 +#define PACKET_MULTICAST 2 +#define PACKET_OTHERHOST 3 +#define PACKET_OUTGOING 4 +#define PACKET_LOOPBACK 5 +#define PACKET_FASTROUTE 6 + +struct sockaddr_ll { + unsigned short int sll_family; + unsigned short int sll_protocol; + int sll_ifindex; + unsigned short int sll_hatype; + unsigned char sll_pkttype; + unsigned char sll_halen; + unsigned char sll_addr[8]; +}; + +struct packet_mreq { + int mr_ifindex; + unsigned short int mr_type; + unsigned short int mr_alen; + unsigned char mr_address[8]; +}; + +#define PACKET_ADD_MEMBERSHIP 1 +#define PACKET_DROP_MEMBERSHIP 2 + +#define PACKET_MR_MULTICAST 0 +#define PACKET_MR_PROMISC 1 +#define PACKET_MR_ALLMULTI 2 +#define PACKET_MR_UNICAST 3 + +#endif /* _NETPACKET_PACKET_H */ diff --git a/user/include/mlibc/options/linux/include/scsi/scsi.h b/user/include/mlibc/options/linux/include/scsi/scsi.h new file mode 100644 index 0000000..fd9cf82 --- /dev/null +++ b/user/include/mlibc/options/linux/include/scsi/scsi.h @@ -0,0 +1,18 @@ + +#ifndef _LINUX_SCSI_SCSI_H +#define _LINUX_SCSI_SCSI_H + +#define RECOVERED_ERROR 0x01 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define INQUIRY 0x12 +#define START_STOP 0x1b +#define ALLOW_MEDIUM_REMOVAL 0x1e + +#define SCSI_IOCTL_GET_IDLUN 0x5382 +#define SCSI_IOCTL_TAGGED_ENABLE 0x5383 +#define SCSI_IOCTL_TAGGED_DISABLE 0x5384 +#define SCSI_IOCTL_PROBE_HOST 0x5385 + +#endif /* _LINUX_SCSI_SCSI_H */ + diff --git a/user/include/mlibc/options/linux/include/scsi/scsi_ioctl.h b/user/include/mlibc/options/linux/include/scsi/scsi_ioctl.h new file mode 100644 index 0000000..888ae39 --- /dev/null +++ b/user/include/mlibc/options/linux/include/scsi/scsi_ioctl.h @@ -0,0 +1,6 @@ + +#ifndef _LINUX_SCSI_SCSI_IOCTL_H +#define _LINUX_SCSI_SCSI_IOCTL_H + +#endif /* _LINUX_SCSI_SCSI_IOCTL_H */ + diff --git a/user/include/mlibc/options/linux/include/scsi/sg.h b/user/include/mlibc/options/linux/include/scsi/sg.h new file mode 100644 index 0000000..30288c9 --- /dev/null +++ b/user/include/mlibc/options/linux/include/scsi/sg.h @@ -0,0 +1,79 @@ + +#ifndef _LINUX_SCSI_SG_H +#define _LINUX_SCSI_SG_H + +#define SG_IO 0x2285 + +#define SG_GET_VERSION_NUM 0x2282 + +#define SG_FLAG_DIRECT_IO 1 +#define SG_FLAG_LUN_INHIBIT 2 + +#define SG_INFO_OK 0x0 +#define SG_INFO_OK_MASK 0x1 + +#define SG_DXFER_NONE (-1) +#define SG_DXFER_TO_DEV (-2) +#define SG_DXFER_FROM_DEV (-3) +#define SG_DXFER_TO_FROM_DEV (-4) + +#define SG_INFO_CHECK 0x1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sg_io_hdr { + int interface_id; + int dxfer_direction; + unsigned char cmd_len; + unsigned char mx_sb_len; + unsigned short iovec_count; + unsigned int dxfer_len; + void *dxferp; + unsigned char *cmdp; + unsigned char *sbp; + unsigned int timeout; + unsigned int flags; + int pack_id; + void *usr_ptr; + unsigned char status; + unsigned char masked_status; + unsigned char msg_status; + unsigned char sb_len_wr; + unsigned short host_status; + unsigned short driver_status; + int resid; + unsigned int duration; + unsigned int info; +} sg_io_hdr_t; + +struct sg_scsi_id { + int host_no; + int channel; + int scsi_id; + int lun; + int scsi_type; + short int h_cmd_per_lun; + short int d_queue_depth; + int unused[2]; +}; + +typedef struct sg_req_info { + char req_state; + char orphan; + char sg_io_owned; + char problem; + int pack_id; + void *usr_ptr; + unsigned int duration; + + int unused; +} sg_req_info_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _LINUX_SCSI_SG_H */ + diff --git a/user/include/mlibc/options/linux/include/sys/epoll.h b/user/include/mlibc/options/linux/include/sys/epoll.h new file mode 100644 index 0000000..aca9b13 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/epoll.h @@ -0,0 +1,66 @@ +#ifndef _SYS_EPOLL_H +#define _SYS_EPOLL_H + +#include +#include +#include +#include + +#define EPOLL_NONBLOCK O_NONBLOCK + +/* These constants match the Linux definitions. */ +#define EPOLLIN 0x001 +#define EPOLLPRI 0x002 +#define EPOLLOUT 0x004 +#define EPOLLRDNORM 0x040 +#define EPOLLRDBAND 0x080 +#define EPOLLWRNORM 0x100 +#define EPOLLWRBAND 0x200 +#define EPOLLMSG 0x400 +#define EPOLLERR 0x008 +#define EPOLLHUP 0x010 +#define EPOLLRDHUP 0x2000 +#define EPOLLEXCLUSIVE (1U << 28) +#define EPOLLWAKEUP (1U << 29) +#define EPOLLONESHOT (1U << 30) +#define EPOLLET (1U << 31) + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union epoll_data { + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; +} epoll_data_t; + +struct epoll_event { + uint32_t events; + epoll_data_t data; +} +#ifdef __x86_64__ +__attribute__((__packed__)) +#endif +; + +#ifndef __MLIBC_ABI_ONLY + +int epoll_create(int __flags); +int epoll_create1(int __flags); +int epoll_ctl(int __epfd, int __mode, int __fd, struct epoll_event *__ev); +int epoll_wait(int __epfd, struct epoll_event *__events, int __maxevents, int __timeout); +int epoll_pwait(int __epfd, struct epoll_event *__events, int __maxevents, int __timeout, const sigset_t *__sigmask); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_EPOLL_H */ diff --git a/user/include/mlibc/options/linux/include/sys/eventfd.h b/user/include/mlibc/options/linux/include/sys/eventfd.h new file mode 100644 index 0000000..74b200d --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/eventfd.h @@ -0,0 +1,29 @@ +#ifndef _SYS_EVENTFD_H +#define _SYS_EVENTFD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef uint64_t eventfd_t; + +#define EFD_SEMAPHORE 1 +#define EFD_CLOEXEC O_CLOEXEC +#define EFD_NONBLOCK O_NONBLOCK + +#ifndef __MLIBC_ABI_ONLY + +int eventfd(unsigned int __initval, int __flags); +int eventfd_read(int __fd, eventfd_t *__value); +int eventfd_write(int __fd, eventfd_t __value); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_EVENTFD_H */ diff --git a/user/include/mlibc/options/linux/include/sys/fsuid.h b/user/include/mlibc/options/linux/include/sys/fsuid.h new file mode 100644 index 0000000..0fa0fb3 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/fsuid.h @@ -0,0 +1,22 @@ +#ifndef _SYS_FSUID_H +#define _SYS_FSUID_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int setfsuid(uid_t __uid); +int setfsgid(gid_t __gid); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_FSUID_H */ diff --git a/user/include/mlibc/options/linux/include/sys/inotify.h b/user/include/mlibc/options/linux/include/sys/inotify.h new file mode 100644 index 0000000..bf9c7c5 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/inotify.h @@ -0,0 +1,71 @@ +#ifndef _SYS_INOTIFY_H +#define _SYS_INOTIFY_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IN_ACCESS 0x1 +#define IN_ATTRIB 0x4 +#define IN_CLOSE_WRITE 0x8 +#define IN_CLOSE_NOWRITE 0x10 +#define IN_CREATE 0x100 +#define IN_DELETE 0x200 +#define IN_DELETE_SELF 0x400 +#define IN_MODIFY 0x2 +#define IN_MOVE_SELF 0x800 +#define IN_MOVED_FROM 0x40 +#define IN_MOVED_TO 0x80 +#define IN_OPEN 0x20 +#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) +#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) +#define IN_DONT_FOLLOW 0x2000000 +#define IN_EXCL_UNLINK 0x4000000 +#define IN_MASK_ADD 0x20000000 +#define IN_ONESHOT 0x80000000 +#define IN_ONLYDIR 0x1000000 +#define IN_IGNORED 0x8000 +#define IN_ISDIR 0x40000000 +#define IN_Q_OVERFLOW 0x4000 +#define IN_UNMOUNT 0x2000 + +#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \ + IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \ + IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \ + IN_MOVE_SELF) + +struct inotify_event { + int wd; + unsigned int mask; + unsigned int cookie; + unsigned int len; + +/* + * glibc uses a flexible array member here, but we get a warning and they don't: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117241 + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + char name[]; +#pragma GCC diagnostic pop +}; + +#ifndef __MLIBC_ABI_ONLY + +int inotify_init(void); +int inotify_init1(int __flags); +int inotify_add_watch(int __ifd, const char *__path, uint32_t __mask); +int inotify_rm_watch(int __ifd, int __wd); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /*_SYS_INOTIFY_H */ + diff --git a/user/include/mlibc/options/linux/include/sys/klog.h b/user/include/mlibc/options/linux/include/sys/klog.h new file mode 100644 index 0000000..f5bd628 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/klog.h @@ -0,0 +1,18 @@ +#ifndef _SYS_KLOG_H +#define _SYS_KLOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int klogctl(int __type, char *__bufp, int __len); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_KLOG_H */ diff --git a/user/include/mlibc/options/linux/include/sys/mount.h b/user/include/mlibc/options/linux/include/sys/mount.h new file mode 100644 index 0000000..8be8857 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/mount.h @@ -0,0 +1,90 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MS_RDONLY 1 +#define MS_NOSUID 2 +#define MS_NODEV 4 +#define MS_NOEXEC 8 +#define MS_SYNCHRONOUS 16 +#define MS_REMOUNT 32 +#define MS_MANDLOCK 64 +#define MS_DIRSYNC 128 +#define MS_NOSYMFOLLOW 256 +#define MS_NOATIME 1024 +#define MS_NODIRATIME 2048 +#define MS_BIND 4096 +#define MS_MOVE 8192 +#define MS_REC 16384 +#define MS_SILENT 32768 +#define MS_POSIXACL (1 << 16) +#define MS_UNBINDABLE (1 << 17) +#define MS_PRIVATE (1 << 18) +#define MS_SLAVE (1 << 19) +#define MS_SHARED (1 << 20) +#define MS_RELATIME (1 << 21) +#define MS_KERNMOUNT (1 << 22) +#define MS_I_VERSION (1 << 23) +#define MS_STRICTATIME (1 << 24) +#define MS_LAZYTIME (1 << 25) +#define MS_NOREMOTELOCK (1 << 27) +#define MS_NOSEC (1 << 28) +#define MS_BORN (1 << 29) +#define MS_ACTIVE (1 << 30) +#define MS_NOUSER (1 << 31) + +#define MNT_FORCE 1 +#define MNT_DETACH 2 +#define MNT_EXPIRE 4 +#define UMOUNT_NOFOLLOW 8 + +#undef BLKROSET +#define BLKROSET _IO(0x12, 93) +#undef BLKROGET +#define BLKROGET _IO(0x12, 94) +#undef BLKRRPART +#define BLKRRPART _IO(0x12, 95) +#undef BLKGETSIZE +#define BLKGETSIZE _IO(0x12, 96) +#undef BLKFLSBUF +#define BLKFLSBUF _IO(0x12, 97) +#undef BLKRASET +#define BLKRASET _IO(0x12, 98) +#undef BLKRAGET +#define BLKRAGET _IO(0x12, 99) +#undef BLKFRASET +#define BLKFRASET _IO(0x12, 100) +#undef BLKFRAGET +#define BLKFRAGET _IO(0x12, 101) +#undef BLKSECTSET +#define BLKSECTSET _IO(0x12, 102) +#undef BLKSECTGET +#define BLKSECTGET _IO(0x12, 103) +#undef BLKSSZGET +#define BLKSSZGET _IO(0x12, 104) +#undef BLKBSZGET +#define BLKBSZGET _IOR(0x12, 112, size_t) +#undef BLKBSZSET +#define BLKBSZSET _IOW(0x12, 113, size_t) +#undef BLKGETSIZE64 +#define BLKGETSIZE64 _IOR(0x12, 114, size_t) + +#ifndef __MLIBC_ABI_ONLY + +int mount(const char *__source, const char *__target, + const char *__fstype, unsigned long __flags, const void *__data); +int umount(const char *__target); +int umount2(const char *__target, int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MOUNT_H */ diff --git a/user/include/mlibc/options/linux/include/sys/pidfd.h b/user/include/mlibc/options/linux/include/sys/pidfd.h new file mode 100644 index 0000000..37f375e --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/pidfd.h @@ -0,0 +1,26 @@ +#ifndef _SYS_PIDFD_H +#define _SYS_PIDFD_H + +#include +#include +#include + +#define PIDFD_NONBLOCK O_NONBLOCK + +#ifndef __MLIBC_ABI_ONLY + +#ifdef __cplusplus +extern "C" { +#endif + +int pidfd_open(pid_t __pid, unsigned int __flags); +pid_t pidfd_getpid(int __fd); +int pidfd_send_signal(int __pidfd, int __sig, siginfo_t *__info, unsigned int __flags); + +#ifdef __cplusplus +} +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif /* _SYS_PIDFD_H */ diff --git a/user/include/mlibc/options/linux/include/sys/prctl.h b/user/include/mlibc/options/linux/include/sys/prctl.h new file mode 100644 index 0000000..61e9eb5 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/prctl.h @@ -0,0 +1,128 @@ + +#ifndef _SYS_PRCTL_H +#define _SYS_PRCTL_H + +#include + +#define PR_SET_PDEATHSIG 1 +#define PR_GET_PDEATHSIG 2 +#define PR_GET_DUMPABLE 3 +#define PR_SET_DUMPABLE 4 +#define PR_GET_UNALIGN 5 +#define PR_SET_UNALIGN 6 +#define PR_UNALIGN_NOPRINT 1 +#define PR_UNALIGN_SIGBUS 2 +#define PR_GET_KEEPCAPS 7 +#define PR_SET_KEEPCAPS 8 +#define PR_GET_FPEMU 9 +#define PR_SET_FPEMU 10 +#define PR_FPEMU_NOPRINT 1 +#define PR_FPEMU_SIGFPE 2 +#define PR_GET_FPEXC 11 +#define PR_SET_FPEXC 12 +#define PR_FP_EXC_SW_ENABLE 0x80 +#define PR_FP_EXC_DIV 0x010000 +#define PR_FP_EXC_OVF 0x020000 +#define PR_FP_EXC_UND 0x040000 +#define PR_FP_EXC_RES 0x080000 +#define PR_FP_EXC_INV 0x100000 +#define PR_FP_EXC_DISABLED 0 +#define PR_FP_EXC_NONRECOV 1 +#define PR_FP_EXC_ASYNC 2 +#define PR_FP_EXC_PRECISE 3 +#define PR_GET_TIMING 13 +#define PR_SET_TIMING 14 +#define PR_TIMING_STATISTICAL 0 +#define PR_TIMING_TIMESTAMP 1 +#define PR_SET_NAME 15 +#define PR_GET_NAME 16 +#define PR_GET_ENDIAN 19 +#define PR_SET_ENDIAN 20 +#define PR_ENDIAN_BIG 0 +#define PR_ENDIAN_LITTLE 1 +#define PR_ENDIAN_PPC_LITTLE 2 +#define PR_GET_SECCOMP 21 +#define PR_SET_SECCOMP 22 +#define PR_CAPBSET_READ 23 +#define PR_CAPBSET_DROP 24 +#define PR_GET_TSC 25 +#define PR_SET_TSC 26 +#define PR_TSC_ENABLE 1 +#define PR_TSC_SIGSEGV 2 +#define PR_GET_SECUREBITS 27 +#define PR_SET_SECUREBITS 28 +#define PR_SET_TIMERSLACK 29 +#define PR_GET_TIMERSLACK 30 + +#define PR_TASK_PERF_EVENTS_DISABLE 31 +#define PR_TASK_PERF_EVENTS_ENABLE 32 + +#define PR_MCE_KILL 33 +#define PR_MCE_KILL_CLEAR 0 +#define PR_MCE_KILL_SET 1 +#define PR_MCE_KILL_LATE 0 +#define PR_MCE_KILL_EARLY 1 +#define PR_MCE_KILL_DEFAULT 2 +#define PR_MCE_KILL_GET 34 + +#define PR_SET_MM 35 +#define PR_SET_MM_START_CODE 1 +#define PR_SET_MM_END_CODE 2 +#define PR_SET_MM_START_DATA 3 +#define PR_SET_MM_END_DATA 4 +#define PR_SET_MM_START_STACK 5 +#define PR_SET_MM_START_BRK 6 +#define PR_SET_MM_BRK 7 +#define PR_SET_MM_ARG_START 8 +#define PR_SET_MM_ARG_END 9 +#define PR_SET_MM_ENV_START 10 +#define PR_SET_MM_ENV_END 11 +#define PR_SET_MM_AUXV 12 +#define PR_SET_MM_EXE_FILE 13 +#define PR_SET_MM_MAP 14 +#define PR_SET_MM_MAP_SIZE 15 + +#define PR_SET_PTRACER 0x59616d61 +#define PR_SET_PTRACER_ANY (-1UL) + +#define PR_SET_CHILD_SUBREAPER 36 +#define PR_GET_CHILD_SUBREAPER 37 + +#define PR_SET_NO_NEW_PRIVS 38 +#define PR_GET_NO_NEW_PRIVS 39 + +#define PR_GET_TID_ADDRESS 40 + +#define PR_SET_THP_DISABLE 41 +#define PR_GET_THP_DISABLE 42 + +#define PR_MPX_ENABLE_MANAGEMENT 43 +#define PR_MPX_DISABLE_MANAGEMENT 44 + +#define PR_SET_FP_MODE 45 +#define PR_GET_FP_MODE 46 +#define PR_FP_MODE_FR (1 << 0) +#define PR_FP_MODE_FRE (1 << 1) + +#define PR_CAP_AMBIENT 47 +#define PR_CAP_AMBIENT_IS_SET 1 +#define PR_CAP_AMBIENT_RAISE 2 +#define PR_CAP_AMBIENT_LOWER 3 +#define PR_CAP_AMBIENT_CLEAR_ALL 4 + +#ifndef __MLIBC_ABI_ONLY + +#ifdef __cplusplus +extern "C" { +#endif + +int prctl(int __op, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif /* _SYS_PRCTL_H */ + diff --git a/user/include/mlibc/options/linux/include/sys/ptrace.h b/user/include/mlibc/options/linux/include/sys/ptrace.h new file mode 100644 index 0000000..915b01d --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/ptrace.h @@ -0,0 +1,55 @@ + +#ifndef _SYS_PTRACE_H +#define _SYS_PTRACE_H + +#include +#include + +#define PTRACE_TRACEME 0 +#define PT_TRACE_ME PTRACE_TRACEME + +#define PT_READ_I PTRACE_PEEKTEXT +#define PT_READ_D PTRACE_PEEKDATA +#define PT_READ_U PTRACE_PEEKUSER +#define PT_WRITE_I PTRACE_POKETEXT +#define PT_WRITE_D PTRACE_POKEDATA +#define PT_WRITE_U PTRACE_POKEUSER +#define PT_CONTINUE PTRACE_CONT +#define PT_KILL PTRACE_KILL +#define PT_STEP PTRACE_SINGLESTEP +#define PT_GETREGS PTRACE_GETREGS +#define PT_SETREGS PTRACE_SETREGS +#define PT_GETFPREGS PTRACE_GETFPREGS +#define PT_SETFPREGS PTRACE_SETFPREGS +#define PT_ATTACH PTRACE_ATTACH +#define PT_DETACH PTRACE_DETACH +#define PT_GETFPXREGS PTRACE_GETFPXREGS +#define PT_SETFPXREGS PTRACE_SETFPXREGS +#define PT_SYSCALL PTRACE_SYSCALL +#define PT_SETOPTIONS PTRACE_SETOPTIONS +#define PT_GETEVENTMSG PTRACE_GETEVENTMSG +#define PT_GETSIGINFO PTRACE_GETSIGINFO +#define PT_SETSIGINFO PTRACE_SETSIGINFO + +#ifdef __cplusplus +extern "C" { +#endif + +struct ptrace_peeksiginfo_args { + uint64_t offset; + uint32_t flags; + int32_t nr; +}; + +#ifndef __MLIBC_ABI_ONLY + +long ptrace(int __op, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PTRACE_H */ + diff --git a/user/include/mlibc/options/linux/include/sys/quota.h b/user/include/mlibc/options/linux/include/sys/quota.h new file mode 100644 index 0000000..8f6ea05 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/quota.h @@ -0,0 +1,24 @@ +#ifndef _SYS_QUOTA_H +#define _SYS_QUOTA_H + +#include + +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int quotactl(int __cmd, const char *__special, int __id, caddr_t __addr); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_QUOTA_H */ diff --git a/user/include/mlibc/options/linux/include/sys/random.h b/user/include/mlibc/options/linux/include/sys/random.h new file mode 100644 index 0000000..e51e0d1 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/random.h @@ -0,0 +1,24 @@ + +#ifndef _SYS_RANDOM_H +#define _SYS_RANDOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +ssize_t getrandom(void *__buffer, size_t __max_size, unsigned int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /*_SYS_RANDOM_H */ + diff --git a/user/include/mlibc/options/linux/include/sys/reboot.h b/user/include/mlibc/options/linux/include/sys/reboot.h new file mode 100644 index 0000000..5983882 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/reboot.h @@ -0,0 +1,20 @@ +#ifndef MLIBC_SYS_REBOOT_H +#define MLIBC_SYS_REBOOT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int reboot(int __arg); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_SYS_REBOOT_H */ diff --git a/user/include/mlibc/options/linux/include/sys/sendfile.h b/user/include/mlibc/options/linux/include/sys/sendfile.h new file mode 100644 index 0000000..4a0c359 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/sendfile.h @@ -0,0 +1,22 @@ + +#ifndef _SYS_SENDFILE_H_ +#define _SYS_SENDFILE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +ssize_t sendfile(int __out_fd, int __in_fd, off_t *__offset, size_t __size); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SENDFILE_H_ */ + diff --git a/user/include/mlibc/options/linux/include/sys/signalfd.h b/user/include/mlibc/options/linux/include/sys/signalfd.h new file mode 100644 index 0000000..13327c1 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/signalfd.h @@ -0,0 +1,48 @@ +#ifndef _SYS_SIGNALFD_H +#define _SYS_SIGNALFD_H + +/* TODO: Define sigset separately and remove this include. */ +#include +/* musl includes those. Restructure this so we do not need them? */ +#include +#include + +#define SFD_CLOEXEC O_CLOEXEC +#define SFD_NONBLOCK O_NONBLOCK + +#ifdef __cplusplus +extern "C" { +#endif + +struct signalfd_siginfo { + uint32_t ssi_signo; + int32_t ssi_errno; + int32_t ssi_code; + uint32_t ssi_pid; + uint32_t ssi_uid; + int32_t ssi_fd; + uint32_t ssi_tid; + uint32_t ssi_band; + uint32_t ssi_overrun; + uint32_t ssi_trapno; + int32_t ssi_status; + int32_t ssi_int; + uint64_t ssi_ptr; + uint64_t ssi_utime; + uint64_t ssi_stime; + uint64_t ssi_addr; + uint16_t ssi_addr_lsb; + uint8_t pad[128-12*4-4*8-2]; +}; + +#ifndef __MLIBC_ABI_ONLY + +int signalfd(int __fd, const sigset_t *__mask, int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SIGNALFD_H */ diff --git a/user/include/mlibc/options/linux/include/sys/statfs.h b/user/include/mlibc/options/linux/include/sys/statfs.h new file mode 100644 index 0000000..c446307 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/statfs.h @@ -0,0 +1,23 @@ +#ifndef _SYS_STATFS_H +#define _SYS_STATFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int statfs(const char *__path, struct statfs *__buf); +int fstatfs(int __fd, struct statfs *__buf); +int fstatfs64(int __fd, struct statfs64 *__buf); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_STATFS_H */ + diff --git a/user/include/mlibc/options/linux/include/sys/swap.h b/user/include/mlibc/options/linux/include/sys/swap.h new file mode 100644 index 0000000..8beb44d --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/swap.h @@ -0,0 +1,24 @@ +#ifndef _SYS_SWAP_H +#define _SYS_SWAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SWAP_FLAG_PREFER 0x8000 +#define SWAP_FLAG_PRIO_MASK 0x7fff +#define SWAP_FLAG_PRIO_SHIFT 0 +#define SWAP_FLAG_DISCARD 0x10000 + +#ifndef __MLIBC_ABI_ONLY + +int swapon(const char *__path, int __flags); +int swapoff(const char *__path); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SWAP_H */ diff --git a/user/include/mlibc/options/linux/include/sys/sysinfo.h b/user/include/mlibc/options/linux/include/sys/sysinfo.h new file mode 100644 index 0000000..194b94e --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/sysinfo.h @@ -0,0 +1,46 @@ +#ifndef _SYS_SYSINFO_H +#define _SYS_SYSINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* TODO: This is from the Linux ABI. Make this an abi-bit. */ + +struct sysinfo { + long uptime; + unsigned long loads[3]; + unsigned long totalram; + unsigned long freeram; + unsigned long sharedram; + unsigned long bufferram; + unsigned long totalswap; + unsigned long freeswap; + unsigned short procs; + unsigned long totalhigh; + unsigned long freehigh; + unsigned int mem_unit; + + /* This is how the kernel header defines it, so suppress the warning. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + char _f[20 - 2 * sizeof(long) - sizeof(int)]; /* Padding to 64 bytes according to my man page */ +#pragma GCC diagnostic pop +}; + +#define SI_LOAD_SHIFT 16 + +#ifndef __MLIBC_ABI_ONLY + +int sysinfo(struct sysinfo *__info); + +int get_nprocs(void); +int get_nprocs_conf(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SYSINFO_H */ diff --git a/user/include/mlibc/options/linux/include/sys/sysmacros.h b/user/include/mlibc/options/linux/include/sys/sysmacros.h new file mode 100644 index 0000000..98b6580 --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/sysmacros.h @@ -0,0 +1,35 @@ +#ifndef _SYS_SYSMACROS_H +#define _SYS_SYSMACROS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +__MLIBC_INLINE_DEFINITION unsigned int __mlibc_dev_major( + unsigned long long int __dev) { + return ((__dev >> 8) & 0xfff) | ((unsigned int)(__dev >> 32) & ~0xfff); +} + +__MLIBC_INLINE_DEFINITION unsigned int __mlibc_dev_minor( + unsigned long long int __dev) { + return (__dev & 0xff) | ((unsigned int)(__dev >> 12) & ~0xff); +} + +__MLIBC_INLINE_DEFINITION unsigned long long int __mlibc_dev_makedev( + unsigned int __major, unsigned int __minor) { + return ((__minor & 0xff) | ((__major & 0xfff) << 8) + | (((unsigned long long int)(__minor & ~0xff)) << 12) + | (((unsigned long long int)(__major & ~0xfff)) << 32)); +} + +#define major(dev) __mlibc_dev_major(dev) +#define minor(dev) __mlibc_dev_minor(dev) +#define makedev(major, minor) __mlibc_dev_makedev(major, minor) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SYSMACROS_H */ diff --git a/user/include/mlibc/options/linux/include/sys/timerfd.h b/user/include/mlibc/options/linux/include/sys/timerfd.h new file mode 100644 index 0000000..5caac5d --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/timerfd.h @@ -0,0 +1,32 @@ +#ifndef _SYS_TIMERFD_H +#define _SYS_TIMERFD_H + +/* musl includes those. Refactor and remove them? */ +#include +#include + +#define TFD_NONBLOCK O_NONBLOCK +#define TFD_CLOEXEC O_CLOEXEC + +#define TFD_TIMER_ABSTIME 1 +#define TFD_TIMER_CANCEL_ON_SET (1 << 1) + +#ifdef __cplusplus +extern "C" { +#endif + +struct itimerspec; + +#ifndef __MLIBC_ABI_ONLY + +int timerfd_create(int __clockid, int __flags); +int timerfd_settime(int __fd, int __flags, const struct itimerspec *__value, struct itimerspec *__oldvalue); +int timerfd_gettime(int __fd, struct itimerspec *__value); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIMERFD_H */ diff --git a/user/include/mlibc/options/linux/include/sys/vfs.h b/user/include/mlibc/options/linux/include/sys/vfs.h new file mode 100644 index 0000000..7e7e60d --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/vfs.h @@ -0,0 +1,16 @@ + +#ifndef _SYS_VFS_H +#define _SYS_VFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_VFS_H */ + diff --git a/user/include/mlibc/options/linux/include/sys/vt.h b/user/include/mlibc/options/linux/include/sys/vt.h new file mode 100644 index 0000000..b0518ed --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/vt.h @@ -0,0 +1,6 @@ +#ifndef _SYS_VT_H +#define _SYS_VT_H + +#include + +#endif /* _SYS_VT_H */ diff --git a/user/include/mlibc/options/linux/include/sys/xattr.h b/user/include/mlibc/options/linux/include/sys/xattr.h new file mode 100644 index 0000000..1b9486d --- /dev/null +++ b/user/include/mlibc/options/linux/include/sys/xattr.h @@ -0,0 +1,38 @@ +#ifndef _MLIBC_LINUX_SYS_XATTR_H +#define _MLIBC_LINUX_SYS_XATTR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int setxattr(const char *__path, const char *__name, const void *__val, size_t __size, + int __flags); +int lsetxattr(const char *__path, const char *__name, const void *__val, size_t __size, + int __flags); +int fsetxattr(int __fd, const char *__name, const void *__val, size_t __size, + int __flags); + +ssize_t getxattr(const char *__path, const char *__name, void *__val, size_t __size); +ssize_t lgetxattr(const char *__path, const char *__name, void *__val, size_t __size); +ssize_t fgetxattr(int __fd, const char *__name, void *__val, size_t __size); + +ssize_t listxattr(const char *__path, char *__list, size_t __size); +ssize_t llistxattr(const char *__path, char *__list, size_t __size); +ssize_t flistxattr(int __fd, char *__list, size_t __size); + +int removexattr(const char *__path, const char *__name); +int lremovexattr(const char *__path, const char *__name); +int fremovexattr(int __fd, const char *__name); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MLIBC_LINUX_SYS_XATTR_H */ diff --git a/user/include/mlibc/options/linux/include/values.h b/user/include/mlibc/options/linux/include/values.h new file mode 100644 index 0000000..75a4345 --- /dev/null +++ b/user/include/mlibc/options/linux/include/values.h @@ -0,0 +1,39 @@ + +#ifndef _VALUES_H +#define _VALUES_H + +#include +#include + +#define CHARBITS (sizeof(char) * 8) +#define SHORTBITS (sizeof(short) * 8) +#define INTBITS (sizeof(int) * 8) +#define LONGBITS (sizeof(long) * 8) +#define PTRBITS (sizeof(char *) * 8) +#define DOUBLEBITS (sizeof(double) * 8) +#define FLOATBITS (sizeof(float) * 8) + +#define MINSHORT SHRT_MIN +#define MININT INT_MIN +#define MINLONG LONG_MIN + +#define MAXSHORT SHRT_MAX +#define MAXINT INT_MAX +#define MAXLONG LONG_MAX + +#define HIBITS MINSHORT +#define HIBITL MINLONG + +#define MAXDOUBLE DBL_MAX +#define MAXFLOAT FLT_MAX +#define MINDOUBLE DBL_MIN +#define MINFLOAT FLT_MIN +#define DMINEXP DBL_MIN_EXP +#define FMINEXP FLT_MIN_EXP +#define DMAXEXP DBL_MAX_EXP +#define FMAXEXP FLT_MAX_EXP + +#define BITSPERBYTE CHAR_BIT + +#endif /* _VALUES_H */ + diff --git a/user/include/mlibc/options/linux/meson.build b/user/include/mlibc/options/linux/meson.build new file mode 100644 index 0000000..4fff1f9 --- /dev/null +++ b/user/include/mlibc/options/linux/meson.build @@ -0,0 +1,94 @@ + +if not linux_option + subdir_done() +endif +libc_sources += files( + 'generic/mntent.cpp', + 'generic/sys-epoll.cpp', + 'generic/sys-inotify.cpp', + 'generic/sys-mount.cpp', + 'generic/sys-prctl.cpp', + 'generic/sys-ptrace.cpp', + 'generic/sys-random.cpp', + 'generic/sys-sendfile.cpp', + 'generic/sys-signalfd.cpp', + 'generic/sys-timerfd.cpp', + 'generic/sys-uio.cpp', + 'generic/sys-eventfd.cpp', + 'generic/sys-reboot.cpp', + 'generic/sys-xattr.cpp', + 'generic/utmp.cpp', + 'generic/linux-unistd.cpp', + 'generic/malloc.cpp', + 'generic/sys-fsuid.cpp', + 'generic/ifaddrs.cpp', + 'generic/sys-sysinfo.cpp', + 'generic/module.cpp', + 'generic/sys-klog.cpp', + 'generic/sched.cpp', + 'generic/sys-quota.cpp', + 'generic/capabilities.cpp', + 'generic/cpuset.cpp', + 'generic/sys-swap.cpp', + 'generic/sys-statfs.cpp', + 'generic/sys-statx.cpp', + 'generic/sys-pidfd.cpp', +) + +if not no_headers + install_headers( + 'include/ifaddrs.h', + 'include/malloc.h', + 'include/memory.h', + 'include/mntent.h', + 'include/values.h', + 'include/lastlog.h', + 'include/module.h', + ) + install_headers( + 'include/bits/linux/linux_unistd.h', + 'include/bits/linux/linux_sched.h', + 'include/bits/linux/linux_stat.h', + 'include/bits/linux/linux_uio.h', + 'include/bits/linux/linux_utmp.h', + 'include/bits/linux/cpu_set.h', + subdir: 'bits/linux' + ) + install_headers( + 'include/netpacket/packet.h', + subdir: 'netpacket' + ) + # libc provides these, not the kernel, so the Linux option shall provide them too. + install_headers( + 'include/scsi/scsi.h', + 'include/scsi/scsi_ioctl.h', + 'include/scsi/sg.h', + subdir: 'scsi' + ) + install_headers( + 'include/sys/epoll.h', + 'include/sys/inotify.h', + 'include/sys/mount.h', + 'include/sys/prctl.h', + 'include/sys/ptrace.h', + 'include/sys/random.h', + 'include/sys/sendfile.h', + 'include/sys/signalfd.h', + 'include/sys/sysmacros.h', + 'include/sys/timerfd.h', + 'include/sys/eventfd.h', + 'include/sys/reboot.h', + 'include/sys/fsuid.h', + 'include/sys/vt.h', + 'include/sys/sysinfo.h', + 'include/sys/klog.h', + 'include/sys/xattr.h', + 'include/sys/quota.h', + 'include/sys/swap.h', + 'include/sys/statfs.h', + 'include/sys/vfs.h', + 'include/sys/pidfd.h', + subdir: 'sys' + ) +endif + diff --git a/user/include/mlibc/options/lsb/generic/auxv.cpp b/user/include/mlibc/options/lsb/generic/auxv.cpp new file mode 100644 index 0000000..a4d2c8f --- /dev/null +++ b/user/include/mlibc/options/lsb/generic/auxv.cpp @@ -0,0 +1,59 @@ + +#include +#include +#include + +#include + +extern "C" uintptr_t *__dlapi_entrystack(); + +int peekauxval(unsigned long type, unsigned long *out) { + // Find the auxiliary vector by skipping args and environment. + auto aux = __dlapi_entrystack(); + aux += *aux + 1; // Skip argc and all arguments + __ensure(!*aux); + aux++; + while(*aux) // Now, we skip the environment. + aux++; + aux++; + + // Parse the auxiliary vector. + while(true) { + auto value = aux + 1; + if(*aux == AT_NULL) { + errno = ENOENT; + return -1; + }else if(*aux == type) { + *out = *value; + return 0; + } + aux += 2; + } +} + +unsigned long getauxval(unsigned long type) { + unsigned long value = 0; + if(peekauxval(type, &value)) + return 0; + return value; +} + +// XXX(qookie): +// This is here because libgcc will call into __getauxval on glibc Linux +// (which is what it believes we are due to the aarch64-linux-gnu toolchain) +// in order to find AT_HWCAP to discover if LSE atomics are supported. +// +// This is not necessary on a custom Linux toolchain and is purely an artifact of +// using the host toolchain. + +// __gnu_linux__ is the define checked by libgcc +#if defined(__aarch64__) && defined(__gnu_linux__) + +extern "C" unsigned long __getauxval(unsigned long type) { + unsigned long value = 0; + if(peekauxval(type, &value)) + return 0; + return value; +} + +#endif diff --git a/user/include/mlibc/options/lsb/generic/dso_exit.cpp b/user/include/mlibc/options/lsb/generic/dso_exit.cpp new file mode 100644 index 0000000..bc9ba1b --- /dev/null +++ b/user/include/mlibc/options/lsb/generic/dso_exit.cpp @@ -0,0 +1,88 @@ + +// for memcpy() +#include + +#include +#include + +#include +#include + +struct ExitHandler { + void (*function)(void *); + void *argument; + void *dsoHandle; +}; + +using ExitQueue = frg::vector; + +ExitQueue &getExitQueue() { + // use frg::eternal to prevent the compiler from scheduling the destructor + // by generating a call to __cxa_atexit(). + static frg::eternal singleton(getAllocator()); + return singleton.get(); +} + +extern "C" int __cxa_atexit(void (*function)(void *), void *argument, void *handle) { + ExitHandler handler; + handler.function = function; + handler.argument = argument; + handler.dsoHandle = handle; + getExitQueue().push(handler); + return 0; +} + +extern "C" void __dlapi_exit(); + +extern "C" void __cxa_finalize(void *dso) { + ExitQueue &eq = getExitQueue(); + for (size_t i = eq.size(); i > 0; i--) { + auto &handler = eq[i - 1]; + if (!handler.function) + continue; + + if (!dso || handler.dsoHandle == dso) { + handler.function(handler.argument); + handler.function = nullptr; + } + } +} + +// In static builds, these should be provided by the crtbegin.o/crtend.o that +// is linked into the executable. +#ifndef MLIBC_STATIC_BUILD +// This is referenced by the compiler when generating constructors for global +// C++ objects so that it can call __cxa_finalize with a unique argument. +extern "C" { [[gnu::visibility("hidden")]] void *__dso_handle; } +#else +extern "C" void *__dso_handle; +#endif + +[[gnu::destructor]] void __mlibc_do_destructors() { + // In normal programs this call to __cxa_finalize is provided by libgcc. + __cxa_finalize(&__dso_handle); +} + +void __mlibc_do_finalize() { + // Invoke any handlers registered with atexit (NOT associated with a DSO). + // Note that we deliberately do not invoke other handlers here, since + // that would destroy mlibc's global objects including stdout and flushing + // open FILEs, but we'd like those to be available to [[gnu::destructor]] + // functions which we invoke below. + ExitQueue &eq = getExitQueue(); + for (size_t i = eq.size(); i > 0; i--) { + auto &handler = eq[i - 1]; + if (!handler.function) + continue; + + if (!handler.dsoHandle) { + handler.function(handler.argument); + handler.function = nullptr; + } + } + + // Call fini/fini_array functions of each loaded object. This is necessary + // to implement [[gnu::destructor]]. Note that C++ applications will call + // __cxa_finalize from here. + __dlapi_exit(); +} diff --git a/user/include/mlibc/options/lsb/generic/tls.cpp b/user/include/mlibc/options/lsb/generic/tls.cpp new file mode 100644 index 0000000..78398e3 --- /dev/null +++ b/user/include/mlibc/options/lsb/generic/tls.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +#if (defined(__riscv) || defined(__m68k__) || defined(__loongarch64)) && defined(MLIBC_STATIC_BUILD) + // On RISC-V, m68k and loongarch64, linker optimisation is not guaranteed and so we may + // still get calls to this function in statically linked binaries. + // TODO: This will break dlopen calls from statically linked programs. + extern "C" void *__tls_get_addr(struct __abi_tls_entry *entry) { + Tcb *tcbPtr = mlibc::get_current_tcb(); + auto dtvPtr = reinterpret_cast(tcbPtr->dtvPointers[0]); + return reinterpret_cast(dtvPtr + entry->offset + TLS_DTV_OFFSET); + } +#elif defined(__i386__) + extern "C" __attribute__((regparm(1))) void *___tls_get_addr(struct __abi_tls_entry *entry) { + return __dlapi_get_tls(entry); + } +#else + extern "C" void *__tls_get_addr(struct __abi_tls_entry *entry) { + return __dlapi_get_tls(entry); + } +#endif + diff --git a/user/include/mlibc/options/lsb/include/sys/auxv.h b/user/include/mlibc/options/lsb/include/sys/auxv.h new file mode 100644 index 0000000..2e8598c --- /dev/null +++ b/user/include/mlibc/options/lsb/include/sys/auxv.h @@ -0,0 +1,25 @@ +#ifndef _SYS_AUXV_H +#define _SYS_AUXV_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* mlibc extension: Like getauxval but handles errors in a sane way. */ +/* Success: Return 0. */ +/* Failure: Return -1 and set errno. */ +int peekauxval(unsigned long __type, unsigned long *__value); + +unsigned long getauxval(unsigned long __type); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/user/include/mlibc/options/lsb/meson.build b/user/include/mlibc/options/lsb/meson.build new file mode 100644 index 0000000..322a912 --- /dev/null +++ b/user/include/mlibc/options/lsb/meson.build @@ -0,0 +1,14 @@ + +lsb_sources = files( + 'generic/auxv.cpp', + 'generic/dso_exit.cpp', + 'generic/tls.cpp', +) + +if not no_headers + install_headers( + 'include/sys/auxv.h', + subdir: 'sys' + ) +endif + diff --git a/user/include/mlibc/options/posix/generic/arpa-inet.cpp b/user/include/mlibc/options/posix/generic/arpa-inet.cpp new file mode 100644 index 0000000..07649b9 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/arpa-inet.cpp @@ -0,0 +1,307 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; + +uint32_t htonl(uint32_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return mlibc::bit_util::byteswap(x); +#else + return x; +#endif +} +uint16_t htons(uint16_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return mlibc::bit_util::byteswap(x); +#else + return x; +#endif +} +uint32_t ntohl(uint32_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return mlibc::bit_util::byteswap(x); +#else + return x; +#endif +} +uint16_t ntohs(uint16_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return mlibc::bit_util::byteswap(x); +#else + return x; +#endif +} + +// ---------------------------------------------------------------------------- +// IPv4 address manipulation. +// ---------------------------------------------------------------------------- +in_addr_t inet_addr(const char *p) { + struct in_addr a; + if(!inet_aton(p, &a)) + return -1; + return a.s_addr; +} + +in_addr_t inet_network(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *inet_ntoa(struct in_addr addr) { + // string: xxx.yyy.zzz.aaa + // 4 * 3 + 3 + 1 = 12 + 4 = 16 + thread_local static char buffer[16]; + uint32_t proper = htonl(addr.s_addr); + snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", + (proper >> 24) & 0xff, ((proper >> 16) & 0xff), + (proper >> 8) & 0xff, proper & 0xff); + return buffer; +} +int inet_aton(const char *string, struct in_addr *dest) { + int array[4]; + int i = 0; + char *end; + + for (; i < 4; i++) { + array[i] = strtoul(string, &end, 0); + if (*end && *end != '.') + return 0; + if (!*end) + break; + string = end + 1; + } + + switch (i) { + case 0: + dest->s_addr = htonl(array[0]); + break; + case 1: + if (array[0] > 255 || array[1] > 0xffffff) + return 0; + dest->s_addr = htonl((array[0] << 24) | array[1]); + break; + case 2: + if (array[0] > 255 || array[1] > 255 || + array[2] > 0xffff) + return 0; + dest->s_addr = htonl((array[0] << 24) | (array[1] << 16) | + array[2]); + break; + case 3: + if (array[0] > 255 || array[1] > 255 || + array[2] > 255 || array[3] > 255) + return 0; + dest->s_addr = htonl((array[0] << 24) | (array[1] << 16) | + (array[2] << 8) | array[3]); + break; + } + + return 1; +} + +// ---------------------------------------------------------------------------- +// Generic IP address manipulation. +// ---------------------------------------------------------------------------- +const char *inet_ntop(int af, const void *__restrict src, char *__restrict dst, + socklen_t size) { + switch (af) { + case AF_INET: { + auto source = reinterpret_cast(src); + uint32_t addr = ntohl(source->s_addr); + if (snprintf(dst, size, "%d.%d.%d.%d", + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + addr & 0xff) < (int)size) + return dst; + break; + } + case AF_INET6: { + auto source = reinterpret_cast(src); + size_t cur_zeroes_off = 0; + size_t cur_zeroes_len = 0; + size_t max_zeroes_off = 0; + size_t max_zeroes_len = 0; + + /* we look for the largest block of zeroed quartet(s) */ + for(size_t i = 0; i < 8; i++) { + auto ptr = source->s6_addr + (i * 2); + if(!ptr[0] && !ptr[1]) { + cur_zeroes_len++; + if(max_zeroes_len < cur_zeroes_len) { + max_zeroes_len = cur_zeroes_len; + max_zeroes_off = cur_zeroes_off; + } + } else { + /* advance the offset to the next quartet to check */ + cur_zeroes_len = 0; + cur_zeroes_off = i + 1; + } + } + + size_t off = 0; + for(size_t i = 0; i < 8; i++) { + auto ptr = source->s6_addr + (i * 2); + + /* if we are at the beginning of the largest block of zeroed quartets, place "::" */ + if(i == max_zeroes_off && max_zeroes_len >= 2) { + if(off < size) { + dst[off++] = ':'; + } + if(off < size) { + dst[off++] = ':'; + } + i += max_zeroes_len - 1; + + continue; + } + + /* place a colon if we're not at the beginning of the string and it is not already there */ + if(off && dst[off - 1] != ':') { + if(off < size) { + dst[off++] = ':'; + } + } + + off += snprintf(dst + off, size - off, "%x", ptr[0] << 8 | ptr[1]); + } + + dst[off] = 0; + + return dst; + } + default: + errno = EAFNOSUPPORT; + return nullptr; + } + + errno = ENOSPC; + return nullptr; +} + +int inet_pton(int af, const char *__restrict src, void *__restrict dst) { + switch (af) { + case AF_INET: { + uint8_t array[4] = {}; + for (int i = 0; i < 4; i++) { + char *end; + long int value = strtol(src, &end, 10); + if (value > 255) + return 0; + if (*end != '\0' && *end != '.') + return 0; + src = end + 1; + array[i] = value; + } + auto addr = reinterpret_cast(dst); + uint32_t ip = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]; + addr->s_addr = htonl(ip); + break; + } + case AF_INET6: { + size_t i = 0; + uint16_t array[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + frg::optional doubleColonOffset = frg::null_opt; + + auto reservedRange = [&]() -> bool { + if(i && ((doubleColonOffset && doubleColonOffset.value()) || !doubleColonOffset)) { + return (ntohs(array[0]) >> 8) == 0; + } + + return false; + }; + + for(; i < 8; i++) { + char *end = nullptr; + auto value = strtol(src, &end, 16); + + if (value > UINT16_MAX) + return 0; + if(end[0] != '\0' && end[0] != ':' && end[0] != '.') + return 0; + + if(end[0] == '.' && reservedRange() && i < 7) { + char *ipv4end = nullptr; + auto value0 = strtol(src, &ipv4end, 10); + if(ipv4end[0] != '.' || value0 > UINT8_MAX || src == ipv4end) + return 0; + src = ipv4end + 1; + auto value1 = strtol(src, &ipv4end, 10); + if(ipv4end[0] != '.' || value1 > UINT8_MAX || src == ipv4end) + return 0; + array[i++] = htons((value0 << 8) | value1); + src = ipv4end + 1; + + auto value2 = strtol(src, &ipv4end, 10); + if(ipv4end[0] != '.' || value2 > UINT8_MAX || src == ipv4end) + return 0; + src = ipv4end + 1; + auto value3 = strtol(src, &ipv4end, 10); + if(value3 > UINT8_MAX || src == ipv4end) + return 0; + array[i] = htons((value2 << 8) | value3); + break; + } else if(end[0] == ':' && end[1] == ':') { + if(doubleColonOffset) + return 0; + doubleColonOffset = i + 1; + src = end + 2; + } else if(end[0] == ':' || end[0] == '\0') { + src = end + 1; + } else { + return 0; + } + + array[i] = htons(value); + + if(end[0] == '\0') + break; + } + + auto addr = reinterpret_cast(dst); + + if(doubleColonOffset) { + size_t suffix = i - doubleColonOffset.value() + 1; + memset(addr->s6_addr, 0, 16); + + for(size_t j = 0; j < doubleColonOffset.value(); j++) { + addr->s6_addr16[j] = array[j]; + } + + for(size_t j = 0; j < suffix; j++) { + addr->s6_addr16[8 - suffix + j] = array[doubleColonOffset.value() + j]; + } + } else { + for(size_t j = 0; j < 8; j++) { + addr->s6_addr16[j] = array[j]; + } + } + + break; + } + default: + errno = EAFNOSUPPORT; + return -1; + } + + return 1; +} + +struct in_addr inet_makeaddr(in_addr_t, in_addr_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +in_addr_t inet_netof(struct in_addr) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/dirent.cpp b/user/include/mlibc/options/posix/generic/dirent.cpp new file mode 100644 index 0000000..4ca23a1 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/dirent.cpp @@ -0,0 +1,184 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// Code taken from musl +int alphasort(const struct dirent **a, const struct dirent **b) { + return strcoll((*a)->d_name, (*b)->d_name); +} + +int closedir(DIR *dir) { + // TODO: Deallocate the dir structure. + close(dir->__handle); + return 0; +} +int dirfd(DIR *dir) { + return dir->__handle; +} +DIR *fdopendir(int fd) { + struct stat st; + + if(fstat(fd, &st) < 0) { + return nullptr; + } + // Musl implements this, but O_PATH is only declared on the linux abi + /*if(fcntl(fd, F_GETFL) & O_PATH) { + errno = EBADF; + return nullptr; + }*/ + if(!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return nullptr; + } + auto dir = frg::construct<__mlibc_dir_struct>(getAllocator()); + __ensure(dir); + dir->__ent_next = 0; + dir->__ent_limit = 0; + int flags = fcntl(fd, F_GETFD); + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + dir->__handle = fd; + return dir; +} +DIR *opendir(const char *path) { + auto dir = frg::construct<__mlibc_dir_struct>(getAllocator()); + __ensure(dir); + dir->__ent_next = 0; + dir->__ent_limit = 0; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_open_dir, nullptr); + if(int e = mlibc::sys_open_dir(path, &dir->__handle); e) { + errno = e; + frg::destruct(getAllocator(), dir); + return nullptr; + }else{ + return dir; + } +} + +struct dirent *readdir(DIR *dir) { + __ensure(dir->__ent_next <= dir->__ent_limit); + if(dir->__ent_next == dir->__ent_limit) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_read_entries, nullptr); + if(int e = mlibc::sys_read_entries(dir->__handle, dir->__ent_buffer, 2048, &dir->__ent_limit); e) + __ensure(!"mlibc::sys_read_entries() failed"); + dir->__ent_next = 0; + if(!dir->__ent_limit) + return nullptr; + } + + auto entp = reinterpret_cast(dir->__ent_buffer + dir->__ent_next); + // We only copy as many bytes as we need to avoid buffer-overflows. + memcpy(&dir->__current, entp, offsetof(struct dirent, d_name) + strlen(entp->d_name) + 1); + dir->__ent_next += entp->d_reclen; + return &dir->__current; +} + +[[gnu::alias("readdir")]] struct dirent64 *readdir64(DIR *dir); + +int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result) { + if(!mlibc::sys_read_entries) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + + __ensure(dir->__ent_next <= dir->__ent_limit); + if(dir->__ent_next == dir->__ent_limit) { + if(int e = mlibc::sys_read_entries(dir->__handle, dir->__ent_buffer, 2048, &dir->__ent_limit); e) + __ensure(!"mlibc::sys_read_entries() failed"); + dir->__ent_next = 0; + if(!dir->__ent_limit) { + *result = nullptr; + return 0; + } + } + + auto entp = reinterpret_cast(dir->__ent_buffer + dir->__ent_next); + // We only copy as many bytes as we need to avoid buffer-overflows. + memcpy(entry, entp, offsetof(struct dirent, d_name) + strlen(entp->d_name) + 1); + dir->__ent_next += entp->d_reclen; + *result = entry; + return 0; +} + +void rewinddir(DIR *dir) { + lseek(dir->__handle, 0, SEEK_SET); + dir->__ent_next = 0; +} + +int scandir(const char *path, struct dirent ***res, int (*select)(const struct dirent *), + int (*compare)(const struct dirent **, const struct dirent **)) { + DIR *dir = opendir(path); + if (!dir) + return -1; // errno will be set by opendir() + + // we should save the errno + int old_errno = errno; + errno = 0; + + struct dirent *dir_ent; + struct dirent **array = nullptr, **tmp = nullptr; + int length = 0; + int count = 0; + while((dir_ent = readdir(dir)) && !errno) { + if(select && !select(dir_ent)) + continue; + + if(count >= length) { + length = 2*length + 1; + tmp = static_cast(realloc(array, + length * sizeof(struct dirent*))); + // we need to check the call actually goes through + // before we overwrite array so that we can + // deallocate the already written entries should realloc() + // have failed + if(!tmp) + break; + array = tmp; + } + array[count] = static_cast(malloc(dir_ent->d_reclen)); + if(!array[count]) + break; + + memcpy(array[count], dir_ent, dir_ent->d_reclen); + count++; + } + + if(errno) { + if(array) + while(count-- > 0) + free(array[count]); + free(array); + return -1; + } + + // from here we can set the old errno back + errno = old_errno; + + if(compare) + qsort(array, count, sizeof(struct dirent*), + (int (*)(const void *, const void *)) compare); + *res = array; + return count; +} +void seekdir(DIR *, long) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long telldir(DIR *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int versionsort(const struct dirent **a, const struct dirent **b) { + return strverscmp((*a)->d_name, (*b)->d_name); +} diff --git a/user/include/mlibc/options/posix/generic/dlfcn.cpp b/user/include/mlibc/options/posix/generic/dlfcn.cpp new file mode 100644 index 0000000..8d1222c --- /dev/null +++ b/user/include/mlibc/options/posix/generic/dlfcn.cpp @@ -0,0 +1,99 @@ + +#include +#include + +#include + +struct __dlapi_symbol { + const char *file; + void *base; + const char *symbol; + void *address; + const void *elf_symbol; + void *link_map; +}; + +extern "C" const char *__dlapi_error(); +extern "C" void *__dlapi_open(const char *, int, void *); +extern "C" void *__dlapi_resolve(void *, const char *, void *, const char *); +extern "C" int __dlapi_reverse(const void *, __dlapi_symbol *); +extern "C" int __dlapi_close(void *); +extern "C" int __dlapi_find_object(void *__address, dl_find_object *__result); + +int dlclose(void *handle) { + return __dlapi_close(handle); +} + +char *dlerror(void) { + return const_cast(__dlapi_error()); +} + +[[gnu::noinline]] +void *dlopen(const char *file, int flags) { + auto ra = __builtin_extract_return_addr(__builtin_return_address(0)); + return __dlapi_open(file, flags, ra); +} + +[[gnu::noinline]] +void *dlsym(void *__restrict handle, const char *__restrict string) { + auto ra = __builtin_extract_return_addr(__builtin_return_address(0)); + return __dlapi_resolve(handle, string, ra, nullptr); +} + +[[gnu::noinline]] +void *dlvsym(void *__restrict handle, const char *__restrict string, const char *__restrict version) { + auto ra = __builtin_extract_return_addr(__builtin_return_address(0)); + return __dlapi_resolve(handle, string, ra, version); +} + +//gnu extensions + +#if __MLIBC_GLIBC_OPTION + +int dladdr(const void *ptr, Dl_info *out) { + __dlapi_symbol info; + if(__dlapi_reverse(ptr, &info)) + return 0; + + out->dli_fname = info.file; + out->dli_fbase = info.base; + out->dli_sname = info.symbol; + out->dli_saddr = info.address; + return 1; +} + +int dladdr1(const void *ptr, Dl_info *out, void **extra, int flags) { + __dlapi_symbol info; + if(__dlapi_reverse(ptr, &info)) { + return 0; + } + + out->dli_fname = info.file; + out->dli_fbase = info.base; + out->dli_sname = info.symbol; + out->dli_saddr = info.address; + + switch(flags) { + case RTLD_DL_SYMENT: + *const_cast(extra) = info.elf_symbol; + break; + case RTLD_DL_LINKMAP: + *extra = info.link_map; + break; + default: + break; + } + + return 1; +} + +int dlinfo(void *__restrict, int, void *__restrict) { + __ensure(!"dlinfo() not implemented"); + __builtin_unreachable(); +} + +int _dl_find_object(void *address, struct dl_find_object *result) { + return __dlapi_find_object(address, result); +} + +#endif // __MLIBC_GLIBC_OPTION diff --git a/user/include/mlibc/options/posix/generic/fcntl.cpp b/user/include/mlibc/options/posix/generic/fcntl.cpp new file mode 100644 index 0000000..8ddd307 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/fcntl.cpp @@ -0,0 +1,118 @@ + +#include +#include +#include +#include + +#include +#include + +int creat(const char *pathname, mode_t mode) { + return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode); +} + +int fallocate(int, int, off_t, off_t) { + mlibc::infoLogger() << "mlibc: fallocate() is a no-op" << frg::endlog; + errno = ENOSYS; + return -1; +} + +int fcntl(int fd, int command, ...) { + va_list args; + va_start(args, command); + int result; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fcntl, -1); + if(int e = mlibc::sys_fcntl(fd, command, args, &result); e) { + errno = e; + return -1; + } + va_end(args); + return result; +} + +int openat(int dirfd, const char *pathname, int flags, ...) { + va_list args; + va_start(args, flags); + mode_t mode = 0; + int fd; + + if((flags & (O_CREAT | O_TMPFILE))) + mode = va_arg(args, mode_t); + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_openat, -1); + if(int e = mlibc::sys_openat(dirfd, pathname, flags, mode, &fd); e) { + errno = e; + return -1; + } + va_end(args); + return fd; +} + +int posix_fadvise(int fd, off_t offset, off_t length, int advice) { + if(!mlibc::sys_fadvise) { + mlibc::infoLogger() << "mlibc: fadvise() ignored due to missing sysdep" << frg::endlog; + return 0; + } + + // posix_fadvise() returns an error instead of setting errno. + return mlibc::sys_fadvise(fd, offset, length, advice); +} + +int posix_fallocate(int fd, off_t offset, off_t size) { + // posix_fallocate() returns an error instead of setting errno. + if(!mlibc::sys_fallocate) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + return mlibc::sys_fallocate(fd, offset, size); +} + +// This is a linux extension +int name_to_handle_at(int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_name_to_handle_at, -1); + if(int e = mlibc::sys_name_to_handle_at(dirfd, pathname, handle, mount_id, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int open_by_handle_at(int, struct file_handle *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t splice(int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_splice, -1); + ssize_t ret; + if(int e = mlibc::sys_splice(in_fd, in_off, out_fd, out_off, size, flags, &ret); e) { + errno = e; + return -1; + } + return ret; +} + +ssize_t vmsplice(int, const struct iovec *, size_t, unsigned int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int open(const char *pathname, int flags, ...) { + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE)) { + va_list args; + va_start(args, flags); + mode = va_arg(args, mode_t); + va_end(args); + } + + int fd; + if(int e = mlibc::sys_open(pathname, flags, mode, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +[[gnu::alias("open")]] int open64(const char *pathname, int flags, ...); \ No newline at end of file diff --git a/user/include/mlibc/options/posix/generic/ftw.cpp b/user/include/mlibc/options/posix/generic/ftw.cpp new file mode 100644 index 0000000..2d93995 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/ftw.cpp @@ -0,0 +1,18 @@ + +#include + +#include + +int ftw(const char *, int (*fn)(const char *, const struct stat *, int), int) { + (void)fn; + __ensure(!"ftw() not implemented"); + __builtin_unreachable(); +} + +int nftw(const char *, int (*fn)(const char *, const struct stat *, int, struct FTW *), + int, int) { + (void)fn; + __ensure(!"nftw() not implemented"); + __builtin_unreachable(); +} + diff --git a/user/include/mlibc/options/posix/generic/grp.cpp b/user/include/mlibc/options/posix/generic/grp.cpp new file mode 100644 index 0000000..b5ed0e4 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/grp.cpp @@ -0,0 +1,386 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + FILE *global_file; + + bool open_global_file() { + if(!global_file) { + global_file = fopen("/etc/group", "r"); + if(!global_file) { + errno = EIO; + return false; + } + } + + return true; + } + + void close_global_file() { + if(global_file) { + fclose(global_file); + global_file = nullptr; + } + } + + template + void walk_segments(frg::string_view line, char delimiter, F fn) { + size_t s = 0; + while(true) { + size_t d = line.find_first(delimiter, s); + if(d == size_t(-1)) + break; + auto chunk = line.sub_string(s, d - s); + fn(chunk); + s = d + 1; + } + if(line[s]) { + auto chunk = line.sub_string(s, line.size() - s); + + if (chunk.size() > 0) { + // Remove trailing newline + if (chunk[chunk.size() - 1] == '\n') + chunk = chunk.sub_string(0, chunk.size() - 1); + + fn(chunk); + } + } + } + + bool extract_entry(frg::string_view line, group *entry) { + frg::string_view segments[5]; + + // Parse the line into 3 or 4 segments (depending if the group has members or not) + int n = 0; + walk_segments(line, ':', [&] (frg::string_view s) { + __ensure(n < 4); + segments[n++] = s; + }); + + if(n < 3) // n can be 3 when there are no members in the group + return false; + + // TODO: Handle strndup() and malloc() failure. + auto name = strndup(segments[0].data(), segments[0].size()); + __ensure(name); + + auto passwd = strndup(segments[1].data(), segments[1].size()); + + auto gid = segments[2].to_number(); + if(!gid) + return false; + + size_t n_members = 0; + walk_segments(segments[3], ',', [&] (frg::string_view) { + n_members++; + }); + + auto members = reinterpret_cast(malloc(sizeof(char *) * (n_members + 1))); + __ensure(members); + size_t k = 0; + walk_segments(segments[3], ',', [&] (frg::string_view m) { + members[k] = strndup(m.data(), m.size()); + __ensure(members[k]); + k++; + }); + members[k] = nullptr; + + entry->gr_name = name; + entry->gr_passwd = passwd; + entry->gr_gid = *gid; + entry->gr_mem = members; + return true; + } + + void clear_entry(group *entry) { + free(entry->gr_name); + if(entry->gr_mem) { + for(size_t i = 0; entry->gr_mem[i]; i++) + free(entry->gr_mem[i]); + free(entry->gr_mem); + } + entry->gr_name = nullptr; + entry->gr_mem = nullptr; + } + + template + int walk_file(struct group *entry, C cond) { + auto file = fopen("/etc/group", "r"); + if(!file) { + return EIO; + } + + char line[512]; + while(fgets(line, 512, file)) { + if(!extract_entry(line, entry)) + continue; + if(cond(entry)) { + fclose(file); + return 0; + } + } + + int err = ESRCH; + if(ferror(file)) { + err = EIO; + } + + fclose(file); + return err; + } + + int copy_to_buffer(struct group *grp, char *buffer, size_t size) { + // Adjust to correct alignment so that we can put gr_mem first in buffer + uintptr_t mask = sizeof(char *) - 1; + size_t offset = (reinterpret_cast(buffer) % sizeof(char *) + mask) & ~mask; + if (size < offset) + return ERANGE; + + buffer += offset; + size -= offset; + + // Calculate the amount of space we need + size_t nmemb, required_size = 0; + for (nmemb = 0; grp->gr_mem[nmemb] != nullptr; nmemb++) { + // One for the string's null terminator and one for the pointer in gr_mem + required_size += strlen(grp->gr_mem[nmemb]) + 1 + sizeof(char *); + } + + // One for null terminator of gr_name, plus sizeof(char *) for nullptr terminator of gr_mem + required_size += strlen(grp->gr_name) + 1 + sizeof(char *); + if (size < required_size) + return ERANGE; + + // Put the gr_mem array first in the buffer as we are guaranteed + // that the pointer is aligned correctly + char *string_data = buffer + (nmemb + 1) * sizeof(char *); + + for (size_t i = 0; i < nmemb; i++) { + reinterpret_cast(buffer)[i] = string_data; + string_data = stpcpy(string_data, grp->gr_mem[i]) + 1; + free(grp->gr_mem[i]); + } + + reinterpret_cast(buffer)[nmemb] = nullptr; + free(grp->gr_mem); + grp->gr_mem = reinterpret_cast(buffer); + + char *gr_name = stpcpy(string_data, grp->gr_name) + 1; + free(grp->gr_name); + grp->gr_name = string_data; + + __ensure(gr_name <= buffer + size); + return 0; + } +} // namespace + +void endgrent(void) { + close_global_file(); +} + +struct group *getgrent(void) { + static group entry; + char line[512]; + + if(!open_global_file()) { + return nullptr; + } + + if(fgets(line, 512, global_file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) { + errno = EINVAL; + return nullptr; + } + return &entry; + } + + if(ferror(global_file)) { + errno = EIO; + } + + return nullptr; +} + +struct group *getgrgid(gid_t gid) { + static group entry; + + int err = walk_file(&entry, [&] (group *entry) { + return entry->gr_gid == gid; + }); + + if (err) { + errno = err; + return nullptr; + } + + return &entry; +} + +int getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t size, struct group **result) { + *result = nullptr; + int err = walk_file(grp, [&] (group *entry) { + return entry->gr_gid == gid; + }); + + if (err) { + return err; + } + + err = copy_to_buffer(grp, buffer, size); + if (err) { + return err; + } + + *result = grp; + return 0; +} + +struct group *getgrnam(const char *name) { + static group entry; + + int err = walk_file(&entry, [&] (group *entry) { + return !strcmp(entry->gr_name, name); + }); + + if (err) { + errno = err; + return nullptr; + } + + return &entry; +} + +int getgrnam_r(const char *name, struct group *grp, char *buffer, size_t size, struct group **result) { + *result = nullptr; + + int err = walk_file(grp, [&] (group *entry) { + return !strcmp(entry->gr_name, name); + }); + + if (err) { + return err; + } + + err = copy_to_buffer(grp, buffer, size); + if (err) { + return err; + } + + *result = grp; + return 0; +} + +void setgrent(void) { + if(!open_global_file()) { + return; + } + rewind(global_file); +} + +int setgroups(size_t size, const gid_t *list) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setgroups, -1); + if(int e = mlibc::sys_setgroups(size, list); e) { + errno = e; + return -1; + } + return 0; +} + +int initgroups(const char *, gid_t) { + mlibc::infoLogger() << "mlibc: initgroups is a stub" << frg::endlog; + return 0; +} + +int putgrent(const struct group *g, FILE *f) { + auto invalid = [](const char *s) { + return s == nullptr || strchr(s, '\n') || strchr(s, ':'); + }; + + if(g == nullptr || invalid(g->gr_name) || invalid(g->gr_passwd)) { + errno = EINVAL; + return -1; + } + + for(int i = 0; g->gr_mem != nullptr && g->gr_mem[i] != nullptr; ++i) { + if (invalid(g->gr_mem[i])) { + errno = EINVAL; + return -1; + } + } + + // Taken from musl. + flockfile(f); + + int r = fprintf(f, "%s:%s:%u:", g->gr_name, g->gr_passwd, g->gr_gid); + if(r < 0) + goto leave; + + for(int i = 0; g->gr_mem != nullptr && g->gr_mem[i] != nullptr; ++i) { + r = fprintf(f, "%s%s", i ? "," : "", g->gr_mem[i]); + if(r < 0) + goto leave; + } + + r = fputc('\n', f); + +leave: + funlockfile(f); + return r < 0 ? -1 : 0; +} + +struct group *fgetgrent(FILE *file) { + static group entry; + char line[512]; + + if(fgets(line, 512, file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) { + errno = EINVAL; + return nullptr; + } + return &entry; + } + + if(ferror(file)) { + errno = EIO; + } + + return nullptr; +} + +int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) { + int n = 1; + int n_limit = *ngroups; + struct group grp; + + if(n_limit >= 1) + *groups++ = gid; + + int err = walk_file(&grp, [&] (group *entry) { + size_t i = 0; + for(; entry->gr_mem[i] && strcmp(user, entry->gr_mem[i]); i++); + if(!entry->gr_mem[i]) + return false; + if(++n <= n_limit) + *groups++ = entry->gr_gid; + return false; + }); + + if(err != ESRCH) { + errno = err; + return -1; + } + + *ngroups = n; + + return (n > n_limit) ? -1 : n; +} diff --git a/user/include/mlibc/options/posix/generic/langinfo.cpp b/user/include/mlibc/options/posix/generic/langinfo.cpp new file mode 100644 index 0000000..b239cbd --- /dev/null +++ b/user/include/mlibc/options/posix/generic/langinfo.cpp @@ -0,0 +1,15 @@ + +#include +#include +#include +#include + +char *nl_langinfo(nl_item item) { + return mlibc::nl_langinfo(item); +} + +char *nl_langinfo_l(nl_item, locale_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + diff --git a/user/include/mlibc/options/posix/generic/libgen.cpp b/user/include/mlibc/options/posix/generic/libgen.cpp new file mode 100644 index 0000000..ff80349 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/libgen.cpp @@ -0,0 +1,51 @@ + +#include +#include +#include + +#include + +// Adopted from musl's code. +char *basename(char *s) { + // This empty string behavior is specified by POSIX. + if (!s || !*s) + return const_cast("."); + + // Delete trailing slashes. + // Note that we do not delete the slash at index zero. + auto i = strlen(s) - 1; + for(; i && s[i] == '/'; i--) + s[i] = 0; + + // Find the last non-trailing slash. + for(; i && s[i - 1] != '/'; i--) + ; + return s + i; +} + +char *dirname(char *s) { + if (!s || !(*s)) + return const_cast("."); + + auto i = strlen(s) - 1; + + // Skip trailing slashes. + for (; s[i] == '/'; i--) + if(!i) // Path only consists of slashes. + return const_cast("/"); + + // Skip the last non-slash path component. + for (; s[i] != '/'; i--) + if(!i) // Path only contains a single component. + return const_cast("."); + + // Skip slashes. + for (; s[i] == '/'; i--) + if(!i) // Path is entry in root directory. + return const_cast("/"); + + s[i+1] = 0; + + return s; +} + diff --git a/user/include/mlibc/options/posix/generic/lookup.cpp b/user/include/mlibc/options/posix/generic/lookup.cpp new file mode 100644 index 0000000..c2da918 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/lookup.cpp @@ -0,0 +1,548 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +namespace { + constexpr unsigned short RETURN_NOERROR [[maybe_unused]] = 0x0; + constexpr unsigned short RETURN_NXDOMAIN = 0x3; + + constexpr unsigned int RECORD_A = 1; + constexpr unsigned int RECORD_CNAME = 5; + constexpr unsigned int RECORD_PTR = 12; + constexpr unsigned int RECORD_AAAA = 28; +} // namespace + +static frg::string read_dns_name(char *buf, char *&it) { + frg::string res{getAllocator()}; + while (true) { + char code = *it++; + if ((code & 0xC0) == 0xC0) { + // pointer + uint8_t offset = ((code & 0x3F) << 8) | *it++; + auto offset_it = buf + offset; + return res + read_dns_name(buf, offset_it); + } else if (!(code & 0xC0)) { + if (!code) + break; + + for (int i = 0; i < code; i++) + res += (*it++); + + if (*it) + res += '.'; + } else { + break; + } + } + + return res; +} + +int lookup_name_dns(struct lookup_result &buf, const char *name, + frg::string &canon_name, int family) { + frg::string request{getAllocator()}; + + int num_q = 1; + struct dns_header header; + header.identification = htons(123); + header.flags = htons(0x100); + header.no_q = htons(num_q); + header.no_ans = htons(0); + header.no_auths = htons(0); + header.no_additional = htons(0); + + request.resize(sizeof(header)); + memcpy(request.data(), &header, sizeof(header)); + + const char *end = name; + while (*end != '\0') { + end = strchrnul(name, '.'); + size_t length = end - name; + frg::string_view substring{name, length}; + name += length + 1; + request += char(length); + request += substring; + } + + request += char(0); + // set question type to fetch A or AAAA records + uint16_t qtype = RECORD_A; + if (family == AF_INET6) + qtype = RECORD_AAAA; + + request += qtype >> 8; + request += qtype & 0xFF; + // set CLASS to IN + request += 0; + request += 1; + + mlibc::service_result serv_buf{getAllocator()}; + int serv_count = mlibc::lookup_serv_by_name(serv_buf, "domain", IPPROTO_UDP, SOCK_DGRAM, 0); + if (serv_count < 0) { + mlibc::infoLogger() << "mlibc: could not resolve DNS service" << frg::endlog; + return -EAI_SERVICE; + } + + struct sockaddr_in sin = {}; + sin.sin_family = AF_INET; + sin.sin_port = htons(serv_buf[0].port); + + auto nameserver = get_nameserver(); + if (!inet_aton(nameserver ? nameserver->name.data() : "127.0.0.1", &sin.sin_addr)) { + mlibc::infoLogger() << "lookup_name_dns(): inet_aton() failed!" << frg::endlog; + return -EAI_SYSTEM; + } + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + mlibc::infoLogger() << "lookup_name_dns(): socket() failed" << frg::endlog; + return -EAI_SYSTEM; + } + + size_t sent = sendto(fd, request.data(), request.size(), 0, + (struct sockaddr*)&sin, sizeof(sin)); + if (sent != request.size()) { + mlibc::infoLogger() << "lookup_name_dns(): sendto() failed to send everything" << frg::endlog; + return -EAI_SYSTEM; + } + + char response[256]; + ssize_t rlen; + int num_ans = 0; + while ((rlen = recvfrom(fd, response, 256, 0, nullptr, nullptr)) >= 0) { + if ((size_t)rlen < sizeof(struct dns_header)) + continue; + auto response_header = reinterpret_cast(response); + if (response_header->identification != header.identification) + return -EAI_FAIL; + + if ((ntohs(response_header->flags) & 0xF) == RETURN_NXDOMAIN) + return -EAI_NONAME; + + auto it = response + sizeof(struct dns_header); + for (int i = 0; i < ntohs(response_header->no_q); i++) { + auto dns_name = read_dns_name(response, it); + (void) dns_name; + it += 4; + } + + for (int i = 0; i < ntohs(response_header->no_ans); i++) { + struct dns_addr_buf buffer; + auto dns_name = read_dns_name(response, it); + + uint16_t rr_type = (it[0] << 8) | it[1]; + uint16_t rr_class = (it[2] << 8) | it[3]; + uint16_t rr_length = (it[8] << 8) | it[9]; + it += 10; + (void)rr_class; + + switch (rr_type) { + case RECORD_A: + if (family != AF_UNSPEC && family != AF_INET) + continue; + + memcpy(buffer.addr, it, rr_length); + it += rr_length; + buffer.family = AF_INET; + buffer.name = std::move(dns_name); + buf.buf.push(std::move(buffer)); + break; + case RECORD_AAAA: + if (family != AF_UNSPEC && family != AF_INET6) + continue; + + memcpy(buffer.addr, it, rr_length); + it += rr_length; + buffer.family = AF_INET6; + buffer.name = std::move(dns_name); + buf.buf.push(std::move(buffer)); + break; + case RECORD_CNAME: + canon_name = read_dns_name(response, it); + buf.aliases.push(std::move(dns_name)); + break; + default: + mlibc::infoLogger() << "lookup_name_dns: unknown rr type " + << rr_type << frg::endlog; + break; + } + } + num_ans += ntohs(response_header->no_ans); + + if (num_ans >= num_q) + break; + } + + close(fd); + return buf.buf.size(); +} + +int lookup_addr_dns(frg::span name, frg::array &addr, int family) { + frg::string request{getAllocator()}; + + int num_q = 1; + struct dns_header header; + header.identification = htons(123); + header.flags = htons(0x100); + header.no_q = htons(num_q); + header.no_ans = htons(0); + header.no_auths = htons(0); + header.no_additional = htons(0); + + request.resize(sizeof(header)); + memcpy(request.data(), &header, sizeof(header)); + + char addr_str[64]; + if(!inet_ntop(family, addr.data(), addr_str, sizeof(addr_str))) { + switch(errno) { + case EAFNOSUPPORT: + return -EAI_FAMILY; + case ENOSPC: + return -EAI_OVERFLOW; + default: + return -EAI_FAIL; + } + } + frg::string req_str{getAllocator(), addr_str}; + req_str += ".in-addr.arpa"; + + frg::string_view req_view{req_str.data(), req_str.size()}; + size_t ptr = 0; + do { + size_t next = req_view.find_first('.', ptr); + size_t length = next != (size_t)-1 ? next - ptr : req_view.size() - ptr; + frg::string_view substring = req_view.sub_string(ptr, length); + request += char(length); + request += substring; + ptr = next + 1; + } while(ptr != 0); + + request += char(0); + // set question type to fetch PTR records + request += 0; + request += 12; + // set CLASS to IN + request += 0; + request += 1; + + mlibc::service_result serv_buf{getAllocator()}; + int serv_count = mlibc::lookup_serv_by_name(serv_buf, "domain", IPPROTO_UDP, SOCK_DGRAM, 0); + if (serv_count < 0) { + mlibc::infoLogger() << "mlibc: could not resolve DNS service" << frg::endlog; + return -EAI_SERVICE; + } + + struct sockaddr_in sin = {}; + sin.sin_family = AF_INET; + sin.sin_port = htons(serv_buf[0].port); + + auto nameserver = get_nameserver(); + if (!inet_aton(nameserver ? nameserver->name.data() : "127.0.0.1", &sin.sin_addr)) { + mlibc::infoLogger() << "lookup_name_dns(): inet_aton() failed!" << frg::endlog; + return -EAI_SYSTEM; + } + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + mlibc::infoLogger() << "lookup_name_dns(): socket() failed" << frg::endlog; + return -EAI_SYSTEM; + } + + size_t sent = sendto(fd, request.data(), request.size(), 0, + (struct sockaddr*)&sin, sizeof(sin)); + if (sent != request.size()) { + mlibc::infoLogger() << "lookup_name_dns(): sendto() failed to send everything" << frg::endlog; + return -EAI_SYSTEM; + } + + char response[256]; + ssize_t rlen; + int num_ans = 0; + while ((rlen = recvfrom(fd, response, 256, 0, nullptr, nullptr)) >= 0) { + if ((size_t)rlen < sizeof(struct dns_header)) + continue; + auto response_header = reinterpret_cast(response); + if (response_header->identification != header.identification) + return -EAI_FAIL; + + auto it = response + sizeof(struct dns_header); + for (int i = 0; i < ntohs(response_header->no_q); i++) { + auto dns_name = read_dns_name(response, it); + (void) dns_name; + it += 4; + } + + for (int i = 0; i < ntohs(response_header->no_ans); i++) { + struct dns_addr_buf buffer; + auto dns_name = read_dns_name(response, it); + + uint16_t rr_type = (it[0] << 8) | it[1]; + uint16_t rr_class = (it[2] << 8) | it[3]; + uint16_t rr_length = (it[8] << 8) | it[9]; + it += 10; + (void)rr_class; + (void)rr_length; + + (void)dns_name; + + switch (rr_type) { + case RECORD_PTR: { + auto ptr_name = read_dns_name(response, it); + if (ptr_name.size() >= name.size()) + return -EAI_OVERFLOW; + std::copy(ptr_name.begin(), ptr_name.end(), name.data()); + name.data()[ptr_name.size()] = '\0'; + return 1; + } + default: + mlibc::infoLogger() << "lookup_addr_dns: unknown rr type " + << rr_type << frg::endlog; + break; + } + num_ans += ntohs(response_header->no_ans); + + if (num_ans >= num_q) + break; + } + } + + close(fd); + return 0; +} + +int lookup_name_hosts(struct lookup_result &buf, const char *name, + frg::string &canon_name, int family) { + auto file = fopen("/etc/hosts", "r"); + if (!file) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return -EAI_SERVICE; + default: + return -EAI_SYSTEM; + } + } + + char line[128]; + int name_length = strlen(name); + while (fgets(line, 128, file)) { + char *pos; + // same way to deal with comments as in services.cpp + if ((pos = strchr(line, '#'))) { + *pos++ = '\n'; + *pos = '\0'; + } + + for(pos = line + 1; (pos = strstr(pos, name)) && + (!isspace(pos[-1]) || !isspace(pos[name_length])); pos++); + if (!pos) + continue; + + for (pos = line; !isspace(*pos); pos++); + *pos = '\0'; + + struct dns_addr_buf buffer; + + if ((family == AF_UNSPEC || family == AF_INET) && inet_pton(AF_INET, line, buffer.addr)) { + buffer.family = AF_INET; + } else if((family == AF_UNSPEC || family == AF_INET6) && inet_pton(AF_INET6, line, buffer.addr)) { + buffer.family = AF_INET6; + } else { + continue; // not a valid address + } + + pos++; + for(; *pos && isspace(*pos); pos++); + char *end; + for(end = pos; *end && !isspace(*end); end++); + + buffer.name = frg::string{pos, + static_cast(end - pos), getAllocator()}; + canon_name = buffer.name; + + buf.buf.push(std::move(buffer)); + + pos = end; + while (pos[1]) { + for (; *pos && isspace(*pos); pos++); + for (end = pos; *end && !isspace(*end); end++); + auto name = frg::string{pos, + static_cast(end - pos), getAllocator()}; + buf.aliases.push(std::move(name)); + pos = end; + } + } + + fclose(file); + return buf.buf.size(); +} + +int lookup_addr_hosts(frg::span name, frg::array &addr, int family) { + auto file = fopen("/etc/hosts", "r"); + if (!file) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return -EAI_SERVICE; + default: + return -EAI_SYSTEM; + } + } + + // Buffer to hold ASCII version of address + char addr_str[64]; + if(!inet_ntop(family, addr.data(), addr_str, sizeof(addr_str))) { + switch(errno) { + case EAFNOSUPPORT: + return -EAI_FAMILY; + case ENOSPC: + return -EAI_OVERFLOW; + default: + return -EAI_FAIL; + } + } + int addr_str_len = strlen(addr_str); + + char line[128]; + while (fgets(line, 128, file)) { + char *pos; + // same way to deal with comments as in services.cpp + if ((pos = strchr(line, '#'))) { + *pos++ = '\n'; + *pos = '\0'; + } + if (strncmp(line, addr_str, addr_str_len)) + continue; + + for (pos = line + addr_str_len + 1; isspace(*pos); pos++); + char *begin = pos; + for (; !isspace(*pos); pos++); + char *end = pos; + + size_t size = end - begin; + if (size >= name.size()) + return -EAI_OVERFLOW; + std::copy(begin, end, name.data()); + name.data()[size] = '\0'; + return 1; + } + return 0; +} + +int lookup_name_null(struct lookup_result &buf, int flags, int family) { + if (flags & AI_PASSIVE) { + if (family != AF_INET6) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET; + + in_addr_t addr = INADDR_ANY; + memcpy(&addr_buf.addr, &addr, 4); + + buf.buf.push_back(addr_buf); + } + if (family != AF_INET) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET6; + + struct in6_addr addr = IN6ADDR_ANY_INIT; + memcpy(&addr_buf.addr, &addr, 16); + + buf.buf.push_back(addr_buf); + } + } else { + if (family != AF_INET6) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET; + + in_addr_t addr = INADDR_LOOPBACK; + memcpy(&addr_buf.addr, &addr, 4); + + buf.buf.push_back(addr_buf); + } + if (family != AF_INET) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET6; + + struct in6_addr addr = IN6ADDR_LOOPBACK_INIT; + memcpy(&addr_buf.addr, &addr, 16); + + buf.buf.push_back(addr_buf); + } + } + return buf.buf.size(); +} + +int lookup_name_ip(struct lookup_result &buf, const char *name, int family) { + if (family == AF_INET) { + in_addr_t addr = 0; + int res = inet_pton(AF_INET, name, &addr); + + if (res <= 0) + return -EAI_NONAME; + + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET; + memcpy(&addr_buf.addr, &addr, 4); + + buf.buf.push_back(addr_buf); + return 1; + } + + if (family == AF_INET6) { + struct in6_addr addr{}; + int res = inet_pton(AF_INET6, name, &addr); + + if (res <= 0) + return -EAI_NONAME; + + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET6; + memcpy(&addr_buf.addr, &addr, 16); + + buf.buf.push_back(addr_buf); + return 1; + } + + // If no family was specified we try ipv4 and then ipv6. + in_addr_t addr4 = 0; + int res = inet_pton(AF_INET, name, &addr4); + + if (res > 0) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET; + memcpy(&addr_buf.addr, &addr4, 4); + + buf.buf.push_back(addr_buf); + return 1; + } + + struct in6_addr addr6{}; + res = inet_pton(AF_INET6, name, &addr6); + + if (res <= 0) + return -EAI_NONAME; + + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET6; + memcpy(&addr_buf.addr, &addr6, 16); + + buf.buf.push_back(addr_buf); + return 1; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/posix/generic/mqueue.cpp b/user/include/mlibc/options/posix/generic/mqueue.cpp new file mode 100644 index 0000000..d635419 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/mqueue.cpp @@ -0,0 +1,22 @@ +#include +#include + +int mq_getattr(mqd_t, struct mq_attr *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int mq_setattr(mqd_t, const struct mq_attr *__restrict__, struct mq_attr *__restrict__) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int mq_unlink(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +mqd_t mq_open(const char *, int, ...) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/net-if.cpp b/user/include/mlibc/options/posix/generic/net-if.cpp new file mode 100644 index 0000000..992aef7 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/net-if.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +#include +#include +#include + +void if_freenameindex(struct if_nameindex *) { + mlibc::infoLogger() << "mlibc: if_freenameindex is a no-op" << frg::endlog; +} + +char *if_indextoname(unsigned int index, char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_if_indextoname, NULL); + + if(int e = sysdep(index, name); e) { + errno = e; + return nullptr; + } + + return name; +} + +struct if_nameindex *if_nameindex(void) { + mlibc::infoLogger() << "mlibc: if_nameindex() is a no-op" << frg::endlog; + errno = ENOSYS; + return nullptr; +} + +unsigned int if_nametoindex(const char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_if_nametoindex, 0); + unsigned int ret = 0; + + if(int e = sysdep(name, &ret); e) { + errno = e; + return 0; + } + + return ret; +} diff --git a/user/include/mlibc/options/posix/generic/netdb.cpp b/user/include/mlibc/options/posix/generic/netdb.cpp new file mode 100644 index 0000000..80d0836 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/netdb.cpp @@ -0,0 +1,520 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__thread int __mlibc_h_errno; + +// This function is from musl +int *__h_errno_location(void) { + return &__mlibc_h_errno; +} + +void endhostent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void endnetent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void endprotoent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void endservent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void freeaddrinfo(struct addrinfo *ptr) { + if (ptr) { + auto buf = (struct mlibc::ai_buf*) ptr - offsetof(struct mlibc::ai_buf, ai); + // this string was allocated by a frg::string + getAllocator().free(ptr->ai_canonname); + free(buf); + } +} + +const char *gai_strerror(int code) { + static thread_local char buffer[128]; + snprintf(buffer, sizeof(buffer), "Unknown error (%d)", code); + return buffer; +} + +int getaddrinfo(const char *__restrict node, const char *__restrict service, + const struct addrinfo *__restrict hints, struct addrinfo **__restrict res) { + if (!node && !service) + return EAI_NONAME; + + int socktype = 0, protocol = 0, family = AF_UNSPEC, flags = AI_V4MAPPED | AI_ADDRCONFIG; + if (hints) { + socktype = hints->ai_socktype; + protocol = hints->ai_protocol; + family = hints->ai_family; + flags = hints->ai_flags; + + int mask = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICHOST | AI_PASSIVE | + AI_CANONNAME | AI_ALL | AI_NUMERICSERV; + if ((flags & mask) != flags) + return EAI_BADFLAGS; + + if (hints->ai_flags & AI_CANONNAME && !node) + return EAI_BADFLAGS; + + if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) + return EAI_FAMILY; + } + + if (flags & AI_ADDRCONFIG) { + if (mlibc::sys_inet_configured) { + bool ipv4 = false; + bool ipv6 = false; + + if (int e = mlibc::sys_inet_configured(&ipv4, &ipv6); e) { + errno = e; + return EAI_SYSTEM; + } + + if (!ipv4 && !ipv6) + return EAI_NONAME; + else if (ipv4 != ipv6) + family = ipv4 ? AF_INET : AF_INET6; + } else { + mlibc::infoLogger() << "mlibc: sys_inet_configured() not implemented, cannot handle getaddrinfo with AI_ADDRCONFIG" << frg::endlog; + errno = ENOSYS; + return EAI_SYSTEM; + } + } + + mlibc::service_result serv_buf{getAllocator()}; + int serv_count = mlibc::lookup_serv_by_name(serv_buf, service, protocol, socktype, flags); + if (serv_count < 0) + return -serv_count; + + struct mlibc::lookup_result addr_buf; + int addr_count = 1; + frg::string canon{getAllocator()}; + if (node) { + if ((addr_count = mlibc::lookup_name_ip(addr_buf, node, family)) <= 0) { + if (flags & AI_NUMERICHOST) + addr_count = -EAI_NONAME; + else if ((addr_count = mlibc::lookup_name_hosts(addr_buf, node, canon, family)) <= 0) + addr_count = mlibc::lookup_name_dns(addr_buf, node, canon, family); + } + + if (addr_count < 0) + return -addr_count; + if (!addr_count) + return EAI_NONAME; + } else { + /* There is no node specified */ + if (flags & AI_NUMERICHOST) + return EAI_NONAME; + addr_count = lookup_name_null(addr_buf, flags, family); + } + + auto out = (struct mlibc::ai_buf *) calloc(serv_count * addr_count, + sizeof(struct mlibc::ai_buf)); + + if (node && !canon.size() && (flags & AI_CANONNAME)) + canon = frg::string{node, getAllocator()}; + + for (int i = 0, k = 0; i < addr_count; i++) { + for (int j = 0; j < serv_count; j++, k++) { + out[i].ai.ai_family = addr_buf.buf[i].family; + out[i].ai.ai_socktype = serv_buf[j].socktype; + out[i].ai.ai_protocol = serv_buf[j].protocol; + out[i].ai.ai_flags = flags; + out[i].ai.ai_addr = (struct sockaddr *) &out[i].sa; + + // If `node` is not null, and if requested by the AI_CANONNAME flag, + // the `ai_canonname` field of the first returned addrinfo structure + // shall point to a null-terminated string containing the canonical name + // corresponding to the node argument. If the canonical name is not available, + // then the ai_canonname field shall refer to the `node` argument or a string with + // the same contents. + if (node && (flags & AI_CANONNAME) && i == 0) + out[i].ai.ai_canonname = canon.data(); + + if(i) + out[i - 1].ai.ai_next = &out[i].ai; + + switch (addr_buf.buf[i].family) { + case AF_INET: + out[i].ai.ai_addrlen = sizeof(struct sockaddr_in); + out[i].sa.sin.sin_port = htons(serv_buf[j].port); + out[i].sa.sin.sin_family = AF_INET; + memcpy(&out[i].sa.sin.sin_addr, addr_buf.buf[i].addr, 4); + break; + case AF_INET6: + out[i].ai.ai_addrlen = sizeof(struct sockaddr_in6); + out[i].sa.sin6.sin6_port = htons(serv_buf[j].port); + out[i].sa.sin6.sin6_family = AF_INET6; + memcpy(&out[i].sa.sin6.sin6_addr, addr_buf.buf[i].addr, 16); + break; + } + } + } + if (addr_count) + out[addr_count - 1].ai.ai_next = nullptr; + + if (canon.size()) + canon.detach(); + + *res = &out[0].ai; + return 0; +} + +struct hostent *gethostent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getnameinfo(const struct sockaddr *__restrict addr, socklen_t addr_len, + char *__restrict host, socklen_t host_len, char *__restrict serv, + socklen_t serv_len, int flags) { + frg::array addr_array; + int family = addr->sa_family; + + switch(family) { + case AF_INET: { + if (addr_len < sizeof(struct sockaddr_in)) + return EAI_FAMILY; + auto sockaddr = reinterpret_cast(addr); + memcpy(addr_array.data(), reinterpret_cast(&sockaddr->sin_addr), 4); + break; + } + case AF_INET6: { + mlibc::infoLogger() << "getnameinfo(): ipv6 is not fully supported in this function" << frg::endlog; + if (addr_len < sizeof(struct sockaddr_in6)) + return EAI_FAMILY; + auto sockaddr = reinterpret_cast(addr); + memcpy(addr_array.data(), reinterpret_cast(&sockaddr->sin6_addr), 16); + break; + } + default: + return EAI_FAMILY; + } + + if (host && host_len) { + frg::span host_span{host, host_len}; + int res = 0; + if (!(flags & NI_NUMERICHOST)) + res = mlibc::lookup_addr_hosts(host_span, addr_array, family); + if (!(flags & NI_NUMERICHOST) && !res) + res = mlibc::lookup_addr_dns(host_span, addr_array, family); + + if (!res) { + if (flags & NI_NAMEREQD) + return EAI_NONAME; + if(!inet_ntop(family, addr_array.data(), host, host_len)) { + switch(errno) { + case EAFNOSUPPORT: + return EAI_FAMILY; + case ENOSPC: + return EAI_OVERFLOW; + default: + return EAI_FAIL; + } + } + } + + if (res < 0) + return -res; + } + + if (serv && serv_len) { + __ensure("getnameinfo(): not implemented service resolution yet!"); + __builtin_unreachable(); + } + + return 0; +} + +struct netent *getnetbyaddr(uint32_t, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct netent *getnetbyname(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct netent *getnetent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct hostent *gethostbyname(const char *name) { + if (!name) { + h_errno = HOST_NOT_FOUND; + return nullptr; + } + + struct mlibc::lookup_result buf; + frg::string canon{getAllocator()}; + int ret = 0; + if ((ret = mlibc::lookup_name_hosts(buf, name, canon, AF_UNSPEC)) <= 0) + ret = mlibc::lookup_name_dns(buf, name, canon, AF_UNSPEC); + if (ret <= 0) { + h_errno = HOST_NOT_FOUND; + return nullptr; + } + + static struct hostent h; + if (h.h_name) { + getAllocator().free(h.h_name); + for (int i = 0; h.h_aliases[i] != nullptr; i++) + getAllocator().free(h.h_aliases[i]); + free(h.h_aliases); + + if (h.h_addr_list) { + for (int i = 0; h.h_addr_list[i] != nullptr; i++) + free(h.h_addr_list[i]); + free(h.h_addr_list); + } + } + h = {}; + + if (!canon.size()) + canon = frg::string{name, getAllocator()}; + + h.h_name = canon.data(); + + h.h_aliases = reinterpret_cast(malloc((buf.aliases.size() + 1) + * sizeof(char*))); + int alias_pos = 0; + for (auto &buf_name : buf.aliases) { + h.h_aliases[alias_pos] = buf_name.data(); + buf_name.detach(); + alias_pos++; + } + h.h_aliases[alias_pos] = nullptr; + canon.detach(); + + // just pick the first family as the one for all addresses...?? + h.h_addrtype = buf.buf[0].family; + if (h.h_addrtype != AF_INET && h.h_addrtype != AF_INET6) { + // this is not allowed per spec + h_errno = NO_DATA; + return nullptr; + } + + // can only be AF_INET or AF_INET6 + h.h_length = h.h_addrtype == AF_INET ? 4 : 16; + h.h_addr_list = reinterpret_cast(malloc((ret + 1) * sizeof(char*))); + int addr_pos = 0; + for (int i = 0; i < ret; i++) { + if (buf.buf[i].family != h.h_addrtype) + continue; + h.h_addr_list[addr_pos] = reinterpret_cast(malloc(h.h_length)); + memcpy(h.h_addr_list[addr_pos], buf.buf[i].addr, h.h_length); + addr_pos++; + } + h.h_addr_list[addr_pos] = nullptr; + + return &h; +} + +struct hostent *gethostbyname2(const char *, int) { + __ensure(!"gethostbyname2() not implemented"); + __builtin_unreachable(); +} + +struct hostent *gethostbyaddr(const void *, socklen_t, int) { + __ensure(!"gethostbyaddr() not implemented"); + __builtin_unreachable(); +} + +int gethostbyaddr_r(const void *__restrict, socklen_t, int, struct hostent *__restrict, + char *__restrict, size_t, struct hostent **__restrict, int *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int gethostbyname_r(const char *__restrict, struct hostent *__restrict, char *__restrict, size_t, + struct hostent **__restrict, int *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct protoent *getprotobyname(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct protoent *getprotobynumber(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct protoent *getprotoent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct servent *getservbyname(const char *name, const char *proto) { + int iproto = -1; + if (proto &&(!strncmp(proto, "tcp", 3) || !strncmp(proto, "TCP", 3))) + iproto = IPPROTO_TCP; + else if (proto && (!strncmp(proto, "udp", 3) || !strncmp(proto, "UDP", 3))) + iproto = IPPROTO_UDP; + + static struct servent ret; + if (ret.s_name) { + free(ret.s_name); + ret.s_name = nullptr; + + for (char **alias = ret.s_aliases; *alias != nullptr; alias++) { + free(*alias); + *alias = nullptr; + } + + free(ret.s_proto); + ret.s_proto = nullptr; + } + + mlibc::service_result serv_buf{getAllocator()}; + int count = mlibc::lookup_serv_by_name(serv_buf, name, iproto, + 0, 0); + if (count <= 0) + return nullptr; + + ret.s_name = serv_buf[0].name.data(); + serv_buf[0].name.detach(); + // Sanity check. + if (strncmp(name, serv_buf[0].name.data(), serv_buf[0].name.size())) + return nullptr; + + ret.s_aliases = reinterpret_cast(malloc((serv_buf[0].aliases.size() + 1) * sizeof(char*))); + int alias_pos = 0; + for (auto &buf_name : serv_buf[0].aliases) { + ret.s_aliases[alias_pos] = buf_name.data(); + buf_name.detach(); + alias_pos++; + } + ret.s_aliases[alias_pos] = nullptr; + + ret.s_port = htons(serv_buf[0].port); + + auto proto_string = frg::string(getAllocator()); + if (!proto) { + if (serv_buf[0].protocol == IPPROTO_TCP) + proto_string = frg::string("tcp", getAllocator()); + else if (serv_buf[0].protocol == IPPROTO_UDP) + proto_string = frg::string("udp", getAllocator()); + else + return nullptr; + } else { + proto_string = frg::string(proto, getAllocator()); + } + ret.s_proto = proto_string.data(); + proto_string.detach(); + + return &ret; +} + +struct servent *getservbyport(int port, const char *proto) { + int iproto = -1; + if (proto && (!strncmp(proto, "tcp", 3) || !strncmp(proto, "TCP", 3))) + iproto = IPPROTO_TCP; + else if (proto && (!strncmp(proto, "udp", 3) || !strncmp(proto, "UDP", 3))) + iproto = IPPROTO_UDP; + + static struct servent ret; + if (ret.s_name) { + free(ret.s_name); + ret.s_name = nullptr; + + for (char **alias = ret.s_aliases; *alias != nullptr; alias++) { + free(*alias); + *alias = nullptr; + } + + free(ret.s_proto); + ret.s_proto = nullptr; + } + + mlibc::service_result serv_buf{getAllocator()}; + int count = mlibc::lookup_serv_by_port(serv_buf, iproto, ntohs(port)); + if (count <= 0) + return nullptr; + + ret.s_name = serv_buf[0].name.data(); + serv_buf[0].name.detach(); + + ret.s_aliases = reinterpret_cast(malloc((serv_buf[0].aliases.size() + 1) * sizeof(char*))); + int alias_pos = 0; + for (auto &buf_name : serv_buf[0].aliases) { + ret.s_aliases[alias_pos] = buf_name.data(); + buf_name.detach(); + alias_pos++; + } + ret.s_aliases[alias_pos] = nullptr; + + ret.s_port = port; + + auto proto_string = frg::string(getAllocator()); + if (!proto) { + if (serv_buf[0].protocol == IPPROTO_TCP) + proto_string = frg::string("tcp", getAllocator()); + else if (serv_buf[0].protocol == IPPROTO_UDP) + proto_string = frg::string("udp", getAllocator()); + else + return nullptr; + } else { + proto_string = frg::string(proto, getAllocator()); + } + ret.s_proto = proto_string.data(); + proto_string.detach(); + + return &ret; +} + +struct servent *getservent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void sethostent(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void setnetent(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void setprotoent(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void setservent(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +const char *hstrerror(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/poll.cpp b/user/include/mlibc/options/posix/generic/poll.cpp new file mode 100644 index 0000000..70a3caf --- /dev/null +++ b/user/include/mlibc/options/posix/generic/poll.cpp @@ -0,0 +1,43 @@ + +#include +#include + +#include +#include +#include + +int poll(struct pollfd *fds, nfds_t count, int timeout) { + int num_events; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_poll, -1); + if(int e = mlibc::sys_poll(fds, count, timeout, &num_events); e) { + errno = e; + return -1; + } + return num_events; +} + +#if __MLIBC_LINUX_OPTION + +#include + +int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask) { + if (mlibc::sys_ppoll) { + int num_events; + if(int e = mlibc::sys_ppoll(fds, nfds, timeout_ts, sigmask, &num_events); e) { + errno = e; + return -1; + } + return num_events; + } + + sigset_t origmask; + int timeout = (timeout_ts == nullptr) ? -1 : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000); + + sigprocmask(SIG_SETMASK, sigmask, &origmask); + int ready = poll(fds, nfds, timeout); + sigprocmask(SIG_SETMASK, &origmask, nullptr); + + return ready; +} +#endif // __MLIBC_LINUX_OPTION + diff --git a/user/include/mlibc/options/posix/generic/posix-file-io.cpp b/user/include/mlibc/options/posix/generic/posix-file-io.cpp new file mode 100644 index 0000000..1a4f38b --- /dev/null +++ b/user/include/mlibc/options/posix/generic/posix-file-io.cpp @@ -0,0 +1,275 @@ +#include +#include +#include + +#include + +namespace mlibc { + +int mem_file::reopen(const char *, const char *) { + mlibc::panicLogger() << "mlibc: freopen() on a mem_file stream is unimplemented!" << frg::endlog; + return -1; +} + +int mem_file::determine_type(stream_type *type) { + *type = stream_type::file_like; + return 0; +} + +int mem_file::determine_bufmode(buffer_mode *mode) { + *mode = buffer_mode::no_buffer; + return 0; +} + +memstream_mem_file::memstream_mem_file(char **ptr, size_t *sizeloc, int flags, void (*do_dispose)(abstract_file *)) +: mem_file{flags, do_dispose}, _bufloc{ptr}, _sizeloc{sizeloc} { } + + +int memstream_mem_file::close() { + _update_ptrs(); + _buf.detach(); + + return 0; +} + +int memstream_mem_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + if ((_pos >= 0 && _pos >= _max_size) || !max_size) { + *actual_size = 0; + return 0; + } + + size_t bytes_read = std::min(size_t(_max_size - _pos), max_size); + memcpy(buffer, _buffer().data() + _pos, bytes_read); + _pos += bytes_read; + *actual_size = bytes_read; + return 0; +} + +int memstream_mem_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + if (_pos + max_size >= _buffer_size()) { + _buf.resize(_pos + max_size + 1, '\0'); + _update_ptrs(); + } + + size_t bytes_write = std::min(static_cast(_buffer_size() - _pos), max_size); + memcpy(_buffer().data() + _pos, buffer, bytes_write); + _pos += max_size; + *actual_size = max_size; + + return 0; +} + +int memstream_mem_file::io_seek(off_t offset, int whence, off_t *new_offset) { + switch (whence) { + case SEEK_SET: + _pos = offset; + if (_pos >= 0 && size_t(_pos) >= _buffer_size()) { + _buf.resize(_pos + 1, '\0'); + _update_ptrs(); + } + *new_offset = _pos; + break; + case SEEK_CUR: + _pos += offset; + if (_pos >= 0 && size_t(_pos) >= _buffer_size()) { + _buf.resize(_pos + 1, '\0'); + _update_ptrs(); + } + *new_offset = _pos; + break; + case SEEK_END: + _pos = _buffer_size() ? _buffer_size() - 1 + offset : _buffer_size() + offset; + _buf.resize(_pos + 1, '\0'); + _update_ptrs(); + *new_offset = _pos; + break; + default: + return EINVAL; + } + return 0; +} + +void memstream_mem_file::_update_ptrs() { + *_bufloc = _buf.data(); + *_sizeloc = _buf.size() - 1; +} + +fmemopen_mem_file::fmemopen_mem_file(void *in_buf, size_t size, int flags, void (*do_dispose)(abstract_file *)) +: mem_file{flags, do_dispose}, _inBuffer{in_buf}, _inBufferSize{size} { + if(!_inBuffer) { + _inBuffer = getAllocator().allocate(size); + _needsDeallocation = true; + } + + if(_flags & O_APPEND) { + // the initial seek-size for append is zero if buf was NULL, or the first '\0' found, or the size + _max_size = (_needsDeallocation) ? 0 : strnlen(reinterpret_cast(_inBuffer), _inBufferSize); + _pos = _max_size; + } else if((_flags & O_WRONLY || _flags & O_RDWR) && _flags & O_CREAT && _flags & O_TRUNC) { + // modes: "w", "w+" + _max_size = 0; + } else { + _max_size = size; + } +} + +int fmemopen_mem_file::close() { + if(_needsDeallocation) { + getAllocator().free(_inBuffer); + } + + return 0; +} + +int fmemopen_mem_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + if ((_pos >= 0 && _pos >= _max_size) || !max_size) { + *actual_size = 0; + return 0; + } + + size_t bytes_read = std::min(size_t(_max_size - _pos), max_size); + memcpy(buffer, _buffer().data() + _pos, bytes_read); + _pos += bytes_read; + *actual_size = bytes_read; + return 0; +} + +int fmemopen_mem_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + off_t bytes_write = std::min(static_cast(_buffer_size() - _pos), max_size); + memcpy(_buffer().data() + _pos, buffer, bytes_write); + _pos += bytes_write; + *actual_size = bytes_write; + + if(_pos > _max_size) { + _max_size = _pos; + } + + // upon flushing, we need to put a null byte at the current position or at the end of the buffer + size_t null = _pos; + // a special case is if the mode is set to updating ('+'), then it always goes at the end + if(null >= _buffer_size() || _flags & O_RDWR) { + null = _buffer_size() - 1; + } + + if(_buffer_size()) { + _buffer()[null] = '\0'; + } + + return 0; +} + +int fmemopen_mem_file::io_seek(off_t offset, int whence, off_t *new_offset) { + switch (whence) { + case SEEK_SET: + if(offset < 0 || size_t(offset) > _buffer_size()) { + return EINVAL; + } + _pos = offset; + *new_offset = _pos; + break; + case SEEK_CUR: + // seeking to negative positions or positions larger than the buffer is disallowed in fmemopen(3) + if((_pos + offset) < 0 || size_t(_pos + offset) > _buffer_size()) { + return EINVAL; + } + _pos += offset; + *new_offset = _pos; + break; + case SEEK_END: + if((_max_size + offset) < 0 || size_t(_max_size + offset) > _buffer_size()) { + return EINVAL; + } + _pos = _max_size + offset; + *new_offset = _pos; + break; + default: + return EINVAL; + } + return 0; +} + +int cookie_file::close() { + if(!_funcs.close) { + return 0; + } + + return _funcs.close(_cookie); +} + +int cookie_file::reopen(const char *, const char *) { + mlibc::panicLogger() << "mlibc: freopen() on a cookie_file stream is unimplemented!" << frg::endlog; + return -1; +} + +int cookie_file::determine_type(stream_type *type) { + *type = stream_type::file_like; + return 0; +} + +int cookie_file::determine_bufmode(buffer_mode *mode) { + *mode = buffer_mode::no_buffer; + return 0; +} + +int cookie_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + if(!_funcs.read) { + return EOF; + } + + *actual_size = _funcs.read(_cookie, buffer, max_size); + + return 0; +} + +int cookie_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + if(!_funcs.write) { + return 0; + } + + *actual_size = _funcs.write(_cookie, buffer, max_size); + + return 0; +} + +int cookie_file::io_seek(off_t offset, int whence, off_t *new_offset) { + if(!_funcs.seek) { + return ENOTSUP; + } + + *new_offset = offset; + + return _funcs.seek(_cookie, new_offset, whence); +} + +} // namespace mlibc + +FILE *fdopen(int fd, const char *mode) { + int flags = mlibc::fd_file::parse_modestring(mode); + + flags &= ~O_TRUNC; // 'w' should not truncate the file + + if (flags & O_APPEND) { + int cur_flags = fcntl(fd, F_GETFL, 0); + if (cur_flags < 0) { + errno = EINVAL; + return nullptr; + } else if (!(cur_flags & O_APPEND)) { + if (fcntl(fd, F_SETFL, cur_flags | O_APPEND)) { + errno = EINVAL; + return nullptr; + } + } + } + + if (flags & O_CLOEXEC) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { + errno = EINVAL; + return nullptr; + } + } + + // TODO: We may need to activate line buffered mode for terminals. + + return frg::construct(getAllocator(), fd, + mlibc::file_dispose_cb); +} diff --git a/user/include/mlibc/options/posix/generic/posix_ctype.cpp b/user/include/mlibc/options/posix/generic/posix_ctype.cpp new file mode 100644 index 0000000..19f129f --- /dev/null +++ b/user/include/mlibc/options/posix/generic/posix_ctype.cpp @@ -0,0 +1,136 @@ +#include +#include + +#include + +int isalnum_l(int c, locale_t) { + return isalnum(c); +} + +int isalpha_l(int c, locale_t) { + return isalpha(c); +} + +int isblank_l(int c, locale_t) { + return isblank(c); +} + +int iscntrl_l(int c, locale_t) { + return iscntrl(c); +} + +int isdigit_l(int c, locale_t) { + return isdigit(c); +} + +int isgraph_l(int c, locale_t) { + return isgraph(c); +} + +int islower_l(int c, locale_t) { + return islower(c); +} + +int isprint_l(int c, locale_t) { + return isprint(c); +} + +int ispunct_l(int c, locale_t) { + return ispunct(c); +} + +int isspace_l(int c, locale_t) { + return isspace(c); +} + +int isupper_l(int c, locale_t) { + return isupper(c); +} + +int isxdigit_l(int c, locale_t) { + return isxdigit(c); +} + +int isascii_l(int c, locale_t) { + return isascii(c); +} + +int tolower_l(int c, locale_t) { + return tolower(c); +} + +int toupper_l(int c, locale_t) { + return toupper(c); +} + +int iswalnum_l(wint_t c, locale_t) { + return iswalnum(c); +} + +int iswblank_l(wint_t c, locale_t) { + return iswblank(c); +} + +int iswcntrl_l(wint_t c, locale_t) { + return iswcntrl(c); +} + +int iswdigit_l(wint_t c, locale_t) { + return iswdigit(c); +} + +int iswgraph_l(wint_t c, locale_t) { + return iswgraph(c); +} + +int iswlower_l(wint_t c, locale_t) { + return iswlower(c); +} + +int iswprint_l(wint_t c, locale_t) { + return iswprint(c); +} + +int iswpunct_l(wint_t c, locale_t) { + return iswpunct(c); +} + +int iswspace_l(wint_t c, locale_t) { + return iswspace(c); +} + +int iswupper_l(wint_t c, locale_t) { + return iswupper(c); +} + +int iswxdigit_l(wint_t c, locale_t) { + return iswxdigit(c); +} + +int iswalpha_l(wint_t c, locale_t) { + return iswalpha(c); +} + +wctype_t wctype_l(const char* p, locale_t) { + return wctype(p); +} + +int iswctype_l(wint_t w, wctype_t t, locale_t) { + return iswctype(w, t); +} + +wint_t towlower_l(wint_t c, locale_t) { + return towlower(c); +} + +wint_t towupper_l(wint_t c, locale_t) { + return towupper(c); +} + +wctrans_t wctrans_l(const char* c, locale_t) { + return wctrans(c); +} + +wint_t towctrans_l(wint_t c, wctrans_t desc, locale_t) { + return towctrans(c, desc); +} diff --git a/user/include/mlibc/options/posix/generic/posix_locale.cpp b/user/include/mlibc/options/posix/generic/posix_locale.cpp new file mode 100644 index 0000000..f19e623 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/posix_locale.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +namespace { + +bool newlocale_seen = false; +bool uselocale_seen = false; + +} // namespace + +locale_t newlocale(int, const char *, locale_t) { + // Due to all of the locale functions being stubs, the locale will not be used + if(!newlocale_seen) { + mlibc::infoLogger() << "mlibc: newlocale() is a no-op" << frg::endlog; + newlocale_seen = true; + } + return nullptr; +} + +void freelocale(locale_t) { + mlibc::infoLogger() << "mlibc: freelocale() is a no-op" << frg::endlog; + return; +} + +locale_t uselocale(locale_t) { + if(!uselocale_seen) { + mlibc::infoLogger() << "mlibc: uselocale() is a no-op" << frg::endlog; + uselocale_seen = true; + } + return nullptr; +} + +locale_t duplocale(locale_t) { + mlibc::infoLogger() << "mlibc: duplocale() is a no-op" << frg::endlog; + return nullptr; +} diff --git a/user/include/mlibc/options/posix/generic/posix_signal.cpp b/user/include/mlibc/options/posix/generic/posix_signal.cpp new file mode 100644 index 0000000..f41f98c --- /dev/null +++ b/user/include/mlibc/options/posix/generic/posix_signal.cpp @@ -0,0 +1,164 @@ + +#include +#include +#include +#include + +#include +#include + +int sigsuspend(const sigset_t *sigmask) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigsuspend, -1); + + // This is guaranteed to return an error (EINTR most probably) + errno = mlibc::sys_sigsuspend(sigmask); + return -1; +} + +int pthread_sigmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + if(mlibc::sys_thread_sigmask) { + if(int e = mlibc::sys_thread_sigmask(how, set, retrieve); e) { + return e; + } + return 0; + } + + if(!mlibc::sys_sigprocmask) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + if(int e = mlibc::sys_sigprocmask(how, set, retrieve); e) { + return e; + } + return 0; +} + +int pthread_kill(pthread_t thread, int sig) { + auto tcb = reinterpret_cast(thread); + auto pid = getpid(); + + if(!mlibc::sys_tgkill) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + + if(int e = mlibc::sys_tgkill(pid, tcb->tid, sig); e) { + return e; + } + + return 0; +} + +int sigaction(int signum, const struct sigaction *__restrict act, struct sigaction *__restrict oldact) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaction, -1); + if(int e = mlibc::sys_sigaction(signum, act, oldact); e) { + errno = e; + return -1; + } + return 0; +} + +int siginterrupt(int sig, int flag) { + int ret; + struct sigaction act; + + sigaction(sig, nullptr, &act); + if (flag) + act.sa_flags &= ~SA_RESTART; + else + act.sa_flags |= SA_RESTART; + + ret = sigaction(sig, &act, nullptr); + return ret; +} + +int kill(pid_t pid, int number) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_kill, -1); + if(int e = mlibc::sys_kill(pid, number); e) { + errno = e; + return -1; + } + return 0; +} + +int killpg(pid_t pgrp, int sig) { + if(pgrp > 1) { + return kill(-pgrp, sig); + } + + errno = EINVAL; + return -1; +} + +int sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigtimedwait, -1); + + int signo; + + if (int e = sysdep(set, info, timeout, &signo)) { + errno = e; + return -1; + } + + return signo; +} + +int sigwaitinfo(const sigset_t *__restrict set, siginfo_t *__restrict info) { + // NOTE: This assumes the sysdep behavior noted in mlibc/posix-sysdeps.hpp + return sigtimedwait(set, info, nullptr); +} + +int sigwait(const sigset_t *__restrict set, int *__restrict sig) { + if (int e = sigwaitinfo(set, nullptr); e < 0) { + return e; + } else { + if (sig) + *sig = e; + + return 0; + } +} + +int sigpending(sigset_t *set) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigpending, -1); + + if(int e = sysdep(set)) { + errno = e; + return -1; + } + + return 0; +} + +int sigaltstack(const stack_t *__restrict ss, stack_t *__restrict oss) { + if (ss && ss->ss_size < MINSIGSTKSZ && !(ss->ss_flags & SS_DISABLE)) { + errno = ENOMEM; + return -1; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaltstack, -1); + if (int e = mlibc::sys_sigaltstack(ss, oss); e) { + errno = e; + return -1; + } + + return 0; +} + +#if __MLIBC_GLIBC_OPTION +int sigisemptyset(const sigset_t *set) { + auto ptr = reinterpret_cast(set); + for(size_t i = 0; i < sizeof(sigset_t); i++) { + if(ptr[i]) { + return 0; + } + } + return 1; +} +#endif // __MLIBC_GLIBC_OPTION + +int sigqueue(pid_t, int, const union sigval) { + __ensure(!"sigqueue() not implemented"); + __builtin_unreachable(); +} + diff --git a/user/include/mlibc/options/posix/generic/posix_stdio.cpp b/user/include/mlibc/options/posix/generic/posix_stdio.cpp new file mode 100644 index 0000000..69caae0 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/posix_stdio.cpp @@ -0,0 +1,218 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct popen_file : mlibc::fd_file { + popen_file(int fd, void (*do_dispose)(abstract_file *) = nullptr) + : fd_file(fd, do_dispose) {} + + pid_t get_popen_pid() { + return _popen_pid; + } + + void set_popen_pid(pid_t new_pid) { + _popen_pid = new_pid; + } + +private: + // Underlying PID in case of popen() + pid_t _popen_pid; +}; + +FILE *fmemopen(void *buf, size_t size, const char *__restrict mode) { + int flags = mlibc::fd_file::parse_modestring(mode); + + return frg::construct(getAllocator(), buf, size, flags, + mlibc::file_dispose_cb); +} + +int pclose(FILE *stream) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1); + + auto file = static_cast(stream); + + int status; + pid_t pid = file->get_popen_pid(); + + fclose(file); + + if (mlibc::sys_waitpid(pid, &status, 0, nullptr, &pid) != 0) { + errno = ECHILD; + return -1; + } + + return status; +} + +FILE *popen(const char *command, const char *typestr) { + bool is_write; + pid_t child; + FILE *ret = nullptr; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork && mlibc::sys_dup2 && mlibc::sys_execve && + mlibc::sys_sigprocmask && mlibc::sys_sigaction && mlibc::sys_pipe, nullptr); + + if (typestr == nullptr) { + errno = EINVAL; + return nullptr; + } + + if (strstr(typestr, "w") != nullptr) { + is_write = true; + } else if (strstr(typestr, "r") != nullptr) { + is_write = false; + } else { + errno = EINVAL; + return nullptr; + } + + bool cloexec = false; + if (strstr(typestr, "e") != nullptr) { + // Set FD_CLOEXEC on the new file descriptor + cloexec = true; + } + + int fds[2]; + if (int e = mlibc::sys_pipe(fds, 0)) { + errno = e; + return nullptr; + } + + struct sigaction new_sa, old_int, old_quit; + sigset_t new_mask, old_mask; + + new_sa.sa_handler = SIG_IGN; + new_sa.sa_flags = 0; + sigemptyset(&new_sa.sa_mask); + mlibc::sys_sigaction(SIGINT, &new_sa, &old_int); + mlibc::sys_sigaction(SIGQUIT, &new_sa, &old_quit); + + sigemptyset(&new_mask); + sigaddset(&new_mask, SIGCHLD); + mlibc::sys_sigprocmask(SIG_BLOCK, &new_mask, &old_mask); + + int parent_end = is_write ? 1 : 0; + int child_end = is_write ? 0 : 1; + + if (int e = mlibc::sys_fork(&child)) { + errno = e; + mlibc::sys_close(fds[0]); + mlibc::sys_close(fds[1]); + } else if (!child) { + // For the child + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + mlibc::sys_close(fds[parent_end]); + + if (mlibc::sys_dup2(fds[child_end], 0, is_write ? 0 : 1)) { + __ensure(!"sys_dup2() failed in popen()"); + } + mlibc::sys_close(fds[child_end]); + + const char *args[] = { + "sh", "-c", command, nullptr + }; + + mlibc::sys_execve("/bin/sh", const_cast(args), environ); + _Exit(127); + } else { + // For the parent + mlibc::sys_close(fds[child_end]); + + ret = frg::construct( + getAllocator(), + fds[parent_end], + mlibc::file_dispose_cb + ); + __ensure(ret); + + auto file = static_cast(ret); + + file->set_popen_pid(child); + + if (cloexec == true) { + fcntl(file->fd(), F_SETFD, O_CLOEXEC); + } + } + + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + return ret; +} + +FILE *open_memstream(char **buf, size_t *sizeloc) { + return frg::construct(getAllocator(), buf, sizeloc, O_RDWR, + mlibc::file_dispose_cb); +} + +int fseeko(FILE *file_base, off_t offset, int whence) { + auto file = static_cast(file_base); + if(int e = file->seek(offset, whence); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("fseeko")]] int fseeko64(FILE *file_base, off64_t offset, int whence); + +off_t ftello(FILE *file_base) { + auto file = static_cast(file_base); + off_t current_offset; + if(int e = file->tell(¤t_offset); e) { + errno = e; + return -1; + } + return current_offset; +} + +[[gnu::alias("ftello")]] off64_t ftello64(FILE *file_base); + +int dprintf(int fd, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vdprintf(fd, format, args); + va_end(args); + return result; +} + +int vdprintf(int fd, const char *format, __builtin_va_list args) { + mlibc::fd_file file{fd}; + int ret = vfprintf(&file, format, args); + file.flush(); + return ret; +} + +char *fgetln(FILE *, size_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *tempnam(const char *, const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +FILE *fopencookie(void *cookie, const char *__restrict mode, cookie_io_functions_t funcs) { + int flags = mlibc::fd_file::parse_modestring(mode); + + return frg::construct(getAllocator(), cookie, flags, funcs, + mlibc::file_dispose_cb); +} diff --git a/user/include/mlibc/options/posix/generic/posix_stdlib.cpp b/user/include/mlibc/options/posix/generic/posix_stdlib.cpp new file mode 100644 index 0000000..54c96d8 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/posix_stdlib.cpp @@ -0,0 +1,569 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace { + constexpr bool debugPathResolution = false; +} // namespace + +// Borrowed from musl +static uint32_t init[] = { +0x00000000,0x5851f42d,0xc0b18ccf,0xcbb5f646, +0xc7033129,0x30705b04,0x20fd5db4,0x9a8b7f78, +0x502959d8,0xab894868,0x6c0356a7,0x88cdb7ff, +0xb477d43f,0x70a3a52b,0xa8e4baf1,0xfd8341fc, +0x8ae16fd9,0x742d2f7a,0x0d1f0796,0x76035e09, +0x40f7702c,0x6fa72ca5,0xaaa84157,0x58a0df74, +0xc74a0364,0xae533cc4,0x04185faf,0x6de3b115, +0x0cab8628,0xf043bfa4,0x398150e9,0x37521657}; + +static int n = 31; +static int i = 3; +static int j = 0; +static uint32_t *x = init + 1; + + +static uint32_t lcg31(uint32_t x) { + return (1103515245 * x + 12345) & 0x7fffffff; +} + +static uint64_t lcg64(uint64_t x) { + return 6364136223846793005ull * x + 1; +} + +static void *savestate(void) { + x[-1] = (n << 16) | (i << 8) | j; + return x - 1; +} + +static void loadstate(uint32_t *state) { + x = state + 1; + n = x[-1] >> 16; + i = (x[-1] >> 8) & 0xff; + j = x[-1] & 0xff; +} + +long random(void) { + long k; + + if(n == 0) { + k = x[0] = lcg31(x[0]); + return k; + } + x[i] += x[j]; + k = x[i] >> 1; + if(++i == n) + i = 0; + if(++j == n) + j = 0; + + return k; +} + +// erand, drand and srand are borrowed from musl +namespace { + +unsigned short seed_48[7] = { 0, 0, 0, 0xe66d, 0xdeec, 0x5, 0xb }; + +uint64_t eand48_step(unsigned short *xi, unsigned short *lc) { + uint64_t x = xi[0] | (xi[1] + 0U) << 16 | (xi[2] + 0ULL) << 32; + uint64_t a = lc[0] | (lc[1] + 0U) << 16 | (lc[2] + 0ULL) << 32; + x = a*x + lc[3]; + xi[0] = x; + xi[1] = x>>16; + xi[2] = x>>32; + return x & 0xffffffffffffull; +} + +} // namespace + +double erand48(unsigned short s[3]) { + union { + uint64_t u; + double f; + } x = { 0x3ff0000000000000ULL | eand48_step(s, seed_48+3)<<4 }; + return x.f - 1.0; +} + +double drand48(void) { + return erand48(seed_48); +} + +unsigned short *seed48(unsigned short *s) { + static unsigned short p[3]; + memcpy(p, seed_48, sizeof p); + memcpy(seed_48, s, sizeof p); + return p; +} + +void srand48(long int seed) { + unsigned short arr[3] = { 0x330e, (unsigned short) seed, (unsigned short) (seed>>16) }; + seed48(arr); +} + +long jrand48(unsigned short [3]) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long int mrand48(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// Borrowed from musl +void srandom(unsigned int seed) { + int k; + uint64_t s = seed; + + if(n == 0) { + x[0] = s; + return; + } + i = n == 31 || n == 7 ? 3 : 1; + j = 0; + for(k = 0; k < n; k++) { + s = lcg64(s); + x[k] = s >> 32; + } + // Make sure x contains at least one odd number + x[0] |= 1; +} + +char *initstate(unsigned int seed, char *state, size_t size) { + void *old; + + if(size < 8) + return nullptr; + old = savestate(); + if(size < 32) + n = 0; + else if(size < 64) + n = 7; + else if(size < 128) + n = 15; + else if(size < 256) + n = 31; + else + n = 63; + x = (uint32_t *)state + 1; + srandom(seed); + savestate(); + return (char *)old; +} + +char *setstate(char *state) { + void *old; + + old = savestate(); + loadstate((uint32_t *)state); + return (char *)old; +} + +// ---------------------------------------------------------------------------- +// Path handling. +// ---------------------------------------------------------------------------- + + +int mkostemps(char *pattern, int suffixlen, int flags) { + auto n = strlen(pattern); + if(n < (6 + static_cast(suffixlen))) { + errno = EINVAL; + return -1; + } + + flags &= ~O_WRONLY; + + for(size_t i = 0; i < 6; i++) { + if(pattern[n - (6 + suffixlen) + i] == 'X') + continue; + errno = EINVAL; + return -1; + } + + // TODO: Do an exponential search. + for(size_t i = 0; i < 999999; i++) { + char sfx = pattern[n - suffixlen]; + __ensure(sprintf(pattern + (n - (6 + suffixlen)), "%06zu", i) == 6); + pattern[n - suffixlen] = sfx; + + int fd; + if(int e = mlibc::sys_open(pattern, O_RDWR | O_CREAT | O_EXCL | flags, S_IRUSR | S_IWUSR, &fd); !e) { + return fd; + }else if(e != EEXIST) { + errno = e; + return -1; + } + } + + errno = EEXIST; + return -1; +} + +int mkostemp(char *pattern, int flags) { + return mkostemps(pattern, 0, flags); +} + +int mkstemp(char *path) { + return mkostemp(path, 0); +} + +int mkstemps(char *pattern, int suffixlen) { + return mkostemps(pattern, suffixlen, 0); +} + +char *mkdtemp(char *pattern) { + mlibc::infoLogger() << "mlibc mkdtemp(" << pattern << ") called" << frg::endlog; + auto n = strlen(pattern); + __ensure(n >= 6); + if(n < 6) { + errno = EINVAL; + return nullptr; + } + for(size_t i = 0; i < 6; i++) { + if(pattern[n - 6 + i] == 'X') + continue; + errno = EINVAL; + return nullptr; + } + + // TODO: Do an exponential search. + for(size_t i = 0; i < 999999; i++) { + __ensure(sprintf(pattern + (n - 6), "%06zu", i) == 6); + if(int e = mlibc::sys_mkdir(pattern, S_IRWXU); !e) { + return pattern; + }else if(e != EEXIST) { + errno = e; + return nullptr; + } + } + + errno = EEXIST; + return nullptr; +} + +char *realpath(const char *path, char *out) { + if(debugPathResolution) + mlibc::infoLogger() << "mlibc realpath(): Called on '" << path << "'" << frg::endlog; + frg::string_view path_view{path}; + + // In case of the root, the string only contains the null-terminator. + frg::small_vector resolv{getAllocator()}; + size_t ps; + + // If the path is relative, we have to preprend the working directory. + if(path[0] == '/') { + resolv.push_back(0); + ps = 1; + }else{ + // Try to getcwd() until the buffer is large enough. + resolv.resize(128); + int saved_errno = errno; + while(true) { + // getcwd could smash errno on failure + resize (ERANGE) + success, + // so we have to save and restore errno in that scenario. + char *ret = getcwd(resolv.data(), resolv.size()); + if(ret != nullptr) { + break; + } + + if(errno == ERANGE) { + errno = saved_errno; + resolv.resize(2 * resolv.size()); + }else{ + return nullptr; + } + } + frg::string_view cwd_view{resolv.data()}; + if(cwd_view == "/") { + // Restore our invariant that we only store the null-terminator for the root. + resolv.resize(1); + resolv[0] = 0; + }else{ + resolv.resize(cwd_view.size() + 1); + } + ps = 0; + } + + // Contains unresolved links as a relative path compared to resolv. + frg::small_vector lnk{getAllocator()}; + size_t ls = 0; + + auto process_segment = [&] (frg::string_view s_view) -> int { + if(debugPathResolution) + mlibc::infoLogger() << "mlibc realpath(): resolv is '" << resolv.data() << "'" + << ", segment is " << s_view.data() + << ", size: " << s_view.size() << frg::endlog; + + if(!s_view.size() || s_view == ".") { + // Keep resolv invariant. + return 0; + }else if(s_view == "..") { + // Remove a single segment from resolv. + if(resolv.size() > 1) { + auto slash = strrchr(resolv.data(), '/'); + __ensure(slash); // We never remove the leading sla. + resolv.resize((slash - resolv.data()) + 1); + *slash = 0; // Replace the slash by a null-terminator. + } + return 0; + } + + // Append the segment to resolv. + auto rsz = resolv.size(); + resolv[rsz - 1] = '/'; // Replace null-terminator by a slash. + resolv.resize(rsz + s_view.size() + 1); + memcpy(resolv.data() + rsz, s_view.data(), s_view.size()); + resolv[rsz + s_view.size()] = 0; + + // stat() the path to (1) see if it exists and (2) see if it is a link. + if(!mlibc::sys_stat) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + if(debugPathResolution) + mlibc::infoLogger() << "mlibc realpath(): stat()ing '" + << resolv.data() << "'" << frg::endlog; + struct stat st; + if(int e = mlibc::sys_stat(mlibc::fsfd_target::path, + -1, resolv.data(), AT_SYMLINK_NOFOLLOW, &st); e) + return e; + + if(S_ISLNK(st.st_mode)) { + if(debugPathResolution) { + mlibc::infoLogger() << "mlibc realpath(): Encountered symlink '" + << resolv.data() << "'" << frg::endlog; + } + + if(!mlibc::sys_readlink) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + + ssize_t sz = 0; + char path[512]; + + if (int e = mlibc::sys_readlink(resolv.data(), path, 512, &sz); e) + return e; + + if(debugPathResolution) { + mlibc::infoLogger() << "mlibc realpath(): Symlink resolves to '" + << frg::string_view{path, static_cast(sz)} << "'" << frg::endlog; + } + + if (path[0] == '/') { + // Absolute path, replace resolv + + // Ignore any trailing '/' so all results will not have one to keep consistency. + while(sz > 1 && path[sz - 1] == '/') + sz -= 1; + + resolv.resize(sz + 1); + strncpy(resolv.data(), path, sz); + resolv.data()[sz] = 0; + + if(debugPathResolution) { + mlibc::infoLogger() << "mlibc realpath(): Symlink is absolute, resolv: '" + << resolv.data() << "'" << frg::endlog; + } + } else { + // Relative path, revert changes to resolv, prepend to lnk + resolv.resize(rsz); + resolv[rsz - 1] = 0; + + auto lsz = lnk.size(); + lnk.resize((lsz - ls) + sz + 1); + memmove(lnk.data() + sz, lnk.data() + ls, lsz - ls); + memcpy(lnk.data(), path, sz); + lnk[(lsz - ls) + sz] = 0; + + ls = 0; + + if(debugPathResolution) { + mlibc::infoLogger() << "mlibc realpath(): Symlink is relative, resolv: '" + << resolv.data() << "' lnk: '" + << frg::string_view{lnk.data(), lnk.size()} << "'" << frg::endlog; + } + } + } + + return 0; + }; + + // Each iteration of this outer loop consumes segment of the input path. + // This design avoids copying the input path into lnk; + // the latter could often involve additional allocations. + while(ps < path_view.size()) { + frg::string_view ps_view; + if(auto slash = strchr(path + ps, '/'); slash) { + ps_view = frg::string_view{path + ps, static_cast(slash - (path + ps))}; + }else{ + ps_view = frg::string_view{path + ps, strlen(path) - ps}; + } + ps += ps_view.size() + 1; + + // Handle one segment from the input path. + if(int e = process_segment(ps_view); e) { + errno = e; + return nullptr; + } + + // This inner loop consumes segments of lnk. + while(ls < lnk.size()) { + frg::string_view ls_view; + if(auto slash = strchr(lnk.data() + ls, '/'); slash) { + ls_view = frg::string_view{lnk.data() + ls, static_cast(slash - (lnk.data() + ls))}; + }else{ + ls_view = frg::string_view{lnk.data() + ls, strlen(lnk.data()) - ls}; + } + ls += ls_view.size() + 1; + + // Handle one segment from the link + if(int e = process_segment(ls_view); e) { + errno = e; + return nullptr; + } + } + + // All of lnk was consumed, reset it + lnk.resize(0); + ls = 0; + } + + if(resolv.size() == 1) { + resolv.resize(0); + resolv.push_back('/'); + resolv.push_back(0); + } + + if(debugPathResolution) + mlibc::infoLogger() << "mlibc realpath(): Returns '" << resolv.data() << "'" << frg::endlog; + + if(resolv.size() > PATH_MAX) { + errno = ENAMETOOLONG; + return nullptr; + } + + if(!out) + out = reinterpret_cast(getAllocator().allocate(resolv.size())); + strcpy(out, resolv.data()); + return out; +} + +// ---------------------------------------------------------------------------- +// Pseudoterminals +// ---------------------------------------------------------------------------- + +int ptsname_r(int fd, char *buffer, size_t length) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ptsname, ENOSYS); + + if(int e = sysdep(fd, buffer, length); e) + return e; + + return 0; +} + +char *ptsname(int fd) { + static char buffer[128]; + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ptsname, NULL); + + if(int e = sysdep(fd, buffer, 128); e) { + errno = e; + return nullptr; + } + + return buffer; +} + +int posix_openpt(int flags) { + int fd, e; + + if(mlibc::sys_openpt) { + e = mlibc::sys_openpt(flags, &fd); + } else { + e = mlibc::sys_open("/dev/ptmx", flags, 0, &fd); + } + + if (e) { + errno = e; + return -1; + } else { + return fd; + } +} + +int unlockpt(int fd) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlockpt, -1); + + if(int e = sysdep(fd); e) { + errno = e; + return -1; + } + + return 0; +} + +int grantpt(int) { + return 0; +} + +double strtod_l(const char *__restrict__ nptr, char ** __restrict__ endptr, locale_t) { + mlibc::infoLogger() << "mlibc: strtod_l ignores locale!" << frg::endlog; + return strtod(nptr, endptr); +} + +long double strtold_l(const char *__restrict__, char ** __restrict__, locale_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +float strtof_l(const char *__restrict__ nptr, char **__restrict__ endptr, locale_t) { + mlibc::infoLogger() << "mlibc: strtof_l ignores locales" << frg::endlog; + return strtof(nptr, endptr); +} + +int strcoll_l(const char *, const char *, locale_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getsubopt(char **__restrict__, char *const *__restrict__, char **__restrict__) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *secure_getenv(const char *name) { + if (mlibc::rtldConfig().secureRequired) + return nullptr; + else + return getenv(name); +} + +void *reallocarray(void *ptr, size_t m, size_t n) { + if(n && m > -1 / n) { + errno = ENOMEM; + return nullptr; + } + + return realloc(ptr, m * n); +} + +char *canonicalize_file_name(const char *name) { + return realpath(name, nullptr); +} diff --git a/user/include/mlibc/options/posix/generic/posix_string.cpp b/user/include/mlibc/options/posix/generic/posix_string.cpp new file mode 100644 index 0000000..aedd354 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/posix_string.cpp @@ -0,0 +1,179 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include + +char *strdup(const char *string) { + auto num_bytes = strlen(string); + + char *new_string = (char *)malloc(num_bytes + 1); + if(!new_string) // TODO: set errno + return nullptr; + + memcpy(new_string, string, num_bytes); + new_string[num_bytes] = 0; + return new_string; +} + +char *strndup(const char *string, size_t max_size) { + auto num_bytes = strnlen(string, max_size); + char *new_string = (char *)malloc(num_bytes + 1); + if(!new_string) // TODO: set errno + return nullptr; + + memcpy(new_string, string, num_bytes); + new_string[num_bytes] = 0; + return new_string; +} + +char *stpcpy(char *__restrict dest, const char *__restrict src) { + auto n = strlen(src); + memcpy(dest, src, n + 1); + return dest + n; +} + +char *stpncpy(char *__restrict dest, const char *__restrict src, size_t n) { + size_t nulls, copied, srcLen = strlen(src); + if (n >= srcLen) { + nulls = n - srcLen; + copied = srcLen; + } else { + nulls = 0; + copied = n; + } + + memcpy(dest, src, copied); + memset(dest + srcLen, 0, nulls); + return dest + n - nulls; +} + +size_t strnlen(const char *s, size_t n) { + size_t len = 0; + while(len < n && s[len]) + ++len; + return len; +} + +char *strsep(char **m, const char *del) { + __ensure(m); + + auto tok = *m; + if(!tok) + return nullptr; + + // Replace the following delimiter by a null-terminator. + // After this loop: *p is null iff we reached the end of the string. + auto p = tok; + while(*p && !strchr(del, *p)) + p++; + + if(*p) { + *p = 0; + *m = p + 1; + }else{ + *m = nullptr; + } + return tok; +} + +char *strsignal(int sig) { + #define CASE_FOR(sigconst) case sigconst: s = #sigconst; break; + const char *s; + switch(sig) { + CASE_FOR(SIGABRT) + CASE_FOR(SIGFPE) + CASE_FOR(SIGILL) + CASE_FOR(SIGINT) + CASE_FOR(SIGSEGV) + CASE_FOR(SIGTERM) + CASE_FOR(SIGPROF) + CASE_FOR(SIGIO) + CASE_FOR(SIGPWR) + CASE_FOR(SIGALRM) + CASE_FOR(SIGBUS) + CASE_FOR(SIGCHLD) + CASE_FOR(SIGCONT) + CASE_FOR(SIGHUP) + CASE_FOR(SIGKILL) + CASE_FOR(SIGPIPE) + CASE_FOR(SIGQUIT) + CASE_FOR(SIGSTOP) + CASE_FOR(SIGTSTP) + CASE_FOR(SIGTTIN) + CASE_FOR(SIGTTOU) + CASE_FOR(SIGUSR1) + CASE_FOR(SIGUSR2) + CASE_FOR(SIGSYS) + CASE_FOR(SIGTRAP) + CASE_FOR(SIGURG) + CASE_FOR(SIGVTALRM) + CASE_FOR(SIGXCPU) + CASE_FOR(SIGXFSZ) + CASE_FOR(SIGWINCH) + default: + mlibc::infoLogger() << "mlibc: Unknown signal number " << sig << frg::endlog; + s = "Unknown signal number"; + } + return const_cast(s); +} + +char *strcasestr(const char *s, const char *pattern) { + size_t plen = strlen(pattern); + const char *p = s; + while(*p) { + // Need strncasecmp() to avoid checking past the end of a successful match. + if(!strncasecmp(p, pattern, plen)) + return const_cast(p); + ++p; + } + return nullptr; +} + +void *memccpy(void *__restrict, const void *__restrict, int, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// This implementation was taken from musl +void *memrchr(const void *m, int c, size_t n) { + const unsigned char *s = (const unsigned char *)m; + c = (unsigned char)c; + while(n--) { + if(s[n] == c) + return (void *)(s + n); + } + return nullptr; +} + +char *strerror_l(int errnum, locale_t) { + mlibc::infoLogger() << "mlibc: strerror_l locale is ignored!" << frg::endlog; + return strerror(errnum); +} + +// BSD extensions. +// Taken from musl +size_t strlcpy(char *d, const char *s, size_t n) { + char *d0 = d; + + if(!n--) + goto finish; + for(; n && (*d=*s); n--, s++, d++); + *d = 0; +finish: + return d-d0 + strlen(s); +} + +size_t strlcat(char *d, const char *s, size_t n) { + size_t l = strnlen(d, n); + if(l == n) { + return l + strlen(s); + } + return l + strlcpy(d + l, s, n - l); +} diff --git a/user/include/mlibc/options/posix/generic/posix_time.cpp b/user/include/mlibc/options/posix/generic/posix_time.cpp new file mode 100644 index 0000000..68ccbc5 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/posix_time.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include + +int timer_getoverrun(timer_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int utimes(const char *filename, const struct timeval times[2]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + struct timespec time[2]; + if(times == nullptr) { + time[0].tv_sec = UTIME_NOW; + time[0].tv_nsec = UTIME_NOW; + time[1].tv_sec = UTIME_NOW; + time[1].tv_nsec = UTIME_NOW; + } else { + time[0].tv_sec = times[0].tv_sec; + time[0].tv_nsec = times[0].tv_usec * 1000; + time[1].tv_sec = times[1].tv_sec; + time[1].tv_nsec = times[1].tv_usec * 1000; + } + + if (int e = mlibc::sys_utimensat(AT_FDCWD, filename, time, 0); e) { + errno = e; + return -1; + } + + return 0; +} + +int futimes(int, const struct timeval[2]) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int lutimes(const char *filename, const struct timeval tv[2]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + struct timespec time[2]; + if(tv == nullptr) { + time[0].tv_sec = UTIME_NOW; + time[0].tv_nsec = UTIME_NOW; + time[1].tv_sec = UTIME_NOW; + time[1].tv_nsec = UTIME_NOW; + } else { + time[0].tv_sec = tv[0].tv_sec; + time[0].tv_nsec = tv[0].tv_usec * 1000; + time[1].tv_sec = tv[1].tv_sec; + time[1].tv_nsec = tv[1].tv_usec * 1000; + } + + if (int e = mlibc::sys_utimensat(AT_FDCWD, filename, time, AT_SYMLINK_NOFOLLOW); e) { + errno = e; + return -1; + } + + return 0; +} diff --git a/user/include/mlibc/options/posix/generic/pthread.cpp b/user/include/mlibc/options/posix/generic/pthread.cpp new file mode 100644 index 0000000..32b4b0d --- /dev/null +++ b/user/include/mlibc/options/posix/generic/pthread.cpp @@ -0,0 +1,1428 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool enableTrace = false; + +struct ScopeTrace { + ScopeTrace(const char *file, int line, const char *function) + : _file(file), _line(line), _function(function) { + if(!enableTrace) + return; + mlibc::infoLogger() << "trace: Enter scope " + << _file << ":" << _line << " (in function " + << _function << ")" << frg::endlog; + } + + ~ScopeTrace() { + if(!enableTrace) + return; + mlibc::infoLogger() << "trace: Exit scope" << frg::endlog; + } + +private: + const char *_file; + int _line; + const char *_function; +}; + +#define SCOPE_TRACE() ScopeTrace(__FILE__, __LINE__, __FUNCTION__) + +static constexpr unsigned int mutexRecursive = 1; + +// TODO: either use uint32_t or determine the bit based on sizeof(int). +static constexpr unsigned int mutex_owner_mask = (static_cast(1) << 30) - 1; +static constexpr unsigned int mutex_waiters_bit = static_cast(1) << 31; + +// Only valid for the internal __mlibc_m mutex of wrlocks. +static constexpr unsigned int mutex_excl_bit = static_cast(1) << 30; + +static constexpr unsigned int rc_count_mask = (static_cast(1) << 31) - 1; +static constexpr unsigned int rc_waiters_bit = static_cast(1) << 31; + +static constexpr size_t default_stacksize = 0x200000; +static constexpr size_t default_guardsize = 4096; + +// ---------------------------------------------------------------------------- +// pthread_attr and pthread functions. +// ---------------------------------------------------------------------------- + +// pthread_attr functions. +int pthread_attr_init(pthread_attr_t *attr) { + *attr = pthread_attr_t{}; + attr->__mlibc_stacksize = default_stacksize; + attr->__mlibc_guardsize = default_guardsize; + attr->__mlibc_detachstate = PTHREAD_CREATE_JOINABLE; + return 0; +} + +int pthread_attr_destroy(pthread_attr_t *) { + return 0; +} + +int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) { + *detachstate = attr->__mlibc_detachstate; + return 0; +} +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) { + if (detachstate != PTHREAD_CREATE_DETACHED && + detachstate != PTHREAD_CREATE_JOINABLE) + return EINVAL; + + attr->__mlibc_detachstate = detachstate; + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t *__restrict attr, size_t *__restrict stacksize) { + *stacksize = attr->__mlibc_stacksize; + return 0; +} + +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) { + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + attr->__mlibc_stacksize = stacksize; + return 0; +} + +int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) { + *stackaddr = attr->__mlibc_stackaddr; + return 0; +} +int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) { + attr->__mlibc_stackaddr = stackaddr; + return 0; +} + +int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize) { + *stackaddr = attr->__mlibc_stackaddr; + *stacksize = attr->__mlibc_stacksize; + return 0; +} +int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize) { + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + attr->__mlibc_stacksize = stacksize; + attr->__mlibc_stackaddr = stackaddr; + return 0; +} + +int pthread_attr_getguardsize(const pthread_attr_t *__restrict attr, size_t *__restrict guardsize) { + *guardsize = attr->__mlibc_guardsize; + return 0; +} +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) { + attr->__mlibc_guardsize = guardsize; + return 0; +} + +int pthread_attr_getscope(const pthread_attr_t *attr, int *scope) { + *scope = attr->__mlibc_scope; + return 0; +} +int pthread_attr_setscope(pthread_attr_t *attr, int scope) { + if (scope != PTHREAD_SCOPE_SYSTEM && + scope != PTHREAD_SCOPE_PROCESS) + return EINVAL; + if (scope == PTHREAD_SCOPE_PROCESS) + return ENOTSUP; + attr->__mlibc_scope = scope; + return 0; +} + +int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched) { + *inheritsched = attr->__mlibc_inheritsched; + return 0; +} +int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched) { + if (inheritsched != PTHREAD_INHERIT_SCHED && + inheritsched != PTHREAD_EXPLICIT_SCHED) + return EINVAL; + attr->__mlibc_inheritsched = inheritsched; + return 0; +} + +int pthread_attr_getschedparam(const pthread_attr_t *__restrict attr, struct sched_param *__restrict schedparam) { + *schedparam = attr->__mlibc_schedparam; + return 0; +} +int pthread_attr_setschedparam(pthread_attr_t *__restrict attr, const struct sched_param *__restrict schedparam) { + // TODO: this is supposed to return EINVAL for when the schedparam doesn't make sense + // for the given schedpolicy. + attr->__mlibc_schedparam = *schedparam; + return 0; +} + +int pthread_attr_getschedpolicy(const pthread_attr_t *__restrict attr, int *__restrict policy) { + *policy = attr->__mlibc_schedpolicy; + return 0; +} +int pthread_attr_setschedpolicy(pthread_attr_t *__restrict attr, int policy) { + if (policy != SCHED_FIFO && policy != SCHED_RR && + policy != SCHED_OTHER) + return EINVAL; + attr->__mlibc_schedpolicy = policy; + return 0; +} + +#if __MLIBC_LINUX_OPTION +int pthread_attr_getaffinity_np(const pthread_attr_t *__restrict attr, + size_t cpusetsize, cpu_set_t *__restrict cpusetp) { + if (!attr) + return EINVAL; + + if (!attr->__mlibc_cpuset) { + memset(cpusetp, -1, cpusetsize); + return 0; + } + + for (size_t cnt = cpusetsize; cnt < attr->__mlibc_cpusetsize; cnt++) + if (reinterpret_cast(attr->__mlibc_cpuset)[cnt] != '\0') + return ERANGE; + + auto p = memcpy(cpusetp, attr->__mlibc_cpuset, + std::min(cpusetsize, attr->__mlibc_cpusetsize)); + if (cpusetsize > attr->__mlibc_cpusetsize) + memset(p, '\0', cpusetsize - attr->__mlibc_cpusetsize); + + return 0; +} + +int pthread_attr_setaffinity_np(pthread_attr_t *__restrict attr, + size_t cpusetsize, const cpu_set_t *__restrict cpusetp) { + if (!attr) + return EINVAL; + + if (!cpusetp || !cpusetsize) { + attr->__mlibc_cpuset = nullptr; + attr->__mlibc_cpusetsize = 0; + return 0; + } + + if (attr->__mlibc_cpusetsize != cpusetsize) { + auto newp = realloc(attr->__mlibc_cpuset, cpusetsize); + if (!newp) + return ENOMEM; + + attr->__mlibc_cpuset = static_cast(newp); + attr->__mlibc_cpusetsize = cpusetsize; + } + + memcpy(attr->__mlibc_cpuset, cpusetp, cpusetsize); + return 0; +} + +int pthread_attr_getsigmask_np(const pthread_attr_t *__restrict attr, + sigset_t *__restrict sigmask) { + if (!attr) + return EINVAL; + + if (!attr->__mlibc_sigmaskset) { + sigemptyset(sigmask); + return PTHREAD_ATTR_NO_SIGMASK_NP; + } + + *sigmask = attr->__mlibc_sigmask; + + return 0; +} +int pthread_attr_setsigmask_np(pthread_attr_t *__restrict attr, + const sigset_t *__restrict sigmask) { + if (!attr) + return EINVAL; + + if (!sigmask) { + attr->__mlibc_sigmaskset = 0; + return 0; + } + + attr->__mlibc_sigmask = *sigmask; + attr->__mlibc_sigmaskset = 1; + + // Filter out internally used signals. + sigdelset(&attr->__mlibc_sigmask, SIGCANCEL); + + return 0; +} + +namespace { + void get_own_stackinfo(void **stack_addr, size_t *stack_size) { + auto fp = fopen("/proc/self/maps", "r"); + if (!fp) { + mlibc::infoLogger() << "mlibc pthreads: /proc/self/maps does not exist! Producing incorrect" + " stack results!" << frg::endlog; + return; + } + + char line[256]; + auto sp = mlibc::get_sp(); + while (fgets(line, 256, fp)) { + uintptr_t from, to; + if(sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2) + continue; + if (sp < to && sp > from) { + // We need to return the lowest byte of the stack. + *stack_addr = reinterpret_cast(from); + *stack_size = to - from; + fclose(fp); + return; + } + } + + fclose(fp); + } +} // namespace + +int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) { + auto tcb = reinterpret_cast(thread); + *attr = pthread_attr_t{}; + + if (!tcb->stackAddr || !tcb->stackSize) { + get_own_stackinfo(&attr->__mlibc_stackaddr, &attr->__mlibc_stacksize); + } else { + attr->__mlibc_stacksize = tcb->stackSize; + attr->__mlibc_stackaddr = tcb->stackAddr; + } + + attr->__mlibc_guardsize = tcb->guardSize; + attr->__mlibc_detachstate = tcb->isJoinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED; + mlibc::infoLogger() << "pthread_getattr_np(): Implementation is incomplete!" << frg::endlog; + return 0; +} + +int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *mask) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getthreadaffinity, ENOSYS); + return mlibc::sys_getthreadaffinity(reinterpret_cast(thread)->tid, cpusetsize, mask); +} + +int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *mask) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setthreadaffinity, ENOSYS); + return mlibc::sys_setthreadaffinity(reinterpret_cast(thread)->tid, cpusetsize, mask); +} +#endif // __MLIBC_LINUX_OPTION + +extern "C" Tcb *__rtld_allocateTcb(); + +// pthread functions. +int pthread_create(pthread_t *__restrict thread, const pthread_attr_t *__restrict attrp, + void *(*entry) (void *), void *__restrict user_arg) { + return mlibc::thread_create(thread, attrp, reinterpret_cast(entry), user_arg, false); +} + +pthread_t pthread_self(void) { + return reinterpret_cast(mlibc::get_current_tcb()); +} + +int pthread_equal(pthread_t t1, pthread_t t2) { + if(t1 == t2) + return 1; + return 0; +} + +namespace { + struct key_global_info { + bool in_use; + + void (*dtor)(void *); + uint64_t generation; + }; + + constinit frg::array< + key_global_info, + PTHREAD_KEYS_MAX + > key_globals_{}; + + FutexLock key_mutex_; +} // namespace + +namespace mlibc { + __attribute__ ((__noreturn__)) void do_exit() { + sys_thread_exit(); + __builtin_unreachable(); + } +} // namespace mlibc + +__attribute__ ((__noreturn__)) void pthread_exit(void *ret_val) { + auto self = mlibc::get_current_tcb(); + + if (__atomic_load_n(&self->cancelBits, __ATOMIC_RELAXED) & tcbExitingBit) + mlibc::do_exit(); + + __atomic_fetch_or(&self->cancelBits, tcbExitingBit, __ATOMIC_RELAXED); + + auto hand = self->cleanupEnd; + while (hand) { + auto old = hand; + hand->func(hand->arg); + hand = hand->prev; + frg::destruct(getAllocator(), old); + } + + for (size_t j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) { + for (size_t i = 0; i < PTHREAD_KEYS_MAX; i++) { + if (auto v = pthread_getspecific(i)) { + key_mutex_.lock(); + auto dtor = key_globals_[i].dtor; + key_mutex_.unlock(); + + if (dtor) { + dtor(v); + (*self->localKeys)[i].value = nullptr; + } + } + } + } + + self->returnValue.voidPtr = ret_val; + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + // TODO: clean up thread resources when we are detached. + + // TODO: do exit(0) when we're the only thread instead + mlibc::do_exit(); +} + +int pthread_join(pthread_t thread, void **ret) { + return mlibc::thread_join(thread, ret); +} + +int pthread_detach(pthread_t thread) { + auto tcb = reinterpret_cast(thread); + if (!__atomic_load_n(&tcb->isJoinable, __ATOMIC_RELAXED)) + return EINVAL; + + int expected = 1; + if(!__atomic_compare_exchange_n(&tcb->isJoinable, &expected, 0, false, __ATOMIC_RELEASE, + __ATOMIC_RELAXED)) + return EINVAL; + + return 0; +} + +void pthread_cleanup_push(void (*func) (void *), void *arg) { + auto self = mlibc::get_current_tcb(); + + auto hand = frg::construct(getAllocator()); + hand->func = func; + hand->arg = arg; + hand->next = nullptr; + hand->prev = self->cleanupEnd; + + if (self->cleanupEnd) + self->cleanupEnd->next = hand; + + self->cleanupEnd = hand; + + if (!self->cleanupBegin) + self->cleanupBegin = self->cleanupEnd; +} + +void pthread_cleanup_pop(int execute) { + auto self = mlibc::get_current_tcb(); + + auto hand = self->cleanupEnd; + + if (self->cleanupEnd) + self->cleanupEnd = self->cleanupEnd->prev; + if (self->cleanupEnd) + self->cleanupEnd->next = nullptr; + + if (execute) + hand->func(hand->arg); + + frg::destruct(getAllocator(), hand); +} + +int pthread_setname_np(pthread_t thread, const char *name) { + auto tcb = reinterpret_cast(thread); + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_thread_setname, ENOSYS); + if(int e = sysdep(tcb, name); e) { + return e; + } + + return 0; +} + +int pthread_getname_np(pthread_t thread, char *name, size_t size) { + auto tcb = reinterpret_cast(thread); + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_thread_getname, ENOSYS); + if(int e = sysdep(tcb, name, size); e) { + return e; + } + + return 0; +} + +int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param) { + auto tcb = reinterpret_cast(thread); + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setschedparam, ENOSYS); + if(int e = mlibc::sys_setschedparam(tcb, policy, param); e) { + return e; + } + + return 0; +} + +int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param) { + auto tcb = reinterpret_cast(thread); + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getschedparam, ENOSYS); + if(int e = mlibc::sys_getschedparam(tcb, policy, param); e) { + return e; + } + + return 0; +} + +//pthread cancel functions + +extern "C" void __mlibc_do_cancel() { + //TODO(geert): for now the same as pthread_exit() + pthread_exit(PTHREAD_CANCELED); +} + +namespace { + + void sigcancel_handler(int signal, siginfo_t *info, void *ucontext) { + ucontext_t *uctx = static_cast(ucontext); + // The function could be called from other signals, or from another + // process, in which case we should do nothing. + if (signal != SIGCANCEL || info->si_pid != getpid() || + info->si_code != SI_TKILL) + return; + + auto tcb = reinterpret_cast(mlibc::get_current_tcb()); + int old_value = tcb->cancelBits; + + /* + * When a thread is marked with deferred cancellation and performs a blocking syscall, + * the spec mandates that the syscall can get interrupted before it has caused any side + * effects (e.g. before a read() has read any bytes from disk). If the syscall has + * already caused side effects it should return its partial work, and set the program + * counter just after the syscall. If the syscall hasn't caused any side effects, it + * should fail with EINTR and set the program counter to the syscall instruction. + * + * cancellable_syscall: + * test whether_a_cancel_is_queued + * je cancel + * syscall + * end_cancellable_syscall + * + * The mlibc::sys_before_cancellable_syscall sysdep should return 1 when the + * program counter is between the 'canellable_syscall' and 'end_cancellable_syscall' label. + */ + if (!(old_value & tcbCancelAsyncBit) && + mlibc::sys_before_cancellable_syscall && !mlibc::sys_before_cancellable_syscall(uctx)) + return; + + int bitmask = tcbCancelTriggerBit | tcbCancelingBit; + while (1) { + int new_value = old_value | bitmask; + + // Check if we are already cancelled or exiting + if (old_value == new_value || old_value & tcbExitingBit) + return; + + int current_value = old_value; + if (__atomic_compare_exchange_n(&tcb->cancelBits, ¤t_value, + new_value, true,__ATOMIC_RELAXED, __ATOMIC_RELAXED)) { + tcb->returnValue.voidPtr = PTHREAD_CANCELED; + + // Perform cancellation + __mlibc_do_cancel(); + + break; + } + + old_value = current_value; + } + } +} // namespace + +namespace mlibc { +namespace { + +struct PthreadSignalInstaller { + PthreadSignalInstaller() { + struct sigaction sa; + sa.sa_sigaction = sigcancel_handler; + sa.sa_flags = SA_SIGINFO; + auto e = ENOSYS; + if(sys_sigaction) + e = sys_sigaction(SIGCANCEL, &sa, nullptr); + // Opt-out of cancellation support. + if(e == ENOSYS) + return; + __ensure(!e); + } +}; + +PthreadSignalInstaller pthread_signal_installer; + +} // anonymous namespace +} // namespace mlibc + +int pthread_setcanceltype(int type, int *oldtype) { + if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) + return EINVAL; + + auto self = reinterpret_cast(mlibc::get_current_tcb()); + int old_value = self->cancelBits; + while (1) { + int new_value = old_value & ~tcbCancelAsyncBit; + if (type == PTHREAD_CANCEL_ASYNCHRONOUS) + new_value |= tcbCancelAsyncBit; + + if (oldtype) + *oldtype = ((old_value & tcbCancelAsyncBit) + ? PTHREAD_CANCEL_ASYNCHRONOUS + : PTHREAD_CANCEL_DEFERRED); + + // Avoid unecessary atomic op. + if (old_value == new_value) + break; + + int current_value = old_value; + if (__atomic_compare_exchange_n(&self->cancelBits, ¤t_value, + new_value, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { + + if (mlibc::tcb_async_cancelled(new_value)) + __mlibc_do_cancel(); + + break; + } + + old_value = current_value; + } + + return 0; +} +int pthread_setcancelstate(int state, int *oldstate) { + if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) + return EINVAL; + + auto self = reinterpret_cast(mlibc::get_current_tcb()); + int old_value = self->cancelBits; + while (1) { + int new_value = old_value & ~tcbCancelEnableBit; + if (state == PTHREAD_CANCEL_ENABLE) + new_value |= tcbCancelEnableBit; + + if (oldstate) + *oldstate = ((old_value & tcbCancelEnableBit) + ? PTHREAD_CANCEL_ENABLE + : PTHREAD_CANCEL_DISABLE); + + // Avoid unecessary atomic op. + if (old_value == new_value) + break; + + int current_value = old_value; + if (__atomic_compare_exchange_n(&self->cancelBits, ¤t_value, + new_value, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { + + if (mlibc::tcb_async_cancelled(new_value)) + __mlibc_do_cancel(); + + sigset_t set = {}; + sigaddset(&set, SIGCANCEL); + if (new_value & PTHREAD_CANCEL_ENABLE) + sigprocmask(SIG_UNBLOCK, &set, nullptr); + else + sigprocmask(SIG_BLOCK, &set, nullptr); + break; + } + + old_value = current_value; + } + + return 0; +} +void pthread_testcancel(void) { + auto self = reinterpret_cast(mlibc::get_current_tcb()); + int value = self->cancelBits; + if ((value & tcbCancelEnableBit) && (value & tcbCancelTriggerBit)) { + __mlibc_do_cancel(); + __builtin_unreachable(); + } +} +int pthread_cancel(pthread_t thread) { + if (!mlibc::sys_tgkill) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + + auto tcb = reinterpret_cast(thread); + // Check if the TCB is valid, somewhat.. + if (tcb->selfPointer != tcb) + return ESRCH; + + int old_value = __atomic_load_n(&tcb->cancelBits, __ATOMIC_RELAXED); + while (1) { + int bitmask = tcbCancelTriggerBit; + + int new_value = old_value | bitmask; + if (old_value == new_value) + break; + + int current_value = old_value; + if (__atomic_compare_exchange_n(&tcb->cancelBits, ¤t_value, + new_value, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { + if (mlibc::tcb_cancel_enabled(new_value)) { + pid_t pid = getpid(); + + int res = mlibc::sys_tgkill(pid, tcb->tid, SIGCANCEL); + + current_value = __atomic_load_n(&tcb->cancelBits, __ATOMIC_RELAXED); + + // If we can't find the thread anymore, it's possible that it exited between + // us setting the cancel trigger bit, and us sending the signal. Check the + // cancelBits for tcbExitingBit to confirm that. + // XXX(qookie): This will be an use-after-free once we start freeing TCBs on + // exit. Perhaps the TCB should be refcounted. + if (!(res == ESRCH && (current_value & tcbExitingBit))) + return res; + } + + break; + } + + old_value = current_value; + } + + return 0; +} + +int pthread_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void)) { + auto self = mlibc::get_current_tcb(); + + auto hand = frg::construct(getAllocator()); + if (!hand) + return -1; + + hand->prepare = prepare; + hand->parent = parent; + hand->child = child; + hand->next = nullptr; + hand->prev = self->atforkEnd; + + if (self->atforkEnd) + self->atforkEnd->next = hand; + + self->atforkEnd = hand; + + if (!self->atforkBegin) + self->atforkBegin = self->atforkEnd; + + return 0; +} + +// ---------------------------------------------------------------------------- +// pthread_key functions. +// ---------------------------------------------------------------------------- + +int pthread_key_create(pthread_key_t *out, void (*destructor)(void *)) { + SCOPE_TRACE(); + + auto g = frg::guard(&key_mutex_); + + pthread_key_t key = PTHREAD_KEYS_MAX; + for (size_t i = 0; i < PTHREAD_KEYS_MAX; i++) { + if (!key_globals_[i].in_use) { + key = i; + break; + } + } + + if (key == PTHREAD_KEYS_MAX) + return EAGAIN; + + key_globals_[key].in_use = true; + key_globals_[key].dtor = destructor; + + *out = key; + + return 0; +} + +int pthread_key_delete(pthread_key_t key) { + SCOPE_TRACE(); + + auto g = frg::guard(&key_mutex_); + + if (key >= PTHREAD_KEYS_MAX || !key_globals_[key].in_use) + return EINVAL; + + key_globals_[key].in_use = false; + key_globals_[key].dtor = nullptr; + key_globals_[key].generation++; + + return 0; +} + +void *pthread_getspecific(pthread_key_t key) { + SCOPE_TRACE(); + + auto self = mlibc::get_current_tcb(); + auto g = frg::guard(&key_mutex_); + + if (key >= PTHREAD_KEYS_MAX || !key_globals_[key].in_use) + return nullptr; + + if (key_globals_[key].generation > (*self->localKeys)[key].generation) { + (*self->localKeys)[key].value = nullptr; + (*self->localKeys)[key].generation = key_globals_[key].generation; + } + + return (*self->localKeys)[key].value; +} + +int pthread_setspecific(pthread_key_t key, const void *value) { + SCOPE_TRACE(); + + auto self = mlibc::get_current_tcb(); + auto g = frg::guard(&key_mutex_); + + if (key >= PTHREAD_KEYS_MAX || !key_globals_[key].in_use) + return EINVAL; + + (*self->localKeys)[key].value = const_cast(value); + (*self->localKeys)[key].generation = key_globals_[key].generation; + + return 0; +} + +// ---------------------------------------------------------------------------- +// pthread_once functions. +// ---------------------------------------------------------------------------- + +static constexpr unsigned int onceComplete = 1; +static constexpr unsigned int onceLocked = 2; + +int pthread_once(pthread_once_t *once, void (*function) (void)) { + SCOPE_TRACE(); + + auto expected = __atomic_load_n(&once->__mlibc_done, __ATOMIC_ACQUIRE); + + // fast path: the function was already run. + while(!(expected & onceComplete)) { + if(!expected) { + // try to acquire the mutex. + if(!__atomic_compare_exchange_n(&once->__mlibc_done, + &expected, onceLocked, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) + continue; + + function(); + + // unlock the mutex. + __atomic_exchange_n(&once->__mlibc_done, onceComplete, __ATOMIC_RELEASE); + if(int e = mlibc::sys_futex_wake((int *)&once->__mlibc_done); e) + __ensure(!"sys_futex_wake() failed"); + return 0; + }else{ + // a different thread is currently running the initializer. + __ensure(expected == onceLocked); + // if the wait gets interrupted by a signal, check again. + // EAGAIN will also be a retry, as it means the other thread completed + // and changed the __mlibc_done variable to signal it before we actually went to sleep. + if(int e = mlibc::sys_futex_wait((int *)&once->__mlibc_done, onceLocked, nullptr); e && e != EINTR && e != EAGAIN) + __ensure(!"sys_futex_wait() failed"); + expected = __atomic_load_n(&once->__mlibc_done, __ATOMIC_ACQUIRE); + } + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// pthread_mutexattr and pthread_mutex functions. +// ---------------------------------------------------------------------------- + +// pthread_mutexattr functions +int pthread_mutexattr_init(pthread_mutexattr_t *attr) { + SCOPE_TRACE(); + return mlibc::thread_mutexattr_init(attr); +} + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) { + SCOPE_TRACE(); + return mlibc::thread_mutexattr_destroy(attr); +} + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict attr, int *__restrict type) { + return mlibc::thread_mutexattr_gettype(attr, type); +} + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) { + return mlibc::thread_mutexattr_settype(attr, type); +} + +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict attr, + int *__restrict robust) { + *robust = attr->__mlibc_robust; + return 0; +} +int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust) { + if (robust != PTHREAD_MUTEX_STALLED && robust != PTHREAD_MUTEX_ROBUST) + return EINVAL; + + attr->__mlibc_robust = robust; + return 0; +} + +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared) { + *pshared = attr->__mlibc_pshared; + return 0; +} +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) { + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + attr->__mlibc_pshared = pshared; + return 0; +} + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict attr, + int *__restrict protocol) { + *protocol = attr->__mlibc_protocol; + return 0; +} + +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol) { + if (protocol != PTHREAD_PRIO_NONE && protocol != PTHREAD_PRIO_INHERIT + && protocol != PTHREAD_PRIO_PROTECT) + return EINVAL; + + attr->__mlibc_protocol = protocol; + return 0; +} + +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict attr, + int *__restrict prioceiling) { + (void)attr; + (void)prioceiling; + return EINVAL; +} + +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling) { + (void)attr; + (void)prioceiling; + return EINVAL; +} + +// pthread_mutex functions +int pthread_mutex_init(pthread_mutex_t *__restrict mutex, + const pthread_mutexattr_t *__restrict attr) { + SCOPE_TRACE(); + + return mlibc::thread_mutex_init(mutex, attr); +} + +int pthread_mutex_destroy(pthread_mutex_t *mutex) { + return mlibc::thread_mutex_destroy(mutex); +} + +int pthread_mutex_lock(pthread_mutex_t *mutex) { + SCOPE_TRACE(); + + return mlibc::thread_mutex_lock(mutex); +} + +int pthread_mutex_trylock(pthread_mutex_t *mutex) { + SCOPE_TRACE(); + + unsigned int this_tid = mlibc::this_tid(); + unsigned int expected = __atomic_load_n(&mutex->__mlibc_state, __ATOMIC_RELAXED); + if(!expected) { + // Try to take the mutex here. + if(__atomic_compare_exchange_n(&mutex->__mlibc_state, + &expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + __ensure(!mutex->__mlibc_recursion); + mutex->__mlibc_recursion = 1; + return 0; + } + } else { + // If this (recursive) mutex is already owned by us, increment the recursion level. + if((expected & mutex_owner_mask) == this_tid) { + if(!(mutex->__mlibc_flags & mutexRecursive)) { + return EBUSY; + } + ++mutex->__mlibc_recursion; + return 0; + } + } + + return EBUSY; +} + +int pthread_mutex_timedlock(pthread_mutex_t *__restrict, + const struct timespec *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int pthread_mutex_unlock(pthread_mutex_t *mutex) { + SCOPE_TRACE(); + + return mlibc::thread_mutex_unlock(mutex); +} + +int pthread_mutex_consistent(pthread_mutex_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// ---------------------------------------------------------------------------- +// pthread_condattr and pthread_cond functions. +// ---------------------------------------------------------------------------- + +int pthread_condattr_init(pthread_condattr_t *attr) { + attr->__mlibc_pshared = PTHREAD_PROCESS_PRIVATE; + attr->__mlibc_clock = CLOCK_REALTIME; + return 0; +} + +int pthread_condattr_destroy(pthread_condattr_t *attr) { + memset(attr, 0, sizeof(*attr)); + return 0; +} + +int pthread_condattr_getclock(const pthread_condattr_t *__restrict attr, + clockid_t *__restrict clock) { + *clock = attr->__mlibc_clock; + return 0; +} + +int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock) { + if (clock != CLOCK_REALTIME && clock != CLOCK_MONOTONIC + && clock != CLOCK_MONOTONIC_RAW && clock != CLOCK_REALTIME_COARSE + && clock != CLOCK_MONOTONIC_COARSE && clock != CLOCK_BOOTTIME) + return EINVAL; + + attr->__mlibc_clock = clock; + return 0; +} + +int pthread_condattr_getpshared(const pthread_condattr_t *__restrict attr, + int *__restrict pshared) { + *pshared = attr->__mlibc_pshared; + return 0; +} + +int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared) { + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + attr->__mlibc_pshared = pshared; + return 0; +} + +int pthread_cond_init(pthread_cond_t *__restrict cond, const pthread_condattr_t *__restrict attr) { + SCOPE_TRACE(); + + return mlibc::thread_cond_init(cond, attr); +} + +int pthread_cond_destroy(pthread_cond_t *cond) { + SCOPE_TRACE(); + + return mlibc::thread_cond_destroy(cond); +} + +int pthread_cond_wait(pthread_cond_t *__restrict cond, pthread_mutex_t *__restrict mutex) { + return pthread_cond_timedwait(cond, mutex, nullptr); +} + +int pthread_cond_timedwait(pthread_cond_t *__restrict cond, pthread_mutex_t *__restrict mutex, + const struct timespec *__restrict abstime) { + return mlibc::thread_cond_timedwait(cond, mutex, abstime); +} + +int pthread_cond_signal(pthread_cond_t *cond) { + SCOPE_TRACE(); + + return pthread_cond_broadcast(cond); +} + +int pthread_cond_broadcast(pthread_cond_t *cond) { + SCOPE_TRACE(); + + return mlibc::thread_cond_broadcast(cond); +} + +// ---------------------------------------------------------------------------- +// pthread_barrierattr and pthread_barrier functions. +// ---------------------------------------------------------------------------- + +int pthread_barrierattr_init(pthread_barrierattr_t *attr) { + attr->__mlibc_pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict attr, + int *__restrict pshared) { + *pshared = attr->__mlibc_pshared; + return 0; +} + +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) { + if (pshared != PTHREAD_PROCESS_SHARED && pshared != PTHREAD_PROCESS_PRIVATE) + return EINVAL; + + attr->__mlibc_pshared = pshared; + return 0; +} + +int pthread_barrierattr_destroy(pthread_barrierattr_t *) { + return 0; +} + +int pthread_barrier_init(pthread_barrier_t *__restrict barrier, + const pthread_barrierattr_t *__restrict attr, unsigned count) { + if (count == 0) + return EINVAL; + + barrier->__mlibc_waiting = 0; + barrier->__mlibc_inside = 0; + barrier->__mlibc_seq = 0; + barrier->__mlibc_count = count; + + // Since we don't implement these yet, set a flag to error later. + auto pshared = attr ? attr->__mlibc_pshared : PTHREAD_PROCESS_PRIVATE; + barrier->__mlibc_flags = pshared; + + return 0; +} + +int pthread_barrier_destroy(pthread_barrier_t *barrier) { + // Wait until there are no threads still using the barrier. + unsigned inside = 0; + do { + unsigned expected = __atomic_load_n(&barrier->__mlibc_inside, __ATOMIC_RELAXED); + if (expected == 0) + break; + + int e = mlibc::sys_futex_wait((int *)&barrier->__mlibc_inside, expected, nullptr); + if (e != 0 && e != EAGAIN && e != EINTR) + mlibc::panicLogger() << "mlibc: sys_futex_wait() returned error " << e << frg::endlog; + } while (inside > 0); + + memset(barrier, 0, sizeof *barrier); + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t *barrier) { + if (barrier->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_barrier_t flags were non-zero" + << frg::endlog; + } + + // inside is incremented on entry and decremented on exit. + // This is used to synchronise with pthread_barrier_destroy, to ensure that a thread doesn't pass + // the barrier and immediately destroy its state while other threads still rely on it. + + __atomic_fetch_add(&barrier->__mlibc_inside, 1, __ATOMIC_ACQUIRE); + + auto leave = [&](){ + unsigned inside = __atomic_sub_fetch(&barrier->__mlibc_inside, 1, __ATOMIC_RELEASE); + if (inside == 0) + mlibc::sys_futex_wake((int *)&barrier->__mlibc_inside); + }; + + unsigned seq = __atomic_load_n(&barrier->__mlibc_seq, __ATOMIC_ACQUIRE); + + while (true) { + unsigned expected = __atomic_load_n(&barrier->__mlibc_waiting, __ATOMIC_RELAXED); + bool swapped = __atomic_compare_exchange_n(&barrier->__mlibc_waiting, &expected, expected + 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); + + if (swapped) { + if (expected + 1 == barrier->__mlibc_count) { + // We were the last thread to hit the barrier. Reset waiters and wake the others. + __atomic_fetch_add(&barrier->__mlibc_seq, 1, __ATOMIC_ACQUIRE); + __atomic_store_n(&barrier->__mlibc_waiting, 0, __ATOMIC_RELEASE); + + mlibc::sys_futex_wake((int *)&barrier->__mlibc_seq); + + leave(); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + + while (true) { + int e = mlibc::sys_futex_wait((int *)&barrier->__mlibc_seq, seq, nullptr); + if (e != 0 && e != EAGAIN && e != EINTR) + mlibc::panicLogger() << "mlibc: sys_futex_wait() returned error " << e << frg::endlog; + + unsigned newSeq = __atomic_load_n(&barrier->__mlibc_seq, __ATOMIC_ACQUIRE); + if (newSeq > seq) { + leave(); + return 0; + } + } + } + } +} + +// ---------------------------------------------------------------------------- +// pthread_rwlock functions. +// ---------------------------------------------------------------------------- + +namespace { + void rwlock_m_lock(pthread_rwlock_t *rw, bool excl) { + unsigned int m_expected = __atomic_load_n(&rw->__mlibc_m, __ATOMIC_RELAXED); + while(true) { + if(m_expected) { + __ensure(m_expected & mutex_owner_mask); + + // Try to set the waiters bit. + if(!(m_expected & mutex_waiters_bit)) { + unsigned int desired = m_expected | mutex_waiters_bit; + if(!__atomic_compare_exchange_n(&rw->__mlibc_m, + &m_expected, desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + continue; + } + + // Wait on the futex. + mlibc::sys_futex_wait((int *)&rw->__mlibc_m, m_expected | mutex_waiters_bit, nullptr); + + // Opportunistically try to take the lock after we wake up. + m_expected = 0; + }else{ + // Try to lock the mutex. + unsigned int desired = 1; + if(excl) + desired |= mutex_excl_bit; + if(__atomic_compare_exchange_n(&rw->__mlibc_m, + &m_expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + break; + } + } + } + + int rwlock_m_trylock(pthread_rwlock_t *rw, bool excl) { + unsigned int m_expected = __atomic_load_n(&rw->__mlibc_m, __ATOMIC_RELAXED); + if(!m_expected) { + // Try to lock the mutex. + unsigned int desired = 1; + if(excl) + desired |= mutex_excl_bit; + if(__atomic_compare_exchange_n(&rw->__mlibc_m, + &m_expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + return 0; + } + + __ensure(m_expected & mutex_owner_mask); + + // POSIX says that this function should never block but also that + // readers should not be blocked by readers. We implement this by returning EAGAIN + // (and not EBUSY) if a reader would block a reader. + if(!excl && !(m_expected & mutex_excl_bit)) + return EAGAIN; + + return EBUSY; + } + + void rwlock_m_unlock(pthread_rwlock_t *rw) { + auto m = __atomic_exchange_n(&rw->__mlibc_m, 0, __ATOMIC_RELEASE); + if(m & mutex_waiters_bit) + mlibc::sys_futex_wake((int *)&rw->__mlibc_m); + } +} // namespace + +int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) { + attr->__mlibc_pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict attr, + int *__restrict pshared) { + *pshared = attr->__mlibc_pshared; + return 0; +} + +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) { + if (pshared != PTHREAD_PROCESS_SHARED && pshared != PTHREAD_PROCESS_PRIVATE) + return EINVAL; + + attr->__mlibc_pshared = pshared; + return 0; +} + +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *) { + return 0; +} + +int pthread_rwlock_init(pthread_rwlock_t *__restrict rw, const pthread_rwlockattr_t *__restrict attr) { + SCOPE_TRACE(); + rw->__mlibc_m = 0; + rw->__mlibc_rc = 0; + + // Since we don't implement this yet, set a flag to error later. + auto pshared = attr ? attr->__mlibc_pshared : PTHREAD_PROCESS_PRIVATE; + rw->__mlibc_flags = pshared; + return 0; +} + +int pthread_rwlock_destroy(pthread_rwlock_t *rw) { + __ensure(!rw->__mlibc_m); + __ensure(!rw->__mlibc_rc); + return 0; +} + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + if (rw->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_rwlock_t flags were non-zero" + << frg::endlog; + } + + // Take the __mlibc_m mutex. + // Will be released in pthread_rwlock_unlock(). + if(int e = rwlock_m_trylock(rw, true)) + return e; + + // Check that there are no readers. + unsigned int rc_expected = __atomic_load_n(&rw->__mlibc_rc, __ATOMIC_ACQUIRE); + if(rc_expected) { + rwlock_m_unlock(rw); + return EBUSY; + } + + return 0; +} + +int pthread_rwlock_wrlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + if (rw->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_rwlock_t flags were non-zero" + << frg::endlog; + } + + // Take the __mlibc_m mutex. + // Will be released in pthread_rwlock_unlock(). + rwlock_m_lock(rw, true); + + // Now wait until there are no more readers. + unsigned int rc_expected = __atomic_load_n(&rw->__mlibc_rc, __ATOMIC_ACQUIRE); + while(true) { + if(!rc_expected) + break; + + __ensure(rc_expected & rc_count_mask); + + // Try to set the waiters bit. + if(!(rc_expected & rc_waiters_bit)) { + unsigned int desired = rc_expected | rc_count_mask; + if(!__atomic_compare_exchange_n(&rw->__mlibc_rc, + &rc_expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) + continue; + } + + // Wait on the futex. + mlibc::sys_futex_wait((int *)&rw->__mlibc_rc, rc_expected | rc_waiters_bit, nullptr); + + // Re-check the reader counter. + rc_expected = __atomic_load_n(&rw->__mlibc_rc, __ATOMIC_ACQUIRE); + } + + return 0; +} + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + if (rw->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_rwlock_t flags were non-zero" + << frg::endlog; + } + + // Increment the reader count while holding the __mlibc_m mutex. + if(int e = rwlock_m_trylock(rw, false); e) + return e; + __atomic_fetch_add(&rw->__mlibc_rc, 1, __ATOMIC_ACQUIRE); + rwlock_m_unlock(rw); + + return 0; +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + if (rw->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_rwlock_t flags were non-zero" + << frg::endlog; + } + + // Increment the reader count while holding the __mlibc_m mutex. + rwlock_m_lock(rw, false); + __atomic_fetch_add(&rw->__mlibc_rc, 1, __ATOMIC_ACQUIRE); + rwlock_m_unlock(rw); + + return 0; +} + +int pthread_rwlock_unlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + unsigned int rc_expected = __atomic_load_n(&rw->__mlibc_rc, __ATOMIC_RELAXED); + if(!rc_expected) { + // We are doing a write-unlock. + rwlock_m_unlock(rw); + return 0; + }else{ + // We are doing a read-unlock. + while(true) { + unsigned int count = rc_expected & rc_count_mask; + __ensure(count); + + // Try to decrement the count. + if(count == 1 && (rc_expected & rc_waiters_bit)) { + unsigned int desired = 0; + if(!__atomic_compare_exchange_n(&rw->__mlibc_rc, + &rc_expected, desired, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) + continue; + + // Wake the futex. + mlibc::sys_futex_wake((int *)&rw->__mlibc_rc); + break; + }else{ + unsigned int desired = (rc_expected & ~rc_count_mask) | (count - 1); + if(!__atomic_compare_exchange_n(&rw->__mlibc_rc, + &rc_expected, desired, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) + continue; + break; + } + } + + return 0; + } +} + +int pthread_getcpuclockid(pthread_t, clockid_t *) { + mlibc::infoLogger() << "mlibc: pthread_getcpuclockid() always returns ENOENT" + << frg::endlog; + return ENOENT; +} diff --git a/user/include/mlibc/options/posix/generic/pwd.cpp b/user/include/mlibc/options/posix/generic/pwd.cpp new file mode 100644 index 0000000..75093e1 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/pwd.cpp @@ -0,0 +1,309 @@ + +#include +#include +#include +#include +#include + +#include + +namespace { + FILE *global_file; // Used by setpwent/getpwent/endpwent. + + bool open_global_file() { + if(!global_file) { + global_file = fopen("/etc/passwd", "r"); + if(!global_file) { + errno = EIO; + return false; + } + } + + return true; + } + + void close_global_file() { + if(global_file) { + fclose(global_file); + global_file = nullptr; + } + } + + bool extract_entry(frg::string_view line, passwd *entry) { + frg::string_view segments[8]; + + // Parse the line into 7 or 8 segments. + size_t s = 0; + int n; + for(n = 0; n < 7; n++) { + size_t d = line.find_first(':', s); + if(d == size_t(-1)) + break; + segments[n] = line.sub_string(s, d - s); + s = d + 1; + } + if(line.find_first(':', s) != size_t(-1)) + return false; + segments[n] = line.sub_string(s, line.size() - s); + n++; + + if(n < 7) + return false; + + // TODO: Handle strndup() failure. + auto name = strndup(segments[0].data(), segments[0].size()); + __ensure(name); + + auto passwd = strndup(segments[1].data(), segments[1].size()); + __ensure(passwd); + + auto uid = segments[2].to_number(); + if(!uid) + return false; + auto gid = segments[3].to_number(); + if(!gid) + return false; + + auto real_name = strndup(segments[4].data(), segments[4].size()); + __ensure(real_name); + auto dir = strndup(segments[5].data(), segments[5].size()); + __ensure(dir); + auto shell = strndup(segments[6].data(), segments[6].size()); + __ensure(shell); + + // Chop the newline off the end of shell + __ensure(strlen(shell) > 0); + shell[strlen(shell) - 1] = '\0'; + + entry->pw_name = name; + entry->pw_passwd = passwd; + entry->pw_uid = *uid; + entry->pw_gid = *gid; + entry->pw_dir = dir; + entry->pw_shell = shell; + entry->pw_gecos = real_name; + return true; + } + + void copy_to_buffer(passwd *pwd, char *buffer, size_t size) { + char *pw_dir = stpcpy(buffer, pwd->pw_name) + 1; + free(pwd->pw_name); + pwd->pw_name = buffer; + + char *pw_shell = stpcpy(pw_dir, pwd->pw_dir) + 1; + free(pwd->pw_dir); + pwd->pw_dir = pw_dir; + + char *pw_passwd = stpcpy(pw_shell, pwd->pw_shell) + 1; + free(pwd->pw_shell); + pwd->pw_shell = pw_shell; + + char *end = stpcpy(pw_passwd, pwd->pw_passwd); + __ensure(end <= buffer + size); + free(pwd->pw_passwd); + pwd->pw_passwd = pw_passwd; + } + + void clear_entry(passwd *entry) { + free(entry->pw_name); + free(entry->pw_dir); + free(entry->pw_passwd); + free(entry->pw_shell); + entry->pw_name = nullptr; + entry->pw_dir = nullptr; + entry->pw_passwd = nullptr; + entry->pw_shell = nullptr; + } +} // namespace + +struct passwd *getpwent(void) { + static passwd entry; + char line[NSS_BUFLEN_PASSWD]; + + if(!open_global_file()) { + return nullptr; + } + + if (fgets(line, NSS_BUFLEN_PASSWD, global_file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) { + errno = EINVAL; // I suppose this can be a valid errno? + return nullptr; + } + return &entry; + } + + if(ferror(global_file)) { + errno = EIO; + } + + return nullptr; +} + +struct passwd *getpwnam(const char *name) { + static passwd entry; + auto file = fopen("/etc/passwd", "r"); + if(!file) + return nullptr; + + char line[NSS_BUFLEN_PASSWD]; + while(fgets(line, NSS_BUFLEN_PASSWD, file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) + continue; + if(!strcmp(entry.pw_name, name)) { + fclose(file); + return &entry; + } + } + + int err = errno; + if(ferror(file)) { + err = EIO; + } + + fclose(file); + errno = err; + return nullptr; +} + +int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t size, struct passwd **result) { + *result = nullptr; + auto file = fopen("/etc/passwd", "r"); + if(!file) { + return EIO; + } + + char line[NSS_BUFLEN_PASSWD]; + while(fgets(line, NSS_BUFLEN_PASSWD, file)) { + if(!extract_entry(line, pwd)) + continue; + if(!strcmp(pwd->pw_name, name)) { + fclose(file); + + size_t required_size = strlen(pwd->pw_name) + strlen(pwd->pw_dir) + + strlen(pwd->pw_shell) + strlen(pwd->pw_passwd) + 4; + if (size < required_size) + return ERANGE; + + copy_to_buffer(pwd, buffer, size); + *result = pwd; + return 0; + } + } + + int ret = 0; + if(ferror(file)) { + ret = EIO; + } + + fclose(file); + return ret; +} + +struct passwd *getpwuid(uid_t uid) { + static passwd entry; + auto file = fopen("/etc/passwd", "r"); + if(!file) + return nullptr; + + char line[NSS_BUFLEN_PASSWD]; + while(fgets(line, NSS_BUFLEN_PASSWD, file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) + continue; + if(entry.pw_uid == uid) { + fclose(file); + return &entry; + } + } + + int err = ESRCH; + if(ferror(file)) { + err = EIO; + } + + fclose(file); + errno = err; + return nullptr; +} + +int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t size, struct passwd **result) { + *result = nullptr; + auto file = fopen("/etc/passwd", "r"); + if(!file) { + return EIO; + } + + char line[NSS_BUFLEN_PASSWD]; + while(fgets(line, NSS_BUFLEN_PASSWD, file)) { + if(!extract_entry(line, pwd)) + continue; + if(pwd->pw_uid == uid) { + fclose(file); + + size_t required_size = strlen(pwd->pw_name) + strlen(pwd->pw_dir) + + strlen(pwd->pw_shell) + + strlen(pwd->pw_passwd) + 4; + if (size < required_size) + return ERANGE; + + copy_to_buffer(pwd, buffer, size); + *result = pwd; + return 0; + } + } + + int ret = 0; + if(ferror(file)) { + ret = EIO; + } + + fclose(file); + return ret; +} + +void setpwent(void) { + if(!open_global_file()) { + return; + } + rewind(global_file); +} + +void endpwent(void) { + close_global_file(); +} + +int putpwent(const struct passwd *p, FILE *f) { + auto invalid = [](const char *s) { + return s == nullptr || strchr(s, '\n') || strchr(s, ':'); + }; + + if (p == nullptr || invalid(p->pw_name) || invalid(p->pw_passwd) || invalid(p->pw_gecos) || invalid(p->pw_dir) || invalid(p->pw_shell)) { + errno = EINVAL; + return -1; + } + + // Taken from musl. + return fprintf(f, "%s:%s:%u:%u:%s:%s:%s\n", p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell) < 0 ? -1 : 0; +} + +struct passwd *fgetpwent(FILE *file) { + static passwd entry; + char line[NSS_BUFLEN_PASSWD]; + + + if (fgets(line, NSS_BUFLEN_PASSWD, file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) { + errno = EINVAL; // I suppose this can be a valid errno? + return nullptr; + } + return &entry; + } + + if(ferror(file)) { + errno = EIO; + } + + return nullptr; +} diff --git a/user/include/mlibc/options/posix/generic/resolv_conf.cpp b/user/include/mlibc/options/posix/generic/resolv_conf.cpp new file mode 100644 index 0000000..a5c3aa7 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/resolv_conf.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +namespace mlibc { + +frg::optional get_nameserver() { + auto file = fopen("/etc/resolv.conf", "r"); + if (!file) + return frg::null_opt; + + char line[128]; + struct nameserver_data ret; + while (fgets(line, 128, file)) { + char *pos; + if (!strchr(line, '\n') && !feof(file)) { + // skip truncated lines + for (int c = getc(file); c != '\n' && c != EOF; c = getc(file)); + continue; + } + + // TODO(geert): resolv.conf can actually have multiple nameservers + // but we just pick the first one for now + if (!strncmp(line, "nameserver", 10) && isspace(line[10])) { + char *end; + for (pos = line + 11; isspace(*pos); pos++); + for (end = pos; *end && !isspace(*end); end++); + *end = '\0'; + ret.name = frg::string( + pos, end - pos, getAllocator()); + break; + } + } + + fclose(file); + if(ret.name.empty()) + return frg::null_opt; + return ret; +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/posix/generic/sched.cpp b/user/include/mlibc/options/posix/generic/sched.cpp new file mode 100644 index 0000000..52f01f6 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sched.cpp @@ -0,0 +1,63 @@ + +#include +#include +#include +#include + +#include +#include + +int sched_yield(void) { + if(mlibc::sys_yield) { + mlibc::sys_yield(); + }else{ + // Missing sched_yield() is not an error. + MLIBC_MISSING_SYSDEP(); + } + return 0; +} + +int sched_get_priority_max(int policy) { + int res = 0; + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_get_max_priority, -1); + if(int e = sysdep(policy, &res); e) { + errno = e; + return -1; + } + return res; +} + +int sched_get_priority_min(int policy) { + int res = 0; + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_get_min_priority, -1); + if(int e = sysdep(policy, &res); e) { + errno = e; + return -1; + } + return res; +} + +int sched_setscheduler(pid_t, int, const struct sched_param *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sched_getparam(pid_t pid, struct sched_param *param) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getparam, -1); + if(int e = sysdep(pid, param); e) { + errno = e; + return -1; + } + return 0; +} + +int sched_setparam(pid_t pid, const struct sched_param *param) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setparam, -1); + if(int e = sysdep(pid, param); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/posix/generic/search.cpp b/user/include/mlibc/options/posix/generic/search.cpp new file mode 100644 index 0000000..5c57cf8 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/search.cpp @@ -0,0 +1,185 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct node { + const void *key; + void *a[2]; + int h; +}; + +namespace { + int height(struct node *node) { + return node ? node->h : 0; + } + + int rotate(struct node **nodep, int side) { + struct node *node = *nodep; + struct node *x = static_cast(node->a[side]); + struct node *y = static_cast(x->a[!side]); + struct node *z = static_cast(x->a[side]); + + int height_node = node->h; + int height_y = height(y); + if (height_y > height(z)) { + // Perform double rotation + node->a[side] = y->a[!side]; + x->a[!side] = y->a[side]; + y->a[!side] = node; + y->a[side] = x; + node->h = height_y; + x->h = height_y; + y->h = height_y + 1; + } else { + // Perform single rotation + node->a[side] = y; + x->a[!side] = node; + node->h = height_y + 1; + x->h = height_y + 2; + y = x; + + } + *nodep = y; + return y->h - height_node; + } + + int balance_tree(struct node **nodep) { + struct node *node = *nodep; + int height_a = height(static_cast(node->a[0])); + int height_b = height(static_cast(node->a[1])); + if (height_a - height_b < 2) { + int old = node->h; + node->h = height_a < height_b ? height_b + 1 : height_a + 1; + return node->h - old; + } + + return rotate(nodep, height_a < height_b); + } +} // namespace + +void *tsearch(const void *key, void **rootp, int(*compar)(const void *, const void *)) { + if (!rootp) + return nullptr; + + struct node *n = static_cast(*rootp); + frg::stack nodes(getAllocator()); + nodes.push(reinterpret_cast(rootp)); + int c = 0; + for (;;) { + if (!n) + break; + c = compar(key, n->key); + if (!c) + return n; + nodes.push(reinterpret_cast(&n->a[c > 0])); + n = static_cast(n->a[c > 0]); + } + + struct node *insert = static_cast(malloc(sizeof(struct node))); + if (!insert) + return nullptr; + insert->key = key; + insert->a[0] = insert->a[1] = nullptr; + insert->h = 1; + + (*nodes.top()) = insert; + nodes.pop(); + while(nodes.size() && balance_tree(nodes.top())) nodes.pop(); + return insert; +} + +// This implementation is taken from musl +void *tfind(const void *key, void *const *rootp, int (*compar)(const void *, const void *)) { + if(!rootp) + return nullptr; + + struct node *n = (struct node *)*rootp; + for(;;) { + if(!n) + break; + int c = compar(key, n->key); + if(!c) + break; + n = (struct node *)n->a[c > 0]; + } + return n; +} + +void *tdelete(const void *, void **, int(*compar)(const void *, const void *)) { + (void)compar; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void twalk(const void *, void (*action)(const void *, VISIT, int)) { + (void)action; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void tdestroy(void *root, void (*free_node)(void *)) { + auto *n = static_cast(root); + frg::stack nodes(getAllocator()); + + while(n || !nodes.empty()) { + if(n == nullptr) { + n = nodes.top(); + nodes.pop(); + free_node(const_cast(n->key)); + auto *next = static_cast(n->a[1]); + free(n); + n = next; + } else { + nodes.push(n); + n = static_cast(n->a[0]); + } + } +} + +void *lsearch(const void *key, void *base, size_t *nelp, size_t width, + int (*compar)(const void *, const void *)) { + (void)key; + (void)base; + (void)nelp; + (void)width; + (void)compar; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void *lfind(const void *key, const void *base, size_t *nelp, + size_t width, int (*compar)(const void *, const void *)) { + (void)key; + (void)base; + (void)nelp; + (void)width; + (void)compar; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +namespace { + hsearch_data globalTable {}; +} // namespace + +int hcreate(size_t num_entries) { + return mlibc::hcreate_r(num_entries, &globalTable); +} + +void hdestroy(void) { + mlibc::hdestroy_r(&globalTable); +} + +ENTRY *hsearch(ENTRY item, ACTION action) { + ENTRY *ret; + if(mlibc::hsearch_r(item, action, &ret, &globalTable) == 0) { + return nullptr; + } + return ret; +} diff --git a/user/include/mlibc/options/posix/generic/semaphore.cpp b/user/include/mlibc/options/posix/generic/semaphore.cpp new file mode 100644 index 0000000..741cd24 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/semaphore.cpp @@ -0,0 +1,115 @@ +#include +#include + +#include +#include +#include +#include + +static constexpr unsigned int semaphoreHasWaiters = static_cast(1 << 31); +static constexpr unsigned int semaphoreCountMask = static_cast(1 << 31) - 1; + +int sem_init(sem_t *sem, int pshared, unsigned int initial_count) { + if (pshared) { + mlibc::infoLogger() << "mlibc: shared semaphores are unsuppored" << frg::endlog; + errno = ENOSYS; + return -1; + } + + if (initial_count > SEM_VALUE_MAX) { + errno = EINVAL; + return -1; + } + + sem->__mlibc_count = initial_count; + + return 0; +} + +int sem_destroy(sem_t *) { + return 0; +} + +int sem_wait(sem_t *sem) { + unsigned int state = 0; + + while (1) { + if (!(state & semaphoreCountMask)) { + if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, semaphoreHasWaiters, + false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + int e = mlibc::sys_futex_wait((int *)&sem->__mlibc_count, state, nullptr); + if (e == 0 || e == EAGAIN) { + continue; + } else if (e == EINTR) { + errno = EINTR; + return -1; + } else { + mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog; + } + } + } else { + unsigned int desired = (state - 1); + if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, desired, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + return 0; + } + } +} + +int sem_timedwait(sem_t *sem, const struct timespec *) { + mlibc::infoLogger() << "\e[31mmlibc: sem_timedwait is implemented as sem_wait\e[0m" << frg::endlog; + return sem_wait(sem); +} + +int sem_post(sem_t *sem) { + auto old_count = __atomic_load_n(&sem->__mlibc_count, __ATOMIC_RELAXED) & semaphoreCountMask; + + if (old_count + 1 > SEM_VALUE_MAX) { + errno = EOVERFLOW; + return -1; + } + + auto state = __atomic_exchange_n(&sem->__mlibc_count, old_count + 1, __ATOMIC_RELEASE); + + if (state & semaphoreHasWaiters) + if (int e = mlibc::sys_futex_wake((int *)&sem->__mlibc_count); e) + __ensure(!"sys_futex_wake() failed"); + + return 0; +} + +sem_t *sem_open(const char *, int, ...) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sem_close(sem_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sem_getvalue(sem_t *, int *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sem_unlink(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sem_trywait(sem_t *sem) { + while (true) { + auto state = __atomic_load_n(&sem->__mlibc_count, __ATOMIC_ACQUIRE); + + if ((state & semaphoreHasWaiters) || !state) { + errno = EAGAIN; + return -1; + } + + auto desired = state - 1; + if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, desired, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) { + return 0; + } + } +} diff --git a/user/include/mlibc/options/posix/generic/services.cpp b/user/include/mlibc/options/posix/generic/services.cpp new file mode 100644 index 0000000..2db9ba2 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/services.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +static int parse_rest(service_buf &buf, char *end, int proto) { + if (!strncmp(end, "/udp", 4)) { + if (proto == IPPROTO_TCP && proto != -1) + return 0; + buf.protocol = IPPROTO_UDP; + buf.socktype = SOCK_DGRAM; + } else if (!strncmp(end, "/tcp", 4)) { + if (proto == IPPROTO_UDP && proto != -1) + return 0; + buf.protocol = IPPROTO_TCP; + buf.socktype = SOCK_STREAM; + } else { + return 0; + } + + //TODO(geert): also parse aliases. + + return 1; +} + +static int lookup_serv_file_port(service_result &buf, int proto, int port) { + auto file = fopen(_PATH_SERVICES, "r"); + if (!file) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return -EAI_SERVICE; + default: + return -EAI_SYSTEM; + } + } + + char line_buf[129] = {0}; + char *line = line_buf + 1; + while(fgets(line, 128, file)) { + int name_length = 0; + char *pos; + // easy way to handle comments, just move the end of the line + // to the beginning of the comment + if ((pos = strchr(line, '#'))) { + *pos++ = '\n'; + *pos = '\0'; + } + + char *end = nullptr; + for (pos = line; *pos; pos++) { + for (; isalpha(*pos); pos++); + int rport = strtoul(pos, &end, 10); + if (rport != port || rport > 65535) { + pos = end; + continue; + } + + // We have found the port, time to rewind to the start + // of the line. + for (; pos[-1]; pos--) + if(!isspace(pos[-1])) + name_length++; + break; + } + + if (!pos) + continue; + + if (!name_length) + continue; + + auto name = frg::string(pos, name_length, + getAllocator()); + + struct service_buf sbuf = {}; + sbuf.port = port; + sbuf.name = std::move(name); + if (!parse_rest(sbuf, end, proto)) + continue; + buf.push_back(std::move(sbuf)); + } + + fclose(file); + return buf.size(); +} + +static int lookup_serv_file_name(service_result &buf, const char *name, + int proto) { + auto file = fopen(_PATH_SERVICES, "r"); + if (!file) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return -EAI_SERVICE; + default: + return -EAI_SYSTEM; + } + } + + char line[128]; + int name_length = strlen(name); + while(fgets(line, 128, file)) { + char *pos; + // easy way to handle comments, just move the end of the line + // to the beginning of the comment + if ((pos = strchr(line, '#'))) { + *pos++ = '\n'; + *pos = '\0'; + } + + for (pos = line; (pos = strstr(pos, name)); pos++) { + // the name must start and end with a space + if (pos > line && !isspace(pos[-1])) + continue; + if (pos[name_length] && !isspace(pos[name_length])) + continue; + break; + } + if (!pos) + continue; + + // Skip the name at the beginning of the line. + for(pos = line; *pos && !isspace(*pos); pos++) + ; + + char *end = nullptr; + int port = strtoul(pos, &end, 10); + if (port > 65535 || end == pos) + continue; + + struct service_buf sbuf; + sbuf.port = port; + sbuf.name = frg::string(name, getAllocator()); + if (!parse_rest(sbuf, end, proto)) + continue; + + buf.push_back(sbuf); + + } + + fclose(file); + return buf.size(); +} + + +// This function returns a negative error code, since a positive +// return code means success. +int lookup_serv_by_name(service_result &buf, const char *name, int proto, + int socktype, int flags) { + switch(socktype) { + case SOCK_STREAM: + if (!proto) + proto = IPPROTO_TCP; + else if (proto != IPPROTO_TCP) + return -EAI_SERVICE; + break; + case SOCK_DGRAM: + if (!proto) + proto = IPPROTO_UDP; + else if (proto != IPPROTO_UDP) + return -EAI_SERVICE; + break; + case 0: + break; + default: + if (name) + return -EAI_SERVICE; + buf[0].port = 0; + buf[0].socktype = socktype; + buf[0].protocol = proto; + return 1; + } + + char *end = nullptr; + unsigned int port = 0; + int count = 0; + + if (name) { + if (!*name) + return -EAI_SERVICE; + port = strtoul(name, &end, 10); + } + // The end pointer is a null pointer so the name was a port + // or the name was not specified. + if (!end || !*end) { + if (proto != IPPROTO_UDP) { + buf[count].port = port; + buf[count].protocol = IPPROTO_TCP; + buf[count].socktype = SOCK_STREAM; + count++; + } + if (proto != IPPROTO_TCP) { + buf[count].port = port; + buf[count].protocol = IPPROTO_UDP; + buf[count].socktype = SOCK_DGRAM; + count++; + } + return count; + } + + if (flags & AI_NUMERICSERV) + return -EAI_NONAME; + + return lookup_serv_file_name(buf, name, proto); +} + +int lookup_serv_by_port(service_result &buf, int proto, int port) { + return lookup_serv_file_port(buf, proto, port); +} + +} // namespace mlibc diff --git a/user/include/mlibc/options/posix/generic/spawn.cpp b/user/include/mlibc/options/posix/generic/spawn.cpp new file mode 100644 index 0000000..b3ff604 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/spawn.cpp @@ -0,0 +1,376 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Musl places this in a seperate header called fdop.h + * This header isn't present in glibc, or on my host, so I + * include it's contents here + */ + +#define FDOP_CLOSE 1 +#define FDOP_DUP2 2 +#define FDOP_OPEN 3 +#define FDOP_CHDIR 4 +#define FDOP_FCHDIR 5 + +struct fdop { + struct fdop *next, *prev; + int cmd, fd, srcfd, oflag; + mode_t mode; + char path[]; +}; + +/* + * This posix_spawn implementation is taken from musl + */ + +static unsigned long handler_set[NSIG / (8 * sizeof(long))]; + +static void __get_handler_set(sigset_t *set) { + memcpy(set, handler_set, sizeof handler_set); +} + +struct args { + int p[2]; + sigset_t oldmask; + const char *path; + const posix_spawn_file_actions_t *fa; + const posix_spawnattr_t *__restrict attr; + char *const *argv, *const *envp; +}; + +static int child(void *args_vp) { + int i, ret; + struct sigaction sa = {}; + struct args *args = (struct args *)args_vp; + int p = args->p[1]; + const posix_spawn_file_actions_t *fa = args->fa; + const posix_spawnattr_t *__restrict attr = args->attr; + sigset_t hset; + bool use_execvpe = false; + + if(attr->__fn) + use_execvpe = true; + + close(args->p[0]); + + /* All signal dispositions must be either SIG_DFL or SIG_IGN + * before signals are unblocked. Otherwise a signal handler + * from the parent might get run in the child while sharing + * memory, with unpredictable and dangerous results. To + * reduce overhead, sigaction has tracked for us which signals + * potentially have a signal handler. */ + __get_handler_set(&hset); + for(i = 1; i < NSIG; i++) { + if((attr->__flags & POSIX_SPAWN_SETSIGDEF) && sigismember(&attr->__def, i)) { + sa.sa_handler = SIG_DFL; + } else if(sigismember(&hset, i)) { + if (i - 32 < 3) { + sa.sa_handler = SIG_IGN; + } else {; + sigaction(i, nullptr, &sa); + if(sa.sa_handler == SIG_IGN) + continue; + sa.sa_handler = SIG_DFL; + } + } else { + continue; + } + sigaction(i, &sa, nullptr); + } + + if(attr->__flags & POSIX_SPAWN_SETSID) { + if((ret = setsid()) < 0) + goto fail; + } + + if(attr->__flags & POSIX_SPAWN_SETPGROUP) { + mlibc::infoLogger() << "mlibc: posix_spawn: ignoring SETPGROUP" << frg::endlog; + //if((ret = setpgid(0, attr->__pgrp))) + // goto fail; + } + + if(attr->__flags & POSIX_SPAWN_RESETIDS) { + if((ret = setgid(getgid())) || (ret = setuid(getuid())) ) + goto fail; + } + + if(fa && fa->__actions) { + struct fdop *op; + int fd; + for(op = (struct fdop *)fa->__actions; op->next; op = op->next); + for(; op; op = op->prev) { + /* It's possible that a file operation would clobber + * the pipe fd used for synchronizing with the + * parent. To avoid that, we dup the pipe onto + * an unoccupied fd. */ + if(op->fd == p) { + ret = dup(p); + if(ret < 0) + goto fail; + close(p); + p = ret; + } + switch(op->cmd) { + case FDOP_CLOSE: + close(op->fd); + break; + case FDOP_DUP2: + fd = op->srcfd; + if(fd == p) { + ret = -EBADF; + goto fail; + } + if(fd != op->fd) { + if((ret = dup2(fd, op->fd)) < 0) + goto fail; + } else { + ret = fcntl(fd, F_GETFD); + ret = fcntl(fd, F_SETFD, ret & ~FD_CLOEXEC); + if(ret < 0) + goto fail; + } + break; + case FDOP_OPEN: + fd = open(op->path, op->oflag, op->mode); + if((ret = fd) < 0) + goto fail; + if(fd != op->fd) { + if((ret = dup2(fd, op->fd)) < 0) + goto fail; + close(fd); + } + break; + case FDOP_CHDIR: + ret = chdir(op->path); + if(ret < 0) + goto fail; + break; + case FDOP_FCHDIR: + ret = fchdir(op->fd); + if(ret < 0) + goto fail; + break; + } + } + } + + /* Close-on-exec flag may have been lost if we moved the pipe + * to a different fd. */ + fcntl(p, F_SETFD, FD_CLOEXEC); + + pthread_sigmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK) + ? &attr->__mask : &args->oldmask, nullptr); + + if(use_execvpe) + execvpe(args->path, args->argv, args->envp); + else + execve(args->path, args->argv, args->envp); + ret = -errno; + +fail: + /* Since sizeof errno < PIPE_BUF, the write is atomic. */ + ret = -ret; + if(ret) + while(write(p, &ret, sizeof ret) < 0); + _exit(127); +} + +int posix_spawn(pid_t *__restrict res, const char *__restrict path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *__restrict attrs, + char *const argv[], char *const envp[]) { + pid_t pid; + int ec = 0, cs; + struct args args; + const posix_spawnattr_t empty_attr = {}; + sigset_t full_sigset; + sigfillset(&full_sigset); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + args.path = path; + args.fa = file_actions; + args.attr = attrs ? attrs : &empty_attr; + args.argv = argv; + args.envp = envp; + pthread_sigmask(SIG_BLOCK, &full_sigset, &args.oldmask); + + /* The lock guards both against seeing a SIGABRT disposition change + * by abort and against leaking the pipe fd to fork-without-exec. */ + //LOCK(__abort_lock); + + if(pipe2(args.p, O_CLOEXEC)) { + //UNLOCK(__abort_lock); + ec = errno; + goto fail; + } + + /* Mlibc change: We use fork + execve, as clone is not implemented. + * This yields the same result in the end. */ + //pid = clone(child, stack + sizeof stack, CLONE_VM | CLONE_VFORK | SIGCHLD, &args); + pid = fork(); + if(!pid) { + child(&args); + } + close(args.p[1]); + //UNLOCK(__abort_lock); + + if(pid > 0) { + if(read(args.p[0], &ec, sizeof ec) != sizeof ec) + ec = 0; + else + waitpid(pid, nullptr, 0); + } else { + ec = -pid; + } + + close(args.p[0]); + + if(!ec && res) + *res = pid; + +fail: + pthread_sigmask(SIG_SETMASK, &args.oldmask, nullptr); + pthread_setcancelstate(cs, nullptr); + + return ec; +} + +int posix_spawnattr_init(posix_spawnattr_t *attr) { + *attr = (posix_spawnattr_t){}; + return 0; +} + +int posix_spawnattr_destroy(posix_spawnattr_t *) { + return 0; +} + +int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags) { + const unsigned all_flags = + POSIX_SPAWN_RESETIDS | + POSIX_SPAWN_SETPGROUP | + POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETSIGMASK | + POSIX_SPAWN_SETSCHEDPARAM | + POSIX_SPAWN_SETSCHEDULER | + POSIX_SPAWN_USEVFORK | + POSIX_SPAWN_SETSID; + if(flags & ~all_flags) + return EINVAL; + attr->__flags = flags; + return 0; +} + +int posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict attr, + const sigset_t *__restrict sigdefault) { + attr->__def = *sigdefault; + return 0; +} + +int posix_spawnattr_setschedparam(posix_spawnattr_t *__restrict, + const struct sched_param *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int posix_spawnattr_setschedpolicy(posix_spawnattr_t *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int posix_spawnattr_setsigmask(posix_spawnattr_t *__restrict attr, + const sigset_t *__restrict sigmask) { + attr->__mask = *sigmask; + return 0; +} + +int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup) { + attr->__pgrp = pgroup; + return 0; +} + +int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions) { + file_actions->__actions = nullptr; + return 0; +} + +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions) { + struct fdop *op = (struct fdop *)file_actions->__actions, *next; + while(op) { + next = op->next; + free(op); + op = next; + } + return 0; +} + +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, + int fildes, int newfildes) { + struct fdop *op = (struct fdop *)malloc(sizeof *op); + if(!op) + return ENOMEM; + op->cmd = FDOP_DUP2; + op->srcfd = fildes; + op->fd = newfildes; + if((op->next = (struct fdop *)file_actions->__actions)) + op->next->prev = op; + op->prev = nullptr; + file_actions->__actions = op; + return 0; +} + +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, + int fildes) { + struct fdop *op = (struct fdop *)malloc(sizeof *op); + if(!op) + return ENOMEM; + op->cmd = FDOP_CLOSE; + op->fd = fildes; + if((op->next = (struct fdop *)file_actions->__actions)) + op->next->prev = op; + op->prev = nullptr; + file_actions->__actions = op; + return 0; +} + +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *__restrict file_actions, + int fildes, const char *__restrict path, int oflag, mode_t mode) { + struct fdop *op = (struct fdop *)malloc(sizeof *op + strlen(path) + 1); + if(!op) + return ENOMEM; + op->cmd = FDOP_OPEN; + op->fd = fildes; + op->oflag = oflag; + op->mode = mode; + strcpy(op->path, path); + if((op->next = (struct fdop *)file_actions->__actions)) + op->next->prev = op; + op->prev = nullptr; + file_actions->__actions = op; + return 0; +} + +int posix_spawnp(pid_t *__restrict pid, const char *__restrict file, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *__restrict attrp, + char *const argv[], char *const envp[]) { + posix_spawnattr_t spawnp_attr = {}; + if(attrp) + spawnp_attr = *attrp; + spawnp_attr.__fn = (void *)execvpe; + return posix_spawn(pid, file, file_actions, &spawnp_attr, argv, envp); +} + diff --git a/user/include/mlibc/options/posix/generic/strings.cpp b/user/include/mlibc/options/posix/generic/strings.cpp new file mode 100644 index 0000000..1afce3f --- /dev/null +++ b/user/include/mlibc/options/posix/generic/strings.cpp @@ -0,0 +1,113 @@ + +#include +#include + +#include +#include +#include + +char *index (const char *s, int c) { + return strchr(s, c); +} + +char *rindex(const char *s, int c) { + return strrchr(s, c); +} + +namespace { + + template + int ffs_generic(T i) { + //Non-portably assume a byte has 8 bits; fine in all plausible cases. + for(size_t b = 0; b < sizeof(T) * 8;) + if(i & (static_cast(0x1) << b++)) + return b; + + return 0; + } + +} // namespace + +// On RISC-V, __builtin_ffs just calls into ffs, so we can't use it here. +#if defined(__has_builtin) && !defined(__riscv) +# if __has_builtin(__builtin_ffs) +# define __mlibc_ffs __builtin_ffs +# endif +# if __has_builtin(__builtin_ffsl) +# define __mlibc_ffsl __builtin_ffsl +# endif +# if __has_builtin(__builtin_ffsll) +# define __mlibc_ffsll __builtin_ffsll +# endif +#endif + +int ffs(int i) { +#ifdef __mlibc_ffs + return __mlibc_ffs(i); +#else + return ffs_generic(i); +#endif +} + +/* + Both ffsl() and ffsll() are glibc extensions + defined in string.h. They are however implemented + here because of similarity in logic and + shared code. +*/ + +int ffsl(long i) { +#ifdef __mlibc_ffsl + return __mlibc_ffsl(i); +#else + return ffs_generic(i); +#endif +} + +int ffsll(long long i) { +#ifdef __mlibc_ffsll + return __mlibc_ffsll(i); +#else + return ffs_generic(i); +#endif +} + +int strcasecmp(const char *a, const char *b) { + size_t i = 0; + while(true) { + unsigned char a_byte = tolower(a[i]); + unsigned char b_byte = tolower(b[i]); + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + i++; + } +} + +int strncasecmp(const char *a, const char *b, size_t size) { + return mlibc::strncasecmp(a, b, size); +} + +// Marked as obsolete in posix 2008 but used by at least tracker +int bcmp(const void *s1, const void *s2, size_t n) { + return memcmp(s1, s2, n); +} + +void bcopy(const void *s1, void *s2, size_t n) { + memmove(s2, s1, n); +} + +void bzero(void *s, size_t n) { + memset(s, 0, n); +} + +void explicit_bzero(void *s, size_t len) { + memset (s, 0, len); + // Compiler barrier to prevent optimizing away the memset + asm volatile ("" ::: "memory"); +} + diff --git a/user/include/mlibc/options/posix/generic/sys-file.cpp b/user/include/mlibc/options/posix/generic/sys-file.cpp new file mode 100644 index 0000000..8e9e0a0 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-file.cpp @@ -0,0 +1,18 @@ + +#include +#include +#include + +#include + +int flock(int fd, int opt) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_flock, -1); + if(int e = mlibc::sys_flock(fd, opt); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("flock")]] int flock64(int fd, int opt); + diff --git a/user/include/mlibc/options/posix/generic/sys-ipc.cpp b/user/include/mlibc/options/posix/generic/sys-ipc.cpp new file mode 100644 index 0000000..b9e0d3d --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-ipc.cpp @@ -0,0 +1,8 @@ +#include + +#include + +key_t ftok(const char *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/sys-mman.cpp b/user/include/mlibc/options/posix/generic/sys-mman.cpp new file mode 100644 index 0000000..a4ce387 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-mman.cpp @@ -0,0 +1,181 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +int mprotect(void *pointer, size_t size, int prot) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_vm_protect, -1); + if(int e = mlibc::sys_vm_protect(pointer, size, prot); e) { + errno = e; + return -1; + } + return 0; +} + +int mlock(const void *addr, size_t len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mlock, -1); + if(int e = mlibc::sys_mlock(addr, len); e) { + errno = e; + return -1; + } + return 0; +} + +int mlockall(int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mlockall, -1); + if(int e = mlibc::sys_mlockall(flags); e) { + errno = e; + return -1; + } + return 0; +} + +int munlock(const void *addr, size_t len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlock, -1); + if(int e = mlibc::sys_munlock(addr, len); e) { + errno = e; + return -1; + } + return 0; +} + +int munlockall(void) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlockall, -1); + if(int e = mlibc::sys_munlockall(); e) { + errno = e; + return -1; + } + return 0; +} + + +int posix_madvise(void *addr, size_t length, int advice) { + if(!mlibc::sys_posix_madvise) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + return mlibc::sys_posix_madvise(addr, length, advice); +} + +int msync(void *addr, size_t length, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msync, -1); + if(int e = mlibc::sys_msync(addr, length, flags); e) { + errno = e; + return -1; + } + return 0; +} + +void *mmap(void *hint, size_t size, int prot, int flags, int fd, off_t offset) { + void *window; + if(int e = mlibc::sys_vm_map(hint, size, prot, flags, fd, offset, &window); e) { + errno = e; + return (void *)-1; + } + return window; +} + +[[gnu::alias("mmap")]] void *mmap64(void *hint, size_t size, int prot, int flags, int fd, off64_t offset); + +int munmap(void *pointer, size_t size) { + if(int e = mlibc::sys_vm_unmap(pointer, size); e) { + errno = e; + return -1; + } + return 0; +} + +// The implementation of shm_open and shm_unlink is taken from musl. +namespace { + char *shm_mapname(const char *name, char *buf) { + char *p; + while(*name == '/') + name++; + if(*(p = strchrnul(name, '/')) || p == name || + (p - name <= 2 && name[0] == '.' && p[-1] == '.')) { + errno = EINVAL; + return nullptr; + } + if(p - name > NAME_MAX) { + errno = ENAMETOOLONG; + return nullptr; + } + memcpy(buf, "/dev/shm/", 9); + memcpy(buf + 9, name, p - name + 1); + return buf; + } +} // namespace + +int shm_open(const char *name, int flags, mode_t mode) { + int cs; + char buf[NAME_MAX + 10]; + if(!(name = shm_mapname(name, buf))) + return -1; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + int fd = open(name, flags | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK, mode); + pthread_setcancelstate(cs, nullptr); + return fd; +} + +int shm_unlink(const char *name) { + char buf[NAME_MAX + 10]; + if(!(name = shm_mapname(name, buf))) + return -1; + return unlink(name); +} + +#if __MLIBC_LINUX_OPTION +void *mremap(void *pointer, size_t size, size_t new_size, int flags, ...) { + __ensure(flags == MREMAP_MAYMOVE); + + void *window; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_vm_remap, (void *)-1); + if(int e = mlibc::sys_vm_remap(pointer, size, new_size, &window); e) { + errno = e; + return (void *)-1; + } + return window; +} + +int remap_file_pages(void *, size_t, int, size_t, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int memfd_create(const char *name, unsigned int flags) { + int ret = -1; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_memfd_create, -1); + if(int e = mlibc::sys_memfd_create(name, flags, &ret)) { + errno = e; + return -1; + } + + return ret; +} + +int madvise(void *addr, size_t length, int advice) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_madvise, -1); + if(int e = mlibc::sys_madvise(addr, length, advice)) { + errno = e; + return -1; + } + + return 0; +} + +int mincore(void *addr, size_t length, unsigned char *vec) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlockall, -1); + if(int e = mlibc::sys_mincore(addr, length, vec); e) { + errno = e; + return -1; + } + return 0; +} +#endif /* __MLIBC_LINUX_OPTION */ diff --git a/user/include/mlibc/options/posix/generic/sys-msg.cpp b/user/include/mlibc/options/posix/generic/sys-msg.cpp new file mode 100644 index 0000000..95f067e --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-msg.cpp @@ -0,0 +1,23 @@ + +#include +#include + +int msgget(key_t, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int msgctl(int, int, struct msqid_ds *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t msgrcv(int, void *, size_t, long, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int msgsnd(int, const void *, size_t, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/sys-resource.cpp b/user/include/mlibc/options/posix/generic/sys-resource.cpp new file mode 100644 index 0000000..a87f284 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-resource.cpp @@ -0,0 +1,61 @@ + +#include +#include + +#include +#include +#include + +int getpriority(int which, id_t who) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getpriority, -1); + int value = 0; + if(int e = mlibc::sys_getpriority(which, who, &value); e) { + errno = e; + } + return value; +} + +int setpriority(int which, id_t who, int prio) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setpriority, -1); + if(int e = mlibc::sys_setpriority(which, who, prio); e) { + errno = e; + return -1; + } + return 0; +} + +int getrusage(int scope, struct rusage *usage) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getrusage, -1); + if(int e = mlibc::sys_getrusage(scope, usage); e) { + errno = e; + return -1; + } + return 0; +} + +int getrlimit(int resource, struct rlimit *limit) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getrlimit, -1); + if(int e = mlibc::sys_getrlimit(resource, limit); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("getrlimit")]] int getrlimit64(int resource, struct rlimit *limit); + +int setrlimit(int resource, const struct rlimit *limit) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setrlimit, -1); + if(int e = mlibc::sys_setrlimit(resource, limit); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("setrlimit")]] int setrlimit64(int resource, const struct rlimit *limit); + +int prlimit(pid_t, int, const struct rlimit *, struct rlimit *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/sys-select.cpp b/user/include/mlibc/options/posix/generic/sys-select.cpp new file mode 100644 index 0000000..f0c3fb1 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-select.cpp @@ -0,0 +1,58 @@ + +#include +#include +#include +#include + +#include +#include + +#include + +void __FD_CLR(int fd, fd_set *set) { + __ensure(fd < FD_SETSIZE); + set->fds_bits[fd / 8] &= ~(1 << (fd % 8)); +} +int __FD_ISSET(int fd, fd_set *set) { + __ensure(fd < FD_SETSIZE); + return set->fds_bits[fd / 8] & (1 << (fd % 8)); +} +void __FD_SET(int fd, fd_set *set) { + __ensure(fd < FD_SETSIZE); + set->fds_bits[fd / 8] |= 1 << (fd % 8); +} +void __FD_ZERO(fd_set *set) { + memset(set->fds_bits, 0, sizeof(fd_set)); +} + +int select(int num_fds, fd_set *__restrict read_set, fd_set *__restrict write_set, + fd_set *__restrict except_set, struct timeval *__restrict timeout) { + int num_events = 0; + struct timespec timeouts = {}; + struct timespec *timeout_ptr = nullptr; + if (timeout) { + timeouts.tv_sec = timeout->tv_sec; + timeouts.tv_nsec = timeout->tv_usec * 1000; + timeout_ptr = &timeouts; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pselect, -1); + if(int e = mlibc::sys_pselect(num_fds, read_set, write_set, except_set, + timeout_ptr, nullptr, &num_events); e) { + errno = e; + return -1; + } + return num_events; +} + +int pselect(int num_fds, fd_set *__restrict read_set, fd_set *__restrict write_set, + fd_set *__restrict except_set, const struct timespec *timeout, const sigset_t *sigmask) { + int num_events = 0; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pselect, -1); + if(int e = mlibc::sys_pselect(num_fds, read_set, write_set, except_set, + timeout, sigmask, &num_events); e) { + errno = e; + return -1; + } + return num_events; +} diff --git a/user/include/mlibc/options/posix/generic/sys-sem.cpp b/user/include/mlibc/options/posix/generic/sys-sem.cpp new file mode 100644 index 0000000..ac3df69 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-sem.cpp @@ -0,0 +1,51 @@ + +#include +#include +#include +#include + +#include + +int semget(key_t key, int n, int fl) { + if(n > USHRT_MAX) { + errno = EINVAL; + return -1; + } + + int id = 0; + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_semget, -1); + if(int e = sysdep(key, n, fl, &id); e) { + errno = e; + return -1; + } + return id; +} + +int semop(int, struct sembuf *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +union semun { + int val; + struct semid_ds *buf; + unsigned short *array; +}; + +int semctl(int id, int num, int cmd, ...) { + union semun semun; + int ret = 0; + + va_list ap; + va_start(ap, cmd); + semun = va_arg(ap, union semun); + va_end(ap); + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_semctl, -1); + if(int e = sysdep(id, num, cmd, semun.buf, &ret); e) { + errno = e; + return -1; + } + + return ret; +} diff --git a/user/include/mlibc/options/posix/generic/sys-shm.cpp b/user/include/mlibc/options/posix/generic/sys-shm.cpp new file mode 100644 index 0000000..8782ae6 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-shm.cpp @@ -0,0 +1,45 @@ +#include +#include + +#include +#include +#include + +void *shmat(int shmid, const void *shmaddr, int shmflg) { + void *ret; + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shmat, ((void *)-1)); + if(int e = sysdep(&ret, shmid, shmaddr, shmflg); e) { + errno = e; + return ((void *)-1); + } + return ret; +} + +int shmctl(int shmid, int cmd, struct shmid_ds *buf) { + int ret; + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shmctl, -1); + if(int e = sysdep(&ret, shmid, cmd, buf); e) { + errno = e; + return -1; + } + return ret; +} + +int shmdt(const void *shmaddr) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shmdt, -1); + if(int e = sysdep(shmaddr); e) { + errno = e; + return -1; + } + return 0; +} + +int shmget(key_t key, size_t size, int shmflg) { + int ret; + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shmget, -1); + if(int e = sysdep(&ret, key, size, shmflg); e) { + errno = e; + return -1; + } + return ret; +} diff --git a/user/include/mlibc/options/posix/generic/sys-socket.cpp b/user/include/mlibc/options/posix/generic/sys-socket.cpp new file mode 100644 index 0000000..e5d7236 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-socket.cpp @@ -0,0 +1,225 @@ + +#include +#include +#include +#include + +#include +#include +#include + +int accept(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length) { + int newfd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_accept, -1); + if(int e = mlibc::sys_accept(fd, &newfd, addr_ptr, addr_length, 0); e) { + errno = e; + return -1; + } + return newfd; +} + +int accept4(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length, int flags) { + int newfd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_accept, -1); + if(int e = mlibc::sys_accept(fd, &newfd, addr_ptr, addr_length, flags); e) { + errno = e; + return -1; + } + + return newfd; +} + +int bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_bind, -1); + if(int e = mlibc::sys_bind(fd, addr_ptr, addr_len); e) { + errno = e; + return -1; + } + return 0; +} + +int connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_connect, -1); + if(int e = mlibc::sys_connect(fd, addr_ptr, addr_len); e) { + errno = e; + return -1; + } + return 0; +} + +int getpeername(int fd, struct sockaddr *addr_ptr, socklen_t *__restrict addr_length) { + socklen_t actual_length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_peername, -1); + if(int e = mlibc::sys_peername(fd, addr_ptr, *addr_length, &actual_length); e) { + errno = e; + return -1; + } + *addr_length = actual_length; + return 0; +} + +int getsockname(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length) { + socklen_t actual_length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sockname, -1); + if(int e = mlibc::sys_sockname(fd, addr_ptr, *addr_length, &actual_length); e) { + errno = e; + return -1; + } + *addr_length = actual_length; + return 0; +} + +int getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getsockopt, -1); + return mlibc::sys_getsockopt(fd, layer, number, buffer, size); +} + +int listen(int fd, int backlog) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_listen, -1); + if(int e = mlibc::sys_listen(fd, backlog); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t recv(int sockfd, void *__restrict buf, size_t len, int flags) { + return recvfrom(sockfd, buf, len, flags, nullptr, nullptr); +} + +ssize_t recvfrom(int sockfd, void *__restrict buf, size_t len, int flags, + struct sockaddr *__restrict src_addr, socklen_t *__restrict addrlen) { + if(mlibc::sys_recvfrom) { + ssize_t length; + if(int e = mlibc::sys_recvfrom(sockfd, buf, len, flags, src_addr, addrlen, &length); e) { + errno = e; + return -1; + } + return length; + } + + struct iovec iov = {}; + iov.iov_base = buf; + iov.iov_len = len; + + struct msghdr hdr = {}; + hdr.msg_name = src_addr; + if (addrlen) { + hdr.msg_namelen = *addrlen; + } + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + + int ret = recvmsg(sockfd, &hdr, flags); + if (ret < 0) + return ret; + + if(addrlen) + *addrlen = hdr.msg_namelen; + return ret; +} + +ssize_t recvmsg(int fd, struct msghdr *hdr, int flags) { + ssize_t length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msg_recv, -1); + if(int e = mlibc::sys_msg_recv(fd, hdr, flags, &length); e) { + errno = e; + return -1; + } + return length; +} + +int recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t send(int fd, const void *buffer, size_t size, int flags) { + return sendto(fd, buffer, size, flags, nullptr, 0); +} + +ssize_t sendto(int fd, const void *buffer, size_t size, int flags, + const struct sockaddr *sock_addr, socklen_t addr_length) { + if(mlibc::sys_sendto) { + ssize_t length; + if(int e = mlibc::sys_sendto(fd, buffer, size, flags, sock_addr, addr_length, &length); e) { + errno = e; + return -1; + } + return length; + } + + struct iovec iov = {}; + iov.iov_base = const_cast(buffer); + iov.iov_len = size; + + struct msghdr hdr = {}; + hdr.msg_name = const_cast(sock_addr); + hdr.msg_namelen = addr_length; + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + + return sendmsg(fd, &hdr, flags); +} + +ssize_t sendmsg(int fd, const struct msghdr *hdr, int flags) { + if(hdr->msg_iovlen > IOV_MAX) + return EMSGSIZE; + + ssize_t length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msg_send, -1); + if(int e = mlibc::sys_msg_send(fd, hdr, flags, &length); e) { + errno = e; + return -1; + } + return length; +} + +int sendmmsg(int, struct mmsghdr *, unsigned int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int setsockopt(int fd, int layer, int number, + const void *buffer, socklen_t size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setsockopt, -1); + return mlibc::sys_setsockopt(fd, layer, number, buffer, size); +} + +int shutdown(int sockfd, int how) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shutdown, -1); + if(int e = sysdep(sockfd, how); e) { + errno = e; + return -1; + } + + return 0; +} + +int sockatmark(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int socket(int family, int type, int protocol) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_socket, -1); + if(int e = mlibc::sys_socket(family, type, protocol, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int socketpair(int domain, int type, int protocol, int sv[2]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_socketpair, -1); + if(int e = mlibc::sys_socketpair(domain, type, protocol, sv); e) { + errno = e; + return -1; + } + return 0; +} + +// connectpair() is provided by the platform + diff --git a/user/include/mlibc/options/posix/generic/sys-stat.cpp b/user/include/mlibc/options/posix/generic/sys-stat.cpp new file mode 100644 index 0000000..bdbcef5 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-stat.cpp @@ -0,0 +1,157 @@ + +#include +#include +#include + +#include +#include + +int chmod(const char *pathname, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_chmod, -1); + if(int e = mlibc::sys_chmod(pathname, mode); e) { + errno = e; + return -1; + } + return 0; +} + +int fchmod(int fd, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchmod, -1); + if(int e = mlibc::sys_fchmod(fd, mode); e) { + errno = e; + return -1; + } + return 0; +} + +int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchmodat, -1); + if(int e = mlibc::sys_fchmodat(dirfd, pathname, mode, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int fstatat(int dirfd, const char *path, struct stat *result, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + if(int e = mlibc::sys_stat(mlibc::fsfd_target::fd_path, dirfd, path, flags, result); e) { + errno = e; + return -1; + } + return 0; +} + +int futimens(int fd, const struct timespec times[2]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + + if (int e = mlibc::sys_utimensat(fd, nullptr, times, 0); e) { + errno = e; + return -1; + } + + return 0; +} + +int mkdir(const char *path, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkdir, -1); + if(int e = mlibc::sys_mkdir(path, mode); e) { + errno = e; + return -1; + } + return 0; +} + +int mkdirat(int dirfd, const char *path, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkdirat, -1); + if(int e = mlibc::sys_mkdirat(dirfd, path, mode); e) { + errno = e; + return -1; + } + return 0; +} + +int mkfifo(const char *path, mode_t mode) { + return mkfifoat(AT_FDCWD, path, mode); +} + +int mkfifoat(int dirfd, const char *path, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkfifoat, -1); + if (int e = mlibc::sys_mkfifoat(dirfd, path, mode); e) { + errno = e; + return -1; + } + + return 0; +} + +int mknod(const char *path, mode_t mode, dev_t dev) { + return mknodat(AT_FDCWD, path, mode, dev); +} + +int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mknodat, -1); + if (int e = mlibc::sys_mknodat(dirfd, path, mode, dev); e) { + errno = e; + return -1; + } + + return 0; +} + +mode_t umask(mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_umask, -1); + mode_t old; + if (int e = mlibc::sys_umask(mode, &old); e) { + errno = e; + return -1; + } + return old; +} + +int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + if(pathname == nullptr) { + errno = EINVAL; + return -1; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + if (int e = mlibc::sys_utimensat(dirfd, pathname, times, flags); e) { + errno = e; + return -1; + } + + return 0; +} + +int stat(const char *path, struct stat *result) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + if(int e = mlibc::sys_stat(mlibc::fsfd_target::path, -1, path, 0, result); e) { + errno = e; + return -1; + } + return 0; +} + +int lstat(const char *path, struct stat *result) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + if(int e = mlibc::sys_stat(mlibc::fsfd_target::path, + -1, path, AT_SYMLINK_NOFOLLOW, result); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("lstat")]] int lstat64(const char *path, struct stat64 *result); + +int fstat(int fd, struct stat *result) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + if(int e = mlibc::sys_stat(mlibc::fsfd_target::fd, fd, "", 0, result); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("fstat")]] int fstat64(int fd, struct stat64 *result); diff --git a/user/include/mlibc/options/posix/generic/sys-statvfs.cpp b/user/include/mlibc/options/posix/generic/sys-statvfs.cpp new file mode 100644 index 0000000..dc7e215 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-statvfs.cpp @@ -0,0 +1,28 @@ +#include +#include + +#include +#include + +int statvfs(const char *path, struct statvfs *out) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_statvfs, -1); + if(int e = mlibc::sys_statvfs(path, out); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("statvfs")]] int statvfs64(const char *path, struct statvfs64 *out); + +int fstatvfs(int fd, struct statvfs *out) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fstatvfs, -1); + if(int e = mlibc::sys_fstatvfs(fd, out); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("fstatvfs")]] int fstatvfs64(int, struct statvfs64 *); + diff --git a/user/include/mlibc/options/posix/generic/sys-time.cpp b/user/include/mlibc/options/posix/generic/sys-time.cpp new file mode 100644 index 0000000..2095735 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-time.cpp @@ -0,0 +1,121 @@ + +#include +#include +#include + +#include +#include +#include + +int gettimeofday(struct timeval *__restrict result, void *__restrict unused) { + (void)unused; // Linux just ignores gettimeofday(). + + if(result) { + long nanos; + if(int e = mlibc::sys_clock_get(CLOCK_REALTIME, &result->tv_sec, &nanos); e) { + errno = e; + return -1; + } + result->tv_usec = nanos / 1000; + } + return 0; +} + +int settimeofday(const struct timeval *tv, const struct timezone *) { + if(!tv) + return 0; + // tv_usec must be in the range 0, 999999 + if(tv->tv_usec >= 1000000) { + errno = EINVAL; + return -1; + } + if(int e = mlibc::sys_clock_set(CLOCK_REALTIME, tv->tv_sec, tv->tv_usec * 1000); e) { + errno = e; + return -1; + } + return 0; +} + +void timeradd(const struct timeval *a, const struct timeval *b, struct timeval *res) { + res->tv_sec = a->tv_sec + b->tv_sec; + res->tv_usec = a->tv_usec + b->tv_usec; + while(res->tv_usec > 999999) { + res->tv_usec -= 1000000; + res->tv_sec += 1; + } +} + +void timersub(const struct timeval *a, const struct timeval *b, struct timeval *res) { + res->tv_sec = a->tv_sec - b->tv_sec; + res->tv_usec = a->tv_usec - b->tv_usec; + while(res->tv_usec < 0) { + res->tv_usec += 1000000; + res->tv_sec -= 1; + } +} + +void timerclear(struct timeval *tvp) { + tvp->tv_sec = 0; + tvp->tv_usec = 0; +} + +int timerisset(struct timeval *tvp) { + if(tvp->tv_sec != 0 || tvp->tv_usec != 0) { + return 1; + } + return 0; +} + +int getitimer(int which, struct itimerval *curr_value) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getitimer, -1); + if(int e = mlibc::sys_getitimer(which, curr_value); e) { + errno = e; + return -1; + } + return 0; +} + +int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setitimer, -1); + if(int e = mlibc::sys_setitimer(which, new_value, old_value); e) { + errno = e; + return -1; + } + return 0; +} + +int timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_create, -1); + if(int e = mlibc::sys_timer_create(clk, evp, res); e) { + errno = e; + return -1; + } + return 0; +} + +int timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_settime, -1); + if(int e = mlibc::sys_timer_settime(t, flags, val, old); e) { + errno = e; + return -1; + } + return 0; +} + +int timer_gettime(timer_t t, struct itimerspec *val) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_gettime, -1); + if(int e = mlibc::sys_timer_gettime(t, val); e) { + errno = e; + return -1; + } + return 0; +} + +int timer_delete(timer_t t) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_delete, -1); + if(int e = mlibc::sys_timer_delete(t); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/user/include/mlibc/options/posix/generic/sys-times.cpp b/user/include/mlibc/options/posix/generic/sys-times.cpp new file mode 100644 index 0000000..61b6e25 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-times.cpp @@ -0,0 +1,19 @@ + +#include +#include + +#include +#include +#include +#include + +clock_t times(struct tms *tms) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_times, -1); + clock_t ret; + if(int e = mlibc::sys_times(tms, &ret); e) { + errno = e; + return -1; + } + return ret; +} + diff --git a/user/include/mlibc/options/posix/generic/sys-uio.cpp b/user/include/mlibc/options/posix/generic/sys-uio.cpp new file mode 100644 index 0000000..0dff9d4 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-uio.cpp @@ -0,0 +1,80 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +ssize_t readv(int fd, const struct iovec *iovs, int iovc) { + ssize_t read_bytes = 0; + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_readv, -1); + + if (int e = sysdep(fd, iovs, iovc, &read_bytes); e) { + errno = e; + return -1; + } + + return read_bytes; +} + +ssize_t writev(int fd, const struct iovec *iovs, int iovc) { + __ensure(iovc); + + ssize_t written = 0; + + auto sysdep = mlibc::sys_writev; + if(sysdep) { + int e = sysdep(fd, iovs, iovc, &written); + if(e) { + errno = e; + return -1; + } + return written; + } + + // TODO: this implementation is not safe to use in signal contexts + mlibc::infoLogger() << "mlibc: falling back to signal-unsafe writev implementation!" << frg::endlog; + size_t bytes = 0; + for(int i = 0; i < iovc; i++) { + if(SSIZE_MAX - bytes < iovs[i].iov_len) { + errno = EINVAL; + return -1; + } + bytes += iovs[i].iov_len; + } + frg::vector buffer{getAllocator()}; + buffer.resize(bytes); + + size_t to_copy = bytes; + char *bp = buffer.data(); + for(int i = 0; i < iovc; i++) { + size_t copy = frg::min(iovs[i].iov_len, to_copy); + + bp = (char *)mempcpy((void *)bp, (void *)iovs[i].iov_base, copy); + + to_copy -= copy; + if(to_copy == 0) + break; + } + + written = write(fd, buffer.data(), bytes); + return written; +} + +ssize_t preadv(int, const struct iovec *, int, off_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t pwritev(int, const struct iovec *, int, off_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/sys-utsname.cpp b/user/include/mlibc/options/posix/generic/sys-utsname.cpp new file mode 100644 index 0000000..863ba52 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-utsname.cpp @@ -0,0 +1,24 @@ + +#include +#include +#include + +#include +#include +#include +#include + +int uname(struct utsname *p) { + if (p == nullptr) { + errno = EFAULT; + return -1; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_uname, -1); + if(int e = mlibc::sys_uname(p); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/user/include/mlibc/options/posix/generic/sys-wait.cpp b/user/include/mlibc/options/posix/generic/sys-wait.cpp new file mode 100644 index 0000000..207f639 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/sys-wait.cpp @@ -0,0 +1,52 @@ + +#include +#include +#include + +#include +#include +#include + +int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitid, -1); + if(int e = sysdep(idtype, id, info, options); e) { + errno = e; + return -1; + } + return 0; +} + +pid_t waitpid(pid_t pid, int *status, int flags) { + pid_t ret; + int tmp_status = 0; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1); + if(int e = mlibc::sys_waitpid(pid, &tmp_status, flags, nullptr, &ret); e) { + errno = e; + return -1; + } + if(status) { + *status = tmp_status; + } + return ret; +} + +pid_t wait(int *status) { + return waitpid(-1, status, 0); +} + +pid_t wait3(int *status, int options, struct rusage *rusage) { + (void) rusage; + mlibc::infoLogger() << "\e[31mmlibc: wait3() is not implemented correctly\e[39m" + << frg::endlog; + return waitpid(-1, status, options); +} + +pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru) { + pid_t ret; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1); + if(int e = mlibc::sys_waitpid(pid, status, options, ru, &ret); e) { + errno = e; + return -1; + } + return ret; +} diff --git a/user/include/mlibc/options/posix/generic/syslog.cpp b/user/include/mlibc/options/posix/generic/syslog.cpp new file mode 100644 index 0000000..75071ad --- /dev/null +++ b/user/include/mlibc/options/posix/generic/syslog.cpp @@ -0,0 +1,151 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// This syslog implementation is largely taken from musl + +static char log_ident[32]; +static int log_options; +static int log_facility = LOG_USER; +static int log_fd = -1; +static int log_opt; +static int log_mask = 0xff; + +static int use_mlibc_logger = 0; +static FutexLock __syslog_lock; + +static const struct sockaddr_un log_addr {AF_UNIX, "/dev/log"}; + +void closelog(void) { + frg::unique_lock holder { __syslog_lock }; + close(log_fd); + log_fd = -1; +} + +static void __openlog() { + log_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if(log_fd >= 0) { + int ret = connect(log_fd, (const sockaddr *)&log_addr, sizeof log_addr); + if(ret) { + mlibc::infoLogger() << "\e[31mmlibc: syslog: connect returned an error, falling back to infoLogger\e[39m" << frg::endlog; + use_mlibc_logger = 1; + } + } +} + +void openlog(const char *ident, int options, int facility) { + frg::unique_lock holder { __syslog_lock }; + if(ident) { + size_t n = strnlen(ident, sizeof log_ident - 1); + memcpy(log_ident, ident, n); + log_ident[n] = 0; + } else { + log_ident[0] = 0; + } + log_options = options; + log_facility = facility; + + if((options & LOG_NDELAY) && log_fd < 0) + __openlog(); +} + +int setlogmask(int mask) { + int old_mask = log_mask; + + log_mask = mask; + + return old_mask; +} + +static void _vsyslog(int priority, const char *message, va_list ap) { + auto is_lost_conn = [] (int e) { + return e == ECONNREFUSED || e == ECONNRESET || e == ENOTCONN || e == EPIPE; + }; + + if(!(priority & log_mask)) { + return; + } + + char timebuf[16]; + time_t now; + struct tm tm; + char buf[1024]; + int errno_save = errno; + int pid; + int l, l2; + int hlen; + int fd; + + if(log_fd < 0) + __openlog(); + + if(use_mlibc_logger) { + vsnprintf(buf, sizeof buf, message, ap); + mlibc::infoLogger() << "mlibc: syslog: " << buf << frg::endlog; + return; + } + + if(!(priority & LOG_FACMASK)) + priority |= log_facility; + + now = time(nullptr); + gmtime_r(&now, &tm); + strftime(timebuf, sizeof timebuf, "%b %e %T", &tm); + + pid = (log_opt & LOG_PID) ? getpid() : 0; + l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ", + priority, timebuf, &hlen, log_ident, (pid ? "[" : ""), pid, (pid ? "]" : "")); + errno = errno_save; + l2 = vsnprintf(buf + l, sizeof buf - l, message, ap); + if(l2 >= 0) { + if(l2 >= (long int)(sizeof buf - l)) + l = sizeof buf - 1; + else + l += l2; + if(buf[l - 1] != '\n') + buf[l++] = '\n'; + if(send(log_fd, buf, l, 0) < 0 && (!is_lost_conn(errno) + || connect(log_fd, (const sockaddr *)&log_addr, sizeof log_addr) < 0 + || send(log_fd, buf, l, 0) < 0) + && (log_opt & LOG_CONS)) { + fd = open("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if(fd >= 0) { + dprintf(fd, "%.*s", l - hlen, buf + hlen); + close(fd); + } + } + if(log_opt & LOG_PERROR) + dprintf(STDERR_FILENO, "%.*s", l - hlen, buf + hlen); + } +} + +void syslog(int priority, const char *format, ...) { + va_list ap; + va_start(ap, format); + vsyslog(priority, format, ap); + va_end(ap); +} + +void vsyslog(int priority, const char *message, va_list ap) { + if (!(log_mask & LOG_MASK(priority & 7)) || (priority & ~0x3ff)) + return; + + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + frg::unique_lock lock(__syslog_lock); + _vsyslog(priority, message, ap); + pthread_setcancelstate(cs, nullptr); +} diff --git a/user/include/mlibc/options/posix/generic/termios.cpp b/user/include/mlibc/options/posix/generic/termios.cpp new file mode 100644 index 0000000..631456a --- /dev/null +++ b/user/include/mlibc/options/posix/generic/termios.cpp @@ -0,0 +1,103 @@ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include + +#include +#include + +speed_t cfgetispeed(const struct termios *tios) { + return tios->c_cflag & CBAUD; +} + +speed_t cfgetospeed(const struct termios *tios) { + return tios->c_cflag & CBAUD; +} + +int cfsetispeed(struct termios *termios, speed_t speed) { + return speed ? cfsetospeed(termios, speed) : 0; +} + +int cfsetospeed(struct termios *termios, speed_t speed) { + if(speed & ~CBAUD) { + errno = EINVAL; + return -1; + } + + termios->c_cflag &= ~CBAUD; + termios->c_cflag |= speed; + + return 0; +} + +void cfmakeraw(struct termios *t) { + t->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + t->c_oflag &= ~OPOST; + t->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + t->c_cflag &= ~(CSIZE | PARENB); + t->c_cflag |= CS8; + t->c_cc[VMIN] = 1; + t->c_cc[VTIME] = 0; +} + +int tcdrain(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcdrain, -1); + if(int e = mlibc::sys_tcdrain(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int tcflow(int fd, int action) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcflow, -1); + if(int e = mlibc::sys_tcflow(fd, action); e) { + errno = e; + return -1; + } + return 0; +} + +int tcflush(int fd, int queue_selector) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcflush, -1); + if(int e = mlibc::sys_tcflush(fd, queue_selector); e) { + errno = e; + return -1; + } + return 0; +} + +int tcgetattr(int fd, struct termios *attr) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcgetattr, -1); + if(int e = mlibc::sys_tcgetattr(fd, attr); e) { + errno = e; + return -1; + } + return 0; +} + +pid_t tcgetsid(int fd) { + int sid; + if(ioctl(fd, TIOCGSID, &sid) < 0) { + return -1; + } + return sid; +} + +int tcsendbreak(int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int tcsetattr(int fd, int opts, const struct termios *attr) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcsetattr, -1); + if(int e = mlibc::sys_tcsetattr(fd, opts, attr); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/user/include/mlibc/options/posix/generic/time.cpp b/user/include/mlibc/options/posix/generic/time.cpp new file mode 100644 index 0000000..494de13 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/time.cpp @@ -0,0 +1,510 @@ +#include +#include +#include +#include +#include + +#include +#include + +namespace { + +int month_to_day(int month) { + switch(month){ + case 0: return 0; + case 1: return 31; + case 2: return 59; + case 3: return 90; + case 4: return 120; + case 5: return 151; + case 6: return 181; + case 7: return 212; + case 8: return 243; + case 9: return 273; + case 10: return 304; + case 11: return 334; + } + return -1; +} + +int is_leapyear(int year) { + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); +} + +int month_and_year_to_day_in_year(int month, int year){ + int day = month_to_day(month); + if(is_leapyear(year) && month < 2) + return day + 1; + + return day; +} + +int target_determination(int month) { + switch(month){ + case 0: return 3; + case 1: return 14; + case 2: return 14; + case 3: return 4; + case 4: return 9; + case 5: return 6; + case 6: return 11; + case 7: return 8; + case 8: return 5; + case 9: return 10; + case 10: return 7; + case 11: return 12; + } + + return -1; +} + +int doom_determination(int full_year) { + int century = full_year / 100; + int anchor = 2 + 5 * (century % 4) % 7; + + int year = full_year % 100; + + if(year % 2) + year += 11; + + year /= 2; + + if(year % 2) + year += 11; + + return 7 - (year % 7) + anchor; +} + +//Determine day of week through the doomsday algorithm. +int day_determination(int day, int month, int year) { + int doom = doom_determination(year); + bool leap = is_leapyear(year); + + int target = target_determination(month); + if(leap && month < 2) + target++; + + int doom_dif = (day - target) % 7; + return (doom + doom_dif) % 7; +} + +struct strptime_internal_state { + bool has_century; + bool has_year; + bool has_month; + bool has_day_of_month; + bool has_day_of_year; + bool has_day_of_week; + + bool full_year_given; + + int century; + + size_t format_index; + size_t input_index; +}; + +char *strptime_internal(const char *__restrict input, const char *__restrict format, + struct tm *__restrict tm, struct strptime_internal_state *__restrict state) { + auto matchLanginfoItem = [&] (int start, size_t num, int &dest, bool &flag) -> bool { + for(size_t i = start; i < (start + num); i++) { + const char *mon = nl_langinfo(i); + size_t len = strlen(mon); + if(mlibc::strncasecmp(&input[state->input_index], mon, len)) + continue; + state->input_index += len; + dest = i - start; + flag = true; + return true; + } + return false; + }; + + auto matchNumericRange = [&] (int start, int end, int &dest, bool *flag) -> bool { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 2 < n) + return false; + if(product < start || product > end) + return false; + state->input_index += n; + dest = product; + if(flag) *flag = true; + return true; + }; + + while(isspace(input[state->input_index])) + state->input_index++; + + if(input[state->input_index] == '\0') + return nullptr; + + while(format[state->format_index] != '\0'){ + if(format[state->format_index] != '%'){ + if(isspace(format[state->format_index])){ + while(isspace(input[state->input_index++])); + state->input_index--; + } + else { + if(format[state->format_index] != input[state->input_index++]) + return nullptr; + } + state->format_index++; + continue; + } + state->format_index++; + switch(format[state->format_index]){ + case '%': + if(input[state->input_index++] != '%') + return nullptr; + break; + case 'a': + case 'A': { + if (!matchLanginfoItem(DAY_1, 7, tm->tm_wday, state->has_day_of_week) && \ + !matchLanginfoItem(ABDAY_1, 7, tm->tm_wday, state->has_day_of_week)) + return nullptr; + break; + } + case 'b': + case 'B': + case 'h': { + if (!matchLanginfoItem(MON_1, 12, tm->tm_mon, state->has_month) && \ + !matchLanginfoItem(ABMON_1, 12, tm->tm_mon, state->has_month)) + return nullptr; + break; + } + case 'c': + __ensure(!"strptime() %c directive unimplemented."); + __builtin_unreachable(); + break; + case 'C': { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 2 < n) + return nullptr; + state->input_index += n; + state->century = product; + state->has_century = true; + break; + } + case 'd': //`%d` and `%e` are equivalent + case 'e': { + if(!matchNumericRange(1, 31, tm->tm_mday, &state->has_day_of_month)) + return nullptr; + break; + } + case 'D': { //equivalent to `%m/%d/%y` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%m/%d/%y", tm, state); + if(result == nullptr) + return nullptr; + + state->format_index = pre_fi; + break; + } + case 'H': { + if(!matchNumericRange(0, 23, tm->tm_hour, nullptr)) + return nullptr; + break; + } + case 'I': { + if(!matchNumericRange(1, 12, tm->tm_hour, nullptr)) + return nullptr; + break; + } + case 'j': { + if(!matchNumericRange(1, 366, tm->tm_yday, &state->has_day_of_year)) + return nullptr; + tm->tm_yday--; + break; + } + case 'm': { + if(!matchNumericRange(1, 12, tm->tm_mon, &state->has_month)) + return nullptr; + tm->tm_mon--; + break; + } + case 'M': { + if(!matchNumericRange(0, 59, tm->tm_min, nullptr)) + return nullptr; + break; + } + case 'n': + case 't': { + size_t n = 0; + while(isspace(input[state->input_index++])) + n++; + if(n == 0) + return nullptr; + state->input_index--; + break; + } + case 'p': { + const char *meridian_str = nl_langinfo(AM_STR); + size_t len = strlen(meridian_str); + if (!mlibc::strncasecmp(&input[state->input_index], meridian_str, len)) { + tm->tm_hour %= 12; + state->input_index += len; + break; + } + meridian_str = nl_langinfo(PM_STR); + len = strlen(meridian_str); + if (!mlibc::strncasecmp(&input[state->input_index], meridian_str, len)) { + tm->tm_hour %= 12; + tm->tm_hour += 12; + state->input_index += len; + break; + } + break; + } + case 'r': { //equivalent to `%I:%M:%S %p` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%I:%M:%S %p", tm, state); + if(result == nullptr) + return nullptr; + + state->format_index = pre_fi; + break; + } + case 'R': { //equivalent to `%H:%M` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%H:%M", tm, state); + if(result == nullptr) + return nullptr; + + state->format_index = pre_fi; + break; + } + case 'S': { + if(!matchNumericRange(0, 60, tm->tm_sec, nullptr)) + return nullptr; + break; + } + case 'T': { //equivalent to `%H:%M:%S` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%H:%M:%S", tm, state); + if(result == nullptr) + return nullptr; + + state->format_index = pre_fi; + break; + } + case 'U': + __ensure(!"strptime() %U directive unimplemented."); + __builtin_unreachable(); + break; + case 'w': { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 1 < n) + return nullptr; + state->input_index += n; + tm->tm_wday = product; + state->has_day_of_week = true; + break; + } + case 'W': + __ensure(!"strptime() %W directive unimplemented."); + __builtin_unreachable(); + break; + case 'x': + __ensure(!"strptime() %x directive unimplemented."); + __builtin_unreachable(); + break; + case 'X': + __ensure(!"strptime() %X directive unimplemented."); + __builtin_unreachable(); + break; + case 'y': { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 2 < n) + return nullptr; + if(product < 69) + product += 100; + state->input_index += n; + tm->tm_year = product; + state->has_year = true; + break; + } + case 'Y': { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 4 < n) + return nullptr; + state->input_index += n; + tm->tm_year = product - 1900; + state->has_year = true; + state->has_century = true; + state->full_year_given = true; + state->century = product / 100; + break; + } + case 'F': { //GNU extensions + //equivalent to `%Y-%m-%d` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%Y-%m-%d", tm, state); + if(result == nullptr) + return nullptr; + + state->format_index = pre_fi; + break; + } + case 'g': + __ensure(!"strptime() %g directive unimplemented."); + __builtin_unreachable(); + break; + case 'G': + __ensure(!"strptime() %G directive unimplemented."); + __builtin_unreachable(); + break; + case 'u': { + if(!matchNumericRange(1, 7, tm->tm_wday, nullptr)) + return nullptr; + tm->tm_wday--; + break; + } + case 'V': + __ensure(!"strptime() %V directive unimplemented."); + __builtin_unreachable(); + break; + case 'z': + __ensure(!"strptime() %z directive unimplemented."); + __builtin_unreachable(); + break; + case 'Z': + __ensure(!"strptime() %Z directive unimplemented."); + __builtin_unreachable(); + break; + case 's': //end of GNU extensions + __ensure(!"strptime() %s directive unimplemented."); + __builtin_unreachable(); + break; + case 'E': { //locale-dependent date & time representation + __ensure(!"strptime() %E* directives unimplemented."); + __builtin_unreachable(); + /* + state->format_index++; + switch(format[state->format_index]){ + case 'c': + break; + case 'C': + break; + case 'x': + break; + case 'X': + break; + case 'y': + break; + case 'Y': + break; + default: + return NULL; + } + */ + } + case 'O': { //locale-dependent numeric symbols + __ensure(!"strptime() %O* directives unimplemented."); + __builtin_unreachable(); + /* + state->format_index++; + switch(format[state->format_index]){ + case 'd': + case 'e': + break; + case 'H': + break; + case 'I': + break; + case 'm': + break; + case 'M': + break; + case 'S': + break; + case 'U': + break; + case 'w': + break; + case 'W': + break; + case 'y': + break; + default: + return NULL; + } + */ + } + default: + return nullptr; + } + state->format_index++; + } + + return (char*)input + state->input_index; +} + +} //anonymous namespace + +char *strptime(const char *__restrict s, const char *__restrict format, struct tm *__restrict tm){ + struct strptime_internal_state state = {}; + + char *result = strptime_internal(s, format, tm, &state); + + if(result == nullptr) + return nullptr; + + if(state.has_century && !state.full_year_given){ + int full_year = state.century * 100; + + if(state.has_year){ + //Compensate for default century-adjustment of `%j` operand + if(tm->tm_year >= 100) + full_year += tm->tm_year - 100; + else + full_year += tm->tm_year; + } + + tm->tm_year = full_year - 1900; + + state.has_year = true; + } + + if(state.has_month && !state.has_day_of_year){ + int day = 0; + if(state.has_year) + day = month_and_year_to_day_in_year(tm->tm_mon, tm->tm_year); + else + day = month_to_day(tm->tm_mon); + + tm->tm_yday = day + tm->tm_mday - 1; + state.has_day_of_year = true; + } + + if(state.has_year && !state.has_day_of_week){ + if(!state.has_month && !state.has_day_of_month){ + tm->tm_wday = day_determination(0, 0, tm->tm_year + 1900); + } + else if(state.has_month && state.has_day_of_month){ + tm->tm_wday = day_determination(tm->tm_mday, tm->tm_mon, tm->tm_year + 1900); + } + state.has_day_of_week = true; + } + + return result; +} + +int clock_getcpuclockid(pid_t, clockid_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/ucontext.cpp b/user/include/mlibc/options/posix/generic/ucontext.cpp new file mode 100644 index 0000000..9413a78 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/ucontext.cpp @@ -0,0 +1,19 @@ +#include +#include + +int getcontext(ucontext_t *) { + __ensure(!"Not implemented!"); + __builtin_unreachable(); +} +int setcontext(const ucontext_t *) { + __ensure(!"Not implemented!"); + __builtin_unreachable(); +} +void makecontext(ucontext_t *, void (*)(), int, ...) { + __ensure(!"Not implemented!"); + __builtin_unreachable(); +} +int swapcontext(ucontext_t *, const ucontext_t *) { + __ensure(!"Not implemented!"); + __builtin_unreachable(); +} diff --git a/user/include/mlibc/options/posix/generic/unistd.cpp b/user/include/mlibc/options/posix/generic/unistd.cpp new file mode 100644 index 0000000..d6cd0c3 --- /dev/null +++ b/user/include/mlibc/options/posix/generic/unistd.cpp @@ -0,0 +1,1435 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if __MLIBC_LINUX_OPTION +#include +#endif + +namespace { + +constexpr bool logExecvpeTries = false; + +} // namespace + +unsigned int alarm(unsigned int seconds) { + struct itimerval it = {}, old = {}; + it.it_value.tv_sec = seconds; + setitimer(ITIMER_REAL, &it, &old); + return old.it_value.tv_sec + !! old.it_value.tv_usec; +} + +int chdir(const char *path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_chdir, -1); + if(int e = mlibc::sys_chdir(path); e) { + errno = e; + return -1; + } + return 0; +} + +int fchdir(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchdir, -1); + if(int e = mlibc::sys_fchdir(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int chown(const char *path, uid_t uid, gid_t gid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchownat, -1); + if(int e = mlibc::sys_fchownat(AT_FDCWD, path, uid, gid, 0); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t confstr(int name, char *buf, size_t len) { + const char *str = ""; + if (name == _CS_PATH) { + str = "/bin:/usr/bin"; + } else if(name == _CS_GNU_LIBPTHREAD_VERSION) { + // We are not glibc, so we can return 0 here. + return 0; + } else if(name == _CS_GNU_LIBC_VERSION) { + // We are not glibc, so we can return 0 here. + return 0; + } else { + mlibc::infoLogger() << "\e[31mmlibc: confstr() request " << name << " is unimplemented\e[39m" + << frg::endlog; + __ensure(!"Not implemented"); + } + + return snprintf(buf, len, "%s", str) + 1; +} + +void _exit(int status) { + mlibc::sys_exit(status); +} + +int execl(const char *path, const char *arg0, ...) { + // TODO: It's a stupid idea to limit the number of arguments here. + char *argv[16]; + argv[0] = const_cast(arg0); + + va_list args; + int n = 1; + va_start(args, arg0); + while(true) { + __ensure(n < 15); + auto argn = va_arg(args, const char *); + argv[n++] = const_cast(argn); + if(!argn) + break; + } + va_end(args); + argv[n] = nullptr; + + return execve(path, argv, environ); +} + +// This function is taken from musl. +int execle(const char *path, const char *arg0, ...) { + int argc; + va_list ap; + va_start(ap, arg0); + for(argc = 1; va_arg(ap, const char *); argc++); + va_end(ap); + + int i; + char *argv[argc + 1]; + char **envp; + va_start(ap, arg0); + argv[0] = (char *)arg0; + for(i = 1; i <= argc; i++) + argv[i] = va_arg(ap, char *); + envp = va_arg(ap, char **); + va_end(ap); + return execve(path, argv, envp); +} + +// This function is taken from musl +int execlp(const char *file, const char *argv0, ...) { + int argc; + va_list ap; + va_start(ap, argv0); + for(argc = 1; va_arg(ap, const char *); argc++); + va_end(ap); + { + int i; + char *argv[argc + 1]; + va_start(ap, argv0); + argv[0] = (char *)argv0; + for(i = 1; i < argc; i++) + argv[i] = va_arg(ap, char *); + argv[i] = nullptr; + va_end(ap); + return execvp(file, argv); + } +} + +int execv(const char *path, char *const argv[]) { + return execve(path, argv, environ); +} + +int execvp(const char *file, char *const argv[]) { + return execvpe(file, argv, environ); +} + +int execvpe(const char *file, char *const argv[], char *const envp[]) { + char *null_list[] = { + nullptr + }; + + if(!argv) + argv = null_list; + if(!envp) + envp = null_list; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_execve, -1); + + if(strchr(file, '/')) { + int e = mlibc::sys_execve(file, argv, envp); + __ensure(e && "sys_execve() is supposed to never return with success"); + errno = e; + return -1; + } + + frg::string_view dirs; + if(const char *pv = getenv("PATH"); pv) { + dirs = pv; + }else{ + dirs = "/bin:/usr/bin"; + } + + size_t p = 0; + int res = ENOENT; + while(p < dirs.size()) { + size_t s; // Offset of next colon or end of string. + if(size_t cs = dirs.find_first(':', p); cs != size_t(-1)) { + s = cs; + }else{ + s = dirs.size(); + } + + frg::string path{getAllocator()}; + path += dirs.sub_string(p, s - p); + path += "/"; + path += file; + + if(logExecvpeTries) + mlibc::infoLogger() << "mlibc: execvpe() tries '" << path.data() << "'" << frg::endlog; + + int e = mlibc::sys_execve(path.data(), argv, envp); + __ensure(e && "sys_execve() is supposed to never return with success"); + switch(e) { + case ENOENT: + case ENOTDIR: + break; + case EACCES: + res = EACCES; + break; + default: + errno = e; + return -1; + } + + p = s + 1; + } + + errno = res; + return -1; +} + +int faccessat(int dirfd, const char *pathname, int mode, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_faccessat, -1); + if(int e = mlibc::sys_faccessat(dirfd, pathname, mode, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int fchown(int fd, uid_t uid, gid_t gid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchownat, -1); + if(int e = mlibc::sys_fchownat(fd, "", uid, gid, AT_EMPTY_PATH); e) { + errno = e; + return -1; + } + return 0; +} + +int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchownat, -1); + if(int e = mlibc::sys_fchownat(fd, path, uid, gid, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int fdatasync(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fdatasync, -1); + if(int e = mlibc::sys_fdatasync(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int fexecve(int, char *const [], char *const []) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long fpathconf(int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int fsync(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fsync, -1); + if(auto e = mlibc::sys_fsync(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int ftruncate(int fd, off_t size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ftruncate, -1); + if(int e = mlibc::sys_ftruncate(fd, size); e) { + errno = e; + return -1; + } + return 0; +} + +[[gnu::alias("ftruncate")]] int ftruncate64(int fd, off64_t size); + +char *getcwd(char *buffer, size_t size) { + if (buffer) { + if (size == 0) { + errno = EINVAL; + return nullptr; + } + } else if (!buffer) { + if (size == 0) + size = PATH_MAX; + + buffer = (char *)malloc(size); + } + + if (mlibc::sys_getcwd) { + if(int e = mlibc::sys_getcwd(buffer, size); e) { + errno = e; + return nullptr; + } + return buffer; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, nullptr); + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_openat, nullptr); + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_close, nullptr); + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup, nullptr); + + struct stat root_stat; + if (int e = mlibc::sys_stat(mlibc::fsfd_target::fd_path, AT_FDCWD, + "/", AT_SYMLINK_NOFOLLOW, + &root_stat); e) { + errno = e; + return nullptr; + } + + struct stat cur_dir_stat; + if (int e = mlibc::sys_stat(mlibc::fsfd_target::fd_path, AT_FDCWD, + ".", AT_SYMLINK_NOFOLLOW, + &cur_dir_stat); e) { + errno = e; + return nullptr; + } + + if (cur_dir_stat.st_ino == root_stat.st_ino + && cur_dir_stat.st_dev == root_stat.st_dev) { + if (size < 2) { + errno = ERANGE; + return nullptr; + } + strcpy(buffer, "/"); + return buffer; + } + + size_t bufptr = size - 1; + buffer[bufptr] = 0; + + int par_dir = AT_FDCWD; + bool last_run = false; + + for (;;) { + int old_par_dir = par_dir; + if (int e = mlibc::sys_openat(old_par_dir, "..", O_RDONLY, 0, &par_dir); e) { + errno = e; + return nullptr; + } + if (old_par_dir != AT_FDCWD) { + mlibc::sys_close(old_par_dir); + } + + struct stat par_dir_stat; + if (int e = mlibc::sys_stat(mlibc::fsfd_target::fd, par_dir, nullptr, + 0, &par_dir_stat); e) { + mlibc::sys_close(par_dir); + errno = e; + return nullptr; + } + + int par_dir_copy; + if (int e = mlibc::sys_dup(par_dir, 0, &par_dir_copy); e) { + mlibc::sys_close(par_dir); + errno = e; + return nullptr; + } + + DIR *par_dir_dir = fdopendir(par_dir_copy); + if (par_dir_dir == nullptr) { + mlibc::sys_close(par_dir_copy); + mlibc::sys_close(par_dir); + return nullptr; + } + + if (par_dir_stat.st_ino == root_stat.st_ino + && par_dir_stat.st_dev == root_stat.st_dev) { + last_run = true; + } + + for (;;) { + struct dirent *cur_ent = readdir(par_dir_dir); + if (cur_ent == nullptr) { + closedir(par_dir_dir); + mlibc::sys_close(par_dir); + return nullptr; + } + + if (strcmp(cur_ent->d_name, ".") == 0 || strcmp(cur_ent->d_name, "..") == 0) { + continue; + } + + struct stat cur_ent_stat; + if (int e = mlibc::sys_stat(mlibc::fsfd_target::fd_path, par_dir, + cur_ent->d_name, AT_SYMLINK_NOFOLLOW, + &cur_ent_stat)) { + closedir(par_dir_dir); + mlibc::sys_close(par_dir); + errno = e; + return nullptr; + } + + if (cur_ent_stat.st_ino == cur_dir_stat.st_ino + && cur_ent_stat.st_dev == cur_dir_stat.st_dev) { + size_t len = strlen(cur_ent->d_name); + if (len + 1 > bufptr + 1) { + closedir(par_dir_dir); + mlibc::sys_close(par_dir); + errno = ERANGE; + return nullptr; + } + bufptr -= len; + memcpy(&buffer[bufptr], cur_ent->d_name, len); + bufptr--; + buffer[bufptr] = '/'; + break; + } + } + + closedir(par_dir_dir); + + cur_dir_stat = par_dir_stat; + + if (last_run) { + break; + } + } + + mlibc::sys_close(par_dir); + + memmove(buffer, &buffer[bufptr], strlen(&buffer[bufptr]) + 1); + return buffer; +} + +int getgroups(int size, gid_t list[]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getgroups, -1); + int ret; + if(int e = mlibc::sys_getgroups(size, list, &ret); e) { + errno = e; + return -1; + } + return ret; +} + +long gethostid(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int gethostname(char *buffer, size_t bufsize) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_gethostname, -1); + if(auto e = mlibc::sys_gethostname(buffer, bufsize); e) { + errno = e; + return -1; + } + return 0; +} + +int sethostname(const char *buffer, size_t bufsize) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sethostname, -1); + if(auto e = mlibc::sys_sethostname(buffer, bufsize); e) { + errno = e; + return -1; + } + return 0; +} + +// Code taken from musl +char *getlogin(void) { + return getenv("LOGNAME"); +} + +int getlogin_r(char *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getopt(int argc, char *const argv[], const char *optstring) { + return mlibc::getopt_common(argc, argv, optstring, nullptr, nullptr, mlibc::GetoptMode::Short); +} + +pid_t getpgid(pid_t pid) { + pid_t pgid; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getpgid, -1); + if(int e = mlibc::sys_getpgid(pid, &pgid); e) { + errno = e; + return -1; + } + return pgid; +} + +pid_t getpgrp(void) { + return getpgid(0); +} + +pid_t getsid(pid_t pid) { + if(!mlibc::sys_getsid) { + MLIBC_MISSING_SYSDEP(); + return -1; + } + pid_t sid; + if(int e = mlibc::sys_getsid(pid, &sid); e) { + errno = e; + return -1; + } + return sid; +} + +int lchown(const char *path, uid_t uid, gid_t gid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchownat, -1); + if(int e = mlibc::sys_fchownat(AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW); e) { + errno = e; + return -1; + } + return 0; +} + +int link(const char *old_path, const char *new_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_link, -1); + if(int e = mlibc::sys_link(old_path, new_path); e) { + errno = e; + return -1; + } + return 0; +} + +int linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_linkat, -1); + if(int e = mlibc::sys_linkat(olddirfd, old_path, newdirfd, new_path, flags); e) { + errno = e; + return -1; + } + return 0; +} + +// Code take from musl +int lockf(int fd, int op, off_t size) { + struct flock l = { + .l_type = F_WRLCK, + .l_whence = SEEK_CUR, + .l_start = 0, + .l_len = size, + .l_pid = 0, + }; + + switch(op) { + case F_TEST: + l.l_type = F_RDLCK; + if(fcntl(fd, F_GETLK, &l) < 0) + return -1; + if(l.l_type == F_UNLCK || l.l_pid == getpid()) + return 0; + errno = EACCES; + return -1; + case F_ULOCK: + l.l_type = F_UNLCK; + [[fallthrough]]; + case F_TLOCK: + return fcntl(fd, F_SETLK, &l); + case F_LOCK: + return fcntl(fd, F_SETLKW, &l); + } + + errno = EINVAL; + return -1; +} + +int nice(int nice) { + int new_nice; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_nice, -1); + if(int e = mlibc::sys_nice(nice, &new_nice); e) { + errno = e; + return -1; + } + + return new_nice; +} + +long pathconf(const char *, int name) { + switch (name) { + case _PC_NAME_MAX: + return NAME_MAX; + default: + mlibc::infoLogger() << "missing pathconf() entry " << name << frg::endlog; + errno = EINVAL; + return -1; + } +} + +int pause(void) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pause, -1); + if(int e = mlibc::sys_pause(); e) { + errno = e; + return -1; + } + __ensure(!"There is no successful completion return value for pause"); + __builtin_unreachable(); +} + +int pipe(int *fds) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pipe, -1); + if(int e = mlibc::sys_pipe(fds, 0); e) { + errno = e; + return -1; + } + return 0; +} + +int pipe2(int *fds, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pipe, -1); + if(int e = mlibc::sys_pipe(fds, flags); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t pread(int fd, void *buf, size_t n, off_t off) { + ssize_t num_read; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pread, -1); + if(int e = mlibc::sys_pread(fd, buf, n, off, &num_read); e) { + errno = e; + return -1; + } + return num_read; +} + +[[gnu::alias("pread")]] ssize_t pread64(int fd, void *buf, size_t n, off_t off); + +ssize_t pwrite(int fd, const void *buf, size_t n, off_t off) { + ssize_t num_written; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pwrite, -1); + if(int e = mlibc::sys_pwrite(fd, buf, n, off, &num_written); e) { + errno = e; + return -1; + } + return num_written; +} + +[[gnu::alias("pwrite")]] ssize_t pwrite64(int fd, const void *buf, size_t n, off_t off); + +ssize_t readlink(const char *__restrict path, char *__restrict buffer, size_t max_size) { + ssize_t length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_readlink, -1); + if(int e = mlibc::sys_readlink(path, buffer, max_size, &length); e) { + errno = e; + return -1; + } + return length; +} + +ssize_t readlinkat(int dirfd, const char *__restrict path, char *__restrict buffer, size_t max_size) { + ssize_t length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_readlinkat, -1); + if(int e = mlibc::sys_readlinkat(dirfd, path, buffer, max_size, &length); e) { + errno = e; + return -1; + } + return length; +} + +int rmdir(const char *path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_rmdir, -1); + if(int e = mlibc::sys_rmdir(path); e) { + errno = e; + return -1; + } + return 0; +} + +int setegid(gid_t egid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setegid, 0); + if(int e = mlibc::sys_setegid(egid); e) { + errno = e; + return -1; + } + return 0; +} + +int seteuid(uid_t euid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_seteuid, 0); + if(int e = mlibc::sys_seteuid(euid); e) { + errno = e; + return -1; + } + return 0; +} + +int setgid(gid_t gid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setgid, 0); + if(int e = mlibc::sys_setgid(gid); e) { + errno = e; + return -1; + } + return 0; +} + +int setpgid(pid_t pid, pid_t pgid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setpgid, -1); + if(int e = mlibc::sys_setpgid(pid, pgid); e) { + errno = e; + return -1; + } + return 0; +} + +pid_t setpgrp(void) { + return setpgid(0, 0); +} + +int setregid(gid_t rgid, gid_t egid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setregid, -1); + if(int e = mlibc::sys_setregid(rgid, egid); e) { + errno = e; + return -1; + } + return 0; +} + +int setreuid(uid_t ruid, uid_t euid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setreuid, -1); + if(int e = mlibc::sys_setreuid(ruid, euid); e) { + errno = e; + return -1; + } + return 0; +} + +pid_t setsid(void) { + if(!mlibc::sys_setsid) { + MLIBC_MISSING_SYSDEP(); + return -1; + } + pid_t sid; + if(int e = mlibc::sys_setsid(&sid); e) { + errno = e; + return -1; + } + return sid; +} + +int setuid(uid_t uid) { + if(!mlibc::sys_setuid) { + MLIBC_MISSING_SYSDEP(); + mlibc::infoLogger() << "mlibc: missing sysdep sys_setuid(). Returning 0" << frg::endlog; + return 0; + } + if(int e = mlibc::sys_setuid(uid); e) { + errno = e; + return -1; + } + return 0; +} + +void swab(const void *__restrict _src, void *__restrict _dest, ssize_t n) { + auto src = reinterpret_cast(_src); + auto dest = reinterpret_cast(_dest); + for (ssize_t i = 0; i < n && n - i > 1; i += 2) { + dest[i] = src[i + 1]; + dest[i + 1] = src[i]; + } +} + +int symlink(const char *target_path, const char *link_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_symlink, -1); + if(int e = mlibc::sys_symlink(target_path, link_path); e) { + errno = e; + return -1; + } + return 0; +} + +int symlinkat(const char *target_path, int dirfd, const char *link_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_symlinkat, -1); + if(int e = mlibc::sys_symlinkat(target_path, dirfd, link_path); e) { + errno = e; + return -1; + } + return 0; +} + +void sync(void) { + if(!mlibc::sys_sync) { + MLIBC_MISSING_SYSDEP(); + } else { + mlibc::sys_sync(); + } +} + +long sysconf(int number) { + if(mlibc::sys_sysconf) { + long ret = 0; + + int e = mlibc::sys_sysconf(number, &ret); + + if(e && e != EINVAL) { + errno = e; + return -1; + } + + if(e != EINVAL) { + return ret; + } + } + + /* default return values, if not overriden by sysdep */ + switch(number) { + case _SC_ARG_MAX: + // On linux, it is defined to 2097152 in most cases, so define it to be 2097152 + return 2097152; + case _SC_PAGE_SIZE: + return mlibc::page_size; + case _SC_OPEN_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_OPEN_MAX) returns fallback value 256\e[39m" << frg::endlog; + return 256; + case _SC_TZNAME_MAX: + return -1; + case _SC_PHYS_PAGES: +#if __MLIBC_LINUX_OPTION + if(mlibc::sys_sysinfo) { + struct sysinfo info{}; + if(mlibc::sys_sysinfo(&info) == 0) + return info.totalram * info.mem_unit / mlibc::page_size; + } +#endif + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_PHYS_PAGES) returns fallback value 1024\e[39m" << frg::endlog; + return 1024; + case _SC_AVPHYS_PAGES: +#if __MLIBC_LINUX_OPTION + if(mlibc::sys_sysinfo) { + struct sysinfo info{}; + if(mlibc::sys_sysinfo(&info) == 0) + return info.freeram * info.mem_unit / mlibc::page_size; + } +#endif + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_AVPHYS_PAGES) returns fallback value 1024\e[39m" << frg::endlog; + return 1024; + case _SC_NPROCESSORS_ONLN: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_NPROCESSORS_ONLN) returns fallback value 1\e[39m" << frg::endlog; + return 1; + case _SC_GETPW_R_SIZE_MAX: + return NSS_BUFLEN_PASSWD; + case _SC_GETGR_R_SIZE_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_GETGR_R_SIZE_MAX) returns fallback value 1024\e[39m" << frg::endlog; + return 1024; + case _SC_CHILD_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_CHILD_MAX) returns fallback value 25\e[39m" << frg::endlog; + // On linux, it is defined to 25 in most cases, so define it to be 25 + return 25; + case _SC_JOB_CONTROL: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_JOB_CONTROL) returns fallback value 1\e[39m" << frg::endlog; + // If 1, job control is supported + return 1; + case _SC_CLK_TCK: + // TODO: This should be obsolete? + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_CLK_TCK) is obsolete and returns arbitrary value 1000000\e[39m" << frg::endlog; + return 1000000; + case _SC_NGROUPS_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_NGROUPS_MAX) returns fallback value 65536\e[39m" << frg::endlog; + // On linux, it is defined to 65536 in most cases, so define it to be 65536 + return 65536; + case _SC_RE_DUP_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_RE_DUP_MAX) returns fallback value RE_DUP_MAX\e[39m" << frg::endlog; + return RE_DUP_MAX; + case _SC_LINE_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_LINE_MAX) returns fallback value 2048\e[39m" << frg::endlog; + // Linux defines it as 2048. + return 2048; + case _SC_XOPEN_CRYPT: + return -1; + case _SC_NPROCESSORS_CONF: + // TODO: actually return a proper value for _SC_NPROCESSORS_CONF + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_NPROCESSORS_CONF) unconditionally returns fallback value 1\e[39m" << frg::endlog; + return 1; + case _SC_HOST_NAME_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_HOST_NAME_MAX) unconditionally returns fallback value 256\e[39m" << frg::endlog; + return 256; + case _SC_LOGIN_NAME_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_LOGIN_NAME_MAX) unconditionally returns fallback value 256\e[39m" << frg::endlog; + return 256; + case _SC_FSYNC: + return _POSIX_FSYNC; + case _SC_SAVED_IDS: + return _POSIX_SAVED_IDS; + case _SC_SYMLOOP_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_SYMLOOP_MAX) unconditionally returns fallback value 8\e[39m" << frg::endlog; + return 8; + default: + mlibc::infoLogger() << "\e[31mmlibc: sysconf() call is not implemented, number: " << number << "\e[39m" << frg::endlog; + errno = EINVAL; + return -1; + } +} + +pid_t tcgetpgrp(int fd) { + int pgrp; + if(ioctl(fd, TIOCGPGRP, &pgrp) < 0) { + return -1; + } + return pgrp; +} + +int tcsetpgrp(int fd, pid_t pgrp) { + return ioctl(fd, TIOCSPGRP, &pgrp); +} + +int truncate(const char *, off_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +[[gnu::alias("truncate")]] int truncate64(const char *, off64_t); + +char *ttyname(int fd) { + const size_t size = 128; + static thread_local char buf[size]; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ttyname, nullptr); + if(int e = mlibc::sys_ttyname(fd, buf, size); e) { + errno = e; + return nullptr; + } + return buf; +} + +int ttyname_r(int fd, char *buf, size_t size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ttyname, -1); + if(int e = mlibc::sys_ttyname(fd, buf, size); e) { + return e; + } + return 0; +} + +int unlink(const char *path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlinkat, -1); + if(int e = mlibc::sys_unlinkat(AT_FDCWD, path, 0); e) { + errno = e; + return -1; + } + return 0; +} + +int unlinkat(int fd, const char *path, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlinkat, -1); + if(int e = mlibc::sys_unlinkat(fd, path, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int getpagesize() { + return mlibc::page_size; +} + +// Code taken from musl +// GLIBC extension for stdin/stdout +char *getpass(const char *prompt) { + int fdin, fdout; + struct termios s, t; + ssize_t l; + static char password[128]; + + if((fdin = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) { + fdin = STDIN_FILENO; + fdout = STDOUT_FILENO; + } else { + fdout = fdin; + } + + tcgetattr(fdin, &t); + s = t; + t.c_lflag &= ~(ECHO | ISIG); + t.c_lflag |= ICANON; + t.c_iflag &= ~(INLCR | IGNCR); + t.c_iflag |= ICRNL; + tcsetattr(fdin, TCSAFLUSH, &t); + tcdrain(fdin); + + dprintf(fdout, "%s", prompt); + + l = read(fdin, password, sizeof password); + if(l >= 0) { + if((l > 0 && password[l - 1] == '\n') || l == sizeof password) + l--; + password[l] = 0; + } + + tcsetattr(fdin, TCSAFLUSH, &s); + + dprintf(fdout, "\n"); + if(fdin != STDIN_FILENO) { + close(fdin); + } + + return l < 0 ? nullptr : password; +} + +char *get_current_dir_name(void) { + char *pwd; + struct stat dotstat, pwdstat; + + pwd = getenv ("PWD"); + if(pwd != nullptr && stat(".", &dotstat) == 0 + && stat(pwd, &pwdstat) == 0 && pwdstat.st_dev == dotstat.st_dev + && pwdstat.st_ino == dotstat.st_ino) + /* The PWD value is correct. Use it. */ + return strdup(pwd); + + return getcwd((char *) nullptr, 0); +} + +// This is a Linux extension +pid_t gettid(void) { + if(!mlibc::sys_gettid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_gettid()"); + } + return mlibc::sys_gettid(); +} + +int getentropy(void *buffer, size_t length) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getentropy, -1); + if(length > 256) { + errno = EIO; + return -1; + } + if(int e = mlibc::sys_getentropy(buffer, length); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t write(int fd, const void *buf, size_t count) { + ssize_t bytes_written; + if(int e = mlibc::sys_write(fd, buf, count, &bytes_written); e) { + errno = e; + return (ssize_t)-1; + } + return bytes_written; +} + +ssize_t read(int fd, void *buf, size_t count) { + ssize_t bytes_read; + if(int e = mlibc::sys_read(fd, buf, count, &bytes_read); e) { + errno = e; + return (ssize_t)-1; + } + return bytes_read; +} + +off_t lseek(int fd, off_t offset, int whence) { + off_t new_offset; + if(int e = mlibc::sys_seek(fd, offset, whence, &new_offset); e) { + errno = e; + return (off_t)-1; + } + return new_offset; +} + +off64_t lseek64(int fd, off64_t offset, int whence) { + off64_t new_offset; + if(int e = mlibc::sys_seek(fd, offset, whence, &new_offset); e) { + errno = e; + return (off64_t)-1; + } + return new_offset; +} + +int close(int fd) { + if(int e = mlibc::sys_close(fd); e) { + errno = e; + return -1; + } + return 0; +} + +unsigned int sleep(unsigned int secs) { + time_t seconds = secs; + long nanos = 0; + if(!mlibc::sys_sleep) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_sleep()"); + } + mlibc::sys_sleep(&seconds, &nanos); + return seconds; +} + +// In contrast to sleep() this functions returns 0/-1 on success/failure. +int usleep(useconds_t usecs) { + time_t seconds = 0; + long nanos = usecs * 1000; + if(!mlibc::sys_sleep) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_sleep()"); + } + return mlibc::sys_sleep(&seconds, &nanos); +} + +int dup(int fd) { + int newfd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup, -1); + if(int e = mlibc::sys_dup(fd, 0, &newfd); e) { + errno = e; + return -1; + } + return newfd; +} + +int dup2(int fd, int newfd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup2, -1); + if(int e = mlibc::sys_dup2(fd, 0, newfd); e) { + errno = e; + return -1; + } + return newfd; +} + +pid_t fork(void) { + auto self = mlibc::get_current_tcb(); + pid_t child; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork, -1); + + auto hand = self->atforkEnd; + while (hand) { + if (hand->prepare) + hand->prepare(); + + hand = hand->prev; + } + + if(int e = mlibc::sys_fork(&child); e) { + errno = e; + return -1; + } + + hand = self->atforkBegin; + while (hand) { + if (!child) { + if (hand->child) + hand->child(); + } else { + if (hand->parent) + hand->parent(); + } + hand = hand->next; + } + + return child; +} + +pid_t vfork(void) { + pid_t child; + /* + * Fork handlers established using pthread_atfork(3) are not + * called when a multithreaded program employing the NPTL + * threading library calls vfork(). Fork handlers are called + * in this case in a program using the LinuxThreads threading + * library. (See pthreads(7) for a description of Linux + * threading libraries.) + * - vfork(2), release 5.13 of the Linux man-pages project + * + * as a result, we call sys_fork instead of running atforks + */ + + /* deferring to fork as implementing vfork correctly requires assembly + * to handle not mucking up the stack + */ + if(!mlibc::sys_fork) { + MLIBC_MISSING_SYSDEP(); + errno = ENOSYS; + return -1; + } + + if(int e = mlibc::sys_fork(&child); e) { + errno = e; + return -1; + } + + return child; +} + +int execve(const char *path, char *const argv[], char *const envp[]) { + char *null_list[] = { + nullptr + }; + + if(!argv) + argv = null_list; + if(!envp) + envp = null_list; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_execve, -1); + int e = mlibc::sys_execve(path, argv, envp); + __ensure(e && "sys_execve() is expected to fail if it returns"); + errno = e; + return -1; +} + +gid_t getgid(void) { + if(!mlibc::sys_getgid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getgid()"); + } + return mlibc::sys_getgid(); +} + +gid_t getegid(void) { + if(!mlibc::sys_getegid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getegid()"); + } + return mlibc::sys_getegid(); +} + +uid_t getuid(void) { + if(!mlibc::sys_getuid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getuid()"); + } + return mlibc::sys_getuid(); +} + +uid_t geteuid(void) { + if(!mlibc::sys_geteuid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_geteuid()"); + } + return mlibc::sys_geteuid(); +} + +pid_t getpid(void) { + if(!mlibc::sys_getpid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getpid()"); + } + return mlibc::sys_getpid(); +} + +pid_t getppid(void) { + if(!mlibc::sys_getppid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getppid()"); + } + return mlibc::sys_getppid(); +} + +int access(const char *path, int mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_access, -1); + if(int e = mlibc::sys_access(path, mode); e) { + errno = e; + return -1; + } + return 0; +} + +namespace { + FILE *user_shell_global_file; // Used by setusershell/getusershell/endusershell. + + bool user_shell_open_global_file() { + if(!user_shell_global_file) { + user_shell_global_file = fopen("/etc/shells", "r"); + if(!user_shell_global_file) { + // if the file cannot be opened, we need to pretend one exists with + // these shells: + static char shells[] = "/bin/sh\n/bin/csh\n"; + + user_shell_global_file = fmemopen(shells, strlen(shells), "r"); + if(user_shell_global_file == nullptr) + return false; + } + } + + return true; + } + + void user_shell_close_global_file() { + if(user_shell_global_file) { + fclose(user_shell_global_file); + user_shell_global_file = nullptr; + } + } +} // namespace + +char *getusershell(void) { + static char shell[PATH_MAX]; + if(!user_shell_open_global_file()) + return nullptr; + + if (fgets(shell, PATH_MAX, user_shell_global_file)){ + shell[strcspn(shell, "\n")] = '\0'; + return shell; + } + + if(ferror(user_shell_global_file)) + errno = EIO; + + return nullptr; +} + +void setusershell(void) { + if(!user_shell_open_global_file()) + return; + + rewind(user_shell_global_file); +} + +void endusershell(void) { + user_shell_close_global_file(); +} + +int isatty(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_isatty, 0); + if(int e = mlibc::sys_isatty(fd); e) { + errno = e; + return 0; + } + return 1; +} + +int chroot(const char *ptr) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_chroot, -1); + if(int e = mlibc::sys_chroot(ptr); e) { + errno = e; + return -1; + } + return 0; +} + +int daemon(int nochdir, int noclose) { + switch(fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); + } + + if(setsid() < 0) + return -1; + + if(!nochdir && chdir("/")) + return -1; + + if(!noclose) { + int fd = open("/dev/null", O_RDWR); + if(fd < 0) + return -1; + + bool failed = false; + if(dup2(fd, 0) < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) + failed = true; + if(fd > 2) + close(fd); + if(failed) + return -1; + } + + return 0; +} + +char *ctermid(char *s) { + return s ? strcpy(s, "/dev/tty") : const_cast("/dev/tty"); +} + +int setresuid(uid_t ruid, uid_t euid, uid_t suid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setresuid, -1); + if(int e = mlibc::sys_setresuid(ruid, euid, suid); e) { + errno = e; + return -1; + } + return 0; +} + +int setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setresgid, -1); + if(int e = mlibc::sys_setresgid(rgid, egid, sgid); e) { + errno = e; + return -1; + } + return 0; +} + +int getdomainname(char *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int setdomainname(const char *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getresuid, -1); + if(int e = mlibc::sys_getresuid(ruid, euid, suid); e) { + errno = e; + return -1; + } + return 0; +} + +int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getresgid, -1); + if(int e = mlibc::sys_getresgid(rgid, egid, sgid); e) { + errno = e; + return -1; + } + return 0; +} + +#if __MLIBC_BSD_OPTION +void *sbrk(intptr_t increment) { + if(increment) { + errno = ENOMEM; + return (void *)-1; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_brk, (void *)-1); + void *out; + if(int e = mlibc::sys_brk(&out); e) { + errno = e; + return (void *)-1; + } + return out; +} +#endif diff --git a/user/include/mlibc/options/posix/generic/utime.cpp b/user/include/mlibc/options/posix/generic/utime.cpp new file mode 100644 index 0000000..f78729f --- /dev/null +++ b/user/include/mlibc/options/posix/generic/utime.cpp @@ -0,0 +1,31 @@ + +#include +#include +#include + +#include +#include + +int utime(const char *filename, const struct utimbuf *times) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + struct timespec time[2]; + if(times) { + time[0].tv_sec = times->actime; + time[0].tv_nsec = 0; + time[1].tv_sec = times->modtime; + time[1].tv_nsec = 0; + } else { + time[0].tv_sec = UTIME_NOW; + time[0].tv_nsec = UTIME_NOW; + time[1].tv_sec = UTIME_NOW; + time[1].tv_nsec = UTIME_NOW; + } + + if (int e = mlibc::sys_utimensat(AT_FDCWD, filename, time, 0); e) { + errno = e; + return -1; + } + + return 0; +} + diff --git a/user/include/mlibc/options/posix/generic/utmpx.cpp b/user/include/mlibc/options/posix/generic/utmpx.cpp new file mode 100644 index 0000000..bf4e76f --- /dev/null +++ b/user/include/mlibc/options/posix/generic/utmpx.cpp @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + +constexpr const char *defaultUtmpxPath = UTMPX_FILE; + +const char *utmpxPath = defaultUtmpxPath; +frg::ticket_spinlock utmpxMutex; + +frg::optional utmpxFd = frg::null_opt; + +utmpx returned; + +} // namespace + +void updwtmpx(const char *file, const struct utmpx *ut) { + int fd; + int err = mlibc::sys_open(file, O_RDWR | O_CREAT | O_CLOEXEC | O_APPEND, 0644, &fd); + if(err) { + mlibc::infoLogger() << "\e[31mmlibc: updwtmpx() failed to open " << file << ": " + << strerror(err) << "\e[39m" << frg::endlog; + return; + } + + mlibc::putUtmpEntry(fd, ut); + + mlibc::sys_close(fd); +} + +void endutxent(void) { + frg::unique_lock lock{utmpxMutex}; + + if(utmpxFd) { + mlibc::sys_close(utmpxFd.value()); + utmpxFd = frg::null_opt; + } +} + +void setutxent(void) { + frg::unique_lock lock{utmpxMutex}; + + if(!utmpxFd) { + int fd; + + // If we are opening the utmp file as a non-root user with a root-made + // utmp, we need to open as a reader instead of a writer, O_RDWR will + // fail as no write permission can be obtained with 0644. + // + // The operations that need writing like updates will naturally fail + // because of the underlying sysdep failing. + int err = mlibc::sys_open(utmpxPath, O_RDWR | O_CREAT | O_CLOEXEC, 0644, &fd); + if(err == EACCES) { + err = mlibc::sys_open(utmpxPath, O_RDONLY | O_CLOEXEC, 0644, &fd); + } + + if(err) { + mlibc::infoLogger() << "\e[31mmlibc: setutxent() failed to open " << utmpxPath << ": " + << strerror(err) << "\e[39m" << frg::endlog; + utmpxFd = frg::null_opt; + } else { + utmpxFd = fd; + } + } else { + off_t discard; + mlibc::sys_seek(utmpxFd.value(), 0, SEEK_SET, &discard); + } +} + +struct utmpx *getutxent(void) { + frg::unique_lock lock{utmpxMutex}; + + if(!utmpxFd) + setutxent(); + if(!utmpxFd) { + errno = ENOENT; + return nullptr; + } + + if(int e = mlibc::getUtmpEntry(*utmpxFd, &returned); e) { + errno = e; + return nullptr; + } + + return &returned; +} + +struct utmpx *pututxline(const struct utmpx *ut) { + frg::unique_lock lock{utmpxMutex}; + + if(!utmpxFd) + setutxent(); + if(!utmpxFd) { + errno = ENOENT; + return nullptr; + } + + if(int e = mlibc::putUtmpEntry(*utmpxFd, ut); e) { + errno = e; + return nullptr; + } + + return (utmpx *) ut; +} + +int utmpxname(const char *file) { + frg::unique_lock lock{utmpxMutex}; + + if(strcmp(file, utmpxPath)) { + if(!strcmp(file, defaultUtmpxPath)) { + free((void *) utmpxPath); + utmpxPath = defaultUtmpxPath; + } else { + char *name = strdup(file); + if(!name) + return -1; + + if(utmpxPath != defaultUtmpxPath) + free((void *) utmpxPath); + + utmpxPath = name; + } + } + + return 0; +} + +struct utmpx *getutxid(const struct utmpx *ut) { + frg::unique_lock lock{utmpxMutex}; + + if(!utmpxFd) + setutxent(); + if(!utmpxFd) { + errno = ENOENT; + return nullptr; + } + + if(int e = mlibc::getUtmpEntryById(*utmpxFd, ut, &returned); e) { + errno = e; + return nullptr; + } + + return &returned; +} + +struct utmpx *getutxline(const struct utmpx *ut) { + frg::unique_lock lock{utmpxMutex}; + + if(!utmpxFd) + setutxent(); + if(!utmpxFd) { + errno = ENOENT; + return nullptr; + } + + if(int e = mlibc::getUtmpEntryByType(*utmpxFd, ut, &returned); e) { + errno = e; + return nullptr; + } + + return &returned; +} diff --git a/user/include/mlibc/options/posix/generic/wordexp.cpp b/user/include/mlibc/options/posix/generic/wordexp.cpp new file mode 100644 index 0000000..97319ce --- /dev/null +++ b/user/include/mlibc/options/posix/generic/wordexp.cpp @@ -0,0 +1,342 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * code taken from OPNSense, with modifications + * + * Copyright (c) 2002 Tim J. Robbins. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHELL_PATH "/bin/sh" +#define SHELL_NAME "sh" + +static size_t we_read_fully(int fd, char *buffer, size_t len) { + size_t done = 0; + + do { + ssize_t nread = read(fd, buffer + done, len - done); + if(nread == -1 && errno == EINTR) + continue; + if(nread <= 0) + break; + done += nread; + } while (done != len); + + return done; +} + +static int we_askshell(const char *words, wordexp_t *we, int flags) { + int pdes[2]; /* pipe to child */ + char bbuf[9]; /* buffer for byte count */ + char wbuf[9]; /* buffer for word count */ + size_t nwords = 0; /* number of words from child */ + size_t nbytes = 0; /* number of bytes from child */ + size_t sofs = 0; /* offset into we->we_strings */ + size_t vofs = 0; /* offset into we->we_wordv */ + pid_t pid; /* PID of child */ + pid_t wpid; /* waitpid return value */ + int status; /* child exit status */ + int error; /* our return value */ + int serrno; /* errno to return */ + char *np, *p; /* handy pointers */ + char *nstrings; /* temporary for realloc() */ + char **new_wordv; /* temporary for realloc() */ + sigset_t newsigblock; + sigset_t oldsigblock; + const char *ifs = getenv("IFS"); + + serrno = errno; + + if(pipe2(pdes, O_CLOEXEC) < 0) + return WRDE_NOSPACE; + + (void)sigemptyset(&newsigblock); + (void)sigaddset(&newsigblock, SIGCHLD); + (void)sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); + + if((pid = fork()) < 0) { + serrno = errno; + close(pdes[0]); + close(pdes[1]); + (void)sigprocmask(SIG_SETMASK, &oldsigblock, nullptr); + errno = serrno; + return WRDE_NOSPACE; + } else if(pid == 0) { + /* + * We are the child; make /bin/sh expand `words'. + */ + (void)sigprocmask(SIG_SETMASK, &oldsigblock, nullptr); + if((pdes[1] != STDOUT_FILENO ? dup2(pdes[1], STDOUT_FILENO) : fcntl(pdes[1], F_SETFD, 0)) < 0) + _exit(1); + + execl(SHELL_PATH, SHELL_NAME, flags & WRDE_UNDEF ? "-u" : "+u", + "-c", "IFS=$1;eval \"$2\";eval \"set -- $3\";IFS=;a=\"$*\";" + "printf '%08x' \"$#\" \"${#a}\";printf '%s\\0' \"$@\"", "", + ifs != nullptr ? ifs : " \t\n", + flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null", + words, + (char *)nullptr); + _exit(1); + } + + /* + * We are the parent; read the output of the shell wordexp function, + * which is a 32-bit hexadecimal word count, a 32-bit hexadecimal + * byte count (not including terminating null bytes), followed by + * the expanded words separated by nulls. + */ + close(pdes[1]); + if(we_read_fully(pdes[0], wbuf, 8) != 8 || we_read_fully(pdes[0], bbuf, 8) != 8) { + error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; + serrno = errno; + goto cleanup; + } + wbuf[8] = bbuf[8] = '\0'; + nwords = strtol(wbuf, nullptr, 16); + nbytes = strtol(bbuf, nullptr, 16) + nwords; + + /* + * Allocate or reallocate (when flags & WRDE_APPEND) the word vector + * and string storage buffers for the expanded words we're about to + * read from the child. + */ + sofs = we->we_nbytes; + vofs = we->we_wordc; + if((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS | WRDE_APPEND)) + vofs += we->we_offs; + we->we_wordc += nwords; + we->we_nbytes += nbytes; + + if((new_wordv = (char **) realloc(we->we_wordv, (we->we_wordc + 1 + (flags & WRDE_DOOFFS ? we->we_offs : 0)) * sizeof(char *))) == nullptr) { + error = WRDE_NOSPACE; + goto cleanup; + } + + we->we_wordv = new_wordv; + + if((nstrings = (char *) realloc(we->we_strings, we->we_nbytes)) == nullptr) { + error = WRDE_NOSPACE; + goto cleanup; + } + + for(size_t i = 0; i < vofs; i++) { + if(we->we_wordv[i] != nullptr) + we->we_wordv[i] += nstrings - we->we_strings; + } + we->we_strings = nstrings; + + if(we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) { + error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; + serrno = errno; + goto cleanup; + } + + error = 0; +cleanup: + close(pdes[0]); + + do { + wpid = waitpid(pid, &status, 0); + } while(wpid < 0 && errno == EINTR); + + (void)sigprocmask(SIG_SETMASK, &oldsigblock, nullptr); + + if(error != 0) { + errno = serrno; + return error; + } + + if(wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) + return flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; + + /* + * Break the null-terminated expanded word strings out into + * the vector. + */ + if(vofs == 0 && flags & WRDE_DOOFFS) { + while (vofs < we->we_offs) + we->we_wordv[vofs++] = nullptr; + } + + p = we->we_strings + sofs; + while (nwords-- != 0) { + we->we_wordv[vofs++] = p; + if((np = (char *) memchr(p, '\0', nbytes)) == nullptr) + return WRDE_NOSPACE; + + nbytes -= np - p + 1; + p = np + 1; + } + + we->we_wordv[vofs] = nullptr; + return 0; +} + +/* + * we_check -- + * Check that the string contains none of the following unquoted + * special characters: |&;<>(){} + * or command substitutions when WRDE_NOCMD is set in flags. + */ +static int we_check(const char *words, int flags) +{ + char c; + int dquote, level, quote, squote; + + quote = squote = dquote = 0; + while ((c = *words++) != '\0') { + switch (c) { + case '\\': { + if(squote == 0) + quote ^= 1; + continue; + } + case '\'': { + if(quote + dquote == 0) + squote ^= 1; + break; + } + case '"': { + if(quote + squote == 0) + dquote ^= 1; + break; + } + case '`': { + if(quote + squote == 0 && flags & WRDE_NOCMD) + return WRDE_CMDSUB; + while ((c = *words++) != '\0' && c != '`') + if(c == '\\' && (c = *words++) == '\0') + break; + if(c == '\0') + return WRDE_SYNTAX; + break; + } + case '|': + case '&': + case ';': + case '<': + case '>': + case '{': + case '}': + case '(': + case ')': + case '\n': { + if(quote + squote + dquote == 0) + return WRDE_BADCHAR; + break; + } + case '$': { + if((c = *words++) == '\0') + break; + else if(quote + squote == 0 && c == '(') { + if(flags & WRDE_NOCMD && *words != '(') + return WRDE_CMDSUB; + level = 1; + while ((c = *words++) != '\0') { + if(c == '\\') { + if((c = *words++) == '\0') + break; + } else if(c == '(') + level++; + else if(c == ')' && --level == 0) + break; + } + if(c == '\0' || level != 0) + return WRDE_SYNTAX; + } else if(quote + squote == 0 && c == '{') { + level = 1; + while ((c = *words++) != '\0') { + if(c == '\\') { + if((c = *words++) == '\0') + break; + } else if(c == '{') + level++; + else if(c == '}' && --level == 0) + break; + } + if(c == '\0' || level != 0) + return WRDE_SYNTAX; + } else + --words; + break; + } + default: { + break; + } + } + quote = 0; + } + + if(quote + squote + dquote != 0) + return WRDE_SYNTAX; + + return 0; +} + +int wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags) { + int error; + + if(flags & WRDE_REUSE) + wordfree(we); + + if((flags & WRDE_APPEND) == 0) { + we->we_wordc = 0; + we->we_wordv = nullptr; + we->we_strings = nullptr; + we->we_nbytes = 0; + } + + if((error = we_check(words, flags)) != 0) { + wordfree(we); + return error; + } + + if((error = we_askshell(words, we, flags)) != 0) { + wordfree(we); + return error; + } + + return 0; +} + +void wordfree(wordexp_t *we) { + if (we == nullptr) + return; + free(we->we_wordv); + free(we->we_strings); + we->we_wordv = nullptr; + we->we_strings = nullptr; + we->we_nbytes = 0; + we->we_wordc = 0; +} diff --git a/user/include/mlibc/options/posix/include/arpa/inet.h b/user/include/mlibc/options/posix/include/arpa/inet.h new file mode 100644 index 0000000..1a492ca --- /dev/null +++ b/user/include/mlibc/options/posix/include/arpa/inet.h @@ -0,0 +1,47 @@ +#ifndef _ARPA_INET_H +#define _ARPA_INET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +uint32_t htonl(uint32_t __x); +uint16_t htons(uint16_t __x); +uint32_t ntohl(uint32_t __x); +uint16_t ntohs(uint16_t __x); + +/* ---------------------------------------------------------------------------- */ +/* IPv4 address manipulation. */ +/* ---------------------------------------------------------------------------- */ + +in_addr_t inet_addr(const char *__cp); +in_addr_t inet_network(const char *__cp); +char *inet_ntoa(struct in_addr __in); + +/* GLIBC replacement for inet_addr(). */ +int inet_aton(const char *__cp, struct in_addr *__dest); + +/* ---------------------------------------------------------------------------- */ +/* Generic IP address manipulation. */ +/* ---------------------------------------------------------------------------- */ +const char *inet_ntop(int __af, const void *__restrict __src, char *__restrict __dst, + socklen_t __size) __attribute__((__nonnull__(3))); +int inet_pton(int __af, const char *__restrict __src, void *__restrict __dst); + +struct in_addr inet_makeaddr(in_addr_t __net, in_addr_t __host); +in_addr_t inet_netof(struct in_addr __in); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ARPA_INET_H */ + diff --git a/user/include/mlibc/options/posix/include/bits/posix/fd_set.h b/user/include/mlibc/options/posix/include/bits/posix/fd_set.h new file mode 100644 index 0000000..5f4ea26 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/fd_set.h @@ -0,0 +1,10 @@ +#ifndef MLIBC_FD_SET_H +#define MLIBC_FD_SET_H + +#include + +typedef struct { + __mlibc_uint8 fds_bits[128]; +} fd_set; + +#endif /* MLIBC_FD_SET_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/id_t.h b/user/include/mlibc/options/posix/include/bits/posix/id_t.h new file mode 100644 index 0000000..6cba848 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/id_t.h @@ -0,0 +1,6 @@ +#ifndef _MLIBC_ID_T_H +#define _MLIBC_ID_T_H + +typedef unsigned int id_t; + +#endif /* _MLIBC_ID_T_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/in_addr_t.h b/user/include/mlibc/options/posix/include/bits/posix/in_addr_t.h new file mode 100644 index 0000000..014e384 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/in_addr_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_IN_ADDR_H +#define MLIBC_IN_ADDR_H + +#include + +typedef uint32_t in_addr_t; + +#endif /* MLIBC_IN_ADDR_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/in_port_t.h b/user/include/mlibc/options/posix/include/bits/posix/in_port_t.h new file mode 100644 index 0000000..537828a --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/in_port_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_IN_PORT_H +#define MLIBC_IN_PORT_H + +#include + +typedef uint16_t in_port_t; + +#endif /* MLIBC_IN_PORT_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/iovec.h b/user/include/mlibc/options/posix/include/bits/posix/iovec.h new file mode 100644 index 0000000..62a3580 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/iovec.h @@ -0,0 +1,11 @@ +#ifndef MLIBC_IOVEC_H +#define MLIBC_IOVEC_H + +#include + +struct iovec { + void *iov_base; + __mlibc_size iov_len; +}; + +#endif /* MLIBC_IOVEC_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/locale_t.h b/user/include/mlibc/options/posix/include/bits/posix/locale_t.h new file mode 100644 index 0000000..171e298 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/locale_t.h @@ -0,0 +1,14 @@ +#ifndef _LOCALE_T_H +#define _LOCALE_T_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *locale_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _LOCALE_T_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/posix_ctype.h b/user/include/mlibc/options/posix/include/bits/posix/posix_ctype.h new file mode 100644 index 0000000..4e715fb --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/posix_ctype.h @@ -0,0 +1,36 @@ +#ifndef _POSIX_CTYPE_H +#define _POSIX_CTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int isalnum_l(int __c, locale_t __loc); +int isalpha_l(int __c, locale_t __loc); +int isblank_l(int __c, locale_t __loc); +int iscntrl_l(int __c, locale_t __loc); +int isdigit_l(int __c, locale_t __loc); +int isgraph_l(int __c, locale_t __loc); +int islower_l(int __c, locale_t __loc); +int isprint_l(int __c, locale_t __loc); +int ispunct_l(int __c, locale_t __loc); +int isspace_l(int __c, locale_t __loc); +int isupper_l(int __c, locale_t __loc); +int isxdigit_l(int __c, locale_t __loc); + +int isascii_l(int __c, locale_t __loc); + +int tolower_l(int __c, locale_t __loc); +int toupper_l(int __c, locale_t __loc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _POSIX_CTYPE_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/posix_locale.h b/user/include/mlibc/options/posix/include/bits/posix/posix_locale.h new file mode 100644 index 0000000..2ba2c77 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/posix_locale.h @@ -0,0 +1,23 @@ +#ifndef MLIBC_POSIX_LOCALE_H +#define MLIBC_POSIX_LOCALE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +locale_t newlocale(int __category_mask, const char *__locale, locale_t __base); +void freelocale(locale_t __locobj); +locale_t uselocale(locale_t __locobj); +locale_t duplocale(locale_t __locobj); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_LOCALE_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/posix_signal.h b/user/include/mlibc/options/posix/include/bits/posix/posix_signal.h new file mode 100644 index 0000000..2d67a84 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/posix_signal.h @@ -0,0 +1,113 @@ + +#ifndef MLIBC_POSIX_SIGNAL_H +#define MLIBC_POSIX_SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ + +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ + +#if defined(__x86_64__) +/* Start Glibc stuff */ + +struct _libc_fpxreg { + unsigned short int significand[4]; + unsigned short int exponent; + unsigned short int __glibc_reserved1[3]; +}; + +struct _libc_xmmreg { + uint32_t element[4]; +}; + +struct _libc_fpstate { + uint16_t cwd; + int16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t dp; + uint32_t mxcsr; + uint32_t mxcr_mask; + struct _libc_fpxreg _st[8]; + struct _libc_xmmreg _xmm[16]; + uint32_t __glibc_reserved1[24]; +}; + +typedef struct _libc_fpstate *fpregset_t; +/* End Glibc stuff */ + +typedef unsigned long int greg_t; +#endif + +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ + +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ + +#ifndef __MLIBC_ABI_ONLY + +/* functions to block / wait for signals */ +int sigsuspend(const sigset_t *__sigmask); +int sigprocmask(int __how, const sigset_t *__restrict __sigmask, sigset_t *__restrict __oldmask); + +int pthread_sigmask(int __how, const sigset_t *__restrict __sigmask, sigset_t *__restrict __oldmask); +int pthread_kill(pthread_t __thrd, int __sig); + +/* functions to handle signals */ +int sigaction(int __signum, const struct sigaction *__restrict __act, struct sigaction *__restrict __oldact); +int sigpending(sigset_t *__set); + +int siginterrupt(int __sig, int __flag); + +int sigaltstack(const stack_t *__restrict __ss, stack_t *__restrict __oss); + +/* functions to raise signals */ +int kill(pid_t __pid, int __number); +int killpg(int __pgrp, int __sig); + +int sigtimedwait(const sigset_t *__restrict __set, siginfo_t *__restrict __info, const struct timespec *__restrict __timeout); +int sigwait(const sigset_t *__restrict __set, int *__restrict __sig); +int sigwaitinfo(const sigset_t *__restrict __set, siginfo_t *__restrict __info); + +/* Glibc extension */ +#if __MLIBC_GLIBC_OPTION +int sigisemptyset(const sigset_t *__set); +#endif /* __MLIBC_GLIBC_OPTION */ + +int sigqueue(pid_t __pid, int __sig, const union sigval __value); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_SIGNAL_H */ + diff --git a/user/include/mlibc/options/posix/include/bits/posix/posix_stdio.h b/user/include/mlibc/options/posix/include/bits/posix/posix_stdio.h new file mode 100644 index 0000000..360be7c --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/posix_stdio.h @@ -0,0 +1,76 @@ + +#ifndef MLIBC_POSIX_STDIO_H +#define MLIBC_POSIX_STDIO_H + +#include +#include +#include +#include + +/* MISSING: var_list */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define P_tmpdir "/tmp" + +#ifndef __MLIBC_ABI_ONLY + +int fileno(FILE *__file); +FILE *fdopen(int __fd, const char *__mode); + +FILE *fmemopen(void *__restrict __buf, size_t __size, const char *__restrict __mode); +int pclose(FILE *__file); +FILE *popen(const char *__command, const char *__type); +FILE *open_memstream(char **__buf, size_t *__sizeloc); + +int fseeko(FILE *__stream, off_t __offset, int __whence); +int fseeko64(FILE *__stream, off64_t __offset, int __whence); +off_t ftello(FILE *__stream); +off64_t ftello64(FILE *__stream); + +__attribute__((format(__printf__, 2, 3))) int dprintf(int __fd, const char *__format, ...); +__attribute__((format(__printf__, 2, 0))) +int vdprintf(int __fd, const char *__format, __builtin_va_list __args); + +char *fgetln(FILE *__stream, size_t *__size); + +char *tempnam(const char *__dir, const char *__pfx); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define RENAME_EXCHANGE (1 << 1) + +/* GNU extensions */ +typedef ssize_t (cookie_read_function_t)(void *__cookie, char *__buffer, size_t __size); +typedef ssize_t (cookie_write_function_t)(void *__cookie, const char *__buffer, size_t __size); +typedef int (cookie_seek_function_t)(void *__cookie, off_t *, int); +typedef int (cookie_close_function_t)(void *__cookie); + +typedef struct _IO_cookie_io_functions_t { + cookie_read_function_t *read; + cookie_write_function_t *write; + cookie_seek_function_t *seek; + cookie_close_function_t *close; +} cookie_io_functions_t; + +#ifndef __MLIBC_ABI_ONLY + +#if defined(_GNU_SOURCE) + +FILE *fopencookie(void *__restrict __cookie, const char *__restrict __mode, cookie_io_functions_t __io_funcs); + +#endif /* defined(_GNU_SOURCE) */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +/* MISSING: various functions and macros */ + +#endif /* MLIBC_POSIX_STDIO_H */ + + diff --git a/user/include/mlibc/options/posix/include/bits/posix/posix_stdlib.h b/user/include/mlibc/options/posix/include/bits/posix/posix_stdlib.h new file mode 100644 index 0000000..350f857 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/posix_stdlib.h @@ -0,0 +1,77 @@ + +#ifndef MLIBC_POSIX_STDLIB_H +#define MLIBC_POSIX_STDLIB_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +long random(void); +double drand48(void); +double erand48(unsigned short __s[3]); +unsigned short *seed48(unsigned short __s[3]); +void srand48(long int __seed); +long int mrand48(void); +long jrand48(unsigned short __s[3]); +char *initstate(unsigned int __seed, char *__state, size_t __size); +char *setstate(char *__state); +void srandom(unsigned int __seed); + +/* ---------------------------------------------------------------------------- */ +/* Environment. */ +/* ---------------------------------------------------------------------------- */ + +int putenv(char *__string); +int setenv(const char *__name, const char *__value, int __overwrite); +int unsetenv(const char *__name); + +/* ---------------------------------------------------------------------------- */ +/* Path handling. */ +/* ---------------------------------------------------------------------------- */ + +int mkstemp(char *__pattern); +int mkstemps(char *__pattern, int __suffixlen); +int mkostemp(char *__pattern, int __flags); +int mkostemps(char *__pattern, int __suffixlen, int __flags); +char *mkdtemp(char *__path); + +char *realpath(const char *__restrict __path, char *__restrict __out); + +/* ---------------------------------------------------------------------------- */ +/* Pseudoterminals */ +/* ---------------------------------------------------------------------------- */ + +int posix_openpt(int __flags); +int grantpt(int __fd); +int unlockpt(int __fd); +char *ptsname(int __fd); +int ptsname_r(int __fd, char *__buf, size_t __len); + +double strtod_l(const char *__restrict__ __nptr, char ** __restrict__ __endptr, locale_t __loc); +long double strtold_l(const char *__restrict__ __nptr, char ** __restrict__ __endptr, locale_t __loc); +float strtof_l(const char *__restrict __string, char **__restrict __end, locale_t __loc); + +int getsubopt(char **__restrict__ __optionp, char *const *__restrict__ __tokens, char **__restrict__ __valuep); + +/* GNU extension */ +char *secure_getenv(const char *__name); +char *canonicalize_file_name(const char *__name); + +/* BSD extension */ +void *reallocarray(void *__ptr, size_t __count, size_t __size); + +int clearenv(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_STDLIB_H */ + diff --git a/user/include/mlibc/options/posix/include/bits/posix/posix_string.h b/user/include/mlibc/options/posix/include/bits/posix/posix_string.h new file mode 100644 index 0000000..1e2096a --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/posix_string.h @@ -0,0 +1,59 @@ + +#ifndef MLIBC_POSIX_STRING_H +#define MLIBC_POSIX_STRING_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *strdup(const char *__string); +char *strndup(const char *__string, size_t __max_size); +size_t strnlen(const char *__s, size_t __max_size); +char *strtok_r(char *__restrict __s, const char *__restrict __delim, char **__restrict __ptr); +char *strsep(char **__stringp, const char *__delim); +char *strsignal(int __sig); +char *stpcpy(char *__restrict __dest, const char *__restrict __src); +char *stpncpy(char *__restrict __dest, const char *__restrict __src, size_t __n); +void *memccpy(void *__restrict __dest, const void *__restrict __src, int __c, size_t __n); + +int strcoll_l(const char *__s1, const char *__s2, locale_t __locale); + +char *strerror_l(int __errnum, locale_t __locale); + +/* GNU extensions. */ +#if defined(_GNU_SOURCE) +char *strcasestr(const char *__s1, const char *__s2); +#define strdupa(x) ({ \ + const char *__str = (x); \ + size_t __len = strlen(__str) + 1; \ + char *__buf = alloca(__len); \ + (char *) memcpy(__buf, __str, __len); \ +}) +#define strndupa(x, y) ({ \ + const char *__str = (x); \ + size_t __len = strnlen(__str, (y)) + 1; \ + char *__buf = alloca(__len); \ + __buf[__len - 1] = '\0'; \ + (char *) memcpy(__buf, __str, __len - 1); \ +}) +void *memrchr(const void *__m, int __c, size_t __n); +#endif /* defined(_GNU_SOURCE) */ + +/* BSD extensions */ +size_t strlcpy(char *__d, const char *__s, size_t __n); +size_t strlcat(char *__d, const char *__s, size_t __n); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_STRING_H */ + diff --git a/user/include/mlibc/options/posix/include/bits/posix/posix_time.h b/user/include/mlibc/options/posix/include/bits/posix/posix_time.h new file mode 100644 index 0000000..71d2cd8 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/posix_time.h @@ -0,0 +1,43 @@ +#ifndef MLIBC_POSIX_TIME_H +#define MLIBC_POSIX_TIME_H + +#include +#include +#include +#include +#include + +#define TIMER_ABSTIME 1 + +#ifdef __cplusplus +extern "C" { +#endif + +struct itimerspec { + struct timespec it_interval; + struct timespec it_value; +}; + +#ifndef __MLIBC_ABI_ONLY + +int timer_getoverrun(timer_t __timerid); + +int utimes(const char *__filename, const struct timeval __tv[2]); + +/* Not standardized, Linux and BSDs have it */ +int futimes(int __fd, const struct timeval __tv[2]); +int lutimes(const char *__filename, const struct timeval __tv[2]); + +int timer_create(clockid_t __clockid, struct sigevent *__restrict __sevp, timer_t *__restrict __timerid); +int timer_settime(timer_t __timerid, int __flags, const struct itimerspec *__restrict __new_value, + struct itimerspec *__restrict __old_value); +int timer_gettime(timer_t __timerid, struct itimerspec *__curr_value); +int timer_delete(timer_t __timerid); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_POSIX_TIME_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/posix_wctype.h b/user/include/mlibc/options/posix/include/bits/posix/posix_wctype.h new file mode 100644 index 0000000..3c4bd7a --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/posix_wctype.h @@ -0,0 +1,43 @@ +#ifndef _POSIX_WCTYPE_H +#define _POSIX_WCTYPE_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int iswalnum_l(wint_t __wc, locale_t __loc); +int iswblank_l(wint_t __wc, locale_t __loc); +int iswcntrl_l(wint_t __wc, locale_t __loc); +int iswdigit_l(wint_t __wc, locale_t __loc); +int iswgraph_l(wint_t __wc, locale_t __loc); +int iswlower_l(wint_t __wc, locale_t __loc); +int iswprint_l(wint_t __wc, locale_t __loc); +int iswpunct_l(wint_t __wc, locale_t __loc); +int iswspace_l(wint_t __wc, locale_t __loc); +int iswupper_l(wint_t __wc, locale_t __loc); +int iswxdigit_l(wint_t __wc, locale_t __loc); +int iswalpha_l(wint_t __wc, locale_t __loc); + +wctype_t wctype_l(const char *__string, locale_t __loc); +int iswctype_l(wint_t __wc, wctype_t __type, locale_t __loc); + +wint_t towlower_l(wint_t __wc, locale_t __loc); +wint_t towupper_l(wint_t __wc, locale_t __loc); + +wctrans_t wctrans_l(const char *__string, locale_t __loc); +wint_t towctrans_l(wint_t __wc, wctrans_t __trans, locale_t __loc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _POSIX_WCTYPE_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/pthread_t.h b/user/include/mlibc/options/posix/include/bits/posix/pthread_t.h new file mode 100644 index 0000000..f5e6b70 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/pthread_t.h @@ -0,0 +1,8 @@ +#ifndef _MLIBC_BITS_PTHREAD_T_HPP +#define _MLIBC_BITS_PTHREAD_T_HPP + +#include + +typedef struct __mlibc_thread_data *pthread_t; + +#endif /* _MLIBC_BITS_PTHREAD_T_HPP */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/stat.h b/user/include/mlibc/options/posix/include/bits/posix/stat.h new file mode 100644 index 0000000..f08b760 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/stat.h @@ -0,0 +1,24 @@ +#ifndef MLIBC_STAT_H +#define MLIBC_STAT_H + +#include + +/* Used by utimensat and friends */ +#define UTIME_NOW ((1l << 30) - 1l) +#define UTIME_OMIT ((1l << 30) - 2l) + +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +/* POSIX compatibility macros */ +#define st_atime st_atim.tv_sec +#define st_mtime st_mtim.tv_sec +#define st_ctime st_ctim.tv_sec + +#endif /* MLIBC_STAT_H */ + diff --git a/user/include/mlibc/options/posix/include/bits/posix/timer_t.h b/user/include/mlibc/options/posix/include/bits/posix/timer_t.h new file mode 100644 index 0000000..b965f37 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/timer_t.h @@ -0,0 +1,6 @@ +#ifndef _MLIBC_TIMER_T_H +#define _MLIBC_TIMER_T_H + +typedef void * timer_t; + +#endif /* _MLIBC_TIMER_T_H */ diff --git a/user/include/mlibc/options/posix/include/bits/posix/timeval.h b/user/include/mlibc/options/posix/include/bits/posix/timeval.h new file mode 100644 index 0000000..22670a2 --- /dev/null +++ b/user/include/mlibc/options/posix/include/bits/posix/timeval.h @@ -0,0 +1,12 @@ +#ifndef MLIBC_TIMEVAL_H +#define MLIBC_TIMEVAL_H + +#include +#include + +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; + +#endif /* MLIBC_TIMEVAL_H */ diff --git a/user/include/mlibc/options/posix/include/byteswap.h b/user/include/mlibc/options/posix/include/byteswap.h new file mode 100644 index 0000000..29b2838 --- /dev/null +++ b/user/include/mlibc/options/posix/include/byteswap.h @@ -0,0 +1,23 @@ + +#ifndef _BYTESWAP_H +#define _BYTESWAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define bswap_16(x) __builtin_bswap16(x) +#define bswap_32(x) __builtin_bswap32(x) +#define bswap_64(x) __builtin_bswap64(x) + +/* Some programs like eudev call these functions instead */ +#define __bswap_16(x) __builtin_bswap16(x) +#define __bswap_32(x) __builtin_bswap32(x) +#define __bswap_64(x) __builtin_bswap64(x) + +#ifdef __cplusplus +} +#endif + +#endif /* _BYTESWAP_H */ + diff --git a/user/include/mlibc/options/posix/include/dirent.h b/user/include/mlibc/options/posix/include/dirent.h new file mode 100644 index 0000000..95d609a --- /dev/null +++ b/user/include/mlibc/options/posix/include/dirent.h @@ -0,0 +1,77 @@ + +#ifndef _DIRENT_H +#define _DIRENT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +#define __MLIBC_DIRENT_BODY ino_t d_ino; \ + off_t d_off; \ + unsigned short d_reclen; \ + unsigned char d_type; \ + char d_name[1024]; + +struct dirent { + __MLIBC_DIRENT_BODY +}; + +struct dirent64 { + __MLIBC_DIRENT_BODY +}; + +#define d_fileno d_ino + +#undef __MLIBC_DIRENT_BODY + +#define IFTODT(mode) (((mode) & 0170000) >> 12) + +struct __mlibc_dir_struct { + int __handle; + __mlibc_size __ent_next; + __mlibc_size __ent_limit; + char __ent_buffer[2048]; + struct dirent __current; +}; + +typedef struct __mlibc_dir_struct DIR; + +#ifndef __MLIBC_ABI_ONLY + +int alphasort(const struct dirent **__a, const struct dirent **__b); +int closedir(DIR *__dirp); +int dirfd(DIR *__dirp); +DIR *fdopendir(int __fd); +DIR *opendir(const char *__pathname); +struct dirent *readdir(DIR *__dirp); +struct dirent64 *readdir64(DIR *__dirp); +int readdir_r(DIR *__restrict __dirp, struct dirent *__restrict __entry, struct dirent **__restrict __res); +void rewinddir(DIR *__dirp); +int scandir(const char *__pathname, struct dirent ***__res, int (*__select)(const struct dirent *__entry), + int (*__compare)(const struct dirent **__a, const struct dirent **__b)); +void seekdir(DIR *__dirp, long __loc); +long telldir(DIR *__dirp); +int versionsort(const struct dirent **__a, const struct dirent **__b); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DIRENT_H */ + diff --git a/user/include/mlibc/options/posix/include/dlfcn.h b/user/include/mlibc/options/posix/include/dlfcn.h new file mode 100644 index 0000000..2abb1f1 --- /dev/null +++ b/user/include/mlibc/options/posix/include/dlfcn.h @@ -0,0 +1,96 @@ + +#ifndef _DLFCN_H +#define _DLFCN_H + +#include + +#define RTLD_LOCAL 0 +#define RTLD_LAZY 1 +#define RTLD_NOW 2 +#define RTLD_NOLOAD 4 +#define RTLD_DEEPBIND 8 +#define RTLD_GLOBAL 256 +#define RTLD_NODELETE 4096 + +#define RTLD_NEXT ((void *)-1) +#define RTLD_DEFAULT ((void *)0) + +#define RTLD_DL_SYMENT 1 +#define RTLD_DL_LINKMAP 2 + +#define RTLD_DI_LINKMAP 2 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int dlclose(void *__handle); +char *dlerror(void); +void *dlopen(const char *__name, int __flags); +void *dlsym(void *__restrict __handle, const char *__restrict __name); +void *dlvsym(void *__restrict __handle, const char *__restrict __name, const char *__restrict __version); + +#endif /* !__MLIBC_ABI_ONLY */ + +#if defined(_GNU_SOURCE) && __MLIBC_GLIBC_OPTION + +/*gnu extension */ +typedef struct { + const char *dli_fname; + void *dli_fbase; + const char *dli_sname; + void *dli_saddr; +} Dl_info; + +#if defined(__i386__) +#define DLFO_STRUCT_HAS_EH_DBASE 1 +#define DLFO_STRUCT_HAS_EH_COUNT 0 +#define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME +#elif defined(__arm__) +#define DLFO_STRUCT_HAS_EH_DBASE 0 +#define DLFO_STRUCT_HAS_EH_COUNT 1 +#define DLFO_EH_SEGMENT_TYPE PT_ARM_EXIDX +#else +#define DLFO_STRUCT_HAS_EH_DBASE 0 +#define DLFO_STRUCT_HAS_EH_COUNT 0 +#define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME +#endif + +struct dl_find_object { + unsigned long long dlfo_flags; + void *dlfo_map_start; + void *dlfo_map_end; + struct link_map *dlfo_link_map; + void *dlfo_eh_frame; +#if DLFO_STRUCT_HAS_EH_DBASE + void *dlfo_eh_dbase; +#if __INTPTR_WIDTH__ == 32 + unsigned int __unused0; +#endif +#endif +#if DLFO_STRUCT_HAS_EH_COUNT + int dlfo_eh_count; + unsigned int __unused1; +#endif + unsigned long long __dlfo_unused[7]; +}; + +#ifndef __MLIBC_ABI_ONLY + +int dladdr(const void *__ptr, Dl_info *__out); +int dladdr1(const void *__ptr, Dl_info *__out, void **__extra, int __flags); +int dlinfo(void *__restrict __handle, int __request, void *__restrict __info); +int _dl_find_object(void *__address, struct dl_find_object *__result); + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif /* defined(_GNU_SOURCE) && __MLIBC_GLIBC_OPTION */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DLFCN_H */ + diff --git a/user/include/mlibc/options/posix/include/fcntl.h b/user/include/mlibc/options/posix/include/fcntl.h new file mode 100644 index 0000000..49c42e5 --- /dev/null +++ b/user/include/mlibc/options/posix/include/fcntl.h @@ -0,0 +1,85 @@ + +#ifndef _FCNTL_H +#define _FCNTL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define O_NDELAY O_NONBLOCK + +/* WARNING: keep `flock` and `flock64` in sync or bad things will happen! */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +#ifndef __MLIBC_ABI_ONLY + +int creat(const char *__path, mode_t __mode); +int fallocate(int __fd, int __mode, off_t __offset, off_t __len); +int fcntl(int __fd, int __command, ...); +int open(const char *__path, int __flags, ...); +int open64(const char *__path, int __flags, ...); +int openat(int __dirfd, const char *__path, int __flags, ...); +int posix_fadvise(int __fd, off_t __offset, off_t __size, int __advice); +int posix_fallocate(int __fd, off_t __offset, off_t __size); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* This is a linux extension */ +#ifdef _GNU_SOURCE +struct file_handle { + unsigned int handle_bytes; + int handle_type; + __extension__ unsigned char f_handle[0]; +}; +#endif + +#ifndef __MLIBC_ABI_ONLY + +#ifdef _GNU_SOURCE +int name_to_handle_at(int __dirfd, const char *__path, struct file_handle *__handle, int *__mount_id, int __flags); +int open_by_handle_at(int __dirfd, struct file_handle *__handle, int __flags); +#endif + +ssize_t splice(int __fd_in, off_t *__off_in, int __fd_out, off_t *__off_out, size_t __len, unsigned int __flags); +ssize_t vmsplice(int __fd, const struct iovec *__iov, size_t __nr_segs, unsigned int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define SPLICE_F_MOVE 1 +#define SPLICE_F_NONBLOCK 2 +#define SPLICE_F_MORE 4 +#define SPLICE_F_GIFT 8 + +#define FALLOC_FL_KEEP_SIZE 1 +#define FALLOC_FL_PUNCH_HOLE 2 + +#ifdef __cplusplus +} +#endif + +#endif /* _FCNTL_H */ + diff --git a/user/include/mlibc/options/posix/include/fnmatch.h b/user/include/mlibc/options/posix/include/fnmatch.h new file mode 100644 index 0000000..5c5dda0 --- /dev/null +++ b/user/include/mlibc/options/posix/include/fnmatch.h @@ -0,0 +1,33 @@ + +#ifndef _FNMATCH_H +#define _FNMATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* POSIX-defined fnmatch() flags. */ +#define FNM_PATHNAME 0x1 +#define FNM_NOESCAPE 0x2 +#define FNM_PERIOD 0x4 + +/* GNU extensions for fnmatch() flags. */ +#define FNM_LEADING_DIR 0x8 +#define FNM_CASEFOLD 0x10 +#define FNM_EXTMATCH 0x20 + +/* fnmatch() return values. */ +#define FNM_NOMATCH 1 + +#ifndef __MLIBC_ABI_ONLY + +int fnmatch(const char *__pattern, const char *__string, int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FNMATCH_H */ + diff --git a/user/include/mlibc/options/posix/include/ftw.h b/user/include/mlibc/options/posix/include/ftw.h new file mode 100644 index 0000000..3240ed3 --- /dev/null +++ b/user/include/mlibc/options/posix/include/ftw.h @@ -0,0 +1,45 @@ + +#ifndef _FTW_H +#define _FTW_H + +#include + +#define FTW_F 1 +#define FTW_D 2 +#define FTW_DNR 3 +#define FTW_DP 4 +#define FTW_NS 5 +#define FTW_SL 6 +#define FTW_SLN 7 + +#define FTW_PHYS 1 +#define FTW_MOUNT 2 +#define FTW_DEPTH 4 +#define FTW_CHDIR 8 + +#define FTW_CONTINUE 0 + +#ifdef __cplusplus +extern "C" { +#endif + +struct FTW { + int base; + int level; +}; + +#ifndef __MLIBC_ABI_ONLY + +int ftw(const char *__dirpath, int (*__fn)(const char *__fpath, const struct stat *__sb, int __typeflag), + int __nopenfd); +int nftw(const char *__dirpath, int (*__fn)(const char *__fpath, const struct stat *__sb, int __typeflag, + struct FTW *__ftwbuf), int __nopenfd, int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FTW_H */ + diff --git a/user/include/mlibc/options/posix/include/glob.h b/user/include/mlibc/options/posix/include/glob.h new file mode 100644 index 0000000..57e3219 --- /dev/null +++ b/user/include/mlibc/options/posix/include/glob.h @@ -0,0 +1,59 @@ + +#ifndef _GLOB_H +#define _GLOB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define GLOB_APPEND 0x01 +#define GLOB_DOOFFS 0x02 +#define GLOB_ERR 0x04 +#define GLOB_MARK 0x08 +#define GLOB_NOCHECK 0x10 +#define GLOB_NOESCAPE 0x20 +#define GLOB_NOSORT 0x40 +#define GLOB_PERIOD 0x80 +#define GLOB_TILDE 0x100 +#define GLOB_TILDE_CHECK 0x200 +#define GLOB_BRACE 0x400 +#define GLOB_NOMAGIC 0x800 +#define GLOB_ALTDIRFUNC 0x1000 +#define GLOB_ONLYDIR 0x2000 +#define GLOB_MAGCHAR 0x4000 + +#define GLOB_ABORTED 1 +#define GLOB_NOMATCH 2 +#define GLOB_NOSPACE 3 +#define GLOB_NOSYS 4 + +struct stat; +typedef struct glob_t { + size_t gl_pathc; + char **gl_pathv; + size_t gl_offs; + int gl_flags; + void (*gl_closedir) (void *); + struct dirent *(*gl_readdir) (void *); + void *(*gl_opendir) (const char *); + int (*gl_lstat) (const char *__restrict, struct stat *__restrict); + int (*gl_stat) (const char *__restrict, struct stat *__restrict); +} glob_t; + +#ifndef __MLIBC_ABI_ONLY + +int glob(const char *__restrict __pattern, int __flags, + int(*__errfunc)(const char *__epath, int __errnum), struct glob_t *__restrict __pglob); +void globfree(struct glob_t *__pglog); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GLOB_H */ + + diff --git a/user/include/mlibc/options/posix/include/grp.h b/user/include/mlibc/options/posix/include/grp.h new file mode 100644 index 0000000..6b16d71 --- /dev/null +++ b/user/include/mlibc/options/posix/include/grp.h @@ -0,0 +1,43 @@ +#ifndef _GRP_H +#define _GRP_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct group { + char *gr_name; + char *gr_passwd; + gid_t gr_gid; + char **gr_mem; +}; + +#ifndef __MLIBC_ABI_ONLY + +void endgrent(void); +struct group *getgrent(void); +struct group *getgrgid(gid_t __gid); +int getgrgid_r(gid_t __gid, struct group *__grp, char *__buf, size_t __buflen, struct group **__res); +struct group *getgrnam(const char *__name); +int getgrnam_r(const char *__name, struct group *__grp, char *__buf, size_t __buflen, struct group **__res); +void setgrent(void); +int putgrent(const struct group *__grp, FILE *__stream); +struct group *fgetgrent(FILE *__stream); + +int setgroups(size_t __size, const gid_t *__list); +int initgroups(const char *__user, gid_t __group); + +/* Non standard extension */ +int getgrouplist(const char *__user, gid_t __group, gid_t *__groups, int *__ngroups); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GRP_H */ diff --git a/user/include/mlibc/options/posix/include/langinfo.h b/user/include/mlibc/options/posix/include/langinfo.h new file mode 100644 index 0000000..2a5bf0f --- /dev/null +++ b/user/include/mlibc/options/posix/include/langinfo.h @@ -0,0 +1,24 @@ + +#ifndef _LANGINFO_H +#define _LANGINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +char *nl_langinfo(nl_item __item); +char *nl_langinfo_l(nl_item __item, locale_t __loc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LANGINFO_H */ + diff --git a/user/include/mlibc/options/posix/include/libgen.h b/user/include/mlibc/options/posix/include/libgen.h new file mode 100644 index 0000000..69ece1d --- /dev/null +++ b/user/include/mlibc/options/posix/include/libgen.h @@ -0,0 +1,28 @@ + +#ifndef _LIBGEN_H +#define _LIBGEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(basename) && defined(_GNU_SOURCE) +/* see: ./options/ansi/include/string.h, search for __mlibc_gnu_basename */ +# undef basename +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *basename(char *__path); +#define basename basename +char *dirname(char *__path); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBGEN_H */ + + diff --git a/user/include/mlibc/options/posix/include/mlibc/lookup.hpp b/user/include/mlibc/options/posix/include/mlibc/lookup.hpp new file mode 100644 index 0000000..a64805a --- /dev/null +++ b/user/include/mlibc/options/posix/include/mlibc/lookup.hpp @@ -0,0 +1,58 @@ +#ifndef _MLIBC_LOOKUP +#define _MLIBC_LOOKUP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +struct dns_addr_buf { + dns_addr_buf() + : name(getAllocator()) {} + frg::string name; + int family; + uint8_t addr[16]; +}; + +struct lookup_result { + lookup_result() + : buf(getAllocator()), aliases(getAllocator()) {} + frg::vector buf; + frg::vector, MemoryAllocator> aliases; +}; + +struct dns_header { + uint16_t identification; + uint16_t flags; + uint16_t no_q; + uint16_t no_ans; + uint16_t no_auths; + uint16_t no_additional; +}; + +struct ai_buf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; +}; + +int lookup_name_dns(struct lookup_result &buf, const char *name, + frg::string &canon_name, int family); +int lookup_addr_dns(frg::span name, frg::array &addr, int family); +int lookup_name_hosts(struct lookup_result &buf, const char *name, + frg::string &canon_name, int family); +int lookup_addr_hosts(frg::span name, frg::array &addr, int family); +int lookup_name_null(struct lookup_result &buf, int flags, int family); +int lookup_name_ip(struct lookup_result &buf, const char *name, int family); + +} // namespace mlibc + +#endif // _MLIBC_LOOKUP diff --git a/user/include/mlibc/options/posix/include/mlibc/posix-file-io.hpp b/user/include/mlibc/options/posix/include/mlibc/posix-file-io.hpp new file mode 100644 index 0000000..63d6037 --- /dev/null +++ b/user/include/mlibc/options/posix/include/mlibc/posix-file-io.hpp @@ -0,0 +1,102 @@ +#ifndef MLIBC_POSIX_FILE_IO_HPP +#define MLIBC_POSIX_FILE_IO_HPP + +#include +#include +#include +#include + +namespace mlibc { + +struct mem_file : abstract_file { + mem_file(int flags, void (*do_dispose)(abstract_file *) = nullptr) : abstract_file{do_dispose}, _flags{flags} { }; + + int reopen(const char *path, const char *mode) override; +protected: + int determine_type(stream_type *type) override; + int determine_bufmode(buffer_mode *mode) override; + + virtual frg::span _buffer() = 0; + virtual size_t _buffer_size() const = 0; + + off_t _pos = 0; + int _flags = 0; + // maintains the size of buffer contents as required by POSIX + off_t _max_size = 0; +}; + +struct memstream_mem_file final : public mem_file { + memstream_mem_file(char **ptr, size_t *sizeloc, int flags, void (*do_dispose)(abstract_file *) = nullptr); + + int close() override; + + int io_read(char *buffer, size_t max_size, size_t *actual_size) override; + int io_write(const char *buffer, size_t max_size, size_t *actual_size) override; + int io_seek(off_t offset, int whence, off_t *new_offset) override; + + frg::span _buffer() override { + return {_buf.data(), _buffer_size()}; + } + + size_t _buffer_size() const override { + return _buf.size(); + } + +private: + void _update_ptrs(); + + // Where to write back buffer and size on flush and close. + char **_bufloc; + size_t *_sizeloc; + + frg::vector _buf = {getAllocator()}; +}; + +struct fmemopen_mem_file final : public mem_file { + fmemopen_mem_file(void *in_buf, size_t size, int flags, void (*do_dispose)(abstract_file *) = nullptr); + + int close() override; + + int io_read(char *buffer, size_t max_size, size_t *actual_size) override; + int io_write(const char *buffer, size_t max_size, size_t *actual_size) override; + int io_seek(off_t offset, int whence, off_t *new_offset) override; + + frg::span _buffer() override { + return {reinterpret_cast(_inBuffer), _buffer_size()}; + } + + size_t _buffer_size() const override { + return _inBufferSize; + } + +private: + void *_inBuffer; + size_t _inBufferSize; + + bool _needsDeallocation = false; +}; + +struct cookie_file : abstract_file { + cookie_file(void *cookie, int flags, cookie_io_functions_t funcs, void (*do_dispose)(abstract_file *) = nullptr) + : abstract_file{do_dispose}, _cookie{cookie}, _flags{flags}, _funcs{funcs} { } + + int close() override; + int reopen(const char *path, const char *mode) override; +protected: + int determine_type(stream_type *type) override; + int determine_bufmode(buffer_mode *mode) override; + + int io_read(char *buffer, size_t max_size, size_t *actual_size) override; + int io_write(const char *buffer, size_t max_size, size_t *actual_size) override; + int io_seek(off_t offset, int whence, off_t *new_offset) override; + +private: + void *_cookie; + + [[maybe_unused]] int _flags; + cookie_io_functions_t _funcs; +}; + +} // namespace mlibc + +#endif // MLIBC_POSIX_FILE_IO_HPP diff --git a/user/include/mlibc/options/posix/include/mlibc/posix-sysdeps.hpp b/user/include/mlibc/options/posix/include/mlibc/posix-sysdeps.hpp new file mode 100644 index 0000000..f96b153 --- /dev/null +++ b/user/include/mlibc/options/posix/include/mlibc/posix-sysdeps.hpp @@ -0,0 +1,263 @@ +#ifndef MLIBC_POSIX_SYSDEPS +#define MLIBC_POSIX_SYSDEPS + +#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 + +namespace [[gnu::visibility("hidden")]] mlibc { + +void sys_libc_log(const char *message); +[[noreturn]] void sys_libc_panic(); + +[[noreturn]] void sys_exit(int status); +[[noreturn, gnu::weak]] void sys_thread_exit(); + + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +[[gnu::weak]] int sys_flock(int fd, int options); + +[[gnu::weak]] int sys_open_dir(const char *path, int *handle); +[[gnu::weak]] int sys_read_entries(int handle, void *buffer, size_t max_size, + size_t *bytes_read); + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); +[[gnu::weak]] int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read); + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written); +[[gnu::weak]] int sys_writev(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written); +[[gnu::weak]] int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read); +[[gnu::weak]] int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_read); + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset); +int sys_close(int fd); + +[[gnu::weak]] int sys_access(const char *path, int mode); +[[gnu::weak]] int sys_faccessat(int dirfd, const char *pathname, int mode, int flags); +[[gnu::weak]] int sys_dup(int fd, int flags, int *newfd); +[[gnu::weak]] int sys_dup2(int fd, int flags, int newfd); +// In contrast to the isatty() library function, the sysdep function uses return value +// zero (and not one) to indicate that the file is a terminal. +[[gnu::weak]] int sys_isatty(int fd); +[[gnu::weak]] int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf); +[[gnu::weak]] int sys_statvfs(const char *path, struct statvfs *out); +[[gnu::weak]] int sys_fstatvfs(int fd, struct statvfs *out); +[[gnu::weak]] int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length); +[[gnu::weak]] int sys_readlinkat(int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length); +[[gnu::weak]] int sys_rmdir(const char *path); +[[gnu::weak]] int sys_ftruncate(int fd, size_t size); +[[gnu::weak]] int sys_fallocate(int fd, off_t offset, size_t size); +[[gnu::weak]] int sys_unlinkat(int fd, const char *path, int flags); +[[gnu::weak]] int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd); +[[gnu::weak]] int sys_socket(int family, int type, int protocol, int *fd); +[[gnu::weak]] int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length); +[[gnu::weak]] ssize_t sys_sendto(int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length); +[[gnu::weak]] int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length); +[[gnu::weak]] ssize_t sys_recvfrom(int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length); +[[gnu::weak]] int sys_listen(int fd, int backlog); +[[gnu::weak]] gid_t sys_getgid(); +[[gnu::weak]] gid_t sys_getegid(); +[[gnu::weak]] uid_t sys_getuid(); +[[gnu::weak]] uid_t sys_geteuid(); +[[gnu::weak]] pid_t sys_getpid(); +[[gnu::weak]] pid_t sys_gettid(); +[[gnu::weak]] pid_t sys_getppid(); +[[gnu::weak]] int sys_getpgid(pid_t pid, pid_t *pgid); +[[gnu::weak]] int sys_getsid(pid_t pid, pid_t *sid); +[[gnu::weak]] int sys_setpgid(pid_t pid, pid_t pgid); +[[gnu::weak]] int sys_setuid(uid_t uid); +[[gnu::weak]] int sys_seteuid(uid_t euid); +[[gnu::weak]] int sys_setgid(gid_t gid); +[[gnu::weak]] int sys_setegid(gid_t egid); +[[gnu::weak]] int sys_getgroups(size_t size, gid_t *list, int *ret); +[[gnu::weak]] void sys_yield(); +[[gnu::weak]] int sys_sleep(time_t *secs, long *nanos); +[[gnu::weak]] int sys_fork(pid_t *child); +[[gnu::weak]] int sys_execve(const char *path, char *const argv[], char *const envp[]); +[[gnu::weak]] int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events); +[[gnu::weak]] int sys_getrusage(int scope, struct rusage *usage); +[[gnu::weak]] int sys_getrlimit(int resource, struct rlimit *limit); +[[gnu::weak]] int sys_setrlimit(int resource, const struct rlimit *limit); +[[gnu::weak]] int sys_getpriority(int which, id_t who, int *value); +[[gnu::weak]] int sys_setpriority(int which, id_t who, int prio); +[[gnu::weak]] int sys_getschedparam(void *tcb, int *policy, struct sched_param *param); +[[gnu::weak]] int sys_setschedparam(void *tcb, int policy, const struct sched_param *param); +[[gnu::weak]] int sys_getscheduler(pid_t pid, int *policy); +[[gnu::weak]] int sys_getparam(pid_t pid, struct sched_param *param); +[[gnu::weak]] int sys_setparam(pid_t pid, const struct sched_param *param); +[[gnu::weak]] int sys_get_max_priority(int policy, int *out); +[[gnu::weak]] int sys_get_min_priority(int policy, int *out); +[[gnu::weak]] int sys_getcwd(char *buffer, size_t size); +[[gnu::weak]] int sys_chdir(const char *path); +[[gnu::weak]] int sys_fchdir(int fd); +[[gnu::weak]] int sys_chroot(const char *path); +[[gnu::weak]] int sys_mkdir(const char *path, mode_t mode); +[[gnu::weak]] int sys_mkdirat(int dirfd, const char *path, mode_t mode); +[[gnu::weak]] int sys_link(const char *old_path, const char *new_path); +[[gnu::weak]] int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags); +[[gnu::weak]] int sys_symlink(const char *target_path, const char *link_path); +[[gnu::weak]] int sys_symlinkat(const char *target_path, int dirfd, const char *link_path); +[[gnu::weak]] int sys_rename(const char *path, const char *new_path); +[[gnu::weak]] int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path); +[[gnu::weak]] int sys_fcntl(int fd, int request, va_list args, int *result); +[[gnu::weak]] int sys_ttyname(int fd, char *buf, size_t size); +[[gnu::weak]] int sys_fadvise(int fd, off_t offset, off_t length, int advice); +[[gnu::weak]] void sys_sync(); +[[gnu::weak]] int sys_fsync(int fd); +[[gnu::weak]] int sys_fdatasync(int fd); +[[gnu::weak]] int sys_chmod(const char *pathname, mode_t mode); +[[gnu::weak]] int sys_fchmod(int fd, mode_t mode); +[[gnu::weak]] int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags); +[[gnu::weak]] int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags); +[[gnu::weak]] int sys_mlock(const void *addr, size_t length); +[[gnu::weak]] int sys_munlock(const void *addr, size_t length); +[[gnu::weak]] int sys_mlockall(int flags); +[[gnu::weak]] int sys_mlock(const void *addr, size_t len); +[[gnu::weak]] int sys_munlockall(void); +[[gnu::weak]] int sys_mincore(void *addr, size_t length, unsigned char *vec); + +// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window); + +[[gnu::weak]] int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window); +[[gnu::weak]] int sys_vm_protect(void *pointer, size_t size, int prot); + +int sys_vm_unmap(void *pointer, size_t size); + +[[gnu::weak]] int sys_setsid(pid_t *sid); +[[gnu::weak]] int sys_tcgetattr(int fd, struct termios *attr); +[[gnu::weak]] int sys_tcsetattr(int, int, const struct termios *attr); +[[gnu::weak]] int sys_tcflow(int, int); +[[gnu::weak]] int sys_tcflush(int fd, int queue); +[[gnu::weak]] int sys_tcdrain(int); +[[gnu::weak]] int sys_pipe(int *fds, int flags); +[[gnu::weak]] int sys_socketpair(int domain, int type_and_flags, int proto, int *fds); +[[gnu::weak]] int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events); +[[gnu::weak]] int sys_ioctl(int fd, unsigned long request, void *arg, int *result); +[[gnu::weak]] int sys_getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size); +[[gnu::weak]] int sys_setsockopt(int fd, int layer, int number, + const void *buffer, socklen_t size); +[[gnu::weak]] int sys_shutdown(int sockfd, int how); +[[gnu::weak]] int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve); +[[gnu::weak]] int sys_thread_sigmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve); +[[gnu::weak]] int sys_sigaction(int, const struct sigaction *__restrict, + struct sigaction *__restrict); +// NOTE: POSIX says that behavior of timeout = nullptr is unspecified. We treat this case +// as an infinite timeout, making sigtimedwait(..., nullptr) equivalent to sigwaitinfo(...) +[[gnu::weak]] int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal); +[[gnu::weak]] int sys_kill(int, int); +[[gnu::weak]] int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags); +[[gnu::weak]] int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length); +[[gnu::weak]] int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length); +[[gnu::weak]] int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length); +[[gnu::weak]] int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length); +[[gnu::weak]] int sys_gethostname(char *buffer, size_t bufsize); +[[gnu::weak]] int sys_sethostname(const char *buffer, size_t bufsize); +[[gnu::weak]] int sys_mkfifoat(int dirfd, const char *path, mode_t mode); +[[gnu::weak]] int sys_getentropy(void *buffer, size_t length); +[[gnu::weak]] int sys_mknodat(int dirfd, const char *path, int mode, int dev); +[[gnu::weak]] int sys_umask(mode_t mode, mode_t *old); + +[[gnu::weak]] int sys_before_cancellable_syscall(ucontext_t *uctx); +[[gnu::weak]] int sys_tgkill(int tgid, int tid, int sig); + +[[gnu::weak]] int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags); +[[gnu::weak]] int sys_sigaltstack(const stack_t *ss, stack_t *oss); +[[gnu::weak]] int sys_sigsuspend(const sigset_t *set); +[[gnu::weak]] int sys_sigpending(sigset_t *set); +[[gnu::weak]] int sys_setgroups(size_t size, const gid_t *list); +[[gnu::weak]] int sys_memfd_create(const char *name, int flags, int *fd); +[[gnu::weak]] int sys_madvise(void *addr, size_t length, int advice); +[[gnu::weak]] int sys_posix_madvise(void *addr, size_t length, int advice); +[[gnu::weak]] int sys_msync(void *addr, size_t length, int flags); + +[[gnu::weak]] int sys_getitimer(int which, struct itimerval *curr_value); +[[gnu::weak]] int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value); +[[gnu::weak]] int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res); +[[gnu::weak]] int sys_timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old); +[[gnu::weak]] int sys_timer_gettime(timer_t t, struct itimerspec *val); +[[gnu::weak]] int sys_timer_delete(timer_t t); +[[gnu::weak]] int sys_times(struct tms *tms, clock_t *out); +[[gnu::weak]] int sys_uname(struct utsname *buf); +[[gnu::weak]] int sys_pause(); + +[[gnu::weak]] int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); +[[gnu::weak]] int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); +[[gnu::weak]] int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +[[gnu::weak]] int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +[[gnu::weak]] int sys_setreuid(uid_t ruid, uid_t euid); +[[gnu::weak]] int sys_setregid(gid_t rgid, gid_t egid); + +[[gnu::weak]] int sys_if_indextoname(unsigned int index, char *name); +[[gnu::weak]] int sys_if_nametoindex(const char *name, unsigned int *ret); + +[[gnu::weak]] int sys_ptsname(int fd, char *buffer, size_t length); +[[gnu::weak]] int sys_unlockpt(int fd); + +[[gnu::weak]] int sys_thread_setname(void *tcb, const char *name); +[[gnu::weak]] int sys_thread_getname(void *tcb, char *name, size_t size); + +[[gnu::weak]] int sys_sysconf(int num, long *ret); + +[[gnu::weak]] int sys_semget(key_t key, int n, int fl, int *id); +[[gnu::weak]] int sys_semctl(int semid, int semnum, int cmd, void *semun, int *ret); + +[[gnu::weak]] int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); +[[gnu::weak]] int sys_getthreadaffinity(pid_t tid, size_t cpusetsize, cpu_set_t *mask); + +[[gnu::weak]] int sys_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask); +[[gnu::weak]] int sys_setthreadaffinity(pid_t tid, size_t cpusetsize, const cpu_set_t *mask); + +[[gnu::weak]] int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options); + +[[gnu::weak]] int sys_name_to_handle_at(int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags); +[[gnu::weak]] int sys_splice(int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags, ssize_t *out); + +[[gnu::weak]] int sys_shmat(void **seg_start, int shmid, const void *shmaddr, int shmflg); +[[gnu::weak]] int sys_shmctl(int *idx, int shmid, int cmd, struct shmid_ds *buf); +[[gnu::weak]] int sys_shmdt(const void *shmaddr); +[[gnu::weak]] int sys_shmget(int *shm_id, key_t key, size_t size, int shmflg); + +[[gnu::weak]] int sys_inet_configured(bool *ipv4, bool *ipv6); + +[[gnu::weak]] int sys_nice(int nice, int *new_nice); + +[[gnu::weak]] int sys_openpt(int oflags, int *fd); + +} //namespace mlibc + +#endif // MLIBC_POSIX_SYSDEPS diff --git a/user/include/mlibc/options/posix/include/mlibc/resolv_conf.hpp b/user/include/mlibc/options/posix/include/mlibc/resolv_conf.hpp new file mode 100644 index 0000000..2a349c7 --- /dev/null +++ b/user/include/mlibc/options/posix/include/mlibc/resolv_conf.hpp @@ -0,0 +1,21 @@ +#ifndef _MLIBC_RESOLV_CONF +#define _MLIBC_RESOLV_CONF + +#include +#include +#include + +namespace mlibc { + +struct nameserver_data { + nameserver_data() + : name(getAllocator()) {} + frg::string name; + // for in the future we can also store options here +}; + +frg::optional get_nameserver(); + +} // namespace mlibc + +#endif // _MLIBC_RESOLV_CONF diff --git a/user/include/mlibc/options/posix/include/mlibc/services.hpp b/user/include/mlibc/options/posix/include/mlibc/services.hpp new file mode 100644 index 0000000..10dec47 --- /dev/null +++ b/user/include/mlibc/options/posix/include/mlibc/services.hpp @@ -0,0 +1,33 @@ +#ifndef _MLIBC_SERVICES +#define _MLIBC_SERVICES + +#include +#include +#include +#include + +namespace mlibc { + +// Only two services for tcp and udp +#define SERV_MAX 2 + +struct service_buf { + service_buf() + : name(getAllocator()), aliases(getAllocator()) + { } + int port, protocol, socktype; + frg::string name; + frg::vector, MemoryAllocator> aliases; +}; + +using service_result = frg::small_vector; + +int lookup_serv_by_name(service_result &buf, const char *name, int proto, + int socktype, int flags); + +int lookup_serv_by_port(service_result &buf, int proto, int port); + + +} // namespace mlibc + +#endif // _MLIBC_SERVICES diff --git a/user/include/mlibc/options/posix/include/mqueue.h b/user/include/mlibc/options/posix/include/mqueue.h new file mode 100644 index 0000000..cbee138 --- /dev/null +++ b/user/include/mlibc/options/posix/include/mqueue.h @@ -0,0 +1,26 @@ +#ifndef _MQUEUE_H +#define _MQUEUE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int mqd_t; + +#ifndef __MLIBC_ABI_ONLY + +int mq_getattr(mqd_t __mqdes, struct mq_attr *__attr); +int mq_setattr(mqd_t __mqdes, const struct mq_attr *__restrict__ __newattr, struct mq_attr *__restrict__ __oldattr); +int mq_unlink(const char *__name); +mqd_t mq_open(const char *__name, int __flags, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MQUEUE_H */ + diff --git a/user/include/mlibc/options/posix/include/net/if.h b/user/include/mlibc/options/posix/include/net/if.h new file mode 100644 index 0000000..86cad34 --- /dev/null +++ b/user/include/mlibc/options/posix/include/net/if.h @@ -0,0 +1,128 @@ + +#ifndef _NET_IF_H +#define _NET_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define IF_NAMESIZE 16 +#define IFNAMSIZ IF_NAMESIZE +#define ALTIFNAMSIZ 128 +#define IFALIASZ 256 + +struct if_nameindex { + unsigned int if_index; + char *if_name; +}; + +struct ifmap { + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq { + union { + char ifrn_name[IFNAMSIZ]; + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short int ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; + char ifru_newname[IFNAMSIZ]; + char *ifru_data; + } ifr_ifru; +}; + +#define ifr_name ifr_ifrn.ifrn_name +#define ifr_hwaddr ifr_ifru.ifru_hwaddr +#define ifr_addr ifr_ifru.ifru_addr +#define ifr_dstaddr ifr_ifru.ifru_dstaddr +#define ifr_broadaddr ifr_ifru.ifru_broadaddr +#define ifr_netmask ifr_ifru.ifru_netmask +#define ifr_flags ifr_ifru.ifru_flags +#define ifr_metric ifr_ifru.ifru_ivalue +#define ifr_mtu ifr_ifru.ifru_mtu +#define ifr_map ifr_ifru.ifru_map +#define ifr_slave ifr_ifru.ifru_slave +#define ifr_data ifr_ifru.ifru_data +#define ifr_ifindex ifr_ifru.ifru_ivalue +#define ifr_bandwidth ifr_ifru.ifru_ivalue +#define ifr_qlen ifr_ifru.ifru_ivalue +#define ifr_newname ifr_ifru.ifru_newname + +struct ifconf { + int ifc_len; + union { + char *ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; + +#define ifc_buf ifc_ifcu.ifcu_buf +#define ifc_req ifc_ifcu.ifcu_req + +#ifndef __MLIBC_ABI_ONLY + +void if_freenameindex(struct if_nameindex *__index); +char *if_indextoname(unsigned int __index, char *__name); +struct if_nameindex *if_nameindex(void); +unsigned int if_nametoindex(const char *__name); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define IFHWADDRLEN 6 + +#define IFF_UP 0x1 +#define IFF_BROADCAST 0x2 +#define IFF_DEBUG 0x4 +#define IFF_LOOPBACK 0x8 +#define IFF_POINTOPOINT 0x10 +#define IFF_NOTRAILERS 0x20 +#define IFF_RUNNING 0x40 +#define IFF_NOARP 0x80 +#define IFF_PROMISC 0x100 +#define IFF_ALLMULTI 0x200 +#define IFF_MASTER 0x400 +#define IFF_SLAVE 0x800 +#define IFF_MULTICAST 0x1000 +#define IFF_PORTSEL 0x2000 +#define IFF_AUTOMEDIA 0x4000 +#define IFF_DYNAMIC 0x8000 +#define IFF_LOWER_UP 0x10000 +#define IFF_DORMANT 0x20000 +#define IFF_ECHO 0x40000 + +#if __MLIBC_LINUX_OPTION + +#define __UAPI_DEF_IF_IFCONF 0 +#define __UAPI_DEF_IF_IFMAP 0 +#define __UAPI_DEF_IF_IFNAMSIZ 0 +#define __UAPI_DEF_IF_IFREQ 0 +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0 +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 0 + +#endif /* __MLIBC_LINUX_OPTION */ + +#ifdef __cplusplus +} +#endif + +#endif /* _NET_IF_H */ + + diff --git a/user/include/mlibc/options/posix/include/net/if_arp.h b/user/include/mlibc/options/posix/include/net/if_arp.h new file mode 100644 index 0000000..8701137 --- /dev/null +++ b/user/include/mlibc/options/posix/include/net/if_arp.h @@ -0,0 +1,105 @@ +#ifndef _NET_IF_ARP_H +#define _NET_IF_ARP_H + +#include +#include +#include + +#define MAX_ADDR_LEN 7 + +#define ARPOP_REQUEST 1 +#define ARPOP_REPLY 2 +#define ARPOP_RREQUEST 3 +#define ARPOP_RREPLY 4 +#define ARPOP_InREQUEST 8 +#define ARPOP_InREPLY 9 +#define ARPOP_NAK 10 + +#define ARPHRD_NETROM 0 +#define ARPHRD_ETHER 1 +#define ARPHRD_EETHER 2 +#define ARPHRD_AX25 3 +#define ARPHRD_PRONET 4 +#define ARPHRD_CHAOS 5 +#define ARPHRD_IEEE802 6 +#define ARPHRD_ARCNET 7 +#define ARPHRD_APPLETLK 8 +#define ARPHRD_DLCI 15 +#define ARPHRD_ATM 19 +#define ARPHRD_METRICOM 23 +#define ARPHRD_IEEE1394 24 +#define ARPHRD_EUI64 27 +#define ARPHRD_INFINIBAND 32 +#define ARPHRD_SLIP 256 +#define ARPHRD_CSLIP 257 +#define ARPHRD_SLIP6 258 +#define ARPHRD_CSLIP6 259 +#define ARPHRD_RSRVD 260 +#define ARPHRD_ADAPT 264 +#define ARPHRD_ROSE 270 +#define ARPHRD_X25 271 +#define ARPHRD_HWX25 272 +#define ARPHRD_CAN 280 +#define ARPHRD_PPP 512 +#define ARPHRD_CISCO 513 +#define ARPHRD_HDLC ARPHRD_CISCO +#define ARPHRD_LAPB 516 +#define ARPHRD_DDCMP 517 +#define ARPHRD_RAWHDLC 518 +#define ARPHRD_RAWIP 519 + +#define ARPHRD_TUNNEL 768 +#define ARPHRD_TUNNEL6 769 +#define ARPHRD_FRAD 770 +#define ARPHRD_SKIP 771 +#define ARPHRD_LOOPBACK 772 +#define ARPHRD_LOCALTLK 773 +#define ARPHRD_FDDI 774 +#define ARPHRD_BIF 775 +#define ARPHRD_SIT 776 +#define ARPHRD_IPDDP 777 +#define ARPHRD_IPGRE 778 +#define ARPHRD_PIMREG 779 +#define ARPHRD_HIPPI 780 +#define ARPHRD_ASH 781 +#define ARPHRD_ECONET 782 +#define ARPHRD_IRDA 783 +#define ARPHRD_FCPP 784 +#define ARPHRD_FCAL 785 +#define ARPHRD_FCPL 786 +#define ARPHRD_FCFABRIC 787 +#define ARPHRD_IEEE802_TR 800 +#define ARPHRD_IEEE80211 801 +#define ARPHRD_IEEE80211_PRISM 802 +#define ARPHRD_IEEE80211_RADIOTAP 803 +#define ARPHRD_IEEE802154 804 +#define ARPHRD_IEEE802154_MONITOR 805 +#define ARPHRD_PHONET 820 +#define ARPHRD_PHONET_PIPE 821 +#define ARPHRD_CAIF 822 +#define ARPHRD_IP6GRE 823 +#define ARPHRD_NETLINK 824 +#define ARPHRD_6LOWPAN 825 +#define ARPHRD_VSOCKMON 826 + +#define ARPHRD_VOID 0xFFFF +#define ARPHRD_NONE 0xFFFE + +struct arphdr { + uint16_t ar_hrd; + uint16_t ar_pro; + uint8_t ar_hln; + uint8_t ar_pln; + uint16_t ar_op; +}; + +struct arpreq { + struct sockaddr arp_pa; + struct sockaddr arp_ha; + int arp_flags; + struct sockaddr arp_netmask; + char arp_dev[16]; +}; + +#endif /* _NET_IF_ARP_H */ + diff --git a/user/include/mlibc/options/posix/include/netdb.h b/user/include/mlibc/options/posix/include/netdb.h new file mode 100644 index 0000000..9f187fa --- /dev/null +++ b/user/include/mlibc/options/posix/include/netdb.h @@ -0,0 +1,149 @@ +#ifndef _NETDB_H +#define _NETDB_H + +#include +#include +#include +#include +#include + +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_V4MAPPED 0x08 +#define AI_ALL 0x10 +#define AI_ADDRCONFIG 0x20 +#define AI_NUMERICSERV 0x40 + +#define NI_NOFQDN 0x01 +#define NI_NUMERICHOST 0x02 +#define NI_NAMEREQD 0x04 +#define NI_NUMERICSCOPE 0x08 +#define NI_DGRAM 0x10 + +#define NI_NUMERICSERV 2 +#define NI_MAXSERV 32 +#define NI_IDN 32 +#define NI_IDN_USE_STD3_ASCII_RULES 128 + +#define NI_MAXHOST 1025 + +#define EAI_AGAIN 1 +#define EAI_BADFLAGS 2 +#define EAI_FAIL 3 +#define EAI_FAMILY 4 +#define EAI_MEMORY 5 +#define EAI_NONAME 6 +#define EAI_SERVICE 7 +#define EAI_SOCKTYPE 8 +#define EAI_SYSTEM 9 +#define EAI_OVERFLOW 10 +#define EAI_NODATA 11 +#define EAI_ADDRFAMILY 12 + +#define HOST_NOT_FOUND 1 +#define TRY_AGAIN 2 +#define NO_RECOVERY 3 +#define NO_DATA 4 +#define NO_ADDRESS NO_DATA + +#define IPPORT_RESERVED 1024 + +#define _PATH_SERVICES "/etc/services" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int *__h_errno_location(void); +#define h_errno (*__h_errno_location()) + +#endif /* !__MLIBC_ABI_ONLY */ + +struct hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +#define h_addr h_addr_list[0] /* Required by some programs */ + +struct netent { + char *n_name; + char **n_aliases; + int n_addrtype; + uint32_t n_net; +}; + +struct protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + +struct servent { + char *s_name; + char **s_aliases; + int s_port; + char *s_proto; +}; + +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; + +#ifndef __MLIBC_ABI_ONLY + +void endhostent(void); +void endnetent(void); +void endprotoent(void); +void endservent(void); +void freeaddrinfo(struct addrinfo *__info); +const char *gai_strerror(int __errnum); +int getaddrinfo(const char *__restrict __node, const char *__restrict __service, + const struct addrinfo *__restrict __hints, struct addrinfo **__restrict __res); +struct hostent *gethostent(void); +struct hostent *gethostbyname(const char *__name); +struct hostent *gethostbyname2(const char *__name, int __flags); +struct hostent *gethostbyaddr(const void *__addr, socklen_t __len, int __type); +int gethostbyaddr_r(const void *__restrict __addr, socklen_t __len, int __type, struct hostent *__restrict __ret, + char *__restrict __buf, size_t __buflen, struct hostent **__restrict __res, int *__restrict __h_errnump); +int gethostbyname_r(const char *__restrict __name, struct hostent *__restrict __ret, char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __res, int *__restrict __h_errnump); +int getnameinfo(const struct sockaddr *__restrict __addr, socklen_t __addrlen, + char *__restrict __host, socklen_t __hostlen, char *__restrict __serv, socklen_t __servlen, int __flags); +struct netent *getnetbyaddr(uint32_t __net, int __type); +struct netent *getnetbyname(const char *__name); +struct netent *getnetent(void); +struct protoent *getprotobyname(const char *__name); +struct protoent *getprotobynumber(int __proto); +struct protoent *getprotoent(void); +struct servent *getservbyname(const char *__name, const char *__proto); +struct servent *getservbyport(int __port, const char *__proto); +struct servent *getservent(void); +void sethostent(int __stayopen); +void setnetent(int __stayopen); +void setprotoent(int __stayopen); +void setservent(int __stayopen); + +/* Deprecated GNU extension */ +const char *hstrerror(int __err); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _NETDB_H */ diff --git a/user/include/mlibc/options/posix/include/netinet/icmp6.h b/user/include/mlibc/options/posix/include/netinet/icmp6.h new file mode 100644 index 0000000..5251bbd --- /dev/null +++ b/user/include/mlibc/options/posix/include/netinet/icmp6.h @@ -0,0 +1,209 @@ +#ifndef _NETINET_ICMP6_H +#define _NETINET_ICMP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#if __MLIBC_GLIBC_OPTION +#include +#endif /* __MLIBC_GLIBC_OPTION */ + +#define ICMP6_FILTER 1 + +#define ICMP6_DST_UNREACH 1 +#define ICMP6_PACKET_TOO_BIG 2 +#define ICMP6_TIME_EXCEEDED 3 +#define ICMP6_PARAM_PROB 4 + +#define ICMP6_FILTER_BLOCK 1 +#define ICMP6_FILTER_PASS 2 +#define ICMP6_FILTER_BLOCKOTHERS 3 +#define ICMP6_FILTER_PASSONLY 4 +#define ICMP6_ECHO_REQUEST 128 +#define ICMP6_ECHO_REPLY 129 + +#define MLD_LISTENER_QUERY 130 +#define MLD_LISTENER_REPORT 131 +#define MLD_LISTENER_REDUCTION 132 + +#define ICMP6_DST_UNREACH_NOROUTE 0 +#define ICMP6_DST_UNREACH_ADMIN 1 +#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 +#define ICMP6_DST_UNREACH_ADDR 3 +#define ICMP6_DST_UNREACH_NOPORT 4 + +#define ICMP6_TIME_EXCEED_TRANSIT 0 +#define ICMP6_TIME_EXCEED_REASSEMBLY 1 + +#define ICMP6_PARAMPROB_HEADER 0 +#define ICMP6_PARAMPROB_NEXTHEADER 1 +#define ICMP6_PARAMPROB_OPTION 2 + +struct icmp6_filter { + uint32_t icmp6_filt[8]; +}; + +struct icmp6_hdr { + uint8_t icmp6_type; + uint8_t icmp6_code; + uint16_t icmp6_cksum; + union { + uint32_t icmp6_un_data32[1]; + uint16_t icmp6_un_data16[2]; + uint8_t icmp6_un_data8[4]; + } icmp6_dataun; +}; + +#define icmp6_data32 icmp6_dataun.icmp6_un_data32 +#define icmp6_data16 icmp6_dataun.icmp6_un_data16 +#define icmp6_data8 icmp6_dataun.icmp6_un_data8 + +#define icmp6_pptr icmp6_data32[0] +#define icmp6_mtu icmp6_data32[0] +#define icmp6_id icmp6_data16[0] +#define icmp6_seq icmp6_data16[1] +#define icmp6_maxdelay icmp6_data16[0] + +#define ICMP6_FILTER_WILLPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) == 0) + +#define ICMP6_FILTER_WILLBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) != 0) + +#define ICMP6_FILTER_SETPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1U << ((type) & 31)))) + +#define ICMP6_FILTER_SETBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) |= (1U << ((type) & 31)))) + +#define ICMP6_FILTER_SETPASSALL(filterp) \ + memset (filterp, 0, sizeof (struct icmp6_filter)); + +#define ICMP6_FILTER_SETBLOCKALL(filterp) \ + memset (filterp, 0xFF, sizeof (struct icmp6_filter)); + +#define ND_ROUTER_SOLICIT 133 +#define ND_ROUTER_ADVERT 134 +#define ND_NEIGHBOR_SOLICIT 135 +#define ND_NEIGHBOR_ADVERT 136 +#define ND_REDIRECT 137 + +struct nd_router_solicit { + struct icmp6_hdr nd_rs_hdr; +}; + +#define nd_rs_type nd_rs_hdr.icmp6_type +#define nd_rs_code nd_rs_hdr.icmp6_code +#define nd_rs_cksum nd_rs_hdr.icmp6_cksum +#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0] + +struct nd_router_advert { + struct icmp6_hdr nd_ra_hdr; + uint32_t nd_ra_reachable; + uint32_t nd_ra_retransmit; +}; + +struct nd_opt_hdr { + uint8_t nd_opt_type; + uint8_t nd_opt_len; +}; + +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define ND_OPT_PREFIX_INFORMATION 3 +#define ND_OPT_REDIRECTED_HEADER 4 +#define ND_OPT_MTU 5 +#define ND_OPT_RTR_ADV_INTERVAL 7 +#define ND_OPT_HOME_AGENT_INFO 8 + +struct nd_opt_prefix_info { + uint8_t nd_opt_pi_type; + uint8_t nd_opt_pi_len; + uint8_t nd_opt_pi_prefix_len; + uint8_t nd_opt_pi_flags_reserved; + uint32_t nd_opt_pi_valid_time; + uint32_t nd_opt_pi_preferred_time; + uint32_t nd_opt_pi_reserved2; + struct in6_addr nd_opt_pi_prefix; +}; + +#define ND_OPT_PI_FLAG_RADDR 0x20 +#define ND_OPT_PI_FLAG_AUTO 0x40 +#define ND_OPT_PI_FLAG_ONLINK 0x80 + +#define nd_ra_type nd_ra_hdr.icmp6_type +#define nd_ra_code nd_ra_hdr.icmp6_code +#define nd_ra_cksum nd_ra_hdr.icmp6_cksum +#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0] +#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] +#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] + +#define ND_RA_FLAG_HOME_AGENT 0x20 +#define ND_RA_FLAG_OTHER 0x40 +#define ND_RA_FLAG_MANAGED 0x80 + +struct nd_opt_rd_hdr { + uint8_t nd_opt_rh_type; + uint8_t nd_opt_rh_len; + uint16_t nd_opt_rh_reserved1; + uint32_t nd_opt_rh_reserved2; +}; + +struct nd_opt_mtu { + uint8_t nd_opt_mtu_type; + uint8_t nd_opt_mtu_len; + uint16_t nd_opt_mtu_reserved; + uint32_t nd_opt_mtu_mtu; +}; + +struct nd_neighbor_solicit { + struct icmp6_hdr nd_ns_hdr; + struct in6_addr nd_ns_target; +}; + +#define nd_ns_type nd_ns_hdr.icmp6_type +#define nd_ns_code nd_ns_hdr.icmp6_code +#define nd_ns_cksum nd_ns_hdr.icmp6_cksum + +struct nd_neighbor_advert { + struct icmp6_hdr nd_na_hdr; + struct in6_addr nd_na_target; +}; +#define nd_na_type nd_na_hdr.icmp6_type +#define nd_na_code nd_na_hdr.icmp6_code +#define nd_na_cksum nd_na_hdr.icmp6_cksum +#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0] + +struct nd_redirect { + struct icmp6_hdr nd_rd_hdr; + struct in6_addr nd_rd_target; + struct in6_addr nd_rd_dst; +}; + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum + +#define ND_NA_FLAG_OVERRIDE 0x00000020 +#define ND_NA_FLAG_SOLICITED 0x00000040 +#define ND_NA_FLAG_ROUTER 0x00000080 + +struct nd_opt_home_agent_info { + uint8_t nd_opt_home_agent_info_type; + uint8_t nd_opt_home_agent_info_len; + uint16_t nd_opt_home_agent_info_reserved; + uint16_t nd_opt_home_agent_info_preference; + uint16_t nd_opt_home_agent_info_lifetime; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_ICMP6_H */ + diff --git a/user/include/mlibc/options/posix/include/netinet/if_ether.h b/user/include/mlibc/options/posix/include/netinet/if_ether.h new file mode 100644 index 0000000..e79abc3 --- /dev/null +++ b/user/include/mlibc/options/posix/include/netinet/if_ether.h @@ -0,0 +1,110 @@ +#ifndef _NETINET_IF_ETHER_H +#define _NETINET_IF_ETHER_H + +#include + +#define ETH_ALEN 6 +#define ETH_HLEN 14 +#define ETH_ZLEN 60 +#define ETH_FRAME_LEN 1514 +#define ETH_FCS_LEN 4 + +#define ETH_P_LOOP 0x0060 +#define ETH_P_PUP 0x0200 +#define ETH_P_PUPAT 0x0201 +#define ETH_P_IP 0x0800 +#define ETH_P_X25 0x0805 +#define ETH_P_ARP 0x0806 +#define ETH_P_BPQ 0x08FF +#define ETH_P_IEEEPUP 0x0a00 +#define ETH_P_IEEEPUPAT 0x0a01 +#define ETH_P_BATMAN 0x4305 +#define ETH_P_DEC 0x6000 +#define ETH_P_DNA_DL 0x6001 +#define ETH_P_DNA_RC 0x6002 +#define ETH_P_DNA_RT 0x6003 +#define ETH_P_LAT 0x6004 +#define ETH_P_DIAG 0x6005 +#define ETH_P_CUST 0x6006 +#define ETH_P_SCA 0x6007 +#define ETH_P_TEB 0x6558 +#define ETH_P_RARP 0x8035 +#define ETH_P_ATALK 0x809B +#define ETH_P_AARP 0x80F3 +#define ETH_P_8021Q 0x8100 +#define ETH_P_IPX 0x8137 +#define ETH_P_IPV6 0x86DD +#define ETH_P_PAUSE 0x8808 +#define ETH_P_SLOW 0x8809 +#define ETH_P_WCCP 0x883E +#define ETH_P_MPLS_UC 0x8847 +#define ETH_P_MPLS_MC 0x8848 +#define ETH_P_ATMMPOA 0x884c +#define ETH_P_PPP_DISC 0x8863 +#define ETH_P_PPP_SES 0x8864 +#define ETH_P_LINK_CTL 0x886c +#define ETH_P_ATMFATE 0x8884 +#define ETH_P_PAE 0x888E +#define ETH_P_AOE 0x88A2 +#define ETH_P_8021AD 0x88A8 +#define ETH_P_802_EX1 0x88B5 +#define ETH_P_TIPC 0x88CA +#define ETH_P_8021AH 0x88E7 +#define ETH_P_MVRP 0x88F5 +#define ETH_P_1588 0x88F7 +#define ETH_P_PRP 0x88FB +#define ETH_P_FCOE 0x8906 +#define ETH_P_TDLS 0x890D +#define ETH_P_FIP 0x8914 +#define ETH_P_80221 0x8917 +#define ETH_P_LOOPBACK 0x9000 +#define ETH_P_QINQ1 0x9100 +#define ETH_P_QINQ2 0x9200 +#define ETH_P_QINQ3 0x9300 +#define ETH_P_EDSA 0xDADA +#define ETH_P_AF_IUCV 0xFBFB + +#define ETH_P_802_3_MIN 0x0600 + +#define ETH_P_802_3 0x0001 +#define ETH_P_AX25 0x0002 +#define ETH_P_ALL 0x0003 +#define ETH_P_802_2 0x0004 +#define ETH_P_SNAP 0x0005 +#define ETH_P_DDCMP 0x0006 +#define ETH_P_WAN_PPP 0x0007 +#define ETH_P_PPP_MP 0x0008 +#define ETH_P_LOCALTALK 0x0009 +#define ETH_P_CAN 0x000C +#define ETH_P_CANFD 0x000D +#define ETH_P_PPPTALK 0x0010 +#define ETH_P_TR_802_2 0x0011 +#define ETH_P_MOBITEX 0x0015 +#define ETH_P_CONTROL 0x0016 +#define ETH_P_IRDA 0x0017 +#define ETH_P_ECONET 0x0018 +#define ETH_P_HDLC 0x0019 +#define ETH_P_ARCNET 0x001A +#define ETH_P_DSA 0x001B +#define ETH_P_TRAILER 0x001C +#define ETH_P_PHONET 0x00F5 +#define ETH_P_IEEE802154 0x00F6 +#define ETH_P_CAIF 0x00F7 + +#include +#include + +struct ether_arp { + struct arphdr ea_hdr; + uint8_t arp_sha[ETH_ALEN]; + uint8_t arp_spa[4]; + uint8_t arp_tha[ETH_ALEN]; + uint8_t arp_tpa[4]; +}; +#define arp_hrd ea_hdr.ar_hrd +#define arp_pro ea_hdr.ar_pro +#define arp_hln ea_hdr.ar_hln +#define arp_pln ea_hdr.ar_pln +#define arp_op ea_hdr.ar_op + +#endif /*_NETINET_IF_ETHER_H */ diff --git a/user/include/mlibc/options/posix/include/netinet/in.h b/user/include/mlibc/options/posix/include/netinet/in.h new file mode 100644 index 0000000..5dee2bd --- /dev/null +++ b/user/include/mlibc/options/posix/include/netinet/in.h @@ -0,0 +1,122 @@ + +#ifndef _NETINET_IN_H +#define _NETINET_IN_H + +#include +#include /* struct sockaddr */ +#include +#include +#include +#include + +#if __MLIBC_GLIBC_OPTION + #include +#endif /*__MLIBC_GLIBC_OPTION */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +extern const struct in6_addr in6addr_any; +extern const struct in6_addr in6addr_loopback; + +uint32_t htonl(uint32_t __x); +uint16_t htons(uint16_t __x); +uint32_t ntohl(uint32_t __x); +uint16_t ntohs(uint16_t __x); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define IN6_IS_ADDR_UNSPECIFIED(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + !_a[2] && \ + !_a[3]; \ +}) +#define IN6_IS_ADDR_LOOPBACK(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + !_a[2] && \ + _a[3] == htonl(0x0001); \ +}) +#define IN6_IS_ADDR_MULTICAST(a) (((const uint8_t *) (a))[0] == 0xff) +#define IN6_IS_ADDR_LINKLOCAL(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + (_a[0] & htonl(0xffc00000)) == htonl(0xfe800000); \ +}) +#define IN6_IS_ADDR_SITELOCAL(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + (_a[0] & htonl(0xffc00000)) == htonl(0xfec00000); \ +}) +#define IN6_IS_ADDR_V4MAPPED(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + _a[2] == htonl(0xffff); \ +}) +#define __ARE_4_BYTE_EQUAL(a, b) \ + ((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] && \ + (a)[3] == (b)[3]) +#define IN6_ARE_ADDR_EQUAL(a, b) \ + __ARE_4_BYTE_EQUAL((const uint32_t *)(a), (const uint32_t *)(b)) + +#define IN6_IS_ADDR_V4COMPAT(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + uint8_t *_a8 = (uint8_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && !_a[1] && !_a[2] && (_a8[15] > 1); \ +}) +#define IN6_IS_ADDR_MC_NODELOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x1)); \ +}) +#define IN6_IS_ADDR_MC_LINKLOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x2)); \ +}) +#define IN6_IS_ADDR_MC_SITELOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x5)); \ +}) +#define IN6_IS_ADDR_MC_ORGLOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x8)); \ +}) +#define IN6_IS_ADDR_MC_GLOBAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0xe)); \ +}) + +#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 +#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 +#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) +#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#define MCAST_EXCLUDE 0 +#define MCAST_INCLUDE 1 + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_IN_H */ + diff --git a/user/include/mlibc/options/posix/include/netinet/ip.h b/user/include/mlibc/options/posix/include/netinet/ip.h new file mode 100644 index 0000000..cb7c06c --- /dev/null +++ b/user/include/mlibc/options/posix/include/netinet/ip.h @@ -0,0 +1,118 @@ + +#ifndef _NETINET_IP_H +#define _NETINET_IP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST +#define IPTOS_CLASS_CS0 0x00 +#define IPTOS_CLASS_CS4 0x80 +#define IPTOS_CLASS_CS6 0xC0 +#define IPTOS_DSCP_EF 0xB8 + +#define IPOPT_COPY 0x80 +#define IPOPT_CLASS_MASK 0x60 +#define IPOPT_NUMBER_MASK 0x1f + +#define IPOPT_COPIED(o) ((o) & IPOPT_COPY) +#define IPOPT_CLASS(o) ((o) & IPOPT_CLASS_MASK) +#define IPOPT_NUMBER(o) ((o) & IPOPT_NUMBER_MASK) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_MEASUREMENT IPOPT_DEBMEAS +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 +#define IPOPT_END IPOPT_EOL +#define IPOPT_NOP 1 +#define IPOPT_NOOP IPOPT_NOP + +#define IPOPT_RR 7 +#define IPOPT_TS 68 +#define IPOPT_TIMESTAMP IPOPT_TS +#define IPOPT_SECURITY 130 +#define IPOPT_SEC IPOPT_SECURITY +#define IPOPT_LSRR 131 +#define IPOPT_SATID 136 +#define IPOPT_SID IPOPT_SATID +#define IPOPT_SSRR 137 +#define IPOPT_RA 148 + +#define IPOPT_OPTVAL 0 +#define IPOPT_OLEN 1 +#define IPOPT_OFFSET 2 +#define IPOPT_MINOFF 4 + +#define MAX_IPOPTLEN 40 + +#define IPOPT_TS_TSONLY 0 +#define IPOPT_TS_TSANDADDR 1 +#define IPOPT_TS_PRESPEC 3 + +#define IPDEFTTL 64 + +struct ip { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ip_hl:4; + unsigned int ip_v:4; +#endif +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int ip_v:4; + unsigned int ip_hl:4; +#endif + uint8_t ip_tos; + unsigned short ip_len; + unsigned short ip_id; + unsigned short ip_off; +#define IP_RF 0x8000 +#define IP_DF 0x4000 +#define IP_MF 0x2000 +#define IP_OFFMASK 0x1fff + uint8_t ip_ttl; + uint8_t ip_p; + unsigned short ip_sum; + struct in_addr ip_src, ip_dst; +}; + +#define IPVERSION 4 + +struct iphdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ihl:4; + unsigned int version:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4; + unsigned int ihl:4; +#else +# error "Please fix " +#endif + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_IP_H */ + diff --git a/user/include/mlibc/options/posix/include/netinet/ip6.h b/user/include/mlibc/options/posix/include/netinet/ip6.h new file mode 100644 index 0000000..268f8a2 --- /dev/null +++ b/user/include/mlibc/options/posix/include/netinet/ip6.h @@ -0,0 +1,30 @@ +#ifndef _NETINET_IP6_H +#define _NETINET_IP6_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ip6_hdr { + union { + struct ip6_hdrctl { + uint32_t ip6_un1_flow; + uint16_t ip6_un1_plen; + uint8_t ip6_un1_nxt; + uint8_t ip6_un1_hlim; + } ip6_un1; + uint8_t ip6_un2_vfc; + } ip6_ctlun; + struct in6_addr ip6_src; + struct in6_addr ip6_dst; +}; + +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_IP6_H */ diff --git a/user/include/mlibc/options/posix/include/netinet/ip_icmp.h b/user/include/mlibc/options/posix/include/netinet/ip_icmp.h new file mode 100644 index 0000000..c5fecd1 --- /dev/null +++ b/user/include/mlibc/options/posix/include/netinet/ip_icmp.h @@ -0,0 +1,140 @@ +#ifndef _NETINET_ICMP_H +#define _NETINET_ICMP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +struct icmphdr { + uint8_t type; + uint8_t code; + uint16_t checksum; + union { + struct { + uint16_t id; + uint16_t sequence; + } echo; + uint32_t gateway; + struct { + uint16_t __unused; + uint16_t mtu; + } frag; + uint8_t reserved[4]; + } un; +}; + +#define ICMP_ECHOREPLY 0 +#define ICMP_DEST_UNREACH 3 +#define ICMP_SOURCE_QUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO 8 +#define ICMP_TIME_EXCEEDED 11 +#define ICMP_PARAMETERPROB 12 +#define ICMP_TIMESTAMP 13 +#define ICMP_TIMESTAMPREPLY 14 +#define ICMP_INFO_REQUEST 15 +#define ICMP_INFO_REPLY 16 +#define ICMP_ADDRESS 17 +#define ICMP_ADDRESSREPLY 18 + +#define ICMP_NET_UNREACH 0 +#define ICMP_HOST_UNREACH 1 +#define ICMP_PROT_UNREACH 2 +#define ICMP_PORT_UNREACH 3 +#define ICMP_FRAG_NEEDED 4 +#define ICMP_SR_FAILED 5 +#define ICMP_NET_UNKNOWN 6 +#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_ISOLATED 8 +#define ICMP_NET_ANO 9 +#define ICMP_HOST_ANO 10 +#define ICMP_NET_UNR_TOS 11 +#define ICMP_HOST_UNR_TOS 12 +#define ICMP_PKT_FILTERED 13 +#define ICMP_PREC_VIOLATION 14 +#define ICMP_PREC_CUTOFF 15 +#define NR_ICMP_UNREACH 15 + +#define ICMP_REDIR_NET 0 +#define ICMP_REDIR_HOST 1 +#define ICMP_REDIR_NETTOS 2 +#define ICMP_REDIR_HOSTTOS 3 + +#define ICMP_EXC_TTL 0 +#define ICMP_EXC_FRAGTIME 1 + +#define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) + +struct icmp_ra_addr { + uint32_t ira_addr; + uint32_t ira_preference; +}; + +struct icmp { + uint8_t icmp_type; + uint8_t icmp_code; + uint16_t icmp_cksum; + union { + unsigned char ih_pptr; + struct in_addr ih_gwaddr; + struct ih_idseq { + uint16_t icd_id; + uint16_t icd_seq; + } ih_idseq; + uint32_t ih_void; + + struct ih_pmtu { + uint16_t ipm_void; + uint16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv { + uint8_t irt_num_addrs; + uint8_t irt_wpa; + uint16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; + union { + struct { + uint32_t its_otime; + uint32_t its_rtime; + uint32_t its_ttime; + } id_ts; + struct { + struct ip idi_ip; + } id_ip; + struct icmp_ra_addr id_radv; + uint32_t id_mask; + uint8_t id_data[1]; + } icmp_dun; +}; + +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_ICMP_H */ diff --git a/user/include/mlibc/options/posix/include/netinet/tcp.h b/user/include/mlibc/options/posix/include/netinet/tcp.h new file mode 100644 index 0000000..2ac4201 --- /dev/null +++ b/user/include/mlibc/options/posix/include/netinet/tcp.h @@ -0,0 +1,95 @@ +#ifndef _NETINET_TCP_H +#define _NETINET_TCP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define some macros using same ABI as Linux */ +#define TCP_NODELAY 1 +#define TCP_MAXSEG 2 +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 +#define TCP_KEEPCNT 6 +#define TCP_DEFER_ACCEPT 9 +#define TCP_INFO 11 +#define TCP_CONGESTION 13 +#define TCP_FASTOPEN 23 + +#define TCP_ESTABLISHED 1 +#define TCP_SYN_SENT 2 +#define TCP_SYN_RECV 3 +#define TCP_FIN_WAIT1 4 +#define TCP_FIN_WAIT2 5 +#define TCP_TIME_WAIT 6 +#define TCP_CLOSE 7 +#define TCP_CLOSE_WAIT 8 +#define TCP_LAST_ACK 9 +#define TCP_LISTEN 10 +#define TCP_CLOSING 11 +#define TCP_QUICKACK 12 + +#define SOL_TCP 6 + +#define TCPI_OPT_TIMESTAMPS 1 +#define TCPI_OPT_SACK 2 +#define TCPI_OPT_WSCALE 4 +#define TCPI_OPT_ECN 8 +#define TCPI_OPT_ECN_SEEN 16 +#define TCPI_OPT_SYN_DATA 32 + +enum tcp_ca_state { + TCP_CA_Open = 0, + TCP_CA_Disorder = 1, + TCP_CA_CWR = 2, + TCP_CA_Recovery = 3, + TCP_CA_Loss = 4 +}; + +struct tcp_info { + uint8_t tcpi_state; + uint8_t tcpi_ca_state; + uint8_t tcpi_retransmits; + uint8_t tcpi_probes; + uint8_t tcpi_backoff; + uint8_t tcpi_options; + __extension__ uint8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4; + + uint32_t tcpi_rto; + uint32_t tcpi_ato; + uint32_t tcpi_snd_mss; + uint32_t tcpi_rcv_mss; + + uint32_t tcpi_unacked; + uint32_t tcpi_sacked; + uint32_t tcpi_lost; + uint32_t tcpi_retrans; + uint32_t tcpi_fackets; + + uint32_t tcpi_last_data_sent; + uint32_t tcpi_last_ack_sent; + uint32_t tcpi_last_data_recv; + uint32_t tcpi_last_ack_recv; + + uint32_t tcpi_pmtu; + uint32_t tcpi_rcv_ssthresh; + uint32_t tcpi_rtt; + uint32_t tcpi_rttvar; + uint32_t tcpi_snd_ssthresh; + uint32_t tcpi_snd_cwnd; + uint32_t tcpi_advmss; + uint32_t tcpi_reordering; + + uint32_t tcpi_rcv_rtt; + uint32_t tcpi_rcv_space; + + uint32_t tcpi_total_retrans; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_TCP_H */ diff --git a/user/include/mlibc/options/posix/include/netinet/udp.h b/user/include/mlibc/options/posix/include/netinet/udp.h new file mode 100644 index 0000000..1563f1c --- /dev/null +++ b/user/include/mlibc/options/posix/include/netinet/udp.h @@ -0,0 +1,31 @@ +#ifndef _NETINET_UDP_H +#define _NETINET_UDP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__extension__ struct udphdr { + __extension__ union { + struct { + uint16_t uh_sport; + uint16_t uh_dport; + uint16_t uh_ulen; + uint16_t uh_sum; + }; + struct { + uint16_t source; + uint16_t dest; + uint16_t len; + uint16_t check; + }; + }; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETINET_UDP_H */ diff --git a/user/include/mlibc/options/posix/include/nl_types.h b/user/include/mlibc/options/posix/include/nl_types.h new file mode 100644 index 0000000..8878629 --- /dev/null +++ b/user/include/mlibc/options/posix/include/nl_types.h @@ -0,0 +1,6 @@ +#ifndef NL_TYPES_H +#define NL_TYPES_H + + + +#endif /* NL_TYPES_H */ diff --git a/user/include/mlibc/options/posix/include/poll.h b/user/include/mlibc/options/posix/include/poll.h new file mode 100644 index 0000000..2611296 --- /dev/null +++ b/user/include/mlibc/options/posix/include/poll.h @@ -0,0 +1,6 @@ +#ifndef _POLL_H +#define _POLL_H + +#include + +#endif /* _POLL_H */ diff --git a/user/include/mlibc/options/posix/include/pthread.h b/user/include/mlibc/options/posix/include/pthread.h new file mode 100644 index 0000000..ca024a4 --- /dev/null +++ b/user/include/mlibc/options/posix/include/pthread.h @@ -0,0 +1,322 @@ + +#ifndef _PTHREAD_H +#define _PTHREAD_H + +#include +#include +/* TODO: pthread is not required to define size_t. */ +#include +#include +#include +#include + +#include +#include + +/* pthread.h is required to include sched.h and time.h */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PTHREAD_CREATE_JOINABLE __MLIBC_THREAD_CREATE_JOINABLE +#define PTHREAD_CREATE_DETACHED __MLIBC_THREAD_CREATE_DETACHED + +/* Values for pthread_attr_{get,set}scope */ +#define PTHREAD_SCOPE_SYSTEM 0 +#define PTHREAD_SCOPE_PROCESS 1 + +/* Values for pthread_attr_{get,set}inheritsched */ +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +/* values for pthread_{get,set}canceltype(). */ +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +/* values for pthread_{get,set}cancelstate(). */ +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 + +/* values for pthread_mutexattr_{get,set}type(). */ +#define PTHREAD_MUTEX_DEFAULT __MLIBC_THREAD_MUTEX_DEFAULT +#define PTHREAD_MUTEX_NORMAL __MLIBC_THREAD_MUTEX_NORMAL +#define PTHREAD_MUTEX_ERRORCHECK __MLIBC_THREAD_MUTEX_ERRORCHECK +#define PTHREAD_MUTEX_RECURSIVE __MLIBC_THREAD_MUTEX_RECURSIVE + +/* values for pthread_mutexattr_{get,set}robust(). */ +#define PTHREAD_MUTEX_STALLED __MLIBC_THREAD_MUTEX_STALLED +#define PTHREAD_MUTEX_ROBUST __MLIBC_THREAD_MUTEX_ROBUST + +/* values for pthread_mutexattr_{get,set}pshared(). */ +#define PTHREAD_PROCESS_PRIVATE __MLIBC_THREAD_PROCESS_PRIVATE +#define PTHREAD_PROCESS_SHARED __MLIBC_THREAD_PROCESS_SHARED + +/* Values for pthread_mutexattr_{get,set}protocol() */ +#define PTHREAD_PRIO_NONE __MLIBC_THREAD_PRIO_NONE +#define PTHREAD_PRIO_INHERIT __MLIBC_THREAD_PRIO_INHERIT +#define PTHREAD_PRIO_PROTECT __MLIBC_THREAD_PRIO_PROTECT + +#define PTHREAD_ONCE_INIT {0} +#define PTHREAD_COND_INITIALIZER {0} +#define PTHREAD_MUTEX_INITIALIZER __MLIBC_THREAD_MUTEX_INITIALIZER +#define PTHREAD_RWLOCK_INITIALIZER {0, 0, 0} + +#define PTHREAD_CANCELED ((void*) -1) + +#define PTHREAD_BARRIER_SERIAL_THREAD -1 + +/* values for pthread_key */ +#define PTHREAD_DESTRUCTOR_ITERATIONS 8 + +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +#define PTHREAD_STACK_MIN 16384 + +#define PTHREAD_ATTR_NO_SIGMASK_NP (-1) + +/* TODO: move to own file and include in sys/types.h */ +typedef struct __mlibc_threadattr pthread_attr_t; + +typedef uintptr_t pthread_key_t; + +struct __mlibc_once { + unsigned int __mlibc_done; +}; +typedef struct __mlibc_once pthread_once_t; + +typedef struct __mlibc_mutexattr pthread_mutexattr_t; + +typedef struct __mlibc_mutex pthread_mutex_t; + +typedef struct __mlibc_condattr pthread_condattr_t; + +typedef struct __mlibc_cond pthread_cond_t; + +struct __mlibc_barrierattr_struct { + int __mlibc_pshared; +}; +typedef struct __mlibc_barrierattr_struct pthread_barrierattr_t; + +struct __mlibc_barrier { + unsigned int __mlibc_waiting; + unsigned int __mlibc_inside; + unsigned int __mlibc_count; + unsigned int __mlibc_seq; + unsigned int __mlibc_flags; +}; +typedef struct __mlibc_barrier pthread_barrier_t; + +struct __mlibc_fair_rwlock { + unsigned int __mlibc_m; /* Mutex. */ + unsigned int __mlibc_rc; /* Reader count (not reference count). */ + unsigned int __mlibc_flags; +}; +typedef struct __mlibc_fair_rwlock pthread_rwlock_t; + +struct __mlibc_rwlockattr { + int __mlibc_pshared; +}; +typedef struct __mlibc_rwlockattr pthread_rwlockattr_t; + +#ifndef __MLIBC_ABI_ONLY + +/* ---------------------------------------------------------------------------- */ +/* pthread_attr and pthread functions. */ +/* ---------------------------------------------------------------------------- */ + +/* pthread_attr functions. */ +int pthread_attr_init(pthread_attr_t *__attr); +int pthread_attr_destroy(pthread_attr_t *__attr); + +int pthread_attr_getdetachstate(const pthread_attr_t *__attr, int *__state); +int pthread_attr_setdetachstate(pthread_attr_t *__attr, int __state); + +int pthread_attr_getstacksize(const pthread_attr_t *__restrict __attr, size_t *__restrict __stacksize); +int pthread_attr_setstacksize(pthread_attr_t *__attr, size_t __stacksize); + +int pthread_attr_getstackaddr(const pthread_attr_t *__attr, void **__stackaddr); +int pthread_attr_setstackaddr(pthread_attr_t *__attr, void *__stackaddr); + +int pthread_attr_getstack(const pthread_attr_t *__attr, void **__stackaddr, size_t *__stacksize); +int pthread_attr_setstack(pthread_attr_t *__attr, void *__stackaddr, size_t __stacksize); + +int pthread_attr_getguardsize(const pthread_attr_t *__restrict __attr, size_t *__restrict __guardsize); +int pthread_attr_setguardsize(pthread_attr_t *__attr, size_t __guardsize); + +int pthread_attr_getscope(const pthread_attr_t *__attr, int *__scope); +int pthread_attr_setscope(pthread_attr_t *__attr, int __scope); + +int pthread_attr_getschedparam(const pthread_attr_t *__restrict __attr, struct sched_param *__restrict __param); +int pthread_attr_setschedparam(pthread_attr_t *__restrict __attr, const struct sched_param *__restrict __param); + +int pthread_attr_getschedpolicy(const pthread_attr_t *__restrict __attr, int *__restrict __schedpolicy); +int pthread_attr_setschedpolicy(pthread_attr_t *__restrict __attr, int __schedpolicy); + +int pthread_attr_getinheritsched(const pthread_attr_t *__restrict __attr, int *__restrict __inheritsched); +int pthread_attr_setinheritsched(pthread_attr_t *__restrict __attr, int __inheritsched); + +#if __MLIBC_LINUX_OPTION +int pthread_attr_getaffinity_np(const pthread_attr_t *__restrict __attr, size_t __cpusetsize, cpu_set_t *__restrict __cpuset); +int pthread_attr_setaffinity_np(pthread_attr_t *__restrict __attr, size_t __cpusetsize, const cpu_set_t *__restrict __cpuset); + +int pthread_attr_getsigmask_np(const pthread_attr_t *__restrict __attr, sigset_t *__restrict __sigmask); +int pthread_attr_setsigmask_np(pthread_attr_t *__restrict __attr, const sigset_t *__restrict __sigmask); + +int pthread_getattr_np(pthread_t __thrd, pthread_attr_t *__attr); + +int pthread_getaffinity_np(pthread_t __thrd, size_t __cpusetsize, cpu_set_t *__cpuset); +int pthread_setaffinity_np(pthread_t __thrd, size_t __cpusetsize, const cpu_set_t *__cpuset); +#endif /* __MLIBC_LINUX_OPTION */ + +/* pthread functions. */ +int pthread_create(pthread_t *__restrict __thrd, const pthread_attr_t *__restrict __attr, + void *(*__fn) (void *__arg), void *__restrict __arg); +pthread_t pthread_self(void); +int pthread_equal(pthread_t __a, pthread_t __b); +__attribute__ ((__noreturn__)) void pthread_exit(void *__arg); + +int pthread_join(pthread_t __thrd, void **__res); +int pthread_detach(pthread_t __thrd); + +void pthread_cleanup_push(void (*__fn) (void *__arg), void *__arg); +void pthread_cleanup_pop(int __execute); + +int pthread_setname_np(pthread_t __thrd, const char *__name); +int pthread_getname_np(pthread_t __thrd, char *__name, size_t __size); + +int pthread_attr_setstack(pthread_attr_t *__attr, void *__stackaddr, size_t __stacksize); +int pthread_attr_getstack(const pthread_attr_t *, void **__stackaddr, size_t *__stacksize); + +int pthread_getattr_np(pthread_t __thrd, pthread_attr_t *__attr); + +int pthread_setschedparam(pthread_t __thrd, int __policy, const struct sched_param *__param); +int pthread_getschedparam(pthread_t __thrd, int *__policy, struct sched_param *__param); + +int pthread_setcanceltype(int __type, int *__oldtype); +int pthread_setcancelstate(int __state, int *__oldstate); +void pthread_testcancel(void); +int pthread_cancel(pthread_t __thrd); + +int pthread_atfork(void (*__prepare) (void), void (*__parent) (void), void (*__child) (void)); + +/* ---------------------------------------------------------------------------- */ +/* pthread_key functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_key_create(pthread_key_t *__key, void (*__destructor) (void *__data)); +int pthread_key_delete(pthread_key_t __key); + +void *pthread_getspecific(pthread_key_t __key); +int pthread_setspecific(pthread_key_t __key, const void *__data); + +/* ---------------------------------------------------------------------------- */ +/* pthread_once functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_once(pthread_once_t *__once, void (*__fn) (void)); + +/* ---------------------------------------------------------------------------- */ +/* pthread_mutexattr and pthread_mutex functions. */ +/* ---------------------------------------------------------------------------- */ + +/* pthread_mutexattr functions */ +int pthread_mutexattr_init(pthread_mutexattr_t *__attr); +int pthread_mutexattr_destroy(pthread_mutexattr_t *__attr); + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict __attr, int *__restrict __type); +int pthread_mutexattr_settype(pthread_mutexattr_t *__attr, int __type); + +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict __attr, int *__restrict __robust); +int pthread_mutexattr_setrobust(pthread_mutexattr_t *__attr, int __robust); + +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__attr, int *__pshared); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *__attr, int __pshared); + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict __attr, int *__restrict __protocol); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *__attr, int __protocol); + +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__attr, int *__prioceiling); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *__attr, int __prioceiling); + +/* pthread_mutex functions */ +int pthread_mutex_init(pthread_mutex_t *__restrict __mtx, const pthread_mutexattr_t *__restrict __attr); +int pthread_mutex_destroy(pthread_mutex_t *__mtx); + +int pthread_mutex_lock(pthread_mutex_t *__mtx); +int pthread_mutex_trylock(pthread_mutex_t *__mtx); +int pthread_mutex_timedlock(pthread_mutex_t *__restrict __mtx, + const struct timespec *__restrict __abs_timeout); +int pthread_mutex_unlock(pthread_mutex_t *__mtx); + +int pthread_mutex_consistent(pthread_mutex_t *__mtx); + +/* ---------------------------------------------------------------------------- */ +/* pthread_condattr and pthread_cond functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_condattr_init(pthread_condattr_t *__attr); +int pthread_condattr_destroy(pthread_condattr_t *__attr); + +int pthread_condattr_getclock(const pthread_condattr_t *__restrict __attr, clockid_t *__restrict __clockid); +int pthread_condattr_setclock(pthread_condattr_t *__attr, clockid_t __clockid); + +int pthread_condattr_getpshared(const pthread_condattr_t *__restrict __attr, int *__restrict __pshared); +int pthread_condattr_setpshared(pthread_condattr_t *__attr, int __pshared); + +int pthread_cond_init(pthread_cond_t *__restrict __cond, const pthread_condattr_t *__restrict __attr); +int pthread_cond_destroy(pthread_cond_t *__cond); + +int pthread_cond_wait(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mtx); +int pthread_cond_timedwait(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mtx, + const struct timespec *__restrict __abs_timeout); +int pthread_cond_signal(pthread_cond_t *__cond); +int pthread_cond_broadcast(pthread_cond_t *__cond); + +/* ---------------------------------------------------------------------------- */ +/* pthread_barrierattr and pthread_barrier functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_barrierattr_init(pthread_barrierattr_t *__attr); +int pthread_barrierattr_destroy(pthread_barrierattr_t *__attr); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *__attr, int __pshared); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict __attr, + int *__restrict __pshared); + +int pthread_barrier_init(pthread_barrier_t *__restrict __barrier, const pthread_barrierattr_t *__restrict __attr, + unsigned int __count); +int pthread_barrier_destroy(pthread_barrier_t *__barrier); + +int pthread_barrier_wait(pthread_barrier_t *__barrier); + +/* ---------------------------------------------------------------------------- */ +/* pthread_wrlockattr and pthread_rwlock functions. */ +/* ---------------------------------------------------------------------------- */ + +int pthread_rwlockattr_init(pthread_rwlockattr_t *__attr); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *__attr); +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *__attr, int __pshared); +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict __attr, + int *__restrict __pshared); + +int pthread_rwlock_init(pthread_rwlock_t *__restrict __rwlock, const pthread_rwlockattr_t *__restrict __attr); +int pthread_rwlock_destroy(pthread_rwlock_t *__rwlock); +int pthread_rwlock_trywrlock(pthread_rwlock_t *__rwlock); +int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock); +int pthread_rwlock_tryrdlock(pthread_rwlock_t *__rwlock); +int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock); +int pthread_rwlock_unlock(pthread_rwlock_t *__rwlock); + +int pthread_getcpuclockid(pthread_t __thrd, clockid_t *__clockid); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PTHREAD_H */ + diff --git a/user/include/mlibc/options/posix/include/pwd.h b/user/include/mlibc/options/posix/include/pwd.h new file mode 100644 index 0000000..fd4f9c4 --- /dev/null +++ b/user/include/mlibc/options/posix/include/pwd.h @@ -0,0 +1,45 @@ + +#ifndef _PWD_H +#define _PWD_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct passwd { + char *pw_name; + char *pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + char *pw_gecos; + char *pw_dir; + char *pw_shell; +}; + +#define NSS_BUFLEN_PASSWD 512 + +#ifndef __MLIBC_ABI_ONLY + +void endpwent(void); +struct passwd *getpwent(void); +struct passwd *getpwnam(const char *__name); +int getpwnam_r(const char *__name, struct passwd *__ret, char *__buf, size_t __buflen, struct passwd **__res); +struct passwd *getpwuid(uid_t __uid); +int getpwuid_r(uid_t __uid, struct passwd *__ret, char *__buf, size_t __buflen, struct passwd **__res); +void setpwent(void); +int putpwent(const struct passwd *__pwd, FILE *__f); +struct passwd *fgetpwent(FILE *__f); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PWD_H */ + diff --git a/user/include/mlibc/options/posix/include/regex.h b/user/include/mlibc/options/posix/include/regex.h new file mode 100644 index 0000000..8a2c827 --- /dev/null +++ b/user/include/mlibc/options/posix/include/regex.h @@ -0,0 +1,67 @@ +#ifndef _REGEX_H +#define _REGEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef ptrdiff_t regoff_t; + +typedef struct re_pattern_buffer { + size_t re_nsub; + void *__opaque, *__padding[4]; + size_t __nsub2; + char __padding2; +} regex_t; + +typedef struct { + regoff_t rm_so; + regoff_t rm_eo; +} regmatch_t; + +/* Flags for regcomp(). */ +#define REG_EXTENDED 1 +#define REG_ICASE 2 +#define REG_NEWLINE 4 +#define REG_NOSUB 8 + +/* Flags for regexec(). */ +#define REG_NOTBOL 1 +#define REG_NOTEOL 2 + +/* Errors for regcomp() and regexec(). */ +#define REG_OK 0 +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 + +/* Obsolete in POSIX. */ +#define REG_ENOSYS -1 + +#ifndef __MLIBC_ABI_ONLY + +int regcomp(regex_t *__restrict __regex, const char *__restrict __pattern, int __flags); +int regexec(const regex_t *__restrict __regex, const char *__restrict __string, size_t __nmatch, + regmatch_t *__restrict __pmatch, int __flags); +size_t regerror(int __errcode, const regex_t *__restrict __regex, char *__restrict __errbuf, size_t __errbuf_size); +void regfree(regex_t *__regex); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/posix/include/sched.h b/user/include/mlibc/options/posix/include/sched.h new file mode 100644 index 0000000..0b56215 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sched.h @@ -0,0 +1,50 @@ + +#ifndef _SCHED_H +#define _SCHED_H + +#include +#include +#include +#include + +/* MISSING: time_t, struct timespec */ + +/* MISSING: POSIX [PS], [SS] and [TSP] options */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if __MLIBC_LINUX_OPTION +#include +#include +#endif + +#define SCHED_OTHER 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 +#define SCHED_BATCH 3 +#define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 +#define SCHED_RESET_ON_FORK 0x40000000 + +#ifndef __MLIBC_ABI_ONLY + +int sched_yield(void); + +int sched_get_priority_max(int __policy); +int sched_get_priority_min(int __policy); + +int sched_setscheduler(pid_t __pid, int __policy, const struct sched_param *__param); + +int sched_getparam(pid_t __pid, struct sched_param *__param); +int sched_setparam(pid_t __pid, const struct sched_param *__param); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SCHED_H */ + diff --git a/user/include/mlibc/options/posix/include/search.h b/user/include/mlibc/options/posix/include/search.h new file mode 100644 index 0000000..39174b5 --- /dev/null +++ b/user/include/mlibc/options/posix/include/search.h @@ -0,0 +1,47 @@ + +#ifndef _SEARCH_H +#define _SEARCH_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + preorder, + postorder, + endorder, + leaf +} VISIT; + +#if __MLIBC_GLIBC_OPTION && defined(_GNU_SOURCE) +#include +#endif + +#ifndef __MLIBC_ABI_ONLY + +void *tsearch(const void *__key, void **__root, int(*__compar)(const void *__a, const void *__b)); +void *tfind(const void *__key, void *const *__root, int (*__compar)(const void *__a, const void *__b)); +void *tdelete(const void *__key, void **__root, int(*__compar)(const void * __a, const void *__b)); +void twalk(const void *__key, void (*__action)(const void *__node, VISIT __which, int __depth)); +void tdestroy(void *__root, void (*__free_node)(void *__node)); + +void *lsearch(const void *__key, void *__base, size_t *__nelp, size_t __width, + int (*__compar)(const void *__a, const void *__b)); +void *lfind(const void *__key, const void *__base, size_t *__nelp, + size_t __width, int (*__compar)(const void *__a, const void *__b)); + +int hcreate(size_t __num_entries); +void hdestroy(void); +ENTRY *hsearch(ENTRY __item, ACTION __action); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SEARCH_H */ diff --git a/user/include/mlibc/options/posix/include/semaphore.h b/user/include/mlibc/options/posix/include/semaphore.h new file mode 100644 index 0000000..8960150 --- /dev/null +++ b/user/include/mlibc/options/posix/include/semaphore.h @@ -0,0 +1,37 @@ +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define SEM_VALUE_MAX 0x7FFFFFFF +#define SEM_FAILED ((sem_t *) 0) + +typedef struct sem_ { + unsigned int __mlibc_count; +} sem_t; + +#ifndef __MLIBC_ABI_ONLY + +int sem_init(sem_t *__sem, int __pshared, unsigned int __initial_count); +sem_t *sem_open(const char *__name, int __oflag, ...); +int sem_close(sem_t *__sem); +int sem_unlink(const char *__name); +int sem_destroy(sem_t *__sem); +int sem_wait(sem_t *__sem); +int sem_trywait(sem_t *__sem); +int sem_timedwait(sem_t *__sem, const struct timespec *__abstime); +int sem_post(sem_t *__sem); +int sem_getvalue(sem_t *__sem, int *__sval); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /*_SEMAPHORE_H */ diff --git a/user/include/mlibc/options/posix/include/spawn.h b/user/include/mlibc/options/posix/include/spawn.h new file mode 100644 index 0000000..ec5d938 --- /dev/null +++ b/user/include/mlibc/options/posix/include/spawn.h @@ -0,0 +1,82 @@ + +#ifndef _SPAWN_H +#define _SPAWN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int __flags; + pid_t __pgrp; + sigset_t __def, __mask; + int __prio, __pol; + void *__fn; + char __pad[64 - sizeof(void *)]; +} posix_spawnattr_t; + +typedef struct { + int __pad0[2]; + void *__actions; + int __pad[16]; +} posix_spawn_file_actions_t; + +/* MISSIG: sigset_t */ + +struct sched_param; + +#define POSIX_SPAWN_RESETIDS 1 +#define POSIX_SPAWN_SETPGROUP 2 +#define POSIX_SPAWN_SETSIGDEF 4 +#define POSIX_SPAWN_SETSIGMASK 8 +#define POSIX_SPAWN_SETSCHEDPARAM 16 +#define POSIX_SPAWN_SETSCHEDULER 32 +#define POSIX_SPAWN_USEVFORK 64 +#define POSIX_SPAWN_SETSID 128 + +#ifndef __MLIBC_ABI_ONLY + +int posix_spawn(pid_t *__restrict __pid, const char *__restrict __path, + const posix_spawn_file_actions_t *__file_actions, + const posix_spawnattr_t *__restrict __attrs, + char *const __argv[], char *const __envp[]); + +int posix_spawnattr_init(posix_spawnattr_t *__attr); +int posix_spawnattr_destroy(posix_spawnattr_t *__attr); +int posix_spawnattr_setflags(posix_spawnattr_t *__attr, short __flags); +int posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict __attr, + const sigset_t *__restrict __sigdefault); +int posix_spawnattr_setschedparam(posix_spawnattr_t *__restrict __attr, + const struct sched_param *__restrict __schedparam); +int posix_spawnattr_setschedpolicy(posix_spawnattr_t *__attr, int __schedpolicy); +int posix_spawnattr_setsigmask(posix_spawnattr_t *__restrict __attr, + const sigset_t *__restrict __sigmask); +int posix_spawnattr_setpgroup(posix_spawnattr_t *__attr, pid_t __pgroup); +int posix_spawn_file_actions_init(posix_spawn_file_actions_t *__file_actions); +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *__file_actions); +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *__file_actions, + int __fildes, int __newfildes); +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *__file_actions, + int __fildes); +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *__restrict __file_actions, + int __fildes, const char *__restrict __path, int __oflag, mode_t __mode); +int posix_spawnp(pid_t *__restrict __pid, const char *__restrict __file, + const posix_spawn_file_actions_t *__file_actions, + const posix_spawnattr_t *__restrict __attrp, + char *const __argv[], char *const __envp[]); + +/* MISSING: all other functions */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* SPAWN_H */ + diff --git a/user/include/mlibc/options/posix/include/strings.h b/user/include/mlibc/options/posix/include/strings.h new file mode 100644 index 0000000..1a49114 --- /dev/null +++ b/user/include/mlibc/options/posix/include/strings.h @@ -0,0 +1,33 @@ + +#ifndef _STRINGS_H +#define _STRINGS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *index (const char *__s, int __c); +char *rindex(const char *__s, int __c); + +int ffs(int __word); +int strcasecmp(const char *__a, const char *__b); +int strncasecmp(const char *__a, const char *__b, size_t __size); + +/* Marked as obsolete in posix 2008 but used by at least tracker */ +int bcmp(const void *__s1, const void *__s2, size_t __n); +void bcopy(const void *__s1, void *__s2, size_t __n); +void bzero(void *__s, size_t __n); +void explicit_bzero(void *__s, size_t __len); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _STRINGS_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/fcntl.h b/user/include/mlibc/options/posix/include/sys/fcntl.h new file mode 100644 index 0000000..cd30455 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/fcntl.h @@ -0,0 +1 @@ +#include diff --git a/user/include/mlibc/options/posix/include/sys/file.h b/user/include/mlibc/options/posix/include/sys/file.h new file mode 100644 index 0000000..11dff16 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/file.h @@ -0,0 +1,26 @@ + +#ifndef _SYS_FILE_H +#define _SYS_FILE_H + +#define LOCK_SH 1 +#define LOCK_EX 2 +#define LOCK_NB 4 +#define LOCK_UN 8 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int flock(int __fd, int __op); +int flock64(int __fd, int __op); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_FILE_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/ipc.h b/user/include/mlibc/options/posix/include/sys/ipc.h new file mode 100644 index 0000000..d6cd429 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/ipc.h @@ -0,0 +1,20 @@ +#ifndef _SYS_IPC_H +#define _SYS_IPC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +key_t ftok(const char *__path, int __proj_id); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/posix/include/sys/mman.h b/user/include/mlibc/options/posix/include/sys/mman.h new file mode 100644 index 0000000..3d17b30 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/mman.h @@ -0,0 +1,46 @@ +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +void *mmap(void *__addr, size_t __size, int __prot, int __flags, int __fd, off_t __offset); +void *mmap64(void *__addr, size_t __size, int __prot, int __flags, int __fd, off64_t __offset); +int mprotect(void *__addr, size_t __size, int __prot); +int munmap(void *__addr, size_t __size); + +int mlock(const void *__addr, size_t __size); +int mlockall(int __flags); +int munlock(const void *__addr, size_t __size); +int munlockall(void); + +int posix_madvise(void *__addr, size_t __size, int __advise); +int msync(void *__addr, size_t __size, int __flags); + +int shm_open(const char *__name, int __oflag, mode_t __mode); +int shm_unlink(const char *__name); + +#if __MLIBC_LINUX_OPTION +void *mremap(void *__old_address, size_t __old_size, size_t __new_size, int __flags, ...); +int remap_file_pages(void *__addr, size_t __size, int __prot, size_t __pgoff, int __flags); +int memfd_create(const char *__name, unsigned int __flags); +int madvise(void *__addr, size_t __size, int __advise); +int mincore(void *__addr, size_t __size, unsigned char *__vec); +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MMAN_H */ diff --git a/user/include/mlibc/options/posix/include/sys/msg.h b/user/include/mlibc/options/posix/include/sys/msg.h new file mode 100644 index 0000000..f62220a --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/msg.h @@ -0,0 +1,27 @@ +#ifndef _SYS_MSG_H +#define _SYS_MSG_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int msgget(key_t __key, int __msgflg); + +int msgctl(int __msqid, int __cmd, struct msqid_ds *__buf); + +ssize_t msgrcv(int __msqid, void *__msgp, size_t __size, long __msgtyp, int __msgflg); +int msgsnd(int __msqid, const void *__msgp, size_t __size, int __msgflg); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MSG_H */ diff --git a/user/include/mlibc/options/posix/include/sys/param.h b/user/include/mlibc/options/posix/include/sys/param.h new file mode 100644 index 0000000..b2c7d71 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/param.h @@ -0,0 +1,35 @@ + +#ifndef _SYS_PARAM_H +#define _SYS_PARAM_H + +#include +#include + +#define NBBY CHAR_BIT +#define NGROUPS NGROUPS_MAX + +/* Report the same value as Linux here. */ +#define MAXNAMLEN 255 +#define MAXPATHLEN 4096 +#define MAXSYMLINKS 20 +#define MAXHOSTNAMELEN HOST_NAME_MAX + +#ifdef __cplusplus +extern "C" { +#endif + +#undef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#undef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define howmany(x, y) (((x) + ((y) - 1)) / (y)) + +#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PARAM_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/poll.h b/user/include/mlibc/options/posix/include/sys/poll.h new file mode 100644 index 0000000..bebe627 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/poll.h @@ -0,0 +1,38 @@ +#ifndef _SYS_POLL_H +#define _SYS_POLL_H + +#include +#include +#include +#include +#include +#include + +typedef __mlibc_size nfds_t; + +#ifdef __cplusplus +extern "C" { +#endif + +struct pollfd { + int fd; + short events; + short revents; +}; + +#ifndef __MLIBC_ABI_ONLY + +int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout); + +#if __MLIBC_LINUX_OPTION +int ppoll(struct pollfd *__fds, nfds_t __nfds, + const struct timespec *__timeout_ts, const sigset_t *__sigmask); +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_POLL_H */ diff --git a/user/include/mlibc/options/posix/include/sys/resource.h b/user/include/mlibc/options/posix/include/sys/resource.h new file mode 100644 index 0000000..1259a4e --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/resource.h @@ -0,0 +1,53 @@ +#ifndef _SYS_RESOURCE_H +#define _SYS_RESOURCE_H + +#include +#include +#include +#include +#include +#include +#include + +#define PRIO_PROCESS 1 +#define PRIO_PGRP 2 +#define PRIO_USER 3 + +#define PRIO_MIN (-20) +#define PRIO_MAX 20 + +#define RLIM_INFINITY ((rlim_t)-1) +#define RLIM_SAVED_MAX ((rlim_t)-1) +#define RLIM_SAVED_CUR ((rlim_t)-1) + +#define RLIM_NLIMITS RLIMIT_NLIMITS + +#ifdef __cplusplus +extern "C" { +#endif + +struct rlimit { + rlim_t rlim_cur; + rlim_t rlim_max; +}; + +#ifndef __MLIBC_ABI_ONLY + +int getpriority(int __which, id_t __who); +int setpriority(int __which, id_t __who, int __prio); + +int getrusage(int __who, struct rusage *__usage); +int getrlimit(int __resource, struct rlimit *__rlim); +int getrlimit64(int __resource, struct rlimit *__rlim); +int setrlimit(int __resource, const struct rlimit *__rlim); +int setrlimit64(int __resource, const struct rlimit *__rlim); + +int prlimit(pid_t __pid, int __resource, const struct rlimit *__new_limits, struct rlimit *__old_limits); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_RESOURCE_H */ diff --git a/user/include/mlibc/options/posix/include/sys/select.h b/user/include/mlibc/options/posix/include/sys/select.h new file mode 100644 index 0000000..10d1a34 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/select.h @@ -0,0 +1,49 @@ + +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H + +#include + +#include +#include +#include +#include +#include + +#define FD_SETSIZE 1024 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long int __fd_mask; +#define __NFDBITS (8 * (int) sizeof (__fd_mask)) + +typedef __fd_mask fd_mask; +#define NFDBITS __NFDBITS + +#ifndef __MLIBC_ABI_ONLY + +void __FD_CLR(int __fd, fd_set *__set); +int __FD_ISSET(int __fd, fd_set *__set); +void __FD_SET(int __fd, fd_set *__set); +void __FD_ZERO(fd_set *__set); + +#define FD_CLR(fd, set) __FD_CLR(fd, set) +#define FD_ISSET(fd, set) __FD_ISSET(fd, set) +#define FD_SET(fd, set) __FD_SET(fd, set) +#define FD_ZERO(set) __FD_ZERO(set) + +int select(int __nfds, fd_set *__restrict __readfds, fd_set *__restrict __writefds, + fd_set *__restrict __exceptfds, struct timeval *__restrict __timeout); +int pselect(int __nfds, fd_set *__restrict __readfds, fd_set *__restrict __writefds, + fd_set *__exceptfds, const struct timespec *__timeout, const sigset_t *__sigmask); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SELECT_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/sem.h b/user/include/mlibc/options/posix/include/sys/sem.h new file mode 100644 index 0000000..d98f91f --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/sem.h @@ -0,0 +1,46 @@ +#ifndef _SYS_SEM_H +#define _SYS_SEM_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GETPID 11 +#define GETVAL 12 +#define GETALL 13 +#define SETVAL 16 +#define SETALL 17 + +#define SEM_UNDO 0x1000 + +struct sembuf { + unsigned short int sem_num; + short int sem_op; + short int sem_flg; +}; + +struct semid_ds { + struct ipc_perm sem_perm; + time_t sem_otime; + time_t sem_ctime; + + unsigned long sem_nsems; +}; + +#ifndef __MLIBC_ABI_ONLY + +int semget(key_t __key, int __nsems, int __semflg); +int semop(int __semid, struct sembuf *__sops, size_t __nsops); +int semctl(int __semid, int __semnum, int __op, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SEM_H */ diff --git a/user/include/mlibc/options/posix/include/sys/shm.h b/user/include/mlibc/options/posix/include/sys/shm.h new file mode 100644 index 0000000..21625be --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/shm.h @@ -0,0 +1,28 @@ +#ifndef _SYS_SHM_H +#define _SYS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#include + +#ifndef __MLIBC_ABI_ONLY + +void *shmat(int __shmid, const void *__shmaddr, int __shmflg); +int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf); +int shmdt(const void *__shmaddr); +int shmget(key_t __key, size_t __size, int __shmflg); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SHM_H */ diff --git a/user/include/mlibc/options/posix/include/sys/socket.h b/user/include/mlibc/options/posix/include/sys/socket.h new file mode 100644 index 0000000..69871ee --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/socket.h @@ -0,0 +1,107 @@ + +#ifndef _SOCKET_H +#define _SOCKET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sockaddr { + sa_family_t sa_family; + char sa_data[14]; +}; + +/* Control message format: */ +/* The offsets marked with ^ are aligned to alignof(size_t). */ +/* */ +/* |---HEADER---|---DATA---|---PADDING---|---HEADER---|... */ +/* ^ ^ ^ */ +/* |---------CMSG_LEN------| */ +/* |---------------CMSG_SPACE------------| */ + +/* Auxiliary macro. While there is basically no reason for applications */ +/* to use this, it is exported by glibc. */ +#define CMSG_ALIGN(s) (((s) + __alignof__(size_t) - 1) & \ + ~(__alignof__(size_t) - 1)) + +/* Basic macros to return content and padding size of a control message. */ +#define CMSG_LEN(s) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (s)) +#define CMSG_SPACE(s) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(s)) + +/* Provides access to the data of a control message. */ +#define CMSG_DATA(c) ((char *)(c) + CMSG_ALIGN(sizeof(struct cmsghdr))) + +#define __MLIBC_CMSG_NEXT(c) ((char *)(c) + CMSG_ALIGN((c)->cmsg_len)) +#define __MLIBC_MHDR_LIMIT(m) ((char *)(m)->msg_control + (m)->msg_controllen) + +/* For parsing control messages only. */ +/* Returns a pointer to the first header or nullptr if there is none. */ +#define CMSG_FIRSTHDR(m) ((size_t)(m)->msg_controllen <= sizeof(struct cmsghdr) \ + ? (struct cmsghdr *)0 : (struct cmsghdr *) (m)->msg_control) + +/* For parsing control messages only. */ +/* Returns a pointer to the next header or nullptr if there is none. */ +#define CMSG_NXTHDR(m, c) \ + ((c)->cmsg_len < sizeof(struct cmsghdr) || \ + (ptrdiff_t)(sizeof(struct cmsghdr) + CMSG_ALIGN((c)->cmsg_len)) \ + >= __MLIBC_MHDR_LIMIT(m) - (char *)(c) \ + ? (struct cmsghdr *)0 : (struct cmsghdr *)__MLIBC_CMSG_NEXT(c)) + +struct linger{ + int l_onoff; + int l_linger; +}; + +struct ucred { + pid_t pid; + uid_t uid; + gid_t gid; +}; + +#ifndef __MLIBC_ABI_ONLY + +int accept(int __sockfd, struct sockaddr *__restrict __addr, socklen_t *__restrict __addrlen); +int accept4(int __sockfd, struct sockaddr *__restrict __addr, socklen_t *__restrict __addrlen, int __flags); +int bind(int __sockfd, const struct sockaddr *__addr, socklen_t __addrlen); +int connect(int __sockfd, const struct sockaddr *__addr, socklen_t __addrlen); +int getpeername(int __sockfd, struct sockaddr *__restrict __addr, socklen_t *__restrict __addrlen); +int getsockname(int __sockfd, struct sockaddr *__restrict __addr, socklen_t *__restrict __addrlen); +int getsockopt(int __sockfd, int __level, int __optname, void *__restrict __optval, socklen_t *__restrict __optlen); +int listen(int __sockfd, int __backlog); +ssize_t recv(int __sockfd, void *__buf, size_t __size, int __flags); +ssize_t recvfrom(int __sockfd, void *__restrict __buf, size_t __size, int __flags, + struct sockaddr *__restrict __src_addr, socklen_t *__restrict __addrlen); +ssize_t recvmsg(int __sockfd, struct msghdr *__msg, int __flags); +ssize_t send(int __sockfd, const void *__buf, size_t __size, int __flags); +ssize_t sendmsg(int __sockfd, const struct msghdr *__msg, int __flags); +ssize_t sendto(int __sockfd, const void *__buf, size_t __size, int __flags, + const struct sockaddr *__dest_addr, socklen_t __addrlen); +int recvmmsg(int __sockfd, struct mmsghdr *__msgvec, unsigned int __vlen, int __flags, struct timespec *__timeout); +int sendmmsg(int __sockfd, struct mmsghdr *__msgvec, unsigned int __vlen, int __flags); +int setsockopt(int __sockfd, int __level, int __option_name, const void *__optval, socklen_t __optlen); +int shutdown(int __sockfd, int __how); +int sockatmark(int __sockfd); +int socket(int __domain, int __type, int __protocol); +int socketpair(int __domain, int __type, int __protocol, int __sv[2]); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UNISTD_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/stat.h b/user/include/mlibc/options/posix/include/sys/stat.h new file mode 100644 index 0000000..98f1d2a --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/stat.h @@ -0,0 +1,44 @@ + +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include +#include + +#if __MLIBC_LINUX_OPTION +#include +#endif /* !__MLIBC_LINUX_OPTION */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int chmod(const char *__pathname, mode_t __mode); +int fchmod(int __fd, mode_t __mode); +int fchmodat(int __fd, const char *__pathname, mode_t __mode, int __flags); +int fstat(int __fd, struct stat *__result); +int fstat64(int __fd, struct stat64 *__result); +int fstatat(int __fd, const char *__restrict __pathname, struct stat *__restrict __buf, int __flags); +int futimens(int __fd, const struct timespec __times[2]); +int lstat(const char *__restrict __pathname, struct stat *__restrict __buf); +int lstat64(const char *__restrict __pathname, struct stat64 *__restrict __buf); +int mkdir(const char *__pathname, mode_t __mode); +int mkdirat(int __dirfd, const char *__pathname, mode_t __mode); +int mkfifo(const char *__pathname, mode_t __mode); +int mkfifoat(int __dirfd, const char *__pathname, mode_t __mode); +int mknod(const char *__pathname, mode_t __mode, dev_t __dev); +int mknodat(int __dirfd, const char *__pathname, mode_t __mode, dev_t __dev); +int stat(const char *__restrict __pathname, struct stat *__restrict __buf); +mode_t umask(mode_t __mode); +int utimensat(int __dirfd, const char *__pathname, const struct timespec __times[2], int __flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_STAT_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/statvfs.h b/user/include/mlibc/options/posix/include/sys/statvfs.h new file mode 100644 index 0000000..03e65a3 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/statvfs.h @@ -0,0 +1,24 @@ +#ifndef _SYS_STATVFS_H +#define _SYS_STATVFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int statvfs(const char *__restrict __pathname, struct statvfs *__restrict __buf); +int statvfs64(const char *__restrict __pathname, struct statvfs64 *__restrict __buf); +int fstatvfs(int __fd, struct statvfs *__buf); +int fstatvfs64(int __fd, struct statvfs64 *__buf); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_STATVFS_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/syslog.h b/user/include/mlibc/options/posix/include/sys/syslog.h new file mode 100644 index 0000000..7761ece --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/syslog.h @@ -0,0 +1 @@ +#include diff --git a/user/include/mlibc/options/posix/include/sys/termios.h b/user/include/mlibc/options/posix/include/sys/termios.h new file mode 100644 index 0000000..2176780 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/termios.h @@ -0,0 +1,6 @@ + +#ifndef _SYS_TERMIOS_H +#define _SYS_TERMIOS_H +#include +#endif /* _SYS_TERMIOS_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/time.h b/user/include/mlibc/options/posix/include/sys/time.h new file mode 100644 index 0000000..29b8212 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/time.h @@ -0,0 +1,62 @@ +#ifndef _SYS_TIME_H +#define _SYS_TIME_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +#ifndef __MLIBC_ABI_ONLY + +/* TODO: this function is [OB]. disable it by default and add a macro to enable it */ +int gettimeofday(struct timeval *__restrict __result, void *__restrict __unused); +int settimeofday(const struct timeval *__result, const struct timezone *__zone); + +void timeradd(const struct timeval *__a, const struct timeval *__b, struct timeval *__res); +void timersub(const struct timeval *__a, const struct timeval *__b, struct timeval *__res); +void timerclear(struct timeval *__tvp); +int timerisset(struct timeval *__tvp); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* timercmp taken from musl */ +#define timercmp(s,t,op) ((s)->tv_sec == (t)->tv_sec ? \ + (s)->tv_usec op (t)->tv_usec : (s)->tv_sec op (t)->tv_sec) + +#ifndef __MLIBC_ABI_ONLY + +int getitimer(int __which, struct itimerval *__curr_value); +int setitimer(int __which, const struct itimerval *__new_value, + struct itimerval *__old_value); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* The following 2 macros are taken from musl */ +#define TIMEVAL_TO_TIMESPEC(tv, ts) ( \ + (ts)->tv_sec = (tv)->tv_sec, \ + (ts)->tv_nsec = (tv)->tv_usec * 1000, \ + (void)0 ) +#define TIMESPEC_TO_TIMEVAL(tv, ts) ( \ + (tv)->tv_sec = (ts)->tv_sec, \ + (tv)->tv_usec = (ts)->tv_nsec / 1000, \ + (void)0 ) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIME_H */ diff --git a/user/include/mlibc/options/posix/include/sys/times.h b/user/include/mlibc/options/posix/include/sys/times.h new file mode 100644 index 0000000..96556bc --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/times.h @@ -0,0 +1,28 @@ +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H + +/* TODO: Only define the clock_t type. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct tms { + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; + +#ifndef __MLIBC_ABI_ONLY + +clock_t times(struct tms *__tms); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIMES_H */ diff --git a/user/include/mlibc/options/posix/include/sys/ttydefaults.h b/user/include/mlibc/options/posix/include/sys/ttydefaults.h new file mode 100644 index 0000000..8ed811f --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/ttydefaults.h @@ -0,0 +1,39 @@ + +#ifndef _SYS_TTYDEFAULTS_H +#define _SYS_TTYDEFAULTS_H + +/* Values taken from musl */ + +#define TTYDEF_IFLAG (BRKINT | ISTRIP | ICRNL | IMAXBEL | IXON | IXANY) +#define TTYDEF_OFLAG (OPOST | ONLCR | XTABS) +#define TTYDEF_LFLAG (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL) +#define TTYDEF_CFLAG (CREAD | CS7 | PARENB | HUPCL) +#define TTYDEF_SPEED (B9600) + +#define CTRL(x) ((x) & 037) +#define CEOF CTRL('d') + +#define CEOL '\0' +#define CEOL2 '\0' +#define CSTATUS '\0' + +#define CERASE 0177 +#define CINTR CTRL('c') +#define CKILL CTRL('u') +#define CMIN 1 +#define CQUIT 034 +#define CSUSP CTRL('z') +#define CTIME 0 +#define CDSUSP CTRL('y') +#define CSTART CTRL('q') +#define CSTOP CTRL('s') +#define CLNEXT CTRL('v') +#define CDISCARD CTRL('o') +#define CWERASE CTRL('w') +#define CREPRINT CTRL('r') +#define CEOT CEOF +#define CBRK CEOL +#define CRPRNT CREPRINT +#define CFLUSH CDISCARD + +#endif /* _SYS_TTYDEFAULTS_H */ diff --git a/user/include/mlibc/options/posix/include/sys/types.h b/user/include/mlibc/options/posix/include/sys/types.h new file mode 100644 index 0000000..41f6ebc --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/types.h @@ -0,0 +1,53 @@ + +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +typedef unsigned int u_int; +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned long int u_long; +typedef char *caddr_t; +typedef off64_t loff_t; + +typedef unsigned long int ulong; +typedef unsigned short int ushort; +typedef unsigned int uint; + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; + +/* BSD extensions */ +typedef int64_t quad_t; +typedef uint64_t u_quad_t; + +#endif /* _SYS_TYPES_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/uio.h b/user/include/mlibc/options/posix/include/sys/uio.h new file mode 100644 index 0000000..422a7f6 --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/uio.h @@ -0,0 +1,37 @@ +#ifndef _SYS_UIO_H +#define _SYS_UIO_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UIO_MAXIOV IOV_MAX + +#ifndef __MLIBC_ABI_ONLY + +ssize_t readv(int __fd, const struct iovec *__iov, int __iovcnt); +ssize_t writev(int __fd, const struct iovec *__iov, int __iovcnt); + +/* Non standard extensions, also found on modern BSD's */ +ssize_t preadv(int __fd, const struct iovec *__iov, int __iovcnt, off_t __offset); +ssize_t pwritev(int __fd, const struct iovec *__iov, int __iovcnt, off_t __offset); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_LINUX_OPTION +#include +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _SYS_UIO_H */ diff --git a/user/include/mlibc/options/posix/include/sys/un.h b/user/include/mlibc/options/posix/include/sys/un.h new file mode 100644 index 0000000..7a0093e --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/un.h @@ -0,0 +1,24 @@ + +#ifndef _SYS_UN_H +#define _SYS_UN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; + +/* Evaluate to actual length of the `sockaddr_un' structure. */ +#define SUN_LEN(ptr) ((size_t) offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_UN_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/utsname.h b/user/include/mlibc/options/posix/include/sys/utsname.h new file mode 100644 index 0000000..5ae31de --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/utsname.h @@ -0,0 +1,22 @@ + +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int uname(struct utsname *__name); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_UTSNAME_H */ + diff --git a/user/include/mlibc/options/posix/include/sys/wait.h b/user/include/mlibc/options/posix/include/sys/wait.h new file mode 100644 index 0000000..16e816f --- /dev/null +++ b/user/include/mlibc/options/posix/include/sys/wait.h @@ -0,0 +1,40 @@ + +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include +#include +/* for siginfo_t */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* According to POSIX, does not make rusage available. */ +struct rusage; + +/* TODO: move to own file and include in sys/types.h */ +typedef enum { + P_ALL, P_PID, P_PGID, P_PIDFD +} idtype_t; + +#ifndef __MLIBC_ABI_ONLY + +pid_t wait(int *__status); +int waitid(idtype_t __idtype, id_t __id, siginfo_t *__siginfo, int __flags); +pid_t waitpid(pid_t __pid, int *__status, int __flags); + +/* GNU extensions. */ +pid_t wait3(int *__status, int __options, struct rusage *__ru); +pid_t wait4(pid_t __pid, int *__status, int __options, struct rusage *__ru); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_WAIT_H */ + diff --git a/user/include/mlibc/options/posix/include/syslog.h b/user/include/mlibc/options/posix/include/syslog.h new file mode 100644 index 0000000..971ada6 --- /dev/null +++ b/user/include/mlibc/options/posix/include/syslog.h @@ -0,0 +1,137 @@ + +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOG_PID 0x01 +#define LOG_CONS 0x02 +#define LOG_NDELAY 0x08 +#define LOG_ODELAY 0x04 +#define LOG_NOWAIT 0x10 +#define LOG_PERROR 0x20 + +#define LOG_KERN (0<<3) +#define LOG_USER (1<<3) +#define LOG_MAIL (2<<3) +#define LOG_DAEMON (3<<3) +#define LOG_AUTH (4<<3) +#define LOG_SYSLOG (5<<3) +#define LOG_LPR (6<<3) +#define LOG_NEWS (7<<3) +#define LOG_UUCP (8<<3) +#define LOG_CRON (9<<3) +#define LOG_AUTHPRIV (10<<3) +#define LOG_FTP (11<<3) + +#define LOG_LOCAL0 (16<<3) +#define LOG_LOCAL1 (17<<3) +#define LOG_LOCAL2 (18<<3) +#define LOG_LOCAL3 (19<<3) +#define LOG_LOCAL4 (20<<3) +#define LOG_LOCAL5 (21<<3) +#define LOG_LOCAL6 (22<<3) +#define LOG_LOCAL7 (23<<3) + +#define LOG_PRIMASK 7 +#define LOG_PRI(p) ((p)&LOG_PRIMASK) +#define LOG_MAKEPRI(f, p) (((f)<<3) | (p)) +#define LOG_MASK(p) (1<<(p)) +#define LOG_UPTO(p) ((1<<((p)+1))-1) +#define LOG_NFACILITIES 24 +#define LOG_FACMASK (0x7F<<3) +#define LOG_FAC(p) (((p)&LOG_FACMASK)>>3) + +#define LOG_EMERG 0 +#define LOG_ALERT 1 +#define LOG_CRIT 2 +#define LOG_ERR 3 +#define LOG_WARNING 4 +#define LOG_NOTICE 5 +#define LOG_INFO 6 +#define LOG_DEBUG 7 + +#if __MLIBC_BSD_OPTION +#if defined(SYSLOG_NAMES) +#define INTERNAL_NOPRI 0x10 +#define INTERNAL_MARK LOG_MAKEPRI(LOG_NFACILITIES << 3, 0) + +typedef struct _code { + char *c_name; + int c_val; +} CODE; +#endif /* SYSLOG_NAMES */ +#endif /* __MLIBC_BSD_OPTION */ + +#ifndef __MLIBC_ABI_ONLY + +#if __MLIBC_BSD_OPTION +#if defined(SYSLOG_NAMES) +CODE prioritynames[] = { + { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, + { "debug", LOG_DEBUG }, + { "emerg", LOG_EMERG }, + { "err", LOG_ERR }, + { "error", LOG_ERR }, + { "info", LOG_INFO }, + { "none", INTERNAL_NOPRI }, + { "notice", LOG_NOTICE }, + { "panic", LOG_EMERG }, + { "warn", LOG_WARNING }, + { "warning", LOG_WARNING }, + { NULL, -1 } +}; + +CODE facilitynames[] = { + { "auth", LOG_AUTH }, + { "authpriv", LOG_AUTHPRIV }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "mark", INTERNAL_MARK }, + { "news", LOG_NEWS }, + { "security", LOG_AUTH }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + { NULL, -1 } +}; +#endif /* SYSLOG_NAMES */ +#endif /* __MLIBC_BSD_OPTION */ + +void closelog(void); +void openlog(const char *__ident, int __option, int __facility); +int setlogmask(int __mask); +__attribute__((__format__(__printf__, 2, 3))) +void syslog(int __priority, const char *__format, ...); + +/* This is a linux extension */ +__attribute__((__format__(__printf__, 2, 0))) +void vsyslog(int __priority, const char *__format, va_list __args); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYSLOG_H */ + diff --git a/user/include/mlibc/options/posix/include/termios.h b/user/include/mlibc/options/posix/include/termios.h new file mode 100644 index 0000000..cf2025b --- /dev/null +++ b/user/include/mlibc/options/posix/include/termios.h @@ -0,0 +1,107 @@ + +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#include +#endif + +/* baud rate constants for speed_t */ +#define B0 0 +#define B50 1 +#define B75 2 +#define B110 3 +#define B134 4 +#define B150 5 +#define B200 6 +#define B300 7 +#define B600 8 +#define B1200 9 +#define B1800 10 +#define B2400 11 +#define B4800 12 +#define B9600 13 +#define B19200 14 +#define B38400 15 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 + +/* constants for tcsetattr() */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +/* constants for tcflush() */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* constants for tcflow() */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_RI TIOCM_RNG +#define TIOCM_CD TIOCM_CAR + +#ifndef __MLIBC_ABI_ONLY + +speed_t cfgetispeed(const struct termios *__tios); +speed_t cfgetospeed(const struct termios *__tios); +int cfsetispeed(struct termios *__tios, speed_t __speed); +int cfsetospeed(struct termios *__tios, speed_t __speed); +void cfmakeraw(struct termios *__tios); +int tcdrain(int __fd); +int tcflow(int __fd, int __action); +int tcflush(int __fd, int __queue_selector); +int tcgetattr(int fd, struct termios *__attr); +pid_t tcgetsid(int __fd); +int tcsendbreak(int __fd, int __duration); +int tcsetattr(int __fd, int __optional_actions, const struct termios *__attr); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* This is a linux extension */ + +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCGSID 0x5429 + +#ifdef __cplusplus +} +#endif + +#endif /* _TERMIOS_H */ + diff --git a/user/include/mlibc/options/posix/include/ucontext.h b/user/include/mlibc/options/posix/include/ucontext.h new file mode 100644 index 0000000..6b53906 --- /dev/null +++ b/user/include/mlibc/options/posix/include/ucontext.h @@ -0,0 +1,23 @@ +#ifndef _UCONTEXT_H +#define _UCONTEXT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef __MLIBC_ABI_ONLY + +int getcontext(ucontext_t *__uctx); +int setcontext(const ucontext_t *__uctx); +void makecontext(ucontext_t *__uctx, void (*__fn)(void), int __argc, ...); +int swapcontext(ucontext_t *__uctx, const ucontext_t *__newctx); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _UCONTEXT_H */ diff --git a/user/include/mlibc/options/posix/include/unistd.h b/user/include/mlibc/options/posix/include/unistd.h new file mode 100644 index 0000000..8fcaeab --- /dev/null +++ b/user/include/mlibc/options/posix/include/unistd.h @@ -0,0 +1,410 @@ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H && __MLIBC_LINUX_OPTION +#include +#endif /* __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H && __MLIBC_LINUX_OPTION */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define _POSIX_VERSION 200809L +#define _POSIX2_VERSION _POSIX_VERSION +#define _XOPEN_VERSION 700 + +#define _POSIX_FSYNC _POSIX_VERSION +#define _POSIX_IPV6 _POSIX_VERSION +#define _POSIX_JOB_CONTROL 1 +#define _POSIX_SAVED_IDS 1 +#define _POSIX_SHELL 1 +#define _POSIX_SPAWN _POSIX_VERSION +#define _POSIX_THREADS _POSIX_VERSION +#define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION +#define _POSIX_MONOTONIC_CLOCK 0 + +/* MISSING: additional _POSIX and _XOPEN feature macros */ +/* MISSING: _POSIX_TIMESTAMP_RESOLUTION and _POSIX2_SYMLINKS */ + +#define _CS_PATH 0 +#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 1 +#define _CS_GNU_LIBC_VERSION 2 +#define _CS_GNU_LIBPTHREAD_VERSION 3 +#define _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS 4 +#define _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS 5 + +#define _CS_POSIX_V6_ILP32_OFF32_CFLAGS 1116 +#define _CS_POSIX_V6_ILP32_OFF32_LDFLAGS 1117 +#define _CS_POSIX_V6_ILP32_OFF32_LIBS 1118 +#define _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS 1119 +#define _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS 1120 +#define _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS 1121 +#define _CS_POSIX_V6_ILP32_OFFBIG_LIBS 1122 +#define _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS 1123 +#define _CS_POSIX_V6_LP64_OFF64_CFLAGS 1124 +#define _CS_POSIX_V6_LP64_OFF64_LDFLAGS 1125 +#define _CS_POSIX_V6_LP64_OFF64_LIBS 1126 +#define _CS_POSIX_V6_LP64_OFF64_LINTFLAGS 1127 +#define _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS 1128 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS 1129 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LIBS 1130 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS 1131 +#define _CS_POSIX_V7_ILP32_OFF32_CFLAGS 1132 +#define _CS_POSIX_V7_ILP32_OFF32_LDFLAGS 1133 +#define _CS_POSIX_V7_ILP32_OFF32_LIBS 1134 +#define _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS 1135 +#define _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS 1136 +#define _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS 1137 +#define _CS_POSIX_V7_ILP32_OFFBIG_LIBS 1138 +#define _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS 1139 +#define _CS_POSIX_V7_LP64_OFF64_CFLAGS 1140 +#define _CS_POSIX_V7_LP64_OFF64_LDFLAGS 1141 +#define _CS_POSIX_V7_LP64_OFF64_LIBS 1142 +#define _CS_POSIX_V7_LP64_OFF64_LINTFLAGS 1143 +#define _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS 1144 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS 1145 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LIBS 1146 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS 1147 +#define _CS_V6_ENV 1148 +#define _CS_V7_ENV 1149 + +/* MISSING: SEEK macros from stdio.h */ + +#define F_LOCK 1 +#define F_TEST 2 +#define F_TLOCK 3 +#define F_ULOCK 4 + +/* MISSING: _PC macros */ +/* For now, use the Linux ABI for _PC constants. */ +#define _PC_LINK_MAX 0 +#define _PC_MAX_CANON 1 +#define _PC_MAX_INPUT 2 +#define _PC_NAME_MAX 3 +#define _PC_PATH_MAX 4 +#define _PC_PIPE_BUF 5 +#define _PC_CHOWN_RESTRICTED 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 + +#define _PC_FILESIZEBITS 9 +#define _PC_SYMLINK_MAX 10 + +/* MISSING: remaining _SC_macros */ +#define _SC_ARG_MAX 0 +#define _SC_CHILD_MAX 1 +#define _SC_CLK_TCK 2 +#define _SC_NGROUPS_MAX 3 +#define _SC_OPEN_MAX 4 +#define _SC_STREAM_MAX 5 +#define _SC_TZNAME_MAX 6 +#define _SC_JOB_CONTROL 7 + +#define _SC_SAVED_IDS 8 +#define _SC_REALTIME_SIGNALS 9 +#define _SC_PRIORITY_SCHEDULING 10 +#define _SC_TIMERS 11 +#define _SC_ASYNCHRONOUS_IO 12 +#define _SC_PRIORITIZED_IO 13 +#define _SC_SYNCHRONIZED_IO 14 +#define _SC_FSYNC 15 +#define _SC_MAPPED_FILES 16 +#define _SC_MEMLOCK 17 +#define _SC_MEMLOCK_RANGE 18 +#define _SC_MEMORY_PROTECTION 19 +#define _SC_MESSAGE_PASSING 20 +#define _SC_SEMAPHORES 21 +#define _SC_SHARED_MEMORY_OBJECTS 22 +#define _SC_AIO_LISTIO_MAX 23 +#define _SC_AIO_MAX 24 +#define _SC_AIO_PRIO_DELTA_MAX 25 +#define _SC_DELAYTIMER_MAX 26 +#define _SC_MQ_OPEN_MAX 27 +#define _SC_MQ_PRIO_MAX 28 +#define _SC_VERSION 29 +#define _SC_PAGE_SIZE 30 +#define _SC_PAGESIZE _SC_PAGE_SIZE +#define _SC_RTSIG_MAX 31 +#define _SC_SEM_NSEMS_MAX 32 +#define _SC_SEM_VALUE_MAX 33 +#define _SC_SIGQUEUE_MAX 34 +#define _SC_TIMER_MAX 35 +#define _SC_BC_BASE_MAX 36 +#define _SC_BC_DIM_MAX 37 +#define _SC_BC_SCALE_MAX 38 +#define _SC_BC_STRING_MAX 39 +#define _SC_COLL_WEIGHTS_MAX 40 +#define _SC_EXPR_NEST_MAX 42 +#define _SC_LINE_MAX 43 +#define _SC_RE_DUP_MAX 44 +#define _SC_2_VERSION 46 +#define _SC_2_C_BIND 47 +#define _SC_2_C_DEV 48 +#define _SC_2_FORT_DEV 49 +#define _SC_2_FORT_RUN 50 +#define _SC_2_SW_DEV 51 +#define _SC_2_LOCALEDEF 52 +#define _SC_IOV_MAX 60 +#define _SC_UIO_MAXIOV _SC_IOV_MAX +#define _SC_THREADS 67 +#define _SC_THREAD_SAFE_FUNCTIONS 68 +#define _SC_GETGR_R_SIZE_MAX 69 +#define _SC_GETPW_R_SIZE_MAX 70 +#define _SC_LOGIN_NAME_MAX 71 +#define _SC_TTY_NAME_MAX 72 +#define _SC_THREAD_DESTRUCTOR_ITERATIONS 73 +#define _SC_THREAD_KEYS_MAX 74 +#define _SC_THREAD_STACK_MIN 75 +#define _SC_THREAD_THREADS_MAX 76 +#define _SC_THREAD_ATTR_STACKADDR 77 +#define _SC_THREAD_ATTR_STACKSIZE 78 +#define _SC_THREAD_PRIORITY_SCHEDULING 79 +#define _SC_THREAD_PRIO_INHERIT 80 +#define _SC_THREAD_PRIO_PROTECT 81 +#define _SC_THREAD_PROCESS_SHARED 82 +#define _SC_NPROCESSORS_CONF 83 +#define _SC_NPROCESSORS_ONLN 84 +#define _SC_PHYS_PAGES 85 +#define _SC_AVPHYS_PAGES 86 +#define _SC_ATEXIT_MAX 87 +#define _SC_PASS_MAX 88 +#define _SC_XOPEN_VERSION 89 +#define _SC_XOPEN_XCU_VERSION 90 +#define _SC_XOPEN_UNIX 91 +#define _SC_XOPEN_CRYPT 92 +#define _SC_XOPEN_ENH_I18N 93 +#define _SC_XOPEN_SHM 94 +#define _SC_2_CHAR_TERM 95 +#define _SC_2_UPE 97 +#define _SC_XOPEN_XPG2 98 +#define _SC_XOPEN_XPG3 99 +#define _SC_XOPEN_XPG4 100 +#define _SC_NZERO 109 +#define _SC_XBS5_ILP32_OFF32 125 +#define _SC_XBS5_ILP32_OFFBIG 126 +#define _SC_XBS5_LP64_OFF64 127 +#define _SC_XBS5_LPBIG_OFFBIG 128 +#define _SC_XOPEN_LEGACY 129 +#define _SC_XOPEN_REALTIME 130 +#define _SC_XOPEN_REALTIME_THREADS 131 +#define _SC_ADVISORY_INFO 132 +#define _SC_BARRIERS 133 +#define _SC_CLOCK_SELECTION 137 +#define _SC_CPUTIME 138 +#define _SC_THREAD_CPUTIME 139 +#define _SC_MONOTONIC_CLOCK 149 +#define _SC_READER_WRITER_LOCKS 153 +#define _SC_SPIN_LOCKS 154 +#define _SC_REGEXP 155 +#define _SC_SHELL 157 +#define _SC_SPAWN 159 +#define _SC_SPORADIC_SERVER 160 +#define _SC_THREAD_SPORADIC_SERVER 161 +#define _SC_TIMEOUTS 164 +#define _SC_TYPED_MEMORY_OBJECTS 165 +#define _SC_2_PBS 168 +#define _SC_2_PBS_ACCOUNTING 169 +#define _SC_2_PBS_LOCATE 170 +#define _SC_2_PBS_MESSAGE 171 +#define _SC_2_PBS_TRACK 172 +#define _SC_SYMLOOP_MAX 173 +#define _SC_STREAMS 174 +#define _SC_2_PBS_CHECKPOINT 175 +#define _SC_V6_ILP32_OFF32 176 +#define _SC_V6_ILP32_OFFBIG 177 +#define _SC_V6_LP64_OFF64 178 +#define _SC_V6_LPBIG_OFFBIG 179 +#define _SC_HOST_NAME_MAX 180 +#define _SC_TRACE 181 +#define _SC_TRACE_EVENT_FILTER 182 +#define _SC_TRACE_INHERIT 183 +#define _SC_TRACE_LOG 184 + +/* Port-specific _SC_* define values */ + +#if defined (__ironclad__) +#define _SC_TOTAL_PAGES 1000 +#define _SC_HOST_OPEN_MAX 1001 +#endif /* defined (__ironclad__) */ + +#define STDERR_FILENO 2 +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 + +#define _POSIX_VDISABLE '\0' + +#define L_ctermid 20 + +/* + * Solving this likely requires us to 'factor out' the typedef into a new + * header file, or use a mechanism like musl's __NEED_intptr_t. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +typedef __mlibc_intptr intptr_t; +#pragma GCC diagnostic pop + +#ifndef __MLIBC_ABI_ONLY + +int access(const char *__path, int __mode); +unsigned int alarm(unsigned int __seconds); +int chdir(const char *__path); +int chown(const char *__path, uid_t __uid, gid_t __gid); +int close(int __fd); +ssize_t confstr(int __name, char *__buf, size_t __size); +char *ctermid(char *__s); +int dup(int __fd); +int dup2(int __src_fd, int __dest_fd); +__attribute__((__noreturn__)) void _exit(int __status); +void endusershell(void); +int execl(const char *__path, const char *__arg, ...); +int execle(const char *__path, const char *__arg, ...); +int execlp(const char *__file, const char *__arg, ...); +int execv(const char *__path, char *const __argv[]); +int execve(const char *__path, char *const __argv[], char *const __envp[]); +int execvp(const char *__file, char *const __argv[]); +int execvpe(const char *__path, char *const __argv[], char *const __envp[]); +int faccessat(int __fd, const char *__path, int __mode, int __flags); +int fchdir(int __fd); +int fchown(int __fd, uid_t __uid, gid_t __gid); +int fchownat(int __fd, const char *__path, uid_t __uid, gid_t __gid, int __flags); +int fdatasync(int __fd); +int fexecve(int __fd, char *const __argv[], char *const __envp[]); +pid_t fork(void); +pid_t vfork(void); +long fpathconf(int __fd, int __name); +int fsync(int __fd); +int ftruncate(int __fd, off_t __size); +int ftruncate64(int __fd, off64_t __size); +char *getcwd(char *__buffer, size_t __size); +gid_t getegid(void); +uid_t geteuid(void); +gid_t getgid(void); +int getgroups(int __size, gid_t __list[]); +long gethostid(void); +int gethostname(char *__buffer, size_t __max_length); +int sethostname(const char *__buffer, size_t __max_length); +char *getlogin(void); +int getlogin_r(char *__buffer, size_t __size); +int getopt(int __argc, char *const __argv[], const char *__optstring); +char *getpass(const char *__prompt); +pid_t getpgid(pid_t __pid); +pid_t getpgrp(void); +pid_t getpid(void); +pid_t getppid(void); +pid_t getsid(pid_t __pid); +uid_t getuid(void); +char *getusershell(void); +int isatty(int __fd); +int lchown(const char *__path, uid_t __uid, gid_t __gid); +int link(const char *__oldpath, const char *__newpath); +int linkat(int __olddirfd, const char *__oldpath, int __newdirfd, const char *__newpath, int __flags); +int lockf(int __fd, int __op, off_t __size); +off_t lseek(int __fd, off_t __offset, int __whence); +off64_t lseek64(int __fd, off64_t __offset, int __whence); +int nice(int __increment); +long pathconf(const char *__path, int __name); +int pause(void); +int pipe(int __pipefd[2]); +ssize_t pread(int __fd, void *__buf, size_t __size, off_t __offset); +ssize_t pread64(int __fd, void *__buf, size_t __size, off_t __offset); +ssize_t pwrite(int __fd, const void *__buf, size_t __size, off_t __offset); +ssize_t pwrite64(int __fd, const void *__buf, size_t __size, off_t __offset); +ssize_t read(int fd, void *buffer, size_t size); +ssize_t readlink(const char *__restrict __path, char *__restrict __buf, size_t __size); +ssize_t readlinkat(int __dirfd, const char *__restrict __path, char *__restrict __buf, size_t __size); +int rmdir(const char *__path); +int setegid(gid_t __egid); +int seteuid(uid_t __euid); +int setgid(gid_t __gid); +int setpgid(pid_t __pid, pid_t __pgid); +pid_t setpgrp(void); +int setregid(gid_t __rgid, gid_t __egid); +int setreuid(uid_t __ruid, uid_t __euid); +pid_t setsid(void); +int setuid(uid_t __uid); +void setusershell(void); +unsigned int sleep(unsigned int __seconds); +void swab(const void *__restrict __from, void *__restrict __to, ssize_t __size); +int symlink(const char *__target, const char *__linkpath); +int symlinkat(const char *__target, int __newdirfd, const char *__linkpath); +void sync(void); +long sysconf(int __name); +pid_t tcgetpgrp(int __fd); +int tcsetpgrp(int __fd, pid_t __pgrp); +int truncate(const char *__path, off_t __size); +int truncate64(const char *__path, off64_t __size); +char *ttyname(int __fd); +int ttyname_r(int __fd, char *__buf, size_t __size); +int unlink(const char *__path); +int unlinkat(int __dirfd, const char *__path, int __flags); +ssize_t write(int __fd, const void *__buffer, size_t __size); + +extern char **environ; +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; + +#endif /* !__MLIBC_ABI_ONLY */ + +/* Non-POSIX functions supported by Linux. */ +#if UINTPTR_MAX == UINT64_MAX +typedef __mlibc_uint64 useconds_t; +#else +typedef __mlibc_uint32 useconds_t; +#endif + +#ifndef __MLIBC_ABI_ONLY + +int getpagesize(void); +char *get_current_dir_name(void); +int usleep(useconds_t __usec); +int chroot(const char *__path); +int daemon(int __nochdir, int __noclose); + +/* This is a Linux extension */ +pid_t gettid(void); +int getentropy(void *__buffer, size_t __size); + +int pipe2(int *__pipefd, int __flags); + +int setresuid(uid_t __ruid, uid_t __euid, uid_t __suid); +int setresgid(gid_t __rgid, gid_t __egid, gid_t __sgid); + +/* Glibc extensions. */ +int getdomainname(char *__name, size_t __len); +int setdomainname(const char *__name, size_t __len); + +int getresuid(uid_t *__ruid, uid_t *__euid, uid_t *__suid); +int getresgid(gid_t *__rgid, gid_t *__egid, gid_t *__sgid); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_LINUX_OPTION +# include +#endif + +#if __MLIBC_BSD_OPTION +# include +#endif + +#endif /* _UNISTD_H */ + diff --git a/user/include/mlibc/options/posix/include/utime.h b/user/include/mlibc/options/posix/include/utime.h new file mode 100644 index 0000000..0d5a2b2 --- /dev/null +++ b/user/include/mlibc/options/posix/include/utime.h @@ -0,0 +1,25 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +#ifndef __MLIBC_ABI_ONLY + +int utime(const char *__filename, const struct utimbuf *__times); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UTIME_H */ diff --git a/user/include/mlibc/options/posix/include/utmpx.h b/user/include/mlibc/options/posix/include/utmpx.h new file mode 100644 index 0000000..4c7685a --- /dev/null +++ b/user/include/mlibc/options/posix/include/utmpx.h @@ -0,0 +1,31 @@ + +#ifndef _UTMPX_H +#define _UTMPX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +void endutxent(void); +struct utmpx *getutxent(void); +struct utmpx *getutxid(const struct utmpx *__id); +struct utmpx *getutxline(const struct utmpx *__ut); +struct utmpx *pututxline(const struct utmpx *__line); +void setutxent(void); + +/* extensions */ +void updwtmpx(const char *__wtmp_file, const struct utmpx *__ut); +int utmpxname(const char *__file); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UTMPX_H */ diff --git a/user/include/mlibc/options/posix/include/wordexp.h b/user/include/mlibc/options/posix/include/wordexp.h new file mode 100644 index 0000000..34dd55a --- /dev/null +++ b/user/include/mlibc/options/posix/include/wordexp.h @@ -0,0 +1,43 @@ +#ifndef _WORDEXP_H +#define _WORDEXP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define WRDE_APPEND 1 +#define WRDE_DOOFFS 2 +#define WRDE_NOCMD 4 +#define WRDE_REUSE 8 +#define WRDE_SHOWERR 16 +#define WRDE_UNDEF 32 + +#define WRDE_SUCCESS 1 +#define WRDE_BADCHAR 1 +#define WRDE_BADVAL 2 +#define WRDE_CMDSUB 3 +#define WRDE_NOSPACE 4 +#define WRDE_SYNTAX 5 + +typedef struct { + size_t we_wordc; + char **we_wordv; + size_t we_offs; + char *we_strings; + size_t we_nbytes; +} wordexp_t; + +#ifndef __MLIBC_ABI_ONLY + +int wordexp(const char *__s, wordexp_t *__p, int __flags); +void wordfree(wordexp_t *__p); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/user/include/mlibc/options/posix/meson.build b/user/include/mlibc/options/posix/meson.build new file mode 100644 index 0000000..681c99b --- /dev/null +++ b/user/include/mlibc/options/posix/meson.build @@ -0,0 +1,178 @@ + +if not posix_option + subdir_done() +endif +libc_sources += files( + 'generic/arpa-inet.cpp', + 'generic/dirent.cpp', + 'generic/dlfcn.cpp', + 'generic/fcntl.cpp', + 'generic/ftw.cpp', + 'generic/grp.cpp', + 'generic/langinfo.cpp', + 'generic/libgen.cpp', + 'generic/lookup.cpp', + 'generic/netdb.cpp', + 'generic/net-if.cpp', + 'generic/poll.cpp', + 'generic/posix_ctype.cpp', + 'generic/posix-file-io.cpp', + 'generic/posix_locale.cpp', + 'generic/posix_signal.cpp', + 'generic/posix_stdio.cpp', + 'generic/posix_stdlib.cpp', + 'generic/posix_string.cpp', + 'generic/posix_time.cpp', + 'generic/pthread.cpp', + 'generic/pwd.cpp', + 'generic/resolv_conf.cpp', + 'generic/sched.cpp', + 'generic/spawn.cpp', + 'generic/strings.cpp', + 'generic/services.cpp', + 'generic/sys-file.cpp', + 'generic/syslog.cpp', + 'generic/sys-mman.cpp', + 'generic/sys-resource.cpp', + 'generic/sys-select.cpp', + 'generic/sys-shm.cpp', + 'generic/sys-socket.cpp', + 'generic/sys-stat.cpp', + 'generic/sys-statvfs.cpp', + 'generic/sys-times.cpp', + 'generic/sys-time.cpp', + 'generic/sys-uio.cpp', + 'generic/sys-utsname.cpp', + 'generic/sys-wait.cpp', + 'generic/termios.cpp', + 'generic/unistd.cpp', + 'generic/utime.cpp', + 'generic/ucontext.cpp', + 'generic/semaphore.cpp', + 'generic/search.cpp', + 'generic/sys-msg.cpp', + 'generic/sys-sem.cpp', + 'generic/sys-ipc.cpp', + 'generic/time.cpp', + 'generic/wordexp.cpp', + 'generic/mqueue.cpp', + 'generic/utmpx.cpp', +) + +if not headers_only + libc_sublibs += static_library('musl-generic-regex', + 'musl-generic-regex/fnmatch.c', + 'musl-generic-regex/glob.c', + 'musl-generic-regex/regcomp.c', + 'musl-generic-regex/regerror.c', + 'musl-generic-regex/regexec.c', + 'musl-generic-regex/tre-mem.c', + pic: true, + include_directories: libc_include_dirs, + dependencies: libc_deps, + c_args: ['-Wno-unused', '-Wno-implicit', '-Wno-parentheses', '-Wno-sign-compare', '-Wno-attributes', '-Wno-unknown-pragmas', '-Wno-implicit-fallthrough', '-Wno-unused-parameter'] + ) +endif + +if not no_headers + install_headers( + 'include/byteswap.h', + 'include/dirent.h', + 'include/dlfcn.h', + 'include/fcntl.h', + 'include/fnmatch.h', + 'include/ftw.h', + 'include/glob.h', + 'include/grp.h', + 'include/langinfo.h', + 'include/libgen.h', + 'include/netdb.h', + 'include/nl_types.h', + 'include/pthread.h', + 'include/pwd.h', + 'include/poll.h', + 'include/regex.h', + 'include/sched.h', + 'include/search.h', + 'include/spawn.h', + 'include/strings.h', + 'include/syslog.h', + 'include/termios.h', + 'include/unistd.h', + 'include/utime.h', + 'include/ucontext.h', + 'include/wordexp.h', + 'include/semaphore.h', + 'include/mqueue.h', + 'include/utmpx.h', + ) + install_headers( + 'include/arpa/inet.h', + subdir: 'arpa' + ) + install_headers( + 'include/net/if.h', + 'include/net/if_arp.h', + subdir: 'net' + ) + install_headers( + 'include/netinet/in.h', + 'include/netinet/ip.h', + 'include/netinet/tcp.h', + 'include/netinet/icmp6.h', + 'include/netinet/if_ether.h', + 'include/netinet/udp.h', + 'include/netinet/ip6.h', + 'include/netinet/ip_icmp.h', + subdir: 'netinet' + ) + install_headers( + 'include/sys/fcntl.h', + 'include/sys/file.h', + 'include/sys/ipc.h', + 'include/sys/mman.h', + 'include/sys/msg.h', + 'include/sys/param.h', + 'include/sys/poll.h', + 'include/sys/resource.h', + 'include/sys/select.h', + 'include/sys/sem.h', + 'include/sys/shm.h', + 'include/sys/socket.h', + 'include/sys/stat.h', + 'include/sys/statvfs.h', + 'include/sys/termios.h', + 'include/sys/time.h', + 'include/sys/times.h', + 'include/sys/ttydefaults.h', + 'include/sys/types.h', + 'include/sys/uio.h', + 'include/sys/un.h', + 'include/sys/utsname.h', + 'include/sys/wait.h', + 'include/sys/syslog.h', + subdir: 'sys' + ) + install_headers( + 'include/bits/posix/id_t.h', + 'include/bits/posix/in_addr_t.h', + 'include/bits/posix/in_port_t.h', + 'include/bits/posix/iovec.h', + 'include/bits/posix/locale_t.h', + 'include/bits/posix/posix_ctype.h', + 'include/bits/posix/posix_locale.h', + 'include/bits/posix/posix_signal.h', + 'include/bits/posix/posix_stdio.h', + 'include/bits/posix/posix_stdlib.h', + 'include/bits/posix/posix_string.h', + 'include/bits/posix/posix_time.h', + 'include/bits/posix/posix_wctype.h', + 'include/bits/posix/stat.h', + 'include/bits/posix/timeval.h', + 'include/bits/posix/fd_set.h', + 'include/bits/posix/pthread_t.h', + 'include/bits/posix/timer_t.h', + subdir: 'bits/posix' + ) +endif + diff --git a/user/include/mlibc/options/posix/musl-generic-regex/fnmatch.c b/user/include/mlibc/options/posix/musl-generic-regex/fnmatch.c new file mode 100644 index 0000000..0e6de47 --- /dev/null +++ b/user/include/mlibc/options/posix/musl-generic-regex/fnmatch.c @@ -0,0 +1,321 @@ +/* + * An implementation of what I call the "Sea of Stars" algorithm for + * POSIX fnmatch(). The basic idea is that we factor the pattern into + * a head component (which we match first and can reject without ever + * measuring the length of the string), an optional tail component + * (which only exists if the pattern contains at least one star), and + * an optional "sea of stars", a set of star-separated components + * between the head and tail. After the head and tail matches have + * been removed from the input string, the components in the "sea of + * stars" are matched sequentially by searching for their first + * occurrence past the end of the previous match. + * + * - Rich Felker, April 2012 + */ + +#include +#include +#include +#include +#include +// #include "locale_impl.h" + +#define END 0 +#define UNMATCHABLE -2 +#define BRACKET -3 +#define QUESTION -4 +#define STAR -5 + +static int str_next(const char *str, size_t n, size_t *step) +{ + if (!n) { + *step = 0; + return 0; + } + if (str[0] >= 128U) { + wchar_t wc; + int k = mbtowc(&wc, str, n); + if (k<0) { + *step = 1; + return -1; + } + *step = k; + return wc; + } + *step = 1; + return str[0]; +} + +static int pat_next(const char *pat, size_t m, size_t *step, int flags) +{ + int esc = 0; + if (!m || !*pat) { + *step = 0; + return END; + } + *step = 1; + if (pat[0]=='\\' && pat[1] && !(flags & FNM_NOESCAPE)) { + *step = 2; + pat++; + esc = 1; + goto escaped; + } + if (pat[0]=='[') { + size_t k = 1; + if (k= 128U) { + wchar_t wc; + int k = mbtowc(&wc, pat, m); + if (k<0) { + *step = 0; + return UNMATCHABLE; + } + *step = k + esc; + return wc; + } + return pat[0]; +} + +static int casefold(int k) +{ + int c = towupper(k); + return c == k ? towlower(k) : c; +} + +static int match_bracket(const char *p, int k, int kfold) +{ + wchar_t wc; + int inv = 0; + p++; + if (*p=='^' || *p=='!') { + inv = 1; + p++; + } + if (*p==']') { + if (k==']') return !inv; + p++; + } else if (*p=='-') { + if (k=='-') return !inv; + p++; + } + wc = p[-1]; + for (; *p != ']'; p++) { + if (p[0]=='-' && p[1]!=']') { + wchar_t wc2; + int l = mbtowc(&wc2, p+1, 4); + if (l < 0) return 0; + if (wc <= wc2) + if ((unsigned)k-wc <= wc2-wc || + (unsigned)kfold-wc <= wc2-wc) + return !inv; + p += l-1; + continue; + } + if (p[0]=='[' && (p[1]==':' || p[1]=='.' || p[1]=='=')) { + const char *p0 = p+2; + int z = p[1]; + p+=3; + while (p[-1]!=z || p[0]!=']') p++; + if (z == ':' && p-1-p0 < 16) { + char buf[16]; + memcpy(buf, p0, p-1-p0); + buf[p-1-p0] = 0; + if (iswctype(k, wctype(buf)) || + iswctype(kfold, wctype(buf))) + return !inv; + } + continue; + } + if (*p < 128U) { + wc = (unsigned char)*p; + } else { + int l = mbtowc(&wc, p, 4); + if (l < 0) return 0; + p += l-1; + } + if (wc==(wchar_t)k || wc==(wchar_t)kfold) return !inv; + } + return inv; +} + +static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n, int flags) +{ + const char *p, *ptail, *endpat; + const char *s, *stail, *endstr; + size_t pinc, sinc, tailcnt=0; + int c, k, kfold; + + if (flags & FNM_PERIOD) { + if (*str == '.' && *pat != '.') + return FNM_NOMATCH; + } + for (;;) { + switch ((c = pat_next(pat, m, &pinc, flags))) { + case UNMATCHABLE: + return FNM_NOMATCH; + case STAR: + pat++; + m--; + break; + default: + k = str_next(str, n, &sinc); + if (k <= 0) + return (c==END) ? 0 : FNM_NOMATCH; + str += sinc; + n -= sinc; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; + if (c == BRACKET) { + if (!match_bracket(pat, k, kfold)) + return FNM_NOMATCH; + } else if (c != QUESTION && k != c && kfold != c) { + return FNM_NOMATCH; + } + pat+=pinc; + m-=pinc; + continue; + } + break; + } + + /* Compute real pat length if it was initially unknown/-1 */ + m = strnlen(pat, m); + endpat = pat + m; + + /* Find the last * in pat and count chars needed after it */ + for (p=ptail=pat; pstr && tailcnt; tailcnt--) { + if (s[-1] < 128U || MB_CUR_MAX==1) s--; + else while ((unsigned char)*--s-0x80U<0x40 && s>str); + } + if (tailcnt) return FNM_NOMATCH; + stail = s; + + /* Check that the pat and str tails match */ + p = ptail; + for (;;) { + c = pat_next(p, endpat-p, &pinc, flags); + p += pinc; + if ((k = str_next(s, endstr-s, &sinc)) <= 0) { + if (c != END) return FNM_NOMATCH; + break; + } + s += sinc; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; + if (c == BRACKET) { + if (!match_bracket(p-pinc, k, kfold)) + return FNM_NOMATCH; + } else if (c != QUESTION && k != c && kfold != c) { + return FNM_NOMATCH; + } + } + + /* We're all done with the tails now, so throw them out */ + endstr = stail; + endpat = ptail; + + /* Match pattern components until there are none left */ + while (pat 0) str += sinc; + else for (str++; str_next(str, endstr-str, &sinc)<0; str++); + } + + return 0; +} + +int fnmatch(const char *pat, const char *str, int flags) +{ + const char *s, *p; + size_t inc; + int c; + if (flags & FNM_PATHNAME) for (;;) { + for (s=str; *s && *s!='/'; s++); + for (p=pat; (c=pat_next(p, -1, &inc, flags))!=END && c!='/'; p+=inc); + if (c!=*s && (!*s || !(flags & FNM_LEADING_DIR))) + return FNM_NOMATCH; + if (fnmatch_internal(pat, p-pat, str, s-str, flags)) + return FNM_NOMATCH; + if (!c) return 0; + str = s+1; + pat = p+inc; + } else if (flags & FNM_LEADING_DIR) { + for (s=str; *s; s++) { + if (*s != '/') continue; + if (!fnmatch_internal(pat, -1, str, s-str, flags)) + return 0; + } + } + return fnmatch_internal(pat, -1, str, -1, flags); +} diff --git a/user/include/mlibc/options/posix/musl-generic-regex/glob.c b/user/include/mlibc/options/posix/musl-generic-regex/glob.c new file mode 100644 index 0000000..b57f2f3 --- /dev/null +++ b/user/include/mlibc/options/posix/musl-generic-regex/glob.c @@ -0,0 +1,311 @@ +#define _BSD_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct match +{ + struct match *next; + char name[]; +}; + +static int append(struct match **tail, const char *name, size_t len, int mark) +{ + struct match *new = malloc(sizeof(struct match) + len + 2); + if (!new) return -1; + (*tail)->next = new; + new->next = NULL; + memcpy(new->name, name, len+1); + if (mark && len && name[len-1]!='/') { + new->name[len] = '/'; + new->name[len+1] = 0; + } + *tail = new; + return 0; +} + +static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*errfunc)(const char *path, int err), struct match **tail) +{ + /* If GLOB_MARK is unused, we don't care about type. */ + if (!type && !(flags & GLOB_MARK)) type = DT_REG; + + /* Special-case the remaining pattern being all slashes, in + * which case we can use caller-passed type if it's a dir. */ + if (*pat && type!=DT_DIR) type = 0; + while (pos+1 < PATH_MAX && *pat=='/') buf[pos++] = *pat++; + + /* Consume maximal [escaped-]literal prefix of pattern, copying + * and un-escaping it to the running buffer as we go. */ + ptrdiff_t i=0, j=0; + int in_bracket = 0, overflow = 0; + for (; pat[i]!='*' && pat[i]!='?' && (!in_bracket || pat[i]!=']'); i++) { + if (!pat[i]) { + if (overflow) return 0; + pat += i; + pos += j; + i = j = 0; + break; + } else if (pat[i] == '[') { + in_bracket = 1; + } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) { + /* Backslashes inside a bracket are (at least by + * our interpretation) non-special, so if next + * char is ']' we have a complete expression. */ + if (in_bracket && pat[i+1]==']') break; + /* Unpaired final backslash never matches. */ + if (!pat[i+1]) return 0; + i++; + } + if (pat[i] == '/') { + if (overflow) return 0; + in_bracket = 0; + pat += i+1; + i = -1; + pos += j+1; + j = -1; + } + /* Only store a character if it fits in the buffer, but if + * a potential bracket expression is open, the overflow + * must be remembered and handled later only if the bracket + * is unterminated (and thereby a literal), so as not to + * disallow long bracket expressions with short matches. */ + if (pos+(j+1) < PATH_MAX) { + buf[pos+j++] = pat[i]; + } else if (in_bracket) { + overflow = 1; + } else { + return 0; + } + /* If we consume any new components, the caller-passed type + * or dummy type from above is no longer valid. */ + type = 0; + } + buf[pos] = 0; + if (!*pat) { + /* If we consumed any components above, or if GLOB_MARK is + * requested and we don't yet know if the match is a dir, + * we must confirm the file exists and/or determine its type. + * + * If marking dirs, symlink type is inconclusive; we need the + * type for the symlink target, and therefore must try stat + * first unless type is known not to be a symlink. Otherwise, + * or if that fails, use lstat for determining existence to + * avoid false negatives in the case of broken symlinks. */ + struct stat st; + if ((flags & GLOB_MARK) && (!type||type==DT_LNK) && !stat(buf, &st)) { + if (S_ISDIR(st.st_mode)) type = DT_DIR; + else type = DT_REG; + } + if (!type && lstat(buf, &st)) { + if (errno!=ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) + return GLOB_ABORTED; + return 0; + } + if (append(tail, buf, pos, (flags & GLOB_MARK) && type==DT_DIR)) + return GLOB_NOSPACE; + return 0; + } + char *p2 = strchr(pat, '/'), saved_sep = '/'; + /* Check if the '/' was escaped and, if so, remove the escape char + * so that it will not be unpaired when passed to fnmatch. */ + if (p2 && !(flags & GLOB_NOESCAPE)) { + char *p; + for (p=p2; p>pat && p[-1]=='\\'; p--); + if ((p2-p)%2) { + p2--; + saved_sep = '\\'; + } + } + DIR *dir = opendir(pos ? buf : "."); + if (!dir) { + if (errfunc(buf, errno) || (flags & GLOB_ERR)) + return GLOB_ABORTED; + return 0; + } + int old_errno = errno; + struct dirent *de; + while (errno=0, de=readdir(dir)) { + /* Quickly skip non-directories when there's pattern left. */ + if (p2 && de->d_type && de->d_type!=DT_DIR && de->d_type!=DT_LNK) + continue; + + size_t l = strlen(de->d_name); + if (l >= PATH_MAX-pos) continue; + + if (p2) *p2 = 0; + + int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) + | ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); + + if (fnmatch(pat, de->d_name, fnm_flags)) + continue; + + /* With GLOB_PERIOD, don't allow matching . or .. unless + * fnmatch would match them with FNM_PERIOD rules in effect. */ + if (p2 && (flags & GLOB_PERIOD) && de->d_name[0]=='.' + && (!de->d_name[1] || de->d_name[1]=='.' && !de->d_name[2]) + && fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD)) + continue; + + memcpy(buf+pos, de->d_name, l+1); + if (p2) *p2 = saved_sep; + int r = do_glob(buf, pos+l, de->d_type, p2 ? p2 : "", flags, errfunc, tail); + if (r) { + closedir(dir); + return r; + } + } + int readerr = errno; + if (p2) *p2 = saved_sep; + closedir(dir); + if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) + return GLOB_ABORTED; + errno = old_errno; + return 0; +} + +static int ignore_err(const char *path, int err) +{ + return 0; +} + +static void freelist(struct match *head) +{ + struct match *match, *next; + for (match=head->next; match; match=next) { + next = match->next; + free(match); + } +} + +static int sort(const void *a, const void *b) +{ + return strcmp(*(const char **)a, *(const char **)b); +} + +static int expand_tilde(char **pat, char *buf, size_t *pos) +{ + char *p = *pat + 1; + size_t i = 0; + + char delim, *name_end = strchrnul(p, '/'); + if ((delim = *name_end)) *name_end++ = 0; + *pat = name_end; + + char *home = *p ? NULL : getenv("HOME"); + if (!home) { + struct passwd pw, *res; + switch (*p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res) + : getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res)) { + case ENOMEM: + return GLOB_NOSPACE; + case 0: + if (!res) + default: + return GLOB_NOMATCH; + } + home = pw.pw_dir; + } + while (i < PATH_MAX - 2 && *home) + buf[i++] = *home++; + if (*home) + return GLOB_NOMATCH; + if ((buf[i] = delim)) + buf[++i] = 0; + *pos = i; + return 0; +} + +int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g) +{ + struct match head = { .next = NULL }, *tail = &head; + size_t cnt, i; + size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; + int error = 0; + char buf[PATH_MAX]; + + if (!errfunc) errfunc = ignore_err; + + if (!(flags & GLOB_APPEND)) { + g->gl_offs = offs; + g->gl_pathc = 0; + g->gl_pathv = NULL; + } + + if (*pat) { + char *p = strdup(pat); + if (!p) return GLOB_NOSPACE; + buf[0] = 0; + size_t pos = 0; + char *s = p; + if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && *p == '~') + error = expand_tilde(&s, buf, &pos); + if (!error) + error = do_glob(buf, pos, 0, s, flags, errfunc, &tail); + free(p); + } + + if (error == GLOB_NOSPACE) { + freelist(&head); + return error; + } + + for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++); + if (!cnt) { + if (flags & GLOB_NOCHECK) { + tail = &head; + if (append(&tail, pat, strlen(pat), 0)) + return GLOB_NOSPACE; + cnt++; + } else + return GLOB_NOMATCH; + } + + if (flags & GLOB_APPEND) { + char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); + if (!pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + g->gl_pathv = pathv; + offs += g->gl_pathc; + } else { + g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); + if (!g->gl_pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + for (i=0; igl_pathv[i] = NULL; + } + for (i=0, tail=head.next; inext, i++) + g->gl_pathv[offs + i] = tail->name; + g->gl_pathv[offs + i] = NULL; + g->gl_pathc += cnt; + + if (!(flags & GLOB_NOSORT)) + qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort); + + return error; +} + +void globfree(glob_t *g) +{ + size_t i; + for (i=0; igl_pathc; i++) + free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); + free(g->gl_pathv); + g->gl_pathc = 0; + g->gl_pathv = NULL; +} + +// weak_alias(glob, glob64); +// weak_alias(globfree, globfree64); diff --git a/user/include/mlibc/options/posix/musl-generic-regex/regcomp.c b/user/include/mlibc/options/posix/musl-generic-regex/regcomp.c new file mode 100644 index 0000000..ab03984 --- /dev/null +++ b/user/include/mlibc/options/posix/musl-generic-regex/regcomp.c @@ -0,0 +1,2953 @@ +/* + regcomp.c - TRE POSIX compatible regex compilation functions. + + Copyright (c) 2001-2009 Ville Laurikari + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 COPYRIGHT + HOLDER 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. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "tre.h" + +#include + +/*********************************************************************** + from tre-compile.h +***********************************************************************/ + +typedef struct { + int position; + int code_min; + int code_max; + int *tags; + int assertions; + tre_ctype_t class; + tre_ctype_t *neg_classes; + int backref; +} tre_pos_and_tags_t; + + +/*********************************************************************** + from tre-ast.c and tre-ast.h +***********************************************************************/ + +/* The different AST node types. */ +typedef enum { + LITERAL, + CATENATION, + ITERATION, + UNION +} tre_ast_type_t; + +/* Special subtypes of TRE_LITERAL. */ +#define EMPTY -1 /* Empty leaf (denotes empty string). */ +#define ASSERTION -2 /* Assertion leaf. */ +#define TAG -3 /* Tag leaf. */ +#define BACKREF -4 /* Back reference leaf. */ + +#define IS_SPECIAL(x) ((x)->code_min < 0) +#define IS_EMPTY(x) ((x)->code_min == EMPTY) +#define IS_ASSERTION(x) ((x)->code_min == ASSERTION) +#define IS_TAG(x) ((x)->code_min == TAG) +#define IS_BACKREF(x) ((x)->code_min == BACKREF) + + +/* A generic AST node. All AST nodes consist of this node on the top + level with `obj' pointing to the actual content. */ +typedef struct { + tre_ast_type_t type; /* Type of the node. */ + void *obj; /* Pointer to actual node. */ + int nullable; + int submatch_id; + int num_submatches; + int num_tags; + tre_pos_and_tags_t *firstpos; + tre_pos_and_tags_t *lastpos; +} tre_ast_node_t; + + +/* A "literal" node. These are created for assertions, back references, + tags, matching parameter settings, and all expressions that match one + character. */ +typedef struct { + long code_min; + long code_max; + int position; + tre_ctype_t class; + tre_ctype_t *neg_classes; +} tre_literal_t; + +/* A "catenation" node. These are created when two regexps are concatenated. + If there are more than one subexpressions in sequence, the `left' part + holds all but the last, and `right' part holds the last subexpression + (catenation is left associative). */ +typedef struct { + tre_ast_node_t *left; + tre_ast_node_t *right; +} tre_catenation_t; + +/* An "iteration" node. These are created for the "*", "+", "?", and "{m,n}" + operators. */ +typedef struct { + /* Subexpression to match. */ + tre_ast_node_t *arg; + /* Minimum number of consecutive matches. */ + int min; + /* Maximum number of consecutive matches. */ + int max; + /* If 0, match as many characters as possible, if 1 match as few as + possible. Note that this does not always mean the same thing as + matching as many/few repetitions as possible. */ + unsigned int minimal:1; +} tre_iteration_t; + +/* An "union" node. These are created for the "|" operator. */ +typedef struct { + tre_ast_node_t *left; + tre_ast_node_t *right; +} tre_union_t; + + +static tre_ast_node_t * +tre_ast_new_node(tre_mem_t mem, int type, void *obj) +{ + tre_ast_node_t *node = tre_mem_calloc(mem, sizeof *node); + if (!node || !obj) + return 0; + node->obj = obj; + node->type = type; + node->nullable = -1; + node->submatch_id = -1; + return node; +} + +static tre_ast_node_t * +tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position) +{ + tre_ast_node_t *node; + tre_literal_t *lit; + + lit = tre_mem_calloc(mem, sizeof *lit); + node = tre_ast_new_node(mem, LITERAL, lit); + if (!node) + return 0; + lit->code_min = code_min; + lit->code_max = code_max; + lit->position = position; + return node; +} + +static tre_ast_node_t * +tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, int minimal) +{ + tre_ast_node_t *node; + tre_iteration_t *iter; + + iter = tre_mem_calloc(mem, sizeof *iter); + node = tre_ast_new_node(mem, ITERATION, iter); + if (!node) + return 0; + iter->arg = arg; + iter->min = min; + iter->max = max; + iter->minimal = minimal; + node->num_submatches = arg->num_submatches; + return node; +} + +static tre_ast_node_t * +tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) +{ + tre_ast_node_t *node; + tre_union_t *un; + + if (!left) + return right; + un = tre_mem_calloc(mem, sizeof *un); + node = tre_ast_new_node(mem, UNION, un); + if (!node || !right) + return 0; + un->left = left; + un->right = right; + node->num_submatches = left->num_submatches + right->num_submatches; + return node; +} + +static tre_ast_node_t * +tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) +{ + tre_ast_node_t *node; + tre_catenation_t *cat; + + if (!left) + return right; + cat = tre_mem_calloc(mem, sizeof *cat); + node = tre_ast_new_node(mem, CATENATION, cat); + if (!node) + return 0; + cat->left = left; + cat->right = right; + node->num_submatches = left->num_submatches + right->num_submatches; + return node; +} + + +/*********************************************************************** + from tre-stack.c and tre-stack.h +***********************************************************************/ + +typedef struct tre_stack_rec tre_stack_t; + +/* Creates a new stack object. `size' is initial size in bytes, `max_size' + is maximum size, and `increment' specifies how much more space will be + allocated with realloc() if all space gets used up. Returns the stack + object or NULL if out of memory. */ +static tre_stack_t * +tre_stack_new(int size, int max_size, int increment); + +/* Frees the stack object. */ +static void +tre_stack_destroy(tre_stack_t *s); + +/* Returns the current number of objects in the stack. */ +static int +tre_stack_num_objects(tre_stack_t *s); + +/* Each tre_stack_push_*(tre_stack_t *s, value) function pushes + `value' on top of stack `s'. Returns REG_ESPACE if out of memory. + This tries to realloc() more space before failing if maximum size + has not yet been reached. Returns REG_OK if successful. */ +#define declare_pushf(typetag, type) \ + static reg_errcode_t tre_stack_push_ ## typetag(tre_stack_t *s, type value) + +declare_pushf(voidptr, void *); +declare_pushf(int, int); + +/* Each tre_stack_pop_*(tre_stack_t *s) function pops the topmost + element off of stack `s' and returns it. The stack must not be + empty. */ +#define declare_popf(typetag, type) \ + static type tre_stack_pop_ ## typetag(tre_stack_t *s) + +declare_popf(voidptr, void *); +declare_popf(int, int); + +/* Just to save some typing. */ +#define STACK_PUSH(s, typetag, value) \ + do \ + { \ + status = tre_stack_push_ ## typetag(s, value); \ + } \ + while (/*CONSTCOND*/0) + +#define STACK_PUSHX(s, typetag, value) \ + { \ + status = tre_stack_push_ ## typetag(s, value); \ + if (status != REG_OK) \ + break; \ + } + +#define STACK_PUSHR(s, typetag, value) \ + { \ + reg_errcode_t _status; \ + _status = tre_stack_push_ ## typetag(s, value); \ + if (_status != REG_OK) \ + return _status; \ + } + +union tre_stack_item { + void *voidptr_value; + int int_value; +}; + +struct tre_stack_rec { + int size; + int max_size; + int increment; + int ptr; + union tre_stack_item *stack; +}; + + +static tre_stack_t * +tre_stack_new(int size, int max_size, int increment) +{ + tre_stack_t *s; + + s = xmalloc(sizeof(*s)); + if (s != NULL) + { + s->stack = xmalloc(sizeof(*s->stack) * size); + if (s->stack == NULL) + { + xfree(s); + return NULL; + } + s->size = size; + s->max_size = max_size; + s->increment = increment; + s->ptr = 0; + } + return s; +} + +static void +tre_stack_destroy(tre_stack_t *s) +{ + xfree(s->stack); + xfree(s); +} + +static int +tre_stack_num_objects(tre_stack_t *s) +{ + return s->ptr; +} + +static reg_errcode_t +tre_stack_push(tre_stack_t *s, union tre_stack_item value) +{ + if (s->ptr < s->size) + { + s->stack[s->ptr] = value; + s->ptr++; + } + else + { + if (s->size >= s->max_size) + { + return REG_ESPACE; + } + else + { + union tre_stack_item *new_buffer; + int new_size; + new_size = s->size + s->increment; + if (new_size > s->max_size) + new_size = s->max_size; + new_buffer = xrealloc(s->stack, sizeof(*new_buffer) * new_size); + if (new_buffer == NULL) + { + return REG_ESPACE; + } + assert(new_size > s->size); + s->size = new_size; + s->stack = new_buffer; + tre_stack_push(s, value); + } + } + return REG_OK; +} + +#define define_pushf(typetag, type) \ + declare_pushf(typetag, type) { \ + union tre_stack_item item; \ + item.typetag ## _value = value; \ + return tre_stack_push(s, item); \ +} + +define_pushf(int, int) +define_pushf(voidptr, void *) + +#define define_popf(typetag, type) \ + declare_popf(typetag, type) { \ + return s->stack[--s->ptr].typetag ## _value; \ + } + +define_popf(int, int) +define_popf(voidptr, void *) + + +/*********************************************************************** + from tre-parse.c and tre-parse.h +***********************************************************************/ + +/* Parse context. */ +typedef struct { + /* Memory allocator. The AST is allocated using this. */ + tre_mem_t mem; + /* Stack used for keeping track of regexp syntax. */ + tre_stack_t *stack; + /* The parsed node after a parse function returns. */ + tre_ast_node_t *n; + /* Position in the regexp pattern after a parse function returns. */ + const char *s; + /* The first character of the last subexpression parsed. */ + const char *start; + /* Current submatch ID. */ + int submatch_id; + /* Current position (number of literal). */ + int position; + /* The highest back reference or -1 if none seen so far. */ + int max_backref; + /* Compilation flags. */ + int cflags; +} tre_parse_ctx_t; + +/* Some macros for expanding \w, \s, etc. */ +static const struct { + char c; + const char *expansion; +} tre_macros[] = { + {'t', "\t"}, {'n', "\n"}, {'r', "\r"}, + {'f', "\f"}, {'a', "\a"}, {'e', "\033"}, + {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"}, + {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"}, + { 0, 0 } +}; + +/* Expands a macro delimited by `regex' and `regex_end' to `buf', which + must have at least `len' items. Sets buf[0] to zero if the there + is no match in `tre_macros'. */ +static const char *tre_expand_macro(const char *s) +{ + int i; + for (i = 0; tre_macros[i].c && tre_macros[i].c != *s; i++); + return tre_macros[i].expansion; +} + +static int +tre_compare_lit(const void *a, const void *b) +{ + const tre_literal_t *const *la = a; + const tre_literal_t *const *lb = b; + /* assumes the range of valid code_min is < INT_MAX */ + return la[0]->code_min - lb[0]->code_min; +} + +struct literals { + tre_mem_t mem; + tre_literal_t **a; + int len; + int cap; +}; + +static tre_literal_t *tre_new_lit(struct literals *p) +{ + tre_literal_t **a; + if (p->len >= p->cap) { + if (p->cap >= 1<<15) + return 0; + p->cap *= 2; + a = xrealloc(p->a, p->cap * sizeof *p->a); + if (!a) + return 0; + p->a = a; + } + a = p->a + p->len++; + *a = tre_mem_calloc(p->mem, sizeof **a); + return *a; +} + +static int add_icase_literals(struct literals *ls, int min, int max) +{ + tre_literal_t *lit; + int b, e, c; + for (c=min; c<=max; ) { + /* assumes islower(c) and isupper(c) are exclusive + and toupper(c)!=c if islower(c). + multiple opposite case characters are not supported */ + if (tre_islower(c)) { + b = e = tre_toupper(c); + for (c++, e++; c<=max; c++, e++) + if (tre_toupper(c) != e) break; + } else if (tre_isupper(c)) { + b = e = tre_tolower(c); + for (c++, e++; c<=max; c++, e++) + if (tre_tolower(c) != e) break; + } else { + c++; + continue; + } + lit = tre_new_lit(ls); + if (!lit) + return -1; + lit->code_min = b; + lit->code_max = e-1; + lit->position = -1; + } + return 0; +} + + +/* Maximum number of character classes in a negated bracket expression. */ +#define MAX_NEG_CLASSES 64 + +struct neg { + int negate; + int len; + tre_ctype_t a[MAX_NEG_CLASSES]; +}; + +// TODO: parse bracket into a set of non-overlapping [lo,hi] ranges + +/* +bracket grammar: +Bracket = '[' List ']' | '[^' List ']' +List = Term | List Term +Term = Char | Range | Chclass | Eqclass +Range = Char '-' Char | Char '-' '-' +Char = Coll | coll_single +Meta = ']' | '-' +Coll = '[.' coll_single '.]' | '[.' coll_multi '.]' | '[.' Meta '.]' +Eqclass = '[=' coll_single '=]' | '[=' coll_multi '=]' +Chclass = '[:' class ':]' + +coll_single is a single char collating element but it can be + '-' only at the beginning or end of a List and + ']' only at the beginning of a List and + '^' anywhere except after the openning '[' +*/ + +static reg_errcode_t parse_bracket_terms(tre_parse_ctx_t *ctx, const char *s, struct literals *ls, struct neg *neg) +{ + const char *start = s; + tre_ctype_t class; + int min, max; + wchar_t wc; + int len; + + for (;;) { + class = 0; + len = mbtowc(&wc, s, -1); + if (len <= 0) + return *s ? REG_BADPAT : REG_EBRACK; + if (*s == ']' && s != start) { + ctx->s = s+1; + return REG_OK; + } + if (*s == '-' && s != start && s[1] != ']' && + /* extension: [a-z--@] is accepted as [a-z]|[--@] */ + (s[1] != '-' || s[2] == ']')) + return REG_ERANGE; + if (*s == '[' && (s[1] == '.' || s[1] == '=')) + /* collating symbols and equivalence classes are not supported */ + return REG_ECOLLATE; + if (*s == '[' && s[1] == ':') { + char tmp[CHARCLASS_NAME_MAX+1]; + s += 2; + for (len=0; len < CHARCLASS_NAME_MAX && s[len]; len++) { + if (s[len] == ':') { + memcpy(tmp, s, len); + tmp[len] = 0; + class = tre_ctype(tmp); + break; + } + } + if (!class || s[len+1] != ']') + return REG_ECTYPE; + min = 0; + max = TRE_CHAR_MAX; + s += len+2; + } else { + min = max = wc; + s += len; + if (*s == '-' && s[1] != ']') { + s++; + len = mbtowc(&wc, s, -1); + max = wc; + /* XXX - Should use collation order instead of + encoding values in character ranges. */ + if (len <= 0 || min > max) + return REG_ERANGE; + s += len; + } + } + + if (class && neg->negate) { + if (neg->len >= MAX_NEG_CLASSES) + return REG_ESPACE; + neg->a[neg->len++] = class; + } else { + tre_literal_t *lit = tre_new_lit(ls); + if (!lit) + return REG_ESPACE; + lit->code_min = min; + lit->code_max = max; + lit->class = class; + lit->position = -1; + + /* Add opposite-case codepoints if REG_ICASE is present. + It seems that POSIX requires that bracket negation + should happen before case-folding, but most practical + implementations do it the other way around. Changing + the order would need efficient representation of + case-fold ranges and bracket range sets even with + simple patterns so this is ok for now. */ + if (ctx->cflags & REG_ICASE && !class) + if (add_icase_literals(ls, min, max)) + return REG_ESPACE; + } + } +} + +static reg_errcode_t parse_bracket(tre_parse_ctx_t *ctx, const char *s) +{ + int i, max, min, negmax, negmin; + tre_ast_node_t *node = 0, *n; + tre_ctype_t *nc = 0; + tre_literal_t *lit; + struct literals ls; + struct neg neg; + reg_errcode_t err; + + ls.mem = ctx->mem; + ls.len = 0; + ls.cap = 32; + ls.a = xmalloc(ls.cap * sizeof *ls.a); + if (!ls.a) + return REG_ESPACE; + neg.len = 0; + neg.negate = *s == '^'; + if (neg.negate) + s++; + + err = parse_bracket_terms(ctx, s, &ls, &neg); + if (err != REG_OK) + goto parse_bracket_done; + + if (neg.negate) { + /* + * With REG_NEWLINE, POSIX requires that newlines are not matched by + * any form of a non-matching list. + */ + if (ctx->cflags & REG_NEWLINE) { + lit = tre_new_lit(&ls); + if (!lit) { + err = REG_ESPACE; + goto parse_bracket_done; + } + lit->code_min = '\n'; + lit->code_max = '\n'; + lit->position = -1; + } + /* Sort the array if we need to negate it. */ + qsort(ls.a, ls.len, sizeof *ls.a, tre_compare_lit); + /* extra lit for the last negated range */ + lit = tre_new_lit(&ls); + if (!lit) { + err = REG_ESPACE; + goto parse_bracket_done; + } + lit->code_min = TRE_CHAR_MAX+1; + lit->code_max = TRE_CHAR_MAX+1; + lit->position = -1; + /* negated classes */ + if (neg.len) { + nc = tre_mem_alloc(ctx->mem, (neg.len+1)*sizeof *neg.a); + if (!nc) { + err = REG_ESPACE; + goto parse_bracket_done; + } + memcpy(nc, neg.a, neg.len*sizeof *neg.a); + nc[neg.len] = 0; + } + } + + /* Build a union of the items in the array, negated if necessary. */ + negmax = negmin = 0; + for (i = 0; i < ls.len; i++) { + lit = ls.a[i]; + min = lit->code_min; + max = lit->code_max; + if (neg.negate) { + if (min <= negmin) { + /* Overlap. */ + negmin = MAX(max + 1, negmin); + continue; + } + negmax = min - 1; + lit->code_min = negmin; + lit->code_max = negmax; + negmin = max + 1; + } + lit->position = ctx->position; + lit->neg_classes = nc; + n = tre_ast_new_node(ctx->mem, LITERAL, lit); + node = tre_ast_new_union(ctx->mem, node, n); + if (!node) { + err = REG_ESPACE; + break; + } + } + +parse_bracket_done: + xfree(ls.a); + ctx->position++; + ctx->n = node; + return err; +} + +static const char *parse_dup_count(const char *s, int *n) +{ + *n = -1; + if (!isdigit(*s)) + return s; + *n = 0; + for (;;) { + *n = 10 * *n + (*s - '0'); + s++; + if (!isdigit(*s) || *n > RE_DUP_MAX) + break; + } + return s; +} + +static const char *parse_dup(const char *s, int ere, int *pmin, int *pmax) +{ + int min, max; + + s = parse_dup_count(s, &min); + if (*s == ',') + s = parse_dup_count(s+1, &max); + else + max = min; + + if ( + (max < min && max >= 0) || + max > RE_DUP_MAX || + min > RE_DUP_MAX || + min < 0 || + (!ere && *s++ != '\\') || + *s++ != '}' + ) + return 0; + *pmin = min; + *pmax = max; + return s; +} + +static int hexval(unsigned c) +{ + if (c-'0'<10) return c-'0'; + c |= 32; + if (c-'a'<6) return c-'a'+10; + return -1; +} + +static reg_errcode_t marksub(tre_parse_ctx_t *ctx, tre_ast_node_t *node, int subid) +{ + if (node->submatch_id >= 0) { + tre_ast_node_t *n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + if (!n) + return REG_ESPACE; + n = tre_ast_new_catenation(ctx->mem, n, node); + if (!n) + return REG_ESPACE; + n->num_submatches = node->num_submatches; + node = n; + } + node->submatch_id = subid; + node->num_submatches++; + ctx->n = node; + return REG_OK; +} + +/* +BRE grammar: +Regex = Branch | '^' | '$' | '^$' | '^' Branch | Branch '$' | '^' Branch '$' +Branch = Atom | Branch Atom +Atom = char | quoted_char | '.' | Bracket | Atom Dup | '\(' Branch '\)' | back_ref +Dup = '*' | '\{' Count '\}' | '\{' Count ',\}' | '\{' Count ',' Count '\}' + +(leading ^ and trailing $ in a sub expr may be an anchor or literal as well) + +ERE grammar: +Regex = Branch | Regex '|' Branch +Branch = Atom | Branch Atom +Atom = char | quoted_char | '.' | Bracket | Atom Dup | '(' Regex ')' | '^' | '$' +Dup = '*' | '+' | '?' | '{' Count '}' | '{' Count ',}' | '{' Count ',' Count '}' + +(a*+?, ^*, $+, \X, {, (|a) are unspecified) +*/ + +static reg_errcode_t parse_atom(tre_parse_ctx_t *ctx, const char *s) +{ + int len, ere = ctx->cflags & REG_EXTENDED; + const char *p; + tre_ast_node_t *node; + wchar_t wc; + switch (*s) { + case '[': + return parse_bracket(ctx, s+1); + case '\\': + p = tre_expand_macro(s+1); + if (p) { + /* assume \X expansion is a single atom */ + reg_errcode_t err = parse_atom(ctx, p); + ctx->s = s+2; + return err; + } + /* extensions: \b, \B, \<, \>, \xHH \x{HHHH} */ + switch (*++s) { + case 0: + return REG_EESCAPE; + case 'b': + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB, -1); + break; + case 'B': + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB_NEG, -1); + break; + case '<': + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOW, -1); + break; + case '>': + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOW, -1); + break; + case 'x': + s++; + int i, v = 0, c; + len = 2; + if (*s == '{') { + len = 8; + s++; + } + for (i=0; imem, v, v, ctx->position++); + s--; + break; + case '{': + case '+': + case '?': + /* extension: treat \+, \? as repetitions in BRE */ + /* reject repetitions after empty expression in BRE */ + if (!ere) + return REG_BADRPT; + case '|': + /* extension: treat \| as alternation in BRE */ + if (!ere) { + node = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + s--; + goto end; + } + /* fallthrough */ + default: + if (!ere && (unsigned)*s-'1' < 9) { + /* back reference */ + int val = *s - '0'; + node = tre_ast_new_literal(ctx->mem, BACKREF, val, ctx->position++); + ctx->max_backref = MAX(val, ctx->max_backref); + } else { + /* extension: accept unknown escaped char + as a literal */ + goto parse_literal; + } + } + s++; + break; + case '.': + if (ctx->cflags & REG_NEWLINE) { + tre_ast_node_t *tmp1, *tmp2; + tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n'-1, ctx->position++); + tmp2 = tre_ast_new_literal(ctx->mem, '\n'+1, TRE_CHAR_MAX, ctx->position++); + if (tmp1 && tmp2) + node = tre_ast_new_union(ctx->mem, tmp1, tmp2); + else + node = 0; + } else { + node = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, ctx->position++); + } + s++; + break; + case '^': + /* '^' has a special meaning everywhere in EREs, and at beginning of BRE. */ + if (!ere && s != ctx->start) + goto parse_literal; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOL, -1); + s++; + break; + case '$': + /* '$' is special everywhere in EREs, and at the end of a BRE subexpression. */ + if (!ere && s[1] && (s[1]!='\\'|| (s[2]!=')' && s[2]!='|'))) + goto parse_literal; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOL, -1); + s++; + break; + case '*': + case '{': + case '+': + case '?': + /* reject repetitions after empty expression in ERE */ + if (ere) + return REG_BADRPT; + case '|': + if (!ere) + goto parse_literal; + case 0: + node = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + break; + default: +parse_literal: + len = mbtowc(&wc, s, -1); + if (len < 0) + return REG_BADPAT; + if (ctx->cflags & REG_ICASE && (tre_isupper(wc) || tre_islower(wc))) { + tre_ast_node_t *tmp1, *tmp2; + /* multiple opposite case characters are not supported */ + tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(wc), tre_toupper(wc), ctx->position); + tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(wc), tre_tolower(wc), ctx->position); + if (tmp1 && tmp2) + node = tre_ast_new_union(ctx->mem, tmp1, tmp2); + else + node = 0; + } else { + node = tre_ast_new_literal(ctx->mem, wc, wc, ctx->position); + } + ctx->position++; + s += len; + break; + } +end: + if (!node) + return REG_ESPACE; + ctx->n = node; + ctx->s = s; + return REG_OK; +} + +#define PUSHPTR(err, s, v) do { \ + if ((err = tre_stack_push_voidptr(s, v)) != REG_OK) \ + return err; \ +} while(0) + +#define PUSHINT(err, s, v) do { \ + if ((err = tre_stack_push_int(s, v)) != REG_OK) \ + return err; \ +} while(0) + +static reg_errcode_t tre_parse(tre_parse_ctx_t *ctx) +{ + tre_ast_node_t *nbranch=0, *nunion=0; + int ere = ctx->cflags & REG_EXTENDED; + const char *s = ctx->start; + int subid = 0; + int depth = 0; + reg_errcode_t err; + tre_stack_t *stack = ctx->stack; + + PUSHINT(err, stack, subid++); + for (;;) { + if ((!ere && *s == '\\' && s[1] == '(') || + (ere && *s == '(')) { + PUSHPTR(err, stack, nunion); + PUSHPTR(err, stack, nbranch); + PUSHINT(err, stack, subid++); + s++; + if (!ere) + s++; + depth++; + nbranch = nunion = 0; + ctx->start = s; + continue; + } + if ((!ere && *s == '\\' && s[1] == ')') || + (ere && *s == ')' && depth)) { + ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + if (!ctx->n) + return REG_ESPACE; + } else { + err = parse_atom(ctx, s); + if (err != REG_OK) + return err; + s = ctx->s; + } + + parse_iter: + for (;;) { + int min, max; + + if (*s!='\\' && *s!='*') { + if (!ere) + break; + if (*s!='+' && *s!='?' && *s!='{') + break; + } + if (*s=='\\' && ere) + break; + /* extension: treat \+, \? as repetitions in BRE */ + if (*s=='\\' && s[1]!='+' && s[1]!='?' && s[1]!='{') + break; + if (*s=='\\') + s++; + + /* handle ^* at the start of a BRE. */ + if (!ere && s==ctx->start+1 && s[-1]=='^') + break; + + /* extension: multiple consecutive *+?{,} is unspecified, + but (a+)+ has to be supported so accepting a++ makes + sense, note however that the RE_DUP_MAX limit can be + circumvented: (a{255}){255} uses a lot of memory.. */ + if (*s=='{') { + s = parse_dup(s+1, ere, &min, &max); + if (!s) + return REG_BADBR; + } else { + min=0; + max=-1; + if (*s == '+') + min = 1; + if (*s == '?') + max = 1; + s++; + } + if (max == 0) + ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + else + ctx->n = tre_ast_new_iter(ctx->mem, ctx->n, min, max, 0); + if (!ctx->n) + return REG_ESPACE; + } + + nbranch = tre_ast_new_catenation(ctx->mem, nbranch, ctx->n); + if ((ere && *s == '|') || + (ere && *s == ')' && depth) || + (!ere && *s == '\\' && s[1] == ')') || + /* extension: treat \| as alternation in BRE */ + (!ere && *s == '\\' && s[1] == '|') || + !*s) { + /* extension: empty branch is unspecified (), (|a), (a|) + here they are not rejected but match on empty string */ + int c = *s; + nunion = tre_ast_new_union(ctx->mem, nunion, nbranch); + nbranch = 0; + + if (c == '\\' && s[1] == '|') { + s+=2; + ctx->start = s; + } else if (c == '|') { + s++; + ctx->start = s; + } else { + if (c == '\\') { + if (!depth) return REG_EPAREN; + s+=2; + } else if (c == ')') + s++; + depth--; + err = marksub(ctx, nunion, tre_stack_pop_int(stack)); + if (err != REG_OK) + return err; + if (!c && depth<0) { + ctx->submatch_id = subid; + return REG_OK; + } + if (!c || depth<0) + return REG_EPAREN; + nbranch = tre_stack_pop_voidptr(stack); + nunion = tre_stack_pop_voidptr(stack); + goto parse_iter; + } + } + } +} + + +/*********************************************************************** + from tre-compile.c +***********************************************************************/ + + +/* + TODO: + - Fix tre_ast_to_tnfa() to recurse using a stack instead of recursive + function calls. +*/ + +/* + Algorithms to setup tags so that submatch addressing can be done. +*/ + + +/* Inserts a catenation node to the root of the tree given in `node'. + As the left child a new tag with number `tag_id' to `node' is added, + and the right child is the old root. */ +static reg_errcode_t +tre_add_tag_left(tre_mem_t mem, tre_ast_node_t *node, int tag_id) +{ + tre_catenation_t *c; + + c = tre_mem_alloc(mem, sizeof(*c)); + if (c == NULL) + return REG_ESPACE; + c->left = tre_ast_new_literal(mem, TAG, tag_id, -1); + if (c->left == NULL) + return REG_ESPACE; + c->right = tre_mem_alloc(mem, sizeof(tre_ast_node_t)); + if (c->right == NULL) + return REG_ESPACE; + + c->right->obj = node->obj; + c->right->type = node->type; + c->right->nullable = -1; + c->right->submatch_id = -1; + c->right->firstpos = NULL; + c->right->lastpos = NULL; + c->right->num_tags = 0; + c->right->num_submatches = 0; + node->obj = c; + node->type = CATENATION; + return REG_OK; +} + +/* Inserts a catenation node to the root of the tree given in `node'. + As the right child a new tag with number `tag_id' to `node' is added, + and the left child is the old root. */ +static reg_errcode_t +tre_add_tag_right(tre_mem_t mem, tre_ast_node_t *node, int tag_id) +{ + tre_catenation_t *c; + + c = tre_mem_alloc(mem, sizeof(*c)); + if (c == NULL) + return REG_ESPACE; + c->right = tre_ast_new_literal(mem, TAG, tag_id, -1); + if (c->right == NULL) + return REG_ESPACE; + c->left = tre_mem_alloc(mem, sizeof(tre_ast_node_t)); + if (c->left == NULL) + return REG_ESPACE; + + c->left->obj = node->obj; + c->left->type = node->type; + c->left->nullable = -1; + c->left->submatch_id = -1; + c->left->firstpos = NULL; + c->left->lastpos = NULL; + c->left->num_tags = 0; + c->left->num_submatches = 0; + node->obj = c; + node->type = CATENATION; + return REG_OK; +} + +typedef enum { + ADDTAGS_RECURSE, + ADDTAGS_AFTER_ITERATION, + ADDTAGS_AFTER_UNION_LEFT, + ADDTAGS_AFTER_UNION_RIGHT, + ADDTAGS_AFTER_CAT_LEFT, + ADDTAGS_AFTER_CAT_RIGHT, + ADDTAGS_SET_SUBMATCH_END +} tre_addtags_symbol_t; + + +typedef struct { + int tag; + int next_tag; +} tre_tag_states_t; + + +/* Go through `regset' and set submatch data for submatches that are + using this tag. */ +static void +tre_purge_regset(int *regset, tre_tnfa_t *tnfa, int tag) +{ + int i; + + for (i = 0; regset[i] >= 0; i++) + { + int id = regset[i] / 2; + int start = !(regset[i] % 2); + if (start) + tnfa->submatch_data[id].so_tag = tag; + else + tnfa->submatch_data[id].eo_tag = tag; + } + regset[0] = -1; +} + + +/* Adds tags to appropriate locations in the parse tree in `tree', so that + subexpressions marked for submatch addressing can be traced. */ +static reg_errcode_t +tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree, + tre_tnfa_t *tnfa) +{ + reg_errcode_t status = REG_OK; + tre_addtags_symbol_t symbol; + tre_ast_node_t *node = tree; /* Tree node we are currently looking at. */ + int bottom = tre_stack_num_objects(stack); + /* True for first pass (counting number of needed tags) */ + int first_pass = (mem == NULL || tnfa == NULL); + int *regset, *orig_regset; + int num_tags = 0; /* Total number of tags. */ + int num_minimals = 0; /* Number of special minimal tags. */ + int tag = 0; /* The tag that is to be added next. */ + int next_tag = 1; /* Next tag to use after this one. */ + int *parents; /* Stack of submatches the current submatch is + contained in. */ + int minimal_tag = -1; /* Tag that marks the beginning of a minimal match. */ + tre_tag_states_t *saved_states; + + tre_tag_direction_t direction = TRE_TAG_MINIMIZE; + if (!first_pass) + { + tnfa->end_tag = 0; + tnfa->minimal_tags[0] = -1; + } + + regset = xmalloc(sizeof(*regset) * ((tnfa->num_submatches + 1) * 2)); + if (regset == NULL) + return REG_ESPACE; + regset[0] = -1; + orig_regset = regset; + + parents = xmalloc(sizeof(*parents) * (tnfa->num_submatches + 1)); + if (parents == NULL) + { + xfree(regset); + return REG_ESPACE; + } + parents[0] = -1; + + saved_states = xmalloc(sizeof(*saved_states) * (tnfa->num_submatches + 1)); + if (saved_states == NULL) + { + xfree(regset); + xfree(parents); + return REG_ESPACE; + } + else + { + unsigned int i; + for (i = 0; i <= tnfa->num_submatches; i++) + saved_states[i].tag = -1; + } + + STACK_PUSH(stack, voidptr, node); + STACK_PUSH(stack, int, ADDTAGS_RECURSE); + + while (tre_stack_num_objects(stack) > bottom) + { + if (status != REG_OK) + break; + + symbol = (tre_addtags_symbol_t)tre_stack_pop_int(stack); + switch (symbol) + { + + case ADDTAGS_SET_SUBMATCH_END: + { + int id = tre_stack_pop_int(stack); + int i; + + /* Add end of this submatch to regset. */ + for (i = 0; regset[i] >= 0; i++); + regset[i] = id * 2 + 1; + regset[i + 1] = -1; + + /* Pop this submatch from the parents stack. */ + for (i = 0; parents[i] >= 0; i++); + parents[i - 1] = -1; + break; + } + + case ADDTAGS_RECURSE: + node = tre_stack_pop_voidptr(stack); + + if (node->submatch_id >= 0) + { + int id = node->submatch_id; + int i; + + + /* Add start of this submatch to regset. */ + for (i = 0; regset[i] >= 0; i++); + regset[i] = id * 2; + regset[i + 1] = -1; + + if (!first_pass) + { + for (i = 0; parents[i] >= 0; i++); + tnfa->submatch_data[id].parents = NULL; + if (i > 0) + { + int *p = xmalloc(sizeof(*p) * (i + 1)); + if (p == NULL) + { + status = REG_ESPACE; + break; + } + assert(tnfa->submatch_data[id].parents == NULL); + tnfa->submatch_data[id].parents = p; + for (i = 0; parents[i] >= 0; i++) + p[i] = parents[i]; + p[i] = -1; + } + } + + /* Add end of this submatch to regset after processing this + node. */ + STACK_PUSHX(stack, int, node->submatch_id); + STACK_PUSHX(stack, int, ADDTAGS_SET_SUBMATCH_END); + } + + switch (node->type) + { + case LITERAL: + { + tre_literal_t *lit = node->obj; + + if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) + { + int i; + if (regset[0] >= 0) + { + /* Regset is not empty, so add a tag before the + literal or backref. */ + if (!first_pass) + { + status = tre_add_tag_left(mem, node, tag); + tnfa->tag_directions[tag] = direction; + if (minimal_tag >= 0) + { + for (i = 0; tnfa->minimal_tags[i] >= 0; i++); + tnfa->minimal_tags[i] = tag; + tnfa->minimal_tags[i + 1] = minimal_tag; + tnfa->minimal_tags[i + 2] = -1; + minimal_tag = -1; + num_minimals++; + } + tre_purge_regset(regset, tnfa, tag); + } + else + { + node->num_tags = 1; + } + + regset[0] = -1; + tag = next_tag; + num_tags++; + next_tag++; + } + } + else + { + assert(!IS_TAG(lit)); + } + break; + } + case CATENATION: + { + tre_catenation_t *cat = node->obj; + tre_ast_node_t *left = cat->left; + tre_ast_node_t *right = cat->right; + int reserved_tag = -1; + + + /* After processing right child. */ + STACK_PUSHX(stack, voidptr, node); + STACK_PUSHX(stack, int, ADDTAGS_AFTER_CAT_RIGHT); + + /* Process right child. */ + STACK_PUSHX(stack, voidptr, right); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + /* After processing left child. */ + STACK_PUSHX(stack, int, next_tag + left->num_tags); + if (left->num_tags > 0 && right->num_tags > 0) + { + /* Reserve the next tag to the right child. */ + reserved_tag = next_tag; + next_tag++; + } + STACK_PUSHX(stack, int, reserved_tag); + STACK_PUSHX(stack, int, ADDTAGS_AFTER_CAT_LEFT); + + /* Process left child. */ + STACK_PUSHX(stack, voidptr, left); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + } + break; + case ITERATION: + { + tre_iteration_t *iter = node->obj; + + if (first_pass) + { + STACK_PUSHX(stack, int, regset[0] >= 0 || iter->minimal); + } + else + { + STACK_PUSHX(stack, int, tag); + STACK_PUSHX(stack, int, iter->minimal); + } + STACK_PUSHX(stack, voidptr, node); + STACK_PUSHX(stack, int, ADDTAGS_AFTER_ITERATION); + + STACK_PUSHX(stack, voidptr, iter->arg); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + /* Regset is not empty, so add a tag here. */ + if (regset[0] >= 0 || iter->minimal) + { + if (!first_pass) + { + int i; + status = tre_add_tag_left(mem, node, tag); + if (iter->minimal) + tnfa->tag_directions[tag] = TRE_TAG_MAXIMIZE; + else + tnfa->tag_directions[tag] = direction; + if (minimal_tag >= 0) + { + for (i = 0; tnfa->minimal_tags[i] >= 0; i++); + tnfa->minimal_tags[i] = tag; + tnfa->minimal_tags[i + 1] = minimal_tag; + tnfa->minimal_tags[i + 2] = -1; + minimal_tag = -1; + num_minimals++; + } + tre_purge_regset(regset, tnfa, tag); + } + + regset[0] = -1; + tag = next_tag; + num_tags++; + next_tag++; + } + direction = TRE_TAG_MINIMIZE; + } + break; + case UNION: + { + tre_union_t *uni = node->obj; + tre_ast_node_t *left = uni->left; + tre_ast_node_t *right = uni->right; + int left_tag; + int right_tag; + + if (regset[0] >= 0) + { + left_tag = next_tag; + right_tag = next_tag + 1; + } + else + { + left_tag = tag; + right_tag = next_tag; + } + + /* After processing right child. */ + STACK_PUSHX(stack, int, right_tag); + STACK_PUSHX(stack, int, left_tag); + STACK_PUSHX(stack, voidptr, regset); + STACK_PUSHX(stack, int, regset[0] >= 0); + STACK_PUSHX(stack, voidptr, node); + STACK_PUSHX(stack, voidptr, right); + STACK_PUSHX(stack, voidptr, left); + STACK_PUSHX(stack, int, ADDTAGS_AFTER_UNION_RIGHT); + + /* Process right child. */ + STACK_PUSHX(stack, voidptr, right); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + /* After processing left child. */ + STACK_PUSHX(stack, int, ADDTAGS_AFTER_UNION_LEFT); + + /* Process left child. */ + STACK_PUSHX(stack, voidptr, left); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + /* Regset is not empty, so add a tag here. */ + if (regset[0] >= 0) + { + if (!first_pass) + { + int i; + status = tre_add_tag_left(mem, node, tag); + tnfa->tag_directions[tag] = direction; + if (minimal_tag >= 0) + { + for (i = 0; tnfa->minimal_tags[i] >= 0; i++); + tnfa->minimal_tags[i] = tag; + tnfa->minimal_tags[i + 1] = minimal_tag; + tnfa->minimal_tags[i + 2] = -1; + minimal_tag = -1; + num_minimals++; + } + tre_purge_regset(regset, tnfa, tag); + } + + regset[0] = -1; + tag = next_tag; + num_tags++; + next_tag++; + } + + if (node->num_submatches > 0) + { + /* The next two tags are reserved for markers. */ + next_tag++; + tag = next_tag; + next_tag++; + } + + break; + } + } + + if (node->submatch_id >= 0) + { + int i; + /* Push this submatch on the parents stack. */ + for (i = 0; parents[i] >= 0; i++); + parents[i] = node->submatch_id; + parents[i + 1] = -1; + } + + break; /* end case: ADDTAGS_RECURSE */ + + case ADDTAGS_AFTER_ITERATION: + { + int minimal = 0; + int enter_tag; + node = tre_stack_pop_voidptr(stack); + if (first_pass) + { + node->num_tags = ((tre_iteration_t *)node->obj)->arg->num_tags + + tre_stack_pop_int(stack); + minimal_tag = -1; + } + else + { + minimal = tre_stack_pop_int(stack); + enter_tag = tre_stack_pop_int(stack); + if (minimal) + minimal_tag = enter_tag; + } + + if (!first_pass) + { + if (minimal) + direction = TRE_TAG_MINIMIZE; + else + direction = TRE_TAG_MAXIMIZE; + } + break; + } + + case ADDTAGS_AFTER_CAT_LEFT: + { + int new_tag = tre_stack_pop_int(stack); + next_tag = tre_stack_pop_int(stack); + if (new_tag >= 0) + { + tag = new_tag; + } + break; + } + + case ADDTAGS_AFTER_CAT_RIGHT: + node = tre_stack_pop_voidptr(stack); + if (first_pass) + node->num_tags = ((tre_catenation_t *)node->obj)->left->num_tags + + ((tre_catenation_t *)node->obj)->right->num_tags; + break; + + case ADDTAGS_AFTER_UNION_LEFT: + /* Lift the bottom of the `regset' array so that when processing + the right operand the items currently in the array are + invisible. The original bottom was saved at ADDTAGS_UNION and + will be restored at ADDTAGS_AFTER_UNION_RIGHT below. */ + while (*regset >= 0) + regset++; + break; + + case ADDTAGS_AFTER_UNION_RIGHT: + { + int added_tags, tag_left, tag_right; + tre_ast_node_t *left = tre_stack_pop_voidptr(stack); + tre_ast_node_t *right = tre_stack_pop_voidptr(stack); + node = tre_stack_pop_voidptr(stack); + added_tags = tre_stack_pop_int(stack); + if (first_pass) + { + node->num_tags = ((tre_union_t *)node->obj)->left->num_tags + + ((tre_union_t *)node->obj)->right->num_tags + added_tags + + ((node->num_submatches > 0) ? 2 : 0); + } + regset = tre_stack_pop_voidptr(stack); + tag_left = tre_stack_pop_int(stack); + tag_right = tre_stack_pop_int(stack); + + /* Add tags after both children, the left child gets a smaller + tag than the right child. This guarantees that we prefer + the left child over the right child. */ + /* XXX - This is not always necessary (if the children have + tags which must be seen for every match of that child). */ + /* XXX - Check if this is the only place where tre_add_tag_right + is used. If so, use tre_add_tag_left (putting the tag before + the child as opposed after the child) and throw away + tre_add_tag_right. */ + if (node->num_submatches > 0) + { + if (!first_pass) + { + status = tre_add_tag_right(mem, left, tag_left); + tnfa->tag_directions[tag_left] = TRE_TAG_MAXIMIZE; + if (status == REG_OK) + status = tre_add_tag_right(mem, right, tag_right); + tnfa->tag_directions[tag_right] = TRE_TAG_MAXIMIZE; + } + num_tags += 2; + } + direction = TRE_TAG_MAXIMIZE; + break; + } + + default: + assert(0); + break; + + } /* end switch(symbol) */ + } /* end while(tre_stack_num_objects(stack) > bottom) */ + + if (!first_pass) + tre_purge_regset(regset, tnfa, tag); + + if (!first_pass && minimal_tag >= 0) + { + int i; + for (i = 0; tnfa->minimal_tags[i] >= 0; i++); + tnfa->minimal_tags[i] = tag; + tnfa->minimal_tags[i + 1] = minimal_tag; + tnfa->minimal_tags[i + 2] = -1; + minimal_tag = -1; + num_minimals++; + } + + assert(tree->num_tags == num_tags); + tnfa->end_tag = num_tags; + tnfa->num_tags = num_tags; + tnfa->num_minimals = num_minimals; + xfree(orig_regset); + xfree(parents); + xfree(saved_states); + return status; +} + + + +/* + AST to TNFA compilation routines. +*/ + +typedef enum { + COPY_RECURSE, + COPY_SET_RESULT_PTR +} tre_copyast_symbol_t; + +/* Flags for tre_copy_ast(). */ +#define COPY_REMOVE_TAGS 1 +#define COPY_MAXIMIZE_FIRST_TAG 2 + +static reg_errcode_t +tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, + int flags, int *pos_add, tre_tag_direction_t *tag_directions, + tre_ast_node_t **copy, int *max_pos) +{ + reg_errcode_t status = REG_OK; + int bottom = tre_stack_num_objects(stack); + int num_copied = 0; + int first_tag = 1; + tre_ast_node_t **result = copy; + tre_copyast_symbol_t symbol; + + STACK_PUSH(stack, voidptr, ast); + STACK_PUSH(stack, int, COPY_RECURSE); + + while (status == REG_OK && tre_stack_num_objects(stack) > bottom) + { + tre_ast_node_t *node; + if (status != REG_OK) + break; + + symbol = (tre_copyast_symbol_t)tre_stack_pop_int(stack); + switch (symbol) + { + case COPY_SET_RESULT_PTR: + result = tre_stack_pop_voidptr(stack); + break; + case COPY_RECURSE: + node = tre_stack_pop_voidptr(stack); + switch (node->type) + { + case LITERAL: + { + tre_literal_t *lit = node->obj; + int pos = lit->position; + int min = lit->code_min; + int max = lit->code_max; + if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) + { + /* XXX - e.g. [ab] has only one position but two + nodes, so we are creating holes in the state space + here. Not fatal, just wastes memory. */ + pos += *pos_add; + num_copied++; + } + else if (IS_TAG(lit) && (flags & COPY_REMOVE_TAGS)) + { + /* Change this tag to empty. */ + min = EMPTY; + max = pos = -1; + } + else if (IS_TAG(lit) && (flags & COPY_MAXIMIZE_FIRST_TAG) + && first_tag) + { + /* Maximize the first tag. */ + tag_directions[max] = TRE_TAG_MAXIMIZE; + first_tag = 0; + } + *result = tre_ast_new_literal(mem, min, max, pos); + if (*result == NULL) + status = REG_ESPACE; + else { + tre_literal_t *p = (*result)->obj; + p->class = lit->class; + p->neg_classes = lit->neg_classes; + } + + if (pos > *max_pos) + *max_pos = pos; + break; + } + case UNION: + { + tre_union_t *uni = node->obj; + tre_union_t *tmp; + *result = tre_ast_new_union(mem, uni->left, uni->right); + if (*result == NULL) + { + status = REG_ESPACE; + break; + } + tmp = (*result)->obj; + result = &tmp->left; + STACK_PUSHX(stack, voidptr, uni->right); + STACK_PUSHX(stack, int, COPY_RECURSE); + STACK_PUSHX(stack, voidptr, &tmp->right); + STACK_PUSHX(stack, int, COPY_SET_RESULT_PTR); + STACK_PUSHX(stack, voidptr, uni->left); + STACK_PUSHX(stack, int, COPY_RECURSE); + break; + } + case CATENATION: + { + tre_catenation_t *cat = node->obj; + tre_catenation_t *tmp; + *result = tre_ast_new_catenation(mem, cat->left, cat->right); + if (*result == NULL) + { + status = REG_ESPACE; + break; + } + tmp = (*result)->obj; + tmp->left = NULL; + tmp->right = NULL; + result = &tmp->left; + + STACK_PUSHX(stack, voidptr, cat->right); + STACK_PUSHX(stack, int, COPY_RECURSE); + STACK_PUSHX(stack, voidptr, &tmp->right); + STACK_PUSHX(stack, int, COPY_SET_RESULT_PTR); + STACK_PUSHX(stack, voidptr, cat->left); + STACK_PUSHX(stack, int, COPY_RECURSE); + break; + } + case ITERATION: + { + tre_iteration_t *iter = node->obj; + STACK_PUSHX(stack, voidptr, iter->arg); + STACK_PUSHX(stack, int, COPY_RECURSE); + *result = tre_ast_new_iter(mem, iter->arg, iter->min, + iter->max, iter->minimal); + if (*result == NULL) + { + status = REG_ESPACE; + break; + } + iter = (*result)->obj; + result = &iter->arg; + break; + } + default: + assert(0); + break; + } + break; + } + } + *pos_add += num_copied; + return status; +} + +typedef enum { + EXPAND_RECURSE, + EXPAND_AFTER_ITER +} tre_expand_ast_symbol_t; + +/* Expands each iteration node that has a finite nonzero minimum or maximum + iteration count to a catenated sequence of copies of the node. */ +static reg_errcode_t +tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, + int *position, tre_tag_direction_t *tag_directions) +{ + reg_errcode_t status = REG_OK; + int bottom = tre_stack_num_objects(stack); + int pos_add = 0; + int pos_add_total = 0; + int max_pos = 0; + int iter_depth = 0; + + STACK_PUSHR(stack, voidptr, ast); + STACK_PUSHR(stack, int, EXPAND_RECURSE); + while (status == REG_OK && tre_stack_num_objects(stack) > bottom) + { + tre_ast_node_t *node; + tre_expand_ast_symbol_t symbol; + + if (status != REG_OK) + break; + + symbol = (tre_expand_ast_symbol_t)tre_stack_pop_int(stack); + node = tre_stack_pop_voidptr(stack); + switch (symbol) + { + case EXPAND_RECURSE: + switch (node->type) + { + case LITERAL: + { + tre_literal_t *lit= node->obj; + if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) + { + lit->position += pos_add; + if (lit->position > max_pos) + max_pos = lit->position; + } + break; + } + case UNION: + { + tre_union_t *uni = node->obj; + STACK_PUSHX(stack, voidptr, uni->right); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + STACK_PUSHX(stack, voidptr, uni->left); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + break; + } + case CATENATION: + { + tre_catenation_t *cat = node->obj; + STACK_PUSHX(stack, voidptr, cat->right); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + STACK_PUSHX(stack, voidptr, cat->left); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + break; + } + case ITERATION: + { + tre_iteration_t *iter = node->obj; + STACK_PUSHX(stack, int, pos_add); + STACK_PUSHX(stack, voidptr, node); + STACK_PUSHX(stack, int, EXPAND_AFTER_ITER); + STACK_PUSHX(stack, voidptr, iter->arg); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + /* If we are going to expand this node at EXPAND_AFTER_ITER + then don't increase the `pos' fields of the nodes now, it + will get done when expanding. */ + if (iter->min > 1 || iter->max > 1) + pos_add = 0; + iter_depth++; + break; + } + default: + assert(0); + break; + } + break; + case EXPAND_AFTER_ITER: + { + tre_iteration_t *iter = node->obj; + int pos_add_last; + pos_add = tre_stack_pop_int(stack); + pos_add_last = pos_add; + if (iter->min > 1 || iter->max > 1) + { + tre_ast_node_t *seq1 = NULL, *seq2 = NULL; + int j; + int pos_add_save = pos_add; + + /* Create a catenated sequence of copies of the node. */ + for (j = 0; j < iter->min; j++) + { + tre_ast_node_t *copy; + /* Remove tags from all but the last copy. */ + int flags = ((j + 1 < iter->min) + ? COPY_REMOVE_TAGS + : COPY_MAXIMIZE_FIRST_TAG); + pos_add_save = pos_add; + status = tre_copy_ast(mem, stack, iter->arg, flags, + &pos_add, tag_directions, ©, + &max_pos); + if (status != REG_OK) + return status; + if (seq1 != NULL) + seq1 = tre_ast_new_catenation(mem, seq1, copy); + else + seq1 = copy; + if (seq1 == NULL) + return REG_ESPACE; + } + + if (iter->max == -1) + { + /* No upper limit. */ + pos_add_save = pos_add; + status = tre_copy_ast(mem, stack, iter->arg, 0, + &pos_add, NULL, &seq2, &max_pos); + if (status != REG_OK) + return status; + seq2 = tre_ast_new_iter(mem, seq2, 0, -1, 0); + if (seq2 == NULL) + return REG_ESPACE; + } + else + { + for (j = iter->min; j < iter->max; j++) + { + tre_ast_node_t *tmp, *copy; + pos_add_save = pos_add; + status = tre_copy_ast(mem, stack, iter->arg, 0, + &pos_add, NULL, ©, &max_pos); + if (status != REG_OK) + return status; + if (seq2 != NULL) + seq2 = tre_ast_new_catenation(mem, copy, seq2); + else + seq2 = copy; + if (seq2 == NULL) + return REG_ESPACE; + tmp = tre_ast_new_literal(mem, EMPTY, -1, -1); + if (tmp == NULL) + return REG_ESPACE; + seq2 = tre_ast_new_union(mem, tmp, seq2); + if (seq2 == NULL) + return REG_ESPACE; + } + } + + pos_add = pos_add_save; + if (seq1 == NULL) + seq1 = seq2; + else if (seq2 != NULL) + seq1 = tre_ast_new_catenation(mem, seq1, seq2); + if (seq1 == NULL) + return REG_ESPACE; + node->obj = seq1->obj; + node->type = seq1->type; + } + + iter_depth--; + pos_add_total += pos_add - pos_add_last; + if (iter_depth == 0) + pos_add = pos_add_total; + + break; + } + default: + assert(0); + break; + } + } + + *position += pos_add_total; + + /* `max_pos' should never be larger than `*position' if the above + code works, but just an extra safeguard let's make sure + `*position' is set large enough so enough memory will be + allocated for the transition table. */ + if (max_pos > *position) + *position = max_pos; + + return status; +} + +static tre_pos_and_tags_t * +tre_set_empty(tre_mem_t mem) +{ + tre_pos_and_tags_t *new_set; + + new_set = tre_mem_calloc(mem, sizeof(*new_set)); + if (new_set == NULL) + return NULL; + + new_set[0].position = -1; + new_set[0].code_min = -1; + new_set[0].code_max = -1; + + return new_set; +} + +static tre_pos_and_tags_t * +tre_set_one(tre_mem_t mem, int position, int code_min, int code_max, + tre_ctype_t class, tre_ctype_t *neg_classes, int backref) +{ + tre_pos_and_tags_t *new_set; + + new_set = tre_mem_calloc(mem, sizeof(*new_set) * 2); + if (new_set == NULL) + return NULL; + + new_set[0].position = position; + new_set[0].code_min = code_min; + new_set[0].code_max = code_max; + new_set[0].class = class; + new_set[0].neg_classes = neg_classes; + new_set[0].backref = backref; + new_set[1].position = -1; + new_set[1].code_min = -1; + new_set[1].code_max = -1; + + return new_set; +} + +static tre_pos_and_tags_t * +tre_set_union(tre_mem_t mem, tre_pos_and_tags_t *set1, tre_pos_and_tags_t *set2, + int *tags, int assertions) +{ + int s1, s2, i, j; + tre_pos_and_tags_t *new_set; + int *new_tags; + int num_tags; + + for (num_tags = 0; tags != NULL && tags[num_tags] >= 0; num_tags++); + for (s1 = 0; set1[s1].position >= 0; s1++); + for (s2 = 0; set2[s2].position >= 0; s2++); + new_set = tre_mem_calloc(mem, sizeof(*new_set) * (s1 + s2 + 1)); + if (!new_set ) + return NULL; + + for (s1 = 0; set1[s1].position >= 0; s1++) + { + new_set[s1].position = set1[s1].position; + new_set[s1].code_min = set1[s1].code_min; + new_set[s1].code_max = set1[s1].code_max; + new_set[s1].assertions = set1[s1].assertions | assertions; + new_set[s1].class = set1[s1].class; + new_set[s1].neg_classes = set1[s1].neg_classes; + new_set[s1].backref = set1[s1].backref; + if (set1[s1].tags == NULL && tags == NULL) + new_set[s1].tags = NULL; + else + { + for (i = 0; set1[s1].tags != NULL && set1[s1].tags[i] >= 0; i++); + new_tags = tre_mem_alloc(mem, (sizeof(*new_tags) + * (i + num_tags + 1))); + if (new_tags == NULL) + return NULL; + for (j = 0; j < i; j++) + new_tags[j] = set1[s1].tags[j]; + for (i = 0; i < num_tags; i++) + new_tags[j + i] = tags[i]; + new_tags[j + i] = -1; + new_set[s1].tags = new_tags; + } + } + + for (s2 = 0; set2[s2].position >= 0; s2++) + { + new_set[s1 + s2].position = set2[s2].position; + new_set[s1 + s2].code_min = set2[s2].code_min; + new_set[s1 + s2].code_max = set2[s2].code_max; + /* XXX - why not | assertions here as well? */ + new_set[s1 + s2].assertions = set2[s2].assertions; + new_set[s1 + s2].class = set2[s2].class; + new_set[s1 + s2].neg_classes = set2[s2].neg_classes; + new_set[s1 + s2].backref = set2[s2].backref; + if (set2[s2].tags == NULL) + new_set[s1 + s2].tags = NULL; + else + { + for (i = 0; set2[s2].tags[i] >= 0; i++); + new_tags = tre_mem_alloc(mem, sizeof(*new_tags) * (i + 1)); + if (new_tags == NULL) + return NULL; + for (j = 0; j < i; j++) + new_tags[j] = set2[s2].tags[j]; + new_tags[j] = -1; + new_set[s1 + s2].tags = new_tags; + } + } + new_set[s1 + s2].position = -1; + return new_set; +} + +/* Finds the empty path through `node' which is the one that should be + taken according to POSIX.2 rules, and adds the tags on that path to + `tags'. `tags' may be NULL. If `num_tags_seen' is not NULL, it is + set to the number of tags seen on the path. */ +static reg_errcode_t +tre_match_empty(tre_stack_t *stack, tre_ast_node_t *node, int *tags, + int *assertions, int *num_tags_seen) +{ + tre_literal_t *lit; + tre_union_t *uni; + tre_catenation_t *cat; + tre_iteration_t *iter; + int i; + int bottom = tre_stack_num_objects(stack); + reg_errcode_t status = REG_OK; + if (num_tags_seen) + *num_tags_seen = 0; + + status = tre_stack_push_voidptr(stack, node); + + /* Walk through the tree recursively. */ + while (status == REG_OK && tre_stack_num_objects(stack) > bottom) + { + node = tre_stack_pop_voidptr(stack); + + switch (node->type) + { + case LITERAL: + lit = (tre_literal_t *)node->obj; + switch (lit->code_min) + { + case TAG: + if (lit->code_max >= 0) + { + if (tags != NULL) + { + /* Add the tag to `tags'. */ + for (i = 0; tags[i] >= 0; i++) + if (tags[i] == lit->code_max) + break; + if (tags[i] < 0) + { + tags[i] = lit->code_max; + tags[i + 1] = -1; + } + } + if (num_tags_seen) + (*num_tags_seen)++; + } + break; + case ASSERTION: + assert(lit->code_max >= 1 + || lit->code_max <= ASSERT_LAST); + if (assertions != NULL) + *assertions |= lit->code_max; + break; + case EMPTY: + break; + default: + assert(0); + break; + } + break; + + case UNION: + /* Subexpressions starting earlier take priority over ones + starting later, so we prefer the left subexpression over the + right subexpression. */ + uni = (tre_union_t *)node->obj; + if (uni->left->nullable) + STACK_PUSHX(stack, voidptr, uni->left) + else if (uni->right->nullable) + STACK_PUSHX(stack, voidptr, uni->right) + else + assert(0); + break; + + case CATENATION: + /* The path must go through both children. */ + cat = (tre_catenation_t *)node->obj; + assert(cat->left->nullable); + assert(cat->right->nullable); + STACK_PUSHX(stack, voidptr, cat->left); + STACK_PUSHX(stack, voidptr, cat->right); + break; + + case ITERATION: + /* A match with an empty string is preferred over no match at + all, so we go through the argument if possible. */ + iter = (tre_iteration_t *)node->obj; + if (iter->arg->nullable) + STACK_PUSHX(stack, voidptr, iter->arg); + break; + + default: + assert(0); + break; + } + } + + return status; +} + + +typedef enum { + NFL_RECURSE, + NFL_POST_UNION, + NFL_POST_CATENATION, + NFL_POST_ITERATION +} tre_nfl_stack_symbol_t; + + +/* Computes and fills in the fields `nullable', `firstpos', and `lastpos' for + the nodes of the AST `tree'. */ +static reg_errcode_t +tre_compute_nfl(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree) +{ + int bottom = tre_stack_num_objects(stack); + + STACK_PUSHR(stack, voidptr, tree); + STACK_PUSHR(stack, int, NFL_RECURSE); + + while (tre_stack_num_objects(stack) > bottom) + { + tre_nfl_stack_symbol_t symbol; + tre_ast_node_t *node; + + symbol = (tre_nfl_stack_symbol_t)tre_stack_pop_int(stack); + node = tre_stack_pop_voidptr(stack); + switch (symbol) + { + case NFL_RECURSE: + switch (node->type) + { + case LITERAL: + { + tre_literal_t *lit = (tre_literal_t *)node->obj; + if (IS_BACKREF(lit)) + { + /* Back references: nullable = false, firstpos = {i}, + lastpos = {i}. */ + node->nullable = 0; + node->firstpos = tre_set_one(mem, lit->position, 0, + TRE_CHAR_MAX, 0, NULL, -1); + if (!node->firstpos) + return REG_ESPACE; + node->lastpos = tre_set_one(mem, lit->position, 0, + TRE_CHAR_MAX, 0, NULL, + (int)lit->code_max); + if (!node->lastpos) + return REG_ESPACE; + } + else if (lit->code_min < 0) + { + /* Tags, empty strings, params, and zero width assertions: + nullable = true, firstpos = {}, and lastpos = {}. */ + node->nullable = 1; + node->firstpos = tre_set_empty(mem); + if (!node->firstpos) + return REG_ESPACE; + node->lastpos = tre_set_empty(mem); + if (!node->lastpos) + return REG_ESPACE; + } + else + { + /* Literal at position i: nullable = false, firstpos = {i}, + lastpos = {i}. */ + node->nullable = 0; + node->firstpos = + tre_set_one(mem, lit->position, (int)lit->code_min, + (int)lit->code_max, 0, NULL, -1); + if (!node->firstpos) + return REG_ESPACE; + node->lastpos = tre_set_one(mem, lit->position, + (int)lit->code_min, + (int)lit->code_max, + lit->class, lit->neg_classes, + -1); + if (!node->lastpos) + return REG_ESPACE; + } + break; + } + + case UNION: + /* Compute the attributes for the two subtrees, and after that + for this node. */ + STACK_PUSHR(stack, voidptr, node); + STACK_PUSHR(stack, int, NFL_POST_UNION); + STACK_PUSHR(stack, voidptr, ((tre_union_t *)node->obj)->right); + STACK_PUSHR(stack, int, NFL_RECURSE); + STACK_PUSHR(stack, voidptr, ((tre_union_t *)node->obj)->left); + STACK_PUSHR(stack, int, NFL_RECURSE); + break; + + case CATENATION: + /* Compute the attributes for the two subtrees, and after that + for this node. */ + STACK_PUSHR(stack, voidptr, node); + STACK_PUSHR(stack, int, NFL_POST_CATENATION); + STACK_PUSHR(stack, voidptr, ((tre_catenation_t *)node->obj)->right); + STACK_PUSHR(stack, int, NFL_RECURSE); + STACK_PUSHR(stack, voidptr, ((tre_catenation_t *)node->obj)->left); + STACK_PUSHR(stack, int, NFL_RECURSE); + break; + + case ITERATION: + /* Compute the attributes for the subtree, and after that for + this node. */ + STACK_PUSHR(stack, voidptr, node); + STACK_PUSHR(stack, int, NFL_POST_ITERATION); + STACK_PUSHR(stack, voidptr, ((tre_iteration_t *)node->obj)->arg); + STACK_PUSHR(stack, int, NFL_RECURSE); + break; + } + break; /* end case: NFL_RECURSE */ + + case NFL_POST_UNION: + { + tre_union_t *uni = (tre_union_t *)node->obj; + node->nullable = uni->left->nullable || uni->right->nullable; + node->firstpos = tre_set_union(mem, uni->left->firstpos, + uni->right->firstpos, NULL, 0); + if (!node->firstpos) + return REG_ESPACE; + node->lastpos = tre_set_union(mem, uni->left->lastpos, + uni->right->lastpos, NULL, 0); + if (!node->lastpos) + return REG_ESPACE; + break; + } + + case NFL_POST_ITERATION: + { + tre_iteration_t *iter = (tre_iteration_t *)node->obj; + + if (iter->min == 0 || iter->arg->nullable) + node->nullable = 1; + else + node->nullable = 0; + node->firstpos = iter->arg->firstpos; + node->lastpos = iter->arg->lastpos; + break; + } + + case NFL_POST_CATENATION: + { + int num_tags, *tags, assertions; + reg_errcode_t status; + tre_catenation_t *cat = node->obj; + node->nullable = cat->left->nullable && cat->right->nullable; + + /* Compute firstpos. */ + if (cat->left->nullable) + { + /* The left side matches the empty string. Make a first pass + with tre_match_empty() to get the number of tags and + parameters. */ + status = tre_match_empty(stack, cat->left, + NULL, NULL, &num_tags); + if (status != REG_OK) + return status; + /* Allocate arrays for the tags and parameters. */ + tags = xmalloc(sizeof(*tags) * (num_tags + 1)); + if (!tags) + return REG_ESPACE; + tags[0] = -1; + assertions = 0; + /* Second pass with tre_mach_empty() to get the list of + tags and parameters. */ + status = tre_match_empty(stack, cat->left, tags, + &assertions, NULL); + if (status != REG_OK) + { + xfree(tags); + return status; + } + node->firstpos = + tre_set_union(mem, cat->right->firstpos, cat->left->firstpos, + tags, assertions); + xfree(tags); + if (!node->firstpos) + return REG_ESPACE; + } + else + { + node->firstpos = cat->left->firstpos; + } + + /* Compute lastpos. */ + if (cat->right->nullable) + { + /* The right side matches the empty string. Make a first pass + with tre_match_empty() to get the number of tags and + parameters. */ + status = tre_match_empty(stack, cat->right, + NULL, NULL, &num_tags); + if (status != REG_OK) + return status; + /* Allocate arrays for the tags and parameters. */ + tags = xmalloc(sizeof(int) * (num_tags + 1)); + if (!tags) + return REG_ESPACE; + tags[0] = -1; + assertions = 0; + /* Second pass with tre_mach_empty() to get the list of + tags and parameters. */ + status = tre_match_empty(stack, cat->right, tags, + &assertions, NULL); + if (status != REG_OK) + { + xfree(tags); + return status; + } + node->lastpos = + tre_set_union(mem, cat->left->lastpos, cat->right->lastpos, + tags, assertions); + xfree(tags); + if (!node->lastpos) + return REG_ESPACE; + } + else + { + node->lastpos = cat->right->lastpos; + } + break; + } + + default: + assert(0); + break; + } + } + + return REG_OK; +} + + +/* Adds a transition from each position in `p1' to each position in `p2'. */ +static reg_errcode_t +tre_make_trans(tre_pos_and_tags_t *p1, tre_pos_and_tags_t *p2, + tre_tnfa_transition_t *transitions, + int *counts, int *offs) +{ + tre_pos_and_tags_t *orig_p2 = p2; + tre_tnfa_transition_t *trans; + int i, j, k, l, dup, prev_p2_pos; + + if (transitions != NULL) + while (p1->position >= 0) + { + p2 = orig_p2; + prev_p2_pos = -1; + while (p2->position >= 0) + { + /* Optimization: if this position was already handled, skip it. */ + if (p2->position == prev_p2_pos) + { + p2++; + continue; + } + prev_p2_pos = p2->position; + /* Set `trans' to point to the next unused transition from + position `p1->position'. */ + trans = transitions + offs[p1->position]; + while (trans->state != NULL) + { +#if 0 + /* If we find a previous transition from `p1->position' to + `p2->position', it is overwritten. This can happen only + if there are nested loops in the regexp, like in "((a)*)*". + In POSIX.2 repetition using the outer loop is always + preferred over using the inner loop. Therefore the + transition for the inner loop is useless and can be thrown + away. */ + /* XXX - The same position is used for all nodes in a bracket + expression, so this optimization cannot be used (it will + break bracket expressions) unless I figure out a way to + detect it here. */ + if (trans->state_id == p2->position) + { + break; + } +#endif + trans++; + } + + if (trans->state == NULL) + (trans + 1)->state = NULL; + /* Use the character ranges, assertions, etc. from `p1' for + the transition from `p1' to `p2'. */ + trans->code_min = p1->code_min; + trans->code_max = p1->code_max; + trans->state = transitions + offs[p2->position]; + trans->state_id = p2->position; + trans->assertions = p1->assertions | p2->assertions + | (p1->class ? ASSERT_CHAR_CLASS : 0) + | (p1->neg_classes != NULL ? ASSERT_CHAR_CLASS_NEG : 0); + if (p1->backref >= 0) + { + assert((trans->assertions & ASSERT_CHAR_CLASS) == 0); + assert(p2->backref < 0); + trans->u.backref = p1->backref; + trans->assertions |= ASSERT_BACKREF; + } + else + trans->u.class = p1->class; + if (p1->neg_classes != NULL) + { + for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++); + trans->neg_classes = + xmalloc(sizeof(*trans->neg_classes) * (i + 1)); + if (trans->neg_classes == NULL) + return REG_ESPACE; + for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++) + trans->neg_classes[i] = p1->neg_classes[i]; + trans->neg_classes[i] = (tre_ctype_t)0; + } + else + trans->neg_classes = NULL; + + /* Find out how many tags this transition has. */ + i = 0; + if (p1->tags != NULL) + while(p1->tags[i] >= 0) + i++; + j = 0; + if (p2->tags != NULL) + while(p2->tags[j] >= 0) + j++; + + /* If we are overwriting a transition, free the old tag array. */ + if (trans->tags != NULL) + xfree(trans->tags); + trans->tags = NULL; + + /* If there were any tags, allocate an array and fill it. */ + if (i + j > 0) + { + trans->tags = xmalloc(sizeof(*trans->tags) * (i + j + 1)); + if (!trans->tags) + return REG_ESPACE; + i = 0; + if (p1->tags != NULL) + while(p1->tags[i] >= 0) + { + trans->tags[i] = p1->tags[i]; + i++; + } + l = i; + j = 0; + if (p2->tags != NULL) + while (p2->tags[j] >= 0) + { + /* Don't add duplicates. */ + dup = 0; + for (k = 0; k < i; k++) + if (trans->tags[k] == p2->tags[j]) + { + dup = 1; + break; + } + if (!dup) + trans->tags[l++] = p2->tags[j]; + j++; + } + trans->tags[l] = -1; + } + + p2++; + } + p1++; + } + else + /* Compute a maximum limit for the number of transitions leaving + from each state. */ + while (p1->position >= 0) + { + p2 = orig_p2; + while (p2->position >= 0) + { + counts[p1->position]++; + p2++; + } + p1++; + } + return REG_OK; +} + +/* Converts the syntax tree to a TNFA. All the transitions in the TNFA are + labelled with one character range (there are no transitions on empty + strings). The TNFA takes O(n^2) space in the worst case, `n' is size of + the regexp. */ +static reg_errcode_t +tre_ast_to_tnfa(tre_ast_node_t *node, tre_tnfa_transition_t *transitions, + int *counts, int *offs) +{ + tre_union_t *uni; + tre_catenation_t *cat; + tre_iteration_t *iter; + reg_errcode_t errcode = REG_OK; + + /* XXX - recurse using a stack!. */ + switch (node->type) + { + case LITERAL: + break; + case UNION: + uni = (tre_union_t *)node->obj; + errcode = tre_ast_to_tnfa(uni->left, transitions, counts, offs); + if (errcode != REG_OK) + return errcode; + errcode = tre_ast_to_tnfa(uni->right, transitions, counts, offs); + break; + + case CATENATION: + cat = (tre_catenation_t *)node->obj; + /* Add a transition from each position in cat->left->lastpos + to each position in cat->right->firstpos. */ + errcode = tre_make_trans(cat->left->lastpos, cat->right->firstpos, + transitions, counts, offs); + if (errcode != REG_OK) + return errcode; + errcode = tre_ast_to_tnfa(cat->left, transitions, counts, offs); + if (errcode != REG_OK) + return errcode; + errcode = tre_ast_to_tnfa(cat->right, transitions, counts, offs); + break; + + case ITERATION: + iter = (tre_iteration_t *)node->obj; + assert(iter->max == -1 || iter->max == 1); + + if (iter->max == -1) + { + assert(iter->min == 0 || iter->min == 1); + /* Add a transition from each last position in the iterated + expression to each first position. */ + errcode = tre_make_trans(iter->arg->lastpos, iter->arg->firstpos, + transitions, counts, offs); + if (errcode != REG_OK) + return errcode; + } + errcode = tre_ast_to_tnfa(iter->arg, transitions, counts, offs); + break; + } + return errcode; +} + + +#define ERROR_EXIT(err) \ + do \ + { \ + errcode = err; \ + if (/*CONSTCOND*/1) \ + goto error_exit; \ + } \ + while (/*CONSTCOND*/0) + + +int +regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) +{ + tre_stack_t *stack; + tre_ast_node_t *tree, *tmp_ast_l, *tmp_ast_r; + tre_pos_and_tags_t *p; + int *counts = NULL, *offs = NULL; + int i, add = 0; + tre_tnfa_transition_t *transitions, *initial; + tre_tnfa_t *tnfa = NULL; + tre_submatch_data_t *submatch_data; + tre_tag_direction_t *tag_directions = NULL; + reg_errcode_t errcode; + tre_mem_t mem; + + /* Parse context. */ + tre_parse_ctx_t parse_ctx; + + /* Allocate a stack used throughout the compilation process for various + purposes. */ + stack = tre_stack_new(512, 1024000, 128); + if (!stack) + return REG_ESPACE; + /* Allocate a fast memory allocator. */ + mem = tre_mem_new(); + if (!mem) + { + tre_stack_destroy(stack); + return REG_ESPACE; + } + + /* Parse the regexp. */ + memset(&parse_ctx, 0, sizeof(parse_ctx)); + parse_ctx.mem = mem; + parse_ctx.stack = stack; + parse_ctx.start = regex; + parse_ctx.cflags = cflags; + parse_ctx.max_backref = -1; + errcode = tre_parse(&parse_ctx); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + preg->re_nsub = parse_ctx.submatch_id - 1; + tree = parse_ctx.n; + +#ifdef TRE_DEBUG + tre_ast_print(tree); +#endif /* TRE_DEBUG */ + + /* Referring to nonexistent subexpressions is illegal. */ + if (parse_ctx.max_backref > (int)preg->re_nsub) + ERROR_EXIT(REG_ESUBREG); + + /* Allocate the TNFA struct. */ + tnfa = xcalloc(1, sizeof(tre_tnfa_t)); + if (tnfa == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->have_backrefs = parse_ctx.max_backref >= 0; + tnfa->have_approx = 0; + tnfa->num_submatches = parse_ctx.submatch_id; + + /* Set up tags for submatch addressing. If REG_NOSUB is set and the + regexp does not have back references, this can be skipped. */ + if (tnfa->have_backrefs || !(cflags & REG_NOSUB)) + { + + /* Figure out how many tags we will need. */ + errcode = tre_add_tags(NULL, stack, tree, tnfa); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + if (tnfa->num_tags > 0) + { + tag_directions = xmalloc(sizeof(*tag_directions) + * (tnfa->num_tags + 1)); + if (tag_directions == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->tag_directions = tag_directions; + memset(tag_directions, -1, + sizeof(*tag_directions) * (tnfa->num_tags + 1)); + } + tnfa->minimal_tags = xcalloc((unsigned)tnfa->num_tags * 2 + 1, + sizeof(*tnfa->minimal_tags)); + if (tnfa->minimal_tags == NULL) + ERROR_EXIT(REG_ESPACE); + + submatch_data = xcalloc((unsigned)parse_ctx.submatch_id, + sizeof(*submatch_data)); + if (submatch_data == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->submatch_data = submatch_data; + + errcode = tre_add_tags(mem, stack, tree, tnfa); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + } + + /* Expand iteration nodes. */ + errcode = tre_expand_ast(mem, stack, tree, &parse_ctx.position, + tag_directions); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + /* Add a dummy node for the final state. + XXX - For certain patterns this dummy node can be optimized away, + for example "a*" or "ab*". Figure out a simple way to detect + this possibility. */ + tmp_ast_l = tree; + tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position++); + if (tmp_ast_r == NULL) + ERROR_EXIT(REG_ESPACE); + + tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r); + if (tree == NULL) + ERROR_EXIT(REG_ESPACE); + + errcode = tre_compute_nfl(mem, stack, tree); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + counts = xmalloc(sizeof(int) * parse_ctx.position); + if (counts == NULL) + ERROR_EXIT(REG_ESPACE); + + offs = xmalloc(sizeof(int) * parse_ctx.position); + if (offs == NULL) + ERROR_EXIT(REG_ESPACE); + + for (i = 0; i < parse_ctx.position; i++) + counts[i] = 0; + tre_ast_to_tnfa(tree, NULL, counts, NULL); + + add = 0; + for (i = 0; i < parse_ctx.position; i++) + { + offs[i] = add; + add += counts[i] + 1; + counts[i] = 0; + } + transitions = xcalloc((unsigned)add + 1, sizeof(*transitions)); + if (transitions == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->transitions = transitions; + tnfa->num_transitions = add; + + errcode = tre_ast_to_tnfa(tree, transitions, counts, offs); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + tnfa->firstpos_chars = NULL; + + p = tree->firstpos; + i = 0; + while (p->position >= 0) + { + i++; + p++; + } + + initial = xcalloc((unsigned)i + 1, sizeof(tre_tnfa_transition_t)); + if (initial == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->initial = initial; + + i = 0; + for (p = tree->firstpos; p->position >= 0; p++) + { + initial[i].state = transitions + offs[p->position]; + initial[i].state_id = p->position; + initial[i].tags = NULL; + /* Copy the arrays p->tags, and p->params, they are allocated + from a tre_mem object. */ + if (p->tags) + { + int j; + for (j = 0; p->tags[j] >= 0; j++); + initial[i].tags = xmalloc(sizeof(*p->tags) * (j + 1)); + if (!initial[i].tags) + ERROR_EXIT(REG_ESPACE); + memcpy(initial[i].tags, p->tags, sizeof(*p->tags) * (j + 1)); + } + initial[i].assertions = p->assertions; + i++; + } + initial[i].state = NULL; + + tnfa->num_transitions = add; + tnfa->final = transitions + offs[tree->lastpos[0].position]; + tnfa->num_states = parse_ctx.position; + tnfa->cflags = cflags; + + tre_mem_destroy(mem); + tre_stack_destroy(stack); + xfree(counts); + xfree(offs); + + preg->TRE_REGEX_T_FIELD = (void *)tnfa; + return REG_OK; + + error_exit: + /* Free everything that was allocated and return the error code. */ + tre_mem_destroy(mem); + if (stack != NULL) + tre_stack_destroy(stack); + if (counts != NULL) + xfree(counts); + if (offs != NULL) + xfree(offs); + preg->TRE_REGEX_T_FIELD = (void *)tnfa; + regfree(preg); + return errcode; +} + + + + +void +regfree(regex_t *preg) +{ + tre_tnfa_t *tnfa; + unsigned int i; + tre_tnfa_transition_t *trans; + + tnfa = (void *)preg->TRE_REGEX_T_FIELD; + if (!tnfa) + return; + + for (i = 0; i < tnfa->num_transitions; i++) + if (tnfa->transitions[i].state) + { + if (tnfa->transitions[i].tags) + xfree(tnfa->transitions[i].tags); + if (tnfa->transitions[i].neg_classes) + xfree(tnfa->transitions[i].neg_classes); + } + if (tnfa->transitions) + xfree(tnfa->transitions); + + if (tnfa->initial) + { + for (trans = tnfa->initial; trans->state; trans++) + { + if (trans->tags) + xfree(trans->tags); + } + xfree(tnfa->initial); + } + + if (tnfa->submatch_data) + { + for (i = 0; i < tnfa->num_submatches; i++) + if (tnfa->submatch_data[i].parents) + xfree(tnfa->submatch_data[i].parents); + xfree(tnfa->submatch_data); + } + + if (tnfa->tag_directions) + xfree(tnfa->tag_directions); + if (tnfa->firstpos_chars) + xfree(tnfa->firstpos_chars); + if (tnfa->minimal_tags) + xfree(tnfa->minimal_tags); + xfree(tnfa); +} \ No newline at end of file diff --git a/user/include/mlibc/options/posix/musl-generic-regex/regerror.c b/user/include/mlibc/options/posix/musl-generic-regex/regerror.c new file mode 100644 index 0000000..41e9a36 --- /dev/null +++ b/user/include/mlibc/options/posix/musl-generic-regex/regerror.c @@ -0,0 +1,37 @@ +#include +#include +#include +// #include "locale_impl.h" + +/* Error message strings for error codes listed in `regex.h'. This list + needs to be in sync with the codes listed there, naturally. */ + +/* Converted to single string by Rich Felker to remove the need for + * data relocations at runtime, 27 Feb 2006. */ + +static const char messages[] = { + "No error\0" + "No match\0" + "Invalid regexp\0" + "Unknown collating element\0" + "Unknown character class name\0" + "Trailing backslash\0" + "Invalid back reference\0" + "Missing ']'\0" + "Missing ')'\0" + "Missing '}'\0" + "Invalid contents of {}\0" + "Invalid character range\0" + "Out of memory\0" + "Repetition not preceded by valid expression\0" + "\0Unknown error" +}; + +size_t regerror(int e, const regex_t *restrict preg, char *restrict buf, size_t size) +{ + const char *s; + for (s=messages; e && *s; e--, s+=strlen(s)+1); + if (!*s) s++; + // s = LCTRANS_CUR(s); + return 1+snprintf(buf, size, "%s", s); +} diff --git a/user/include/mlibc/options/posix/musl-generic-regex/regexec.c b/user/include/mlibc/options/posix/musl-generic-regex/regexec.c new file mode 100644 index 0000000..1a169ab --- /dev/null +++ b/user/include/mlibc/options/posix/musl-generic-regex/regexec.c @@ -0,0 +1,1028 @@ +/* + regexec.c - TRE POSIX compatible matching functions (and more). + + Copyright (c) 2001-2009 Ville Laurikari + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 COPYRIGHT + HOLDER 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. + +*/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "tre.h" + +#include + +static void +tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, + const tre_tnfa_t *tnfa, regoff_t *tags, regoff_t match_eo); + +/*********************************************************************** + from tre-match-utils.h +***********************************************************************/ + +#define GET_NEXT_WCHAR() do { \ + prev_c = next_c; pos += pos_add_next; \ + if ((pos_add_next = mbtowc(&next_c, str_byte, MB_LEN_MAX)) <= 0) { \ + if (pos_add_next < 0) { ret = REG_NOMATCH; goto error_exit; } \ + else pos_add_next++; \ + } \ + str_byte += pos_add_next; \ + } while (0) + +#define IS_WORD_CHAR(c) ((c) == L'_' || tre_isalnum(c)) + +#define CHECK_ASSERTIONS(assertions) \ + (((assertions & ASSERT_AT_BOL) \ + && (pos > 0 || reg_notbol) \ + && (prev_c != L'\n' || !reg_newline)) \ + || ((assertions & ASSERT_AT_EOL) \ + && (next_c != L'\0' || reg_noteol) \ + && (next_c != L'\n' || !reg_newline)) \ + || ((assertions & ASSERT_AT_BOW) \ + && (IS_WORD_CHAR(prev_c) || !IS_WORD_CHAR(next_c))) \ + || ((assertions & ASSERT_AT_EOW) \ + && (!IS_WORD_CHAR(prev_c) || IS_WORD_CHAR(next_c))) \ + || ((assertions & ASSERT_AT_WB) \ + && (pos != 0 && next_c != L'\0' \ + && IS_WORD_CHAR(prev_c) == IS_WORD_CHAR(next_c))) \ + || ((assertions & ASSERT_AT_WB_NEG) \ + && (pos == 0 || next_c == L'\0' \ + || IS_WORD_CHAR(prev_c) != IS_WORD_CHAR(next_c)))) + +#define CHECK_CHAR_CLASSES(trans_i, tnfa, eflags) \ + (((trans_i->assertions & ASSERT_CHAR_CLASS) \ + && !(tnfa->cflags & REG_ICASE) \ + && !tre_isctype((tre_cint_t)prev_c, trans_i->u.class)) \ + || ((trans_i->assertions & ASSERT_CHAR_CLASS) \ + && (tnfa->cflags & REG_ICASE) \ + && !tre_isctype(tre_tolower((tre_cint_t)prev_c),trans_i->u.class) \ + && !tre_isctype(tre_toupper((tre_cint_t)prev_c),trans_i->u.class)) \ + || ((trans_i->assertions & ASSERT_CHAR_CLASS_NEG) \ + && tre_neg_char_classes_match(trans_i->neg_classes,(tre_cint_t)prev_c,\ + tnfa->cflags & REG_ICASE))) + + + + +/* Returns 1 if `t1' wins `t2', 0 otherwise. */ +static int +tre_tag_order(int num_tags, tre_tag_direction_t *tag_directions, + regoff_t *t1, regoff_t *t2) +{ + int i; + for (i = 0; i < num_tags; i++) + { + if (tag_directions[i] == TRE_TAG_MINIMIZE) + { + if (t1[i] < t2[i]) + return 1; + if (t1[i] > t2[i]) + return 0; + } + else + { + if (t1[i] > t2[i]) + return 1; + if (t1[i] < t2[i]) + return 0; + } + } + /* assert(0);*/ + return 0; +} + +static int +tre_neg_char_classes_match(tre_ctype_t *classes, tre_cint_t wc, int icase) +{ + while (*classes != (tre_ctype_t)0) + if ((!icase && tre_isctype(wc, *classes)) + || (icase && (tre_isctype(tre_toupper(wc), *classes) + || tre_isctype(tre_tolower(wc), *classes)))) + return 1; /* Match. */ + else + classes++; + return 0; /* No match. */ +} + + +/*********************************************************************** + from tre-match-parallel.c +***********************************************************************/ + +/* + This algorithm searches for matches basically by reading characters + in the searched string one by one, starting at the beginning. All + matching paths in the TNFA are traversed in parallel. When two or + more paths reach the same state, exactly one is chosen according to + tag ordering rules; if returning submatches is not required it does + not matter which path is chosen. + + The worst case time required for finding the leftmost and longest + match, or determining that there is no match, is always linearly + dependent on the length of the text being searched. + + This algorithm cannot handle TNFAs with back referencing nodes. + See `tre-match-backtrack.c'. +*/ + +typedef struct { + tre_tnfa_transition_t *state; + regoff_t *tags; +} tre_tnfa_reach_t; + +typedef struct { + regoff_t pos; + regoff_t **tags; +} tre_reach_pos_t; + + +static reg_errcode_t +tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, + regoff_t *match_tags, int eflags, + regoff_t *match_end_ofs) +{ + /* State variables required by GET_NEXT_WCHAR. */ + tre_char_t prev_c = 0, next_c = 0; + const char *str_byte = string; + regoff_t pos = -1; + regoff_t pos_add_next = 1; +#ifdef TRE_MBSTATE + mbstate_t mbstate; +#endif /* TRE_MBSTATE */ + int reg_notbol = eflags & REG_NOTBOL; + int reg_noteol = eflags & REG_NOTEOL; + int reg_newline = tnfa->cflags & REG_NEWLINE; + reg_errcode_t ret; + + char *buf; + tre_tnfa_transition_t *trans_i; + tre_tnfa_reach_t *reach, *reach_next, *reach_i, *reach_next_i; + tre_reach_pos_t *reach_pos; + int *tag_i; + int num_tags, i; + + regoff_t match_eo = -1; /* end offset of match (-1 if no match found yet) */ + int new_match = 0; + regoff_t *tmp_tags = NULL; + regoff_t *tmp_iptr; + +#ifdef TRE_MBSTATE + memset(&mbstate, '\0', sizeof(mbstate)); +#endif /* TRE_MBSTATE */ + + if (!match_tags) + num_tags = 0; + else + num_tags = tnfa->num_tags; + + /* Allocate memory for temporary data required for matching. This needs to + be done for every matching operation to be thread safe. This allocates + everything in a single large block with calloc(). */ + { + size_t tbytes, rbytes, pbytes, xbytes, total_bytes; + char *tmp_buf; + + /* Ensure that tbytes and xbytes*num_states cannot overflow, and that + * they don't contribute more than 1/8 of SIZE_MAX to total_bytes. */ + if (num_tags > SIZE_MAX/(8 * sizeof(regoff_t) * tnfa->num_states)) + return REG_ESPACE; + + /* Likewise check rbytes. */ + if (tnfa->num_states+1 > SIZE_MAX/(8 * sizeof(*reach_next))) + return REG_ESPACE; + + /* Likewise check pbytes. */ + if (tnfa->num_states > SIZE_MAX/(8 * sizeof(*reach_pos))) + return REG_ESPACE; + + /* Compute the length of the block we need. */ + tbytes = sizeof(*tmp_tags) * num_tags; + rbytes = sizeof(*reach_next) * (tnfa->num_states + 1); + pbytes = sizeof(*reach_pos) * tnfa->num_states; + xbytes = sizeof(regoff_t) * num_tags; + total_bytes = + (sizeof(long) - 1) * 4 /* for alignment paddings */ + + (rbytes + xbytes * tnfa->num_states) * 2 + tbytes + pbytes; + + /* Allocate the memory. */ + buf = calloc(total_bytes, 1); + if (buf == NULL) + return REG_ESPACE; + + /* Get the various pointers within tmp_buf (properly aligned). */ + tmp_tags = (void *)buf; + tmp_buf = buf + tbytes; + tmp_buf += ALIGN(tmp_buf, long); + reach_next = (void *)tmp_buf; + tmp_buf += rbytes; + tmp_buf += ALIGN(tmp_buf, long); + reach = (void *)tmp_buf; + tmp_buf += rbytes; + tmp_buf += ALIGN(tmp_buf, long); + reach_pos = (void *)tmp_buf; + tmp_buf += pbytes; + tmp_buf += ALIGN(tmp_buf, long); + for (i = 0; i < tnfa->num_states; i++) + { + reach[i].tags = (void *)tmp_buf; + tmp_buf += xbytes; + reach_next[i].tags = (void *)tmp_buf; + tmp_buf += xbytes; + } + } + + for (i = 0; i < tnfa->num_states; i++) + reach_pos[i].pos = -1; + + GET_NEXT_WCHAR(); + pos = 0; + + reach_next_i = reach_next; + while (1) + { + /* If no match found yet, add the initial states to `reach_next'. */ + if (match_eo < 0) + { + trans_i = tnfa->initial; + while (trans_i->state != NULL) + { + if (reach_pos[trans_i->state_id].pos < pos) + { + if (trans_i->assertions + && CHECK_ASSERTIONS(trans_i->assertions)) + { + trans_i++; + continue; + } + + reach_next_i->state = trans_i->state; + for (i = 0; i < num_tags; i++) + reach_next_i->tags[i] = -1; + tag_i = trans_i->tags; + if (tag_i) + while (*tag_i >= 0) + { + if (*tag_i < num_tags) + reach_next_i->tags[*tag_i] = pos; + tag_i++; + } + if (reach_next_i->state == tnfa->final) + { + match_eo = pos; + new_match = 1; + for (i = 0; i < num_tags; i++) + match_tags[i] = reach_next_i->tags[i]; + } + reach_pos[trans_i->state_id].pos = pos; + reach_pos[trans_i->state_id].tags = &reach_next_i->tags; + reach_next_i++; + } + trans_i++; + } + reach_next_i->state = NULL; + } + else + { + if (num_tags == 0 || reach_next_i == reach_next) + /* We have found a match. */ + break; + } + + /* Check for end of string. */ + if (!next_c) break; + + GET_NEXT_WCHAR(); + + /* Swap `reach' and `reach_next'. */ + reach_i = reach; + reach = reach_next; + reach_next = reach_i; + + /* For each state in `reach', weed out states that don't fulfill the + minimal matching conditions. */ + if (tnfa->num_minimals && new_match) + { + new_match = 0; + reach_next_i = reach_next; + for (reach_i = reach; reach_i->state; reach_i++) + { + int skip = 0; + for (i = 0; tnfa->minimal_tags[i] >= 0; i += 2) + { + int end = tnfa->minimal_tags[i]; + int start = tnfa->minimal_tags[i + 1]; + if (end >= num_tags) + { + skip = 1; + break; + } + else if (reach_i->tags[start] == match_tags[start] + && reach_i->tags[end] < match_tags[end]) + { + skip = 1; + break; + } + } + if (!skip) + { + reach_next_i->state = reach_i->state; + tmp_iptr = reach_next_i->tags; + reach_next_i->tags = reach_i->tags; + reach_i->tags = tmp_iptr; + reach_next_i++; + } + } + reach_next_i->state = NULL; + + /* Swap `reach' and `reach_next'. */ + reach_i = reach; + reach = reach_next; + reach_next = reach_i; + } + + /* For each state in `reach' see if there is a transition leaving with + the current input symbol to a state not yet in `reach_next', and + add the destination states to `reach_next'. */ + reach_next_i = reach_next; + for (reach_i = reach; reach_i->state; reach_i++) + { + for (trans_i = reach_i->state; trans_i->state; trans_i++) + { + /* Does this transition match the input symbol? */ + if (trans_i->code_min <= (tre_cint_t)prev_c && + trans_i->code_max >= (tre_cint_t)prev_c) + { + if (trans_i->assertions + && (CHECK_ASSERTIONS(trans_i->assertions) + || CHECK_CHAR_CLASSES(trans_i, tnfa, eflags))) + { + continue; + } + + /* Compute the tags after this transition. */ + for (i = 0; i < num_tags; i++) + tmp_tags[i] = reach_i->tags[i]; + tag_i = trans_i->tags; + if (tag_i != NULL) + while (*tag_i >= 0) + { + if (*tag_i < num_tags) + tmp_tags[*tag_i] = pos; + tag_i++; + } + + if (reach_pos[trans_i->state_id].pos < pos) + { + /* Found an unvisited node. */ + reach_next_i->state = trans_i->state; + tmp_iptr = reach_next_i->tags; + reach_next_i->tags = tmp_tags; + tmp_tags = tmp_iptr; + reach_pos[trans_i->state_id].pos = pos; + reach_pos[trans_i->state_id].tags = &reach_next_i->tags; + + if (reach_next_i->state == tnfa->final + && (match_eo == -1 + || (num_tags > 0 + && reach_next_i->tags[0] <= match_tags[0]))) + { + match_eo = pos; + new_match = 1; + for (i = 0; i < num_tags; i++) + match_tags[i] = reach_next_i->tags[i]; + } + reach_next_i++; + + } + else + { + assert(reach_pos[trans_i->state_id].pos == pos); + /* Another path has also reached this state. We choose + the winner by examining the tag values for both + paths. */ + if (tre_tag_order(num_tags, tnfa->tag_directions, + tmp_tags, + *reach_pos[trans_i->state_id].tags)) + { + /* The new path wins. */ + tmp_iptr = *reach_pos[trans_i->state_id].tags; + *reach_pos[trans_i->state_id].tags = tmp_tags; + if (trans_i->state == tnfa->final) + { + match_eo = pos; + new_match = 1; + for (i = 0; i < num_tags; i++) + match_tags[i] = tmp_tags[i]; + } + tmp_tags = tmp_iptr; + } + } + } + } + } + reach_next_i->state = NULL; + } + + *match_end_ofs = match_eo; + ret = match_eo >= 0 ? REG_OK : REG_NOMATCH; +error_exit: + xfree(buf); + return ret; +} + + + +/*********************************************************************** + from tre-match-backtrack.c +***********************************************************************/ + +/* + This matcher is for regexps that use back referencing. Regexp matching + with back referencing is an NP-complete problem on the number of back + references. The easiest way to match them is to use a backtracking + routine which basically goes through all possible paths in the TNFA + and chooses the one which results in the best (leftmost and longest) + match. This can be spectacularly expensive and may run out of stack + space, but there really is no better known generic algorithm. Quoting + Henry Spencer from comp.compilers: + + + POSIX.2 REs require longest match, which is really exciting to + implement since the obsolete ("basic") variant also includes + \. I haven't found a better way of tackling this than doing + a preliminary match using a DFA (or simulation) on a modified RE + that just replicates subREs for \, and then doing a + backtracking match to determine whether the subRE matches were + right. This can be rather slow, but I console myself with the + thought that people who use \ deserve very slow execution. + (Pun unintentional but very appropriate.) + +*/ + +typedef struct { + regoff_t pos; + const char *str_byte; + tre_tnfa_transition_t *state; + int state_id; + int next_c; + regoff_t *tags; +#ifdef TRE_MBSTATE + mbstate_t mbstate; +#endif /* TRE_MBSTATE */ +} tre_backtrack_item_t; + +typedef struct tre_backtrack_struct { + tre_backtrack_item_t item; + struct tre_backtrack_struct *prev; + struct tre_backtrack_struct *next; +} *tre_backtrack_t; + +#ifdef TRE_MBSTATE +#define BT_STACK_MBSTATE_IN stack->item.mbstate = (mbstate) +#define BT_STACK_MBSTATE_OUT (mbstate) = stack->item.mbstate +#else /* !TRE_MBSTATE */ +#define BT_STACK_MBSTATE_IN +#define BT_STACK_MBSTATE_OUT +#endif /* !TRE_MBSTATE */ + +#define tre_bt_mem_new tre_mem_new +#define tre_bt_mem_alloc tre_mem_alloc +#define tre_bt_mem_destroy tre_mem_destroy + + +#define BT_STACK_PUSH(_pos, _str_byte, _str_wide, _state, _state_id, _next_c, _tags, _mbstate) \ + do \ + { \ + int i; \ + if (!stack->next) \ + { \ + tre_backtrack_t s; \ + s = tre_bt_mem_alloc(mem, sizeof(*s)); \ + if (!s) \ + { \ + tre_bt_mem_destroy(mem); \ + if (tags) \ + xfree(tags); \ + if (pmatch) \ + xfree(pmatch); \ + if (states_seen) \ + xfree(states_seen); \ + return REG_ESPACE; \ + } \ + s->prev = stack; \ + s->next = NULL; \ + s->item.tags = tre_bt_mem_alloc(mem, \ + sizeof(*tags) * tnfa->num_tags); \ + if (!s->item.tags) \ + { \ + tre_bt_mem_destroy(mem); \ + if (tags) \ + xfree(tags); \ + if (pmatch) \ + xfree(pmatch); \ + if (states_seen) \ + xfree(states_seen); \ + return REG_ESPACE; \ + } \ + stack->next = s; \ + stack = s; \ + } \ + else \ + stack = stack->next; \ + stack->item.pos = (_pos); \ + stack->item.str_byte = (_str_byte); \ + stack->item.state = (_state); \ + stack->item.state_id = (_state_id); \ + stack->item.next_c = (_next_c); \ + for (i = 0; i < tnfa->num_tags; i++) \ + stack->item.tags[i] = (_tags)[i]; \ + BT_STACK_MBSTATE_IN; \ + } \ + while (0) + +#define BT_STACK_POP() \ + do \ + { \ + int i; \ + assert(stack->prev); \ + pos = stack->item.pos; \ + str_byte = stack->item.str_byte; \ + state = stack->item.state; \ + next_c = stack->item.next_c; \ + for (i = 0; i < tnfa->num_tags; i++) \ + tags[i] = stack->item.tags[i]; \ + BT_STACK_MBSTATE_OUT; \ + stack = stack->prev; \ + } \ + while (0) + +#undef MIN +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) + +static reg_errcode_t +tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string, + regoff_t *match_tags, int eflags, regoff_t *match_end_ofs) +{ + /* State variables required by GET_NEXT_WCHAR. */ + tre_char_t prev_c = 0, next_c = 0; + const char *str_byte = string; + regoff_t pos = 0; + regoff_t pos_add_next = 1; +#ifdef TRE_MBSTATE + mbstate_t mbstate; +#endif /* TRE_MBSTATE */ + int reg_notbol = eflags & REG_NOTBOL; + int reg_noteol = eflags & REG_NOTEOL; + int reg_newline = tnfa->cflags & REG_NEWLINE; + + /* These are used to remember the necessary values of the above + variables to return to the position where the current search + started from. */ + int next_c_start; + const char *str_byte_start; + regoff_t pos_start = -1; +#ifdef TRE_MBSTATE + mbstate_t mbstate_start; +#endif /* TRE_MBSTATE */ + + /* End offset of best match so far, or -1 if no match found yet. */ + regoff_t match_eo = -1; + /* Tag arrays. */ + int *next_tags; + regoff_t *tags = NULL; + /* Current TNFA state. */ + tre_tnfa_transition_t *state; + int *states_seen = NULL; + + /* Memory allocator to for allocating the backtracking stack. */ + tre_mem_t mem = tre_bt_mem_new(); + + /* The backtracking stack. */ + tre_backtrack_t stack; + + tre_tnfa_transition_t *trans_i; + regmatch_t *pmatch = NULL; + int ret; + +#ifdef TRE_MBSTATE + memset(&mbstate, '\0', sizeof(mbstate)); +#endif /* TRE_MBSTATE */ + + if (!mem) + return REG_ESPACE; + stack = tre_bt_mem_alloc(mem, sizeof(*stack)); + if (!stack) + { + ret = REG_ESPACE; + goto error_exit; + } + stack->prev = NULL; + stack->next = NULL; + + if (tnfa->num_tags) + { + tags = xmalloc(sizeof(*tags) * tnfa->num_tags); + if (!tags) + { + ret = REG_ESPACE; + goto error_exit; + } + } + if (tnfa->num_submatches) + { + pmatch = xmalloc(sizeof(*pmatch) * tnfa->num_submatches); + if (!pmatch) + { + ret = REG_ESPACE; + goto error_exit; + } + } + if (tnfa->num_states) + { + states_seen = xmalloc(sizeof(*states_seen) * tnfa->num_states); + if (!states_seen) + { + ret = REG_ESPACE; + goto error_exit; + } + } + + retry: + { + int i; + for (i = 0; i < tnfa->num_tags; i++) + { + tags[i] = -1; + if (match_tags) + match_tags[i] = -1; + } + for (i = 0; i < tnfa->num_states; i++) + states_seen[i] = 0; + } + + state = NULL; + pos = pos_start; + GET_NEXT_WCHAR(); + pos_start = pos; + next_c_start = next_c; + str_byte_start = str_byte; +#ifdef TRE_MBSTATE + mbstate_start = mbstate; +#endif /* TRE_MBSTATE */ + + /* Handle initial states. */ + next_tags = NULL; + for (trans_i = tnfa->initial; trans_i->state; trans_i++) + { + if (trans_i->assertions && CHECK_ASSERTIONS(trans_i->assertions)) + { + continue; + } + if (state == NULL) + { + /* Start from this state. */ + state = trans_i->state; + next_tags = trans_i->tags; + } + else + { + /* Backtrack to this state. */ + BT_STACK_PUSH(pos, str_byte, 0, trans_i->state, + trans_i->state_id, next_c, tags, mbstate); + { + int *tmp = trans_i->tags; + if (tmp) + while (*tmp >= 0) + stack->item.tags[*tmp++] = pos; + } + } + } + + if (next_tags) + for (; *next_tags >= 0; next_tags++) + tags[*next_tags] = pos; + + + if (state == NULL) + goto backtrack; + + while (1) + { + tre_tnfa_transition_t *next_state; + int empty_br_match; + + if (state == tnfa->final) + { + if (match_eo < pos + || (match_eo == pos + && match_tags + && tre_tag_order(tnfa->num_tags, tnfa->tag_directions, + tags, match_tags))) + { + int i; + /* This match wins the previous match. */ + match_eo = pos; + if (match_tags) + for (i = 0; i < tnfa->num_tags; i++) + match_tags[i] = tags[i]; + } + /* Our TNFAs never have transitions leaving from the final state, + so we jump right to backtracking. */ + goto backtrack; + } + + /* Go to the next character in the input string. */ + empty_br_match = 0; + trans_i = state; + if (trans_i->state && trans_i->assertions & ASSERT_BACKREF) + { + /* This is a back reference state. All transitions leaving from + this state have the same back reference "assertion". Instead + of reading the next character, we match the back reference. */ + regoff_t so, eo; + int bt = trans_i->u.backref; + regoff_t bt_len; + int result; + + /* Get the substring we need to match against. Remember to + turn off REG_NOSUB temporarily. */ + tre_fill_pmatch(bt + 1, pmatch, tnfa->cflags & ~REG_NOSUB, + tnfa, tags, pos); + so = pmatch[bt].rm_so; + eo = pmatch[bt].rm_eo; + bt_len = eo - so; + + result = strncmp((const char*)string + so, str_byte - 1, + (size_t)bt_len); + + if (result == 0) + { + /* Back reference matched. Check for infinite loop. */ + if (bt_len == 0) + empty_br_match = 1; + if (empty_br_match && states_seen[trans_i->state_id]) + { + goto backtrack; + } + + states_seen[trans_i->state_id] = empty_br_match; + + /* Advance in input string and resync `prev_c', `next_c' + and pos. */ + str_byte += bt_len - 1; + pos += bt_len - 1; + GET_NEXT_WCHAR(); + } + else + { + goto backtrack; + } + } + else + { + /* Check for end of string. */ + if (next_c == L'\0') + goto backtrack; + + /* Read the next character. */ + GET_NEXT_WCHAR(); + } + + next_state = NULL; + for (trans_i = state; trans_i->state; trans_i++) + { + if (trans_i->code_min <= (tre_cint_t)prev_c + && trans_i->code_max >= (tre_cint_t)prev_c) + { + if (trans_i->assertions + && (CHECK_ASSERTIONS(trans_i->assertions) + || CHECK_CHAR_CLASSES(trans_i, tnfa, eflags))) + { + continue; + } + + if (next_state == NULL) + { + /* First matching transition. */ + next_state = trans_i->state; + next_tags = trans_i->tags; + } + else + { + /* Second matching transition. We may need to backtrack here + to take this transition instead of the first one, so we + push this transition in the backtracking stack so we can + jump back here if needed. */ + BT_STACK_PUSH(pos, str_byte, 0, trans_i->state, + trans_i->state_id, next_c, tags, mbstate); + { + int *tmp; + for (tmp = trans_i->tags; tmp && *tmp >= 0; tmp++) + stack->item.tags[*tmp] = pos; + } +#if 0 /* XXX - it's important not to look at all transitions here to keep + the stack small! */ + break; +#endif + } + } + } + + if (next_state != NULL) + { + /* Matching transitions were found. Take the first one. */ + state = next_state; + + /* Update the tag values. */ + if (next_tags) + while (*next_tags >= 0) + tags[*next_tags++] = pos; + } + else + { + backtrack: + /* A matching transition was not found. Try to backtrack. */ + if (stack->prev) + { + if (stack->item.state->assertions & ASSERT_BACKREF) + { + states_seen[stack->item.state_id] = 0; + } + + BT_STACK_POP(); + } + else if (match_eo < 0) + { + /* Try starting from a later position in the input string. */ + /* Check for end of string. */ + if (next_c == L'\0') + { + break; + } + next_c = next_c_start; +#ifdef TRE_MBSTATE + mbstate = mbstate_start; +#endif /* TRE_MBSTATE */ + str_byte = str_byte_start; + goto retry; + } + else + { + break; + } + } + } + + ret = match_eo >= 0 ? REG_OK : REG_NOMATCH; + *match_end_ofs = match_eo; + + error_exit: + tre_bt_mem_destroy(mem); +#ifndef TRE_USE_ALLOCA + if (tags) + xfree(tags); + if (pmatch) + xfree(pmatch); + if (states_seen) + xfree(states_seen); +#endif /* !TRE_USE_ALLOCA */ + + return ret; +} + +/*********************************************************************** + from regexec.c +***********************************************************************/ + +/* Fills the POSIX.2 regmatch_t array according to the TNFA tag and match + endpoint values. */ +static void +tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, + const tre_tnfa_t *tnfa, regoff_t *tags, regoff_t match_eo) +{ + tre_submatch_data_t *submatch_data; + unsigned int i, j; + int *parents; + + i = 0; + if (match_eo >= 0 && !(cflags & REG_NOSUB)) + { + /* Construct submatch offsets from the tags. */ + submatch_data = tnfa->submatch_data; + while (i < tnfa->num_submatches && i < nmatch) + { + if (submatch_data[i].so_tag == tnfa->end_tag) + pmatch[i].rm_so = match_eo; + else + pmatch[i].rm_so = tags[submatch_data[i].so_tag]; + + if (submatch_data[i].eo_tag == tnfa->end_tag) + pmatch[i].rm_eo = match_eo; + else + pmatch[i].rm_eo = tags[submatch_data[i].eo_tag]; + + /* If either of the endpoints were not used, this submatch + was not part of the match. */ + if (pmatch[i].rm_so == -1 || pmatch[i].rm_eo == -1) + pmatch[i].rm_so = pmatch[i].rm_eo = -1; + + i++; + } + /* Reset all submatches that are not within all of their parent + submatches. */ + i = 0; + while (i < tnfa->num_submatches && i < nmatch) + { + if (pmatch[i].rm_eo == -1) + assert(pmatch[i].rm_so == -1); + assert(pmatch[i].rm_so <= pmatch[i].rm_eo); + + parents = submatch_data[i].parents; + if (parents != NULL) + for (j = 0; parents[j] >= 0; j++) + { + if (pmatch[i].rm_so < pmatch[parents[j]].rm_so + || pmatch[i].rm_eo > pmatch[parents[j]].rm_eo) + pmatch[i].rm_so = pmatch[i].rm_eo = -1; + } + i++; + } + } + + while (i < nmatch) + { + pmatch[i].rm_so = -1; + pmatch[i].rm_eo = -1; + i++; + } +} + + +/* + Wrapper functions for POSIX compatible regexp matching. +*/ + +int +regexec(const regex_t *restrict preg, const char *restrict string, + size_t nmatch, regmatch_t pmatch[restrict], int eflags) +{ + tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD; + reg_errcode_t status; + regoff_t *tags = NULL, eo; + if (tnfa->cflags & REG_NOSUB) nmatch = 0; + if (tnfa->num_tags > 0 && nmatch > 0) + { + tags = xmalloc(sizeof(*tags) * tnfa->num_tags); + if (tags == NULL) + return REG_ESPACE; + } + + /* Dispatch to the appropriate matcher. */ + if (tnfa->have_backrefs) + { + /* The regex has back references, use the backtracking matcher. */ + status = tre_tnfa_run_backtrack(tnfa, string, tags, eflags, &eo); + } + else + { + /* Exact matching, no back references, use the parallel matcher. */ + status = tre_tnfa_run_parallel(tnfa, string, tags, eflags, &eo); + } + + if (status == REG_OK) + /* A match was found, so fill the submatch registers. */ + tre_fill_pmatch(nmatch, pmatch, tnfa->cflags, tnfa, tags, eo); + if (tags) + xfree(tags); + return status; +} \ No newline at end of file diff --git a/user/include/mlibc/options/posix/musl-generic-regex/tre-mem.c b/user/include/mlibc/options/posix/musl-generic-regex/tre-mem.c new file mode 100644 index 0000000..a3df685 --- /dev/null +++ b/user/include/mlibc/options/posix/musl-generic-regex/tre-mem.c @@ -0,0 +1,158 @@ +/* + tre-mem.c - TRE memory allocator + + Copyright (c) 2001-2009 Ville Laurikari + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 COPYRIGHT + HOLDER 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. + +*/ + +/* + This memory allocator is for allocating small memory blocks efficiently + in terms of memory overhead and execution speed. The allocated blocks + cannot be freed individually, only all at once. There can be multiple + allocators, though. +*/ + +#include +#include + +#include "tre.h" + +/* + This memory allocator is for allocating small memory blocks efficiently + in terms of memory overhead and execution speed. The allocated blocks + cannot be freed individually, only all at once. There can be multiple + allocators, though. +*/ + +/* Returns a new memory allocator or NULL if out of memory. */ +tre_mem_t +tre_mem_new_impl(int provided, void *provided_block) +{ + tre_mem_t mem; + if (provided) + { + mem = provided_block; + memset(mem, 0, sizeof(*mem)); + } + else + mem = xcalloc(1, sizeof(*mem)); + if (mem == NULL) + return NULL; + return mem; +} + + +/* Frees the memory allocator and all memory allocated with it. */ +void +tre_mem_destroy(tre_mem_t mem) +{ + tre_list_t *tmp, *l = mem->blocks; + + while (l != NULL) + { + xfree(l->data); + tmp = l->next; + xfree(l); + l = tmp; + } + xfree(mem); +} + + +/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the + allocated block or NULL if an underlying malloc() failed. */ +void * +tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block, + int zero, size_t size) +{ + void *ptr; + + if (mem->failed) + { + return NULL; + } + + if (mem->n < size) + { + /* We need more memory than is available in the current block. + Allocate a new block. */ + tre_list_t *l; + if (provided) + { + if (provided_block == NULL) + { + mem->failed = 1; + return NULL; + } + mem->ptr = provided_block; + mem->n = TRE_MEM_BLOCK_SIZE; + } + else + { + int block_size; + if (size * 8 > TRE_MEM_BLOCK_SIZE) + block_size = size * 8; + else + block_size = TRE_MEM_BLOCK_SIZE; + l = xmalloc(sizeof(*l)); + if (l == NULL) + { + mem->failed = 1; + return NULL; + } + l->data = xmalloc(block_size); + if (l->data == NULL) + { + xfree(l); + mem->failed = 1; + return NULL; + } + l->next = NULL; + if (mem->current != NULL) + mem->current->next = l; + if (mem->blocks == NULL) + mem->blocks = l; + mem->current = l; + mem->ptr = l->data; + mem->n = block_size; + } + } + + /* Make sure the next pointer will be aligned. */ + size += ALIGN(mem->ptr + size, long); + + /* Allocate from current block. */ + ptr = mem->ptr; + mem->ptr += size; + mem->n -= size; + + /* Set to zero if needed. */ + if (zero) + memset(ptr, 0, size); + + return ptr; +} \ No newline at end of file diff --git a/user/include/mlibc/options/posix/musl-generic-regex/tre.h b/user/include/mlibc/options/posix/musl-generic-regex/tre.h new file mode 100644 index 0000000..030ad54 --- /dev/null +++ b/user/include/mlibc/options/posix/musl-generic-regex/tre.h @@ -0,0 +1,241 @@ +/* Taken from musl tre.h */ +/* + tre-internal.h - TRE internal definitions + + Copyright (c) 2001-2009 Ville Laurikari + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 COPYRIGHT + HOLDER 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. + +*/ + +#include +#include +#include + +#define hidden __attribute__((__visibility__("hidden"))) + +/* TODO: These should probably go in limits.h */ +#define CHARCLASS_NAME_MAX 14 +#define RE_DUP_MAX 255 + +#undef TRE_MBSTATE + +#define NDEBUG + +#define TRE_REGEX_T_FIELD __opaque +typedef int reg_errcode_t; + +typedef wchar_t tre_char_t; + +#define DPRINT(msg) do { } while(0) + +#define elementsof(x) ( sizeof(x) / sizeof(x[0]) ) + +#define tre_mbrtowc(pwc, s, n, ps) (mbtowc((pwc), (s), (n))) + +/* Wide characters. */ +typedef wint_t tre_cint_t; +#define TRE_CHAR_MAX 0x10ffff + +#define tre_isalnum iswalnum +#define tre_isalpha iswalpha +#define tre_isblank iswblank +#define tre_iscntrl iswcntrl +#define tre_isdigit iswdigit +#define tre_isgraph iswgraph +#define tre_islower iswlower +#define tre_isprint iswprint +#define tre_ispunct iswpunct +#define tre_isspace iswspace +#define tre_isupper iswupper +#define tre_isxdigit iswxdigit + +#define tre_tolower towlower +#define tre_toupper towupper +#define tre_strlen wcslen + +/* Use system provided iswctype() and wctype(). */ +typedef wctype_t tre_ctype_t; +#define tre_isctype iswctype +#define tre_ctype wctype + +/* Returns number of bytes to add to (char *)ptr to make it + properly aligned for the type. */ +#define ALIGN(ptr, type) \ + ((((long)ptr) % sizeof(type)) \ + ? (sizeof(type) - (((long)ptr) % sizeof(type))) \ + : 0) + +#undef MAX +#undef MIN +#define MAX(a, b) (((a) >= (b)) ? (a) : (b)) +#define MIN(a, b) (((a) <= (b)) ? (a) : (b)) + +/* TNFA transition type. A TNFA state is an array of transitions, + the terminator is a transition with NULL `state'. */ +typedef struct tnfa_transition tre_tnfa_transition_t; + +struct tnfa_transition { + /* Range of accepted characters. */ + tre_cint_t code_min; + tre_cint_t code_max; + /* Pointer to the destination state. */ + tre_tnfa_transition_t *state; + /* ID number of the destination state. */ + int state_id; + /* -1 terminated array of tags (or NULL). */ + int *tags; + /* Assertion bitmap. */ + int assertions; + /* Assertion parameters. */ + union { + /* Character class assertion. */ + tre_ctype_t class; + /* Back reference assertion. */ + int backref; + } u; + /* Negative character class assertions. */ + tre_ctype_t *neg_classes; +}; + + +/* Assertions. */ +#define ASSERT_AT_BOL 1 /* Beginning of line. */ +#define ASSERT_AT_EOL 2 /* End of line. */ +#define ASSERT_CHAR_CLASS 4 /* Character class in `class'. */ +#define ASSERT_CHAR_CLASS_NEG 8 /* Character classes in `neg_classes'. */ +#define ASSERT_AT_BOW 16 /* Beginning of word. */ +#define ASSERT_AT_EOW 32 /* End of word. */ +#define ASSERT_AT_WB 64 /* Word boundary. */ +#define ASSERT_AT_WB_NEG 128 /* Not a word boundary. */ +#define ASSERT_BACKREF 256 /* A back reference in `backref'. */ +#define ASSERT_LAST 256 + +/* Tag directions. */ +typedef enum { + TRE_TAG_MINIMIZE = 0, + TRE_TAG_MAXIMIZE = 1 +} tre_tag_direction_t; + +/* Instructions to compute submatch register values from tag values + after a successful match. */ +struct tre_submatch_data { + /* Tag that gives the value for rm_so (submatch start offset). */ + int so_tag; + /* Tag that gives the value for rm_eo (submatch end offset). */ + int eo_tag; + /* List of submatches this submatch is contained in. */ + int *parents; +}; + +typedef struct tre_submatch_data tre_submatch_data_t; + + +/* TNFA definition. */ +typedef struct tnfa tre_tnfa_t; + +struct tnfa { + tre_tnfa_transition_t *transitions; + unsigned int num_transitions; + tre_tnfa_transition_t *initial; + tre_tnfa_transition_t *final; + tre_submatch_data_t *submatch_data; + char *firstpos_chars; + int first_char; + unsigned int num_submatches; + tre_tag_direction_t *tag_directions; + int *minimal_tags; + int num_tags; + int num_minimals; + int end_tag; + int num_states; + int cflags; + int have_backrefs; + int have_approx; +}; + +/* from tre-mem.h: */ + +#define TRE_MEM_BLOCK_SIZE 1024 + +typedef struct tre_list { + void *data; + struct tre_list *next; +} tre_list_t; + +typedef struct tre_mem_struct { + tre_list_t *blocks; + tre_list_t *current; + char *ptr; + size_t n; + int failed; + void **provided; +} *tre_mem_t; + +#ifndef __MLIBC_ABI_ONLY + +#define tre_mem_new_impl __tre_mem_new_impl +#define tre_mem_alloc_impl __tre_mem_alloc_impl +#define tre_mem_destroy __tre_mem_destroy + +hidden tre_mem_t tre_mem_new_impl(int provided, void *provided_block); +hidden void *tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block, + int zero, size_t size); + +/* Returns a new memory allocator or NULL if out of memory. */ +#define tre_mem_new() tre_mem_new_impl(0, NULL) + +/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the + allocated block or NULL if an underlying malloc() failed. */ +#define tre_mem_alloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 0, size) + +/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the + allocated block or NULL if an underlying malloc() failed. The memory + is set to zero. */ +#define tre_mem_calloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 1, size) + +#ifdef TRE_USE_ALLOCA +/* alloca() versions. Like above, but memory is allocated with alloca() + instead of malloc(). */ + +#define tre_mem_newa() \ + tre_mem_new_impl(1, alloca(sizeof(struct tre_mem_struct))) + +#define tre_mem_alloca(mem, size) \ + ((mem)->n >= (size) \ + ? tre_mem_alloc_impl((mem), 1, NULL, 0, (size)) \ + : tre_mem_alloc_impl((mem), 1, alloca(TRE_MEM_BLOCK_SIZE), 0, (size))) +#endif /* TRE_USE_ALLOCA */ + + +/* Frees the memory allocator and all memory allocated with it. */ +hidden void tre_mem_destroy(tre_mem_t mem); + +#define xmalloc malloc +#define xcalloc calloc +#define xfree free +#define xrealloc realloc + +#endif /* !__MLIBC_ABI_ONLY */ diff --git a/user/include/mlibc/options/rtld/aarch64/elf.hpp b/user/include/mlibc/options/rtld/aarch64/elf.hpp new file mode 100644 index 0000000..a285d85 --- /dev/null +++ b/user/include/mlibc/options/rtld/aarch64/elf.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS64 +#define ELF_MACHINE EM_AARCH64 + +using elf_ehdr = Elf64_Ehdr; +using elf_phdr = Elf64_Phdr; +using elf_dyn = Elf64_Dyn; +using elf_rel = Elf64_Rel; +using elf_rela = Elf64_Rela; +using elf_relr = Elf64_Relr; +using elf_sym = Elf64_Sym; +using elf_addr = Elf64_Addr; + +using elf_info = Elf64_Xword; +using elf_addend = Elf64_Sxword; + +using elf_version = Elf64_Half; +using elf_verdef = Elf64_Verdef; +using elf_verdaux = Elf64_Verdaux; +using elf_verneed = Elf64_Verneed; +using elf_vernaux = Elf64_Vernaux; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE + +#define R_NONE R_AARCH64_NONE +#define R_JUMP_SLOT R_AARCH64_JUMP_SLOT +#define R_ABSOLUTE R_AARCH64_ABS64 +#define R_GLOB_DAT R_AARCH64_GLOB_DAT +#define R_RELATIVE R_AARCH64_RELATIVE +#define R_IRELATIVE R_AARCH64_IRELATIVE +// #define R_OFFSET +#define R_COPY R_AARCH64_COPY +#define R_TLS_DTPMOD R_AARCH64_TLS_DTPMOD +#define R_TLS_DTPREL R_AARCH64_TLS_DTPREL +#define R_TLS_TPREL R_AARCH64_TLS_TPREL +#define R_TLSDESC R_AARCH64_TLSDESC + +#define TP_TCB_OFFSET (16) + +struct ifunc_arg { + unsigned long _size; + unsigned long _hwcap; + unsigned long _hwcap2; + unsigned long _hwcap3; + unsigned long _hwcap4; +}; + +using ifunc_handler = elf_addr (*)(uint64_t, ifunc_arg *); diff --git a/user/include/mlibc/options/rtld/aarch64/entry.S b/user/include/mlibc/options/rtld/aarch64/entry.S new file mode 100644 index 0000000..a2c9722 --- /dev/null +++ b/user/include/mlibc/options/rtld/aarch64/entry.S @@ -0,0 +1,13 @@ +#include "mlibc-asm/helpers.h" + +PROC_START(_start) + bl relocateSelf + + mov x0, sp + bl interpreterMain + + br x0 +PROC_END(_start) + +GNU_STACK_NOTE() + diff --git a/user/include/mlibc/options/rtld/aarch64/runtime.S b/user/include/mlibc/options/rtld/aarch64/runtime.S new file mode 100644 index 0000000..c3e2cff --- /dev/null +++ b/user/include/mlibc/options/rtld/aarch64/runtime.S @@ -0,0 +1,62 @@ + +.global __mlibcTlsdescStatic +.hidden __mlibcTlsdescStatic +.type __mlibcTlsdescStatic,@function +__mlibcTlsdescStatic: + ldr x0, [x0, #8] + ret + +// This function depends on the Tcb layout, since it pulls out the dtv pointer +// out of the thread control block +.global __mlibcTlsdescDynamic +.hidden __mlibcTlsdescDynamic +.type __mlibcTlsdescDynamic,@function +__mlibcTlsdescDynamic: + stp x1, x2, [sp, #-16]! + ldr x0, [x0, #8] + ldp x1, x2, [x0] // tlsIndex, addend + mrs x0, tpidr_el0 // tp + ldr x0, [x0, #-104] // tp->dtvPointers + ldr x0, [x0, x1, lsl 3] // [tlsIndex] + add x0, x0, x2 // + addend + mrs x1, tpidr_el0 // tp + sub x0, x0, x1 // result - tp + ldp x1, x2, [sp], #16 + ret + +.global pltRelocateStub +pltRelocateStub: + // we need to save / restore all registers than can hold function arguments + // we do not need to save callee-saved registers as they will not be trashed by lazyRelocate + // TODO: save floating point argument registers + + stp x0, x1, [sp, #-16]! + + // pointer to PLT entry + ldr x1, [sp, #24] + ldr x0, [x16] + sub x1, x1, x0 + asr x0, x0, #3 + + // pointer GOT + sub x0, x16, #8 // &PLTGOT[1] + + stp x2, x3, [sp, #-16]! + stp x4, x5, [sp, #-16]! + stp x6, x7, [sp, #-16]! + stp x8, x30, [sp, #-16]! + + bl lazyRelocate + mov x9, x0 + + ldp x8, x30, [sp], #16 + ldp x6, x7, [sp], #16 + ldp x4, x5, [sp], #16 + ldp x2, x1, [sp], #16 + + ldp x0, x1, [sp], #16 + add sp, sp, #16 + br x9 + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/rtld/generic/linker.cpp b/user/include/mlibc/options/rtld/generic/linker.cpp new file mode 100644 index 0000000..974a1be --- /dev/null +++ b/user/include/mlibc/options/rtld/generic/linker.cpp @@ -0,0 +1,2279 @@ +#include +#include +#include + +// keep a list of optional generic relocation types +enum { + R_OFFSET = (uintptr_t) -1, +}; + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf.hpp" +#include "linker.hpp" + +#if !MLIBC_MMAP_ALLOCATE_DSO +uintptr_t libraryBase = 0x41000000; +#endif + +constexpr bool verbose = false; +constexpr bool stillSlightlyVerbose = false; +constexpr bool logBaseAddresses = false; +constexpr bool logRpath = false; +constexpr bool logLdPath = false; +constexpr bool logSymbolVersions = false; +constexpr bool eagerBinding = true; + +#if defined(__x86_64__) || defined(__i386__) +constexpr inline bool tlsAboveTp = false; +constexpr inline uintptr_t tlsOffsetFromTp = 0; +#elif defined(__aarch64__) +constexpr inline bool tlsAboveTp = true; +constexpr inline uintptr_t tlsOffsetFromTp = 16; +#elif defined(__riscv) +constexpr inline bool tlsAboveTp = true; +constexpr inline uintptr_t tlsOffsetFromTp = 0; +#elif defined(__m68k__) +constexpr inline bool tlsAboveTp = true; +constexpr inline ptrdiff_t tlsOffsetFromTp = -0x7000; +#elif defined(__loongarch64) +constexpr inline bool tlsAboveTp = true; +constexpr inline uintptr_t tlsOffsetFromTp = 0; +#else +# error Unknown architecture +#endif + +extern DebugInterface globalDebugInterface; +extern uintptr_t __stack_chk_guard; + +extern frg::manual_box> libraryPaths; +extern frg::manual_box> preloads; + +#if MLIBC_STATIC_BUILD +extern "C" size_t __init_array_start[]; +extern "C" size_t __init_array_end[]; +extern "C" size_t __fini_array_start[]; +extern "C" size_t __fini_array_end[]; +extern "C" size_t __preinit_array_start[]; +extern "C" size_t __preinit_array_end[]; +#endif + +size_t tlsMaxAlignment = 16; + +// This is the global "resolution timestamp" (RTS) counter. +// It is incremented each time __dlapi_open() (i.e. dlopen()) is called. +// Each DSO stores its objectRts (i.e. RTS at the time the object was loaded). +// DSOs in the global scope also store a globalRts (i.e. RTS at the time the +// object became global). This mechanism is used to determine which +// part of the global scope is considered for symbol resolution. +uint64_t rtsCounter = 2; + +namespace { + +unsigned long getauxval(unsigned long type) { + auto aux = reinterpret_cast(rtld_auxvector()); + __ensure(aux); + + // Parse the auxiliary vector. + while(true) { + auto value = aux + 1; + if(*aux == AT_NULL) { + return 0; + }else if(*aux == type) { + return *value; + } + aux += 2; + } +} + +#if defined(__riscv) + +#include + +int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags) { + return mlibc::sys_riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags); +} + +#endif + +elf_addr handleIfunc(elf_addr addr) { + #if defined(__aarch64__) + auto hwcap = getauxval(AT_HWCAP); + + ifunc_arg ifunc_arg = { + ._size = sizeof(ifunc_arg), + ._hwcap = hwcap, + #if defined(AT_HWCAP2) + ._hwcap2 = getauxval(AT_HWCAP2), + #else + ._hwcap2 = 0, + #endif + #if defined(AT_HWCAP3) + ._hwcap3 = getauxval(AT_HWCAP3), + #else + ._hwcap3 = 0, + #endif + #if defined(AT_HWCAP4) + ._hwcap4 = getauxval(AT_HWCAP4), + #else + ._hwcap4 = 0, + #endif + }; + + return reinterpret_cast(addr)(hwcap | (1ULL << 62), &ifunc_arg); + #elif defined(__riscv) + auto hwcap = getauxval(AT_HWCAP); + return reinterpret_cast(addr) + (hwcap, &__riscv_hwprobe, nullptr); + #elif defined(__loongarch64) + ifunc_arg ifunc_arg = { + ._size = sizeof(ifunc_arg), + ._hwcap = getauxval(AT_HWCAP), + }; + return reinterpret_cast(addr)(&ifunc_arg); + #elif defined(__i386__) || defined(__x86_64__) || defined(__m68k__) + return reinterpret_cast(addr)(); + #endif +} + +} // namespace + +bool trySeek(int fd, int64_t offset) { + off_t noff; + return mlibc::sys_seek(fd, offset, SEEK_SET, &noff) == 0; +} + +bool tryReadExactly(int fd, void *data, size_t length) { + size_t offset = 0; + while(offset < length) { + ssize_t chunk; + if(mlibc::sys_read(fd, reinterpret_cast(data) + offset, + length - offset, &chunk)) + return false; + __ensure(chunk > 0); + offset += chunk; + } + __ensure(offset == length); + return true; +} + +void closeOrDie(int fd) { + if(mlibc::sys_close(fd)) + __ensure(!"sys_close() failed"); +} + +uintptr_t alignUp(uintptr_t address, size_t align) { + return (address + align - 1) & ~(align - 1); +} + +// -------------------------------------------------------- +// ObjectRepository +// -------------------------------------------------------- + +ObjectRepository::ObjectRepository() +: loadedObjects{getAllocator()}, + dependencyQueue{getAllocator()}, + _nameMap{frg::hash{}, getAllocator()}, + _destructQueue{getAllocator()} {} + +SharedObject *ObjectRepository::injectObjectFromDts(frg::string_view name, + frg::string path, uintptr_t base_address, + elf_dyn *dynamic, uint64_t rts) { + __ensure(!findLoadedObject(name)); + + auto object = frg::construct(getAllocator(), + name.data(), std::move(path), false, globalScope.get(), rts); + object->baseAddress = base_address; + object->dynamic = dynamic; + _parseDynamic(object); + _parseVerdef(object); + + object->wasVisited = true; + dependencyQueue.push_back(object); + _addLoadedObject(object); + + return object; +} + +SharedObject *ObjectRepository::injectObjectFromPhdrs(frg::string_view name, + frg::string path, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer, + uint64_t rts) { + __ensure(!findLoadedObject(name)); + + auto object = frg::construct(getAllocator(), + name.data(), std::move(path), true, globalScope.get(), rts); + _fetchFromPhdrs(object, phdr_pointer, phdr_entry_size, num_phdrs, entry_pointer); + _parseDynamic(object); + _parseVerdef(object); + + object->wasVisited = true; + dependencyQueue.push_back(object); + _addLoadedObject(object); + + return object; +} + +SharedObject *ObjectRepository::injectStaticObject(frg::string_view name, + frg::string path, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer, + uint64_t rts) { + __ensure(!findLoadedObject(name)); + auto object = frg::construct(getAllocator(), + name.data(), std::move(path), true, globalScope.get(), rts); + _fetchFromPhdrs(object, phdr_pointer, phdr_entry_size, num_phdrs, entry_pointer); + +#if MLIBC_STATIC_BUILD + object->initArray = reinterpret_cast(__init_array_start); + object->initArraySize = static_cast((uintptr_t)__init_array_end - + (uintptr_t)__init_array_start); + object->finiArray = reinterpret_cast(__fini_array_start); + object->finiArraySize = static_cast((uintptr_t)__fini_array_end - + (uintptr_t)__fini_array_start); + object->preInitArray = reinterpret_cast(__preinit_array_start); + object->preInitArraySize = static_cast((uintptr_t)__preinit_array_end - + (uintptr_t)__preinit_array_start); +#endif + + _addLoadedObject(object); + + return object; +} + +frg::expected ObjectRepository::requestObjectWithName(frg::string_view name, + SharedObject *origin, Scope *localScope, bool createScope, uint64_t rts) { + if (auto obj = findLoadedObject(name)) + return obj; + + auto tryToOpen = [&] (const char *path) { + int fd; + if(auto x = mlibc::sys_open(path, O_RDONLY, 0, &fd); x) { + return -1; + } + return fd; + }; + + // TODO(arsen): this process can probably undergo heavy optimization, by + // preprocessing the rpath only once on parse + auto processRpath = [&] (frg::string_view path) { + frg::string sPath { getAllocator() }; + if (path.starts_with("$ORIGIN")) { + frg::string_view dirname = origin->path; + auto lastsl = dirname.find_last('/'); + if (lastsl != size_t(-1)) { + dirname = dirname.sub_string(0, lastsl); + } else { + dirname = "."; + } + sPath = frg::string{ getAllocator(), dirname }; + sPath += path.sub_string(7, path.size() - 7); + } else { + sPath = frg::string{ getAllocator(), path }; + } + if (sPath[sPath.size() - 1] != '/') { + sPath += '/'; + } + sPath += name; + if (logRpath) + mlibc::infoLogger() << "rtld: trying in rpath " << sPath << frg::endlog; + int fd = tryToOpen(sPath.data()); + if (logRpath && fd >= 0) + mlibc::infoLogger() << "rtld: found in rpath" << frg::endlog; + return frg::tuple { fd, std::move(sPath) }; + }; + + frg::string chosenPath { getAllocator() }; + int fd = -1; + if (origin && origin->runPath) { + size_t start = 0; + size_t idx = 0; + frg::string_view rpath { origin->runPath }; + auto next = [&] () { + idx = rpath.find_first(':', start); + if (idx == (size_t)-1) + idx = rpath.size(); + }; + for (next(); idx < rpath.size(); next()) { + auto path = rpath.sub_string(start, idx - start); + start = idx + 1; + auto [fd_, fullPath] = processRpath(path); + if (fd_ != -1) { + fd = fd_; + chosenPath = std::move(fullPath); + break; + } + } + if (fd == -1) { + auto path = rpath.sub_string(start, rpath.size() - start); + auto [fd_, fullPath] = processRpath(path); + if (fd_ != -1) { + fd = fd_; + chosenPath = std::move(fullPath); + } + } + } else if (logRpath) { + mlibc::infoLogger() << "rtld: no rpath set for object" << frg::endlog; + } + + for(size_t i = 0; i < libraryPaths->size() && fd == -1; i++) { + auto ldPath = (*libraryPaths)[i]; + auto path = frg::string{getAllocator(), ldPath} + '/' + name; + if(logLdPath) + mlibc::infoLogger() << "rtld: Trying to load " << name << " from ldpath " << ldPath << "/" << frg::endlog; + fd = tryToOpen(path.data()); + if(fd >= 0) { + chosenPath = std::move(path); + break; + } + } + if(fd == -1) + return LinkerError::notFound; + + if (createScope) { + __ensure(localScope == nullptr); + + // TODO: Free this when the scope is no longer needed. + localScope = frg::construct(getAllocator()); + } + + __ensure(localScope != nullptr); + + auto object = frg::construct(getAllocator(), + name.data(), std::move(chosenPath), false, localScope, rts); + + auto result = _fetchFromFile(object, fd); + closeOrDie(fd); + if(!result) { + frg::destruct(getAllocator(), object); + return result.error(); + } + + _parseDynamic(object); + _parseVerdef(object); + _addLoadedObject(object); + + return object; +} + +frg::expected ObjectRepository::requestObjectAtPath(frg::string_view path, + Scope *localScope, bool createScope, uint64_t rts) { + // TODO: Support SONAME correctly. + auto lastSlash = path.find_last('/') + 1; + auto name = path; + if (!lastSlash) { + name = name.sub_string(lastSlash, path.size() - lastSlash); + } + if (auto obj = findLoadedObject(name)) + return obj; + + if (createScope) { + __ensure(localScope == nullptr); + + // TODO: Free this when the scope is no longer needed. + localScope = frg::construct(getAllocator()); + } + + __ensure(localScope != nullptr); + + auto object = frg::construct(getAllocator(), + name.data(), path.data(), false, localScope, rts); + + frg::string no_prefix(getAllocator(), path); + + int fd; + if(mlibc::sys_open((no_prefix + '\0').data(), O_RDONLY, 0, &fd)) { + frg::destruct(getAllocator(), object); + return LinkerError::notFound; + } + auto result = _fetchFromFile(object, fd); + closeOrDie(fd); + if(!result) { + frg::destruct(getAllocator(), object); + return result.error(); + } + + _parseDynamic(object); + _parseVerdef(object); + _addLoadedObject(object); + + return object; +} + +void ObjectRepository::discoverDependenciesFromLoadedObject(SharedObject *object) { + _discoverDependencies(object, object->localScope, object->objectRts); + _parseVerneed(object); +} + +SharedObject *ObjectRepository::findCaller(void *addr) { + uintptr_t target = reinterpret_cast(addr); + + for (auto [name, object] : _nameMap) { + // Search all PT_LOAD segments for the specified address. + for(size_t j = 0; j < object->phdrCount; j++) { + auto phdr = (elf_phdr *)((uintptr_t)object->phdrPointer + j * object->phdrEntrySize); + if (phdr->p_type == PT_LOAD) { + uintptr_t start = object->baseAddress + phdr->p_vaddr; + uintptr_t end = start + phdr->p_memsz; + if (start <= target && target < end) + return object; + } + } + } + + return nullptr; +} + +SharedObject *ObjectRepository::findLoadedObject(frg::string_view name) { + auto it = _nameMap.get(name); + if (it) + return *it; + + for (auto object : loadedObjects) { + // See if any object has a matching SONAME. + if (object->soName && name == object->soName) + return object; + } + + // TODO: We should also look at the device and inode here as a fallback. + return nullptr; +} + +void ObjectRepository::addObjectToDestructQueue(SharedObject *object) { + _destructQueue.push(object); +} + +void doDestruct(SharedObject *object); + +void ObjectRepository::destructObjects() { + while (_destructQueue.size() > 0) { + auto top = _destructQueue.top(); + doDestruct(top); + _destructQueue.pop(); + } +} + +// -------------------------------------------------------- +// ObjectRepository: Fetching methods. +// -------------------------------------------------------- + +void ObjectRepository::_fetchFromPhdrs(SharedObject *object, void *phdr_pointer, + size_t phdr_entry_size, size_t phdr_count, void *entry_pointer) { + __ensure(object->isMainObject); + object->phdrPointer = phdr_pointer; + object->phdrEntrySize = phdr_entry_size; + object->phdrCount = phdr_count; + if(verbose) + mlibc::infoLogger() << "rtld: Loading " << object->name << frg::endlog; + + // Note: the entry pointer is absolute and not relative to the base address. + object->entry = entry_pointer; + + frg::optional dynamic_offset; + frg::optional tls_offset; + + // segments are already mapped, so we just have to find the dynamic section + for(size_t i = 0; i < phdr_count; i++) { + auto phdr = (elf_phdr *)((uintptr_t)phdr_pointer + i * phdr_entry_size); + switch(phdr->p_type) { + case PT_PHDR: + // Determine the executable's base address (in the PIE case) by comparing + // the PHDR segment's load address against it's address in the ELF file. + object->baseAddress = reinterpret_cast(phdr_pointer) - phdr->p_vaddr; + if(verbose) + mlibc::infoLogger() << "rtld: Executable is loaded at " + << (void *)object->baseAddress << frg::endlog; + break; + case PT_DYNAMIC: + dynamic_offset = phdr->p_vaddr; + break; + case PT_TLS: { + object->tlsSegmentSize = phdr->p_memsz; + object->tlsAlignment = phdr->p_align; + object->tlsImageSize = phdr->p_filesz; + tls_offset = phdr->p_vaddr; + break; + case PT_INTERP: + object->interpreterPath = frg::string{ + (char*)(object->baseAddress + phdr->p_vaddr), + getAllocator() + }; + } break; + default: + //FIXME warn about unknown phdrs + break; + } + } + + if(dynamic_offset) + object->dynamic = (elf_dyn *)(object->baseAddress + *dynamic_offset); + if(tls_offset) + object->tlsImagePtr = (void *)(object->baseAddress + *tls_offset); +} + + +frg::expected ObjectRepository::_fetchFromFile(SharedObject *object, int fd) { + __ensure(!object->isMainObject); + + // read the elf file header + elf_ehdr ehdr; + if(!tryReadExactly(fd, &ehdr, sizeof(elf_ehdr))) + return LinkerError::fileTooShort; + + if(ehdr.e_ident[0] != 0x7F + || ehdr.e_ident[1] != 'E' + || ehdr.e_ident[2] != 'L' + || ehdr.e_ident[3] != 'F') + return LinkerError::notElf; + + if((ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN) + || ehdr.e_machine != ELF_MACHINE + || ehdr.e_ident[EI_CLASS] != ELF_CLASS) + return LinkerError::wrongElfType; + + // read the elf program headers + auto phdr_buffer = (char *)getAllocator().allocate(ehdr.e_phnum * ehdr.e_phentsize); + if(!phdr_buffer) + return LinkerError::outOfMemory; + + if(!trySeek(fd, ehdr.e_phoff)) { + getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize); + return LinkerError::invalidProgramHeader; + } + if(!tryReadExactly(fd, phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize)) { + getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize); + return LinkerError::invalidProgramHeader; + } + + object->phdrPointer = phdr_buffer; + object->phdrCount = ehdr.e_phnum; + object->phdrEntrySize = ehdr.e_phentsize; + + // Allocate virtual address space for the DSO. + constexpr size_t hugeSize = 0x200000; + + uintptr_t highest_address = 0; + for(int i = 0; i < ehdr.e_phnum; i++) { + auto phdr = (elf_phdr *)(phdr_buffer + i * ehdr.e_phentsize); + + if(phdr->p_type != PT_LOAD) + continue; + + auto limit = phdr->p_vaddr + phdr->p_memsz; + if(limit > highest_address) + highest_address = limit; + } + + __ensure(!(object->baseAddress & (hugeSize - 1))); + + highest_address = (highest_address + mlibc::page_size - 1) & ~(mlibc::page_size - 1); + +#if MLIBC_MMAP_ALLOCATE_DSO + void *mappedAddr = nullptr; + + if (mlibc::sys_vm_map(nullptr, + highest_address - object->baseAddress, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, &mappedAddr)) { + mlibc::infoLogger() << "sys_vm_map failed when allocating address space for DSO \"" + << object->name << "\"" + << ", base " << (void *)object->baseAddress + << ", requested " << (highest_address - object->baseAddress) << " bytes" + << frg::endlog; + getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize); + return LinkerError::outOfMemory; + } + + object->baseAddress = reinterpret_cast(mappedAddr); +#else + object->baseAddress = libraryBase; + libraryBase += (highest_address + (hugeSize - 1)) & ~(hugeSize - 1); +#endif + + if(verbose || logBaseAddresses) + mlibc::infoLogger() << "rtld: Loading " << object->name + << " at " << (void *)object->baseAddress << frg::endlog; + + // Load all segments. + constexpr size_t pageSize = 0x1000; + for(int i = 0; i < ehdr.e_phnum; i++) { + auto phdr = (elf_phdr *)(phdr_buffer + i * ehdr.e_phentsize); + + if(phdr->p_type == PT_LOAD) { + size_t misalign = phdr->p_vaddr & (pageSize - 1); + if(!phdr->p_memsz) + continue; + __ensure(phdr->p_memsz >= phdr->p_filesz); + + // If the following condition is violated, we cannot use mmap() the segment; + // however, GCC only generates ELF files that satisfy this. + __ensure(misalign == (phdr->p_offset & (pageSize - 1))); + + auto map_address = object->baseAddress + phdr->p_vaddr - misalign; + auto backed_map_size = (phdr->p_filesz + misalign + pageSize - 1) & ~(pageSize - 1); + auto total_map_size = (phdr->p_memsz + misalign + pageSize - 1) & ~(pageSize - 1); + auto initial_prot = PROT_READ | PROT_WRITE; + + int prot = 0; + if(phdr->p_flags & PF_R) + prot |= PROT_READ; + if(phdr->p_flags & PF_W) + prot |= PROT_WRITE; + if(phdr->p_flags & PF_X) + prot |= PROT_EXEC; + + #if MLIBC_MAP_DSO_SEGMENTS + // we can avoid the vm_protect call if we don't have to write to the segment + if(phdr->p_memsz == phdr->p_filesz) + initial_prot = prot; + + void *map_pointer; + if(mlibc::sys_vm_map(reinterpret_cast(map_address), + backed_map_size, initial_prot, + MAP_PRIVATE | MAP_FIXED, fd, phdr->p_offset - misalign, &map_pointer)) + __ensure(!"sys_vm_map failed"); + if(total_map_size > backed_map_size) + if(mlibc::sys_vm_map(reinterpret_cast(map_address + backed_map_size), + total_map_size - backed_map_size, initial_prot, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0, &map_pointer)) + __ensure(!"sys_vm_map failed"); + + if(mlibc::sys_vm_readahead) + if(mlibc::sys_vm_readahead(reinterpret_cast(map_address), + backed_map_size)) + mlibc::infoLogger() << "mlibc: sys_vm_readahead() failed in ld.so" + << frg::endlog; + + // Clear the trailing area at the end of the backed mapping. + // We do not clear the leading area; programs are not supposed to access it. + memset(reinterpret_cast(map_address + misalign + phdr->p_filesz), + 0, phdr->p_memsz - phdr->p_filesz); + #else + (void)backed_map_size; + + void *map_pointer; + if(mlibc::sys_vm_map(reinterpret_cast(map_address), + total_map_size, initial_prot, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0, &map_pointer)) + __ensure(!"sys_vm_map failed"); + + __ensure(trySeek(fd, phdr->p_offset)); + __ensure(tryReadExactly(fd, reinterpret_cast(map_address) + misalign, + phdr->p_filesz)); + #endif + if(initial_prot != prot) { + if (!mlibc::sys_vm_protect) + __ensure(!"sys_vm_protect not provided"); + + if (mlibc::sys_vm_protect(reinterpret_cast(map_address), total_map_size, prot)) + __ensure(!"sys_vm_protect failed"); + } + }else if(phdr->p_type == PT_TLS) { + object->tlsSegmentSize = phdr->p_memsz; + object->tlsAlignment = phdr->p_align; + object->tlsImageSize = phdr->p_filesz; + object->tlsImagePtr = (void *)(object->baseAddress + phdr->p_vaddr); + }else if(phdr->p_type == PT_DYNAMIC) { + object->dynamic = (elf_dyn *)(object->baseAddress + phdr->p_vaddr); + }else if(phdr->p_type == PT_INTERP + || phdr->p_type == PT_PHDR + || phdr->p_type == PT_NOTE + || phdr->p_type == PT_RISCV_ATTRIBUTES + || phdr->p_type == PT_GNU_EH_FRAME + || phdr->p_type == PT_GNU_RELRO + || phdr->p_type == PT_GNU_STACK + || phdr->p_type == PT_GNU_PROPERTY) { + // ignore the phdr + }else{ + mlibc::panicLogger() << "Unexpected PHDR type 0x" + << frg::hex_fmt(phdr->p_type) << " in DSO " << object->name << frg::endlog; + } + } + + return frg::success; +} + +// -------------------------------------------------------- +// ObjectRepository: Parsing methods. +// -------------------------------------------------------- + +void ObjectRepository::_parseDynamic(SharedObject *object) { + if(!object->dynamic) + mlibc::infoLogger() << "ldso: Object '" << object->name + << "' does not have a dynamic section" << frg::endlog; + __ensure(object->dynamic); + + // Fix up these offsets to addresses after the loop, since the + // addresses depend on the value of DT_STRTAB. + frg::optional runpath_offset; + /* If true, ignore the RPATH. */ + bool runpath_found = false; + frg::optional soname_offset; + + for(size_t i = 0; object->dynamic[i].d_tag != DT_NULL; i++) { + elf_dyn *dynamic = &object->dynamic[i]; + switch(dynamic->d_tag) { + // handle hash table, symbol table and string table + case DT_HASH: + object->hashStyle = HashStyle::systemV; + object->hashTableOffset = dynamic->d_un.d_ptr; + break; + case DT_GNU_HASH: + object->hashStyle = HashStyle::gnu; + object->hashTableOffset = dynamic->d_un.d_ptr; + break; + case DT_STRTAB: + object->stringTableOffset = dynamic->d_un.d_ptr; + break; + case DT_STRSZ: + break; // we don't need the size of the string table + case DT_SYMTAB: + object->symbolTableOffset = dynamic->d_un.d_ptr; + break; + case DT_SYMENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_sym)); + break; + // handle lazy relocation table + case DT_PLTGOT: + object->globalOffsetTable = (void **)(object->baseAddress + + dynamic->d_un.d_ptr); + break; + case DT_JMPREL: + object->lazyRelocTableOffset = dynamic->d_un.d_ptr; + break; + case DT_PLTRELSZ: + object->lazyTableSize = dynamic->d_un.d_val; + break; + case DT_PLTREL: + if(dynamic->d_un.d_val == DT_RELA) { + object->lazyExplicitAddend = true; + }else{ + __ensure(dynamic->d_un.d_val == DT_REL); + object->lazyExplicitAddend = false; + } + break; + // TODO: Implement this correctly! + case DT_SYMBOLIC: + object->symbolicResolution = true; + break; + case DT_BIND_NOW: + object->eagerBinding = true; + break; + case DT_FLAGS: { + if(dynamic->d_un.d_val & DF_SYMBOLIC) + object->symbolicResolution = true; + if(dynamic->d_un.d_val & DF_STATIC_TLS) + object->haveStaticTls = true; + if(dynamic->d_un.d_val & DF_BIND_NOW) + object->eagerBinding = true; + + auto ignored = DF_BIND_NOW | DF_SYMBOLIC | DF_STATIC_TLS; +#ifdef __riscv + // Work around https://sourceware.org/bugzilla/show_bug.cgi?id=24673. + ignored |= DF_TEXTREL; +#else + if(dynamic->d_un.d_val & DF_TEXTREL) + mlibc::panicLogger() << "\e[31mrtld: DF_TEXTREL is unimplemented" << frg::endlog; +#endif + if(dynamic->d_un.d_val & ~ignored) + mlibc::infoLogger() << "\e[31mrtld: DT_FLAGS(" << frg::hex_fmt{dynamic->d_un.d_val & ~ignored} + << ") is not implemented correctly!\e[39m" + << frg::endlog; + } break; + case DT_FLAGS_1: + if(dynamic->d_un.d_val & DF_1_NOW) + object->eagerBinding = true; + // The DF_1_PIE flag is informational only. It is used by e.g file(1). + // The DF_1_NODELETE flag has a similar effect to RTLD_NODELETE, both of which we + // ignore because we don't implement dlclose(). + if(dynamic->d_un.d_val & ~(DF_1_NOW | DF_1_PIE | DF_1_NODELETE)) + mlibc::infoLogger() << "\e[31mrtld: DT_FLAGS_1(" << frg::hex_fmt{dynamic->d_un.d_val} + << ") is not implemented correctly!\e[39m" + << frg::endlog; + break; + case DT_RPATH: + if (runpath_found) { + /* Ignore RPATH if RUNPATH was present. */ + break; + } + [[fallthrough]]; + case DT_RUNPATH: + runpath_found = dynamic->d_tag == DT_RUNPATH; + runpath_offset = dynamic->d_un.d_val; + break; + case DT_INIT: + if(dynamic->d_un.d_ptr != 0) + object->initPtr = (InitFuncPtr)(object->baseAddress + dynamic->d_un.d_ptr); + break; + case DT_FINI: + if(dynamic->d_un.d_ptr != 0) + object->finiPtr = (InitFuncPtr)(object->baseAddress + dynamic->d_un.d_ptr); + break; + case DT_INIT_ARRAY: + if(dynamic->d_un.d_ptr != 0) + object->initArray = (InitFuncPtr *)(object->baseAddress + dynamic->d_un.d_ptr); + break; + case DT_FINI_ARRAY: + if(dynamic->d_un.d_ptr != 0) + object->finiArray = (InitFuncPtr *)(object->baseAddress + dynamic->d_un.d_ptr); + break; + case DT_INIT_ARRAYSZ: + object->initArraySize = dynamic->d_un.d_val; + break; + case DT_FINI_ARRAYSZ: + object->finiArraySize = dynamic->d_un.d_val; + break; + case DT_PREINIT_ARRAY: + if(dynamic->d_un.d_ptr != 0) { + // Only the main object is allowed pre-initializers. + __ensure(object->isMainObject); + object->preInitArray = (InitFuncPtr *)(object->baseAddress + dynamic->d_un.d_ptr); + } + break; + case DT_PREINIT_ARRAYSZ: + // Only the main object is allowed pre-initializers. + __ensure(object->isMainObject); + object->preInitArraySize = dynamic->d_un.d_val; + break; + case DT_DEBUG: +#if ELF_CLASS == ELFCLASS32 + dynamic->d_un.d_val = reinterpret_cast(&globalDebugInterface); +#elif ELF_CLASS == ELFCLASS64 + dynamic->d_un.d_val = reinterpret_cast(&globalDebugInterface); +#endif + break; + case DT_SONAME: + soname_offset = dynamic->d_un.d_val; + break; + // handle version information + case DT_VERSYM: + object->versionTableOffset = dynamic->d_un.d_ptr; + break; + case DT_VERDEF: + object->versionDefinitionTableOffset = dynamic->d_un.d_ptr; + break; + case DT_VERDEFNUM: + object->versionDefinitionCount = dynamic->d_un.d_val; + break; + case DT_VERNEED: + object->versionRequirementTableOffset = dynamic->d_un.d_ptr; + break; + case DT_VERNEEDNUM: + object->versionRequirementCount = dynamic->d_un.d_val; + break; + // ignore unimportant tags + case DT_NEEDED: // we handle this later + case DT_RELA: case DT_RELASZ: case DT_RELAENT: case DT_RELACOUNT: + case DT_REL: case DT_RELSZ: case DT_RELENT: case DT_RELCOUNT: + case DT_RELR: case DT_RELRSZ: case DT_RELRENT: +#ifdef __riscv + case DT_TEXTREL: // Work around https://sourceware.org/bugzilla/show_bug.cgi?id=24673. +#endif + break; + case DT_TLSDESC_PLT: case DT_TLSDESC_GOT: + break; + default: + // Ignore unknown entries in the os-specific area as we don't use them. + if((dynamic->d_tag < DT_LOOS || dynamic->d_tag > DT_HIOS) + && (dynamic->d_tag < DT_LOPROC || dynamic->d_tag > DT_HIPROC)) { + mlibc::panicLogger() << "Unexpected dynamic entry " + << (void *)dynamic->d_tag << " in object" << frg::endlog; + } + } + } + + if(runpath_offset) { + object->runPath = reinterpret_cast(object->baseAddress + + object->stringTableOffset + *runpath_offset); + } + if(soname_offset) { + object->soName = reinterpret_cast(object->baseAddress + + object->stringTableOffset + *soname_offset); + } +} + +void ObjectRepository::_parseVerdef(SharedObject *object) { + if(!object->versionDefinitionTableOffset) { + if(verbose) + mlibc::infoLogger() + << "mlibc: Object " << object->name + << " defines no versions" << frg::endlog; + return; + } + + if(verbose) + mlibc::infoLogger() + << "mlibc: Object " << object->name + << " defines " << object->versionDefinitionCount + << " version(s)" << frg::endlog; + + uintptr_t address = + object->baseAddress + + object->versionDefinitionTableOffset; + + for(size_t i = 0; i < object->versionDefinitionCount; i++) { + elf_verdef def; + memcpy(&def, reinterpret_cast(address), sizeof(elf_verdef)); + + // Required by spec. + __ensure(def.vd_version == 1); + __ensure(def.vd_cnt >= 1); + __ensure(!(def.vd_flags & ~(VER_FLG_BASE | VER_FLG_WEAK))); + + // NOTE(qookie): glibc also ignores any additional Verdaux entries after the + // first one. + elf_verdaux aux; + memcpy(&aux, reinterpret_cast(address + def.vd_aux), sizeof(elf_verdaux)); + + const char *name = + reinterpret_cast( + object->baseAddress + + object->stringTableOffset + aux.vda_name); + + if(verbose) + mlibc::infoLogger() + << "mlibc: Object " << object->name + << " defines version " << name + << " (index " << def.vd_ndx << ")" + << frg::endlog; + + if(!(def.vd_flags & VER_FLG_BASE)) { + SymbolVersion ver{name, def.vd_hash}; + object->definedVersions.push(ver); + object->knownVersions.insert(def.vd_ndx, ver); + } + + address += def.vd_next; + } +} + +void ObjectRepository::_parseVerneed(SharedObject *object) { + if(!object->versionRequirementTableOffset) { + if(verbose) + mlibc::infoLogger() << "mlibc: Object " << object->name << " requires no versions" << frg::endlog; + return; + } + + if(verbose) + mlibc::infoLogger() + << "mlibc: Object " << object->name + << " requires " << object->versionRequirementCount + << " version(s)" << frg::endlog; + + uintptr_t address = + object->baseAddress + + object->versionRequirementTableOffset; + + for(size_t i = 0; i < object->versionRequirementCount; i++) { + elf_verneed need; + memcpy(&need, reinterpret_cast(address), sizeof(elf_verneed)); + + // Required by spec. + __ensure(need.vn_version == 1); + + frg::string_view file = + reinterpret_cast( + object->baseAddress + + object->stringTableOffset + need.vn_file); + + // Figure out the target object from file + SharedObject *target = nullptr; + for(auto dep : object->dependencies) { + if(verbose) + mlibc::infoLogger() + << "mlibc: Trying " << dep->name << " (SONAME: " + << dep->soName << ") to satisfy " << file << frg::endlog; + if(dep->name == file || (dep->soName && dep->soName == file)) { + target = dep; + break; + } + } + if(!target) + mlibc::panicLogger() + << "mlibc: No object named \"" + << file + << "\" found for VERNEED entry of object " + << object->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() + << "mlibc: Object " << object->name + << " requires " << need.vn_cnt + << " version(s) from DSO " + << file << frg::endlog; + + uintptr_t auxAddr = address + need.vn_aux; + for(size_t j = 0; j < need.vn_cnt; j++) { + elf_vernaux aux; + memcpy(&aux, reinterpret_cast(auxAddr), sizeof(elf_vernaux)); + + // TODO(qookie): Handle weak versions. + __ensure(!aux.vna_flags); + + const char *name = + reinterpret_cast( + object->baseAddress + + object->stringTableOffset + aux.vna_name); + + if(verbose) + mlibc::infoLogger() + << "mlibc: Object " << object->name + << " requires version " << name + << " (index " << aux.vna_other + << ") from DSO " << file + << frg::endlog; + + frg::optional ver; + for(auto &def : target->definedVersions) { + if(def.hash() != aux.vna_hash) continue; + if(def.name() == name) { + ver = def; + break; + } + } + + if(!ver) + mlibc::panicLogger() + << "mlibc: Object " << target->name + << " does not define version \"" + << name << "\" needed by object " + << object->name << frg::endlog; + + bool isDefault = !(aux.vna_other & 0x8000); + // Bit 15 indicates whether the static linker should ignore this version. + object->knownVersions.insert(aux.vna_other & 0x7FFF, isDefault ? ver->makeDefault() : *ver); + + auxAddr += aux.vna_next; + } + address += need.vn_next; + } +} + +void ObjectRepository::_discoverDependencies(SharedObject *object, + Scope *localScope, uint64_t rts) { + if(object->isMainObject) { + for(auto preload : *preloads) { + frg::expected libraryResult; + if (preload.find_first('/') == size_t(-1)) { + libraryResult = requestObjectWithName(preload, object, globalScope.get(), false, 1); + } else { + libraryResult = requestObjectAtPath(preload, globalScope.get(), false, 1); + } + if(!libraryResult) + mlibc::panicLogger() << "rtld: Could not load preload " << preload << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtld: Preloading " << preload << frg::endlog; + + auto library = libraryResult.value(); + object->dependencies.push_back(library); + if (library->wasVisited) + continue; + library->wasVisited = true; + dependencyQueue.push_back(library); + } + } + + // Load required dynamic libraries. + for(size_t i = 0; object->dynamic[i].d_tag != DT_NULL; i++) { + elf_dyn *dynamic = &object->dynamic[i]; + if(dynamic->d_tag != DT_NEEDED) + continue; + + const char *library_str = (const char *)(object->baseAddress + + object->stringTableOffset + dynamic->d_un.d_val); + + auto libraryResult = requestObjectWithName(frg::string_view{library_str}, + object, localScope, false, rts); + if(!libraryResult) + mlibc::panicLogger() << "Could not satisfy dependency " << library_str << frg::endlog; + + auto library = libraryResult.value(); + object->dependencies.push(library); + if (library->wasVisited) + continue; + library->wasVisited = true; + dependencyQueue.push_back(library); + } +} + +void ObjectRepository::_addLoadedObject(SharedObject *object) { + _nameMap.insert(object->name, object); + loadedObjects.push_back(object); +} + +// -------------------------------------------------------- +// SharedObject +// -------------------------------------------------------- + +SharedObject::SharedObject(const char *name, frg::string path, + bool is_main_object, Scope *local_scope, uint64_t object_rts) + : name(name, getAllocator()), path(std::move(path)), + interpreterPath(getAllocator()), soName(nullptr), + isMainObject(is_main_object), objectRts(object_rts), inLinkMap(false), + baseAddress(0), localScope(local_scope), dynamic(nullptr), + globalOffsetTable(nullptr), entry(nullptr), tlsSegmentSize(0), + tlsAlignment(0), tlsImageSize(0), tlsImagePtr(nullptr), + tlsInitialized(false), hashTableOffset(0), symbolTableOffset(0), + stringTableOffset(0), + knownVersions({}, getAllocator()), definedVersions(getAllocator()), + lazyRelocTableOffset(0), lazyTableSize(0), + lazyExplicitAddend(false), symbolicResolution(false), + eagerBinding(false), haveStaticTls(false), + dependencies(getAllocator()), tlsModel(TlsModel::null), + tlsOffset(0), globalRts(0), wasLinked(false), + scheduledForInit(false), onInitStack(false), + wasInitialized(false) { } + +SharedObject::SharedObject(const char *name, const char *path, + bool is_main_object, Scope *localScope, uint64_t object_rts) + : SharedObject(name, + frg::string { path, getAllocator() }, + is_main_object, localScope, object_rts) {} + +frg::tuple SharedObject::getSymbolByIndex(size_t index) { + SymbolVersion ver{1}; // If we don't have any version information, treat all symbols as global. + ObjectSymbol sym{ + this, + reinterpret_cast( + baseAddress + + symbolTableOffset + + index * sizeof(elf_sym))}; + + if(versionTableOffset) { + // Pull out the VERSYM entry for this symbol + elf_version verIdx; + memcpy( + &verIdx, + reinterpret_cast( + baseAddress + + versionTableOffset + + index * sizeof(elf_version)), + sizeof(elf_version) + ); + + // Bit 15 indicates that this version is not the default one. + bool isDefault = !(verIdx & 0x8000); + verIdx &= 0x7FFF; + + // 0 and 1 are special, 0 is local, 1 is global (not in VERDEF/VERNEED) + if(verIdx != 0 && verIdx != 1) { + auto maybeVer = knownVersions.find(verIdx); + if(maybeVer == knownVersions.end()) + mlibc::panicLogger() + << "mlibc: Symbol " << sym.getString() + << " of object " << name + << " has invalid version index " << verIdx + << frg::endlog; + + ver = maybeVer->get<1>(); + } else { + ver = SymbolVersion{verIdx}; + } + + if(isDefault) + ver = ver.makeDefault(); + + if(logSymbolVersions) + mlibc::infoLogger() + << "mlibc: Symbol " << sym.getString() + << " of object " << name + << " has version " << ver.name() + << " and " << (ver.isDefault() ? "is" : "isn't") + << " the default version" + << frg::endlog; + } else { + // If we have no version information, the only symbol we've got is the default. + ver = ver.makeDefault(); + } + + return {sym, ver}; +} + +void processLateRelocation(Relocation rel) { + // resolve the symbol if there is a symbol + frg::optional p; + if(rel.symbol_index()) { + auto [sym, ver] = rel.object()->getSymbolByIndex(rel.symbol_index()); + + p = Scope::resolveGlobalOrLocal(*globalScope, rel.object()->localScope, + sym.getString(), rel.object()->objectRts, Scope::resolveCopy, ver); + } + + switch(rel.type()) { + case R_COPY: + __ensure(p); + memcpy(rel.destination(), (void *)p->virtualAddress(), p->symbol()->st_size); + break; + + case R_IRELATIVE: + rel.relocate(handleIfunc(rel.object()->baseAddress + rel.addend_rel())); + break; + + default: + break; + } +} + +void processLateRelocations(SharedObject *object) { + frg::optional rel_offset; + frg::optional rel_length; + + frg::optional rela_offset; + frg::optional rela_length; + + for(size_t i = 0; object->dynamic[i].d_tag != DT_NULL; i++) { + elf_dyn *dynamic = &object->dynamic[i]; + + switch(dynamic->d_tag) { + case DT_REL: + rel_offset = dynamic->d_un.d_ptr; + break; + case DT_RELSZ: + rel_length = dynamic->d_un.d_val; + break; + case DT_RELENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_rel)); + break; + case DT_RELA: + rela_offset = dynamic->d_un.d_ptr; + break; + case DT_RELASZ: + rela_length = dynamic->d_un.d_val; + break; + case DT_RELAENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_rela)); + break; + } + } + + if(rela_offset && rela_length) { + for(size_t offset = 0; offset < *rela_length; offset += sizeof(elf_rela)) { + auto reloc = (elf_rela *)(object->baseAddress + *rela_offset + offset); + auto r = Relocation(object, reloc); + processLateRelocation(r); + } + } else if(rel_offset && rel_length) { + for(size_t offset = 0; offset < *rel_length; offset += sizeof(elf_rel)) { + auto reloc = (elf_rel *)(object->baseAddress + *rel_offset + offset); + auto r = Relocation(object, reloc); + processLateRelocation(r); + } + }else{ + __ensure(!rela_offset && !rela_length); + __ensure(!rel_offset && !rel_length); + } +} + +void doInitialize(SharedObject *object) { + __ensure(object->wasLinked); + __ensure(!object->wasInitialized); + + if(verbose) + mlibc::infoLogger() << "rtld: Initialize " << object->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtld: Running DT_INIT function" << frg::endlog; + if(object->initPtr != nullptr) + object->initPtr(); + + if(verbose) + mlibc::infoLogger() << "rtld: Running DT_INIT_ARRAY functions" << frg::endlog; + __ensure((object->initArraySize % sizeof(InitFuncPtr)) == 0); + for(size_t i = 0; i < object->initArraySize / sizeof(InitFuncPtr); i++) + object->initArray[i](); + + if(verbose) + mlibc::infoLogger() << "rtld: Object initialization complete" << frg::endlog; + object->wasInitialized = true; +} + +void doDestruct(SharedObject *object) { + if(!object->wasInitialized || object->wasDestroyed) + return; + + if(verbose) + mlibc::infoLogger() << "rtld: Destruct " << object->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtld: Running DT_FINI_ARRAY functions" << frg::endlog; + __ensure((object->finiArraySize % sizeof(InitFuncPtr)) == 0); + for(size_t i = object->finiArraySize / sizeof(InitFuncPtr); i > 0; i--) + object->finiArray[i - 1](); + + if(verbose) + mlibc::infoLogger() << "rtld: Running DT_FINI function" << frg::endlog; + if(object->finiPtr != nullptr) + object->finiPtr(); + + if(verbose) + mlibc::infoLogger() << "rtld: Object destruction complete" << frg::endlog; + object->wasDestroyed = true; +} + +// -------------------------------------------------------- +// RuntimeTlsMap +// -------------------------------------------------------- + +RuntimeTlsMap::RuntimeTlsMap() +: initialPtr{0}, initialLimit{0}, indices{getAllocator()} { } + +void initTlsObjects(Tcb *tcb, const frg::vector &objects, bool checkInitialized) { + // Initialize TLS segments that follow the static model. + for(auto object : objects) { + if(object->tlsModel == TlsModel::initial) { + if(checkInitialized && object->tlsInitialized) + continue; + + char *tcb_ptr = reinterpret_cast(tcb); + auto tls_ptr = tcb_ptr + object->tlsOffset; + + if constexpr (tlsAboveTp) { + tls_ptr += sizeof(Tcb); + } + + memset(tls_ptr, 0, object->tlsSegmentSize); + memcpy(tls_ptr, object->tlsImagePtr, object->tlsImageSize); + + if (verbose) { + mlibc::infoLogger() << "rtld: wrote tls image at " << (void *)tls_ptr + << ", size = 0x" << frg::hex_fmt{object->tlsSegmentSize} << frg::endlog; + } + + if (checkInitialized) + object->tlsInitialized = true; + } + } +} + +Tcb *allocateTcb() { + size_t tlsInitialSize = runtimeTlsMap->initialLimit; + + // To make sure that both the TCB and TLS data are sufficiently aligned, allocate + // slightly more than necessary and adjust alignment afterwards. + size_t alignOverhead = frg::max(alignof(Tcb), tlsMaxAlignment); + size_t allocSize = tlsInitialSize + sizeof(Tcb) + alignOverhead; + auto allocation = reinterpret_cast(getAllocator().allocate(allocSize)); + memset(reinterpret_cast(allocation), 0, allocSize); + + uintptr_t tlsAddress, tcbAddress; + if constexpr (tlsAboveTp) { + // Here we must satisfy two requirements of the TCB and the TLS data: + // 1. One should follow the other immediately in memory. We do this so that + // we can simply add or subtract sizeof(Tcb) to obtain the address of the other. + // 2. Both should be sufficiently aligned. + // To do this, we will fix whichever address has stricter alignment requirements, and + // derive the other from it. + if (tlsMaxAlignment > alignof(Tcb)) { + tlsAddress = alignUp(allocation + sizeof(Tcb), tlsMaxAlignment); + tcbAddress = tlsAddress - sizeof(Tcb); + } else { + tcbAddress = alignUp(allocation, alignof(Tcb)); + tlsAddress = tcbAddress + sizeof(Tcb); + } + __ensure((tlsAddress & (tlsMaxAlignment - 1)) == 0); + __ensure(tlsAddress == tcbAddress + sizeof(Tcb)); + } else { + // The TCB should be aligned such that the preceding blocks are aligned too. + tcbAddress = alignUp(allocation + tlsInitialSize, alignOverhead); + tlsAddress = tcbAddress - tlsInitialSize; + } + __ensure((tcbAddress & (alignof(Tcb) - 1)) == 0); + + if (verbose) { + mlibc::infoLogger() << "rtld: tcb allocated at " << (void *)tcbAddress + << ", size = 0x" << frg::hex_fmt{sizeof(Tcb)} << frg::endlog; + mlibc::infoLogger() << "rtld: tls allocated at " << (void *)tlsAddress + << ", size = 0x" << frg::hex_fmt{tlsInitialSize} << frg::endlog; + } + + Tcb *tcb_ptr = new ((char *)tcbAddress) Tcb; + tcb_ptr->selfPointer = tcb_ptr; + + tcb_ptr->stackCanary = __stack_chk_guard; + tcb_ptr->cancelBits = tcbCancelEnableBit; + tcb_ptr->didExit = 0; + tcb_ptr->isJoinable = 1; + memset(&tcb_ptr->returnValue, 0, sizeof(tcb_ptr->returnValue)); + tcb_ptr->localKeys = frg::construct>(getAllocator()); + tcb_ptr->dtvSize = runtimeTlsMap->indices.size(); + tcb_ptr->dtvPointers = frg::construct_n(getAllocator(), runtimeTlsMap->indices.size()); + memset(tcb_ptr->dtvPointers, 0, sizeof(void *) * runtimeTlsMap->indices.size()); + for(size_t i = 0; i < runtimeTlsMap->indices.size(); ++i) { + auto object = runtimeTlsMap->indices[i]; + if(object->tlsModel != TlsModel::initial) + continue; + + if constexpr (tlsAboveTp) { + tcb_ptr->dtvPointers[i] = reinterpret_cast(tcb_ptr) + sizeof(Tcb) + object->tlsOffset; + } else { + tcb_ptr->dtvPointers[i] = reinterpret_cast(tcb_ptr) + object->tlsOffset; + } + } + + return tcb_ptr; +} + +void *accessDtv(SharedObject *object) { + Tcb *tcb_ptr = mlibc::get_current_tcb(); + + // We might need to reallocate the DTV. + if(object->tlsIndex >= tcb_ptr->dtvSize) { + // TODO: need to protect runtimeTlsMap against concurrent access. + auto ndtv = frg::construct_n(getAllocator(), runtimeTlsMap->indices.size()); + memset(ndtv, 0, sizeof(void *) * runtimeTlsMap->indices.size()); + memcpy(ndtv, tcb_ptr->dtvPointers, sizeof(void *) * tcb_ptr->dtvSize); + frg::destruct_n(getAllocator(), tcb_ptr->dtvPointers, tcb_ptr->dtvSize); + tcb_ptr->dtvSize = runtimeTlsMap->indices.size(); + tcb_ptr->dtvPointers = ndtv; + } + + // We might need to fill in a new DTV entry. + if(!tcb_ptr->dtvPointers[object->tlsIndex]) { + __ensure(object->tlsModel == TlsModel::dynamic); + + auto buffer = getAllocator().allocate(object->tlsSegmentSize); + __ensure(!(reinterpret_cast(buffer) & (object->tlsAlignment - 1))); + memset(buffer, 0, object->tlsSegmentSize); + memcpy(buffer, object->tlsImagePtr, object->tlsImageSize); + tcb_ptr->dtvPointers[object->tlsIndex] = buffer; + + if (verbose) { + mlibc::infoLogger() << "rtld: accessDtv wrote tls image at " << buffer + << ", size = 0x" << frg::hex_fmt{object->tlsSegmentSize} << frg::endlog; + } + } + + return (void *)((char *)tcb_ptr->dtvPointers[object->tlsIndex] + TLS_DTV_OFFSET); +} + +void *tryAccessDtv(SharedObject *object) { + Tcb *tcb_ptr = mlibc::get_current_tcb(); + + if (object->tlsIndex >= tcb_ptr->dtvSize) + return nullptr; + if (!tcb_ptr->dtvPointers[object->tlsIndex]) + return nullptr; + + return (void *)((char *)tcb_ptr->dtvPointers[object->tlsIndex] + TLS_DTV_OFFSET); +} + +// -------------------------------------------------------- +// ObjectSymbol +// -------------------------------------------------------- + +ObjectSymbol::ObjectSymbol(SharedObject *object, const elf_sym *symbol) +: _object(object), _symbol(symbol) { } + +const char *ObjectSymbol::getString() { + __ensure(_symbol->st_name != 0); + return (const char *)(_object->baseAddress + + _object->stringTableOffset + _symbol->st_name); +} + +uintptr_t ObjectSymbol::virtualAddress() { + auto bind = ELF_ST_BIND(_symbol->st_info); + __ensure(bind == STB_GLOBAL || bind == STB_WEAK || bind == STB_GNU_UNIQUE); + __ensure(_symbol->st_shndx != SHN_UNDEF); + + if (ELF_ST_TYPE(_symbol->st_info) == STT_GNU_IFUNC) + return handleIfunc(_object->baseAddress + _symbol->st_value); + + return _object->baseAddress + _symbol->st_value; +} + +size_t ObjectSymbol::size() { + return _symbol->st_size; +} + +bool ObjectSymbol::contains(uintptr_t addr) { + if(!size() && virtualAddress() == addr) + return true; + + if(size() && addr >= virtualAddress() && addr < (virtualAddress() + size())) + return true; + + return false; +} + +// -------------------------------------------------------- +// Scope +// -------------------------------------------------------- + +uint32_t elf64Hash(frg::string_view string) { + uint32_t h = 0, g; + + for(size_t i = 0; i < string.size(); ++i) { + h = (h << 4) + (uint32_t)string[i]; + g = h & 0xF0000000; + if(g) + h ^= g >> 24; + h &= 0x0FFFFFFF; + } + + return h; +} + +uint32_t gnuHash(frg::string_view string) { + uint32_t h = 5381; + for(size_t i = 0; i < string.size(); ++i) + h = (h << 5) + h + string[i]; + return h; +} + +// TODO: move this to some namespace or class? +frg::optional resolveInObject(SharedObject *object, frg::string_view string, + frg::optional version) { + // Checks if the symbol can be used to satisfy the dependency. + auto eligible = [&] (ObjectSymbol cand) { + if(cand.symbol()->st_shndx == SHN_UNDEF) + return false; + + auto bind = ELF_ST_BIND(cand.symbol()->st_info); + if(bind != STB_GLOBAL && bind != STB_WEAK && bind != STB_GNU_UNIQUE) + return false; + + return true; + }; + + // Checks if the symbol's version matches the desired version. + auto correctVersion = [&] (SymbolVersion candVersion) { + // TODO(qookie): Not sure if local symbols should participate in dynamic symbol resolution + if(!version && (candVersion.isDefault() || candVersion.isLocal() || candVersion.isGlobal())) + return true; + // Caller requested default version, but this isn't it. + if(!version) + return false; + // If the requested version is global (caller has VERNEED but not for this symbol), + // use the default one. + if(version->isGlobal() && !candVersion.isGlobal() && !candVersion.isLocal() && candVersion.isDefault()) + return true; + return *version == candVersion; + }; + + if (object->hashStyle == HashStyle::systemV) { + auto hash_table = (Elf64_Word *)(object->baseAddress + object->hashTableOffset); + Elf64_Word num_buckets = hash_table[0]; + auto bucket = elf64Hash(string) % num_buckets; + + auto index = hash_table[2 + bucket]; + while(index != 0) { + auto [cand, ver] = object->getSymbolByIndex(index); + if(eligible(cand) && frg::string_view{cand.getString()} == string && correctVersion(ver)) + return cand; + + index = hash_table[2 + num_buckets + index]; + } + + return frg::optional{}; + }else{ + __ensure(object->hashStyle == HashStyle::gnu); + + auto hash_table = reinterpret_cast(object->baseAddress + + object->hashTableOffset); + auto buckets = reinterpret_cast(object->baseAddress + + object->hashTableOffset + sizeof(GnuHashTableHeader) + + hash_table->bloomSize * sizeof(elf_addr)); + auto chains = reinterpret_cast(object->baseAddress + + object->hashTableOffset + sizeof(GnuHashTableHeader) + + hash_table->bloomSize * sizeof(elf_addr) + + hash_table->nBuckets * sizeof(uint32_t)); + + // TODO: Use the bloom filter. + + // The symbols of a given bucket are contiguous in the table. + auto hash = gnuHash(string); + auto index = buckets[hash % hash_table->nBuckets]; + + if(!index) + return frg::optional{}; + + while(true) { + // chains[] contains an array of hashes, parallel to the symbol table. + auto chash = chains[index - hash_table->symbolOffset]; + if ((chash & ~1) == (hash & ~1)) { + auto [cand, ver] = object->getSymbolByIndex(index); + if(eligible(cand) && frg::string_view{cand.getString()} == string && correctVersion(ver)) + return cand; + } + + // If we hit the end of the chain, the symbol is not present. + if(chash & 1) + return frg::optional{}; + index++; + } + } +} + +frg::optional Scope::_resolveNext(frg::string_view string, + SharedObject *target, frg::optional version) { + // Skip objects until we find the target, and only look for symbols after that. + size_t i; + for (i = 0; i < _objects.size(); i++) { + if (_objects[i] == target) + break; + } + + if (i == _objects.size()) { + mlibc::infoLogger() << "rtld: object passed to Scope::resolveAfter was not found" << frg::endlog; + return frg::optional(); + } + + for (i = i + 1; i < _objects.size(); i++) { + if(_objects[i]->isMainObject) + continue; + + frg::optional p = resolveInObject(_objects[i], string, version); + if(p) + return p; + } + + return frg::optional(); +} + +Scope::Scope(bool isGlobal) +: isGlobal{isGlobal}, _objects(getAllocator()) { } + +void Scope::appendObject(SharedObject *object) { + // Don't insert duplicates. + for (auto obj : _objects) { + if (obj == object) + return; + } + + _objects.push(object); +} + +frg::optional Scope::resolveGlobalOrLocal(Scope &globalScope, + Scope *localScope, frg::string_view string, uint64_t skipRts, ResolveFlags flags, + frg::optional version) { + auto sym = globalScope.resolveSymbol(string, skipRts, flags | skipGlobalAfterRts, version); + if(!sym && localScope) + sym = localScope->resolveSymbol(string, skipRts, flags | skipGlobalAfterRts, version); + return sym; +} + +frg::optional Scope::resolveGlobalOrLocalNext(Scope &globalScope, + Scope *localScope, frg::string_view string, SharedObject *origin, + frg::optional version) { + auto sym = globalScope._resolveNext(string, origin, version); + if(!sym && localScope) { + sym = localScope->_resolveNext(string, origin, version); + } + return sym; +} + +// TODO: let this return uintptr_t +frg::optional Scope::resolveSymbol(frg::string_view string, + uint64_t skipRts, ResolveFlags flags, + frg::optional version) { + for (auto object : _objects) { + if((flags & resolveCopy) && object->isMainObject) + continue; + if((flags & skipGlobalAfterRts) && object->globalRts > skipRts) { + // globalRts should be monotone increasing for objects in the global scope, + // so as an optimization we can break early here. + // TODO: If we implement DT_SYMBOLIC, this assumption fails. + if(isGlobal) + break; + else + continue; + } + + frg::optional p = resolveInObject(object, string, version); + if(p) + return p; + } + + return frg::optional(); +} + +// -------------------------------------------------------- +// Loader +// -------------------------------------------------------- + +Loader::Loader(Scope *scope, SharedObject *mainExecutable, bool is_initial_link, uint64_t rts) +: _mainExecutable{mainExecutable}, _loadScope{scope}, _isInitialLink{is_initial_link}, + _linkRts{rts}, _linkBfs{getAllocator()}, _initQueue{getAllocator()} { } + +void Loader::_buildLinkBfs(SharedObject *root) { + __ensure(_linkBfs.size() == 0); + + struct Token {}; + using Set = frg::hash_map, MemoryAllocator>; + Set set{frg::hash{}, getAllocator()}; + _linkBfs.push(root); + + // Loop over indices (not iterators) here: We are adding elements in the loop! + for(size_t i = 0; i < _linkBfs.size(); i++) { + auto current = _linkBfs[i]; + + // At this point the object is loaded and we can fill in its debug struct, + // the linked list fields will be filled later. + current->linkMap.base = current->baseAddress; + current->linkMap.name = current->path.data(); + current->linkMap.dynv = current->dynamic; + + __ensure((current->tlsAlignment & (current->tlsAlignment - 1)) == 0); + + if (_isInitialLink && current->tlsAlignment > tlsMaxAlignment) { + tlsMaxAlignment = current->tlsAlignment; + } + + for (auto dep : current->dependencies) { + if (!set.get(dep)) { + set.insert(dep, Token{}); + _linkBfs.push(dep); + } + } + } +} + +void Loader::linkObjects(SharedObject *root) { + _buildLinkBfs(root); + _buildTlsMaps(); + + // Promote objects to the desired scope. + for(auto object : _linkBfs) { + if (object->globalRts == 0 && _loadScope->isGlobal) + object->globalRts = _linkRts; + + _loadScope->appendObject(object); + } + + // Process regular relocations. + for(auto object : _linkBfs) { + // Some objects have already been linked before. + if(object->objectRts < _linkRts) + continue; + + if(object->dynamic == nullptr) + continue; + + if(verbose) + mlibc::infoLogger() << "rtld: Linking " << object->name << frg::endlog; + + __ensure(!object->wasLinked); + + // TODO: Support this. + if(object->symbolicResolution) + mlibc::infoLogger() << "\e[31mrtld: DT_SYMBOLIC is not implemented correctly!\e[39m" + << frg::endlog; + + _processStaticRelocations(object); + _processLazyRelocations(object); + } + + // Process copy relocations. + for(auto object : _linkBfs) { + if(!object->isMainObject) + continue; + + // Some objects have already been linked before. + if(object->objectRts < _linkRts) + continue; + + if(object->dynamic == nullptr) + continue; + + processLateRelocations(object); + } + + for(auto object : _linkBfs) { + object->wasLinked = true; + + if(object->inLinkMap) + continue; + + auto linkMap = reinterpret_cast(globalDebugInterface.head); + + object->linkMap.prev = linkMap; + object->linkMap.next = linkMap->next; + if(linkMap->next) + linkMap->next->prev = &(object->linkMap); + linkMap->next = &(object->linkMap); + object->inLinkMap = true; + } +} + +void Loader::_buildTlsMaps() { + if(_isInitialLink) { + __ensure(runtimeTlsMap->initialPtr == 0); + __ensure(runtimeTlsMap->initialLimit == 0); + + __ensure(!_linkBfs.empty()); + __ensure(_linkBfs.front()->isMainObject); + + for(auto object : _linkBfs) { + __ensure(object->tlsModel == TlsModel::null); + + if(object->tlsSegmentSize == 0) + continue; + + // Allocate an index for the object. + object->tlsIndex = runtimeTlsMap->indices.size(); + runtimeTlsMap->indices.push_back(object); + + object->tlsModel = TlsModel::initial; + + if constexpr (tlsAboveTp) { + size_t misalign = runtimeTlsMap->initialPtr & (object->tlsAlignment - 1); + if(misalign) + runtimeTlsMap->initialPtr += object->tlsAlignment - misalign; + + object->tlsOffset = runtimeTlsMap->initialPtr; + runtimeTlsMap->initialPtr += object->tlsSegmentSize; + } else { + runtimeTlsMap->initialPtr += object->tlsSegmentSize; + + size_t misalign = runtimeTlsMap->initialPtr & (object->tlsAlignment - 1); + if(misalign) + runtimeTlsMap->initialPtr += object->tlsAlignment - misalign; + + object->tlsOffset = -runtimeTlsMap->initialPtr; + } + + if(verbose) + mlibc::infoLogger() << "rtld: TLS of " << object->name + << " mapped to 0x" << frg::hex_fmt{object->tlsOffset} + << ", size: " << object->tlsSegmentSize + << ", alignment: " << object->tlsAlignment << frg::endlog; + } + + // Reserve some additional space for future libraries. + runtimeTlsMap->initialLimit = runtimeTlsMap->initialPtr + 64; + }else{ + for(auto object : _linkBfs) { + if(object->tlsModel != TlsModel::null) + continue; + if(object->tlsSegmentSize == 0) + continue; + + // Allocate an index for the object. + object->tlsIndex = runtimeTlsMap->indices.size(); + runtimeTlsMap->indices.push_back(object); + + // There are some libraries (e.g. Mesa) that require static TLS even though + // they expect to be dynamically loaded. + if(object->haveStaticTls) { + object->tlsModel = TlsModel::initial; + + if constexpr (tlsAboveTp) { + size_t misalign = runtimeTlsMap->initialPtr & (object->tlsAlignment - 1); + if(misalign) + runtimeTlsMap->initialPtr += object->tlsAlignment - misalign; + + object->tlsOffset = runtimeTlsMap->initialPtr; + runtimeTlsMap->initialPtr += object->tlsSegmentSize; + } else { + runtimeTlsMap->initialPtr += object->tlsSegmentSize; + + size_t misalign = runtimeTlsMap->initialPtr & (object->tlsAlignment - 1); + if(misalign) + runtimeTlsMap->initialPtr += object->tlsAlignment - misalign; + + object->tlsOffset = -runtimeTlsMap->initialPtr; + } + + if(runtimeTlsMap->initialPtr > runtimeTlsMap->initialLimit) + mlibc::panicLogger() << "rtld: Static TLS space exhausted while while" + " allocating TLS for " << object->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtld: TLS of " << object->name + << " mapped to 0x" << frg::hex_fmt{object->tlsOffset} + << ", size: " << object->tlsSegmentSize + << ", alignment: " << object->tlsAlignment << frg::endlog; + }else{ + object->tlsModel = TlsModel::dynamic; + } + } + } +} + +void Loader::initObjects(ObjectRepository *repository) { + initTlsObjects(mlibc::get_current_tcb(), _linkBfs, true); + + if (_mainExecutable && _mainExecutable->preInitArray) { + if (verbose) + mlibc::infoLogger() << "rtld: Running DT_PREINIT_ARRAY functions" << frg::endlog; + + __ensure(_mainExecutable->isMainObject); + __ensure(!_mainExecutable->wasInitialized); + __ensure((_mainExecutable->preInitArraySize % sizeof(InitFuncPtr)) == 0); + for(size_t i = 0; i < _mainExecutable->preInitArraySize / sizeof(InitFuncPtr); i++) + _mainExecutable->preInitArray[i](); + } + + // Convert the breadth-first representation to a depth-first post-order representation, + // so that every object is initialized *after* its dependencies. + for(auto object : _linkBfs) { + if(!object->scheduledForInit) + _scheduleInit(object); + } + + for(auto object : _initQueue) { + if(!object->wasInitialized) { + doInitialize(object); + repository->addObjectToDestructQueue(object); + } + } +} + +// TODO: Use an explicit vector to reduce stack usage to O(1)? +void Loader::_scheduleInit(SharedObject *object) { + // Here we detect cyclic dependencies. + __ensure(!object->onInitStack); + object->onInitStack = true; + + __ensure(!object->scheduledForInit); + object->scheduledForInit = true; + + for(size_t i = 0; i < object->dependencies.size(); i++) { + if(!object->dependencies[i]->scheduledForInit) + _scheduleInit(object->dependencies[i]); + } + + _initQueue.push(object); + object->onInitStack = false; +} + +void Loader::_processRelocations(Relocation &rel) { + // copy and irelative relocations have to be performed after all other relocations + if(rel.type() == R_COPY || rel.type() == R_IRELATIVE) + return; + + // resolve the symbol if there is a symbol + frg::optional p; + if(rel.symbol_index()) { + auto [sym, ver] = rel.object()->getSymbolByIndex(rel.symbol_index()); + + p = Scope::resolveGlobalOrLocal(*globalScope, rel.object()->localScope, + sym.getString(), rel.object()->objectRts, 0, ver); + if(!p) { + if(ELF_ST_BIND(sym.symbol()->st_info) != STB_WEAK) + mlibc::panicLogger() << "Unresolved load-time symbol " + << sym.getString() << " in object " << rel.object()->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtld: Unresolved weak load-time symbol " + << sym.getString() << " in object " << rel.object()->name << frg::endlog; + } + } + + switch(rel.type()) { + case R_NONE: + break; + + case R_JUMP_SLOT: { + __ensure(!rel.addend_norel()); + uintptr_t symbol_addr = p ? p->virtualAddress() : 0; + rel.relocate(symbol_addr); + } break; + +#if !defined(__riscv) && !defined(__loongarch64) + // on some architectures, R_GLOB_DAT can be defined to other relocations + case R_GLOB_DAT: { + __ensure(rel.symbol_index()); + uintptr_t symbol_addr = p ? p->virtualAddress() : 0; + rel.relocate(symbol_addr + rel.addend_norel()); + } break; +#endif + + case R_ABSOLUTE: { + __ensure(rel.symbol_index()); + uintptr_t symbol_addr = p ? p->virtualAddress() : 0; + rel.relocate(symbol_addr + rel.addend_rel()); + } break; + + case R_RELATIVE: { + __ensure(!rel.symbol_index()); + rel.relocate(rel.object()->baseAddress + rel.addend_rel()); + } break; + + // DTPMOD and DTPREL are dynamic TLS relocations (for __tls_get_addr()). + // TPOFF is a relocation to the initial TLS model. + case R_TLS_DTPMOD: { + // sets the first `sizeof(uintptr_t)` bytes of `struct __abi_tls_entry` + // this means that we can just use the `SharedObject *` to resolve whatever we need + __ensure(!rel.addend_rel()); + if(rel.symbol_index()) { + __ensure(p); + rel.relocate(elf_addr(p->object())); + }else{ + if(stillSlightlyVerbose) + mlibc::infoLogger() << "rtld: Warning: TLS_DTPMOD64 with no symbol in object " + << rel.object()->name << frg::endlog; + rel.relocate(elf_addr(rel.object())); + } + } break; + case R_TLS_DTPREL: { + __ensure(rel.symbol_index()); + __ensure(p); + rel.relocate(p->symbol()->st_value + rel.addend_rel() - TLS_DTV_OFFSET); + } break; + case R_TLS_TPREL: { + uintptr_t off = rel.addend_rel(); + ssize_t tls_offset = 0; + + if(rel.symbol_index()) { + __ensure(p); + if(p->object()->tlsModel != TlsModel::initial) + mlibc::panicLogger() << "rtld: In object " << rel.object()->name + << ": Static TLS relocation to symbol " << p->getString() + << " in dynamically loaded object " + << p->object()->name << frg::endlog; + off += p->symbol()->st_value; + tls_offset = p->object()->tlsOffset; + }else{ + if(stillSlightlyVerbose) + mlibc::infoLogger() << "rtld: Warning: TPOFF64 with no symbol" + " in object " << rel.object()->name << frg::endlog; + if(rel.object()->tlsModel != TlsModel::initial) + mlibc::panicLogger() << "rtld: In object " << rel.object()->name + << ": Static TLS relocation to dynamically loaded object " + << rel.object()->name << frg::endlog; + tls_offset = rel.object()->tlsOffset; + } + + off += tls_offset + tlsOffsetFromTp; + rel.relocate(off); + } break; + default: + mlibc::panicLogger() << "Unexpected relocation type " + << (void *) rel.type() << frg::endlog; + } +} + +void Loader::_processStaticRelocations(SharedObject *object) { + frg::optional rela_offset; + frg::optional rela_length; + + frg::optional rel_offset; + frg::optional rel_length; + + frg::optional relr_offset; + frg::optional relr_length; + + for(size_t i = 0; object->dynamic[i].d_tag != DT_NULL; i++) { + elf_dyn *dynamic = &object->dynamic[i]; + + switch(dynamic->d_tag) { + case DT_RELA: + rela_offset = dynamic->d_un.d_ptr; + break; + case DT_RELASZ: + rela_length = dynamic->d_un.d_val; + break; + case DT_RELAENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_rela)); + break; + case DT_REL: + rel_offset = dynamic->d_un.d_ptr; + break; + case DT_RELSZ: + rel_length = dynamic->d_un.d_val; + break; + case DT_RELENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_rel)); + break; + case DT_RELR: + relr_offset = dynamic->d_un.d_ptr; + break; + case DT_RELRSZ: + relr_length = dynamic->d_un.d_val; + break; + case DT_RELRENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_relr)); + break; + } + } + + if(rela_offset && rela_length) { + __ensure(!rel_offset && !rel_length); + + for(size_t offset = 0; offset < *rela_length; offset += sizeof(elf_rela)) { + auto reloc = (elf_rela *)(object->baseAddress + *rela_offset + offset); + auto r = Relocation(object, reloc); + + _processRelocations(r); + } + }else if(rel_offset && rel_length) { + __ensure(!rela_offset && !rela_length); + + for(size_t offset = 0; offset < *rel_length; offset += sizeof(elf_rel)) { + auto reloc = (elf_rel *)(object->baseAddress + *rel_offset + offset); + auto r = Relocation(object, reloc); + + _processRelocations(r); + } + } + + if(relr_offset && relr_length) { + elf_addr *addr = nullptr; + + for(size_t offset = 0; offset < *relr_length; offset += sizeof(elf_relr)) { + auto entry = *(elf_relr *)(object->baseAddress + *relr_offset + offset); + + // Even entry indicates the beginning address. + if(!(entry & 1)) { + addr = (elf_addr *)(object->baseAddress + entry); + __ensure(addr); + *addr++ += object->baseAddress; + }else { + // Odd entry indicates entry is a bitmap of the subsequent locations to be relocated. + + // The first bit of an entry is always a marker about whether the entry is an address or a bitmap, + // discard it. + entry >>= 1; + + for(int i = 0; entry; ++i) { + if(entry & 1) { + addr[i] += object->baseAddress; + } + entry >>= 1; + } + + // Each entry describes at max 63 (on 64bit) or 31 (on 32bit) subsequent locations. + addr += CHAR_BIT * sizeof(elf_relr) - 1; + } + } + } +} + +// TODO: TLSDESC relocations aren't aarch64/x86_64 specific +#if defined(__aarch64__) || defined(__x86_64__) +extern "C" void *__mlibcTlsdescStatic(void *); +extern "C" void *__mlibcTlsdescDynamic(void *); +#endif + +void Loader::_processLazyRelocations(SharedObject *object) { + if(object->globalOffsetTable == nullptr) { + __ensure(object->lazyRelocTableOffset == 0); + return; + } + object->globalOffsetTable[1] = object; + object->globalOffsetTable[2] = (void *)&pltRelocateStub; + + if(!object->lazyTableSize) + return; + + // adjust the addresses of JUMP_SLOT relocations + __ensure(object->lazyExplicitAddend.has_value()); + size_t rel_size = (*object->lazyExplicitAddend) ? sizeof(elf_rela) : sizeof(elf_rel); + + for(size_t offset = 0; offset < object->lazyTableSize; offset += rel_size) { + elf_info type; + elf_info symbol_index; + + uintptr_t rel_addr; + uintptr_t addend [[maybe_unused]] = 0; + + if(*object->lazyExplicitAddend) { + auto reloc = (elf_rela *)(object->baseAddress + object->lazyRelocTableOffset + offset); + type = ELF_R_TYPE(reloc->r_info); + symbol_index = ELF_R_SYM(reloc->r_info); + rel_addr = object->baseAddress + reloc->r_offset; + addend = reloc->r_addend; + } else { + auto reloc = (elf_rel *)(object->baseAddress + object->lazyRelocTableOffset + offset); + type = ELF_R_TYPE(reloc->r_info); + symbol_index = ELF_R_SYM(reloc->r_info); + rel_addr = object->baseAddress + reloc->r_offset; + } + + switch (type) { + case R_JUMP_SLOT: + if(eagerBinding) { + auto [sym, ver] = object->getSymbolByIndex(symbol_index); + auto p = Scope::resolveGlobalOrLocal(*globalScope, object->localScope, sym.getString(), object->objectRts, 0, ver); + + if(!p) { + if(ELF_ST_BIND(sym.symbol()->st_info) != STB_WEAK) + mlibc::panicLogger() << "rtld: Unresolved JUMP_SLOT symbol " + << sym.getString() << " in object " << object->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtld: Unresolved weak JUMP_SLOT symbol " + << sym.getString() << " in object " << object->name << frg::endlog; + *((uintptr_t *)rel_addr) = 0; + }else{ + *((uintptr_t *)rel_addr) = p->virtualAddress(); + } + }else{ + *((uintptr_t *)rel_addr) += object->baseAddress; + } + break; +#if defined(__x86_64__) + case R_X86_64_IRELATIVE: { + auto ptr = object->baseAddress + addend; + auto target = reinterpret_cast(ptr)(); + *((uintptr_t *)rel_addr) = target; + break; + } +#endif +// TODO: TLSDESC relocations aren't aarch64/x86_64 specific +#if defined(__aarch64__) || defined(__x86_64__) + case R_TLSDESC: { + size_t symValue = 0; + SharedObject *target = nullptr; + + if (symbol_index) { + auto [sym, ver] = object->getSymbolByIndex(symbol_index); + auto p = Scope::resolveGlobalOrLocal(*globalScope, object->localScope, sym.getString(), object->objectRts, 0, ver); + + if (!p) { + __ensure(ELF_ST_BIND(sym.symbol()->st_info) != STB_WEAK); + mlibc::panicLogger() << "rtld: Unresolved TLSDESC for symbol " + << sym.getString() << " in object " << object->name << frg::endlog; + } else { + target = p->object(); + if (p->symbol()) + symValue = p->symbol()->st_value; + } + } else { + target = object; + } + + __ensure(target); + + if (target->tlsModel == TlsModel::initial) { + ((uint64_t *)rel_addr)[0] = reinterpret_cast(&__mlibcTlsdescStatic); + uint64_t value = symValue + target->tlsOffset + tlsOffsetFromTp + addend; + ((uint64_t *)rel_addr)[1] = value; + } else { + struct TlsdescData { + uintptr_t tlsIndex; + uintptr_t addend; + }; + + // Access DTV for object to force the entry to be allocated and initialized + accessDtv(target); + + __ensure(target->tlsIndex < mlibc::get_current_tcb()->dtvSize); + + // TODO: We should free this when the DSO gets destroyed + auto data = frg::construct(getAllocator()); + data->tlsIndex = target->tlsIndex; + data->addend = symValue + addend; + + ((uint64_t *)rel_addr)[0] = reinterpret_cast(&__mlibcTlsdescDynamic); + ((uint64_t *)rel_addr)[1] = reinterpret_cast(data); + } + } break; +#endif + default: + mlibc::panicLogger() << "unimplemented lazy relocation type " << type << frg::endlog; + break; + } + } +} + diff --git a/user/include/mlibc/options/rtld/generic/linker.hpp b/user/include/mlibc/options/rtld/generic/linker.hpp new file mode 100644 index 0000000..6318949 --- /dev/null +++ b/user/include/mlibc/options/rtld/generic/linker.hpp @@ -0,0 +1,528 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf.hpp" + +struct ObjectRepository; +struct Scope; +struct Loader; +struct SharedObject; +struct ObjectSymbol; +struct SymbolVersion; + +extern uint64_t rtsCounter; + +enum class TlsModel { + null, + initial, + dynamic +}; + +enum class LinkerError { + success, + notFound, + fileTooShort, + notElf, + wrongElfType, + outOfMemory, + invalidProgramHeader +}; + +uint32_t elf64Hash(frg::string_view string); + +// -------------------------------------------------------- +// ObjectRepository +// -------------------------------------------------------- + +struct ObjectRepository { + ObjectRepository(); + + ObjectRepository(const ObjectRepository &) = delete; + + ObjectRepository &operator= (const ObjectRepository &) = delete; + + // This is primarily used to create a SharedObject for the RTLD itself. + SharedObject *injectObjectFromDts(frg::string_view name, + frg::string path, + uintptr_t base_address, elf_dyn *dynamic, uint64_t rts); + + // This is used to create a SharedObject for the executable that we want to link. + SharedObject *injectObjectFromPhdrs(frg::string_view name, + frg::string path, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer, + uint64_t rts); + + SharedObject *injectStaticObject(frg::string_view name, + frg::string path, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer, + uint64_t rts); + + frg::expected requestObjectWithName(frg::string_view name, + SharedObject *origin, Scope *localScope, bool createScope, uint64_t rts); + + frg::expected requestObjectAtPath(frg::string_view path, + Scope *localScope, bool createScope, uint64_t rts); + + void discoverDependenciesFromLoadedObject(SharedObject *object); + + SharedObject *findCaller(void *address); + + SharedObject *findLoadedObject(frg::string_view name); + + void addObjectToDestructQueue(SharedObject *object); + void destructObjects(); + + // Used by dl_iterate_phdr: stores objects in the order they are loaded. + frg::vector loadedObjects; + + // Used for breadth-first searching dependencies. + frg::vector dependencyQueue; + +private: + void _fetchFromPhdrs(SharedObject *object, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer); + + frg::expected _fetchFromFile(SharedObject *object, int fd); + + void _parseDynamic(SharedObject *object); + + void _parseVerdef(SharedObject *object); + void _parseVerneed(SharedObject *object); + + void _discoverDependencies(SharedObject *object, Scope *localScope, uint64_t rts); + + void _addLoadedObject(SharedObject *object); + + frg::hash_map, MemoryAllocator> _nameMap; + + // Used for destructing the objects, stores all the objects in the order they are initialized. + frg::stack _destructQueue; +}; + +// -------------------------------------------------------- +// SharedObject +// -------------------------------------------------------- + +enum class HashStyle { + none, + systemV, + gnu +}; + +struct GnuHashTableHeader { + uint32_t nBuckets; + uint32_t symbolOffset; + uint32_t bloomSize; + uint32_t bloomShift; +}; + +using InitFuncPtr = void (*)(); + +// The ABI of this struct is fixed by GDB +struct DebugInterface { + int ver; + void *head; + void (*brk)(void); + int state; + void *base; +}; + +// The ABI of this struct is fixed by GDB +struct LinkMap { + uintptr_t base = 0; + const char *name = nullptr; + elf_dyn *dynv = nullptr; + LinkMap *next = nullptr, *prev = nullptr; +}; + +struct SharedObject { + // path is copied + SharedObject(const char *name, frg::string path, + bool is_main_object, Scope *localScope, uint64_t object_rts); + + SharedObject(const char *name, const char *path, bool is_main_object, + Scope *localScope, uint64_t object_rts); + + frg::string name; + frg::string path; + frg::string interpreterPath; + const char *soName; + bool isMainObject; + uint64_t objectRts; + + // link map for debugging + LinkMap linkMap; + bool inLinkMap; + + // base address this shared object was loaded to + uintptr_t baseAddress; + + Scope *localScope; + + // pointers to the dynamic table, GOT and entry point + elf_dyn *dynamic = nullptr; + void **globalOffsetTable; + void *entry; + + // object initialization information + InitFuncPtr initPtr = nullptr; + InitFuncPtr finiPtr = nullptr; + InitFuncPtr *initArray = nullptr; + InitFuncPtr *finiArray = nullptr; + InitFuncPtr *preInitArray = nullptr; + size_t initArraySize = 0; + size_t finiArraySize = 0; + size_t preInitArraySize = 0; + + + // TODO: read this from the PHDR + size_t tlsSegmentSize, tlsAlignment, tlsImageSize; + void *tlsImagePtr; + bool tlsInitialized; + + // symbol and string table of this shared object + HashStyle hashStyle = HashStyle::none; + uintptr_t hashTableOffset; + uintptr_t symbolTableOffset; + uintptr_t stringTableOffset; + + // Version tables of this shared object + uintptr_t versionTableOffset = 0; + uintptr_t versionDefinitionTableOffset = 0; + size_t versionDefinitionCount = 0; + uintptr_t versionRequirementTableOffset = 0; + size_t versionRequirementCount = 0; + + // Versions we know about for this object's VERSYM. + frg::hash_map< + elf_version, + SymbolVersion, + frg::hash, + MemoryAllocator + > knownVersions; + // Versions that this object defines. + frg::vector definedVersions; + + const char *runPath = nullptr; + + // save the lazy JUMP_SLOT relocation table + uintptr_t lazyRelocTableOffset; + size_t lazyTableSize; + frg::optional lazyExplicitAddend; + + bool symbolicResolution; + bool eagerBinding; + bool haveStaticTls; + + // vector of dependencies + frg::vector dependencies; + + TlsModel tlsModel; + size_t tlsIndex; + ssize_t tlsOffset; + + uint64_t globalRts; + bool wasLinked; + + bool scheduledForInit; + bool onInitStack; + bool wasInitialized; + + bool wasDestroyed = false; + + bool wasVisited = false; + + bool dependenciesDiscovered = false; + + // PHDR related stuff, we only set these for the main executable + void *phdrPointer = nullptr; + size_t phdrEntrySize = 0; + size_t phdrCount = 0; + + frg::tuple getSymbolByIndex(size_t index); +}; + +struct Relocation { + Relocation(SharedObject *object, elf_rela *r) + : object_{object}, type_{Addend::Explicit} { + offset_ = r->r_offset; + info_ = r->r_info; + addend_ = r->r_addend; + } + + Relocation(SharedObject *object, elf_rel *r) + : object_{object}, type_{Addend::Implicit} { + offset_ = r->r_offset; + info_ = r->r_info; + } + + SharedObject *object() { + return object_; + } + + elf_info type() const { + return ELF_R_TYPE(info_); + } + + elf_info symbol_index() const { + return ELF_R_SYM(info_); + } + + elf_addr addend_rel() { + switch(type_) { + case Addend::Explicit: + return addend_; + case Addend::Implicit: { + auto ptr = reinterpret_cast(object_->baseAddress + offset_); + return *ptr; + } + } + __builtin_unreachable(); + } + + elf_addr addend_norel() { + switch(type_) { + case Addend::Explicit: + return addend_; + case Addend::Implicit: + return 0; + } + __builtin_unreachable(); + } + + void *destination() { + return reinterpret_cast(object_->baseAddress + offset_); + } + + void relocate(elf_addr addr) { + auto ptr = destination(); + memcpy(ptr, &addr, sizeof(addr)); + } + +private: + enum class Addend { + Implicit, + Explicit + }; + + SharedObject *object_; + Addend type_; + + elf_addr offset_; + elf_info info_; + elf_addend addend_ = 0; +}; + +void processCopyRelocations(SharedObject *object); + +// -------------------------------------------------------- +// RuntimeTlsMap +// -------------------------------------------------------- + +struct RuntimeTlsMap { + RuntimeTlsMap(); + + // Amount of initialLimit that has already been allocated. + size_t initialPtr; + + // Size of the inital TLS segment. + size_t initialLimit; + + // TLS indices. + frg::vector indices; +}; + +extern frg::manual_box runtimeTlsMap; + +Tcb *allocateTcb(); +void initTlsObjects(Tcb *tcb, const frg::vector &objects, bool checkInitialized); +void *accessDtv(SharedObject *object); +// Tries to access the DTV, if not allocated, or object doesn't have +// PT_TLS, return nullptr. +void *tryAccessDtv(SharedObject *object); + +// -------------------------------------------------------- +// ObjectSymbol +// -------------------------------------------------------- + +struct ObjectSymbol { + ObjectSymbol(SharedObject *object, const elf_sym *symbol); + + SharedObject *object() { + return _object; + } + + const elf_sym *symbol() { + return _symbol; + } + + const char *getString(); + + uintptr_t virtualAddress(); + size_t size(); + + // returns whether the address refers to the symbol + bool contains(uintptr_t addr); + +private: + SharedObject *_object; + const elf_sym *_symbol; +}; + +frg::optional resolveInObject(SharedObject *object, frg::string_view string, + frg::optional version); + +// -------------------------------------------------------- +// SymbolVersion +// -------------------------------------------------------- + +struct SymbolVersion { + SymbolVersion(const char *name, uint32_t hash) + : _local{false}, _global{false}, _default{false} + , _name{name}, _hash{hash} { } + + SymbolVersion(int idx) + : _local{idx == 0}, _global{idx == 1}, _default{false} + , _name{""}, _hash{0} { } + + SymbolVersion(const char *name) + : _local{false}, _global{false}, _default{false} + , _name{name}, _hash{elf64Hash(name)} { } + + bool isLocal() const { + return _local; + } + + bool isGlobal() const { + return _global; + } + + bool isDefault() const { + return _default; + } + + frg::string_view name() const { + if(_local) return "(*local*)"; + if(_global) return "(*global*)"; + return _name; + } + + uint32_t hash() const { + return _hash; + } + + bool operator==(const SymbolVersion &other) const { + if(_local || other._local) return _local && other._local; + if(_global || other._global) return _global && other._global; + if(_hash != other._hash) return false; + return _name == other._name; + } + + SymbolVersion makeDefault() const { + auto copy = *this; + copy._default = true; + + return copy; + } + +private: + bool _local, _global; + bool _default; + + frg::string_view _name; + uint32_t _hash; +}; + + +// -------------------------------------------------------- +// Scope +// -------------------------------------------------------- + +struct Scope { + using ResolveFlags = uint32_t; + static inline constexpr ResolveFlags resolveCopy = 1; + static inline constexpr ResolveFlags skipGlobalAfterRts = 1 << 1; + + static frg::optional resolveGlobalOrLocal(Scope &globalScope, + Scope *localScope, frg::string_view string, uint64_t skipRts, ResolveFlags flags, + frg::optional version); + static frg::optional resolveGlobalOrLocalNext(Scope &globalScope, + Scope *localScope, frg::string_view string, SharedObject *origin, + frg::optional version); + + Scope(bool isGlobal = false); + + void appendObject(SharedObject *object); + + frg::optional resolveSymbol(frg::string_view string, uint64_t skipRts, ResolveFlags flags, + frg::optional version); + + bool isGlobal; + +private: + frg::optional _resolveNext(frg::string_view string, SharedObject *target, + frg::optional version); +public: // TODO: Make this private again. (Was made public for __dlapi_reverse()). + frg::vector _objects; +}; + +extern frg::manual_box globalScope; + +// -------------------------------------------------------- +// Loader +// -------------------------------------------------------- + +struct Loader { +public: + Loader(Scope *scope, SharedObject *mainExecutable, bool is_initial_link, uint64_t rts); + +public: + void linkObjects(SharedObject *root); + +private: + void _buildLinkBfs(SharedObject *root); + void _buildTlsMaps(); + + void _processStaticRelocations(SharedObject *object); + void _processLazyRelocations(SharedObject *object); + + void _processRelocations(Relocation &rel); + +public: + void initObjects(ObjectRepository *repository); + +private: + void _scheduleInit(SharedObject *object); + +private: + SharedObject *_mainExecutable; + Scope *_loadScope; + bool _isInitialLink; + uint64_t _linkRts; + + frg::vector _linkBfs; + + frg::vector _initQueue; +}; + +// -------------------------------------------------------- +// Namespace scope functions +// -------------------------------------------------------- + +extern "C" void pltRelocateStub() __attribute__((__visibility__("hidden"))); + +// -------------------------------------------------------- +// RTLD interface +// -------------------------------------------------------- + +uintptr_t *rtld_auxvector(); + diff --git a/user/include/mlibc/options/rtld/generic/main.cpp b/user/include/mlibc/options/rtld/generic/main.cpp new file mode 100644 index 0000000..b2db152 --- /dev/null +++ b/user/include/mlibc/options/rtld/generic/main.cpp @@ -0,0 +1,1032 @@ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf.hpp" +#include "linker.hpp" + +#if __MLIBC_POSIX_OPTION +#include +#endif + +#define HIDDEN __attribute__((__visibility__("hidden"))) +#define EXPORT __attribute__((__visibility__("default"))) + +static constexpr bool logEntryExit = false; +static constexpr bool logStartup = false; +static constexpr bool logDlCalls = false; + +#ifndef MLIBC_STATIC_BUILD +extern HIDDEN void *_GLOBAL_OFFSET_TABLE_[]; +extern HIDDEN elf_dyn _DYNAMIC[]; +#endif + +namespace mlibc { + // Declared in options/internal/mlibc/tcb.hpp. + bool tcb_available_flag = false; +} // namespace mlibc + +mlibc::RtldConfig rtldConfig; + +bool ldShowAuxv = false; + +uintptr_t *entryStack; +static constinit Tcb earlyTcb{}; +frg::manual_box initialRepository; +frg::manual_box globalScope; + +frg::manual_box runtimeTlsMap; + +// We use a small vector to avoid memory allocation for the default library paths +frg::manual_box> libraryPaths; + +frg::manual_box> preloads; + +static SharedObject *executableSO; +extern HIDDEN char __ehdr_start[]; + +// Global debug interface variable +DebugInterface globalDebugInterface; + +#ifndef MLIBC_STATIC_BUILD + +// Use a PC-relative instruction sequence to find our runtime load address. +uintptr_t getLdsoBase() { +#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__m68k__) || defined(__loongarch64) + // On x86_64, the first GOT entry holds the link-time address of _DYNAMIC. + // TODO: This isn't guaranteed on AArch64, so this might fail with some linkers. + auto linktime_dynamic = reinterpret_cast(_GLOBAL_OFFSET_TABLE_[0]); + auto runtime_dynamic = reinterpret_cast(_DYNAMIC); + return runtime_dynamic - linktime_dynamic; +#elif defined(__riscv) + return reinterpret_cast(&__ehdr_start); +#else + #error Unknown architecture! +#endif +} + +#if !defined(__m68k__) +// Relocates the dynamic linker (i.e. this DSO) itself. +// Assumptions: +// - There are no references to external symbols. +// Note that this code is fragile in the sense that it must not contain relocations itself. +// TODO: Use tooling to verify this at compile time. +extern "C" void relocateSelf() { + size_t rela_offset = 0; + size_t rela_size = 0; + size_t rel_offset = 0; + size_t rel_size = 0; + size_t relr_offset = 0; + size_t relr_size = 0; + for(size_t i = 0; _DYNAMIC[i].d_tag != DT_NULL; i++) { + auto ent = &_DYNAMIC[i]; + switch(ent->d_tag) { + case DT_REL: rel_offset = ent->d_un.d_ptr; break; + case DT_RELSZ: rel_size = ent->d_un.d_val; break; + case DT_RELA: rela_offset = ent->d_un.d_ptr; break; + case DT_RELASZ: rela_size = ent->d_un.d_val; break; + case DT_RELR: relr_offset = ent->d_un.d_ptr; break; + case DT_RELRSZ: relr_size = ent->d_un.d_val; break; + } + } + + auto ldso_base = getLdsoBase(); + + for(size_t disp = 0; disp < rela_size; disp += sizeof(elf_rela)) { + auto reloc = reinterpret_cast(ldso_base + rela_offset + disp); + + auto type = ELF_R_TYPE(reloc->r_info); + if(ELF_R_SYM(reloc->r_info)) + __builtin_trap(); + + auto p = reinterpret_cast(ldso_base + reloc->r_offset); + switch(type) { + case R_RELATIVE: + *p = ldso_base + reloc->r_addend; + break; + default: + __builtin_trap(); + } + } + + for(size_t disp = 0; disp < rel_size; disp += sizeof(elf_rel)) { + auto reloc = reinterpret_cast(ldso_base + rel_offset + disp); + + auto type = ELF_R_TYPE(reloc->r_info); + if(ELF_R_SYM(reloc->r_info)) + __builtin_trap(); + + auto p = reinterpret_cast(ldso_base + reloc->r_offset); + switch(type) { + case R_RELATIVE: + *p += ldso_base; + break; + default: + __builtin_trap(); + } + } + + elf_addr *addr = nullptr; + for(size_t disp = 0; disp < relr_size; disp += sizeof(elf_relr)) { + auto entry = *(elf_relr *)(ldso_base + relr_offset + disp); + + // Even entry indicates the beginning address. + if(!(entry & 1)) { + addr = (elf_addr *)(ldso_base + entry); + __ensure(addr); + *addr++ += ldso_base; + }else { + // Odd entry indicates entry is a bitmap of the subsequent locations to be relocated. + + // The first bit of an entry is always a marker about whether the entry is an address or a bitmap, + // discard it. + entry >>= 1; + + for(int i = 0; entry; ++i) { + if(entry & 1) { + addr[i] += ldso_base; + } + entry >>= 1; + } + + // Each entry describes at max 63 (on 64bit) or 31 (on 32bit) subsequent locations. + addr += CHAR_BIT * sizeof(elf_relr) - 1; + } + } +} +#else +// m68k needs a tighter relocation function to avoid itself relying on the GOT. +extern "C" void relocateSelf68k(elf_dyn *dynamic, uintptr_t ldso_base) { + size_t rela_offset = 0; + size_t rela_size = 0; + for(size_t i = 0; dynamic[i].d_tag != DT_NULL; i++) { + auto ent = &dynamic[i]; + switch(ent->d_tag) { + case DT_RELA: rela_offset = ent->d_un.d_ptr; break; + case DT_RELASZ: rela_size = ent->d_un.d_val; break; + } + } + + for(size_t disp = 0; disp < rela_size; disp += sizeof(elf_rela)) { + auto reloc = reinterpret_cast(ldso_base + rela_offset + disp); + auto type = ELF_R_TYPE(reloc->r_info); + + auto p = reinterpret_cast(ldso_base + reloc->r_offset); + switch(type) { + case R_NONE: + break; + + case R_RELATIVE: + *p = ldso_base + reloc->r_addend; + break; + default: { + __builtin_trap(); + } + } + } +} +#endif // !defined(__m68k__) +#endif + +extern "C" void *lazyRelocate(SharedObject *object, unsigned int rel_index) { + __ensure(object->lazyExplicitAddend); + auto reloc = (elf_rela *)(object->baseAddress + object->lazyRelocTableOffset + + rel_index * sizeof(elf_rela)); + auto type = ELF_R_TYPE(reloc->r_info); + auto symbol_index = ELF_R_SYM(reloc->r_info); + + __ensure(type == R_X86_64_JUMP_SLOT); + __ensure(ELF_CLASS == ELFCLASS64); + + auto [sym, ver] = object->getSymbolByIndex(symbol_index); + auto p = Scope::resolveGlobalOrLocal(*globalScope, object->localScope, sym.getString(), object->objectRts, 0, ver); + if(!p) + mlibc::panicLogger() << "Unresolved JUMP_SLOT symbol" << frg::endlog; + + //mlibc::infoLogger() << "Lazy relocation to " << symbol_str + // << " resolved to " << pointer << frg::endlog; + + *(uint64_t *)(object->baseAddress + reloc->r_offset) = p->virtualAddress(); + return (void *)p->virtualAddress(); +} + +extern "C" [[ gnu::visibility("default") ]] void *__rtld_allocateTcb() { + auto tcb = allocateTcb(); + initTlsObjects(tcb, globalScope->_objects, false); + return tcb; +} + +extern "C" { + [[ gnu::visibility("hidden") ]] void dl_debug_state() { + // This function is used to signal changes in the debugging link map, + // GDB just sets a breakpoint on this function and we can call it + // everytime we update the link map. We don't need to implement + // anything besides defining and calling it. + } +} + +extern "C" [[gnu::alias("dl_debug_state"), gnu::visibility("default")]] void _dl_debug_state() noexcept; + +// This symbol can be used by GDB to find the global interface structure +[[ gnu::visibility("default") ]] DebugInterface *_dl_debug_addr = &globalDebugInterface; + +static frg::vector parseList(frg::string_view paths, frg::string_view separators) { + frg::vector list{getAllocator()}; + + size_t p = 0; + while(p < paths.size()) { + size_t s; // Offset of next colon or end of string. + if(size_t cs = paths.find_first_of(separators, p); cs != size_t(-1)) { + s = cs; + }else{ + s = paths.size(); + } + + auto path = paths.sub_string(p, s - p); + p = s + 1; + + if(path.size() == 0) + continue; + + if(path.ends_with("/")) { + size_t i = path.size() - 1; + while(i > 0 && path[i] == '/') + i--; + path = path.sub_string(0, i + 1); + } + + if(path == "/") + path = ""; + + list.push_back(path); + } + + return list; +} + +#ifndef MLIBC_STATIC_BUILD +static constexpr uint64_t supportedDtFlags = DF_BIND_NOW; +static constexpr uint64_t supportedDtFlags1 = DF_1_NOW; +#endif + +extern "C" void *interpreterMain(uintptr_t *entry_stack) { + if(logEntryExit) + mlibc::infoLogger() << "Entering ld.so" << frg::endlog; + entryStack = entry_stack; + + // Set up an early TCB such that we can cache our own TID. + // The TID is needed to use futexes, so this caching saves a lot of syscalls. + earlyTcb.selfPointer = &earlyTcb; + earlyTcb.tid = mlibc::this_tid(); + if(mlibc::sys_tcb_set(&earlyTcb)) + __ensure(!"sys_tcb_set() failed"); + mlibc::tcb_available_flag = true; + + runtimeTlsMap.initialize(); + libraryPaths.initialize(getAllocator()); + preloads.initialize(getAllocator()); + + void *phdr_pointer = nullptr; + size_t phdr_entry_size = 0; + size_t phdr_count = 0; + void *entry_pointer = nullptr; + void *stack_entropy = nullptr; + + const char *execfn = "(executable)"; + +#ifndef MLIBC_STATIC_BUILD + using ctor_fn = void(*)(void); + + ctor_fn *ldso_ctors = nullptr; + size_t num_ldso_ctors = 0; + + auto ldso_base = getLdsoBase(); + if(logStartup) { + mlibc::infoLogger() << "ldso: Own base address is: 0x" + << frg::hex_fmt(ldso_base) << frg::endlog; + mlibc::infoLogger() << "ldso: Own dynamic section is at: " << _DYNAMIC << frg::endlog; + } + +#ifdef __x86_64__ + // These entries are reserved on x86_64. + // TODO: Use a fake PLT stub that reports an error message? + _GLOBAL_OFFSET_TABLE_[1] = nullptr; + _GLOBAL_OFFSET_TABLE_[2] = nullptr; +#endif + + // Validate our own dynamic section. + // Here, we make sure that the dynamic linker does not need relocations itself. + uintptr_t strtab_offset = 0; + uintptr_t soname_str = 0; + for(size_t i = 0; _DYNAMIC[i].d_tag != DT_NULL; i++) { + auto ent = &_DYNAMIC[i]; + switch(ent->d_tag) { + case DT_STRTAB: strtab_offset = ent->d_un.d_ptr; break; + case DT_SONAME: soname_str = ent->d_un.d_val; break; + case DT_INIT_ARRAY: ldso_ctors = reinterpret_cast(ent->d_un.d_ptr + ldso_base); break; + case DT_INIT_ARRAYSZ: num_ldso_ctors = ent->d_un.d_val / sizeof(ctor_fn); break; + case DT_HASH: + case DT_GNU_HASH: + case DT_STRSZ: + case DT_SYMTAB: + case DT_SYMENT: + case DT_RELA: + case DT_RELASZ: + case DT_RELAENT: + case DT_RELACOUNT: + case DT_DEBUG: + case DT_REL: + case DT_RELSZ: + case DT_RELENT: + case DT_RELCOUNT: + case DT_RELR: + case DT_RELRSZ: + case DT_RELRENT: + case DT_PLTGOT: + case DT_BIND_NOW: + continue; + case DT_FLAGS: { + if((ent->d_un.d_val & ~supportedDtFlags) == 0) { + continue; + } + mlibc::panicLogger() << "rtld: unexpected DT_FLAGS value of " << frg::hex_fmt(ent->d_un.d_val) << " in program interpreter" << frg::endlog; + break; + } + case DT_FLAGS_1: { + if((ent->d_un.d_val & ~supportedDtFlags1) == 0) { + continue; + } + mlibc::panicLogger() << "rtld: unexpected DT_FLAGS_1 value of " << frg::hex_fmt(ent->d_un.d_val) << " in program interpreter" << frg::endlog; + break; + } + default: + mlibc::panicLogger() << "rtld: unexpected dynamic entry " << ent->d_tag << " in program interpreter" << frg::endlog; + } + } + __ensure(strtab_offset); + __ensure(soname_str); + + // Find the auxiliary vector by skipping args and environment. + auto aux = entryStack; + aux += *aux + 1; // First, we skip argc and all args. + __ensure(!*aux); + aux++; + while(*aux) { // Loop through the environment. + auto env = reinterpret_cast(*aux); + frg::string_view view{env}; + size_t s = view.find_first('='); + + if(s == size_t(-1)) + mlibc::panicLogger() << "rtld: environment '" << env << "' is missing a '='" << frg::endlog; + + auto name = view.sub_string(0, s); + auto value = const_cast(view.data() + s + 1); + + if(name == "LD_SHOW_AUXV" && *value && *value != '0') { + ldShowAuxv = true; + }else if(name == "LD_LIBRARY_PATH" && *value) { + for(auto path : parseList(value, ":;")) + libraryPaths->push_back(path); + }else if(name == "LD_PRELOAD" && *value) { + *preloads = parseList(value, " :"); + } + + aux++; + } + aux++; + + for (const frg::string_view path : parseList(MLIBC_DEFAULT_LIBRARY_PATHS, "\n")) { + libraryPaths->push_back(path); + } + + // Parse the actual vector. + while(true) { + auto value = aux + 1; + if(!(*aux)) + break; + + if(ldShowAuxv) { + switch(*aux) { + case AT_PHDR: mlibc::infoLogger() << "AT_PHDR: 0x" << frg::hex_fmt{*value} << frg::endlog; break; + case AT_PHENT: mlibc::infoLogger() << "AT_PHENT: " << *value << frg::endlog; break; + case AT_PHNUM: mlibc::infoLogger() << "AT_PHNUM: " << *value << frg::endlog; break; + case AT_ENTRY: mlibc::infoLogger() << "AT_ENTRY: 0x" << frg::hex_fmt{*value} << frg::endlog; break; + case AT_PAGESZ: mlibc::infoLogger() << "AT_PAGESZ: " << *value << frg::endlog; break; + case AT_BASE: mlibc::infoLogger() << "AT_BASE: 0x" << frg::hex_fmt{*value} << frg::endlog; break; + case AT_FLAGS: mlibc::infoLogger() << "AT_FLAGS: 0x" << frg::hex_fmt{*value} << frg::endlog; break; + case AT_NOTELF: mlibc::infoLogger() << "AT_NOTELF: " << frg::hex_fmt{*value} << frg::endlog; break; + case AT_UID: mlibc::infoLogger() << "AT_UID: " << *value << frg::endlog; break; + case AT_EUID: mlibc::infoLogger() << "AT_EUID: " << *value << frg::endlog; break; + case AT_GID: mlibc::infoLogger() << "AT_GID: " << *value << frg::endlog; break; + case AT_EGID: mlibc::infoLogger() << "AT_EGID: " << *value << frg::endlog; break; +#ifdef AT_PLATFORM + case AT_PLATFORM: mlibc::infoLogger() << "AT_PLATFORM: " << reinterpret_cast(*value) << frg::endlog; break; +#endif +#ifdef AT_HWCAP + case AT_HWCAP: mlibc::infoLogger() << "AT_HWCAP: " << frg::hex_fmt{*value} << frg::endlog; break; +#endif +#ifdef AT_CLKTCK + case AT_CLKTCK: mlibc::infoLogger() << "AT_CLKTCK: " << *value << frg::endlog; break; +#endif +#ifdef AT_FPUCW + case AT_FPUCW: mlibc::infoLogger() << "AT_FPUCW: " << frg::hex_fmt{*value} << frg::endlog; break; +#endif +#ifdef AT_SECURE + case AT_SECURE: mlibc::infoLogger() << "AT_SECURE: " << *value << frg::endlog; break; +#endif +#ifdef AT_RANDOM + case AT_RANDOM: mlibc::infoLogger() << "AT_RANDOM: 0x" << frg::hex_fmt{*value} << frg::endlog; break; +#endif +#ifdef AT_EXECFN + case AT_EXECFN: mlibc::infoLogger() << "AT_EXECFN: " << reinterpret_cast(*value) << frg::endlog; break; +#endif +#ifdef AT_SYSINFO_EHDR + case AT_SYSINFO_EHDR: mlibc::infoLogger() << "AT_SYSINFO_EHDR: 0x" << frg::hex_fmt{*value} << frg::endlog; break; +#endif + } + } + + // TODO: Whitelist auxiliary vector entries here? + switch(*aux) { + case AT_PHDR: phdr_pointer = reinterpret_cast(*value); break; + case AT_PHENT: phdr_entry_size = *value; break; + case AT_PHNUM: phdr_count = *value; break; + case AT_ENTRY: entry_pointer = reinterpret_cast(*value); break; + case AT_EXECFN: execfn = reinterpret_cast(*value); break; + case AT_RANDOM: stack_entropy = reinterpret_cast(*value); break; + case AT_SECURE: rtldConfig.secureRequired = reinterpret_cast(*value); break; + } + + aux += 2; + } + globalDebugInterface.base = reinterpret_cast(ldso_base); + +// This is here because libgcc will add a global constructor on glibc Linux +// (which is what it believes we are due to the aarch64-linux-gnu toolchain) +// in order to check if LSE atomics are supported. +// +// This is not necessary on a custom Linux toolchain and is purely an artifact of +// using the host toolchain. +#if defined(__aarch64__) && defined(__gnu_linux__) + for (size_t i = 0; i < num_ldso_ctors; i++) { + if(logStartup) + mlibc::infoLogger() << "ldso: Running own constructor at " + << reinterpret_cast(ldso_ctors[i]) + << frg::endlog; + ldso_ctors[i](); + } +#else + if (num_ldso_ctors > 0) { + mlibc::panicLogger() << "ldso: Found unexpected own global constructor(s), init_array starts at: " + << ldso_ctors + << frg::endlog; + } +#endif + +#else + auto ehdr = reinterpret_cast(__ehdr_start); + phdr_pointer = reinterpret_cast((uintptr_t)ehdr->e_phoff + (uintptr_t)ehdr); + phdr_entry_size = ehdr->e_phentsize; + phdr_count = ehdr->e_phnum; + entry_pointer = reinterpret_cast(ehdr->e_entry); +#endif + __ensure(phdr_pointer); + __ensure(entry_pointer); + + if(logStartup) + mlibc::infoLogger() << "ldso: Executable PHDRs are at " << phdr_pointer + << frg::endlog; + + // perform the initial dynamic linking + initialRepository.initialize(); + + globalScope.initialize(true); + + // Add the dynamic linker, as well as the exectuable to the repository. +#ifndef MLIBC_STATIC_BUILD + auto ldso_soname = reinterpret_cast(ldso_base + strtab_offset + soname_str); + auto ldso = initialRepository->injectObjectFromDts(ldso_soname, + frg::string { getAllocator() }, + ldso_base, _DYNAMIC, 1); + + auto ldso_ehdr = reinterpret_cast(__ehdr_start); + auto ldso_phdr = reinterpret_cast(ldso_base + ldso_ehdr->e_phoff); + + ldso->phdrPointer = ldso_phdr; + ldso->phdrCount = ldso_ehdr->e_phnum; + ldso->phdrEntrySize = ldso_ehdr->e_phentsize; + + // TODO: support non-zero base addresses? + executableSO = initialRepository->injectObjectFromPhdrs(execfn, + frg::string { execfn, getAllocator() }, + phdr_pointer, phdr_entry_size, phdr_count, entry_pointer, 1); + + // We can't initialise the ldso object after the executable SO, + // so we have to set the ldso path after loading both. + ldso->path = executableSO->interpreterPath; + + // Discover dependencies in a breadth-first search. + for (size_t i = 0; i < initialRepository->dependencyQueue.size(); i++) { + auto current = initialRepository->dependencyQueue[i]; + initialRepository->discoverDependenciesFromLoadedObject(current); + current->dependenciesDiscovered = true; + } +#else + executableSO = initialRepository->injectStaticObject(execfn, + frg::string{ execfn, getAllocator() }, + phdr_pointer, phdr_entry_size, phdr_count, entry_pointer, 1); + globalDebugInterface.base = (void*)executableSO->baseAddress; +#endif + + globalDebugInterface.head = &executableSO->linkMap; + executableSO->inLinkMap = true; + Loader linker{globalScope.get(), executableSO, true, 1}; + linker.linkObjects(executableSO); + + mlibc::initStackGuard(stack_entropy); + + auto tcb = allocateTcb(); + tcb->tid = earlyTcb.tid; + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + globalDebugInterface.ver = 1; + globalDebugInterface.brk = &dl_debug_state; + globalDebugInterface.state = 0; + dl_debug_state(); + + linker.initObjects(initialRepository.get()); + + if(logEntryExit) + mlibc::infoLogger() << "Leaving ld.so, jump to " + << (void *)executableSO->entry << frg::endlog; + return executableSO->entry; +} + +const char *lastError; + +extern "C" [[ gnu::visibility("default") ]] uintptr_t *__dlapi_entrystack() { + return entryStack; +} + +extern "C" [[ gnu::visibility("default") ]] +const char *__dlapi_error() { + auto error = lastError; + lastError = nullptr; + return error; +} + +extern "C" [[ gnu::visibility("default") ]] +void *__dlapi_get_tls(struct __abi_tls_entry *entry) { + return reinterpret_cast(accessDtv(entry->object)) + entry->offset; +} + +extern "C" [[ gnu::visibility("default") ]] +const mlibc::RtldConfig &__dlapi_get_config() { + return rtldConfig; +} + +extern "C" [[ gnu::visibility("default") ]] void __dlapi_exit() { + initialRepository->destructObjects(); +} + +#if __MLIBC_POSIX_OPTION + +extern "C" [[ gnu::visibility("default") ]] +void *__dlapi_open(const char *file, int flags, void *returnAddress) { + if (logDlCalls) + mlibc::infoLogger() << "rtld: __dlapi_open(" << (file ? file : "nullptr") << ")" << frg::endlog; + + if (flags & RTLD_DEEPBIND) + mlibc::infoLogger() << "rtld: dlopen(RTLD_DEEPBIND) is unsupported" << frg::endlog; + + if(!file) + return executableSO; + + // TODO: Thread-safety! + auto rts = rtsCounter++; + + SharedObject *object; + if (flags & RTLD_NOLOAD) { + object = initialRepository->findLoadedObject(file); + if (object && object->globalRts == 0 && (flags & RTLD_GLOBAL)) { + // The object was opened with RTLD_LOCAL, but we are called with RTLD_NOLOAD | RTLD_GLOBAL. + // According to the man page, we should promote to the global scope here. + object->globalRts = rts; + globalScope->appendObject(object); + } + } else { + bool isGlobal = flags & RTLD_GLOBAL; + Scope *newScope = isGlobal ? globalScope.get() : nullptr; + + frg::expected objectResult; + if (frg::string_view{file}.find_first('/') == size_t(-1)) { + // In order to know which RUNPATH / RPATH to process, we must find the calling object. + SharedObject *origin = initialRepository->findCaller(returnAddress); + if (!origin) { + mlibc::panicLogger() << "rtld: unable to determine calling object of dlopen " + << "(ra = " << returnAddress << ")" << frg::endlog; + } + + objectResult = initialRepository->requestObjectWithName(file, origin, newScope, !isGlobal, rts); + } else { + objectResult = initialRepository->requestObjectAtPath(file, newScope, !isGlobal, rts); + } + + if(!objectResult) { + switch (objectResult.error()) { + case LinkerError::success: + __builtin_unreachable(); + case LinkerError::notFound: + lastError = "Cannot locate requested DSO"; + break; + case LinkerError::fileTooShort: + lastError = "File too short"; + break; + case LinkerError::notElf: + lastError = "File is not an ELF file"; + break; + case LinkerError::wrongElfType: + lastError = "File has wrong ELF type"; + break; + case LinkerError::outOfMemory: + lastError = "Out of memory"; + break; + case LinkerError::invalidProgramHeader: + lastError = "File has invalid program header"; + break; + } + return nullptr; + } + + object = objectResult.value(); + initialRepository->discoverDependenciesFromLoadedObject(object); + for (size_t i = 0; i < initialRepository->dependencyQueue.size(); i++) { + auto current = initialRepository->dependencyQueue[i]; + if(!current->dependenciesDiscovered) { + initialRepository->discoverDependenciesFromLoadedObject(current); + current->dependenciesDiscovered = true; + } + } + + Loader linker{object->localScope, nullptr, false, rts}; + linker.linkObjects(object); + linker.initObjects(initialRepository.get()); + } + + dl_debug_state(); + + return object; +} + +extern "C" [[ gnu::visibility("default") ]] +void *__dlapi_resolve(void *handle, const char *string, void *returnAddress, const char *version) { + if (logDlCalls) { + const char *name; + bool quote = false; + if (handle == RTLD_DEFAULT) { + name = "RTLD_DEFAULT"; + } else if (handle == RTLD_NEXT) { + name = "RTLD_NEXT"; + } else { + name = ((SharedObject *)handle)->name.data(); + quote = true; + } + + mlibc::infoLogger() << "rtld: __dlapi_resolve(" << (quote ? "\"" : "") << name + << (quote ? "\"" : "") << ", \"" << string << "\")" << frg::endlog; + } + + frg::optional target; + frg::optional targetVersion = frg::null_opt; + + if(version) + targetVersion = SymbolVersion{version}; + + if (handle == RTLD_DEFAULT) { + target = globalScope->resolveSymbol(string, 0, 0, targetVersion); + } else if (handle == RTLD_NEXT) { + SharedObject *origin = initialRepository->findCaller(returnAddress); + if (!origin) { + mlibc::panicLogger() << "rtld: unable to determine calling object of dlsym " + << "(ra = " << returnAddress << ")" << frg::endlog; + } + + target = Scope::resolveGlobalOrLocalNext(*globalScope, origin->localScope, string, origin, targetVersion); + } else { + // POSIX does not unambiguously state how dlsym() is supposed to work; it just + // states that "The symbol resolution algorithm used shall be dependency order + // as described in dlopen()". + // + // Linux libc's lookup the symbol in the given DSO and all of its dependencies + // in breadth-first order. That is also what we implement here. + // + // Note that this *differs* from the algorithm that is used for relocations + // (since the algorithm used for relocations takes (i) the global scope, + // and (ii) the local scope of the DSO into account (which can contain more objects + // than just the dependencies of the DSO, if the DSO was loaded as a dependency + // of a dlopen()ed DSO). + + frg::vector queue{getAllocator()}; + + struct Token { }; + frg::hash_map< + SharedObject *, Token, + frg::hash, MemoryAllocator + > visited{frg::hash{}, getAllocator()}; + + auto root = reinterpret_cast(handle); + visited.insert(root, Token{}); + queue.push_back(root); + + for(size_t i = 0; i < queue.size(); i++) { + auto current = queue[i]; + + target = resolveInObject(current, string, targetVersion); + if(target) + break; + + for(auto dep : current->dependencies) { + if(visited.get(dep)) + continue; + visited.insert(dep, Token{}); + queue.push_back(dep); + } + } + } + + if (!target) { + if (logDlCalls) + mlibc::infoLogger() << "rtld: could not resolve \"" << string << "\"" << frg::endlog; + + lastError = "Cannot resolve requested symbol"; + return nullptr; + } + return reinterpret_cast(target->virtualAddress()); +} + +struct __dlapi_symbol { + const char *file; + void *base; + const char *symbol; + void *address; + const void *elf_symbol; + void *link_map; +}; + +extern "C" [[ gnu::visibility("default") ]] +int __dlapi_reverse(const void *ptr, __dlapi_symbol *info) { + if (logDlCalls) + mlibc::infoLogger() << "rtld: __dlapi_reverse(" << ptr << ")" << frg::endlog; + + for(size_t i = 0; i < initialRepository->loadedObjects.size(); i++) { + auto object = initialRepository->loadedObjects[i]; + + auto eligible = [&] (ObjectSymbol cand) { + if(cand.symbol()->st_shndx == SHN_UNDEF) + return false; + + auto bind = ELF_ST_BIND(cand.symbol()->st_info); + if(bind != STB_GLOBAL && bind != STB_WEAK) + return false; + + return true; + }; + + size_t start_symbols = 0; + size_t num_symbols = 0; + + if(object->hashStyle == HashStyle::systemV) { + auto hash_table = (Elf64_Word *)(object->baseAddress + object->hashTableOffset); + + // nchain == number of symtab entries + num_symbols = hash_table[1]; + } else if(object->hashStyle == HashStyle::gnu) { + size_t last_sym = 0; + + auto hash_table = reinterpret_cast(object->baseAddress + object->hashTableOffset); + auto bucket = reinterpret_cast(uintptr_t(hash_table) + sizeof(*hash_table) + (hash_table->bloomSize * sizeof(elf_addr))); + auto chains = reinterpret_cast(uintptr_t(bucket) + hash_table->nBuckets * 4); + + if (hash_table->nBuckets) { + for(size_t i = 0; i < hash_table->nBuckets; i++) { + if(last_sym < bucket[i]) + last_sym = bucket[i]; + } + + while(!(chains[last_sym - hash_table->symbolOffset] & 1)) + last_sym++; + } + + start_symbols = hash_table->symbolOffset; + num_symbols = last_sym; + } else { + __ensure(!"unexpected hash style!"); + } + + for(size_t i = start_symbols; i < num_symbols; i++) { + ObjectSymbol cand{object, (elf_sym *)(object->baseAddress + + object->symbolTableOffset + i * sizeof(elf_sym))}; + if(eligible(cand) && cand.contains(reinterpret_cast(ptr))) { + if (logDlCalls) + mlibc::infoLogger() << "rtld: Found symbol " << cand.getString() << " in object " + << object->path << frg::endlog; + + info->file = object->path.data(); + info->base = reinterpret_cast(object->baseAddress); + info->symbol = cand.getString(); + info->address = reinterpret_cast(cand.virtualAddress()); + info->elf_symbol = cand.symbol(); + info->link_map = &object->linkMap; + return 0; + } + } + } + + // Not found, find the DSO it should be in. + for(size_t i = 0; i < initialRepository->loadedObjects.size(); i++) { + auto object = initialRepository->loadedObjects[i]; + + for(size_t j = 0; j < object->phdrCount; j++) { + auto phdr = (elf_phdr *)((uintptr_t)object->phdrPointer + j * object->phdrEntrySize); + if(phdr->p_type != PT_LOAD) { + continue; + } + uintptr_t start = object->baseAddress + phdr->p_vaddr; + uintptr_t end = start + phdr->p_memsz; + if(reinterpret_cast(ptr) >= start && reinterpret_cast(ptr) < end) { + if (logDlCalls) + mlibc::infoLogger() << "rtld: Found DSO " << object->path << frg::endlog; + info->file = object->path.data(); + info->base = reinterpret_cast(object->baseAddress); + info->symbol = nullptr; + info->address = nullptr; + info->elf_symbol = nullptr; + info->link_map = &object->linkMap; + return 0; + } + } + } + + if (logDlCalls) + mlibc::infoLogger() << "rtld: Could not find symbol in __dlapi_reverse()" << frg::endlog; + + return -1; +} + +extern "C" [[ gnu::visibility("default") ]] +int __dlapi_close(void *) { + if (logDlCalls) + mlibc::infoLogger() << "mlibc: dlclose() is a no-op" << frg::endlog; + return 0; +} + +#endif + +extern "C" [[ gnu::visibility("default") ]] +int __dlapi_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void*), void *data) { + int last_return = 0; + for (auto object : initialRepository->loadedObjects) { + struct dl_phdr_info info; + info.dlpi_addr = object->baseAddress; + info.dlpi_name = object->name.data(); + + if(object->isMainObject) { + info.dlpi_name = ""; + } else { + info.dlpi_name = object->name.data(); + } + info.dlpi_phdr = static_cast(object->phdrPointer); + info.dlpi_phnum = object->phdrCount; + info.dlpi_adds = rtsCounter; + info.dlpi_subs = 0; // TODO(geert): implement dlclose(). + if (object->tlsModel != TlsModel::null) + info.dlpi_tls_modid = object->tlsIndex; + else + info.dlpi_tls_modid = 0; + info.dlpi_tls_data = tryAccessDtv(object); + + last_return = callback(&info, sizeof(struct dl_phdr_info), data); + if(last_return) + return last_return; + } + + return last_return; +} + +extern "C" [[ gnu::visibility("default") ]] +void __dlapi_enter(uintptr_t *entry_stack) { +#if MLIBC_STATIC_BUILD + interpreterMain(entry_stack); +#else + (void)entry_stack; +#endif +} + +#if __MLIBC_GLIBC_OPTION + +extern "C" [[gnu::visibility("default")]] int __dlapi_find_object(void *address, dl_find_object *result) { + for(const SharedObject *object : initialRepository->loadedObjects) { + if(object->baseAddress > reinterpret_cast(address)) + continue; + + if(object->inLinkMap) + result->dlfo_link_map = (link_map *)&object->linkMap; + else + result->dlfo_link_map = nullptr; + + uintptr_t end_addr = 0; + for(size_t j = 0; j < object->phdrCount; j++) { + auto phdr = (elf_phdr *)((uintptr_t)object->phdrPointer + j * object->phdrEntrySize); + if(phdr->p_type == DLFO_EH_SEGMENT_TYPE) { + result->dlfo_eh_frame = (void *)(object->baseAddress + phdr->p_vaddr); + continue; + } + if(phdr->p_type != PT_LOAD) { + continue; + } + end_addr = frg::max(end_addr, phdr->p_vaddr + phdr->p_memsz); + } + + if(reinterpret_cast(address) > object->baseAddress + end_addr) + continue; + + result->dlfo_flags = 0; + result->dlfo_map_start = (void *)object->baseAddress; + result->dlfo_map_end = (void *)(object->baseAddress + end_addr); + +// TODO: fill these fields with proper values +#if DLFO_STRUCT_HAS_EH_DBASE + mlibc::infoLogger() << "mlibc: _dl_find_object dlfo_eh_dbase is not implemented and always returns NULL" << frg::endlog; + result->dlfo_eh_dbase = nullptr; +#endif // DLFO_STRUCT_HAS_EH_DBASE +#if DLFO_STRUCT_HAS_EH_COUNT + mlibc::infoLogger() << "mlibc: _dl_find_object dlfo_eh_count is not implemented and always returns 0" << frg::endlog; + result->dlfo_eh_count = 0; +#endif // DLFO_STRUCT_HAS_EH_COUNT + + return 0; + } + + return -1; +} + +#if !defined(MLIBC_STATIC_BUILD) +extern "C" [[gnu::visibility("default"), gnu::alias("__dlapi_find_object")]] int _dl_find_object(void *address, dl_find_object *result); +#endif + +#endif // __MLIBC_GLIBC_OPTION + +uintptr_t *rtld_auxvector() { + // Find the auxiliary vector by skipping args and environment. + auto aux = entryStack; + aux += *aux + 1; // Skip argc and all arguments + __ensure(!*aux); + aux++; + while(*aux) // Now, we skip the environment. + aux++; + aux++; + + return aux; +} + +// XXX(qookie): +// This is here because libgcc will call into __getauxval on glibc Linux +// (which is what it believes we are due to the aarch64-linux-gnu toolchain) +// in order to find AT_HWCAP to discover if LSE atomics are supported. +// +// This is not necessary on a custom Linux toolchain and is purely an artifact of +// using the host toolchain. + +// __gnu_linux__ is the define checked by libgcc +#if defined(__aarch64__) && defined(__gnu_linux__) && !defined(MLIBC_STATIC_BUILD) + +extern "C" unsigned long __getauxval(unsigned long type) { + auto aux = rtld_auxvector(); + __ensure(aux); + + // Parse the auxiliary vector. + while(true) { + auto value = aux + 1; + if(*aux == AT_NULL) { + return 0; + }else if(*aux == type) { + return *value; + } + aux += 2; + } +} + +#endif diff --git a/user/include/mlibc/options/rtld/include/mlibc/rtld-abi.hpp b/user/include/mlibc/options/rtld/include/mlibc/rtld-abi.hpp new file mode 100644 index 0000000..9ab707e --- /dev/null +++ b/user/include/mlibc/options/rtld/include/mlibc/rtld-abi.hpp @@ -0,0 +1,30 @@ +#ifndef MLIBC_RTLD_ABI +#define MLIBC_RTLD_ABI + +#include + +#if defined(__x86_64__) || defined(__aarch64__) || defined(__i386__) || defined(__riscv) || defined (__m68k__) || defined(__loongarch64) + +struct __abi_tls_entry { + struct SharedObject *object; + size_t offset; +}; +static_assert(sizeof(__abi_tls_entry) == sizeof(size_t) * 2, "Bad __abi_tls_entry size"); + +extern "C" void *__dlapi_get_tls(struct __abi_tls_entry *); + +#else +#error "Missing architecture specific code." +#endif + +#if defined(__riscv) +constexpr inline unsigned long TLS_DTV_OFFSET = 0x800; +#elif defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__loongarch64) +constexpr inline unsigned long TLS_DTV_OFFSET = 0; +#elif defined(__m68k__) +constexpr inline unsigned long TLS_DTV_OFFSET = 0x8000; +#else +#error "Missing architecture specific code." +#endif + +#endif // MLIBC_RTLD_ABI diff --git a/user/include/mlibc/options/rtld/include/mlibc/rtld-config.hpp b/user/include/mlibc/options/rtld/include/mlibc/rtld-config.hpp new file mode 100644 index 0000000..9e4488c --- /dev/null +++ b/user/include/mlibc/options/rtld/include/mlibc/rtld-config.hpp @@ -0,0 +1,27 @@ +#ifndef MLIBC_RTLD_CONFIG +#define MLIBC_RTLD_CONFIG + +namespace mlibc { + +struct RtldConfig { + bool secureRequired; +}; + +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +extern "C" const mlibc::RtldConfig &__dlapi_get_config(); +#pragma clang diagnostic pop + +#ifndef MLIBC_BUILDING_RTLD +namespace mlibc { + +inline const RtldConfig &rtldConfig() { + return __dlapi_get_config(); +} + +} +#endif + +#endif // MLIBC_RTLD_CONFIG diff --git a/user/include/mlibc/options/rtld/include/mlibc/rtld-sysdeps.hpp b/user/include/mlibc/options/rtld/include/mlibc/rtld-sysdeps.hpp new file mode 100644 index 0000000..6f42d41 --- /dev/null +++ b/user/include/mlibc/options/rtld/include/mlibc/rtld-sysdeps.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_RTLD_SYSDEPS +#define MLIBC_RTLD_SYSDEPS + +namespace [[gnu::visibility("hidden")]] mlibc { + +int sys_tcb_set(void *pointer); + +[[gnu::weak]] int sys_vm_readahead(void *pointer, size_t size); + +} // namespace mlibc + +#endif // MLIBC_RTLD_SYSDEPS diff --git a/user/include/mlibc/options/rtld/loongarch64/elf.hpp b/user/include/mlibc/options/rtld/loongarch64/elf.hpp new file mode 100644 index 0000000..49f5fea --- /dev/null +++ b/user/include/mlibc/options/rtld/loongarch64/elf.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS64 +#define ELF_MACHINE EM_LOONGARCH + +using elf_ehdr = Elf64_Ehdr; +using elf_phdr = Elf64_Phdr; +using elf_dyn = Elf64_Dyn; +using elf_rel = Elf64_Rel; +using elf_rela = Elf64_Rela; +using elf_relr = Elf64_Relr; +using elf_sym = Elf64_Sym; +using elf_addr = Elf64_Addr; + +using elf_info = Elf64_Xword; +using elf_addend = Elf64_Sxword; + +using elf_version = Elf64_Half; +using elf_verdef = Elf64_Verdef; +using elf_verdaux = Elf64_Verdaux; +using elf_verneed = Elf64_Verneed; +using elf_vernaux = Elf64_Vernaux; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE + +#define R_NONE R_LARCH_NONE +#define R_JUMP_SLOT R_LARCH_JUMP_SLOT +#define R_ABSOLUTE R_LARCH_64 +#define R_GLOB_DAT R_LARCH_64 +#define R_RELATIVE R_LARCH_RELATIVE +#define R_IRELATIVE R_LARCH_IRELATIVE +#define R_COPY R_LARCH_COPY +#define R_TLS_DTPMOD R_LARCH_TLS_DTPMOD64 +#define R_TLS_DTPREL R_LARCH_TLS_DTPREL64 +#define R_TLS_TPREL R_LARCH_TLS_TPREL64 +// There appears to be no R_TLSDESC-equivalent + +struct ifunc_arg { + unsigned long _size; + unsigned long _hwcap; +}; + +using ifunc_handler = elf_addr (*)(ifunc_arg *); diff --git a/user/include/mlibc/options/rtld/loongarch64/entry.S b/user/include/mlibc/options/rtld/loongarch64/entry.S new file mode 100644 index 0000000..0aeb968 --- /dev/null +++ b/user/include/mlibc/options/rtld/loongarch64/entry.S @@ -0,0 +1,16 @@ +#include "mlibc-asm/helpers.h" + +PROC_START(_start) + pcaddu18i $ra, %call36(relocateSelf) + jirl $ra, $ra, 0 + + move $fp, $zero + move $a0, $sp + pcaddu18i $ra, %call36(interpreterMain) + jirl $ra, $ra, 0 + + jr $a0 +PROC_END(_start) + +GNU_STACK_NOTE() + diff --git a/user/include/mlibc/options/rtld/loongarch64/runtime.S b/user/include/mlibc/options/rtld/loongarch64/runtime.S new file mode 100644 index 0000000..a9dc367 --- /dev/null +++ b/user/include/mlibc/options/rtld/loongarch64/runtime.S @@ -0,0 +1,5 @@ +.global pltRelocateStub +pltRelocateStub: + break 0 // TODO +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/rtld/m68k/elf.hpp b/user/include/mlibc/options/rtld/m68k/elf.hpp new file mode 100644 index 0000000..6f76b3b --- /dev/null +++ b/user/include/mlibc/options/rtld/m68k/elf.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS32 +#define ELF_MACHINE EM_68K + +using elf_ehdr = Elf32_Ehdr; +using elf_phdr = Elf32_Phdr; +using elf_dyn = Elf32_Dyn; +using elf_rel = Elf32_Rel; +using elf_rela = Elf32_Rela; +using elf_relr = Elf32_Relr; +using elf_sym = Elf32_Sym; +using elf_addr = Elf32_Addr; + +using elf_info = Elf32_Word; +using elf_addend = Elf32_Sword; + +using elf_version = Elf32_Half; +using elf_verdef = Elf32_Verdef; +using elf_verdaux = Elf32_Verdaux; +using elf_verneed = Elf32_Verneed; +using elf_vernaux = Elf32_Vernaux; + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE + +#define R_NONE R_68K_NONE +#define R_JUMP_SLOT R_68K_JMP_SLOT +#define R_ABSOLUTE R_68K_32 +#define R_GLOB_DAT R_68K_GLOB_DAT +#define R_RELATIVE R_68K_RELATIVE +#define R_OFFSET R_68K_PC32 +#define R_COPY R_68K_COPY +#define R_TLS_DTPMOD R_68K_TLS_DTPMOD32 +#define R_TLS_DTPREL R_68K_TLS_DTPREL32 +#define R_TLS_TPREL R_68K_TLS_TPREL32 +#define R_IRELATIVE 222 /* doesn't happen */ + +#define TP_TCB_OFFSET 0 + +using ifunc_handler = elf_addr (*)(void); diff --git a/user/include/mlibc/options/rtld/m68k/entry.S b/user/include/mlibc/options/rtld/m68k/entry.S new file mode 100644 index 0000000..deb164f --- /dev/null +++ b/user/include/mlibc/options/rtld/m68k/entry.S @@ -0,0 +1,21 @@ +#include "mlibc-asm/helpers.h" + +PROC_START(_start) + lea (_GLOBAL_OFFSET_TABLE_@GOTPC,%pc), %a0 + lea (_DYNAMIC,%pc), %a1 + + move.l %a1, %a5 + sub.l (%a0), %a5 + + move.l %a5, -(%sp) + move.l %a1, -(%sp) + jbsr relocateSelf68k@PLTPC + addq.l #8, %sp + + move.l %sp, -(%sp) + jbsr interpreterMain@PLTPC + + jmp (%a0) +PROC_END(_start) + +GNU_STACK_NOTE() diff --git a/user/include/mlibc/options/rtld/m68k/runtime.S b/user/include/mlibc/options/rtld/m68k/runtime.S new file mode 100644 index 0000000..eb61631 --- /dev/null +++ b/user/include/mlibc/options/rtld/m68k/runtime.S @@ -0,0 +1,9 @@ +.global pltRelocateStub +# save / restore all registers that can hold function parameters +pltRelocateStub: + # we need to save / restore all registers than can hold function arguments + # we do not need to save callee-saved registers as they will not be trashed by lazyRelocate + # TODO: save floating point argument registers + illegal + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/options/rtld/riscv64/elf.hpp b/user/include/mlibc/options/rtld/riscv64/elf.hpp new file mode 100644 index 0000000..d8d54b1 --- /dev/null +++ b/user/include/mlibc/options/rtld/riscv64/elf.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +#define ELF_CLASS ELFCLASS64 +#define ELF_MACHINE EM_RISCV + +using elf_ehdr = Elf64_Ehdr; +using elf_phdr = Elf64_Phdr; +using elf_dyn = Elf64_Dyn; +using elf_rel = Elf64_Rel; +using elf_rela = Elf64_Rela; +using elf_relr = Elf64_Relr; +using elf_sym = Elf64_Sym; +using elf_addr = Elf64_Addr; + +using elf_info = Elf64_Xword; +using elf_addend = Elf64_Sxword; + +using elf_version = Elf64_Half; +using elf_verdef = Elf64_Verdef; +using elf_verdaux = Elf64_Verdaux; +using elf_verneed = Elf64_Verneed; +using elf_vernaux = Elf64_Vernaux; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE + +#define R_NONE R_RISCV_NONE +#define R_JUMP_SLOT R_RISCV_JUMP_SLOT +#define R_ABSOLUTE R_RISCV_64 +#define R_GLOB_DAT R_RISCV_64 +#define R_RELATIVE R_RISCV_RELATIVE +#define R_IRELATIVE R_RISCV_IRELATIVE +// #define R_OFFSET +#define R_COPY R_RISCV_COPY +#define R_TLS_DTPMOD R_RISCV_TLS_DTPMOD64 +#define R_TLS_DTPREL R_RISCV_TLS_DTPREL64 +#define R_TLS_TPREL R_RISCV_TLS_TPREL64 +#define R_TLSDESC R_RISCV_TLSDESC + +#define TP_TCB_OFFSET 0 + +using ifunc_handler = elf_addr (*)(uint64_t, __riscv_hwprobe_t, void *); diff --git a/user/include/mlibc/options/rtld/riscv64/entry.S b/user/include/mlibc/options/rtld/riscv64/entry.S new file mode 100644 index 0000000..cdb2575 --- /dev/null +++ b/user/include/mlibc/options/rtld/riscv64/entry.S @@ -0,0 +1,13 @@ +#include "mlibc-asm/helpers.h" + +PROC_START(_start) + call relocateSelf + + mv a0, sp + call interpreterMain + + jr a0 +PROC_END(_start) + +GNU_STACK_NOTE() + diff --git a/user/include/mlibc/options/rtld/riscv64/runtime.S b/user/include/mlibc/options/rtld/riscv64/runtime.S new file mode 100644 index 0000000..5128fd3 --- /dev/null +++ b/user/include/mlibc/options/rtld/riscv64/runtime.S @@ -0,0 +1,5 @@ +.global pltRelocateStub +pltRelocateStub: + unimp // TODO +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/options/rtld/x86/elf.hpp b/user/include/mlibc/options/rtld/x86/elf.hpp new file mode 100644 index 0000000..692e5f2 --- /dev/null +++ b/user/include/mlibc/options/rtld/x86/elf.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS32 +#define ELF_MACHINE EM_386 + +using elf_ehdr = Elf32_Ehdr; +using elf_phdr = Elf32_Phdr; +using elf_dyn = Elf32_Dyn; +using elf_rel = Elf32_Rel; +using elf_rela = Elf32_Rela; +using elf_relr = Elf32_Relr; +using elf_sym = Elf32_Sym; +using elf_addr = Elf32_Addr; + +using elf_info = Elf32_Word; +using elf_addend = Elf32_Sword; + +using elf_version = Elf32_Half; +using elf_verdef = Elf32_Verdef; +using elf_verdaux = Elf32_Verdaux; +using elf_verneed = Elf32_Verneed; +using elf_vernaux = Elf32_Vernaux; + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE + +#define R_NONE R_386_NONE +#define R_JUMP_SLOT R_386_JMP_SLOT +#define R_ABSOLUTE R_386_32 +#define R_GLOB_DAT R_386_GLOB_DAT +#define R_RELATIVE R_386_RELATIVE +#define R_IRELATIVE R_386_IRELATIVE +#define R_OFFSET R_386_PC32 +#define R_COPY R_386_COPY +#define R_TLS_DTPMOD R_386_TLS_DTPMOD32 +#define R_TLS_DTPREL R_386_TLS_DTPOFF32 +#define R_TLS_TPREL R_386_TLS_TPOFF +#define R_TLSDESC R_386_TLS_DESC + +#define TP_TCB_OFFSET 0 + +using ifunc_handler = elf_addr (*)(void); diff --git a/user/include/mlibc/options/rtld/x86/entry.S b/user/include/mlibc/options/rtld/x86/entry.S new file mode 100644 index 0000000..df823df --- /dev/null +++ b/user/include/mlibc/options/rtld/x86/entry.S @@ -0,0 +1,13 @@ +#include "mlibc-asm/helpers.h" + +PROC_START(_start) +.cfi_undefined eip + call relocateSelf + + push %esp + call interpreterMain + + jmp *%eax +PROC_END(_start) + +GNU_STACK_NOTE() diff --git a/user/include/mlibc/options/rtld/x86/runtime.S b/user/include/mlibc/options/rtld/x86/runtime.S new file mode 100755 index 0000000..40a175f --- /dev/null +++ b/user/include/mlibc/options/rtld/x86/runtime.S @@ -0,0 +1,9 @@ +.global pltRelocateStub +# save / restore all registers that can hold function parameters +pltRelocateStub: + # we need to save / restore all registers than can hold function arguments + # we do not need to save callee-saved registers as they will not be trashed by lazyRelocate + # TODO: save floating point argument registers + ud2 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/options/rtld/x86_64/elf.hpp b/user/include/mlibc/options/rtld/x86_64/elf.hpp new file mode 100644 index 0000000..66b1019 --- /dev/null +++ b/user/include/mlibc/options/rtld/x86_64/elf.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS64 +#define ELF_MACHINE EM_X86_64 + +using elf_ehdr = Elf64_Ehdr; +using elf_phdr = Elf64_Phdr; +using elf_dyn = Elf64_Dyn; +using elf_rel = Elf64_Rel; +using elf_rela = Elf64_Rela; +using elf_relr = Elf64_Relr; +using elf_sym = Elf64_Sym; +using elf_addr = Elf64_Addr; + +using elf_info = Elf64_Xword; +using elf_addend = Elf64_Sxword; + +using elf_version = Elf64_Half; +using elf_verdef = Elf64_Verdef; +using elf_verdaux = Elf64_Verdaux; +using elf_verneed = Elf64_Verneed; +using elf_vernaux = Elf64_Vernaux; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE + +#define R_NONE R_X86_64_NONE +#define R_JUMP_SLOT R_X86_64_JUMP_SLOT +#define R_ABSOLUTE R_X86_64_64 +#define R_GLOB_DAT R_X86_64_GLOB_DAT +#define R_RELATIVE R_X86_64_RELATIVE +#define R_IRELATIVE R_X86_64_IRELATIVE +// #define R_OFFSET +#define R_COPY R_X86_64_COPY +#define R_TLS_DTPMOD R_X86_64_DTPMOD64 +#define R_TLS_DTPREL R_X86_64_DTPOFF64 +#define R_TLS_TPREL R_X86_64_TPOFF64 +#define R_TLSDESC R_X86_64_TLSDESC + +#define TP_TCB_OFFSET 0 + +using ifunc_handler = elf_addr (*)(void); diff --git a/user/include/mlibc/options/rtld/x86_64/entry.S b/user/include/mlibc/options/rtld/x86_64/entry.S new file mode 100644 index 0000000..c0f59f6 --- /dev/null +++ b/user/include/mlibc/options/rtld/x86_64/entry.S @@ -0,0 +1,14 @@ +#include "mlibc-asm/helpers.h" + +PROC_START(_start) +.cfi_undefined rip + call relocateSelf + + mov %rsp, %rdi + call interpreterMain + + jmp *%rax +PROC_END(_start) + +GNU_STACK_NOTE() + diff --git a/user/include/mlibc/options/rtld/x86_64/runtime.S b/user/include/mlibc/options/rtld/x86_64/runtime.S new file mode 100644 index 0000000..ba9a520 --- /dev/null +++ b/user/include/mlibc/options/rtld/x86_64/runtime.S @@ -0,0 +1,63 @@ +.global __mlibcTlsdescStatic +.hidden __mlibcTlsdescStatic +.type __mlibcTlsdescStatic, @function +__mlibcTlsdescStatic: + mov 8(%rax), %rax + ret + +.global __mlibcTlsdescDynamic +.hidden __mlibcTlsdescDynamic +.type __mlibcTlsdescDynamic, @function +__mlibcTlsdescDynamic: + push %rbx + push %rcx + + mov 8(%rax), %rax + + mov (%rax), %rbx // index + mov 8(%rax), %rcx // addend + + mov %fs:16, %rax // *tp->dtvPointers + mov (%rax, %rbx, 8), %rax // dtvPointers[0][index] + add %rcx, %rax // + addend + sub %fs:0, %rax + + pop %rcx + pop %rbx + ret + +.global pltRelocateStub +pltRelocateStub: + # we need to save / restore all registers than can hold function arguments + # we do not need to save callee-saved registers as they will not be trashed by lazyRelocate + # TODO: save floating point argument registers + + push %rsi + push %rdi + mov 16(%rsp), %rdi + mov 24(%rsp), %rsi + + push %rax + push %rcx + push %rdx + push %r8 + push %r9 + push %r10 + + call lazyRelocate + mov %rax, %r11 + + pop %r10 + pop %r9 + pop %r8 + pop %rdx + pop %rcx + pop %rax + + pop %rdi + pop %rsi + add $16, %rsp + jmp *%r11 + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/scripts/abi-link.sh b/user/include/mlibc/scripts/abi-link.sh new file mode 100755 index 0000000..fdd0a5c --- /dev/null +++ b/user/include/mlibc/scripts/abi-link.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# USAGE: put files and ports in the arrays below and export the abi you want to use + + +declare -a files=() +declare -a ports=() + +for file in "${files[@]}"; do + for port in "${ports[@]}"; do + ln -rsiv abis/$abi/$file sysdeps/$port/include/abi-bits/$file + done +done diff --git a/user/include/mlibc/scripts/check-options-header-include.sh b/user/include/mlibc/scripts/check-options-header-include.sh new file mode 100644 index 0000000..d0c595f --- /dev/null +++ b/user/include/mlibc/scripts/check-options-header-include.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +shopt -s lastpipe + +errors_found=0 + +find . -wholename '*include/*.h' -print0 | while read -rd $'\0' file; do + uses=$(grep -c -E "__MLIBC_(ANSI|BSD|POSIX|LINUX|GLIBC)_OPTION" "$file") + if [ "$uses" -ne 0 ]; then + does_include=$(grep -c "#include " "$file") + if [ "$does_include" -eq 0 ]; then + echo "'$file' does not include mlibc-config.h while it does use mlibc option macros" + errors_found+=1 + fi + fi +done + +exit $errors_found diff --git a/user/include/mlibc/scripts/get-linux-headers.sh b/user/include/mlibc/scripts/get-linux-headers.sh new file mode 100755 index 0000000..8fac384 --- /dev/null +++ b/user/include/mlibc/scripts/get-linux-headers.sh @@ -0,0 +1,18 @@ +#! /bin/sh + +set -ex + +LINUX_MAJOR=v6.x +LINUX_VERSION=6.16 +: "${ARCH:=$(uname -m)}" + +curl -Lo linux-$LINUX_VERSION.tar.xz https://cdn.kernel.org/pub/linux/kernel/$LINUX_MAJOR/linux-$LINUX_VERSION.tar.xz +tar -xf linux-$LINUX_VERSION.tar.xz +rm linux-$LINUX_VERSION.tar.xz +cd linux-$LINUX_VERSION +make mrproper +make ARCH=$ARCH headers_install +find usr/include -type f ! -name '*.h' -delete +mv usr/include ../linux-headers +cd .. +rm -rf linux-$LINUX_VERSION diff --git a/user/include/mlibc/scripts/hdoc.toml.in b/user/include/mlibc/scripts/hdoc.toml.in new file mode 100644 index 0000000..eb51611 --- /dev/null +++ b/user/include/mlibc/scripts/hdoc.toml.in @@ -0,0 +1,15 @@ +[project] +name = "mlibc" +use_system_includes = false +git_repo_url = "https://github.com/managarm/mlibc/" +git_default_branch = "master" + +[ignore] +paths = [ + "options/ansi/musl-generic-math/" +] + +[paths] +input_dir = "@source_root@" +output_dir = "@build_root@/docs/" +compile_commands = "@build_root@/compile_commands.json" diff --git a/user/include/mlibc/scripts/header-abi-compare-config.yml b/user/include/mlibc/scripts/header-abi-compare-config.yml new file mode 100644 index 0000000..fe19d9f --- /dev/null +++ b/user/include/mlibc/scripts/header-abi-compare-config.yml @@ -0,0 +1,303 @@ +# additional includes to supply via `-I` arguments +includes: [] + +# paths relative to includedir whose files we don't want to parse themselves, +# but whose content we want to analyze if they're included from another header. +base_skipped_directories: + - bits +# paths relative to includedir that we want to completely ignore, even for transitive includes +base_ignored_directories: + - finclude + - gnu + +# same as the two above, but for files +base_skipped_files: [] +base_ignored_files: [] + +# record mapping from base (glibc) to mlibc +map_record_to_struct: + - "__SOCKADDR_ARG": "struct sockaddr *restrict" + - "__CONST_SOCKADDR_ARG": "const struct sockaddr *" + +# struct equivalence mapping from base (glibc) to mlibc +equivalent_structs: + - "struct _IO_FILE": "struct __mlibc_file_base" + - "__mbstate_t": "struct __mlibc_mbstate" + - "cnd_t": "struct __mlibc_cond" + - "mtx_t": "struct __mlibc_mutex" + - "struct __locale_struct": "void" + - "pthread_mutexattr_t": "struct __mlibc_mutexattr" + - "pthread_mutex_t": "struct __mlibc_mutex" + - "pthread_condattr_t": "struct __mlibc_condattr" + - "pthread_barrierattr_t": "struct __mlibc_barrierattr" + - "pthread_rwlockattr_t": "struct __mlibc_rwlockattr" + - "pthread_rwlock_t": "struct __mlibc_fair_rwlock" + - "union pthread_attr_t": "struct __mlibc_threadattr" + - "pthread_barrier_t": "struct __mlibc_barrier" + - "pthread_cond_t": "struct __mlibc_cond" + - "__sigset_t": "sigset_t" + - "struct ucontext_t": "struct __ucontext" + - "struct __dirstream": "struct __mlibc_dir_struct" + - "sem_t": "struct sem_" + - "struct stat64": "struct stat" + - "struct msqid64_ds": "struct msqid_ds" + - "struct msqid_ds": "struct msqid64_ds" + - "struct rlimit64": "struct rlimit" + - "glob_t": "struct glob_t" + - "stack_t": "struct __stack" + - "__useconds_t": "useconds_t" + +# files to ignore, relative to includedir +ignored_files: + - math.h + - tgmath.h + - regexp.h + - sys/asm.h + - sys/elf.h + - sys/vm86.h + +ignored_structs: + # structs to ignore because we expose the kernel layout + - fd_set + - semid_ds + + # libc-level constructs that are allowed to differ, and probably do + - ifaddrs + - lastlog + - regmatch_t + - sem_t + - sigevent + - utmp + - utmpx + +ignored_typedefs: + # opaque structs where users can't rely on any particular layout + - cnd_t + - fpos_t + - jmp_buf + - mtx_t + - pthread_attr_t + - pthread_barrier_t + - pthread_cond_t + - pthread_condattr_t + - pthread_mutex_t + - pthread_mutexattr_t + - pthread_rwlock_t + - pthread_rwlockattr_t + - sigjmp_buf + - wordexp_t + + # glibc skill issue: regoff_t should be at least ptrdiff_t or ssize_t-sized, but glibc uses int + - regmatch_t + +# macros we ignore for being libc-level constructs or being allowed to diverge +ignored_macros: + - AT_XPIPE + - AT_OPENFILES + - AT_FS_SERVER + - AT_MBUS_SERVER + - _Complex_I + - FTW_F + - FTW_D + - FTW_DNR + - FTW_DP + - FTW_NS + - FTW_SL + - FTW_SLN + - FTW_PHYS + - FTW_MOUNT + - FTW_DEPTH + - FTW_CHDIR + - FTW_CONTINUE + - WRDE_APPEND + - WRDE_DOOFFS + - WRDE_NOCMD + - WRDE_REUSE + - WRDE_SHOWERR + - WRDE_UNDEF + - WRDE_SUCCESS + - WRDE_BADCHAR + - WRDE_BADVAL + - WRDE_CMDSUB + - WRDE_NOSPACE + - WRDE_SYNTAX + - PF_MAX + - SOMAXCONN + - IPPROTO_MAX + - FOPEN_MAX + - FILENAME_MAX + - TMP_MAX + - LINE_MAX + - CHARCLASS_NAME_MAX + - RE_DUP_MAX + - SIGRTMIN + - L_ctermid + - L_tmpnam + - _IOFBF + - _IOLBF + - _IONBF + - _PATH_DEFPATH + - _PATH_STDPATH + - _PATH_VARDB + - _POSIX_OPEN_MAX + - PTHREAD_DESTRUCTOR_ITERATIONS + - PTHREAD_STACK_MIN + - MINSIGSTKSZ + - SIGSTKSZ + - _PC_FILESIZEBITS + - _PC_SYMLINK_MAX + - NL_ARGMAX + - MB_LEN_MAX + - ABDAY_1 + - ABDAY_2 + - ABDAY_3 + - ABDAY_4 + - ABDAY_5 + - ABDAY_6 + - ABDAY_7 + - DAY_1 + - DAY_2 + - DAY_3 + - DAY_4 + - DAY_5 + - DAY_6 + - DAY_7 + - ABMON_1 + - ABMON_2 + - ABMON_3 + - ABMON_4 + - ABMON_5 + - ABMON_6 + - ABMON_7 + - ABMON_8 + - ABMON_9 + - ABMON_10 + - ABMON_11 + - ABMON_12 + - MON_1 + - MON_2 + - MON_3 + - MON_4 + - MON_5 + - MON_6 + - MON_7 + - MON_8 + - MON_9 + - MON_10 + - MON_11 + - MON_12 + - AM_STR + - PM_STR + - D_T_FMT + - D_FMT + - T_FMT + - T_FMT_AMPM + - ERA + - ERA_D_FMT + - ALT_DIGITS + - ERA_D_T_FMT + - ERA_T_FMT + - CODESET + - CRNCYSTR + - RADIXCHAR + - DECIMAL_POINT + - THOUSEP + - THOUSANDS_SEP + - YESEXPR + - NOEXPR + - LC_ALL + - LC_COLLATE + - LC_CTYPE + - LC_MONETARY + - LC_NUMERIC + - LC_TIME + - LC_MESSAGES + - LC_MEASUREMENT + - LC_GLOBAL_LOCALE + - LC_CTYPE_MASK + - LC_NUMERIC_MASK + - LC_TIME_MASK + - LC_COLLATE_MASK + - LC_MONETARY_MASK + - LC_MESSAGES_MASK + - LC_MEASUREMENT_MASK + - LC_ALL_MASK + - AI_PASSIVE + - AI_CANONNAME + - AI_NUMERICHOST + - AI_V4MAPPED + - AI_ALL + - AI_ADDRCONFIG + - AI_NUMERICSERV + - NI_NOFQDN + - NI_NUMERICHOST + - NI_NAMEREQD + - NI_NUMERICSCOPE + - NI_DGRAM + - NI_NUMERICSERV + - NI_MAXSERV + - NI_IDN + - NI_IDN_USE_STD3_ASCII_RULES + - NI_MAXHOST + - EAI_AGAIN + - EAI_BADFLAGS + - EAI_FAIL + - EAI_FAMILY + - EAI_MEMORY + - EAI_NONAME + - EAI_SERVICE + - EAI_SOCKTYPE + - EAI_SYSTEM + - EAI_OVERFLOW + - EAI_NODATA + - EAI_ADDRFAMILY + - GLOB_APPEND + - GLOB_DOOFFS + - GLOB_ERR + - GLOB_MARK + - GLOB_NOCHECK + - GLOB_NOESCAPE + - GLOB_NOSORT + - GLOB_PERIOD + - GLOB_TILDE + - GLOB_TILDE_CHECK + - GLOB_BRACE + - GLOB_NOMAGIC + - GLOB_ALTDIRFUNC + - GLOB_ONLYDIR + - GLOB_MAGCHAR + - GLOB_ABORTED + - GLOB_NOMATCH + - GLOB_NOSPACE + - GLOB_NOSYS + - BUFSIZ + - F_LOCK + - F_TEST + - F_TLOCK + - F_ULOCK + - O_LARGEFILE + - FSETLOCKING_INTERNAL + - FSETLOCKING_BYCALLER + - FSETLOCKING_QUERY + - NSS_BUFLEN_PASSWD + +# enum members whose value should not be dependended on +ignored_enum_constants: + - thrd_timedout + - thrd_busy + - thrd_error + - thrd_nomem + +# structs that would get ignored by default (with leading double underscores) that we +# don't actually want to get ignored +forced_structs: + - "__mlibc_thread_data" + - "__mlibc_threadattr" + - "__mlibc_mutex" + - "__mlibc_mutexattr" + - "__mlibc_cond" + - "__mlibc_condattr" + - "__ucontext" + +forced_typedefs: + - "__ucontext" diff --git a/user/include/mlibc/scripts/header-abi-compare.py b/user/include/mlibc/scripts/header-abi-compare.py new file mode 100755 index 0000000..ae77c06 --- /dev/null +++ b/user/include/mlibc/scripts/header-abi-compare.py @@ -0,0 +1,934 @@ +#!/usr/bin/env python3 + +import argparse +import os +import pathlib +import re +import subprocess +import sys +import tempfile +import typing +from dataclasses import dataclass, field + +import clang.cindex +import colorama +import yaml +from clang.cindex import CursorKind, TokenKind, TypeKind + +dry_run = True +errors_emitted = 0 + + +def on_ci() -> bool: + return "CI" in os.environ + + +def log_err(prefix, msg): + global errors_emitted + + if on_ci(): + print(f"{prefix}: {msg}", file=sys.stderr) + else: + print( + f"{colorama.Fore.RED}{prefix}{colorama.Style.RESET_ALL}: {msg}", + file=sys.stderr, + ) + errors_emitted += 1 + + +def no_system_includes(cursor, level): + """filter out verbose stuff from system include files""" + return (level != 1) or ( + cursor.location.file is not None + and not cursor.location.file.name.startswith("/usr/include") + ) + + +class Type: + def __init__(self, t: clang.cindex.Type): + self.t = t + self.kind = t.kind + self.typename = ( + str(self.t.spelling).removesuffix("restrict").removeprefix("const ") + ) + self.compat_typename = None + + match t.kind: + case TypeKind.ELABORATED: + replacement = next( + filter( + lambda x: self.typename in x.keys(), + config["map_record_to_struct"], + ), + None, + ) + if replacement is not None: + self.compat_typename = ( + replacement[self.typename] + .removesuffix("restrict") + .removeprefix("const ") + ) + case TypeKind.RECORD: + replacement = next( + filter( + lambda x: self.typename in x.keys(), + config["map_record_to_struct"], + ), + None, + ) + if replacement is not None: + self.kind = TypeKind.POINTER + self.compat_typename = ( + replacement[self.typename] + .removesuffix("restrict") + .removeprefix("const ") + ) + case TypeKind.POINTER: + ptr_type = ( + self.t.get_pointee() + .spelling.removesuffix("restrict") + .removeprefix("const ") + ) + replacement = next( + filter( + lambda x: ptr_type in x.keys(), config["equivalent_structs"] + ), + None, + ) + if replacement is not None: + self.compat_typename = ( + replacement[ptr_type] + .removesuffix("restrict") + .removeprefix("const ") + + " *" + ) + + @property + def canonical(self): + return Type(self.t.get_canonical()) + + @property + def pointee_type(self): + if self.kind == TypeKind.POINTER: + return Type(self.t.get_pointee()) + if ( + self.kind == TypeKind.INCOMPLETEARRAY + or self.kind == TypeKind.CONSTANTARRAY + or self.kind == TypeKind.VARIABLEARRAY + ): + return Type(self.t.get_array_element_type()) + if self.kind == TypeKind.ELABORATED: + return None + log_err( + "unhandled pointee resolution", str(self.kind).removeprefix("TypeKind.") + ) + return None + + def __str__(self): + return self.typename + + def __eq__(self, other): + if self.kind != other.kind: + if ( + self.kind == TypeKind.INCOMPLETEARRAY + or other.kind == TypeKind.INCOMPLETEARRAY + ): + if self.pointee_type is None or other.pointee_type is None: + return False + return self.pointee_type == other.pointee_type + elif ( + self.kind == TypeKind.CONSTANTARRAY + or other.kind == TypeKind.CONSTANTARRAY + ): + if self.pointee_type is None or other.pointee_type is None: + return False + return self.pointee_type == other.pointee_type + elif ( + self.kind == TypeKind.VARIABLEARRAY + or other.kind == TypeKind.VARIABLEARRAY + ): + if self.pointee_type is None or other.pointee_type is None: + return False + return self.pointee_type == other.pointee_type + elif self.kind == TypeKind.ELABORATED or other.kind == TypeKind.ELABORATED: + return ( + self.t.get_size() == other.t.get_size() + and self.t.get_align() == other.t.get_align() + ) + else: + return False + + if str(self) == str(other): + return True + return ( + self.compat_typename == str(other) + or self.compat_typename == other.compat_typename + ) + + def is_valid(self): + return self.t.kind != TypeKind.INVALID + + +@dataclass +class Function: + name: str + linkage: clang.cindex.LinkageKind + ret_type: clang.cindex.Type + location: clang.cindex.SourceLocation + arguments: typing.List[Type] + + def __init__(self, c: clang.cindex.Cursor): + self.c = c + self.name = c.mangled_name + self.linkage = c.linkage + self.ret_type = c.result_type + self.location = c.location + self.arguments = list() + + for arg in c.get_arguments(): + self.arguments.append(Type(arg.type)) + + +@dataclass +class MacroDefinition: + name: str + location: clang.cindex.SourceLocation + + def __init__(self, c: clang.cindex.Cursor): + self.c = c + self.name = c.spelling + self.location = c.location + self.tokens = list(self.c.get_tokens()) + + @property + def first_token(self): + return self.tokens[1] if len(self.tokens) > 1 else None + + +@dataclass +class EnumDecl: + name: str + location: clang.cindex.SourceLocation + + def __init__(self, c: clang.cindex.Cursor): + self.c = c + self.name = c.spelling + self.location = c.location + + +@dataclass +class StructDecl: + name: str + location: clang.cindex.SourceLocation + + def __init__(self, c: clang.cindex.Cursor): + self.c = c + self.name = c.spelling + self.location = c.location + self.alignment = c.type.get_align() + self.size = c.type.get_size() + + +@dataclass +class Typedef: + name: str + location: clang.cindex.SourceLocation + + def __init__(self, c: clang.cindex.Cursor): + self.c = c + self.name = c.spelling + self.location = c.location + self.alignment = c.type.get_align() + self.size = c.type.get_size() + +@dataclass +class State: + """ + Represents the parsed state of a set of headers. + """ + + path: pathlib.Path + functions: typing.Dict[str, Function] = field(default_factory=dict) + macros: typing.Dict[str, MacroDefinition] = field(default_factory=dict) + enums: typing.Dict[str, EnumDecl] = field(default_factory=dict) + structs: typing.Dict[str, StructDecl] = field(default_factory=dict) + typedefs: typing.Dict[str, StructDecl] = field(default_factory=dict) + + def __init__(self, path: pathlib.Path): + self.path = path + self.functions = dict() + self.macros = dict() + self.enums = dict() + self.structs = dict() + self.typedefs = dict() + + +@dataclass +class Comparison: + config: dict + + def is_ignored(self, typename, ignorelist, name): + if ( + typename == "macros" + and (name.startswith("_") or name.startswith("MLIBC_")) + and name.endswith("_H") + ): + return True + if name in ignorelist: + return True + if "forced_" + typename in config and name in config["forced_" + typename]: + return False + if name.startswith("__"): + return True + if "ignored_" + typename in config and name in config["ignored_" + typename]: + return True + return False + + @staticmethod + def is_skipped_file(base_dir: pathlib.Path, file: pathlib.Path, config): + if Comparison.is_ignored_file(base_dir, file, config): + return True + + if base_dir == args.reference: + for p in config["base_skipped_directories"]: + if str(file).startswith(os.path.join(base_dir, p)): + return True + for p in config["base_skipped_files"]: + stripped_file = str(file).removeprefix(str(base_dir)).removeprefix("/") + if stripped_file == p: + return True + return False + + @staticmethod + def is_ignored_file(base_dir: pathlib.Path, file: pathlib.Path, config): + if not str(file).startswith(str(base_dir)): + return True + + if base_dir == args.reference: + for p in config["base_ignored_directories"]: + if str(file).startswith(os.path.join(base_dir, p)): + return True + for p in config["base_ignored_files"]: + stripped_file = str(file).removeprefix(str(base_dir)).removeprefix("/") + if stripped_file == p: + return True + for p in config["ignored_files"]: + stripped_file = str(file).removeprefix(str(base_dir)).removeprefix("/") + if stripped_file == p: + return True + for p in config["includes"]: + if str(base_dir).startswith(p): + return True + return False + + def from_cursor(self, base_dir, header, cursor, filter_pred, state: State, level=0): + if cursor.location.file: + f = pathlib.Path(str(cursor.location.file)) + + if Comparison.is_ignored_file(base_dir, f, config): + return + + if filter_pred(cursor, level): + if args.dump_tree: + print(f"{"-" * level} {cursor.kind} {cursor.spelling}") + for c in cursor.get_children(): + self.from_cursor(base_dir, header, c, filter_pred, state, level + 1) + + match cursor.kind: + case CursorKind.TRANSLATION_UNIT: + for c in cursor.get_children(): + self.from_cursor( + base_dir, header, c, filter_pred, state, level + 1 + ) + case CursorKind.INCLUSION_DIRECTIVE: + pass + case CursorKind.FUNCTION_DECL: + if not cursor.mangled_name.startswith("__"): + f = Function(cursor) + state.functions.update({f.name: f}) + case CursorKind.STATIC_ASSERT | CursorKind.UNEXPOSED_DECL: + pass + case CursorKind.ENUM_DECL: + if not self.is_ignored("enums", [], cursor.spelling): + for x in cursor.get_children(): + state.enums.update({x.spelling: EnumDecl(x)}) + case CursorKind.MACRO_DEFINITION: + if not self.is_ignored("macros", [], cursor.spelling): + state.macros.update({cursor.spelling: MacroDefinition(cursor)}) + case CursorKind.STRUCT_DECL: + if not self.is_ignored("structs", [], cursor.spelling): + if cursor.is_definition(): + state.structs.update({cursor.spelling: StructDecl(cursor)}) + case CursorKind.UNION_DECL: + if not self.is_ignored("unions", [], cursor.spelling): + if cursor.is_definition(): + state.structs.update({cursor.spelling: StructDecl(cursor)}) + case CursorKind.TYPEDEF_DECL: + if not self.is_ignored("typedefs", [], cursor.spelling): + children = list(cursor.get_children()) + if not children: + return + + state.typedefs.update({cursor.spelling: Typedef(cursor)}) + + if children[0].kind == CursorKind.TYPE_REF: + child_struct_name = children[0].spelling.removeprefix( + "struct " + ) + + if child_struct_name in state.structs: + state.structs.update( + {cursor.spelling: state.structs[child_struct_name]} + ) + case CursorKind.MACRO_INSTANTIATION | CursorKind.VAR_DECL: + # don't care (for now) + pass + case _: + log_err( + "unhandled cursor type", + f"{cursor.kind} {cursor.spelling} {cursor.displayname} {cursor.location}", + ) + + +def cc_name(): + if args.clang_version: + return [f"clang-{args.clang_version}", f"--target={f"{args.arch}-linux-gnu"}"] + return ["clang", f"--target={f"{args.arch}-linux-gnu"}"] + + +def cxx_name(): + # m68k on clang defaults to a small codemodel that doesn't work + # and I have not found a way to change it outside of `llc` other + if args.arch == "m68k": + return ["m68k-linux-gnu-g++"] + if args.clang_version: + return [f"clang++-{args.clang_version}", f"--target={f"{args.arch}-linux-gnu"}"] + return ["clang++", f"--target={f"{args.arch}-linux-gnu"}"] + + +def parse( + file: pathlib.Path, resource_dir: pathlib.Path, base_dir: pathlib.Path, state: State +): + index = clang.cindex.Index.create() + tu = None + + clang_args = [f"-I{resource_dir}"] + clang_args += [f"-I{p}" for p in config["includes"]] + clang_args += [f"-I{base_dir}"] + clang_args += [f"-I{base_dir / f"{args.arch}-linux-gnu"}"] + clang_args += [f"--target={f"{args.arch}-linux-gnu"}"] + clang_args += ["-D_GNU_SOURCE", "-D_FILE_OFFSET_BITS=64", "-Wno-macro-redefined"] + + try: + tu = index.parse( + base_dir / file, + args=clang_args, + options=clang.cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD + | clang.cindex.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES, + ) + except Exception as e: + log_err("parsing error", f"{file}: {e}") + return + + assert tu + + if not Comparison.is_skipped_file(base_dir, base_dir / file, config): + if tu.diagnostics: + [log_err("compile error", d) for d in tu.diagnostics] + print(f"\n{errors_emitted} errors emitted") + exit(errors_emitted) + + parser = Comparison(config) + if args.verbose: + print(f"// {tu.spelling.strip()}") + parser.from_cursor(base_dir, file, tu.cursor, no_system_includes, state) + + +def compare_states(a, b): + global errors_emitted + + a_symbols = sorted(a.functions.keys()) + b_symbols = sorted(b.functions.keys()) + symbols = a_symbols + symbols.extend(x for x in b_symbols if x not in symbols) + c = Comparison(config) + + if args.function_signatures: + lines = [] + + for s in symbols: + if s not in a.functions or s not in b.functions: + continue + + a_func = a.functions[s] + b_func = b.functions[s] + + a_ret_type = Type(a_func.ret_type.get_canonical()) + b_ret_type = Type(b_func.ret_type.get_canonical()) + + if ( + a_ret_type != b_ret_type + and a_func.ret_type.spelling != b_func.ret_type.spelling + ): + lines.append( + f"\t{s}: mismatched return type ({a_ret_type} vs. {b_ret_type})" + ) + errors_emitted += 1 + + a_args = a_func.arguments + b_args = b_func.arguments + + if len(a_args) != len(b_args): + lines.append( + f"\t{s}: argument count mismatch ({len(a_args)} vs. {len(b_args)})" + ) + errors_emitted += 1 + + for i, at in enumerate(a_args): + bt = b_args[i] + if at != bt and at.canonical != bt.canonical: + lines.append( + f"\t{s}: mismatched type for argument at position {(i + 1)} ({at} ({str(at.kind).removeprefix("TypeKind.")}) vs. {bt} ({str(bt.kind).removeprefix("TypeKind.")}))" + ) + errors_emitted += 1 + + if lines: + print() + print(f"checking {len(symbols)} functions for signature mismatches:") + for line in lines: + print(line) + + if args.missing_functions: + a_unique_symbols = list(filter(lambda e: e not in b_symbols, a_symbols)) + b_unique_symbols = list(filter(lambda e: e not in a_symbols, b_symbols)) + + if args.verbose and len(a_unique_symbols) > 0: + print() + print(f"{len(a_unique_symbols)} symbols only defined in {a.path}:") + for s in sorted(a_unique_symbols): + print(f"{s} defined in {a.functions[s].location}") + + if len(b_unique_symbols) > 0: + print() + print(f"{len(b_unique_symbols)} symbols only defined in {b.path}:") + for s in sorted(b_unique_symbols): + print(f"{s} defined in {b.functions[s].location}") + + def loc(s): + return f"{s.location.file}:{s.location.line}" + + if args.structs: + + for mapping in config["equivalent_structs"]: + (a_name, b_name), = mapping.items() + a_name = a_name.removeprefix("struct ") + b_name = b_name.removeprefix("struct ") + if a_name not in a.structs or b_name not in b.structs: + continue + if c.is_ignored("structs", [], a_name) or c.is_ignored("structs", [], b_name): + continue + if (a_name in a.typedefs and c.is_ignored("typedefs", [], a_name)) or (c.is_ignored("typedefs", [], b_name)): + continue + b.structs[a_name] = b.structs[b_name] + + common_structs = sorted(set(a.structs) & set(b.structs)) + lines = [] + + for name in common_structs: + if c.is_ignored("typedefs", [], name): + continue; + + sa = a.structs[name] + sb = b.structs[name] + + if sa.alignment != sb.alignment: + lines.append( + f"\t{name}: alignment {sa.alignment} vs. {sb.alignment} ({loc(sa)}, {loc(sb)})" + ) + errors_emitted += 1 + + if sa.size != sb.size: + lines.append( + f"\t{name}: size {sa.size} vs. {sb.size} ({loc(sa)}, {loc(sb)})" + ) + errors_emitted += 1 + + if lines: + print() + print( + f"checking {len(common_structs)} structs for size/alignment mismatches:" + ) + for line in lines: + print(line) + + if args.typedefs: + common_typedefs = sorted(set(a.typedefs) & set(b.typedefs)) + lines = [] + + for name in common_typedefs: + if (name in a.structs or name in b.structs) and c.is_ignored("structs", [], name): + continue; + + ta = a.typedefs[name] + tb = b.typedefs[name] + + if ta.alignment != tb.alignment and ta.alignment > 0 and tb.alignment > 0: + lines.append( + f"\t{name}: alignment {ta.alignment} vs. {tb.alignment} ({loc(ta)}, {loc(tb)})" + ) + errors_emitted += 1 + + if ta.size != tb.size and ta.size > 0 and tb.size > 0: + lines.append( + f"\t{name}: size {ta.size} vs. {tb.size} ({loc(ta)}, {loc(tb)})" + ) + errors_emitted += 1 + + if lines: + print() + print( + f"checking {len(common_typedefs)} typedefs for size/alignment mismatches:" + ) + for line in lines: + print(line) + + if args.macro_definitions: + tempdir = tempfile.TemporaryDirectory(prefix="abichecker") + td = pathlib.Path(tempdir.name) + script_path = pathlib.Path(__file__).resolve().parent + + atp = open(td / "test-a-primary.hpp", "w") + btp = open(td / "test-b-primary.hpp", "w") + + print(f'#include "{script_path}/linux-headers.h"', file=atp) + print(f'#include "{script_path}/linux-headers.h"', file=btp) + + def filter_preprocessed_file(input, output): + include_next_line = False + + with open(output, "w") as o: + with open(input, "r") as i: + for line in i: + if line.startswith("const auto __v_"): + o.write(line) + include_next_line = not line.strip().endswith(";") + elif include_next_line: + if not line.strip().startswith("#"): + o.write(line) + include_next_line = not line.strip().endswith(";") + + a_included_files = list() + b_included_files = list() + tested_macros = list() + + def is_macro_literal(obj): + if type(obj) is not MacroDefinition: + return False + return obj.first_token and obj.first_token.kind == TokenKind.LITERAL + + def is_enum(obj): + return type(obj) is EnumDecl + + for name, bm in (b.macros | b.enums).items(): + if name in (a.macros | a.enums): + am = (a.macros | a.enums)[name] + header = ( + str(am.location.file) + .removeprefix(str(args.reference)) + .removeprefix("/") + ) + if header not in a_included_files and not c.is_skipped_file( + args.reference, args.reference / header, config + ): + print(f"#include <{header}>", file=atp) + a_included_files.append(header) + header = ( + str(bm.location.file).removeprefix(str(args.mlibc)).removeprefix("/") + ) + if header not in b_included_files: + print(f"#include <{header}>", file=btp) + b_included_files.append(header) + if name in (a.macros | a.enums) and ( + is_macro_literal(bm) + or (is_enum(bm) and not c.is_ignored("enum_constants", [], name)) + ): + print(f"const auto __v_{name} = {name};", file=atp) + print(f"const auto __v_{name} = {name};", file=btp) + tested_macros.append(name) + + atp.close() + btp.close() + + a_preprocess = subprocess.run( + cxx_name() + + [ + "-E", + "-std=c++23", + "-nostdlib", + f"-I{args.reference}", + "-o", + f"{tempdir.name}/test-a-preprocessed.hpp", + f"{tempdir.name}/test-a-primary.hpp", + "-D_GNU_SOURCE", + "-D_FILE_OFFSET_BITS=64", + "-D_REGEX_LARGE_OFFSETS" + "-Wno-macro-redefined", + ], + capture_output=True, + ) + if a_preprocess.returncode != 0: + print(f"Preprocessing the macro list of {args.reference} failed:") + print(f"\tCommand: '{' '.join(a_preprocess.args)}'") + print(a_preprocess.stderr.decode("utf-8")) + b_preprocess = subprocess.run( + cxx_name() + + [ + "-E", + "-std=c++23", + "-nostdlib", + f"-I{args.mlibc}", + "-o", + f"{tempdir.name}/test-b-preprocessed.hpp", + f"{tempdir.name}/test-b-primary.hpp", + "-D_GNU_SOURCE", + "-D_FILE_OFFSET_BITS=64", + "-D_REGEX_LARGE_OFFSETS" + "-Wno-macro-redefined", + ], + capture_output=True, + ) + if b_preprocess.returncode != 0: + print(f"Preprocessing the macro list of {args.mlibc} failed:") + print(b_preprocess.stderr.decode("utf-8")) + + filter_preprocessed_file( + td / "test-a-preprocessed.hpp", td / "test-a-filtered.hpp" + ) + filter_preprocessed_file( + td / "test-b-preprocessed.hpp", td / "test-b-filtered.hpp" + ) + + at = open(td / "test-a.cpp", "w") + bt = open(td / "test-b.cpp", "w") + + print(f'#include "{script_path}/linux-headers.h"', file=at) + print(f'#include "{script_path}/linux-headers.h"', file=bt) + + for inc in a_included_files: + print(f"#include <{inc}>", file=at) + for inc in b_included_files: + print(f"#include <{inc}>", file=bt) + print("", file=at) + print("", file=bt) + + print(f'#include "{tempdir.name}/test-a-filtered.hpp"', file=at) + print(f'#include "{tempdir.name}/test-b-filtered.hpp"', file=bt) + print(f'#include "{script_path}/to_integral.hpp"', file=at) + print(f'#include "{script_path}/to_integral.hpp"', file=bt) + + print("int main() {", file=at) + print("int main() {", file=bt) + + for name in tested_macros: + print(f'\tmacro_print("{name}", __v_{name});', file=at) + print(f'\tmacro_print("{name}", __v_{name});', file=bt) + + print("\treturn 0;", file=at) + print("\treturn 0;", file=bt) + print("}", file=at) + print("}", file=bt) + + at.close() + bt.close() + + a_compile = subprocess.run( + cxx_name() + + [ + "-std=c++23", + "-I", + f"{args.reference}", + "-o", + f"{tempdir.name}/test-a", + f"{tempdir.name}/test-a.cpp", + "-D_GNU_SOURCE", + "-D_FILE_OFFSET_BITS=64", + "-D_REGEX_LARGE_OFFSETS" + "-Wno-macro-redefined", + ], + capture_output=True, + ) + if a_compile.returncode != 0: + log_err("Compiling macro test failed", f"test.cpp for {args.reference}") + print(a_compile.stderr.decode("utf-8")) + sys.exit(1) + + b_compile = subprocess.run( + cxx_name() + + [ + "-std=c++23", + "-I", + f"{args.mlibc}", + "-o", + f"{tempdir.name}/test-b", + f"{tempdir.name}/test-b.cpp", + "-D_GNU_SOURCE", + "-D_FILE_OFFSET_BITS=64", + "-D_REGEX_LARGE_OFFSETS" + "-Wno-macro-redefined", + ], + capture_output=True, + ) + if b_compile.returncode != 0: + log_err("Compiling macro test failed", f"test.cpp for {args.mlibc}") + print(b_compile.stderr.decode("utf-8")) + sys.exit(1) + + test_a_file = tempfile.NamedTemporaryFile(dir=tempdir.name) + test_b_file = tempfile.NamedTemporaryFile(dir=tempdir.name) + qemu_cmd = [] + + if args.arch != "x86_64": + qemu_cmd = [f"qemu-{args.arch}"] + if args.ld_lib: + qemu_cmd += ["-L", args.ld_lib] + + test_a = subprocess.run( + qemu_cmd + [f"{tempdir.name}/test-a"], stdout=test_a_file + ) + if test_a.returncode != 0: + log_err("Running macro test failed", f"test for {args.reference}") + test_b = subprocess.run( + qemu_cmd + [f"{tempdir.name}/test-b"], stdout=test_b_file + ) + if test_b.returncode != 0: + log_err("Running macro test failed", f"test for {args.mlibc}") + + color_output = ["--color=always"] if not on_ci() else [] + + diff = subprocess.run( + ["diff", test_a_file.name, test_b_file.name] + color_output, + capture_output=True, + text=True, + ) + diff_str = diff.stdout.strip() + if diff_str: + print() + print("diff of macro definitions:") + print(diff_str) + ansi_escape = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]") + errors_emitted += sum( + 1 + for line in diff_str.splitlines() + if ansi_escape.sub("", line).startswith("< ") + ) + + +if __name__ == "__main__": + argparser = argparse.ArgumentParser() + argparser.add_argument( + "-m", + dest="missing_functions", + action="store_true", + help="search for missing functions", + ) + argparser.add_argument( + "-M", + dest="macro_definitions", + action="store_true", + help="compare macro definitions", + ) + argparser.add_argument( + "-f", + dest="function_signatures", + action="store_true", + help="check function signatures", + ) + argparser.add_argument( + "-s", dest="structs", action="store_true", help="check structs" + ) + argparser.add_argument( + "-t", dest="typedefs", action="store_true", help="check structs" + ) + argparser.add_argument( + "-v", "--verbose", dest="verbose", action="store_true", help="verbose output" + ) + argparser.add_argument( + "-T", + dest="dump_tree", + action="store_true", + help="dump tree (for debug, extremely verbose)", + ) + argparser.add_argument( + "--config", + help="path to the configuration file", + dest="config", + type=argparse.FileType("r"), + required=True, + ) + argparser.add_argument( + "--arch", help="target architecture", dest="arch", type=str, default="x86_64" + ) + argparser.add_argument( + "--ld-library-path", + help="additional LD_LIBRARY_PATH to supply to qemu-user", + dest="ld_lib", + type=str, + ) + argparser.add_argument( + "--clang-version", + help="specify which versioned clang to use", + dest="clang_version", + type=int, + ) + argparser.add_argument( + "--exit-with-zero-for-abi-mismatches", + help="exit with zero even if ABI mismatches are detected", + dest="exit_zero", + action="store_true", + ) + argparser.add_argument( + "reference", help="path to the references libc's sysroot", type=pathlib.Path + ) + argparser.add_argument( + "mlibc", help="mlibc headers to be checked", type=pathlib.Path + ) + argparser.add_argument("file", nargs="?", help="limit scope to this file") + + colorama.just_fix_windows_console() + + args = argparser.parse_args() + + config = yaml.load(args.config, yaml.CSafeLoader) + reference_state = State(args.reference) + mlibc_state = State(args.mlibc) + + # determine the path to clang's resource dir (like /usr/lib/clang/20/include) + resource_dir_result = subprocess.run( + cc_name() + ["-print-resource-dir"], capture_output=True + ) + resource_dir = pathlib.Path(resource_dir_result.stdout.decode().strip()) / "include" + + for pair in ((args.reference, reference_state), (args.mlibc, mlibc_state)): + (path, state) = pair + if not args.file: + for header in sorted(path.rglob("*.h")): + parse( + pathlib.Path(str(header).removeprefix(str(path)).removeprefix("/")), + resource_dir, + path, + state, + ) + else: + parse(pathlib.Path(args.file), resource_dir, path, state) + + compare_states(reference_state, mlibc_state) + + if errors_emitted > 0: + print(f"\n{errors_emitted} errors emitted.") + else: + print("No ABI differences found.") + + if args.exit_zero: + exit(0) + + exit(min(errors_emitted, 0xFF)) diff --git a/user/include/mlibc/scripts/hide-everything.ld b/user/include/mlibc/scripts/hide-everything.ld new file mode 100644 index 0000000..fac4f05 --- /dev/null +++ b/user/include/mlibc/scripts/hide-everything.ld @@ -0,0 +1,4 @@ +{ + /* Hide all C++ symbols. */ + local: _Z*; +}; diff --git a/user/include/mlibc/scripts/linux-headers.h b/user/include/mlibc/scripts/linux-headers.h new file mode 100644 index 0000000..27e320d --- /dev/null +++ b/user/include/mlibc/scripts/linux-headers.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/user/include/mlibc/scripts/rust-libc-config.yml b/user/include/mlibc/scripts/rust-libc-config.yml new file mode 100644 index 0000000..fec4bc5 --- /dev/null +++ b/user/include/mlibc/scripts/rust-libc-config.yml @@ -0,0 +1,2216 @@ +includes: [] + +ignored_files: + - "abi-bits/limits.h" + - "abi-bits/vt.h" + - "abi-bits/wait.h" + - "abi-bits/xattr.h" + - "arpa/nameser.h" + - "bits/ensure.h" + - "bits/glibc/glibc_assert.h" + - "bits/glibc/glibc_search.h" + - "bits/glibc/glibc_signal.h" + - "bits/null.h" + - "bits/search.h" + - "bits/syscall.h" + - "net/ethernet.h" + - "net/if_arp.h" + - "net/if_ppp.h" + - "netax25/ax25.h" + - "netinet/icmp6.h" + - "netinet/ip.h" + - "netinet/ip6.h" + - "netinet/ip_icmp.h" + - "netinet/tcp.h" + - "netinet/udp.h" + - "netipx/ipx.h" + - "netrom/netrom.h" + - "scsi/scsi.h" + - "scsi/sg.h" + - "sys/dir.h" + - "sys/mount.h" + - "sys/mtio.h" + - "sys/user.h" + - "sys/procfs.h" + - "sys/queue.h" + - "sys/ttydefaults.h" + + - "ar.h" + - "byteswap.h" + - "complex.h" + - "dlfcn.h" + - "elf.h" + - "endian.h" + - "err.h" + - "fenv.h" + - "fnmatch.h" + - "ftw.h" + - "fstab.h" + - "gshadow.h" + - "inttypes.h" + - "lastlog.h" + - "locale.h" + - "math.h" + - "mlibc-config.h" + - "module.h" + - "paths.h" + - "printf.h" + - "pty.h" + - "resolv.h" + - "search.h" + - "setjmp.h" + - "stdarg.h" + - "stddef.h" + - "stdint.h" + - "strings.h" + - "sysexits.h" + - "syslog.h" + - "threads.h" + - "utime.h" + - "values.h" + - "wchar.h" + - "wctype.h" + - "wordexp.h" + +ignored_structs: + - "_IO_cookie_io_functions_t" + - "div_t" + - "ldiv_t" + - "lldiv_t" + - "dirent64" + - "dl_phdr_info" + - "link_map" + - "r_debug" + - "epoll_event" + - "ifreq" + - "ifconf" + - "stat64" + - "statfs64" + - "statvfs64" + - "timezone" + # unix/linux_like/mod.rs + - "in_addr" + - "ip_mreq" + - "ip_mreqn" + - "ip_mreq_source" + - "sockaddr" + - "sockaddr_in" + - "sockaddr_in6" + - "addrinfo" # TODO: fix #[cfg()] + - "sockaddr_ll" + - "fd_set" + - "tm" + - "sched_param" # TODO: fix #[cfg()] + - "Dl_info" + - "lconv" + - "in_pktinfo" + - "ifaddrs" + - "in6_rtmsg" + - "arpreq" + - "arpreq_old" + - "arphdr" + - "mmsghdr" + - "sockaddr_un" + - "sockaddr_storage" + - "utsname" + - "sigevent" + # unix/mod.rs + - "iovec" + - "ipv6_mreq" + - "timeval" + - "rusage" + - "timespec" + - "itimerval" + - "linger" + - "winsize" + - "group" + - "hostent" + - "protoent" + - "servent" + - "rlimit" + - "tms" + - "pollfd" + # unix/align.rs + - "in6_addr" + +forced_structs: + - "__mlibc_file_base" + - "__mlibc_threadattr" + - "__mlibc_once" + - "__mlibc_mutexattr" + - "__mlibc_mutex" + - "__mlibc_condattr" + - "__mlibc_cond" + - "__mlibc_barrierattr_struct" + - "__mlibc_barrier" + - "__mlibc_fair_rwlock" + - "__mlibc_rwlockattr" + - "__mlibc_dir_struct" + - "__mlibc_mbstate" + - "__mlibc_thread_data" + - "__fd_mask" + - "__mlibc_fsid" + - "__ucontext" + - "__stack" + +forced_empty_structs: [] + +ignored_enums: + - "idtype_t" + - "VISIT" + +ignored_unions: + - "epoll_data" + # unix/mod.rs + - "sigval" + +ignored_var_declarations: + - "stdout" + - "stdin" + - "stderr" + - "program_invocation_name" + - "program_invocation_short_name" + - "daylight" + - "timezone" + - "tzname" + - "optarg" + - "optind" + - "opterr" + - "optopt" + - "optreset" + - "environ" + - "_DYNAMIC" + - "in6addr_any" + - "in6addr_loopback" + - "error_message_count" + - "error_one_per_line" + - "error_print_progname" + +ignored_macros: + - "strdupa" + - "strndupa" + - "e_exit" + - "e_termination" + - "stat64" + - "MB_CUR_MAX" + - "CHARBITS" + - "CHAR_MAX" + - "CHAR_MIN" + - "CLOCKS_PER_SEC" + - "CMSG_NXTHDR" + - "CPU_ALLOC" + - "CPU_ALLOC_SIZE" + - "CPU_CLR" + - "CPU_CLR_S" + - "CPU_COUNT" + - "CPU_COUNT_S" + - "CPU_FREE" + - "CPU_ISSET" + - "CPU_ISSET_S" + - "CPU_SET" + - "CPU_SET_S" + - "CPU_ZERO" + - "CPU_ZERO_S" + - "DOUBLEBITS" + - "FE_ALL_EXCEPT" + - "FE_DFL_ENV" + - "FLOATBITS" + - "GSHADOW" + - "IFTODT" + - "IN6ADDR_ANY_INIT" + - "IN6ADDR_LOOPBACK_INIT" + - "IN6_ARE_ADDR_EQUAL" + - "IN6_IS_ADDR_LINKLOCAL" + - "IN6_IS_ADDR_LOOPBACK" + - "IN6_IS_ADDR_MC_GLOBAL" + - "IN6_IS_ADDR_MC_LINKLOCAL" + - "IN6_IS_ADDR_MC_NODELOCAL" + - "IN6_IS_ADDR_MC_ORGLOCAL" + - "IN6_IS_ADDR_MC_SITELOCAL" + - "IN6_IS_ADDR_MULTICAST" + - "IN6_IS_ADDR_SITELOCAL" + - "IN6_IS_ADDR_UNSPECIFIED" + - "IN6_IS_ADDR_V4COMPAT" + - "IN6_IS_ADDR_V4MAPPED" + - "INADDR_ALLHOSTS_GROUP" + - "INADDR_ALLRTRS_GROUP" + - "INADDR_ALLSNOOPERS_GROUP" + - "INADDR_ANY" + - "INADDR_BROADCAST" + - "INADDR_LOOPBACK" + - "INADDR_MAX_LOCAL_GROUP" + - "INADDR_NONE" + - "INADDR_UNSPEC_GROUP" + - "INT16_C" + - "INT32_C" + - "INT64_C" + - "INT8_C" + - "INTBITS" + - "INTMAX_C" + - "INT_MAX" + - "INT_MIN" + - "IN_BADCLASS" + - "IN_BADCLASS" + - "IN_CLASSA" + - "IN_CLASSA_HOST" + - "IN_CLASSB" + - "IN_CLASSB_HOST" + - "IN_CLASSC" + - "IN_CLASSC_HOST" + - "IN_CLASSD" + - "IN_EXPERIMENTAL" + - "IN_EXPERIMENTAL" + - "IN_MULTICAST" + - "IPC_PRIVATE" + - "IPTOS_TOS" + - "LLONG_MAX" + - "LLONG_MIN" + - "LONGBITS" + - "LONG_LONG_MAX" + - "LONG_LONG_MIN" + - "LONG_MAX" + - "LONG_MIN" + - "MAX" + - "MB_CUR_MAX" + - "MIN" + - "MOUNTED" + - "NULL" + - "PAGE_MASK" + - "PAGE_SHIFT" + - "PAGE_SIZE" + - "PTHREAD_CANCELED" + - "PTHREAD_COND_INITIALIZER" + - "PTHREAD_MUTEX_INITIALIZER" + - "PTHREAD_ONCE_INIT" + - "PTHREAD_RWLOCK_INITIALIZER" + - "PTRBITS" + - "P_tmpdir" + - "RENAME_EXCHANGE" + - "SCHAR_MAX" + - "SCHAR_MIN" + - "SEM_FAILED" + - "SHADOW" + - "SHMLBA" + - "SHORTBITS" + - "SHRT_MAX" + - "SHRT_MIN" + - "SIG_DFL" + - "SIG_ERR" + - "SIG_IGN" + - "SSIZE_MAX" + - "SSIZE_MIN" + - "SUBCMDMASK" + - "SUBCMDSHIFT" + - "SUN_LEN" + - "SWAP_FLAG_DISCARD" + - "SWAP_FLAG_PREFER" + - "SWAP_FLAG_PRIO_MASK" + - "SWAP_FLAG_PRIO_SHIFT" + - "S_IEXEC" + - "S_IREAD" + - "S_ISBLK" + - "S_ISCHR" + - "S_ISDIR" + - "S_ISFIFO" + - "S_ISLNK" + - "S_ISREG" + - "S_ISSOCK" + - "S_IWRITE" + - "TIMESPEC_TO_TIMEVAL" + - "TIMEVAL_TO_TIMESPEC" + - "UCHAR_MAX" + - "UCHAR_MIN" + - "UINT16_C" + - "UINT32_C" + - "UINT64_C" + - "UINT8_C" + - "UINTMAX_C" + - "UINT_MAX" + - "UINT_MAX" + - "UINT_MIN" + - "ULLONG_MAX" + - "ULLONG_MIN" + - "ULONG_LONG_MAX" + - "ULONG_LONG_MIN" + - "ULONG_MAX" + - "ULONG_MIN" + - "USHRT_MAX" + - "USHRT_MIN" + - "UTIME_NOW" + - "UTIME_OMIT" + - "UTMP_FILE" + - "UTMP_FILENAME" + - "WCHAR_MAX" + - "WCHAR_MIN" + - "WEOF" + - "WTMP_FILE" + - "WTMP_FILENAME" + - "_PATH_SERVICES" + - "_POSIX2_VERSION" + - "_POSIX_FSYNC" + - "_POSIX_IPV6" + - "_POSIX_SPAWN" + - "_POSIX_THREADS" + - "_POSIX_THREAD_SAFE_FUNCTIONS" + - "_POSIX_VDISABLE" + - "_res" + - "alloca" + - "assert" + - "basename" + - "d_fileno" + - "errno" + - "h_addr" + - "h_errno" + - "howmany" + - "major" + - "makedev" + - "minor" + - "msqid_ds" + - "statvfs64" + - "ipc_perm" + - "roundup" + - "s6_addr" + - "s6_addr16" + - "s6_addr32" + - "sa_handler" + - "sa_sigaction" + - "si_addr" + - "si_addr_lsb" + - "si_arch" + - "si_band" + - "si_call_addr" + - "si_fd" + - "si_int" + - "si_lower" + - "si_overrun" + - "si_pid" + - "si_pkey" + - "si_ptr" + - "si_status" + - "si_stime" + - "si_syscall" + - "si_timerid" + - "si_uid" + - "si_upper" + - "si_utime" + - "si_value" + - "st_atime" + - "st_ctime" + - "st_mtime" + - "static_assert" + - "timercmp" + - "toascii" + - "ut_addr" + - "ut_name" + - "ut_time" + - "ut_xtime" + - "arp_hrd" + - "arp_pro" + - "arp_hln" + - "arp_pln" + - "arp_op" + - "MAXHOSTNAMELEN" + - "UTMPX_FILE" + - "WTMPX_FILE" + - "no_argument" + - "required_argument" + - "optional_argument" + # DO NOT REMOVE: mlibc internals + - "MLIBC_UNIMPLEMENTED" + - "MLIBC_MISSING_SYSDEP" + - "MLIBC_CHECK_OR_ENOSYS" + - "thread_local" + - "NFDBITS" + - "ElfW" + - "ELFMAG" + # unix/mod.rs + - "INT_MIN" + - "INT_MAX" + - "SIG_DFL" + - "SIG_IGN" + - "SIG_ERR" + - "DT_UNKNOWN" + - "DT_FIFO" + - "DT_CHR" + - "DT_DIR" + - "DT_BLK" + - "DT_REG" + - "DT_LNK" + - "DT_SOCK" + - "FD_CLOEXEC" + - "USRQUOTA" + - "GRPQUOTA" + - "SIGIOT" + - "S_ISUID" + - "S_ISGID" + - "S_ISVTX" + - "IF_NAMESIZE" + - "IFNAMSIZ" + - "LOG_EMERG" + - "LOG_ALERT" + - "LOG_CRIT" + - "LOG_ERR" + - "LOG_WARNING" + - "LOG_NOTICE" + - "LOG_INFO" + - "LOG_DEBUG" + - "LOG_KERN" + - "LOG_USER" + - "LOG_MAIL" + - "LOG_DAEMON" + - "LOG_AUTH" + - "LOG_SYSLOG" + - "LOG_LPR" + - "LOG_NEWS" + - "LOG_UUCP" + - "LOG_LOCAL0" + - "LOG_LOCAL1" + - "LOG_LOCAL2" + - "LOG_LOCAL3" + - "LOG_LOCAL4" + - "LOG_LOCAL5" + - "LOG_LOCAL6" + - "LOG_LOCAL7" + - "LOG_PID" + - "LOG_CONS" + - "LOG_ODELAY" + - "LOG_NDELAY" + - "LOG_NOWAIT" + - "LOG_PRIMASK" + - "LOG_FACMASK" + - "PRIO_MIN" + - "PRIO_MAX" + - "IPPROTO_ICMP" + - "IPPROTO_ICMPV6" + - "IPPROTO_TCP" + - "IPPROTO_UDP" + - "IPPROTO_IP" + - "IPPROTO_IPV6" + - "INADDR_LOOPBACK" + - "INADDR_ANY" + - "INADDR_BROADCAST" + - "INADDR_NONE" + - "ARPOP_REQUEST" + - "ARPOP_REPLY" + - "ATF_COM" + - "ATF_PERM" + - "ATF_PUBL" + - "ATF_USETRAILERS" + # unix/linux_like/mod.rs + - "EXIT_FAILURE" + - "EXIT_SUCCESS" + - "RAND_MAX" + - "EOF" + - "SEEK_SET" + - "SEEK_CUR" + - "SEEK_END" + - "_IOFBF" + - "_IONBF" + - "_IOLBF" + - "F_DUPFD" + - "F_GETFD" + - "F_SETFD" + - "F_GETFL" + - "F_SETFL" + - "F_SETLEASE" + - "F_GETLEASE" + - "F_NOTIFY" + - "F_CANCELLK" + - "F_DUPFD_CLOEXEC" + - "F_SETPIPE_SZ" + - "F_GETPIPE_SZ" + - "F_ADD_SEALS" + - "F_GET_SEALS" + - "F_SEAL_SEAL" + - "F_SEAL_SHRINK" + - "F_SEAL_GROW" + - "F_SEAL_WRITE" + - "SIGTRAP" + - "PTHREAD_CREATE_JOINABLE" + - "PTHREAD_CREATE_DETACHED" + - "CLOCK_REALTIME" + - "CLOCK_MONOTONIC" + - "CLOCK_PROCESS_CPUTIME_ID" + - "CLOCK_THREAD_CPUTIME_ID" + - "CLOCK_MONOTONIC_RAW" + - "CLOCK_REALTIME_COARSE" + - "CLOCK_MONOTONIC_COARSE" + - "CLOCK_BOOTTIME" + - "CLOCK_REALTIME_ALARM" + - "CLOCK_BOOTTIME_ALARM" + - "CLOCK_TAI" + - "TIMER_ABSTIME" + - "RUSAGE_SELF" + - "O_RDONLY" + - "O_WRONLY" + - "O_RDWR" + - "SOCK_CLOEXEC" + - "S_IFIFO" + - "S_IFCHR" + - "S_IFBLK" + - "S_IFDIR" + - "S_IFREG" + - "S_IFLNK" + - "S_IFSOCK" + - "S_IFMT" + - "S_IRWXU" + - "S_IXUSR" + - "S_IWUSR" + - "S_IRUSR" + - "S_IRWXG" + - "S_IXGRP" + - "S_IWGRP" + - "S_IRGRP" + - "S_IRWXO" + - "S_IXOTH" + - "S_IWOTH" + - "S_IROTH" + - "F_OK" + - "R_OK" + - "W_OK" + - "X_OK" + - "STDIN_FILENO" + - "STDOUT_FILENO" + - "STDERR_FILENO" + - "SIGHUP" + - "SIGINT" + - "SIGQUIT" + - "SIGILL" + - "SIGABRT" + - "SIGFPE" + - "SIGKILL" + - "SIGSEGV" + - "SIGPIPE" + - "SIGALRM" + - "SIGTERM" + - "SA_NOMASK" + - "SA_ONESHOT" + - "PROT_NONE" + - "PROT_READ" + - "PROT_WRITE" + - "PROT_EXEC" + - "XATTR_CREATE" + - "XATTR_REPLACE" + + - "LC_CTYPE_MASK" + - "LC_NUMERIC_MASK" + - "LC_TIME_MASK" + - "LC_COLLATE_MASK" + - "LC_MONETARY_MASK" + - "LC_MESSAGES_MASK" + + - "MAP_FILE" + - "MAP_SHARED" + - "MAP_PRIVATE" + - "MAP_FIXED" + - "MAP_FAILED" + + - "MS_ASYNC" + - "MS_INVALIDATE" + - "MS_SYNC" + + - "MS_RDONLY" + - "MS_NOSUID" + - "MS_NODEV" + - "MS_NOEXEC" + - "MS_SYNCHRONOUS" + - "MS_REMOUNT" + - "MS_MANDLOCK" + - "MS_DIRSYNC" + - "MS_NOATIME" + - "MS_NODIRATIME" + - "MS_BIND" + - "MS_MOVE" + - "MS_REC" + - "MS_SILENT" + - "MS_POSIXACL" + - "MS_UNBINDABLE" + - "MS_PRIVATE" + - "MS_SLAVE" + - "MS_SHARED" + - "MS_RELATIME" + - "MS_KERNMOUNT" + - "MS_I_VERSION" + - "MS_STRICTATIME" + - "MS_LAZYTIME" + - "MS_ACTIVE" + - "MS_MGC_VAL" + - "MS_MGC_MSK" + + - "SCM_RIGHTS" + - "SCM_CREDENTIALS" + + - "PROT_GROWSDOWN" + - "PROT_GROWSUP" + + - "MAP_TYPE" + + - "MADV_NORMAL" + - "MADV_RANDOM" + - "MADV_SEQUENTIAL" + - "MADV_WILLNEED" + - "MADV_DONTNEED" + - "MADV_FREE" + - "MADV_REMOVE" + - "MADV_DONTFORK" + - "MADV_DOFORK" + - "MADV_MERGEABLE" + - "MADV_UNMERGEABLE" + - "MADV_HUGEPAGE" + - "MADV_NOHUGEPAGE" + - "MADV_DONTDUMP" + - "MADV_DODUMP" + - "MADV_WIPEONFORK" + - "MADV_KEEPONFORK" + - "MADV_COLD" + - "MADV_PAGEOUT" + - "MADV_HWPOISON" + + - "MADV_POPULATE_READ" + - "MADV_POPULATE_WRITE" + - "MADV_DONTNEED_LOCKED" + + - "IFF_UP" + - "IFF_BROADCAST" + - "IFF_DEBUG" + - "IFF_LOOPBACK" + - "IFF_POINTOPOINT" + - "IFF_NOTRAILERS" + - "IFF_RUNNING" + - "IFF_NOARP" + - "IFF_PROMISC" + - "IFF_ALLMULTI" + - "IFF_MASTER" + - "IFF_SLAVE" + - "IFF_MULTICAST" + - "IFF_PORTSEL" + - "IFF_AUTOMEDIA" + - "IFF_DYNAMIC" + + - "SOL_IP" + - "SOL_TCP" + - "SOL_UDP" + - "SOL_IPV6" + - "SOL_ICMPV6" + - "SOL_RAW" + - "SOL_DECNET" + - "SOL_X25" + - "SOL_PACKET" + - "SOL_ATM" + - "SOL_AAL" + - "SOL_IRDA" + - "SOL_NETBEUI" + - "SOL_LLC" + - "SOL_DCCP" + - "SOL_NETLINK" + - "SOL_TIPC" + - "SOL_BLUETOOTH" + - "SOL_ALG" + + - "AF_UNSPEC" + - "AF_UNIX" + - "AF_INET" + - "AF_AX25" + - "AF_IPX" + - "AF_APPLETALK" + - "AF_NETROM" + - "AF_BRIDGE" + - "AF_ATMPVC" + - "AF_X25" + - "AF_INET6" + - "AF_ROSE" + - "AF_DECnet" + - "AF_NETBEUI" + - "AF_SECURITY" + - "AF_KEY" + - "AF_NETLINK" + - "AF_ROUTE" + - "AF_PACKET" + - "AF_ASH" + - "AF_ECONET" + - "AF_ATMSVC" + - "AF_RDS" + - "AF_SNA" + - "AF_IRDA" + - "AF_PPPOX" + - "AF_WANPIPE" + - "AF_LLC" + - "AF_CAN" + - "AF_TIPC" + - "AF_BLUETOOTH" + - "AF_IUCV" + - "AF_RXRPC" + - "AF_ISDN" + - "AF_PHONET" + - "AF_IEEE802154" + - "AF_CAIF" + - "AF_ALG" + + - "PF_UNSPEC" + - "PF_UNIX" + - "PF_INET" + - "PF_AX25" + - "PF_IPX" + - "PF_APPLETALK" + - "PF_NETROM" + - "PF_BRIDGE" + - "PF_ATMPVC" + - "PF_X25" + - "PF_INET6" + - "PF_ROSE" + - "PF_DECnet" + - "PF_NETBEUI" + - "PF_SECURITY" + - "PF_KEY" + - "PF_NETLINK" + - "PF_ROUTE" + - "PF_PACKET" + - "PF_ASH" + - "PF_ECONET" + - "PF_ATMSVC" + - "PF_RDS" + - "PF_SNA" + - "PF_IRDA" + - "PF_PPPOX" + - "PF_WANPIPE" + - "PF_LLC" + - "PF_CAN" + - "PF_TIPC" + - "PF_BLUETOOTH" + - "PF_IUCV" + - "PF_RXRPC" + - "PF_ISDN" + - "PF_PHONET" + - "PF_IEEE802154" + - "PF_CAIF" + - "PF_ALG" + + - "MSG_OOB" + - "MSG_PEEK" + - "MSG_DONTROUTE" + - "MSG_CTRUNC" + - "MSG_TRUNC" + - "MSG_DONTWAIT" + - "MSG_EOR" + - "MSG_WAITALL" + - "MSG_FIN" + - "MSG_SYN" + - "MSG_CONFIRM" + - "MSG_RST" + - "MSG_ERRQUEUE" + - "MSG_NOSIGNAL" + - "MSG_MORE" + - "MSG_WAITFORONE" + - "MSG_FASTOPEN" + - "MSG_CMSG_CLOEXEC" + + - "SCM_TIMESTAMP" + + - "SOCK_RAW" + - "SOCK_RDM" + - "IP_TOS" + - "IP_TTL" + - "IP_HDRINCL" + - "IP_OPTIONS" + - "IP_ROUTER_ALERT" + - "IP_RECVOPTS" + - "IP_RETOPTS" + - "IP_PKTINFO" + - "IP_PKTOPTIONS" + - "IP_MTU_DISCOVER" + - "IP_RECVERR" + - "IP_RECVTTL" + - "IP_RECVTOS" + - "IP_MTU" + - "IP_FREEBIND" + - "IP_IPSEC_POLICY" + - "IP_XFRM_POLICY" + - "IP_PASSSEC" + - "IP_TRANSPARENT" + - "IP_ORIGDSTADDR" + - "IP_RECVORIGDSTADDR" + - "IP_MINTTL" + - "IP_NODEFRAG" + - "IP_CHECKSUM" + - "IP_BIND_ADDRESS_NO_PORT" + - "IP_MULTICAST_IF" + - "IP_MULTICAST_TTL" + - "IP_MULTICAST_LOOP" + - "IP_ADD_MEMBERSHIP" + - "IP_DROP_MEMBERSHIP" + - "IP_UNBLOCK_SOURCE" + - "IP_BLOCK_SOURCE" + - "IP_ADD_SOURCE_MEMBERSHIP" + - "IP_DROP_SOURCE_MEMBERSHIP" + - "IP_MSFILTER" + - "IP_MULTICAST_ALL" + - "IP_UNICAST_IF" + + - "IP_DEFAULT_MULTICAST_TTL" + - "IP_DEFAULT_MULTICAST_LOOP" + + - "IP_PMTUDISC_DONT" + - "IP_PMTUDISC_WANT" + - "IP_PMTUDISC_DO" + - "IP_PMTUDISC_PROBE" + - "IP_PMTUDISC_INTERFACE" + - "IP_PMTUDISC_OMIT" + + - "IPPROTO_HOPOPTS" + - "IPPROTO_IGMP" + - "IPPROTO_IPIP" + - "IPPROTO_EGP" + - "IPPROTO_PUP" + - "IPPROTO_IDP" + - "IPPROTO_TP" + - "IPPROTO_DCCP" + - "IPPROTO_ROUTING" + - "IPPROTO_FRAGMENT" + - "IPPROTO_RSVP" + - "IPPROTO_GRE" + - "IPPROTO_ESP" + - "IPPROTO_AH" + - "IPPROTO_NONE" + - "IPPROTO_DSTOPTS" + - "IPPROTO_MTP" + - "IPPROTO_ENCAP" + - "IPPROTO_PIM" + - "IPPROTO_COMP" + - "IPPROTO_SCTP" + - "IPPROTO_MH" + - "IPPROTO_UDPLITE" + - "IPPROTO_RAW" + - "IPPROTO_BEETPH" + - "IPPROTO_MPLS" + - "IPPROTO_MPTCP" + - "IPPROTO_ETHERNET" + + - "MCAST_EXCLUDE" + - "MCAST_INCLUDE" + - "MCAST_JOIN_GROUP" + - "MCAST_BLOCK_SOURCE" + - "MCAST_UNBLOCK_SOURCE" + - "MCAST_LEAVE_GROUP" + - "MCAST_JOIN_SOURCE_GROUP" + - "MCAST_LEAVE_SOURCE_GROUP" + - "MCAST_MSFILTER" + + - "IPV6_ADDRFORM" + - "IPV6_2292PKTINFO" + - "IPV6_2292HOPOPTS" + - "IPV6_2292DSTOPTS" + - "IPV6_2292RTHDR" + - "IPV6_2292PKTOPTIONS" + - "IPV6_CHECKSUM" + - "IPV6_2292HOPLIMIT" + - "IPV6_NEXTHOP" + - "IPV6_AUTHHDR" + - "IPV6_UNICAST_HOPS" + - "IPV6_MULTICAST_IF" + - "IPV6_MULTICAST_HOPS" + - "IPV6_MULTICAST_LOOP" + - "IPV6_ADD_MEMBERSHIP" + - "IPV6_DROP_MEMBERSHIP" + - "IPV6_ROUTER_ALERT" + - "IPV6_MTU_DISCOVER" + - "IPV6_MTU" + - "IPV6_RECVERR" + - "IPV6_V6ONLY" + - "IPV6_JOIN_ANYCAST" + - "IPV6_LEAVE_ANYCAST" + - "IPV6_IPSEC_POLICY" + - "IPV6_XFRM_POLICY" + - "IPV6_HDRINCL" + - "IPV6_RECVPKTINFO" + - "IPV6_PKTINFO" + - "IPV6_RECVHOPLIMIT" + - "IPV6_HOPLIMIT" + - "IPV6_RECVHOPOPTS" + - "IPV6_HOPOPTS" + - "IPV6_RTHDRDSTOPTS" + - "IPV6_RECVRTHDR" + - "IPV6_RTHDR" + - "IPV6_RECVDSTOPTS" + - "IPV6_DSTOPTS" + - "IPV6_RECVPATHMTU" + - "IPV6_PATHMTU" + - "IPV6_DONTFRAG" + - "IPV6_RECVTCLASS" + - "IPV6_TCLASS" + - "IPV6_AUTOFLOWLABEL" + - "IPV6_ADDR_PREFERENCES" + - "IPV6_MINHOPCOUNT" + - "IPV6_ORIGDSTADDR" + - "IPV6_RECVORIGDSTADDR" + - "IPV6_TRANSPARENT" + - "IPV6_UNICAST_IF" + - "IPV6_PREFER_SRC_TMP" + - "IPV6_PREFER_SRC_PUBLIC" + - "IPV6_PREFER_SRC_PUBTMP_DEFAULT" + - "IPV6_PREFER_SRC_COA" + - "IPV6_PREFER_SRC_HOME" + - "IPV6_PREFER_SRC_CGA" + - "IPV6_PREFER_SRC_NONCGA" + + - "IPV6_PMTUDISC_DONT" + - "IPV6_PMTUDISC_WANT" + - "IPV6_PMTUDISC_DO" + - "IPV6_PMTUDISC_PROBE" + - "IPV6_PMTUDISC_INTERFACE" + - "IPV6_PMTUDISC_OMIT" + + - "TCP_NODELAY" + - "TCP_MAXSEG" + - "TCP_CORK" + - "TCP_KEEPIDLE" + - "TCP_KEEPINTVL" + - "TCP_KEEPCNT" + - "TCP_SYNCNT" + - "TCP_LINGER2" + - "TCP_DEFER_ACCEPT" + - "TCP_WINDOW_CLAMP" + - "TCP_INFO" + - "TCP_QUICKACK" + - "TCP_CONGESTION" + - "TCP_MD5SIG" + + - "TCP_THIN_LINEAR_TIMEOUTS" + - "TCP_THIN_DUPACK" + - "TCP_USER_TIMEOUT" + - "TCP_REPAIR" + - "TCP_REPAIR_QUEUE" + - "TCP_QUEUE_SEQ" + - "TCP_REPAIR_OPTIONS" + - "TCP_FASTOPEN" + - "TCP_TIMESTAMP" + - "TCP_NOTSENT_LOWAT" + - "TCP_CC_INFO" + - "TCP_SAVE_SYN" + - "TCP_SAVED_SYN" + + - "TCP_REPAIR_WINDOW" + - "TCP_FASTOPEN_CONNECT" + - "TCP_ULP" + - "TCP_MD5SIG_EXT" + - "TCP_FASTOPEN_KEY" + - "TCP_FASTOPEN_NO_COOKIE" + - "TCP_ZEROCOPY_RECEIVE" + - "TCP_INQ" + - "TCP_CM_INQ" + - "TCP_MD5SIG_MAXKEYLEN" + + - "SO_DEBUG" + + - "SHUT_RD" + - "SHUT_WR" + - "SHUT_RDWR" + + - "LOCK_SH" + - "LOCK_EX" + - "LOCK_NB" + - "LOCK_UN" + + - "SS_ONSTACK" + - "SS_DISABLE" + + - "PATH_MAX" + + - "UIO_MAXIOV" + + - "FD_SETSIZE" + + - "EPOLLIN" + - "EPOLLPRI" + - "EPOLLOUT" + - "EPOLLERR" + - "EPOLLHUP" + - "EPOLLRDNORM" + - "EPOLLRDBAND" + - "EPOLLWRNORM" + - "EPOLLWRBAND" + - "EPOLLMSG" + - "EPOLLRDHUP" + - "EPOLLEXCLUSIVE" + - "EPOLLWAKEUP" + - "EPOLLONESHOT" + - "EPOLLET" + + - "EPOLL_CTL_ADD" + - "EPOLL_CTL_MOD" + - "EPOLL_CTL_DEL" + + - "MNT_FORCE" + - "MNT_DETACH" + - "MNT_EXPIRE" + - "UMOUNT_NOFOLLOW" + + - "Q_GETFMT" + - "Q_GETINFO" + - "Q_SETINFO" + - "QIF_BLIMITS" + - "QIF_SPACE" + - "QIF_ILIMITS" + - "QIF_INODES" + - "QIF_BTIME" + - "QIF_ITIME" + - "QIF_LIMITS" + - "QIF_USAGE" + - "QIF_TIMES" + - "QIF_ALL" + + - "Q_SYNC" + - "Q_QUOTAON" + - "Q_QUOTAOFF" + - "Q_GETQUOTA" + - "Q_SETQUOTA" + + - "TCIOFF" + - "TCION" + - "TCOOFF" + - "TCOON" + - "TCIFLUSH" + - "TCOFLUSH" + - "TCIOFLUSH" + - "NL0" + - "NL1" + - "TAB0" + - "CR0" + - "FF0" + - "BS0" + - "VT0" + - "VERASE" + - "VKILL" + - "VINTR" + - "VQUIT" + - "VLNEXT" + - "IGNBRK" + - "BRKINT" + - "IGNPAR" + - "PARMRK" + - "INPCK" + - "ISTRIP" + - "INLCR" + - "IGNCR" + - "ICRNL" + - "IXANY" + - "IMAXBEL" + - "OPOST" + - "CS5" + - "CRTSCTS" + - "ECHO" + - "OCRNL" + - "ONOCR" + - "ONLRET" + - "OFILL" + - "OFDEL" + + - "CLONE_VM" + - "CLONE_FS" + - "CLONE_FILES" + - "CLONE_SIGHAND" + - "CLONE_PTRACE" + - "CLONE_VFORK" + - "CLONE_PARENT" + - "CLONE_THREAD" + - "CLONE_NEWNS" + - "CLONE_SYSVSEM" + - "CLONE_SETTLS" + - "CLONE_PARENT_SETTID" + - "CLONE_CHILD_CLEARTID" + - "CLONE_DETACHED" + - "CLONE_UNTRACED" + - "CLONE_CHILD_SETTID" + - "CLONE_NEWCGROUP" + - "CLONE_NEWUTS" + - "CLONE_NEWIPC" + - "CLONE_NEWUSER" + - "CLONE_NEWPID" + - "CLONE_NEWNET" + - "CLONE_IO" + + - "WNOHANG" + - "WUNTRACED" + - "WSTOPPED" + - "WEXITED" + - "WCONTINUED" + - "WNOWAIT" + + - "ADDR_NO_RANDOMIZE" + - "MMAP_PAGE_ZERO" + - "ADDR_COMPAT_LAYOUT" + - "READ_IMPLIES_EXEC" + - "ADDR_LIMIT_32BIT" + - "SHORT_INODE" + - "WHOLE_SECONDS" + - "STICKY_TIMEOUTS" + - "ADDR_LIMIT_3GB" + + - "PTRACE_O_TRACESYSGOOD" + - "PTRACE_O_TRACEFORK" + - "PTRACE_O_TRACEVFORK" + - "PTRACE_O_TRACECLONE" + - "PTRACE_O_TRACEEXEC" + - "PTRACE_O_TRACEVFORKDONE" + - "PTRACE_O_TRACEEXIT" + - "PTRACE_O_TRACESECCOMP" + - "PTRACE_O_SUSPEND_SECCOMP" + - "PTRACE_O_EXITKILL" + - "PTRACE_O_MASK" + + - "PTRACE_EVENT_FORK" + - "PTRACE_EVENT_VFORK" + - "PTRACE_EVENT_CLONE" + - "PTRACE_EVENT_EXEC" + - "PTRACE_EVENT_VFORK_DONE" + - "PTRACE_EVENT_EXIT" + - "PTRACE_EVENT_SECCOMP" + + - "SPLICE_F_MOVE" + - "SPLICE_F_NONBLOCK" + - "SPLICE_F_MORE" + - "SPLICE_F_GIFT" + + - "RTLD_LOCAL" + - "RTLD_LAZY" + + - "POSIX_FADV_NORMAL" + - "POSIX_FADV_RANDOM" + - "POSIX_FADV_SEQUENTIAL" + - "POSIX_FADV_WILLNEED" + + - "AT_FDCWD" + - "AT_SYMLINK_NOFOLLOW" + - "AT_REMOVEDIR" + - "AT_SYMLINK_FOLLOW" + - "AT_NO_AUTOMOUNT" + - "AT_EMPTY_PATH" + - "AT_RECURSIVE" + + - "LOG_CRON" + - "LOG_AUTHPRIV" + - "LOG_FTP" + - "LOG_PERROR" + + - "PIPE_BUF" + + - "SI_LOAD_SHIFT" + - "SI_ASYNCNL" + - "SI_USER" + - "SI_KERNEL" + - "SI_QUEUE" + - "SI_TIMER" + - "SI_MESGQ" + - "SI_ASYNCIO" + - "SI_SIGIO" + - "SI_TKILL" + - "SI_ASYNCNL" + + - "BUS_ADRALN" + - "BUS_ADRERR" + - "BUS_OBJERR" + - "BUS_MCEERR_AR" + - "BUS_MCEERR_AO" + + - "TRAP_BRKPT" + - "TRAP_TRACE" + - "TRAP_BRANCH" + - "TRAP_HWBKPT" + - "TRAP_UNK" + + - "CLD_EXITED" + - "CLD_KILLED" + - "CLD_DUMPED" + - "CLD_TRAPPED" + - "CLD_STOPPED" + - "CLD_CONTINUED" + + - "SIGEV_SIGNAL" + - "SIGEV_NONE" + - "SIGEV_THREAD" + + - "P_ALL" + - "P_PID" + - "P_PGID" + - "P_PIDFD" + + - "UTIME_OMIT" + - "UTIME_NOW" + + - "POLLIN" + - "POLLPRI" + - "POLLOUT" + - "POLLERR" + - "POLLHUP" + - "POLLNVAL" + - "POLLRDNORM" + - "POLLRDBAND" + - "POLLRDHUP" + + - "IPTOS_LOWDELAY" + - "IPTOS_THROUGHPUT" + - "IPTOS_RELIABILITY" + - "IPTOS_MINCOST" + + - "IPTOS_PREC_NETCONTROL" + - "IPTOS_PREC_INTERNETCONTROL" + - "IPTOS_PREC_CRITIC_ECP" + - "IPTOS_PREC_FLASHOVERRIDE" + - "IPTOS_PREC_FLASH" + - "IPTOS_PREC_IMMEDIATE" + - "IPTOS_PREC_PRIORITY" + - "IPTOS_PREC_ROUTINE" + + - "IPTOS_ECN_MASK" + - "IPTOS_ECN_ECT1" + - "IPTOS_ECN_ECT0" + - "IPTOS_ECN_CE" + + - "IPOPT_COPY" + - "IPOPT_CLASS_MASK" + - "IPOPT_NUMBER_MASK" + + - "IPOPT_CONTROL" + - "IPOPT_RESERVED1" + - "IPOPT_MEASUREMENT" + - "IPOPT_RESERVED2" + - "IPOPT_END" + - "IPOPT_NOOP" + - "IPOPT_SEC" + - "IPOPT_LSRR" + - "IPOPT_TIMESTAMP" + - "IPOPT_RR" + - "IPOPT_SID" + - "IPOPT_SSRR" + - "IPOPT_RA" + - "IPVERSION" + - "MAXTTL" + - "IPDEFTTL" + - "IPOPT_OPTVAL" + - "IPOPT_OLEN" + - "IPOPT_OFFSET" + - "IPOPT_MINOFF" + - "MAX_IPOPTLEN" + - "IPOPT_NOP" + - "IPOPT_EOL" + - "IPOPT_TS" + - "IPOPT_TS_TSONLY" + - "IPOPT_TS_TSANDADDR" + - "IPOPT_TS_PRESPEC" + + - "ARPOP_RREQUEST" + - "ARPOP_RREPLY" + - "ARPOP_InREQUEST" + - "ARPOP_InREPLY" + - "ARPOP_NAK" + + - "ATF_NETMASK" + - "ATF_DONTPUB" + + - "ARPHRD_NETROM" + - "ARPHRD_ETHER" + - "ARPHRD_EETHER" + - "ARPHRD_AX25" + - "ARPHRD_PRONET" + - "ARPHRD_CHAOS" + - "ARPHRD_IEEE802" + - "ARPHRD_ARCNET" + - "ARPHRD_APPLETLK" + - "ARPHRD_DLCI" + - "ARPHRD_ATM" + - "ARPHRD_METRICOM" + - "ARPHRD_IEEE1394" + - "ARPHRD_EUI64" + - "ARPHRD_INFINIBAND" + + - "ARPHRD_SLIP" + - "ARPHRD_CSLIP" + - "ARPHRD_SLIP6" + - "ARPHRD_CSLIP6" + - "ARPHRD_RSRVD" + - "ARPHRD_ADAPT" + - "ARPHRD_ROSE" + - "ARPHRD_X25" + - "ARPHRD_HWX25" + - "ARPHRD_CAN" + - "ARPHRD_PPP" + - "ARPHRD_CISCO" + - "ARPHRD_HDLC" + - "ARPHRD_LAPB" + - "ARPHRD_DDCMP" + - "ARPHRD_RAWHDLC" + + - "ARPHRD_TUNNEL" + - "ARPHRD_TUNNEL6" + - "ARPHRD_FRAD" + - "ARPHRD_SKIP" + - "ARPHRD_LOOPBACK" + - "ARPHRD_LOCALTLK" + - "ARPHRD_FDDI" + - "ARPHRD_BIF" + - "ARPHRD_SIT" + - "ARPHRD_IPDDP" + - "ARPHRD_IPGRE" + - "ARPHRD_PIMREG" + - "ARPHRD_HIPPI" + - "ARPHRD_ASH" + - "ARPHRD_ECONET" + - "ARPHRD_IRDA" + - "ARPHRD_FCPP" + - "ARPHRD_FCAL" + - "ARPHRD_FCPL" + - "ARPHRD_FCFABRIC" + - "ARPHRD_IEEE802_TR" + - "ARPHRD_IEEE80211" + - "ARPHRD_IEEE80211_PRISM" + - "ARPHRD_IEEE80211_RADIOTAP" + - "ARPHRD_IEEE802154" + + - "ARPHRD_VOID" + - "ARPHRD_NONE" + + - "ADFS_SUPER_MAGIC" + - "AFFS_SUPER_MAGIC" + - "AFS_SUPER_MAGIC" + - "AUTOFS_SUPER_MAGIC" + - "BPF_FS_MAGIC" + - "BTRFS_SUPER_MAGIC" + - "CGROUP2_SUPER_MAGIC" + - "CGROUP_SUPER_MAGIC" + - "CODA_SUPER_MAGIC" + - "CRAMFS_MAGIC" + - "DEBUGFS_MAGIC" + - "DEVPTS_SUPER_MAGIC" + - "ECRYPTFS_SUPER_MAGIC" + - "EFS_SUPER_MAGIC" + - "EXT2_SUPER_MAGIC" + - "EXT3_SUPER_MAGIC" + - "EXT4_SUPER_MAGIC" + - "F2FS_SUPER_MAGIC" + - "FUSE_SUPER_MAGIC" + - "FUTEXFS_SUPER_MAGIC" + - "HOSTFS_SUPER_MAGIC" + - "HPFS_SUPER_MAGIC" + - "HUGETLBFS_MAGIC" + - "ISOFS_SUPER_MAGIC" + - "JFFS2_SUPER_MAGIC" + - "MINIX2_SUPER_MAGIC2" + - "MINIX2_SUPER_MAGIC" + - "MINIX3_SUPER_MAGIC" + - "MINIX_SUPER_MAGIC2" + - "MINIX_SUPER_MAGIC" + - "MSDOS_SUPER_MAGIC" + - "NCP_SUPER_MAGIC" + - "NFS_SUPER_MAGIC" + - "NILFS_SUPER_MAGIC" + - "OCFS2_SUPER_MAGIC" + - "OPENPROM_SUPER_MAGIC" + - "OVERLAYFS_SUPER_MAGIC" + - "PROC_SUPER_MAGIC" + - "QNX4_SUPER_MAGIC" + - "QNX6_SUPER_MAGIC" + - "RDTGROUP_SUPER_MAGIC" + - "REISERFS_SUPER_MAGIC" + - "SECURITYFS_MAGIC" + - "SELINUX_MAGIC" + - "SMACK_MAGIC" + - "SMB_SUPER_MAGIC" + - "SYSFS_MAGIC" + - "TMPFS_MAGIC" + - "TRACEFS_MAGIC" + - "UDF_SUPER_MAGIC" + - "USBDEVICE_SUPER_MAGIC" + - "XENFS_SUPER_MAGIC" + - "NSFS_MAGIC" + + - "CMSG_ALIGN" + - "CMSG_FIRSTHDR" + - "CMSG_DATA" + - "CMSG_SPACE" + - "CMSG_LEN" + - "FD_CLR" + - "FD_ISSET" + - "FD_SET" + - "FD_ZERO" + - "SIGRTMAX" + - "SIGRTMIN" + - "WIFSTOPPED" + - "WSTOPSIG" + - "WIFCONTINUED" + - "WIFSIGNALED" + - "WTERMSIG" + - "WIFEXITED" + - "WEXITSTATUS" + - "WCOREDUMP" + - "W_EXITCODE" + - "W_STOPCODE" + - "QCMD" + - "IPOPT_COPIED" + - "IPOPT_CLASS" + - "IPOPT_NUMBER" + - "IPTOS_ECN" + - "KERNEL_VERSION" + - "EPOLLIN" + - "EPOLLPRI" + - "EPOLLOUT" + - "EPOLLERR" + - "EPOLLHUP" + - "EPOLLRDNORM" + - "EPOLLRDBAND" + - "EPOLLWRNORM" + - "EPOLLWRBAND" + - "EPOLLMSG" + - "EPOLLRDHUP" + - "EPOLLEXCLUSIVE" + - "EPOLLWAKEUP" + - "EPOLLONESHOT" + - "EPOLLET" + - "ifr_name" + - "ifr_hwaddr" + - "ifr_addr" + - "ifr_dstaddr" + - "ifr_broadaddr" + - "ifr_netmask" + - "ifr_flags" + - "ifr_metric" + - "ifr_mtu" + - "ifr_map" + - "ifr_slave" + - "ifr_data" + - "ifr_ifindex" + - "ifr_bandwidth" + - "ifr_qlen" + - "ifr_newname" + - "ifc_buf" + - "ifc_req" + - "RLIM_SAVED_MAX" + - "RLIM_SAVED_CUR" + - "RLIM_INFINITY" + - "PR_SET_PTRACER" + - "PR_SET_PTRACER_ANY" + - "MNTOPT_DEFAULTS" + - "MNTOPT_RO" + - "MNTOPT_RW" + - "MNTOPT_SUID" + - "MNTOPT_NOSUID" + - "MNTOPT_NOAUTO" + +forced_macros: + - "__MLIBC_THREAD_CREATE_JOINABLE" + - "__MLIBC_THREAD_CREATE_DETACHED" + - "__MLIBC_THREAD_MUTEX_DEFAULT" + - "__MLIBC_THREAD_MUTEX_NORMAL" + - "__MLIBC_THREAD_MUTEX_ERRORCHECK" + - "__MLIBC_THREAD_MUTEX_RECURSIVE" + - "__MLIBC_THREAD_PROCESS_PRIVATE" + - "__MLIBC_THREAD_PROCESS_SHARED" + - "__MLIBC_THREAD_MUTEX_STALLED" + - "__MLIBC_THREAD_MUTEX_ROBUST" + - "__MLIBC_THREAD_PRIO_NONE" + - "__MLIBC_THREAD_PRIO_INHERIT" + - "__MLIBC_THREAD_PRIO_PROTECT" + +ignored_types: + - "cookie_read_function_t" + - "cookie_write_function_t" + - "cookie_seek_function_t" + - "cookie_close_function_t" + - "cookie_io_functions_t" + - "siginfo_t" + - "ax25_address" + - "fenv_t" + - "mcontext_t" + - "div_t" + - "ldiv_t" + - "lldiv_t" + - "glob_t" + - "regmatch_t" + - "posix_spawnattr_t" + - "posix_spawn_file_actions_t" + - "idtype_t" + - "res_state" + - "VISIT" + - "epoll_data_t" + - "locale_t" + - "fd_set" + - "pthread_t" + # unix/mod.rs + - "size_t" + - "pid_t" + - "ssize_t" + - "intptr_t" + - "in_addr_t" + - "in_port_t" + - "cc_t" + - "uid_t" + - "gid_t" + - "fpos_t" + - "FILE" + - "DIR" + # unix/linux_like/mod.rs + - "sa_family_t" + - "speed_t" + - "tcflag_t" + - "clockid_t" + - "timer_t" + - "key_t" + - "id_t" + +forced_types: + - "__fd_mask" + - "__sighandler" + - "__cpu_mask" + +ignored_functions: + - "strtold" + - "strtold_l" + - "wcstold" + - "div" + - "ldiv" + - "lldiv" + - "res_ninit" + - "res_nclose" + - "twalk" + - "wait3" + - "fopencookie" + # unix/mod.rs + - "isalnum" + - "isalpha" + - "iscntrl" + - "isdigit" + - "isgraph" + - "islower" + - "isprint" + - "ispunct" + - "isspace" + - "isupper" + - "isxdigit" + - "isblank" + - "tolower" + - "toupper" + - "qsort" + - "bsearch" + - "fopen" + - "freopen" + - "fflush" + - "fclose" + - "remove" + - "rename" + - "tmpfile" + - "setvbuf" + - "setbuf" + - "getchar" + - "putchar" + - "fgetc" + - "fgets" + - "fputc" + - "fputs" + - "puts" + - "ungetc" + - "fread" + - "fwrite" + - "fseek" + - "ftell" + - "rewind" + - "fgetpos" + - "fsetpos" + - "feof" + - "ferror" + - "clearerr" + - "perror" + - "atof" + - "atoi" + - "atol" + - "atoll" + - "strtod" + - "strtof" + - "strtol" + - "strtoll" + - "strtoul" + - "strtoull" + - "calloc" + - "malloc" + - "realloc" + - "free" + - "abort" + - "exit" + - "_exit" + - "system" + - "getenv" + - "strcpy" + - "strncpy" + - "stpcpy" + - "stpncpy" + - "strcat" + - "strncat" + - "strcmp" + - "strcoll" + - "strncmp" + - "strchr" + - "strrchr" + - "strspn" + - "strcspn" + - "strdup" + - "strndup" + - "strpbrk" + - "strstr" + - "strcasecmp" + - "strncasecmp" + - "strlen" + - "strnlen" + - "strerror" + - "strtok" + - "strtok_r" + - "strxfrm" + - "strsignal" + - "wcslen" + - "wcstombs" + - "memchr" + - "wmemchr" + - "memcmp" + - "memcpy" + - "memmove" + - "memset" + - "memccpy" + + - "getpwnam" + - "getpwuid" + - "fprintf" + - "printf" + - "snprintf" + - "sprintf" + - "fscanf" + - "scanf" + - "sscanf" + - "getchar_unlocked" + - "putchar_unlocked" + - "socket" + - "connect" + - "listen" + - "accept" + - "getpeername" + - "getsockname" + - "getsockname" + - "setsockopt" + - "socketpair" + - "sendto" + - "shutdown" + - "chmod" + - "fchmod" + - "fstat" + - "mkdir" + - "stat" + - "pclose" + - "fdopen" + - "fileno" + - "open" + - "creat" + - "fcntl" + - "opendir" + - "readdir" + - "closedir" + - "rewinddir" + - "fchmodat" + - "fchown" + - "fchownat" + - "fstatat" + - "linkat" + - "renameat" + - "symlinkat" + - "unlinkat" + - "access" + - "alarm" + - "chdir" + - "fchdir" + - "chown" + - "lchown" + - "close" + - "dup" + - "dup2" + - "execl" + - "execle" + - "execlp" + - "execv" + - "execve" + - "execvp" + - "fork" + - "fpathconf" + - "getcwd" + - "getegid" + - "geteuid" + - "getgid" + - "getgroups" + - "getlogin" + - "getopt" + - "getpgid" + - "getpgrp" + - "getpid" + - "getppid" + - "getuid" + - "isatty" + - "link" + - "lseek" + - "lseek64" + - "pathconf" + - "pipe" + - "posix_memalign" + - "read" + - "rmdir" + - "seteuid" + - "setegid" + - "setgid" + - "setpgid" + - "setsid" + - "setuid" + - "setreuid" + - "setregid" + - "sleep" + - "nanosleep" + - "tcgetpgrp" + - "tcsetpgrp" + - "ttyname" + - "ttyname_r" + - "unlink" + - "wait" + - "waitpid" + - "write" + - "pread" + - "pwrite" + - "umask" + - "utime" + - "kill" + - "killpg" + - "mlock" + - "munlock" + - "mlockall" + - "munlockall" + - "mmap" + - "munmap" + - "if_nametoindex" + - "if_indextoname" + - "lstat" + - "fsync" + - "setenv" + - "unsetenv" + - "symlink" + - "truncate" + - "ftruncate" + - "signal" + - "getrusage" + - "realpath" + - "flock" + - "times" + - "pthread_self" + - "pthread_equal" + - "pthread_join" + - "pthread_exit" + - "pthread_attr_init" + - "pthread_attr_destroy" + - "pthread_attr_getstacksize" + - "pthread_attr_setstacksize" + - "pthread_attr_setdetachstate" + - "pthread_detach" + - "sched_yield" + - "pthread_key_create" + - "pthread_key_delete" + - "pthread_getspecific" + - "pthread_setspecific" + - "pthread_mutex_init" + - "pthread_mutex_destroy" + - "pthread_mutex_lock" + - "pthread_mutex_trylock" + - "pthread_mutex_unlock" + - "pthread_mutexattr_init" + - "pthread_mutexattr_destroy" + - "pthread_mutexattr_settype" + - "pthread_cond_init" + - "pthread_cond_wait" + - "pthread_cond_timedwait" + - "pthread_cond_signal" + - "pthread_cond_broadcast" + - "pthread_cond_destroy" + - "pthread_condattr_init" + - "pthread_condattr_destroy" + - "pthread_rwlock_init" + - "pthread_rwlock_destroy" + - "pthread_rwlock_rdlock" + - "pthread_rwlock_tryrdlock" + - "pthread_rwlock_wrlock" + - "pthread_rwlock_trywrlock" + - "pthread_rwlock_unlock" + - "pthread_rwlockattr_init" + - "pthread_rwlockattr_destroy" + - "getsockopt" + - "raise" + - "utimes" + - "dlopen" + - "dlerror" + - "dlsym" + - "dlclose" + - "getaddrinfo" + - "freeaddrinfo" + - "hstrerror" + - "gai_strerror" + - "res_init" + - "gmtime_r" + - "localtime_r" + - "mktime" + - "time" + - "gmtime" + - "localtime" + - "difftime" + - "timegm" + - "mknod" + - "gethostname" + - "endservent" + - "getservbyname" + - "getservbyport" + - "getservent" + - "setservent" + - "getprotobyname" + - "getprotobynumber" + - "chroot" + - "usleep" + - "send" + - "recv" + - "putenv" + - "poll" + - "select" + - "setlocale" + - "localeconv" + - "sem_wait" + - "sem_trywait" + - "sem_post" + - "statvfs" + - "fstatvfs" + - "sigemptyset" + - "sigaddset" + - "sigfillset" + - "sigdelset" + - "sigismember" + - "sigprocmask" + - "sigpending" + - "sysconf" + - "mkfifo" + - "fseeko" + - "ftello" + - "tcdrain" + - "cfgetispeed" + - "cfgetospeed" + - "cfsetispeed" + - "cfsetospeed" + - "tcgetattr" + - "tcsetattr" + - "tcflow" + - "tcflush" + - "tcgetsid" + - "tcsendbreak" + - "mkstemp" + - "mkdtemp" + - "tmpnam" + - "openlog" + - "closelog" + - "setlogmask" + - "syslog" + - "nice" + - "grantpt" + - "posix_openpt" + - "ptsname" + - "unlockpt" + - "strcasestr" + - "getline" + - "lockf" + + - "htonl" + - "htons" + - "ntohl" + - "ntohs" + + - "getsid" + - "pause" + - "mkdirat" + - "openat" + - "fdopendir" + - "readdir_r" + + - "readlinkat" + - "fmemopen" + - "open_memstream" + - "atexit" + - "sigaction" + - "readlink" + - "pselect" + + - "cfmakeraw" + - "cfsetspeed" + + - "confstr" + - "strerror_r" + + - "aligned_alloc" + # unix/linux_like/mod.rs + - "ioctl" + - "sem_destroy" + - "sem_init" + - "fdatasync" + - "mincore" + - "clock_getres" + - "clock_gettime" + - "clock_settime" + - "clock_getcpuclockid" + - "dirfd" + - "pthread_getattr_np" + - "pthread_attr_getstack" + - "pthread_attr_setstack" + - "memalign" + - "setgroups" + - "pipe2" + - "statfs" + - "fstatfs" + - "memrchr" + - "posix_fadvise" + - "futimens" + - "utimensat" + - "duplocale" + - "freelocale" + - "newlocale" + - "uselocale" + - "mknodat" + - "pthread_condattr_getclock" + - "pthread_condattr_setclock" + - "pthread_condattr_setpshared" + - "pthread_mutexattr_setpshared" + - "pthread_rwlockattr_getpshared" + - "pthread_rwlockattr_setpshared" + - "ptsname_r" + - "clearenv" + - "waitid" + - "getresuid" + - "getresgid" + - "acct" + - "brk" + - "sbrk" + - "vfork" + - "setresgid" + - "setresuid" + - "wait4" + - "login_tty" + - "execvpe" + - "fexecve" + - "getifaddrs" + - "freeifaddrs" + - "bind" + - "writev" + - "readv" + - "sendmsg" + - "recvmsg" + - "uname" + - "strchrnul" + - "strftime" + - "strftime_l" + - "strptime" + - "mkostemp" + - "mkostemps" + - "getdomainname" + - "setdomainname" + - "fstatfs64" + - "statvfs64" + - "fstatvfs64" + - "statfs64" + - "creat64" + - "fstat64" + - "fstatat64" + - "ftruncate64" + - "lseek64" + - "lstat64" + - "mmap64" + - "open64" + - "openat64" + - "posix_fadvise64" + - "pread64" + - "pwrite64" + - "readdir64" + - "readdir64_r" + - "stat64" + - "truncate64" + - "preadv64" + - "pwritev64" + - "forkpty" + - "openpty" + - "statx" + +forced_functions: + - "__errno_location" + +force_raw_function_pointer: + - "pthread_create" + +force_local_type: + - "option" + +force_struct_member_type: + "sigaction": + - name: "__sa_handler" + rename-to: "sa_sigaction" + type: "sighandler_t" + "siginfo_t": + - name: "__si_fields" + type: "[c_char; 112]" + "stat": + - name: "st_atim" + replace: + - name: "st_atime" + type: "crate::time_t" + - name: "st_atime_nsec" + type: "i64" + - name: "st_mtim" + replace: + - name: "st_mtime" + type: "crate::time_t" + - name: "st_mtime_nsec" + type: "i64" + - name: "st_ctim" + replace: + - name: "st_ctime" + type: "crate::time_t" + - name: "st_ctime_nsec" + type: "i64" + +force_struct_zero_fill: + - "__mlibc_mutex" + - "__mlibc_cond" + - "__mlibc_fair_rwlock" + +force_macro_type: + "c_ulong": + - "FIOCLEX" + - "FIONBIO" + - "FIONCLEX" + - "FIONREAD" + - "SIOCDEVPRIVATE" + - "SIOCGIFMTU" + - "SIOCSIFMTU" + - "TIOCGWINSZ" + - "TIOCSCTTY" + - "TIOCSWINSZ" + - "SA_NOCLDSTOP" + - "SA_NOCLDWAIT" + - "SA_NODEFER" + - "SA_ONSTACK" + - "SA_RESETHAND" + - "SA_RESTART" + - "SA_SIGINFO" + - "ST_RDONLY" + - "ST_NOSUID" + - "ST_NODEV" + - "ST_NOEXEC" + - "ST_SYNCHRONOUS" + - "ST_MANDLOCK" + - "ST_WRITE" + - "ST_APPEND" + - "ST_IMMUTABLE" + - "ST_NOATIME" + - "ST_NODIRATIME" + "c_uint": + - "IGNBRK" + - "BRKINT" + - "IGNPAR" + - "PARMRK" + - "INPCK" + - "ISTRIP" + - "INLCR" + - "IGNCR" + - "ICRNL" + - "IUCLC" + - "IXON" + - "IXANY" + - "IXOFF" + "c_short": + - "POLLWRNORM" + - "POLLWRBAND" + "usize": + - "NCCS" + - "PTHREAD_STACK_MIN" + - "VEOF" + - "VMIN" + - "VTIME" + - "SIGSTKSZ" + "crate::speed_t": + - "B0" + - "B50" + - "B75" + - "B110" + - "B134" + - "B150" + - "B200" + - "B300" + - "B600" + - "B1200" + - "B1800" + - "B2400" + - "B4800" + - "B9600" + - "B19200" + - "B38400" + - "B57600" + - "B115200" + - "B230400" + - "B460800" + - "B500000" + - "B576000" + - "B921600" + - "B1000000" + - "B1152000" + - "B1500000" + - "B2000000" + - "B2500000" + - "B3000000" + - "B3500000" + - "B4000000" + "crate::tcflag_t": + - "BS1" + - "BSDLY" + - "CBAUD" + - "CBAUDEX" + - "CIBAUD" + - "CLOCAL" + - "CMSPAR" + - "CR1" + - "CR2" + - "CR3" + - "CRDLY" + - "CREAD" + - "CS6" + - "CS7" + - "CS8" + - "CSIZE" + - "CSTOPB" + - "ECHOCTL" + - "ECHOE" + - "ECHOK" + - "ECHOKE" + - "ECHONL" + - "ECHOPRT" + - "EXTPROC" + - "FF1" + - "FFDLY" + - "FLUSHO" + - "HUPCL" + - "ICANON" + - "IEXTEN" + - "ISIG" + - "IUTF8" + - "NLDLY" + - "NOFLSH" + - "OLCUC" + - "ONLCR" + - "PARENB" + - "PARODD" + - "PENDIN" + - "TAB1" + - "TAB2" + - "TAB3" + - "TABDLY" + - "TOSTOP" + - "VT1" + - "VTDLY" + - "XTABS" diff --git a/user/include/mlibc/scripts/rust-libc-header.rs b/user/include/mlibc/scripts/rust-libc-header.rs new file mode 100644 index 0000000..97c8d6c --- /dev/null +++ b/user/include/mlibc/scripts/rust-libc-header.rs @@ -0,0 +1,267 @@ +// This file is autogenerated! +// All changes made will be lost (eventually)! + +use crate::prelude::*; + +use crate::sighandler_t; + +pub type blkcnt64_t = i64; +pub type rlimit64 = crate::rlimit; +pub type rlim64_t = crate::rlim_t; +pub type dirent64 = crate::dirent; +pub type stat64 = crate::stat; +pub type statfs64 = crate::statfs; +pub type statvfs64 = crate::statvfs; +pub type idtype_t = c_uint; +pub type Ioctl = c_ulong; +pub type pthread_t = *mut c_void; + +pub type __u8 = c_uchar; +pub type __u16 = c_ushort; +pub type __s16 = c_short; +pub type __u32 = c_uint; +pub type __s32 = c_int; +pub type __u64 = c_ulonglong; +pub type __s64 = c_longlong; + +pub const RTLD_DEFAULT: *mut c_void = 0i64 as *mut c_void; +pub const RLIM_INFINITY: crate::rlim_t = !0; + +pub type Elf32_Half = u16; +pub type Elf32_Word = u32; +pub type Elf32_Off = u32; +pub type Elf32_Addr = u32; + +pub type Elf64_Half = u16; +pub type Elf64_Word = u32; +pub type Elf64_Off = u64; +pub type Elf64_Addr = u64; +pub type Elf64_Xword = u64; + +s! { + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } +} + +s! { + pub struct dl_phdr_info { + #[cfg(target_pointer_width = "64")] + pub dlpi_addr: Elf64_Addr, + #[cfg(target_pointer_width = "32")] + pub dlpi_addr: Elf32_Addr, + + pub dlpi_name: *const c_char, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phdr: *const Elf64_Phdr, + #[cfg(target_pointer_width = "32")] + pub dlpi_phdr: *const Elf32_Phdr, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phnum: Elf64_Half, + #[cfg(target_pointer_width = "32")] + pub dlpi_phnum: Elf32_Half, + + pub dlpi_adds: c_ulonglong, + pub dlpi_subs: c_ulonglong, + pub dlpi_tls_modid: size_t, + pub dlpi_tls_data: *mut c_void, + } +} + +f! { + pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr { + if ((*cmsg).cmsg_len as usize) < mem::size_of::() { + return 0 as *mut cmsghdr; + }; + let next = (cmsg as usize + super::CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize; + if (next.offset(1)) as usize > max || + next as usize + super::CMSG_ALIGN((*next).cmsg_len as usize) > max { + 0 as *mut cmsghdr + } else { + next as *mut cmsghdr + } + } +} + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; 16], +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; 12], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [0; 12], +}; + +s_no_extra_traits! { + pub struct ifreq { + pub ifru_addr: crate::sockaddr, + pub ifru_dstaddr: crate::sockaddr, + pub ifru_broadaddr: crate::sockaddr, + pub ifru_netmask: crate::sockaddr, + pub ifru_hwaddr: crate::sockaddr, + pub ifru_flags: c_short, + pub ifru_ivalue: c_int, + pub ifru_mtu: c_int, + pub ifru_map: crate::ifmap, + pub ifru_slave: [c_char; 16], + pub ifru_newname: [c_char; 16], + pub ifru_data: *mut c_char, + } +} + +safe_f! { + pub {const} fn makedev(major: c_uint, minor: c_uint) -> crate::dev_t { + let major = major as crate::dev_t; + let minor = minor as crate::dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 32; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } + + pub {const} fn major(dev: crate::dev_t) -> c_uint { + let mut major = 0; + major |= (dev & 0x00000000000fff00) >> 8; + major |= (dev & 0xfffff00000000000) >> 32; + major as c_uint + } + + pub {const} fn minor(dev: crate::dev_t) -> c_uint { + let mut minor = 0; + minor |= (dev & 0x00000000000000ff) >> 0; + minor |= (dev & 0x00000ffffff00000) >> 12; + minor as c_uint + } +} + +extern "C" { + #[link_name = "__gnu_strerror_r"] + pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; +} + +impl siginfo_t { + pub unsafe fn si_status(&self) -> c_int { + #[repr(C)] + struct siginfo_sigchld { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + si_pid: crate::pid_t, + si_uid: crate::uid_t, + si_status: c_int, + si_utime: crate::clock_t, + si_stime: crate::clock_t, + } + (*(self as *const siginfo_t as *const siginfo_sigchld)).si_status + } + + pub unsafe fn si_addr(&self) -> *mut c_void { + #[repr(C)] + struct siginfo_sigfault { + _si_signo: c_int, + _si_errno: c_int, + _si_code: c_int, + si_addr: *mut c_void, + } + (*(self as *const siginfo_t as *const siginfo_sigfault)).si_addr + } +} + +s! { + pub struct sockaddr_nl { + pub nl_family: crate::sa_family_t, + nl_pad: c_ushort, + pub nl_pid: u32, + pub nl_groups: u32, + } +} + +// linux/netlink.h +pub const NLA_ALIGNTO: c_int = 4; + +pub const NETLINK_ROUTE: c_int = 0; +pub const NETLINK_UNUSED: c_int = 1; +pub const NETLINK_USERSOCK: c_int = 2; +pub const NETLINK_FIREWALL: c_int = 3; +pub const NETLINK_SOCK_DIAG: c_int = 4; +pub const NETLINK_NFLOG: c_int = 5; +pub const NETLINK_XFRM: c_int = 6; +pub const NETLINK_SELINUX: c_int = 7; +pub const NETLINK_ISCSI: c_int = 8; +pub const NETLINK_AUDIT: c_int = 9; +pub const NETLINK_FIB_LOOKUP: c_int = 10; +pub const NETLINK_CONNECTOR: c_int = 11; +pub const NETLINK_NETFILTER: c_int = 12; +pub const NETLINK_IP6_FW: c_int = 13; +pub const NETLINK_DNRTMSG: c_int = 14; +pub const NETLINK_KOBJECT_UEVENT: c_int = 15; +pub const NETLINK_GENERIC: c_int = 16; +pub const NETLINK_SCSITRANSPORT: c_int = 18; +pub const NETLINK_ECRYPTFS: c_int = 19; +pub const NETLINK_RDMA: c_int = 20; +pub const NETLINK_CRYPTO: c_int = 21; +pub const NETLINK_INET_DIAG: c_int = NETLINK_SOCK_DIAG; + +pub const NLM_F_REQUEST: c_int = 1; +pub const NLM_F_MULTI: c_int = 2; +pub const NLM_F_ACK: c_int = 4; +pub const NLM_F_ECHO: c_int = 8; +pub const NLM_F_DUMP_INTR: c_int = 16; +pub const NLM_F_DUMP_FILTERED: c_int = 32; + +pub const NLM_F_ROOT: c_int = 0x100; +pub const NLM_F_MATCH: c_int = 0x200; +pub const NLM_F_ATOMIC: c_int = 0x400; +pub const NLM_F_DUMP: c_int = NLM_F_ROOT | NLM_F_MATCH; + +pub const NLM_F_REPLACE: c_int = 0x100; +pub const NLM_F_EXCL: c_int = 0x200; +pub const NLM_F_CREATE: c_int = 0x400; +pub const NLM_F_APPEND: c_int = 0x800; + +pub const NLM_F_NONREC: c_int = 0x100; +pub const NLM_F_BULK: c_int = 0x200; + +pub const NLM_F_CAPPED: c_int = 0x100; +pub const NLM_F_ACK_TLVS: c_int = 0x200; + +pub const NETLINK_ADD_MEMBERSHIP: c_int = 1; +pub const NETLINK_DROP_MEMBERSHIP: c_int = 2; +pub const NETLINK_PKTINFO: c_int = 3; +pub const NETLINK_BROADCAST_ERROR: c_int = 4; +pub const NETLINK_NO_ENOBUFS: c_int = 5; +pub const NETLINK_RX_RING: c_int = 6; +pub const NETLINK_TX_RING: c_int = 7; +pub const NETLINK_LISTEN_ALL_NSID: c_int = 8; +pub const NETLINK_LIST_MEMBERSHIPS: c_int = 9; +pub const NETLINK_CAP_ACK: c_int = 10; +pub const NETLINK_EXT_ACK: c_int = 11; +pub const NETLINK_GET_STRICT_CHK: c_int = 12; + +pub const NLA_F_NESTED: c_int = 1 << 15; +pub const NLA_F_NET_BYTEORDER: c_int = 1 << 14; +pub const NLA_TYPE_MASK: c_int = !(NLA_F_NESTED | NLA_F_NET_BYTEORDER); diff --git a/user/include/mlibc/scripts/rust-libc.py b/user/include/mlibc/scripts/rust-libc.py new file mode 100644 index 0000000..85a5b79 --- /dev/null +++ b/user/include/mlibc/scripts/rust-libc.py @@ -0,0 +1,722 @@ +#!/bin/env python3 + +# HOW THIS WORKS +# +# This script takes mlibc header files and generates bindings to be used with rust's "libc" crate. +# A configuration file is needed for its proper function; an example is provided alongside this +# script. Please do note that it is used for managarm, which lives under `unix/linux_like` in the +# "libc" crate. If your OS does not live under this directory, but e.g. under just `unix` instead, +# you will need to adapt the configuration to fit your use. +# +# HOW TO USE +# +# > python rust-libc [] +# +# By default, the script parses all header files in the directory supplied, except for when a +# single header is provided, where it will only parse that. + +import argparse +import io +import os +import pathlib +import string +import subprocess +import sys + +import clang.cindex +import colorama +import yaml +from clang.cindex import Cursor, CursorKind, TokenKind, TypeKind +from dataclasses import dataclass + +dry_run = True +errors_emitted = 0 + + +def log_err(prefix, msg): + global errors_emitted + + print( + f"{colorama.Fore.RED}{prefix}{colorama.Style.RESET_ALL}: {msg}", file=sys.stderr + ) + errors_emitted += 1 + + +def emit(msg): + if not dry_run: + print(msg) + + +def no_system_includes(cursor, level): + """filter out verbose stuff from system include files""" + return (level != 1) or ( + cursor.location.file is not None + and not cursor.location.file.name.startswith("/usr/include") + ) + + +class Type: + def __init__( + self, + c: clang.cindex.Cursor, + t: clang.cindex.Type = None, + convert_arrays_to_ptrs=False, + ): + self.cursor = c + self.type = t if t else c.type + self.convert_arrays_to_ptrs = convert_arrays_to_ptrs + + @property + def kind(self): + return self.type.kind + + def convert_ptr_type(self, c, ty, is_pointee=False): + pointee = ty if is_pointee else ty.get_pointee() + + if pointee.kind == TypeKind.FUNCTIONPROTO: + arg_list = [] + for f in pointee.argument_types(): + arg_list.append(f"{Type(c, f)}") + args = ", ".join(arg_list) + ret_type = Type(c, pointee.get_result()) + if c.semantic_parent.spelling in config["force_raw_function_pointer"]: + return f'extern "C" fn({args})' + ( + f" -> {ret_type}" if str(ret_type) != "c_void" else "" + ) + else: + return f'Option {ret_type}>" if str(ret_type) != "c_void" else ">" + ) + + is_mut = not pointee.spelling.startswith("const") + prefix = "*" + ("mut" if is_mut else "const") + " " + + type_iter = pointee + + while type_iter.kind == TypeKind.POINTER: + prefix += "*mut " + type_iter = type_iter.get_pointee() + + t = type_iter.spelling.removeprefix("const ") + tokens = t.split(" ") + + match tokens: + case ["char", *_]: + return prefix + "c_char" + case ["struct", x, *_] if x in config["force_local_type"]: + return prefix + x + case ["struct", x, *_]: + return f"{prefix} crate::{x}" + case ["int", *_]: + return prefix + "c_int" + case ["unsigned", "char", *_]: + return prefix + "c_uchar" + case ["unsigned", "short", *_]: + return prefix + "c_ushort" + case ["unsigned", "int", *_]: + return prefix + "c_uint" + case ["unsigned", "long", *_]: + return prefix + "c_ulong" + case ["unsigned", *_]: + log_err("unhandled unsigned type", f"'{t}'") + case ["void", *_]: + return prefix + "c_void" + case ["double", *_]: + return prefix + "c_double" + case [*_]: + return prefix + "crate::" + t + + def __str__(self): + typename = str(self.kind) + match self.kind: + case TypeKind.VOID: + typename = "c_void" + case TypeKind.LONG: + typename = "c_long" + case TypeKind.LONGLONG: + typename = "c_longlong" + case TypeKind.UINT: + typename = "c_uint" + case TypeKind.INT: + typename = "c_int" + case TypeKind.ULONG: + typename = "c_ulong" + case TypeKind.ULONGLONG: + typename = "c_ulonglong" + case TypeKind.USHORT: + typename = "c_ushort" + case TypeKind.SHORT: + typename = "c_short" + case TypeKind.CHAR_S: + typename = "c_char" + case TypeKind.UCHAR: + typename = "c_uchar" + case TypeKind.DOUBLE: + typename = "c_double" + case TypeKind.LONGDOUBLE: + typename = "c_longdouble" + case TypeKind.FLOAT: + typename = "c_float" + case TypeKind.CONSTANTARRAY: + if self.convert_arrays_to_ptrs: + typename = self.convert_ptr_type( + self.cursor, self.type.get_array_element_type(), is_pointee=True + ) + else: + typename = f"[{str(Type(self.cursor, self.type.get_array_element_type()))}; {self.type.element_count}]" + case TypeKind.INCOMPLETEARRAY: + typename = "*mut " + str( + Type(self.cursor, self.type.get_array_element_type()) + ) + case TypeKind.ELABORATED: + if self.is_va_list(): + typename = "*mut c_char" + elif self.cursor.is_anonymous(): + typename = "crate::" + Type.cursor_name(self.cursor) + elif self.type.get_declaration().displayname in ( + "uint8_t", + "__mlibc_uint8", + ): + typename = "u8" + elif self.type.get_declaration().displayname in ( + "int8_t", + "__mlibc_int8", + ): + typename = "i8" + elif self.type.get_declaration().displayname in ( + "uint16_t", + "__mlibc_uint16", + ): + typename = "u16" + elif self.type.get_declaration().displayname in ( + "int16_t", + "__mlibc_int16", + ): + typename = "i16" + elif self.type.get_declaration().displayname in ( + "uint32_t", + "__mlibc_uint32", + ): + typename = "u32" + elif self.type.get_declaration().displayname in ( + "int32_t", + "__mlibc_int32", + ): + typename = "i32" + elif self.type.get_declaration().displayname in ( + "uint64_t", + "__mlibc_uint64", + ): + typename = "u64" + elif self.type.get_declaration().displayname in ( + "int64_t", + "__mlibc_int64", + ): + typename = "i64" + elif self.type.get_declaration().displayname in ( + "intptr_t", + "__mlibc_intptr", + ): + typename = "isize" + elif self.type.get_declaration().displayname in ("__mlibc_size"): + typename = "usize" + else: + typename = "crate::" + str(self.type.get_declaration().displayname) + case TypeKind.POINTER: + typename = self.convert_ptr_type(self.cursor, self.type) + case TypeKind.TYPEDEF: + return str(self.type.spelling) + case TypeKind.RECORD: + return "" + return typename + + @property + def canonical(self): + return str(Type(self.type.get_canonical())) + + def is_valid(self): + return self.kind != TypeKind.INVALID + + def is_va_list(self): + return ( + self.kind == TypeKind.ELABORATED + and self.type.get_declaration().displayname == "__builtin_va_list" + ) + + def escape_name(name: str): + if name in ("type", "in"): + return f"r#{name}" + return name + + def cursor_name(c: Cursor): + d = c.type.get_declaration() + if d and d.is_anonymous(): + return ( + f"anon_{pathlib.Path(str(d.location.file)).stem}_line{d.location.line}" + ) + return Type.escape_name(c.displayname) + + +@dataclass +class State: + functions = [] + macros = [] + types = [] + structs = [] + variables = [] + + +@dataclass +class RustBindingGenerator: + config: dict + in_function_block = False + in_struct_block = False + in_union_block = False + + def handle_macro(self, cursor, gen, state): + def is_num(s): + if s.removeprefix("0o").isnumeric(): + return True + if set(s.removeprefix("0x")).issubset(string.hexdigits): + return True + return False + + done = False + is_negative = False + + assert len(gen) >= 1 + assert gen[0].kind == TokenKind.IDENTIFIER + gen.pop(0) + + if len(gen) >= 1: + tokens = [] + c_type = "c_int" + is_unsigned = False + i = 0 + while not done and gen and i < len(gen): + c_type = "int" + if gen[i].kind == TokenKind.PUNCTUATION and gen[i].spelling in ( + "(", + ")", + ): + if not (i == 0 or i == (len(gen) - 1)): + tokens.append(gen[i].spelling) + i += 1 + elif gen[i].kind == TokenKind.PUNCTUATION and gen[i].spelling == "-": + is_unsigned = False + i += 1 + elif gen[i].kind in ( + TokenKind.LITERAL, + TokenKind.IDENTIFIER, + TokenKind.PUNCTUATION, + ): + spelling = gen[i].spelling + if spelling.endswith("ULL") and is_num(spelling[:-3]): + spelling = spelling.removesuffix("ULL") + c_type = "longlong" + is_unsigned = True + if spelling.endswith("LL") and is_num(spelling[:-2]): + spelling = spelling.removesuffix("LL") + c_type = "longlong" + is_unsigned = False + if spelling.endswith("UL") and is_num(spelling[:-2]): + spelling = spelling.removesuffix("UL") + c_type = "long" + is_unsigned = True + elif spelling.endswith("L") and is_num(spelling[:-1]): + spelling = spelling.removesuffix("L") + c_type = "long" + is_unsigned = False + elif spelling.endswith("U") and is_num(spelling[:-1]): + spelling = spelling.removesuffix("U") + is_unsigned = True + + if ( + is_num(spelling) + and spelling.startswith("0") + and not spelling.startswith("0x") + and spelling != "0" + ): + spelling = f"0o{spelling[1:]}" + + tokens.append(spelling) + i += 1 + else: + log_err( + f"unexpected token in macro '{cursor.displayname}'", + f"{gen[i].kind} {gen[i].spelling} at {gen[0].location}, skipping macro", + ) + done = True + c_type = "c_" + ("u" if is_unsigned else "") + c_type + if not self.is_ignored("macros", state.macros, cursor.displayname): + for name in config["force_macro_type"]: + if cursor.displayname in config["force_macro_type"][name]: + c_type = name + break + emit( + "pub const {}: {} = {}{};".format( + cursor.displayname, + c_type, + "-" if is_negative else "", + "".join(tokens), + ) + ) + state.macros.append(cursor.displayname) + + def indent(self, level=0): + if self.in_function_block or self.in_struct_block or self.in_union_block: + return "\t" * (level + 1) + return "" + + def handle_field_decl(self, cursor, c, inline_defs): + tc = Type(c) + assert tc.is_valid() + name = str(tc) + if c.is_anonymous(): + name = Type.cursor_name(c) + if Type.cursor_name(cursor) in config["force_struct_member_type"]: + info = config["force_struct_member_type"][Type.cursor_name(cursor)] + if list(filter(lambda x: x["name"] == c.displayname, info)): + detail = next(filter(lambda x: x["name"] == c.displayname, info)) + if "type" in detail: + assert "replace" not in detail + name = ( + detail["rename-to"] if "rename-to" in detail else c.displayname + ) + emit( + self.indent(1) + + f"pub {Type.escape_name(name)}: {detail['type']}," + ) + if inline_defs[-1].get_usr() == c.type.get_declaration().get_usr(): + inline_defs.pop() + return + elif "replace" in detail: + for member in detail["replace"]: + emit( + self.indent(1) + + "pub {}: {},".format(member["name"], member["type"]) + ) + return + else: + log_err( + "invalid configuration", + f"missing info for override for struct '{c.displayname}'", + ) + emit(self.indent(1) + f"pub {Type.escape_name(c.displayname)}: {name},") + + def handle_data_structs(self, cursor, state, level=0): + inline_defs = [] + + children = [i for i in cursor.get_children()] + + if ( + not children + and Type.cursor_name(cursor) not in config["forced_empty_structs"] + ): + return + + if self.in_struct_block and cursor.kind != CursorKind.STRUCT_DECL: + emit("}") + self.in_struct_block = False + if self.in_union_block and cursor.kind != CursorKind.UNION_DECL: + emit("}") + self.in_union_block = False + + match cursor.kind: + case CursorKind.STRUCT_DECL: + if not self.in_struct_block: + emit("s! {") + self.in_struct_block = True + packed = False + for m in cursor.get_children(): + if CursorKind.PACKED_ATTR == m.kind: + packed = True + break + if packed: + emit(self.indent() + "#[repr(packed)]") + emit(self.indent() + f"pub struct {Type.cursor_name(cursor)} {{") + state.structs.append(Type.cursor_name(cursor)) + case CursorKind.UNION_DECL: + if not self.in_union_block: + emit("s_no_extra_traits! {") + self.in_union_block = True + emit("#[repr(C)]") + emit(self.indent() + f"pub union {Type.cursor_name(cursor)} {{") + state.structs.append(Type.cursor_name(cursor)) + case CursorKind.ENUM_DECL: + if cursor.type.get_declaration().is_anonymous() and level == 1: + # ignore anonymous enums in the global scope + return + emit(self.indent() + f"pub enum {Type.cursor_name(cursor)} {{") + state.structs.append(Type.cursor_name(cursor)) + case _: + log_err("unhandled data struct kind", f"{cursor.kind}") + + if Type.cursor_name(cursor) in config["force_struct_zero_fill"]: + struct_size = cursor.type.get_size() + emit("\t\t#[doc(hidden)]") + emit(f"\t\tsize: [u8; {struct_size}],") + else: + for c in children: + match c.kind: + case CursorKind.FIELD_DECL: + self.handle_field_decl(cursor, c, inline_defs) + case CursorKind.STRUCT_DECL | CursorKind.UNION_DECL: + inline_defs.append(c) + case CursorKind.ENUM_CONSTANT_DECL: + emit(f"{c.displayname} = {c.enum_value},") + case CursorKind.PACKED_ATTR: + pass + case _: + log_err(f"unhandled {cursor.kind} member", f"kind {c.kind}") + emit(self.indent() + "}") + + if cursor.kind == CursorKind.ENUM_DECL: + emit(f"impl Copy for {Type.cursor_name(cursor)} " + "{}") + emit(f"impl Clone for {Type.cursor_name(cursor)} " + "{") + emit(f"\tfn clone(&self) -> {Type.cursor_name(cursor)} {{") + emit("\t\t*self") + emit("\t}") + emit("}") + + for s in inline_defs: + self.handle_data_structs(s, state, level + 1) + + def is_ignored(self, typename, ignorelist, name): + if typename == "macros" and name.startswith("_") and name.endswith("_H"): + return True + if name in ignorelist: + return True + if "forced_" + typename in config and name in config["forced_" + typename]: + return False + if name.startswith("__"): + return True + if "ignored_" + typename in config and name in config["ignored_" + typename]: + return True + return False + + def is_ignored_file(base_dir: pathlib.Path, file: pathlib.Path, config): + if not str(file).startswith(str(base_dir)): + return True + + for p in config["ignored_files"]: + stripped_file = str(file).removeprefix(str(base_dir)).removeprefix("/") + if stripped_file == p: + return True + for p in config["includes"]: + if str(base_dir).startswith(p): + return True + return False + + def from_cursor(self, base_dir, header, cursor, filter_pred, level=0): + global state + + if cursor.location.file: + f = pathlib.Path(str(cursor.location.file)) + + if RustBindingGenerator.is_ignored_file(base_dir, f, config): + return + + if filter_pred(cursor, level): + t = Type(cursor) + + if self.in_struct_block and cursor.kind != CursorKind.STRUCT_DECL: + emit("}") + self.in_struct_block = False + if self.in_union_block and cursor.kind != CursorKind.STRUCT_DECL: + emit("}") + self.in_union_block = False + if self.in_function_block and cursor.kind != CursorKind.FUNCTION_DECL: + emit("}") + self.in_function_block = False + + match cursor.kind: + case CursorKind.MACRO_DEFINITION: + if not self.is_ignored("macros", [], cursor.displayname): + gen = [token for token in cursor.get_tokens()] + self.handle_macro(cursor, gen, state) + case CursorKind.STRUCT_DECL: + if self.is_ignored("structs", state.structs, cursor.displayname): + return + + self.handle_data_structs(cursor, state, level) + case CursorKind.UNION_DECL: + if self.is_ignored("unions", state.structs, cursor.displayname): + return + + self.handle_data_structs(cursor, state, level) + case CursorKind.ENUM_DECL: + if self.is_ignored("enums", state.structs, cursor.displayname): + return + + self.handle_data_structs(cursor, state, level) + case CursorKind.TYPEDEF_DECL: + if not self.is_ignored("types", state.types, cursor.displayname): + underlying = Type(cursor, cursor.underlying_typedef_type) + self.from_cursor( + base_dir, + header, + cursor.underlying_typedef_type.get_declaration(), + filter_pred, + level, + ) + if cursor.displayname not in state.structs: + emit(f"pub type {cursor.displayname} = {underlying};") + state.types.append(cursor.displayname) + case CursorKind.FUNCTION_DECL: + if self.is_ignored("functions", state.functions, cursor.spelling): + return + + args = [] + for c in cursor.get_arguments(): + arg_name = c.displayname if c.displayname else f"arg{len(args)}" + tc = Type(c, convert_arrays_to_ptrs=True) + if tc.is_va_list(): + arg_name = c.displayname if c.displayname else "arg_list" + assert tc.is_valid() + if str(tc): + args.append(f"{Type.escape_name(arg_name)}: {str(tc)}") + if cursor.type.is_function_variadic(): + args.append("...") + arg_str = ", ".join(args) + ret_type = str(Type(cursor, cursor.type.get_result())) + if not self.in_function_block: + emit('extern "C" {') + self.in_function_block = True + emit( + f"\tpub fn {cursor.spelling}({arg_str})" + + (f" -> {ret_type};" if ret_type != "c_void" else ";") + ) + state.functions.append(cursor.spelling) + case CursorKind.TRANSLATION_UNIT: + for c in cursor.get_children(): + self.from_cursor(base_dir, header, c, filter_pred, level + 1) + case CursorKind.INCLUSION_DIRECTIVE: + pass + case CursorKind.VAR_DECL: + if self.is_ignored( + "var_declarations", state.variables, cursor.spelling + ): + return + else: + log_err( + "munhandled cursor type", + f"VAR_DECL of '{cursor.spelling}'", + ) + case CursorKind.STATIC_ASSERT | CursorKind.UNEXPOSED_DECL: + pass + case CursorKind.MACRO_INSTANTIATION: + # TODO: cross-reference this with constant arrays? + pass + case _: + log_err( + "unhandled cursor type", + f"{cursor.kind} {cursor.spelling} {cursor.displayname} {cursor.location}", + ) + + if t.is_valid(): + emit(f"type '{t}' canonical '{t.canonical}'") + + if level == 0 and self.in_struct_block: + emit("}") + self.in_struct_block = False + + if level == 0 and self.in_union_block: + emit("}") + self.in_union_block = False + + if level == 0 and self.in_function_block: + emit("}") + self.in_function_block = False + + +def parse(file: pathlib.Path, base_dir: pathlib.Path): + index = clang.cindex.Index.create() + tu = None + + try: + tu = index.parse( + base_dir / file, + args=[f"-I{p}" for p in config["includes"]] + ["-I" + str(base_dir), "-D_GNU_SOURCE"], + options=clang.cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD + | clang.cindex.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES, + ) + except: + log_err("parsing error", file) + return + + assert tu + + if not RustBindingGenerator.is_ignored_file(base_dir, base_dir / file, config): + if tu.diagnostics: + [log_err("compile error", d) for d in tu.diagnostics] + print(f"\n{errors_emitted + 1} errors emitted") + exit(errors_emitted + 1) + + parser = RustBindingGenerator(config) + emit("") + print(f"// {tu.spelling.removeprefix(str(base_dir)).removeprefix('/')}") + parser.from_cursor(base_dir, file, tu.cursor, no_system_includes) + + +def gcc_install_path(gcc: str) -> pathlib.Path | None: + try: + result = subprocess.run( + [gcc, '-print-search-dirs'], + capture_output=True, + text=True, + check=True + ) + for line in result.stdout.splitlines(): + if line.startswith('install:'): + return (pathlib.Path(line.removeprefix('install: ').strip()) / 'include').resolve() + except subprocess.CalledProcessError as e: + print(f"Error running {gcc}:", e) + except FileNotFoundError: + print(f"{gcc} not found") + return None + + +if __name__ == "__main__": + argparser = argparse.ArgumentParser() + argparser.add_argument("-n", dest="dry_run", action="store_true") + argparser.add_argument("path") + argparser.add_argument("gcc") + argparser.add_argument("file", nargs="?") + + args = argparser.parse_args() + + dry_run = args.dry_run + + colorama.just_fix_windows_console() + + with io.open(os.path.join(os.path.dirname(__file__), "rust-libc-config.yml"), "r") as f: + config = yaml.load(f, yaml.CSafeLoader) + + path = pathlib.Path(args.path) + + gcc_include_path = gcc_install_path(args.gcc) + if not gcc_include_path: + print("could not determine gcc's include directory") + exit(1) + + gcc_include_path = os.path.relpath(pathlib.Path(gcc_include_path), pathlib.Path.cwd()) + if "includes" not in config: + config["includes"] = list() + config["includes"].insert(0, gcc_include_path) + + with io.open(os.path.join(os.path.dirname(__file__), "rust-libc-header.rs"), "r") as f: + emit(f.read()) + + state = State() + + if not args.file: + for header in sorted(path.rglob("*.h")): + parse(str(header).removeprefix(str(path)).removeprefix("/"), path) + else: + parse(pathlib.Path(args.file), path) + + if errors_emitted > 0: + print(f"\n{errors_emitted} errors emitted") + + exit(errors_emitted) diff --git a/user/include/mlibc/scripts/to_integral.hpp b/user/include/mlibc/scripts/to_integral.hpp new file mode 100644 index 0000000..6c48f68 --- /dev/null +++ b/user/include/mlibc/scripts/to_integral.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include + +template +constexpr void macro_print(const char *name, E val) { + printf("%s = %ld\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, signed long long val) { + printf("%s = %lld\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, signed long val) { + printf("%s = %ld\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, signed int val) { + printf("%s = %d\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, signed short val) { + printf("%s = %hd\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, signed char val) { + printf("%s = %hhd\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, unsigned long long val) { + printf("%s = %llu\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, unsigned long val) { + printf("%s = %lu\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, unsigned int val) { + printf("%s = %u\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, unsigned short val) { + printf("%s = %hu\n", name, val); +} + +template<> +constexpr void macro_print(const char *name, unsigned char val) { + printf("%s = %hhu ('%c')\n", name, val, val); +} + +template<> +constexpr void macro_print(const char *name, const char *val) { + printf("%s = \"%s\"\n", name, val); +} diff --git a/user/include/mlibc/subprojects/.wraplock b/user/include/mlibc/subprojects/.wraplock new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/subprojects/freestnd-c-hdrs.wrap b/user/include/mlibc/subprojects/freestnd-c-hdrs.wrap new file mode 100644 index 0000000..753cfb1 --- /dev/null +++ b/user/include/mlibc/subprojects/freestnd-c-hdrs.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://codeberg.org/OSDev/freestnd-c-hdrs.git +revision = d33711241b46ecb8f2ad33927fcefdcb3ac0162e +patch_directory = freestnd-c-hdrs diff --git a/user/include/mlibc/subprojects/freestnd-cxx-hdrs.wrap b/user/include/mlibc/subprojects/freestnd-cxx-hdrs.wrap new file mode 100644 index 0000000..7b8de6f --- /dev/null +++ b/user/include/mlibc/subprojects/freestnd-cxx-hdrs.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://codeberg.org/OSDev/freestnd-cxx-hdrs.git +revision = a6b351e0ab3e74e5789b01fa1447e4cd62373da7 +patch_directory = freestnd-cxx-hdrs diff --git a/user/include/mlibc/subprojects/frigg.wrap b/user/include/mlibc/subprojects/frigg.wrap new file mode 100644 index 0000000..c1a9f85 --- /dev/null +++ b/user/include/mlibc/subprojects/frigg.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://github.com/managarm/frigg.git +revision = 98220ab8f3ac6b1f146c360598a334f7f1fc06e1 diff --git a/user/include/mlibc/subprojects/packagefiles/freestnd-c-hdrs/meson.build b/user/include/mlibc/subprojects/packagefiles/freestnd-c-hdrs/meson.build new file mode 100644 index 0000000..4a4c077 --- /dev/null +++ b/user/include/mlibc/subprojects/packagefiles/freestnd-c-hdrs/meson.build @@ -0,0 +1,10 @@ +project('freestnd-c-hdrs') + +cpu = host_machine.cpu_family() +if cpu == 'x86' + cpu = 'i686' +endif + +incl = include_directories(cpu / 'include') + +freestnd_c_hdrs_dep = declare_dependency(include_directories: incl) diff --git a/user/include/mlibc/subprojects/packagefiles/freestnd-cxx-hdrs/meson.build b/user/include/mlibc/subprojects/packagefiles/freestnd-cxx-hdrs/meson.build new file mode 100644 index 0000000..625592a --- /dev/null +++ b/user/include/mlibc/subprojects/packagefiles/freestnd-cxx-hdrs/meson.build @@ -0,0 +1,10 @@ +project('freestnd-cxx-hdrs') + +cpu = host_machine.cpu_family() +if cpu == 'x86' + cpu = 'i686' +endif + +incl = include_directories(cpu / 'include') + +freestnd_cxx_hdrs_dep = declare_dependency(include_directories: incl) diff --git a/user/include/mlibc/sysdeps/aero/.clang-format b/user/include/mlibc/sysdeps/aero/.clang-format new file mode 100644 index 0000000..4662692 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/.clang-format @@ -0,0 +1,2 @@ +--- +DisableFormat: true diff --git a/user/include/mlibc/sysdeps/aero/crt-x86_64/crt0.S b/user/include/mlibc/sysdeps/aero/crt-x86_64/crt0.S new file mode 100644 index 0000000..62298e3 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/crt-x86_64/crt0.S @@ -0,0 +1,10 @@ +.section .text + +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + +.size _start, . - _start +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/aero/crt-x86_64/crti.S b/user/include/mlibc/sysdeps/aero/crt-x86_64/crti.S new file mode 100644 index 0000000..f04679c --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/crt-x86_64/crti.S @@ -0,0 +1,10 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/aero/crt-x86_64/crtn.S b/user/include/mlibc/sysdeps/aero/crt-x86_64/crtn.S new file mode 100644 index 0000000..1b61d5a --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/crt-x86_64/crtn.S @@ -0,0 +1,8 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/aero/generic/aero.cpp b/user/include/mlibc/sysdeps/aero/generic/aero.cpp new file mode 100644 index 0000000..80f9c6f --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/aero.cpp @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 + +struct Slice { + void *ptr; + uint64_t len; +}; + +/// Helper function to construct a slice vector from the provided argument +/// array. A slice basically consists of a pointer to the data and the length of +/// it. +/// +/// ## Examples +/// ```cc +/// auto slice = create_slice({ "hello", "world" }); +/// ``` +/// +/// The `slice` will look like the following: +/// +/// ```cc +/// vector( +/// Slice { .ptr: hello_ptr, .size: hello_size }, +/// Slice { .ptr: world_ptr, .size: world_size } +/// ) +/// ``` +static frg::vector create_slice(char *const arg[]) { + if (arg == nullptr) { + return frg::vector{getAllocator()}; + } + + // Find out the length of arg: + size_t len = 0; + + while (arg[len] != nullptr) { + len += 1; + } + + frg::vector params{getAllocator()}; + params.resize(len); + + // Construct the slice vector: + for (size_t i = 0; i < len; ++i) { + params[i].ptr = (void *)arg[i]; + params[i].len = strlen(arg[i]); + } + + return params; +} + +namespace mlibc { +int sys_uname(struct utsname *buf) { + auto result = syscall(SYS_UNAME, buf); + + if (result < 0) { + return -result; + } + + return result; +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + // auto result = syscall(SYS_FUTEX_WAIT, pointer, expected, time); + // + // if (result < 0) { + // return -result; + // } + // + return 0; +} + +int sys_futex_wake(int *pointer) { + // auto result = syscall(SYS_FUTEX_WAKE, pointer); + // + // if (result < 0) { + // return -result; + // } + // + return 0; +} + +int sys_tcb_set(void *pointer) { + auto result = syscall(SYS_ARCH_PRCTL, ARCH_SET_FS, (uint64_t)pointer); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, + off_t offset, void **window) { + auto result = syscall(SYS_MMAP, hint, size, prot, flags, fd, offset); + + if (result < 0) { + return -result; + } + + *window = (void *)result; + return 0; +} + +int sys_vm_unmap(void *address, size_t size) { + return syscall(SYS_MUNMAP, address, size); +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + auto res = syscall(SYS_MPROTECT, pointer, size, prot); + if (res < 0) + return -res; + + return 0; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +void sys_libc_panic() { + mlibc::infoLogger() << "libc_panic: panicked at 'unknown'" << frg::endlog; + __ensure(!syscall(SYS_BACKTRACE)); + + sys_exit(1); +} + +void sys_libc_log(const char *msg) { syscall(SYS_LOG, msg, strlen(msg)); } + +void sys_exit(int status) { + syscall(SYS_EXIT, status); + + __builtin_unreachable(); +} + +#ifndef MLIBC_BUILDING_RTLD + +pid_t sys_getpid() { + auto result = syscall(SYS_GETPID); + __ensure(result >= 0); + + return result; +} + +pid_t sys_getppid() { + auto result = syscall(SYS_GETPPID); + __ensure(result != 0); + + return result; +} + +int sys_kill(int pid, int sig) { + auto result = syscall(SYS_KILL, pid, sig); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec ts; + auto result = syscall(SYS_GETTIME, clock, &ts); + + if (result < 0) { + return -result; + } + + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + + return 0; +} + +int sys_getcwd(char *buffer, size_t size) { + auto result = syscall(SYS_GETCWD, buffer, size); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_chdir(const char *path) { + auto result = syscall(SYS_CHDIR, path, strlen(path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + auto result = syscall(SYS_GETHOSTNAME, buffer, bufsize); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_sleep(time_t *sec, long *nanosec) { + struct timespec ts = {.tv_sec = *sec, .tv_nsec = *nanosec}; + + auto result = syscall(SYS_SLEEP, &ts); + + if (result < 0) { + return -result; + } + + return 0; +} + +pid_t sys_getpgid(pid_t pid, pid_t *pgid) { + auto ret = syscall(SYS_GETPGID, pid); + if(int e = sc_error(ret); e) + return e; + *pgid = ret; + return 0; +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + auto ret = syscall(SYS_SETPGID, pid, pgid); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +uid_t sys_getuid() { + mlibc::infoLogger() << "mlibc: sys_setuid is a stub" << frg::endlog; + return 0; +} + +uid_t sys_geteuid() { + mlibc::infoLogger() << "mlibc: sys_seteuid is a stub" << frg::endlog; + return 0; +} + +int sys_setsid(pid_t *sid) { + auto ret = syscall(SYS_SETSID); + if(int e = sc_error(ret); e) + return e; + *sid = ret; + return 0; +} + +int sys_seteuid(uid_t euid) UNIMPLEMENTED("sys_seteuid") + + gid_t sys_getgid() { + mlibc::infoLogger() << "mlibc: sys_setgid is a stub" << frg::endlog; + return 0; +} + +gid_t sys_getegid() { + mlibc::infoLogger() << "mlibc: sys_getegid is a stub" << frg::endlog; + return 0; +} + +int sys_setgid(gid_t gid) { + mlibc::infoLogger() << "mlibc: sys_setgid is a stub" << frg::endlog; + return 0; +} + +int sys_setegid(gid_t egid) { + mlibc::infoLogger() << "mlibc: sys_setegid is a stub" << frg::endlog; + return 0; +} + +void sys_yield() { + mlibc::infoLogger() << "mlibc: sys_yield is a stub" << frg::endlog; + __ensure(!syscall(SYS_BACKTRACE)); +} + +int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + auto result = syscall(SYS_CLONE, (uintptr_t)__mlibc_start_thread, stack); + + if (result < 0) { + return -result; + } + + *tid_out = (pid_t)result; + return 0; +} + +int sys_thread_setname(void *tcb, const char *name) { + mlibc::infoLogger() << "The name of this thread is " << name << frg::endlog; + return 0; +} + +void sys_thread_exit() { + syscall(SYS_EXIT); + __builtin_trap(); +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, + pid_t *ret_pid) { + if (ru) { + mlibc::infoLogger() + << "mlibc: struct rusage in sys_waitpid is unsupported" + << frg::endlog; + return ENOSYS; + } + + auto result = syscall(SYS_WAITPID, pid, status, flags); + + if (result < 0) { + return -result; + } + + *ret_pid = result; + return 0; +} + +int sys_fork(pid_t *child) { + auto result = syscall(SYS_FORK); + + if (result < 0) { + return -result; + } + + *child = result; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + auto envv_slice = create_slice(envp); + auto argv_slice = create_slice(argv); + + auto path_ptr = (uintptr_t)path; + auto path_len = strlen(path); + + auto result = + syscall(SYS_EXEC, path_ptr, path_len, argv_slice.data(), + argv_slice.size(), envv_slice.data(), envv_slice.size()); + + if (result < 0) { + return -result; + } + + __builtin_unreachable(); +} + +// int sys_getentropy(void *buffer, size_t length) +// UNIMPLEMENTED("sys_getentropy") + +#endif +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/aero/generic/entry.cpp b/user/include/mlibc/sysdeps/aero/generic/entry.cpp new file mode 100644 index 0000000..2d11d60 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/entry.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], + char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux + // sysdeps) + auto result = + main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} diff --git a/user/include/mlibc/sysdeps/aero/generic/filesystem.cpp b/user/include/mlibc/sysdeps/aero/generic/filesystem.cpp new file mode 100644 index 0000000..95c49b9 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/filesystem.cpp @@ -0,0 +1,494 @@ +#include "mlibc/fsfd_target.hpp" +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +namespace mlibc { +int sys_write(int fd, const void *buffer, size_t count, ssize_t *written) { + auto result = syscall(SYS_WRITE, fd, buffer, count); + + if (result < 0) { + return -result; + } + + *written = result; + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + auto result = syscall(SYS_READ, fd, buf, count); + + if (result < 0) { + *bytes_read = 0; + return -result; + } + + *bytes_read = result; + return 0; +} + +int sys_fsync(int) { + mlibc::infoLogger() << "\e[35mmlibc: fsync is a stub\e[39m" << frg::endlog; + return 0; +} + +int sys_fdatasync(int) { + mlibc::infoLogger() << "\e[35mmlibc: fdatasync() is a no-op\e[39m" << frg::endlog; + return 0; +} + +// clang-format off +int sys_pwrite(int fd, const void *buffer, size_t count, off_t off, + ssize_t *written) UNIMPLEMENTED("sys_pwrite") + +// clang-format off +int sys_pread(int fd, void *buf, size_t count, + off_t off, ssize_t *bytes_read) UNIMPLEMENTED("sys_pread") + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + auto result = syscall(SYS_SEEK, fd, offset, whence); + + if (result < 0) { + return -result; + } + + *new_offset = result; + return 0; +} + +int sys_open(const char *filename, int flags, mode_t mode, int *fd) { + auto result = syscall(SYS_OPEN, 0, filename, strlen(filename), flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_close(int fd) { + auto result = syscall(SYS_CLOSE, fd); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + auto ret = syscall(SYS_ACCESS, dirfd, pathname, strlen(pathname), mode, flags); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_access(const char *filename, int mode) { + return sys_faccessat(AT_FDCWD, filename, mode, 0); +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf) { + switch (fsfdt) { + case fsfd_target::path: + fd = AT_FDCWD; + break; + + case fsfd_target::fd: + flags |= AT_EMPTY_PATH; + + case fsfd_target::fd_path: + break; + + default: + __ensure(!"Invalid fsfd_target"); + __builtin_unreachable(); + } + + auto ret = syscall(SYS_FSTAT, fd, path, strlen(path), flags, statbuf); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + auto sys_res = syscall(SYS_IOCTL, fd, request, arg); + + if (sys_res < 0) { + return -sys_res; + } + + if (result) + *result = sys_res; + return 0; +} + +int sys_isatty(int fd) { + // NOTE: The easiest way to check if a file descriptor is a TTY is to + // do an ioctl of TIOCGWINSZ on it and see if it succeeds :^) + struct winsize ws; + int result; + + if (!sys_ioctl(fd, TIOCGWINSZ, &ws, &result)) { + return 0; + } + + return ENOTTY; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int result; + + if (int e = sys_ioctl(fd, TCGETS, (void *)attr, &result); e) + return e; + + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int req; + + switch (optional_action) { + case TCSANOW: req = TCSETS; break; + case TCSADRAIN: req = TCSETSW; break; + case TCSAFLUSH: req = TCSETSF; break; + default: return EINVAL; + } + + if (int e = sys_ioctl(fd, req, (void *)attr, NULL); e) + return e; + + return 0; +} + +int sys_mkdir(const char *path, mode_t) { + auto result = syscall(SYS_MKDIR, path, strlen(path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_link(const char *srcpath, const char *destpath) { + auto result = + syscall(SYS_LINK, srcpath, strlen(srcpath), destpath, strlen(destpath)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_rmdir(const char *path) { + return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); +} + +int sys_unlinkat(int fd, const char *path, int flags) { + auto ret = syscall(SYS_UNLINK, fd, path, strlen(path), flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_symlink(const char *target_path, const char *link_path) { + return sys_symlinkat(target_path, AT_FDCWD, link_path); +} + +int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + auto ret = syscall(SYS_SYMLINK_AT, dirfd, target_path, strlen(target_path), link_path, strlen(link_path)); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +struct aero_dir_entry { + size_t inode; + size_t offset; + size_t reclen; + size_t filetyp; + char name[]; +} __attribute__((__packed__)); + +int sys_read_entries(int handle, void *buffer, size_t max_size, + size_t *bytes_read) { + auto result = syscall(SYS_GETDENTS, handle, buffer, max_size); + + // Check if we got an error. + if (result < 0) { + *bytes_read = 0; + return -result; + } + + // Nothing to read. + if (result == 0) { + *bytes_read = 0; + return 0; + } + + auto entry = (struct aero_dir_entry *)buffer; + + struct dirent dirent = { + .d_ino = static_cast(entry->inode), + .d_off = static_cast(entry->offset), + .d_reclen = static_cast(entry->reclen), + .d_type = static_cast(entry->filetyp), + }; + + // The reclen is the size of the dirent struct, plus the size of the name. + auto name_size = entry->reclen - sizeof(struct aero_dir_entry); + __ensure(name_size < 255); + + memcpy(&dirent.d_name, entry->name, name_size); + *bytes_read = entry->reclen; + + memcpy(buffer, &dirent, sizeof(struct dirent)); + return 0; +} + +int sys_open_dir(const char *path, int *handle) { + return sys_open(path, O_DIRECTORY, 0, handle); +} + +int sys_rename(const char *path, const char *new_path) { + auto result = + syscall(SYS_RENAME, path, strlen(path), new_path, strlen(new_path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_readlink(const char *path, void *buffer, size_t max_size, + ssize_t *length) { + auto result = syscall(SYS_READ_LINK, path, strlen(path), buffer, max_size); + + if (result < 0) { + return -result; + } + + *length = result; + return 0; +} + +int sys_dup(int fd, int flags, int *newfd) { + auto result = syscall(SYS_DUP, fd, flags); + + if (result < 0) { + return -result; + } + + *newfd = result; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + auto result = syscall(SYS_DUP2, fd, newfd, flags); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_fcntl(int fd, int request, va_list args, int *result_value) { + auto result = syscall(SYS_FCNTL, fd, request, va_arg(args, uint64_t)); + + if (result < 0) { + return -result; + } + + *result_value = result; + return 0; +} + +// int sys_chmod(const char *pathname, mode_t mode) UNIMPLEMENTED("sys_chmod") + +int sys_pipe(int *fds, int flags) { + auto result = syscall(SYS_PIPE, fds, flags); + + if (result < 0) { + return -result; + } + + return 0; +} + +// epoll API syscalls: +int sys_epoll_create(int flags, int *fd) { + auto result = syscall(SYS_EPOLL_CREATE, flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + auto result = syscall(SYS_EPOLL_CTL, epfd, mode, fd, ev); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, + const sigset_t *sigmask, int *raised) { + auto result = syscall(SYS_EPOLL_PWAIT, epfd, ev, n, timeout, sigmask); + + if (result < 0) { + return -result; + } + + *raised = result; + return 0; +} + +int sys_eventfd_create(unsigned int initval, int flags, int *fd) { + auto result = syscall(SYS_EVENT_FD, initval, flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + auto result = syscall(SYS_POLL, fds, nfds, timeout, sigmask); + + if (result < 0) { + return -result; + } + + *num_events = result; + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + + return sys_ppoll(fds, count, &ts, NULL, num_events); +} + +#ifndef MLIBC_BUILDING_RTLD +#include +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if (int e = sys_ioctl(fd, TIOCGPTN, &index, NULL); e) + return e; + if ((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + int fd = epoll_create1(0); + if (fd == -1) + return -1; + + for (int k = 0; k < FD_SETSIZE; k++) { + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + + if (read_set && FD_ISSET(k, read_set)) + ev.events |= EPOLLIN; + if (write_set && FD_ISSET(k, write_set)) + ev.events |= EPOLLOUT; + if (except_set && FD_ISSET(k, except_set)) + ev.events |= EPOLLPRI; + + if (!ev.events) + continue; + + ev.data.u32 = k; + if (epoll_ctl(fd, EPOLL_CTL_ADD, k, &ev)) + return -1; + } + + struct epoll_event evnts[16]; + int n = epoll_pwait( + fd, evnts, 16, + timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 100) : -1, + sigmask); + + if (n == -1) + return -1; + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + int m = 0; + + for (int i = 0; i < n; i++) { + int k = evnts[i].data.u32; + + if (read_set && FD_ISSET(k, read_set) && + evnts[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_read_set); + m++; + } + + if (write_set && FD_ISSET(k, write_set) && + evnts[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_write_set); + m++; + } + + if (except_set && FD_ISSET(k, except_set) && + evnts[i].events & EPOLLPRI) { + FD_SET(k, &res_except_set); + m++; + } + } + + if (close(fd)) + __ensure("mlibc::pselect: close() failed on epoll file"); + + if (read_set) + memcpy(read_set, &res_read_set, sizeof(fd_set)); + + if (write_set) + memcpy(write_set, &res_write_set, sizeof(fd_set)); + + if (except_set) + memcpy(except_set, &res_except_set, sizeof(fd_set)); + + *num_events = m; + return 0; +} +#endif // #ifndef MLIBC_BUILDING_RTLD +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/aero/generic/signals.S b/user/include/mlibc/sysdeps/aero/generic/signals.S new file mode 100644 index 0000000..62dee9b --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/signals.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_signal_restore + +__mlibc_signal_restore: + mov $39, %rax + syscall + ud2 +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/aero/generic/signals.cpp b/user/include/mlibc/sysdeps/aero/generic/signals.cpp new file mode 100644 index 0000000..611db69 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/signals.cpp @@ -0,0 +1,48 @@ +#include +#include + +#include +#include + +#define LOG_SIGACTION_INSTALL 0 + +extern "C" void __mlibc_signal_restore(); // defined in `signals.S` + +namespace mlibc { +int sys_sigaction(int how, const struct sigaction *__restrict action, + struct sigaction *__restrict old_action) { +#if LOG_SIGACTION_INSTALL + mlibc::infoLogger() << "sys_sigaction: signal " << how << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: size: " << sizeof(*action) + << frg::endlog; + + if (action != NULL) { + mlibc::infoLogger() << "sys_sigaction: handler " + << (int64_t)action->sa_handler << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: action " + << (int64_t)action->sa_sigaction << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: flags " + << (int64_t)action->sa_flags << frg::endlog; + } + + mlibc::infoLogger() << frg::endlog; +#endif + + auto sigreturn = (sc_word_t)__mlibc_signal_restore; + auto ret = syscall(SYS_SIGACTION, how, (sc_word_t)action, sigreturn, + (sc_word_t)old_action); + + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve) { + + auto ret = syscall(SYS_SIGPROCMASK, how, set, retrieve); + if(int e = sc_error(ret); e) + return e; + return 0; +} +} // namespace mlibc \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/generic/sockets.cpp b/user/include/mlibc/sysdeps/aero/generic/sockets.cpp new file mode 100644 index 0000000..5fc2a92 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/sockets.cpp @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +namespace mlibc { +int sys_socket(int family, int type, int protocol, int *fd) { + auto result = syscall(SYS_SOCKET, family, type, protocol); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + auto result = syscall(SYS_BIND, fd, addr_ptr, (sc_word_t)addr_length); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, + socklen_t addr_length) { + auto result = syscall(SYS_CONNECT, fd, addr_ptr, (sc_word_t)addr_length); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_listen(int fd, int backlog) { + auto result = syscall(SYS_LISTEN, fd, backlog); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_accept(int sockfd, int *newfd, struct sockaddr *addr_ptr, + socklen_t *addr_length, int flags) { + auto result = syscall(SYS_ACCEPT, sockfd, addr_ptr, addr_length); + + if (result < 0) { + return -result; + } + + *newfd = result; + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length) { + auto result = syscall(SYS_SOCK_SEND, fd, hdr, flags); + if (result < 0) + return -result; + + *length = result; + return 0; +} + +int sys_msg_recv(int sockfd, struct msghdr *msg_hdr, int flags, + ssize_t *length) { + auto result = syscall(SYS_SOCK_RECV, sockfd, msg_hdr, flags); + + if (result < 0) { + return -result; + } + + *length = result; + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + auto result = syscall(SYS_SOCKET_PAIR, domain, type_and_flags, proto, fds); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, + socklen_t *__restrict size) { + (void)fd; + (void)size; + if (layer == SOL_SOCKET && number == SO_PEERCRED) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET " + "and SO_PEERCRED is unimplemented\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET " + "and SO_SNDBUF is unimplemented\e[39m" + << frg::endlog; + *(int *)buffer = 4096; + return 0; + } else if (layer == SOL_SOCKET && number == SO_TYPE) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_TYPE is " + "unimplemented, hardcoding SOCK_STREAM\e[39m" + << frg::endlog; + *(int *)buffer = SOCK_STREAM; + return 0; + } else if (layer == SOL_SOCKET && number == SO_ERROR) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is " + "unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and " + "SO_KEEPALIVE is unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else { + mlibc::panicLogger() + << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer + << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } + + return 0; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, + socklen_t size) { + (void)fd; + (void)buffer; + (void)size; + + if (layer == SOL_SOCKET && number == SO_PASSCRED) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_PASSCRED) is not " + "implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_ATTACH_FILTER) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_ATTACH_FILTER) is " + "not implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_RCVBUFFORCE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not " + "implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_SNDBUF is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_KEEPALIVE is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_REUSEADDR) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_REUSEADDR is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == AF_NETLINK && number == SO_ACCEPTCONN) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with AF_NETLINK " + "and SO_ACCEPTCONN is unimplemented\e[39m" + << frg::endlog; + return 0; + } else { + mlibc::infoLogger() + << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer + << " number: " << number << "\e[39m" << frg::endlog; + return 0; + } +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + auto ret = syscall(SYS_GETPEERNAME, fd, addr_ptr, &max_addr_length); + if(int e = sc_error(ret); e) + return e; + *actual_length = max_addr_length; + return 0; +} + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + auto ret = syscall(SYS_GETSOCKNAME, fd, addr_ptr, &max_addr_length); + if(int e = sc_error(ret); e) + return e; + *actual_length = max_addr_length; + return 0; +} + +int sys_shutdown(int sockfd, int how) { + auto ret = syscall(SYS_SOCK_SHUTDOWN, sockfd, how); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_if_nametoindex(const char *name, unsigned int *ret) { + int fd = 0; + int r = sys_socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if (r) + return r; + + struct ifreq ifr; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + + r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, NULL); + close(fd); + + if (r) + return r; + + *ret = ifr.ifr_ifindex; + return 0; +} +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/aero/generic/thread.cpp b/user/include/mlibc/sysdeps/aero/generic/thread.cpp new file mode 100644 index 0000000..bc9a449 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/thread.cpp @@ -0,0 +1,55 @@ +#include +#include + +#include +#include + +#include + +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID: + while (!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if (mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x1000000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, + size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/aero/generic/thread_entry.S b/user/include/mlibc/sysdeps/aero/generic/thread_entry.S new file mode 100644 index 0000000..498fda3 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/thread_entry.S @@ -0,0 +1,10 @@ +.section .text +.global __mlibc_start_thread + +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/aero/generic/time.cpp b/user/include/mlibc/sysdeps/aero/generic/time.cpp new file mode 100644 index 0000000..c995148 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/generic/time.cpp @@ -0,0 +1,25 @@ +#include +#include + +namespace mlibc { +int sys_setitimer(int which, const struct itimerval *new_value, + struct itimerval *old_value) { + auto result = syscall(SYS_SETITIMER, which, new_value, old_value); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_getitimer(int which, struct itimerval *curr_value) { + auto result = syscall(SYS_GETITIMER, which, curr_value); + + if (result < 0) { + return -result; + } + + return 0; +} +} // namespace mlibc \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/access.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/access.h new file mode 100755 index 0000000..ac6af5f --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/aero/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/auxv.h new file mode 100755 index 0000000..86157e8 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/aero/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..a296e9f --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/aero/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..a90d056 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/aero/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..758a31e --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/aero/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/dev_t.h new file mode 100755 index 0000000..673e40f --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/aero/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/epoll.h new file mode 100755 index 0000000..7e5405c --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/aero/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/errno.h new file mode 100755 index 0000000..09ac7f4 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/aero/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/fcntl.h new file mode 100755 index 0000000..463e2c9 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/gid_t.h new file mode 100755 index 0000000..aa24991 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/aero/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/in.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/in.h new file mode 100755 index 0000000..80100b2 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/aero/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/ino_t.h new file mode 100755 index 0000000..f78ea41 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/aero/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/inotify.h new file mode 100755 index 0000000..f558dc4 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/aero/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/ipc.h new file mode 100755 index 0000000..e5ff5fd --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/aero/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/limits.h new file mode 100755 index 0000000..36f5277 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/aero/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/mode_t.h new file mode 100755 index 0000000..ca2f8b2 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/aero/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..33d5dd3 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/aero/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/packet.h new file mode 100755 index 0000000..1577df7 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/aero/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/pid_t.h new file mode 100755 index 0000000..e3e3dc7 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/aero/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/poll.h new file mode 100755 index 0000000..f2062d5 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/aero/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/ptrace.h new file mode 100755 index 0000000..ce3bbd0 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/aero/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/random.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/random.h new file mode 100755 index 0000000..a2e204a --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/random.h @@ -0,0 +1 @@ +../../../../abis/aero/random.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/reboot.h new file mode 100755 index 0000000..77013a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/resource.h new file mode 100755 index 0000000..ba54927 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/aero/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..729f71f --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/aero/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..086bf5f --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/aero/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/shm.h new file mode 100755 index 0000000..d223528 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/aero/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/sigevent.h new file mode 100755 index 0000000..83d069b --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/linux/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/signal.h new file mode 100755 index 0000000..4dcb0b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/socket.h new file mode 100755 index 0000000..e3b71dc --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/aero/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/stat.h new file mode 100755 index 0000000..1f63b41 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/time.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/time.h new file mode 100755 index 0000000..9544445 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/aero/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/uid_t.h new file mode 100755 index 0000000..85051f4 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/aero/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/utsname.h new file mode 100755 index 0000000..b285754 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..c03405d --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/aero/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/aero/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/aero/include/aero/syscall.h b/user/include/mlibc/sysdeps/aero/include/aero/syscall.h new file mode 100644 index 0000000..197b574 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/aero/syscall.h @@ -0,0 +1,237 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#include +#include + +#define SYS_READ 0 +#define SYS_WRITE 1 +#define SYS_OPEN 2 +#define SYS_CLOSE 3 +#define SYS_SHUTDOWN 4 +#define SYS_EXIT 5 +#define SYS_FORK 6 +#define SYS_REBOOT 7 +#define SYS_MMAP 8 +#define SYS_MUNMAP 9 +#define SYS_ARCH_PRCTL 10 +#define SYS_GETDENTS 11 +#define SYS_GETCWD 12 +#define SYS_CHDIR 13 +#define SYS_MKDIR 14 +#define SYS_MKDIR_AT 15 +#define SYS_RMDIR 16 +#define SYS_EXEC 17 +#define SYS_LOG 18 +#define SYS_UNAME 19 +#define SYS_WAITPID 20 +#define SYS_IOCTL 21 +#define SYS_GETPID 22 +#define SYS_SOCKET 23 +#define SYS_CONNECT 24 +#define SYS_BIND 25 +#define SYS_LISTEN 26 +#define SYS_ACCEPT 27 +#define SYS_SEEK 28 +#define SYS_GETTID 29 +#define SYS_GETTIME 30 +#define SYS_SLEEP 31 +#define SYS_ACCESS 32 +#define SYS_PIPE 33 +#define SYS_UNLINK 34 +#define SYS_GETHOSTNAME 35 +#define SYS_SETHOSTNAME 36 +#define SYS_INFO 37 +#define SYS_CLONE 38 +#define SYS_SIGRETURN 39 +#define SYS_SIGACTION 40 +#define SYS_SIGPROCMASK 41 +#define SYS_DUP 42 +#define SYS_FCNTL 43 +#define SYS_DUP2 44 +#define SYS_IPC_SEND 45 +#define SYS_IPC_RECV 46 +#define SYS_DISCOVER_ROOT 47 +#define SYS_BECOME_ROOT 48 +#define SYS_STAT 49 +#define SYS_FSTAT 50 +#define SYS_READ_LINK 51 +#define SYS_EPOLL_CREATE 52 +#define SYS_EPOLL_PWAIT 53 +#define SYS_EPOLL_CTL 54 +#define SYS_EVENT_FD 55 +#define SYS_KILL 56 +#define SYS_FUTEX_WAIT 57 +#define SYS_FUTEX_WAKE 58 +#define SYS_LINK 59 +#define SYS_BACKTRACE 60 +#define SYS_POLL 61 +#define SYS_EXIT_THREAD 62 +#define SYS_SOCK_RECV 63 +#define SYS_SETITIMER 64 +#define SYS_GETITIMER 65 +#define SYS_GETPPID 66 +#define SYS_SOCKET_PAIR 67 +#define SYS_RENAME 68 +#define SYS_MPROTECT 69 +#define SYS_SOCK_SEND 70 +#define SYS_TRACE 71 +#define SYS_SETPGID 72 +#define SYS_SETSID 73 +#define SYS_GETPGID 74 +#define SYS_SOCK_SHUTDOWN 75 +#define SYS_GETPEERNAME 76 +#define SYS_GETSOCKNAME 77 +#define SYS_DEBUG 78 +#define SYS_SETSOCKOPT 79 +#define SYS_GETSOCKOPT 80 +#define SYS_SYMLINK_AT 81 + +/* Invalid syscall used to trigger a log error in the kernel (as a hint) */ +/* so, that we can implement the syscall in the kernel. */ +#define UNIMPLEMENTED(FUNCTION_NAME) \ + { \ + sys_libc_log("Unimplemented syscall: " FUNCTION_NAME); \ + sys_exit(1); \ + __builtin_unreachable(); \ + } + +extern "C" { +using sc_word_t = long; + +static sc_word_t syscall0(int sc) { + sc_word_t ret; + asm volatile("syscall" : "=a"(ret) : "a"(sc) : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall1(int sc, sc_word_t arg1) { + sc_word_t ret; + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall2(int sc, sc_word_t arg1, sc_word_t arg2) { + sc_word_t ret; + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall3(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3) { + sc_word_t ret; + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall4(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4) { + sc_word_t ret; + + register sc_word_t arg4_reg asm("r10") = arg4; + + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg4_reg) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall5(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4, sc_word_t arg5) { + sc_word_t ret; + + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg4_reg), + "r"(arg5_reg) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall6(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4, sc_word_t arg5, + sc_word_t arg6) { + sc_word_t ret; + + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + register sc_word_t arg6_reg asm("r9") = arg6; + + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg4_reg), + "r"(arg5_reg), "r"(arg6_reg) + : "rcx", "r11", "memory"); + return ret; +} +} /* extern "C" */ + +/* Cast to the argument type of the extern "C" functions. */ +__attribute__((__always_inline__)) inline sc_word_t sc_cast(long x) { return x; } +__attribute__((__always_inline__)) inline sc_word_t sc_cast(const void *x) { + return reinterpret_cast(x); +} + +/* C++ wrappers for the extern "C" functions. */ +__attribute__((__always_inline__)) static inline long _syscall(int call) { + return syscall0(call); +} + +__attribute__((__always_inline__)) static inline long _syscall(int call, + sc_word_t arg0) { + return syscall1(call, arg0); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1) { + return syscall2(call, arg0, arg1); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1, sc_word_t arg2) { + return syscall3(call, arg0, arg1, arg2); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3) { + return syscall4(call, arg0, arg1, arg2, arg3); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4) { + return syscall5(call, arg0, arg1, arg2, arg3, arg4); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4, sc_word_t arg5) { + return syscall6(call, arg0, arg1, arg2, arg3, arg4, arg5); +} + +template +__attribute__((__always_inline__)) static inline long syscall(sc_word_t call, + T... args) { + return _syscall(call, sc_cast(args)...); +} + +inline int sc_error(long ret) { + if (ret < 0) + return -ret; + return 0; +} +#endif /* SYSCALL_H */ diff --git a/user/include/mlibc/sysdeps/aero/include/mlibc/thread-entry.hpp b/user/include/mlibc/sysdeps/aero/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..a241479 --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/include/mlibc/thread-entry.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +extern "C" void __mlibc_start_thread(void); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb); + +namespace mlibc { +int prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, + size_t *guard_size); +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/aero/meson.build b/user/include/mlibc/sysdeps/aero/meson.build new file mode 100644 index 0000000..5a8bcfd --- /dev/null +++ b/user/include/mlibc/sysdeps/aero/meson.build @@ -0,0 +1,118 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': true, + 'glibc': true, + 'bsd': true, +} + +rtld_dso_sources += files( + 'generic/aero.cpp', + 'generic/filesystem.cpp', +) + +libc_sources += files( + 'generic/aero.cpp', + 'generic/entry.cpp', + 'generic/thread_entry.S', + 'generic/thread.cpp', + 'generic/filesystem.cpp', + 'generic/sockets.cpp', + 'generic/signals.cpp', + 'generic/time.cpp', +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/random.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + install_headers( + 'include/aero/syscall.h', + subdir: 'aero' + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif + +if host_machine.cpu_family() == 'x86_64' + libc_sources += files('generic/signals.S') +else + error('Unknown architecture') +endif diff --git a/user/include/mlibc/sysdeps/astral/.clang-format b/user/include/mlibc/sysdeps/astral/.clang-format new file mode 100644 index 0000000..4662692 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/.clang-format @@ -0,0 +1,2 @@ +--- +DisableFormat: true diff --git a/user/include/mlibc/sysdeps/astral/crt-x86_64/crt1.S b/user/include/mlibc/sysdeps/astral/crt-x86_64/crt1.S new file mode 100644 index 0000000..b6964d9 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/crt-x86_64/crt1.S @@ -0,0 +1,7 @@ +.section .text +.global _start +_start: + lea main(%rip), %rdi + mov %rsp, %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/astral/crt-x86_64/crti.S b/user/include/mlibc/sysdeps/astral/crt-x86_64/crti.S new file mode 100644 index 0000000..911b078 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/crt-x86_64/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/astral/crt-x86_64/crtn.S b/user/include/mlibc/sysdeps/astral/crt-x86_64/crtn.S new file mode 100644 index 0000000..0187e50 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/crt-x86_64/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/astral/generic/astral.cpp b/user/include/mlibc/sysdeps/astral/generic/astral.cpp new file mode 100644 index 0000000..a86353f --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/generic/astral.cpp @@ -0,0 +1,15 @@ +#include +#include +#include + +#ifndef MLIBC_BUILDING_RTLD + +int arch_ctl(int func, void *arg) { + long ret; + long error = syscall(SYSCALL_ARCHCTL, &ret, func, (uint64_t)arg); + if(error) + errno = error; + return error ? -1 : ret; +} + +#endif diff --git a/user/include/mlibc/sysdeps/astral/generic/entry.cpp b/user/include/mlibc/sysdeps/astral/generic/entry.cpp new file mode 100644 index 0000000..661377e --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/generic/entry.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[]), uintptr_t *entry_stack) { + __dlapi_enter(entry_stack); + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} + diff --git a/user/include/mlibc/sysdeps/astral/generic/generic.cpp b/user/include/mlibc/sysdeps/astral/generic/generic.cpp new file mode 100644 index 0000000..be7ad9e --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/generic/generic.cpp @@ -0,0 +1,916 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + int sys_setgroups(size_t size, const gid_t *list) { + (void)size; + (void)list; + // TODO unstub + return 0; + } + + int sys_getgroups(size_t size, gid_t *list, int *ret) { + (void)size; + (void)list; + (void)ret; + // TODO unstub + *ret = 0; + return 0; + } + + int sys_getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size) { + (void)size; + (void)buffer; + // TODO unstub + mlibc::infoLogger() << "getsockopt: " << fd << " " << layer << " " << number << frg::endlog; + return 0; + } + + int sys_inet_configured(bool *ipv4, bool *ipv6) { + // there is no ipv6 support in the kernel currently and no way of checking for configured interfaces + *ipv4 = true; + *ipv6 = false; + return 0; + } + + int sys_getcpu(int *cpu) { + long ret; + // can never fail + syscall(SYSCALL_GETCPU, &ret); + *cpu = ret; + return 0; + } + + int sys_flock(int fd, int options) { + long r; + return syscall(SYSCALL_FLOCK, &r, fd, options); + } + + int sys_nice(int nice, int *ret) { + long r = -1; + long e = syscall(SYSCALL_NICE, &r, nice); + *ret = r; + return e; + } + + int sys_shutdown(int sockfd, int how) { + long ret; + return syscall(SYSCALL_SHUTDOWN, &ret, sockfd, how); + } + + int sys_tgkill(int pid, int tid, int sig) { + long ret; + return syscall(SYSCALL_KILLTHREAD, &ret, pid, tid, sig); + } + + int sys_sigpending(sigset_t *set) { + long ret; + return syscall(SYSCALL_SIGPENDING, &ret, (uint64_t)set); + } + + int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal) { + long ret; + long err = syscall(SYSCALL_SIGTIMEDWAIT, &ret, (uint64_t)set, (uint64_t)info, (uint64_t)timeout); + *out_signal = ret; + return err; + } + + int sys_sigsuspend(const sigset_t *set) { + long ret; + return syscall(SYSCALL_SIGSUSPEND, &ret, (uint64_t)set); + } + + int sys_vm_protect(void *pointer, size_t size, int prot) { + long ret; + return syscall(SYSCALL_MPROTECT, &ret, (uint64_t)pointer, size, prot); + } + + int sys_setuid(uid_t id) { + long ret; + return syscall(SYSCALL_SETUID, &ret, id); + } + + int sys_setgid(gid_t id) { + long ret; + return syscall(SYSCALL_SETGID, &ret, id); + } + + int sys_seteuid(uid_t id) { + long ret; + return syscall(SYSCALL_SETEUID, &ret, id); + } + + int sys_setegid(gid_t id) { + long ret; + return syscall(SYSCALL_SETEGID, &ret, id); + } + + uid_t sys_getuid() { + uid_t r, e, s; + sys_getresuid(&r, &e, &s); + + return r; + } + + uid_t sys_geteuid() { + uid_t r, e, s; + sys_getresuid(&r, &e, &s); + + return e; + } + + gid_t sys_getgid() { + gid_t r, e, s; + sys_getresgid(&r, &e, &s); + + return r; + } + + gid_t sys_getegid() { + gid_t r, e, s; + sys_getresgid(&r, &e, &s); + + return e; + } + + int sys_setresuid(uid_t _ruid, uid_t _euid, uid_t _suid) { + long ret; + return syscall(SYSCALL_SETRESUID, &ret, _ruid, _euid, _suid); + } + + int sys_setresgid(gid_t _rgid, gid_t _egid, gid_t _sgid) { + long ret; + return syscall(SYSCALL_SETRESGID, &ret, _rgid, _egid, _sgid); + } + + int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + long ret; + return syscall(SYSCALL_GETRESUID, &ret, (uint64_t)ruid, (uint64_t)euid, (uint64_t)suid); + } + + int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + long ret; + return syscall(SYSCALL_GETRESGID, &ret, (uint64_t)rgid, (uint64_t)egid, (uint64_t)sgid); + } + + int sys_mknodat(int dirfd, const char *path, int mode, int dev) { + long ret; + return syscall(SYSCALL_MKNODAT, &ret, dirfd, (uint64_t)path, mode, dev); + } + + int sys_mkfifoat(int dirfd, const char *path, mode_t mode) { + return sys_mknodat(dirfd, path, S_IFIFO | mode, 0); + } + + int sys_rmdir(const char *path) { + return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); + } + + int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + long readc; + long error = syscall(SYSCALL_PREAD, &readc, fd, (uint64_t)buf, n, off); + *bytes_read = readc; + return error; + } + + int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { + long writec; + long error = syscall(SYSCALL_PWRITE, &writec, fd, (uint64_t)buf, n, off); + *bytes_written = writec; + return error; + } + + int sys_getrlimit(int resource, struct rlimit *limit) { + switch(resource) { + case RLIMIT_NOFILE: + limit->rlim_cur = RLIM_INFINITY; + limit->rlim_max = RLIM_INFINITY; + return 0; + default: + return EINVAL; + } + } + + #ifndef MLIBC_BUILDING_RTLD + + typedef struct { + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[1024]; + } dent_t; + + #endif + + int sys_pause() { + long ret; + return syscall(SYSCALL_PAUSE, &ret); + } + + int sys_chroot(const char *path) { + long ret; + return syscall(SYSCALL_CHROOT, &ret, (uint64_t)path); + } + + int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + long ret; + int len = max_addr_length; + long error = syscall(SYSCALL_GETPEERNAME, &ret, fd, (uint64_t)addr_ptr, (uint64_t)&len); + *actual_length = len; + return error; + } + + int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + long ret; + int len = max_addr_length; + long error = syscall(SYSCALL_GETSOCKNAME, &ret, fd, (uint64_t)addr_ptr, (uint64_t)&len); + *actual_length = len; + return error; + } + + int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + long ret = 0; + long err = syscall(SYSCALL_SOCKETPAIR, &ret, domain, type_and_flags, proto); + if(err) + return err; + + fds[0] = ret & 0xffffffff; + fds[1] = (ret >> 32) & 0xffffffff; + return err; + } + + int sys_getitimer(int which, struct itimerval *curr_value) { + long ret; + return syscall(SYSCALL_GETITIMER, &ret, which, (uint64_t)curr_value); + } + + int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + long ret; + return syscall(SYSCALL_SETITIMER, &ret, which, (uint64_t)new_value, (uint64_t)old_value); + } + + #ifndef MLIBC_BUILDING_RTLD + #define TTY_IOCTL_NAME 0x771101141113l + #define TTY_NAME_MAX 32 + #define TTY_PREFIX "/dev/" + + + int sys_ttyname(int fd, char * buffer, size_t size) { + size_t prefixLen = strlen(TTY_PREFIX); + if(size < TTY_NAME_MAX + prefixLen) { + mlibc::panicLogger() << "ttyname size too small" << frg::endlog; + __builtin_unreachable(); + } + + strcpy(buffer, TTY_PREFIX); + + int res; + return sys_ioctl(fd, TTY_IOCTL_NAME, (void *)(buffer + prefixLen), &res); + } + #endif + + int sys_fsync(int fd) { + long ret; + return syscall(SYSCALL_FSYNC, &ret, fd); + } + + int sys_fdatasync(int fd) { + // TODO proper datasync syscall + return sys_fsync(fd); + } + + pid_t sys_getppid() { + long ret; + syscall(SYSCALL_GETPPID, &ret); + return ret; + } + + int sys_getsid(pid_t pid, pid_t *pgid) { + long ret; + long error = syscall(SYSCALL_GETSID, &ret, pid); + *pgid = ret; + return error; + } + + int sys_getpgid(pid_t pid, pid_t *pgid) { + long ret; + long error = syscall(SYSCALL_GETPGID, &ret, pid); + *pgid = ret; + return error; + } + + int sys_gethostname(char *buffer, size_t bufsize) { + long ret; + return syscall(SYSCALL_HOSTNAME, &ret, NULL, 0, (uint64_t)buffer, bufsize); + } + + int sys_sethostname(const char *buffer, size_t bufsize) { + long ret; + return syscall(SYSCALL_HOSTNAME, &ret, (uint64_t)buffer, bufsize, NULL, 0); + } + + int sys_uname(struct utsname *buf) { + long ret; + return syscall(SYSCALL_UNAME, &ret, (uint64_t)buf); + } + + void sys_sync() { + long ret; + syscall(SYSCALL_SYNC, &ret); + } + + #ifndef MLIBC_BUILDING_RTLD + int sys_getentropy(void *buffer, size_t length) { + int fd; + int error = sys_open("/dev/urandom", O_RDONLY, 0, &fd); + if(error) + mlibc::panicLogger() << "/dev/urandom open error " << strerror(error) << frg::endlog; + + ssize_t bytes; + error = sys_read(fd, buffer, length, &bytes); + if(error) { + mlibc::infoLogger() << "/dev/urandom read error " << strerror(error) << frg::endlog; + return error; + } + + sys_close(fd); + return 0; + } + #endif + + int sys_kill(int pid, int signal) { + long ret; + return syscall(SYSCALL_KILL, &ret, pid, signal); + } + + int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + long ret; + return syscall(SYSCALL_SIGPROCMASK, &ret, how, (uint64_t)set, (uint64_t)retrieve); + } + + int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + long ret; + return syscall(SYSCALL_SIGALTSTACK, &ret, (uint64_t)ss, (uint64_t)oss); + } + + #ifndef MLIBC_BUILDING_RTLD + extern "C" void __mlibc_restorer(); + + int sys_sigaction(int sig, const struct sigaction *__restrict act, + struct sigaction *__restrict oldact) { + long ret; + + struct sigaction newAction; + if(act) + memcpy(&newAction, act, sizeof(struct sigaction)); + + if(act && (newAction.sa_flags & SA_RESTORER) == 0) { + newAction.sa_restorer = __mlibc_restorer; + newAction.sa_flags |= SA_RESTORER; + } + + return syscall(SYSCALL_SIGACTION, &ret, sig, act ? (uint64_t)&newAction : 0, (uint64_t)oldact); + } + + int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + int tmp; + if(int e = sys_ioctl(fd, TIOCGPTN, &index, &tmp); e) + return e; + + if((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + + return 0; + } + #endif + + int sys_setpgid(pid_t pid, pid_t pgid) { + long ret; + return syscall(SYSCALL_SETPGID, &ret, pid, pgid); + } + + int sys_setsid(pid_t *out) { + long ret; + long error = syscall(SYSCALL_SETSID, &ret); + *out = ret; + return error; + } + + int sys_futex_tid() { + long ret; + syscall(SYSCALL_GETTID, &ret); + return ret; + } + + pid_t sys_gettid() { + long ret; + syscall(SYSCALL_GETTID, &ret); + return ret; + } + + #ifndef MLIBC_BUILDING_RTLD + + [[noreturn]] void sys_thread_exit() { + syscall(SYSCALL_THREADEXIT, nullptr); + __builtin_unreachable(); + } + + extern "C" void __mlibc_thread_entry(); + + int sys_clone(void *tcb, pid_t *pid_out, void *stack) { + (void)tcb; + long ret; + long err = syscall(SYSCALL_NEWTHREAD, &ret, (uintptr_t)__mlibc_thread_entry, (uintptr_t)stack); + *pid_out = ret; + return err; + } + + #endif + + int sys_listen(int fd, int backlog) { + long ret; + return syscall(SYSCALL_LISTEN, &ret, fd, backlog); + } + + int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + long ret; + long error = syscall(SYSCALL_ACCEPT, &ret, fd, (uint64_t)addr_ptr, (uint64_t)addr_length, flags); + *newfd = ret; + return error; + } + + int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + long ret; + return syscall(SYSCALL_CONNECT, &ret, fd, (uint64_t)addr_ptr, addr_length); + } + + int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length) { + long ret; + long err = syscall(SYSCALL_RECVMSG, &ret, fd, (uint64_t)hdr, flags); + *length = ret; + return err; + } + + int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + long ret; + return syscall(SYSCALL_SETSOCKOPT, &ret, fd, layer, number, (uint64_t)buffer, size); + } + + int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length) { + long ret; + long err = syscall(SYSCALL_SENDMSG, &ret, fd, (uint64_t)hdr, flags); + *length = ret; + return err; + } + + int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + long ret; + return syscall(SYSCALL_BIND, &ret, fd, (uint64_t)addr_ptr, addr_length); + } + + int sys_socket(int family, int type, int protocol, int *fd) { + long ret; + long err = syscall(SYSCALL_SOCKET, &ret, family, type, protocol); + *fd = ret; + return err; + } + + int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + long ret; + return syscall(SYSCALL_RENAMEAT, &ret, olddirfd, (uint64_t)old_path, newdirfd, (uint64_t)new_path); + } + + int sys_rename(const char *path, const char *new_path) { + return sys_renameat(AT_FDCWD, path, AT_FDCWD, new_path); + } + + int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + long ret; + return syscall(SYSCALL_UTIMENSAT, &ret, dirfd, (uint64_t)pathname, (uint64_t)times, flags); + } + + int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { + long ret; + return syscall(SYSCALL_FCHOWNAT, &ret, dirfd, (uint64_t)pathname, owner, group, flags); + } + + int sys_mount(const char *source, const char *target, const char *fstype, unsigned long flags, const void *data) { + long ret; + return syscall(SYSCALL_MOUNT, &ret, (uint64_t)source, (uint64_t)target, (uint64_t)fstype, flags, (uint64_t)data); + } + + int sys_ftruncate(int fd, size_t size) { + long ret; + return syscall(SYSCALL_FTRUNCATE, &ret, fd, size); + } + + int sys_sleep(time_t *secs, long *nanos) { + struct timespec ts; + ts.tv_sec = *secs; + ts.tv_nsec = *nanos; + long ret; + long err = syscall(SYSCALL_NANOSLEEP, &ret, (uintptr_t)&ts, (uintptr_t)&ts); + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + return err; + } + + int sys_tcgetattr(int fd, struct termios *attr){ + int res; + return sys_ioctl(fd, TCGETS, (void *)attr, &res); + } + + int sys_tcsetattr(int fd, int act, const struct termios *attr){ + (void)act; + int res; + return sys_ioctl(fd, TCSETS, (void *)attr, &res); + } + + int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + long ret; + long error = syscall(SYSCALL_POLL, &ret, (uint64_t)fds, count, timeout); + *num_events = ret; + return error; + } + + int sys_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + long ret; + long error = syscall(SYSCALL_PPOLL, &ret, (uint64_t)fds, nfds, (uint64_t)timeout, (uint64_t)sigmask); + *num_events = ret; + return error; + } + +#ifndef MLIBC_BUILDING_RTLD + int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + pollfd *fds = (pollfd *)malloc(num_fds * sizeof(pollfd)); + + if(fds == NULL) + return ENOMEM; + + int actual_count = 0; + + for(int fd = 0; fd < num_fds; ++fd) { + short events = 0; + if(read_set && FD_ISSET(fd, read_set)) { + events |= POLLIN; + } + + if(write_set && FD_ISSET(fd, write_set)) { + events |= POLLOUT; + } + + if(except_set && FD_ISSET(fd, except_set)) { + events |= POLLPRI; + } + + if(events) { + fds[actual_count].fd = fd; + fds[actual_count].events = events; + fds[actual_count].revents = 0; + actual_count++; + } + } + + int num; + int err = sys_ppoll(fds, actual_count, timeout, sigmask, &num); + + if(err) { + free(fds); + return err; + } + + #define READ_SET_POLLSTUFF (POLLIN | POLLHUP | POLLERR) + #define WRITE_SET_POLLSTUFF (POLLOUT | POLLERR) + #define EXCEPT_SET_POLLSTUFF (POLLPRI) + + int return_count = 0; + for(int fd = 0; fd < actual_count; ++fd) { + int events = fds[fd].events; + if((events & POLLIN) && (fds[fd].revents & READ_SET_POLLSTUFF) == 0) { + FD_CLR(fds[fd].fd, read_set); + events &= ~POLLIN; + } + + if((events & POLLOUT) && (fds[fd].revents & WRITE_SET_POLLSTUFF) == 0) { + FD_CLR(fds[fd].fd, write_set); + events &= ~POLLOUT; + } + + if((events & POLLPRI) && (fds[fd].revents & EXCEPT_SET_POLLSTUFF) == 0) { + FD_CLR(fds[fd].fd, except_set); + events &= ~POLLPRI; + } + + if(events) + return_count++; + } + *num_events = return_count; + free(fds); + return 0; + } +#endif + + int sys_umask(mode_t mode, mode_t *old) { + long ret; + long error = syscall(SYSCALL_UMASK, &ret, mode); + *old = ret; + return error; + } + + int sys_fchmod(int fd, mode_t mode) { + long ret; + return syscall(SYSCALL_FCHMOD, &ret, fd, mode); + } + + int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + long ret; + return syscall(SYSCALL_FCHMODAT, &ret, fd, (uint64_t)pathname, mode, flags); + } + + int sys_chmod(const char *pathname, mode_t mode) { + return sys_fchmodat(AT_FDCWD, pathname, mode, 0); + } + + int sys_readlinkat(int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length) { + long ret; + long error = syscall(SYSCALL_READLINKAT, &ret, dirfd, (uint64_t)path, (uint64_t)buffer, max_size); + *length = ret; + return error; + } + + int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length) { + return sys_readlinkat(AT_FDCWD, path, buffer, max_size, length); + } + + static int dolink(int oldfd, const char *oldpath, int newfd, const char *newpath, int flags, int type) { + long ret; + return syscall(SYSCALL_LINKAT, &ret, oldfd, (uint64_t)oldpath, newfd, (uint64_t)newpath, flags, type); + } + + int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + return dolink(olddirfd, old_path, newdirfd, new_path, flags, 0); + } + + int sys_link(const char *old_path, const char *new_path) { + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); + } + + int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + return dolink(AT_FDCWD, target_path, dirfd, link_path, 0, 1); + } + + int sys_symlink(const char *target_path, const char *link_path) { + return sys_symlinkat(target_path, AT_FDCWD, link_path); + } + + int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + long ret; + return syscall(SYSCALL_MKDIRAT, &ret, dirfd, (uint64_t)path, mode); + } + + int sys_mkdir(const char *path, mode_t mode) { + return sys_mkdirat(AT_FDCWD, path, mode); + } + + int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + long ret; + long err = syscall(SYSCALL_IOCTL, &ret, fd, request, (uint64_t)arg); + *result = ret; + return err; + } + + int sys_unlinkat(int fd, const char *path, int flags) { + long ret; + return syscall(SYSCALL_UNLINKAT, &ret, fd, (uint64_t)path, flags); + } + + int sys_faccessat(int dirfd, const char *pathname, int mode, int flags){ + long ret; + return syscall(SYSCALL_FACCESSAT, &ret, dirfd, (uint64_t)pathname, mode, flags); + } + + int sys_access(const char *path, int mode){ + return sys_faccessat(AT_FDCWD, path, mode, 0); + } + + int sys_pipe(int *fds, int flags) { + long ret = 0; + long err = syscall(SYSCALL_PIPE2, &ret, flags); + if(err) + return err; + + fds[0] = ret & 0xffffffff; + fds[1] = (ret >> 32) & 0xffffffff; + return err; + } + + int sys_chdir(const char *path) { + long ret; + return syscall(SYSCALL_CHDIR, &ret, (uint64_t)path); + } + + int sys_fchdir(int fd) { + long ret; + return syscall(SYSCALL_FCHDIR, &ret, fd); + } + + int sys_fcntl(int fd, int request, va_list args, int *result) { + long arg = va_arg(args, uint64_t); + long ret; + long err = syscall(SYSCALL_FCNTL, &ret, fd, request, arg); + *result = ret; + return err; + } + + int sys_dup(int fd, int flags, int *newfd) { + (void)flags; + long ret; + long err = syscall(SYSCALL_DUP, &ret, fd); + *newfd = ret; + return err; + } + + int sys_dup2(int fd, int flags, int newfd) { + (void)flags; + long ret; + return syscall(SYSCALL_DUP2, &ret, fd, newfd); + } + + int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read) { + long ret; + long err = syscall(SYSCALL_GETDENTS, &ret, handle, (uint64_t)buffer, max_size); + if(err) + return err; + *bytes_read = ret; + return err; + } + + int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + (void)ru; + long ret; + long err = syscall(SYSCALL_WAITPID, &ret, pid, (uint64_t)status, flags); + *ret_pid = ret; + return err; + } + + int sys_execve(const char *path, char *const argv[], char *const envp[]) { + long ret; + return syscall(SYSCALL_EXECVE, &ret, (uint64_t)path, (uint64_t)argv, (uint64_t)envp); + } + + int sys_fork(pid_t *pid) { + long ret = 0; + long error = syscall(SYSCALL_FORK, &ret); + *pid = ret; + return error; + } + + int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + long ret; + switch (fsfdt) { + case fsfd_target::path: + return syscall(SYSCALL_FSTATAT, &ret, AT_FDCWD, (uint64_t)path, (uint64_t)statbuf, flags); + case fsfd_target::fd: + return syscall(SYSCALL_FSTAT, &ret, fd, (uint64_t)statbuf); + case fsfd_target::fd_path: + return syscall(SYSCALL_FSTATAT, &ret, fd, (uint64_t)path, (uint64_t)statbuf, flags); + default: + mlibc::infoLogger() << "mlibc: stat: Unknown fsfd_target: " << (int)fsfdt << frg::endlog; + return ENOSYS; + } + } + + pid_t sys_getpid() { + long ret; + syscall(SYSCALL_GETPID, &ret); + return ret; + } + + void sys_libc_log(const char *message) { + long ret; + syscall(SYSCALL_PRINT, &ret, (uint64_t)message); + } + + [[noreturn]] void sys_libc_panic() { + sys_libc_log("mlibc: panic"); + sys_exit(1); + } + + [[noreturn]] void sys_exit(int status) { + syscall(SYSCALL_EXIT, NULL, status); + __builtin_unreachable(); + } + + int sys_tcb_set(void *pointer) { + long r; + return syscall(SYSCALL_ARCHCTL, &r, ARCH_CTL_SET_FSBASE, (uint64_t)pointer); + } + + #define FUTEX_WAIT 0 + #define FUTEX_WAKE 1 + + int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + long ret; + return syscall(SYSCALL_FUTEX, &ret, (uint64_t)pointer, FUTEX_WAIT, expected, (uint64_t)time); + } + + int sys_futex_wake(int *pointer) { + long ret; + return syscall(SYSCALL_FUTEX, &ret, (uint64_t)pointer, FUTEX_WAKE, INT_MAX, NULL); + } + + int sys_anon_allocate(size_t size, void **pointer) { + size += 4096 - (size % 4096); + return sys_vm_map(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0, pointer); + } + int sys_anon_free(void *pointer, size_t size) { + size += 4096 - (size % 4096); + return sys_vm_unmap(pointer, size); + } + + int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + long ret; + long err = syscall(SYSCALL_OPENAT, &ret, dirfd, (uint64_t)path, flags, mode); + if(err) + return err; + *fd = ret; + return 0; + } + + int sys_open(const char *pathname, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, pathname, flags, mode, fd); + }; + + int sys_open_dir(const char *path, int *handle) { + return sys_open(path, O_DIRECTORY, 0, handle); + } + + int sys_read(int fd, void *buff, size_t count, ssize_t *bytes_read) { + long readc; + long error = syscall(SYSCALL_READ, &readc, fd, (uint64_t)buff, count); + *bytes_read = readc; + return error; + } + + int sys_write(int fd, const void *buff, size_t count, ssize_t *bytes_written) { + long writec; + long error = syscall(SYSCALL_WRITE, &writec, fd, (uint64_t)buff, count); + *bytes_written = writec; + return error; + } + + int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + long ret = 0; + long error = syscall(SYSCALL_SEEK, &ret, fd, offset, whence); + *new_offset = ret; + return error; + } + + int sys_close(int fd) { + long r; + return syscall(SYSCALL_CLOSE, &r, fd); + } + + int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + long ret; + long err = syscall(SYSCALL_MMAP, &ret, (uint64_t)hint, size, prot, flags, fd, offset); + *window = (void *)ret; + return err; + } + + int sys_vm_unmap(void *pointer, size_t size) { + long ret; + return syscall(SYSCALL_MUNMAP, &ret, (uintptr_t)pointer, size); + } + + int sys_isatty(int fd) { + long ret; + return syscall(SYSCALL_ISATTY, &ret, fd); + } + + int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec ts; + long ret; + int err = syscall(SYSCALL_CLOCKGET, &ret, clock, (uint64_t)&ts); + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + return err; + } +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/access.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/access.h new file mode 100755 index 0000000..cb83931 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/auxv.h new file mode 100755 index 0000000..c43f878 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..0b0ec27 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..7dc8d7c --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..6a42da5 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/dev_t.h new file mode 100755 index 0000000..bca881e --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/epoll.h new file mode 100755 index 0000000..eb4b76d --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/errno.h new file mode 100755 index 0000000..6e507de --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/fcntl.h new file mode 100755 index 0000000..463e2c9 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/gid_t.h new file mode 100755 index 0000000..abce6d6 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/in.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/in.h new file mode 100755 index 0000000..418d1d5 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/ino_t.h new file mode 100755 index 0000000..4c20aca --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/inotify.h new file mode 100755 index 0000000..b5cb282 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/ipc.h new file mode 100755 index 0000000..9f8d68e --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/astral/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/limits.h new file mode 100755 index 0000000..6c88db2 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5d78fdf --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..bb3b625 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/packet.h new file mode 100755 index 0000000..998ef1a --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/pid_t.h new file mode 100755 index 0000000..baa90f6 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/poll.h new file mode 100755 index 0000000..8ea6a0a --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/ptrace.h new file mode 100755 index 0000000..b2517b2 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/random.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/random.h new file mode 100755 index 0000000..12eb458 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/random.h @@ -0,0 +1 @@ +../../../../abis/astral/random.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/reboot.h new file mode 100755 index 0000000..77013a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/resource.h new file mode 100755 index 0000000..88d7402 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..4ac7b2f --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/astral/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..df7bccf --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/shm.h new file mode 100755 index 0000000..2eb1f06 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/astral/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/sigevent.h new file mode 100755 index 0000000..83d069b --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/linux/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/signal.h new file mode 100755 index 0000000..4dcb0b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/socket.h new file mode 100755 index 0000000..f1dc016 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/stat.h new file mode 100755 index 0000000..1f63b41 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/time.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/time.h new file mode 100755 index 0000000..2a02625 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/uid_t.h new file mode 100755 index 0000000..b306777 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/utsname.h new file mode 100755 index 0000000..b285754 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..bbe258c --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/vt.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/vt.h new file mode 100755 index 0000000..5798a4a --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/vt.h @@ -0,0 +1 @@ +../../../../abis/linux/vt.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/astral/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/astral/include/astral/archctl.h b/user/include/mlibc/sysdeps/astral/include/astral/archctl.h new file mode 100644 index 0000000..7e4f2a1 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/astral/archctl.h @@ -0,0 +1,23 @@ +#ifndef _ASTRAL_ARCHCTL_H +#define _ASTRAL_ARCHCTL_H + +#define ARCH_CTL_SET_GSBASE 0 +#define ARCH_CTL_SET_FSBASE 1 +#define ARCH_CTL_GET_GSBASE 2 +#define ARCH_CTL_GET_FSBASE 3 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int arch_ctl(int, void *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ASTRAL_ARCH_CTLH */ diff --git a/user/include/mlibc/sysdeps/astral/include/astral/syscall.h b/user/include/mlibc/sysdeps/astral/include/astral/syscall.h new file mode 100644 index 0000000..8414286 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/include/astral/syscall.h @@ -0,0 +1,123 @@ +#ifndef _ASTRAL_SYSCALL_H +#define _ASTRAL_SYSCALL_H + +#include +#include + +#define SYSCALL_PRINT 0 +#define SYSCALL_MMAP 1 +#define SYSCALL_OPENAT 2 +#define SYSCALL_READ 3 +#define SYSCALL_SEEK 4 +#define SYSCALL_CLOSE 5 +#define SYSCALL_ARCHCTL 6 +#define SYSCALL_WRITE 7 +#define SYSCALL_GETPID 8 +#define SYSCALL_FSTAT 9 +#define SYSCALL_FSTATAT 10 +#define SYSCALL_FORK 11 +#define SYSCALL_EXECVE 12 +#define SYSCALL_EXIT 13 +#define SYSCALL_WAITPID 14 +#define SYSCALL_MUNMAP 15 +#define SYSCALL_GETDENTS 16 +#define SYSCALL_DUP 17 +#define SYSCALL_DUP2 18 +#define SYSCALL_DUP3 19 +#define SYSCALL_FCNTL 20 +#define SYSCALL_CHDIR 21 +#define SYSCALL_PIPE2 22 +#define SYSCALL_ISATTY 23 +#define SYSCALL_FACCESSAT 24 +#define SYSCALL_UNLINKAT 25 +#define SYSCALL_IOCTL 26 +#define SYSCALL_MKDIRAT 27 +#define SYSCALL_CLOCKGET 28 +#define SYSCALL_LINKAT 29 +#define SYSCALL_READLINKAT 30 +#define SYSCALL_FCHMOD 31 +#define SYSCALL_FCHMODAT 32 +#define SYSCALL_UMASK 33 +#define SYSCALL_POLL 34 +#define SYSCALL_NANOSLEEP 35 +#define SYSCALL_FTRUNCATE 36 +#define SYSCALL_MOUNT 37 +#define SYSCALL_FCHOWNAT 38 +#define SYSCALL_UTIMENSAT 39 +#define SYSCALL_RENAMEAT 40 +#define SYSCALL_SOCKET 41 +#define SYSCALL_BIND 42 +#define SYSCALL_SENDMSG 43 +#define SYSCALL_SETSOCKOPT 44 +#define SYSCALL_RECVMSG 45 +#define SYSCALL_LISTEN 46 +#define SYSCALL_CONNECT 47 +#define SYSCALL_ACCEPT 48 +#define SYSCALL_NEWTHREAD 49 +#define SYSCALL_THREADEXIT 50 +#define SYSCALL_FUTEX 51 +#define SYSCALL_GETTID 52 +#define SYSCALL_GETPPID 53 +#define SYSCALL_GETPGID 54 +#define SYSCALL_GETSID 55 +#define SYSCALL_SETSID 56 +#define SYSCALL_SETPGID 57 +#define SYSCALL_SIGACTION 58 +#define SYSCALL_SIGALTSTACK 59 +#define SYSCALL_SIGPROCMASK 60 +#define SYSCALL_KILL 61 +#define SYSCALL_SIGRETURN 62 +#define SYSCALL_UNAME 63 +#define SYSCALL_HOSTNAME 64 +#define SYSCALL_SYNC 65 +#define SYSCALL_FSYNC 66 +#define SYSCALL_FCHDIR 67 +#define SYSCALL_SETITIMER 68 +#define SYSCALL_GETITIMER 69 +#define SYSCALL_SOCKETPAIR 70 +#define SYSCALL_GETSOCKNAME 71 +#define SYSCALL_GETPEERNAME 72 +#define SYSCALL_CHROOT 73 +#define SYSCALL_PAUSE 74 +#define SYSCALL_PPOLL 75 +#define SYSCALL_PREAD 76 +#define SYSCALL_PWRITE 77 +#define SYSCALL_MKNODAT 78 +#define SYSCALL_GETRESUID 79 +#define SYSCALL_GETRESGID 80 +#define SYSCALL_SETRESUID 81 +#define SYSCALL_SETRESGID 82 +#define SYSCALL_MPROTECT 83 +#define SYSCALL_SETUID 84 +#define SYSCALL_SETEUID 85 +#define SYSCALL_SETGID 86 +#define SYSCALL_SETEGID 87 +#define SYSCALL_SIGSUSPEND 88 +#define SYSCALL_SIGTIMEDWAIT 89 +#define SYSCALL_SIGPENDING 90 +#define SYSCALL_KILLTHREAD 91 +#define SYSCALL_SHUTDOWN 92 +#define SYSCALL_NICE 93 +#define SYSCALL_FLOCK 94 +#define SYSCALL_GETCPU 95 + +#ifndef __MLIBC_ABI_ONLY + +static long syscall(long func, long* ret, uint64_t p1 = 0, uint64_t p2 = 0, uint64_t p3 = 0, uint64_t p4 = 0, uint64_t p5 = 0, uint64_t p6 = 0) { + volatile long err; + + register uint64_t r4 asm("r10") = p4; + register uint64_t r5 asm("r8") = p5; + register uint64_t r6 asm("r9") = p6; + + asm volatile("syscall" + : "=a"(*ret), "=d"(err) + : "a"(func), "D"(p1), "S"(p2), "d"(p3), "r"(r4), + "r"(r5), "r"(r6) + : "memory", "rcx", "r11"); + return err; +} + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif /* _ASTRAL_SYSCALL_H */ diff --git a/user/include/mlibc/sysdeps/astral/meson.build b/user/include/mlibc/sysdeps/astral/meson.build new file mode 100644 index 0000000..04b168c --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/meson.build @@ -0,0 +1,123 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': true, + 'glibc': true, + 'bsd': true, +} + +rtld_sources += files( + 'generic/generic.cpp', + 'generic/astral.cpp', +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/astral.cpp', + 'generic/generic.cpp', + 'threading/x86_64-thread.cpp', + 'threading/x86_64-thread-entry.S', + 'signal/x86_64-restorer.S', +) + +if not no_headers + install_headers( + 'include/abi-bits/access.h', + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/vt.h', + 'include/abi-bits/random.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true, + ) + install_headers( + 'include/astral/syscall.h', + 'include/astral/archctl.h', + subdir: 'astral', + follow_symlinks: true, + ) +endif + +if not headers_only + crt = custom_target('crt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt1.S', + output: 'crt1.o', + install: true, + install_dir: get_option('libdir') + ) + + crt_pie = custom_target('Scrt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt1.S', + output: 'Scrt1.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif diff --git a/user/include/mlibc/sysdeps/astral/signal/x86_64-restorer.S b/user/include/mlibc/sysdeps/astral/signal/x86_64-restorer.S new file mode 100644 index 0000000..364525f --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/signal/x86_64-restorer.S @@ -0,0 +1,7 @@ +.section .text +.global __mlibc_restorer +__mlibc_restorer: + sub $8, %rsp + mov $62, %rax + syscall +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/astral/threading/x86_64-thread-entry.S b/user/include/mlibc/sysdeps/astral/threading/x86_64-thread-entry.S new file mode 100644 index 0000000..4a8fc26 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/threading/x86_64-thread-entry.S @@ -0,0 +1,8 @@ + .section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_thread_trampoline +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/astral/threading/x86_64-thread.cpp b/user/include/mlibc/sysdeps/astral/threading/x86_64-thread.cpp new file mode 100644 index 0000000..4db77e8 --- /dev/null +++ b/user/include/mlibc/sysdeps/astral/threading/x86_64-thread.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_thread_trampoline(void *(*fn)(void *), Tcb *tcb, void *arg) { + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"failed to set tcb for new thread"); + + while(__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + tcb->invokeThreadFunc(reinterpret_cast(fn), arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +#define DEFAULT_STACK 0x400000 + +namespace mlibc { + int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if(!*stack) { + *stack_base = mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if(*stack_base == MAP_FAILED) + return errno; + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; + } +} diff --git a/user/include/mlibc/sysdeps/dripos/.clang-format b/user/include/mlibc/sysdeps/dripos/.clang-format new file mode 100644 index 0000000..4662692 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/.clang-format @@ -0,0 +1,2 @@ +--- +DisableFormat: true diff --git a/user/include/mlibc/sysdeps/dripos/crt-x86_64/crt1.S b/user/include/mlibc/sysdeps/dripos/crt-x86_64/crt1.S new file mode 100644 index 0000000..18d109e --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/crt-x86_64/crt1.S @@ -0,0 +1,9 @@ + +.section .text +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/dripos/generic/entry.cpp b/user/include/mlibc/sysdeps/dripos/generic/entry.cpp new file mode 100644 index 0000000..62c9dbe --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/generic/entry.cpp @@ -0,0 +1,14 @@ + +#include +#include +#include +#include + +extern char **environ; + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux sysdeps) + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} + diff --git a/user/include/mlibc/sysdeps/dripos/generic/generic.cpp b/user/include/mlibc/sysdeps/dripos/generic/generic.cpp new file mode 100644 index 0000000..643b14e --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/generic/generic.cpp @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +void sys_libc_log(const char *message) { + unsigned long res; + asm volatile ("syscall" : "=a"(res) + : "a"(50), "D"(message) + : "rcx", "r11", "rdx"); +} + +void sys_libc_panic() { + mlibc::infoLogger() << "\e[31mmlibc: panic!" << frg::endlog; + asm volatile ("syscall" : + : "a"(12), "D"(1) + : "rcx", "r11", "rdx"); +} + +int sys_tcb_set(void *pointer) { + int res; + asm volatile ("syscall" : "=a"(res) + : "a"(300), "D"(pointer) + : "rcx", "r11", "rdx"); + return res; +} + +int sys_anon_allocate(size_t size, void **pointer) { + void *ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(9), "D"(0), "S"(size) + : "rcx", "r11"); + + if (!ret) + return sys_errno; + + *pointer = ret; + return 0; +} + +int sys_anon_free(void *pointer, size_t size) { + int unused_return; + int sys_errno; + + asm volatile ("syscall" + : "=a"(unused_return), "=d"(sys_errno) + : "a"(11), "D"(pointer), "S"(size) + : "rcx", "r11"); + + if (unused_return) + return sys_errno; + + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD +void sys_exit(int status) { + asm volatile ("syscall" : + : "a"(12), "D"(status) + : "rcx", "r11", "rdx"); +} +#endif + +#ifndef MLIBC_BUILDING_RTLD +int sys_clock_get(int clock, time_t *secs, long *nanos) { + return 0; +} +#endif + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + int ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(2), "D"(path), "S"(flags), "d"(0) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *fd = ret; + return 0; +} + +int sys_close(int fd) { + int ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(3), "D"(fd) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + ssize_t ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(0), "D"(fd), "S"(buf), "d"(count) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *bytes_read = ret; + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + ssize_t ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(1), "D"(fd), "S"(buf), "d"(count) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *bytes_written = ret; + return 0; +} +#endif + + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + off_t ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(8), "D"(fd), "S"(offset), "d"(whence) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *new_offset = ret; + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, + int fd, off_t offset, void **window) { + __ensure(flags & MAP_ANONYMOUS); + void *ret; + int sys_errno; + + // mlibc::infoLogger() << "calling sys_vm_map with size: " << size << frg::endlog; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(9), "D"(hint), "S"(size) + : "rcx", "r11"); + + if (!ret) + return sys_errno; + + *window = ret; + + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + return sys_anon_free(pointer, size); +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + uint64_t err; + asm volatile ("syscall" + : "=d"(err) + : "a"(66), "D"(pointer), "S"(expected) + : "rcx", "r11"); + + if (err) { + return -1; + } + + return 0; +} + +int sys_futex_wake(int *pointer) { + uint64_t err; + asm volatile ("syscall" + : "=d"(err) + : "a"(65), "D"(pointer) + : "rcx", "r11"); + + if (err) { + return -1; + } + + return 0; +} + +// All remaining functions are disabled in ldso. +#ifndef MLIBC_BUILDING_RTLD + +int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + int tid; + + asm volatile ("syscall" + : "=a"(tid) + : "a"(67), "D"(__mlibc_start_thread), "S"(stack), "d"(tcb) + : "rcx", "r11"); + + if (tid_out) + *tid_out = tid; + + return 0; +} + +void sys_thread_exit() { + asm volatile ("syscall" + : + : "a"(68) + : "rcx", "r11"); + __builtin_trap(); +} + +int sys_sleep(time_t *secs, long *nanos) { + long ms = (*nanos / 1000000) + (*secs * 1000); + asm volatile ("syscall" + : + : "a"(6), "D"(ms) + : "rcx", "r11"); + *secs = 0; + *nanos = 0; + return 0; +} + +int sys_fork(pid_t *child) { + pid_t ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(57) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *child = ret; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + int ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(59), "D"(path), "S"(argv), "d"(envp) + : "rcx", "r11"); + + if (sys_errno != 0) + return sys_errno; + + return 0; +} + +pid_t sys_getpid() { + pid_t pid; + asm volatile ("syscall" : "=a"(pid) + : "a"(5) + : "rcx", "r11", "rdx"); + return pid; +} +pid_t sys_getppid() { + pid_t ppid; + asm volatile ("syscall" : "=a"(ppid) + : "a"(14) + : "rcx", "r11", "rdx"); + return ppid; +} + +#endif // MLIBC_BUILDING_RTLD + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/dripos/generic/thread.cpp b/user/include/mlibc/sysdeps/dripos/generic/thread.cpp new file mode 100644 index 0000000..42cd758 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/generic/thread.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while(!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} //namespace mlibc diff --git a/user/include/mlibc/sysdeps/dripos/generic/thread_entry.S b/user/include/mlibc/sysdeps/dripos/generic/thread_entry.S new file mode 100644 index 0000000..51e703b --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/generic/thread_entry.S @@ -0,0 +1,11 @@ + +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/access.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/access.h new file mode 100755 index 0000000..daaf1c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/dripos/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/auxv.h new file mode 100755 index 0000000..866c8bb --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/dripos/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..d5dd73d --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..91cfa43 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..cc58e58 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/dev_t.h new file mode 100755 index 0000000..cf31f9e --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/epoll.h new file mode 100755 index 0000000..682eab8 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/dripos/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/errno.h new file mode 100755 index 0000000..2a2ab26 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/dripos/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/fcntl.h new file mode 100755 index 0000000..e99f2e3 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/dripos/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/gid_t.h new file mode 100755 index 0000000..e74c2ff --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/in.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/in.h new file mode 100755 index 0000000..49cafa0 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/dripos/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/ino_t.h new file mode 100755 index 0000000..28eddad --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/inotify.h new file mode 100755 index 0000000..0f86a3a --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/dripos/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/ipc.h new file mode 100755 index 0000000..9dc3405 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/dripos/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/limits.h new file mode 100755 index 0000000..98eea7a --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/dripos/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/mode_t.h new file mode 100755 index 0000000..ffc9fc9 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..ff66abe --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/packet.h new file mode 100755 index 0000000..5702e41 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/dripos/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/pid_t.h new file mode 100755 index 0000000..aebe4f7 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/poll.h new file mode 100755 index 0000000..d15b54c --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/dripos/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/ptrace.h new file mode 100755 index 0000000..057b78f --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/dripos/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/resource.h new file mode 100755 index 0000000..0d932ce --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/dripos/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..19471c3 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..4e4317a --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/dripos/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/shm.h new file mode 100755 index 0000000..a29490f --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/dripos/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/sigevent.h new file mode 100755 index 0000000..2ef47a3 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/dripos/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/signal.h new file mode 100755 index 0000000..57f529a --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/dripos/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/socket.h new file mode 100755 index 0000000..355f548 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/dripos/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/stat.h new file mode 100755 index 0000000..eac265e --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/dripos/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/termios.h new file mode 100755 index 0000000..c84dbc8 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/dripos/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/time.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/time.h new file mode 100755 index 0000000..2a02625 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/uid_t.h new file mode 100755 index 0000000..1606195 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/dripos/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/utsname.h new file mode 100755 index 0000000..5e19238 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/dripos/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..598a480 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/dripos/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/wait.h new file mode 100755 index 0000000..e65e224 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/dripos/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/dripos/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/dripos/include/mlibc/thread-entry.hpp b/user/include/mlibc/sysdeps/dripos/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..2dd88a6 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/include/mlibc/thread-entry.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +extern "C" void __mlibc_start_thread(void); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb); + +namespace mlibc { + void *prepare_stack(void *entry, void *user_arg, void *tcb); +} diff --git a/user/include/mlibc/sysdeps/dripos/meson.build b/user/include/mlibc/sysdeps/dripos/meson.build new file mode 100644 index 0000000..b0eb2d8 --- /dev/null +++ b/user/include/mlibc/sysdeps/dripos/meson.build @@ -0,0 +1,84 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': false, + 'glibc': true, + 'bsd': true, +} + +rtld_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/generic.cpp', + 'generic/thread.cpp', + 'generic/thread_entry.S' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) +endif + +if not headers_only + crt = custom_target('crt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt1.S', + output: 'crt1.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/user/include/mlibc/sysdeps/generic-helpers/include/generic-helpers/netlink.hpp b/user/include/mlibc/sysdeps/generic-helpers/include/generic-helpers/netlink.hpp new file mode 100644 index 0000000..6be6e89 --- /dev/null +++ b/user/include/mlibc/sysdeps/generic-helpers/include/generic-helpers/netlink.hpp @@ -0,0 +1,291 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mlibc/allocator.hpp" +#include "mlibc/posix-sysdeps.hpp" + +namespace { + +/** + * Helper class for issuing rtnetlink requests and receiving replies. + */ +struct NetlinkHelper { + ~NetlinkHelper() { + if(fd_) + close(*fd_); + } + + bool send_request(int type) { + if(!fd_ || *fd_ == -1) { + int fd; + if(int e = mlibc::sys_socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE, &fd); e) + return false; + fd_ = fd; + } + + struct NetlinkMessage { + nlmsghdr hdr; + rtgenmsg msg; + } request; + + memset(&request, 0, sizeof(request)); + request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + request.hdr.nlmsg_type = type; + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request) - sizeof(nlmsghdr)); + request.msg.rtgen_family = AF_UNSPEC; + + return send(fd_.value(), reinterpret_cast(&request), sizeof(request), 0) == sizeof(request); + } + + bool recv(void cb(void *, const nlmsghdr *), void *ctx) { + ssize_t read; + + while((read = ::recv(fd_.value(), reinterpret_cast(data_.data()), data_.size(), 0)) > 0) { + auto hdr = reinterpret_cast(data_.data()); + + for(; NLMSG_OK(hdr, static_cast(read)); hdr = NLMSG_NEXT(hdr, read)) { + if(hdr->nlmsg_type == NLMSG_DONE) + return true; + if(hdr->nlmsg_type == NLMSG_ERROR) { + nlmsgerr *err = reinterpret_cast(NLMSG_DATA(hdr)); + mlibc::infoLogger() << "mlibc: NetlinkHelper received NLMSG_ERROR " << -err->error << ": " + << strerror(-err->error) << frg::endlog; + return false; + } + + cb(ctx, hdr); + } + } + + return false; + } +private: + frg::optional fd_; + frg::array data_; +}; + +/** + * Helper class for constructing `struct ifaddrs` with data from rtnetlink. + * + * This can be used for implementing `sys_getifaddrs` if the OS supports rtnetlink. + */ +struct IfaddrHelper { + ifaddrs ifa = {}; + + int if_index_; + + sockaddr_storage addr_; + sockaddr_storage netmask_; + sockaddr_storage broadcast_; + sockaddr_storage dest_addr_; + + char name_[IFNAMSIZ + 1]; + +public: + explicit IfaddrHelper(ifaddrs **list) { + // append ourselves to the end of the chain + ifaddrs *last = *list; + + if(last) { + while(last->ifa_next) + last = last->ifa_next; + + last->ifa_next = &this->ifa; + } else { + *list = &this->ifa; + } + } + + void set_broadcast_addr(int family, const void *data, size_t byteCount) { + ifa.ifa_broadaddr = copy_addr(family, data, byteCount, &broadcast_); + } + + /** + * Handler for IFA_ADDRESS. + * + * Sets the destination address, and provides the fallback for the local address if + * it is not separately specified, via IFA_LOCAL and its handler. + */ + void set_addr(int family, const void *data, size_t bytes) { + if(ifa.ifa_addr == nullptr) + ifa.ifa_addr = copy_addr(family, data, bytes, &addr_); + + ifa.ifa_dstaddr = copy_addr(family, data, bytes, &dest_addr_); + } + + /** + * Handler for IFA_LOCAL. + * + * Also sets the destination address, if appropriate; this will be overridden if a + * destination address is specified, via IFA_ADDRESS and its handler. + */ + void set_local_address(int family, const void *data, size_t byteCount) { + // rtnetlink distinguishes the addresses IFA_ADDRESS and IFA_LOCAL + // - IFA_LOCAL is the local interface address. + // - IFA_ADDRESS is the prefix address: + // - for a point-to-point connection, this is the destination address, + // - while for a normally configured broadcast interface, it is the same as IFA_LOCAL. + + // if we already have an ifa_addr, move it over to ifa_dstaddr + if(ifa.ifa_addr != nullptr) + ifa.ifa_dstaddr = reinterpret_cast(memcpy(&dest_addr_, &addr_, sizeof(addr_))); + + ifa.ifa_addr = copy_addr(family, data, byteCount, &addr_); + } + + void set_netmask(int family, size_t prefix_length) { + netmask_.ss_family = family; + + auto dst = sockaddr_bytes(family, &netmask_); + // set as many complete bytes as needed to 255 + memset(dst.data(), 0xFF, prefix_length / 8); + + // if needed, set the last partial byte to its correct mask + if(prefix_length % 8) + dst[prefix_length/8] = (0xFF << (8 - (prefix_length % 8))) & 0xFF; + + ifa.ifa_netmask = reinterpret_cast(&netmask_); + } + + void set_packet_attrs(int ifindex, unsigned short hatype, unsigned char halen) { + sockaddr_ll *sll = reinterpret_cast(&addr_); + sll->sll_ifindex = ifindex; + sll->sll_hatype = hatype; + sll->sll_halen = halen; + } + +private: + /** + * Copy an address to its storage, and return a pointer to that. + */ + sockaddr *copy_addr(sa_family_t family, const void *data, size_t byteCount, sockaddr_storage *ss) { + ss->ss_family = family; + + auto sb = sockaddr_bytes(family, ss); + memcpy(sb.data(), data, frg::min(byteCount, sb.size())); + + if(family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(data) || IN6_IS_ADDR_MC_LINKLOCAL(data))) { + reinterpret_cast(ss)->sin6_scope_id = if_index_; + } + + return reinterpret_cast(ss); + } + + /** + * Retrieve an appropriately sized span for the sockaddr's addr + */ + frg::span sockaddr_bytes(int family, sockaddr_storage *ss) { + if(family == AF_INET) { + sockaddr_in *ss4 = reinterpret_cast(ss); + return {reinterpret_cast(&ss4->sin_addr), sizeof(ss4->sin_addr)}; + } else if(family == AF_INET6) { + sockaddr_in6 *ss6 = reinterpret_cast(ss); + return {reinterpret_cast(&ss6->sin6_addr), sizeof(ss6->sin6_addr)}; + } else if(family == AF_PACKET) { + sockaddr_ll *sll = reinterpret_cast(ss); + return {reinterpret_cast(&sll->sll_addr), sizeof(sll->sll_addr)}; + } else { + mlibc::panicLogger() << "unimplemented family " << family << frg::endlog; + __builtin_unreachable(); + } + } +}; + +// We rely on the appended ifaddrs struct to actually be a IfaddrHelper +static_assert(offsetof(IfaddrHelper, ifa) == 0); + +/** + * Callback function to be used with NetlinkHelper for implementing `sys_getifaddrs` by using rtnetlink. + */ +void getifaddrs_callback(void *context, const nlmsghdr *hdr) { + ifaddrs **out = reinterpret_cast(context); + + if(hdr->nlmsg_type == RTM_NEWLINK) { + ifinfomsg *ifi = reinterpret_cast(NLMSG_DATA(hdr)); + + auto new_addr = frg::construct(getAllocator(), out); + new_addr->if_index_ = ifi->ifi_index; + new_addr->ifa.ifa_flags = ifi->ifi_flags; + + rtattr *rta = IFLA_RTA(ifi); + size_t rta_len = IFLA_PAYLOAD(hdr); + + while(RTA_OK(rta, rta_len)) { + if(rta->rta_type == IFLA_ADDRESS) { + if(RTA_PAYLOAD(rta) < sizeof(new_addr->addr_)) { + new_addr->set_addr(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->set_packet_attrs(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); + } + } else if(rta->rta_type == IFLA_BROADCAST) { + if(RTA_PAYLOAD(rta) < sizeof(new_addr->broadcast_)) { + new_addr->set_broadcast_addr(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->set_packet_attrs(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); + } + } else if(rta->rta_type == IFLA_IFNAME) { + if(RTA_PAYLOAD(rta) < sizeof(new_addr->name_)) { + memcpy(new_addr->name_, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->ifa.ifa_name = new_addr->name_; + } + } + + rta = RTA_NEXT(rta, rta_len); + } + } else if(hdr->nlmsg_type == RTM_NEWADDR) { + ifaddrmsg *msg = reinterpret_cast(NLMSG_DATA(hdr)); + + const IfaddrHelper *current = reinterpret_cast(*out); + while (current != nullptr && current->if_index_ != static_cast(msg->ifa_index)) { + current = reinterpret_cast(current->ifa.ifa_next); + } + + IfaddrHelper *new_addr = frg::construct(getAllocator(), out); + new_addr->if_index_ = static_cast(msg->ifa_index); + + if(current != nullptr) { + strcpy(new_addr->name_, current->name_); + new_addr->ifa.ifa_name = new_addr->name_; + new_addr->ifa.ifa_flags = current->ifa.ifa_flags; + } + + rtattr *rta = IFA_RTA(msg); + size_t rta_len = IFA_PAYLOAD(hdr); + + while(RTA_OK(rta, rta_len)) { + if(rta->rta_type == IFA_ADDRESS) { + if(msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { + new_addr->set_addr(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->set_netmask(msg->ifa_family, msg->ifa_prefixlen); + } + } else if(rta->rta_type == IFA_BROADCAST) { + if(msg->ifa_family == AF_INET) { + new_addr->set_broadcast_addr(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); + if(current == nullptr) { + new_addr->ifa.ifa_flags |= IFF_BROADCAST; + } + } + } else if(rta->rta_type == IFA_LOCAL) { + if(msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { + new_addr->set_local_address(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); + } + } else if(rta->rta_type == IFA_LABEL) { + if(RTA_PAYLOAD(rta) < sizeof(new_addr->name_)) { + memcpy(new_addr->name_, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->ifa.ifa_name = new_addr->name_; + } + } + + rta = RTA_NEXT(rta, rta_len); + } + } +} + +} // namespace diff --git a/user/include/mlibc/sysdeps/ironclad/.clang-format b/user/include/mlibc/sysdeps/ironclad/.clang-format new file mode 100644 index 0000000..4662692 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/.clang-format @@ -0,0 +1,2 @@ +--- +DisableFormat: true diff --git a/user/include/mlibc/sysdeps/ironclad/crt-riscv64/Scrt1.S b/user/include/mlibc/sysdeps/ironclad/crt-riscv64/Scrt1.S new file mode 100644 index 0000000..17cc3fd --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/crt-riscv64/Scrt1.S @@ -0,0 +1,30 @@ +.weak __global_pointer$ +.hidden __global_pointer$ + +.section .text +.global _start +_start: + # Load gp. +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + + mv a0, sp + la a1, main + call __mlibc_entry@plt + unimp + +# Load gp from .preinit_array since it may be used by the executable's .init_array. +# We still load it in _start to account for static binaries. This matches glibc's behavior. +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + +.section .preinit_array,"aw" + .dword load_gp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/ironclad/crt-riscv64/crt1.S b/user/include/mlibc/sysdeps/ironclad/crt-riscv64/crt1.S new file mode 100644 index 0000000..faaf407 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/crt-riscv64/crt1.S @@ -0,0 +1,30 @@ +.weak __global_pointer$ +.hidden __global_pointer$ + +.section .text +.global _start +_start: + # Load gp. +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + + mv a0, sp + la a1, main + call __mlibc_entry + unimp + +# Load gp from .preinit_array since it may be used by the executable's .init_array. +# We still load it in _start to account for static binaries. This matches glibc's behavior. +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + +.section .preinit_array,"aw" + .dword load_gp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/ironclad/crt-riscv64/crti.S b/user/include/mlibc/sysdeps/ironclad/crt-riscv64/crti.S new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/sysdeps/ironclad/crt-riscv64/crtn.S b/user/include/mlibc/sysdeps/ironclad/crt-riscv64/crtn.S new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/sysdeps/ironclad/crt-x86_64/Scrt1.S b/user/include/mlibc/sysdeps/ironclad/crt-x86_64/Scrt1.S new file mode 100644 index 0000000..d0e8213 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/crt-x86_64/Scrt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + lea main(%rip), %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crt1.S b/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crt1.S new file mode 100644 index 0000000..6afb421 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crt1.S @@ -0,0 +1,10 @@ + +.section .text +.global _start +_start: + mov %rsp, %rdi + mov $main, %rsi + call __mlibc_entry + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crti.S b/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crti.S new file mode 100644 index 0000000..956c627 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crti.S @@ -0,0 +1,15 @@ + .ident "x86_64-ironclad-mlibc crti" + + .section .init + .globl _init + .type _init,@function +_init: + push %rax + + .section .fini + .globl _fini + .type _fini,@function +_fini: + push %rax + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crtn.S b/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crtn.S new file mode 100644 index 0000000..d3903d1 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/crt-x86_64/crtn.S @@ -0,0 +1,11 @@ +.ident "x86_64-ironclad-mlibc crtn" + +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/ironclad/generic/entry.cpp b/user/include/mlibc/sysdeps/ironclad/generic/entry.cpp new file mode 100644 index 0000000..9efec85 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/entry.cpp @@ -0,0 +1,26 @@ + +#include +#include +#include +#include +#include +#include + +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; + +extern "C" void __mlibc_sigret(void) { + int ret, errno; + SYSCALL0(SYSCALL_SIGNAL_RETURN); + mlibc::panicLogger() << "mlibc: failed to exit signal with " << errno << frg::endlog; + __builtin_unreachable(); +} + +extern "C" void __mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + __dlapi_enter(entry_stack); + + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} + diff --git a/user/include/mlibc/sysdeps/ironclad/generic/generic.cpp b/user/include/mlibc/sysdeps/ironclad/generic/generic.cpp new file mode 100644 index 0000000..abe181b --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/generic.cpp @@ -0,0 +1,1656 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_sigret(void); + +namespace mlibc { + +void sys_libc_log(const char *message) { + ssize_t unused; + sys_write(1, message, strlen(message), &unused); + sys_write(1, "\n", 1, &unused); +} + +void sys_libc_panic() { + ssize_t unused; + char const *message = "mlibc panicked unrecoverably\n"; + sys_write(2, message, strlen(message), &unused); + sys_exit(1); +} + +void sys_exit(int status) { + int ret, errno; + SYSCALL1(SYSCALL_EXIT, status); + __builtin_unreachable(); +} + +int sys_tcb_set(void *pointer) { + int errno; + +#if defined(__x86_64__) + int ret; + SYSCALL2(SYSCALL_ARCH_PRCTL, 1, pointer); +#elif defined(__riscv) && __riscv_xlen == 64 + uintptr_t tp = reinterpret_cast(pointer) + sizeof(Tcb); + asm volatile("mv tp, %0" : : "r"(tp) : "memory"); + errno = 0; +#else + #error Unknown architecture +#endif + + return errno; +} + +int sys_thread_getname(void *tcb, char *name, size_t size) { + int ret, errno; + auto t = reinterpret_cast(tcb); + SYSCALL3(SYSCALL_GETTIDID, t->tid, name, size); + return errno; +} + +int sys_thread_setname(void *tcb, const char *name) { + int ret, errno; + size_t len = strlen(name); + auto t = reinterpret_cast(tcb); + SYSCALL3(SYSCALL_SETTIDID, t->tid, name, len); + return errno; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + int ret, errno; + + int path_len = strlen(path); + SYSCALL4(SYSCALL_OPEN, dirfd, path, path_len, flags); + + // Have to check for O_CREAT since there is a pesky Linux-specific O_EXCL + // extension that makes it not fail if we are opening a block device. + // Otherwise O_EXCL with the file existing should be always a failure. + if (ret != -1 && (flags & O_EXCL) && (flags & O_CREAT)) { + SYSCALL1(SYSCALL_CLOSE, ret); + return EEXIST; + } + + // We implement creating files in this sysdep. + if ((errno == ENOENT) && (flags & O_CREAT) && ((flags & O_DIRECTORY) == 0)) { + SYSCALL5(SYSCALL_MAKENODE, AT_FDCWD, path, path_len, S_IFREG | mode, 0); + if (ret == -1) { + return errno; + } + SYSCALL4(SYSCALL_OPEN, AT_FDCWD, path, path_len, flags); + } + + // Handle some post-opening triggers. + if (ret != -1) { + if (flags & O_TRUNC) { + // If the file cannot be truncated, dont sweat it, some software + // depends on some things being truncate-able that ironclad does + // not allow. For example, some devices. + sys_ftruncate(ret, 0); + } + if (flags & O_DIRECTORY) { + struct stat st; + sys_stat(fsfd_target::fd, ret, NULL, 0, &st); + if (!S_ISDIR (st.st_mode)) { + SYSCALL1(SYSCALL_CLOSE, ret); + ret = -1; + errno = ENOTDIR; + } + } + } + + *fd = ret; + return errno; +} + +int sys_open_dir(const char *path, int *handle) { + return sys_open(path, O_RDONLY | O_DIRECTORY, 0660, handle); +} + +int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read) { + size_t ret; + int errno; + SYSCALL3(SYSCALL_GETDENTS, handle, buffer, max_size); + if (errno != 0) { + return errno; + } else { + *bytes_read = ret; + return 0; + } +} + +void sys_thread_exit() { + int ret, errno; + SYSCALL0(SYSCALL_EXIT_THREAD); + __builtin_unreachable(); +} + +int sys_close(int fd) { + int ret, errno; + SYSCALL1(SYSCALL_CLOSE, fd); + return errno; +} + +void sys_sync() { + int ret, errno; + SYSCALL0(SYSCALL_SYNC); + if (ret != 0) { + sys_libc_log("mlibc: sync failed"); + } +} + +int sys_fsync(int fd) { + int ret, errno; + SYSCALL2(SYSCALL_FSYNC, fd, 0); + return errno; +} + +int sys_fdatasync(int fd) { + int ret, errno; + SYSCALL2(SYSCALL_FSYNC, fd, 1); + return errno; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + ssize_t ret; + int errno; + SYSCALL5(SYSCALL_READ, fd, buf, count, 0, 0); + *bytes_read = ret; + return errno; +} + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + ssize_t ret; + int errno; + SYSCALL5(SYSCALL_WRITE, fd, buf, count, 0, 0); + *bytes_written = ret; + return errno; +} + +int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + ssize_t ret; + int errno; + SYSCALL5(SYSCALL_READ, fd, buf, n, off, 1); + *bytes_read = ret; + return errno; +} + +int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { + ssize_t ret; + int errno; + SYSCALL5(SYSCALL_WRITE, fd, buf, n, off, 1); + *bytes_written = ret; + return errno; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + ssize_t ret; + int errno; + SYSCALL3(SYSCALL_SEEK, fd, offset, whence); + *new_offset = ret; + return errno; +} + +int sys_ftruncate (int fd, size_t size) { + int ret, errno; + SYSCALL2(SYSCALL_TRUNCATE, fd, size); + return errno; +} + +int sys_fallocate(int fd, off_t offset, size_t size) { + if (offset < 0 || size == 0) { + return EINVAL; + } + + int ret, errno; + SYSCALL2(SYSCALL_TRUNCATE, fd, offset + size); + return errno; +} + +int sys_flock(int fd, int options) { + struct flock lock; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = (off_t)((uint64_t)-1); + lock.l_pid = sys_getpid(); + + switch (options & ~(LOCK_NB)) { + case LOCK_SH: + lock.l_type = F_RDLCK; + break; + case LOCK_EX: + lock.l_type = F_WRLCK; + break; + case LOCK_UN: + lock.l_type = F_UNLCK; + break; + default: + return -1; + } + + int command = options & LOCK_NB ? F_SETLK : F_SETLKW; + int ret, errno; + SYSCALL3(SYSCALL_FCNTL, fd, command, &lock); + return errno; +} + +int sys_getpriority(int which, id_t who, int *value) { + int ret, errno; + SYSCALL2(SYSCALL_GETPRIO, which, who); + *value = ret; + return errno; +} + +int sys_setpriority(int which, id_t who, int value) { + int ret, errno; + SYSCALL3(SYSCALL_SETPRIO, which, who, value); + return errno; +} + +int sys_getrusage(int scope, struct rusage *usage) { + int ret, errno; + SYSCALL2(SYSCALL_GETRUSAGE, scope, usage); + + // Ironclad returns nanoseconds instead of microseconds for usage, so we + // have to compensate for that. + usage->ru_utime.tv_usec = usage->ru_utime.tv_usec / 1000; + usage->ru_stime.tv_usec = usage->ru_stime.tv_usec / 1000; + + return errno; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + void *ret; + int errno; + SYSCALL6(SYSCALL_MMAP, hint, size, prot, flags, fd, offset); + *window = ret; + + if ((errno == ENOMEM) && ((flags & MAP_ANON) == 0)) { + int ret = sys_anon_allocate(size, window); + if (ret) { + return ret; + } + ssize_t len; + ret = sys_pread(fd, *window, size, offset, &len); + return 0; + } + + return errno; +} + +int sys_posix_madvise(void *addr, size_t length, int advice) { + int ret, errno; + SYSCALL3(SYSCALL_MADVISE, addr, length, advice); + return errno; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { + int ret, errno; + SYSCALL5(SYSCALL_GETSOCKOPT, fd, layer, number, buffer, size); + return errno; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + int ret, errno; + SYSCALL5(SYSCALL_SETSOCKOPT, fd, layer, number, buffer, size); + return errno; +} + +int sys_vm_unmap(void *pointer, size_t size) { + int ret; + int errno; + SYSCALL2(SYSCALL_MUNMAP, pointer, size); + if (ret != 0) { + return errno; + } else { + return 0; + } +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + int ret; + int errno; + SYSCALL3(SYSCALL_MPROTECT, pointer, size, prot); + if (ret != 0) { + return errno; + } + return 0; +} + +int sys_getsid(pid_t pid, pid_t *sid) { + int ret, errno; + SYSCALL1(SYSCALL_GETSID, pid); + *sid = ret; + return errno; +} + +pid_t sys_getpid() { + pid_t ret; + int errno; + SYSCALL0(SYSCALL_GETPID); + return ret; +} + +pid_t sys_gettid() { + pid_t ret; + int errno; + SYSCALL0(SYSCALL_GETTID); + return ret; +} + +pid_t sys_getppid() { + pid_t ret; + int errno; + SYSCALL0(SYSCALL_GETPPID); + return ret; +} + +int sys_getgroups(size_t size, gid_t *list, int *retval) { + int ret, errno; + SYSCALL2(SYSCALL_GETGROUPS, size, list); + *retval = ret; + return errno; +} + +int sys_setgroups(size_t size, const gid_t *list) { + int ret, errno; + SYSCALL2(SYSCALL_SETGROUPS, size, list); + return errno; +} + +int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out) { + int ret, errno; + SYSCALL4(SYSCALL_PTRACE, req, pid, addr, data); + *out = (long)ret; + return errno; +} + +int sys_fcntl(int fd, int request, va_list args, int *result) { + int ret, errno; + SYSCALL3(SYSCALL_FCNTL, fd, request, va_arg(args, uint64_t)); + *result = ret; + return errno; +} + +int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + int ret, errno; + SYSCALL3(SYSCALL_SIGPROCMASK, how, set, retrieve); + return errno; +} + +int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + int ret, errno; + SYSCALL2(SYSCALL_SIGALTSTACK, ss, oss); + return errno; +} + +int sys_tgkill(int pid, int tid, int sig) { + (void)tid; + return sys_kill(pid, sig); +} + +int sys_isatty(int fd) { + struct termios t; + if (sys_tcgetattr(fd, &t) == 0) { + return 0; + } else { + return ENOTTY; + } +} + +int sys_getpgid(pid_t pid, pid_t *pgid) { + int ret, errno; + SYSCALL1(SYSCALL_GETPGID, pid); + *pgid = ret; + return errno; +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + int ret, errno; + SYSCALL2(SYSCALL_SETPGID, pid, pgid); + return errno; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + int ret, errno, argv_len, envp_len; + for (argv_len = 0; argv[argv_len] != NULL; argv_len++); + for (envp_len = 0; envp[envp_len] != NULL; envp_len++); + + size_t path_len = strlen (path); + SYSCALL6(SYSCALL_EXEC, path, path_len, argv, argv_len, envp, envp_len); + + if (ret == -1) { + return errno; + } + + return 0; +} + +int sys_fork(pid_t *child) { + pid_t ret; + int errno; + + SYSCALL1(SYSCALL_FORK, 0); + + if (ret == -1) { + return errno; + } + + if (child != NULL) { + *child = ret; + } + + return 0; +} + +int sys_vfork(pid_t *child) { + pid_t ret; + int errno; + + SYSCALL1(SYSCALL_FORK, 1); + + if (ret == -1) { + return errno; + } + + if (child != NULL) { + *child = ret; + } + + return 0; +} + +int sys_getrlimit(int resource, struct rlimit *limit) { + uint64_t ret, errno; + SYSCALL3(SYSCALL_RLIMIT, resource, NULL, limit); + return errno; +} + +int sys_setrlimit(int resource, const struct rlimit *limit) { + uint64_t ret, errno; + SYSCALL3(SYSCALL_RLIMIT, resource, limit, NULL); + return errno; +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + pid_t ret; + int errno; + + if(ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + + SYSCALL3(SYSCALL_WAIT, pid, status, flags); + + if (ret == -1) { + return errno; + } + + *ret_pid = ret; + return errno; +} + +int sys_uname(struct utsname *buf) { + int ret, errno; + SYSCALL1(SYSCALL_UNAME, buf); + return errno; +} + +int sys_ttyname(int fd, char *buff, size_t size) { + int ret, errno; + SYSCALL3(SYSCALL_TTYNAME, fd, buff, size); + return errno; +} + +int sys_ptsname(int fd, char *buff, size_t size) { + return sys_ttyname(fd, buff, size); +} + +int sys_sethostname(const char *buff, size_t size) { + int ret, errno; + + SYSCALL2(SYSCALL_SETHOSTNAME, buff, size); + + if (ret == -1) { + return errno; + } + + return 0; +} + +int sys_chdir(const char *buff) { + int ret, errno; + + size_t buff_len = strlen(buff); + SYSCALL4(SYSCALL_OPEN, AT_FDCWD, buff, buff_len, O_RDONLY); + if (ret == -1) { + return ENOENT; + } + + SYSCALL1(SYSCALL_CHDIR, ret); + + if (ret == -1) { + return errno; + } + + return 0; +} + +int sys_fchdir(int fd) { + int ret, errno; + + SYSCALL1(SYSCALL_CHDIR, fd); + + if (ret == -1) { + return errno; + } + + return 0; +} + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + int ret, errno; + + SYSCALL3(SYSCALL_IOCTL, fd, request, arg); + + if (ret == -1) { + return errno; + } + + *result = ret; + return 0; +} + +void sys_yield(void) { + int ret, errno; + SYSCALL0(SYSCALL_SCHED_YIELD); +} + +int sys_getparam(pid_t pid, struct sched_param *param) { + int ret, errno; + SYSCALL2(SYSCALL_GET_SCHEDULER, pid, param); + return errno; +} + +int sys_setparam(pid_t pid, const struct sched_param *param) { + int ret, errno; + SYSCALL2(SYSCALL_SET_SCHEDULER, pid, param); + return errno; +} + +int sys_kill(int pid, int sig) { + int ret, errno; + SYSCALL2(SYSCALL_SEND_SIGNAL, pid, sig); + return errno; +} + +int sys_dup(int fd, int flags, int *newfd) { + int ret, errno; + if (flags & O_CLOEXEC) { + SYSCALL3(SYSCALL_FCNTL, fd, F_DUPFD_CLOEXEC, 0); + } else { + SYSCALL3(SYSCALL_FCNTL, fd, F_DUPFD, 0); + } + + *newfd = ret; + + if (errno == 0) { + SYSCALL3(SYSCALL_FCNTL, *newfd, F_SETFD, flags); + } + + return errno; +} + +int sys_dup2(int fd, int flags, int newfd) { + int ret = sys_close(newfd); + if (ret != 0 && ret != EBADF) { + return EBADF; + } + + int errno; + if (flags & O_CLOEXEC) { + SYSCALL3(SYSCALL_FCNTL, fd, F_DUPFD_CLOEXEC, newfd); + } else { + SYSCALL3(SYSCALL_FCNTL, fd, F_DUPFD, newfd); + } + + if (ret != -1 && ret != newfd) { + return EBADF; + } + + if (errno == 0) { + SYSCALL3(SYSCALL_FCNTL, newfd, F_SETFD, flags); + } + + return errno; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int ret; + + if (int r = sys_ioctl(fd, TCGETS, attr, &ret) != 0) { + return r; + } + + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int ret; + + switch (optional_action) { + case TCSANOW: + optional_action = TCSETS; break; + case TCSADRAIN: + optional_action = TCSETSW; break; + case TCSAFLUSH: + optional_action = TCSETSF; break; + default: + __ensure(!"Unsupported tcsetattr"); + } + + if (int r = sys_ioctl(fd, optional_action, (void *)attr, &ret) != 0) { + return r; + } + + return 0; +} + +int sys_tcflow(int fd, int action) { + int ret; + return sys_ioctl(fd, TCXONC, &action, &ret); +} + +int sys_tcflush(int fd, int action) { + int ret; + return sys_ioctl(fd, TCFLSH, &action, &ret); +} + +int sys_tcdrain(int fd) { + int ret; + int value = 0; + return sys_ioctl(fd, TCSBRKP, &value, &ret); +} + +int sys_access(const char *path, int mode) { + int ret, errno; + size_t len = strlen(path); + SYSCALL5(SYSCALL_ACCESS, AT_FDCWD, path, len, mode, 0); + return errno; +} + +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL5(SYSCALL_ACCESS, dirfd, pathname, len, mode, flags); + return errno; +} + +struct futex_item { + uint64_t addr; + uint32_t expected; + uint32_t flags; +}; + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + int ret, errno; + struct futex_item item = {.addr = (uint64_t)pointer, .expected = (uint32_t)expected, .flags = 0}; + if (time == NULL) { + struct timespec t = {(time_t)-1, (time_t)-1}; + SYSCALL4(SYSCALL_FUTEX, 0b01, &item, 1, &t); + } else { + SYSCALL4(SYSCALL_FUTEX, 0b01, &item, 1, time); + } + return errno; +} + +int sys_futex_wake(int *pointer) { + int ret, errno; + struct futex_item item = {.addr = (uint64_t)pointer, .expected = 0, .flags = 0}; + struct timespec t = {(time_t)-1, (time_t)-1}; + SYSCALL4(SYSCALL_FUTEX, 0b10, &item, 1, &t); + return errno; +} + +int sys_pipe(int *fds, int flags) { + int ret, errno; + SYSCALL2(SYSCALL_PIPE, fds, flags); + return errno; +} + +int sys_getentropy(void *buffer, size_t length) { + ssize_t ret; + int errno; + SYSCALL2(SYSCALL_GETENTROPY, buffer, length); + return errno; +} + +int sys_mkdir(const char *path, mode_t mode) { + return sys_mkdirat(AT_FDCWD, path, mode); +} + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + return sys_mknodat(dirfd, path, S_IFDIR | mode, 0); +} + +int sys_rmdir(const char* path){ + int ret, errno; + size_t path_len = strlen (path); + SYSCALL4(SYSCALL_UNLINK, AT_FDCWD, path, path_len, AT_REMOVEDIR); + return errno; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + int ret, errno; + size_t path_len = strlen (path); + SYSCALL4(SYSCALL_UNLINK, fd, path, path_len, flags); + return errno; +} + +int sys_link(const char* srcpath, const char* destpath) { + int ret, errno; + size_t src_len = strlen (srcpath); + size_t dst_len = strlen (destpath); + SYSCALL6(SYSCALL_LINK, AT_FDCWD, srcpath, src_len, AT_FDCWD, destpath, dst_len); + return errno; +} + +int sys_socket(int domain, int type, int protocol, int *fd) { + (void)protocol; + int ret, errno; + SYSCALL2(SYSCALL_SOCKET, domain, type); + if (ret != -1) { + *fd = ret; + return 0; + } else { + return errno; + } +} + +int sys_socketpair(int domain, int type, int protocol, int *fds) { + (void)protocol; + int ret, errno; + SYSCALL3(SYSCALL_SOCKETPAIR, domain, type, fds); + return errno; +} + +uid_t sys_getuid() { + uint64_t ret, errno; + SYSCALL0(SYSCALL_GETUID); + return (uid_t)ret; +} + +uid_t sys_geteuid() { + uint64_t ret, errno; + SYSCALL0(SYSCALL_GETEUID); + return (uid_t)ret; +} + +int sys_setuid(uid_t uid) { + int ret, errno; + SYSCALL2(SYSCALL_SETUIDS, uid, uid); + return ret; +} + +int sys_seteuid(uid_t euid) { + int ret, errno; + SYSCALL2(SYSCALL_SETUIDS, ((uint64_t)-1), euid); + return ret; +} + +int sys_setreuid(uid_t ruid, uid_t euid) { + int ret, errno; + SYSCALL2(SYSCALL_SETUIDS, ruid, euid); + return ret; +} + +gid_t sys_getgid() { + uint64_t ret, errno; + SYSCALL0(SYSCALL_GETGID); + return (gid_t)ret; +} + +gid_t sys_getegid() { + return sys_getgid(); +} + +int sys_setgid(gid_t gid) { + int ret, errno; + SYSCALL2(SYSCALL_SETGIDS, gid, gid); + return ret; +} + +int sys_setegid(gid_t egid) { + int ret, errno; + SYSCALL2(SYSCALL_SETGIDS, ((uint64_t)-1), egid); + return ret; +} + +int sys_setregid(gid_t rgid, gid_t egid) { + int ret, errno; + SYSCALL2(SYSCALL_SETGIDS, rgid, egid); + return ret; +} + +int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + if (ruid) { + *ruid = sys_getuid(); + } + if (euid) { + *euid = sys_geteuid(); + } + if (suid) { + *suid = sys_getuid(); + } + return 0; +} + +int sys_getresgid(uid_t *rgid, uid_t *egid, uid_t *sgid) { + if (rgid) { + *rgid = sys_getgid(); + } + if (egid) { + *egid = sys_getegid(); + } + if (sgid) { + *sgid = sys_getgid(); + } + return 0; +} + +int sys_setsid(pid_t *sid) { + int ret, errno; + SYSCALL0(SYSCALL_SETSID); + *sid = ret; + return errno; +} + +#ifndef MLIBC_BUILDING_RTLD + +extern "C" void __mlibc_thread_entry(); + +int sys_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { + int ret, errno; + + if (act != NULL) { + struct sigaction newact = *act; + newact.sa_restorer = __mlibc_sigret; + SYSCALL3(SYSCALL_SIGACTION, signum, &newact, oldact); + } else { + SYSCALL3(SYSCALL_SIGACTION, signum, NULL, oldact); + } + return errno; +} + +int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + int ret, errno; + SYSCALL4(SYSCALL_CREATE_THREAD, (uintptr_t)__mlibc_thread_entry, 0, stack, tcb); + + if (ret == -1) { + return errno; + } + + *tid_out = (pid_t)ret; + return 0; +} + +int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + *stack_size = *stack_size ? *stack_size : 0x400000; + + if (!*stack) { + *stack = (void *)((char *)mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0) + *stack_size); + if (*stack == MAP_FAILED) { + return errno; + } + } + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; +} + +int sys_clock_getres(int clock, time_t *secs, long *nanos) { + struct timespec time; + int ret, errno; + SYSCALL3(SYSCALL_CLOCK, 0, clock, &time); + *secs = time.tv_sec; + *nanos = time.tv_nsec; + return errno; +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec time; + int ret, errno; + SYSCALL3(SYSCALL_CLOCK, 1, clock, &time); + *secs = time.tv_sec; + *nanos = time.tv_nsec; + return errno; +} + +int sys_clock_set(int clock, time_t secs, long nanos) { + struct timespec time = {.tv_sec = secs, .tv_nsec = nanos }; + int ret, errno; + SYSCALL3(SYSCALL_CLOCK, 2, clock, &time); + return errno; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addrlen) { + int ret, errno; + SYSCALL3(SYSCALL_BIND, fd, addr_ptr, addrlen); + return errno; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addrlen) { + int ret, errno; + SYSCALL3(SYSCALL_CONNECT, fd, addr_ptr, addrlen); + return errno; +} + +int sys_listen(int fd, int backlog) { + int ret, errno; + SYSCALL2(SYSCALL_LISTEN, fd, backlog); + return errno; +} + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + int ret, errno; + SYSCALL4(SYSCALL_ACCEPT, fd, addr_ptr, addr_length, flags); + *newfd = ret; + return errno; +} + + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + int ret, errno; + SYSCALL3(SYSCALL_GETSOCKNAME, fd, addr_ptr, &max_addr_length); + *actual_length = max_addr_length; + return errno; +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + int ret, errno; + SYSCALL3(SYSCALL_GETPEERNAME, fd, addr_ptr, &max_addr_length); + *actual_length = max_addr_length; + return errno; +} + +int sys_shutdown(int sockfd, int how) { + int ret, errno; + SYSCALL2(SYSCALL_SHUTDOWN, sockfd, how); + return errno; +} + +int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + (void)which; (void)new_value; (void)old_value; + return ENOSYS; +} + +int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length) { + int ret, errno; + + if (hdr->msg_control != NULL) { + SYSCALL3(SYSCALL_RECVSOCKCTL, fd, hdr->msg_control, hdr->msg_controllen); + } + + size_t count = 0; + for (int i = 0; i < hdr->msg_iovlen; i++) { + SYSCALL6(SYSCALL_RECVFROM, fd, hdr->msg_iov[i].iov_base, hdr->msg_iov[i].iov_len, + flags, hdr->msg_name, hdr->msg_namelen); + if (ret == -1) { + return errno; + } + count += ret; + } + + *length = count; + return 0; +} + +int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length) { + int ret, errno; + + if (hdr->msg_control != NULL) { + SYSCALL3(SYSCALL_SENDSOCKCTL, fd, hdr->msg_control, hdr->msg_controllen); + } + + size_t count = 0; + for (int i = 0; i < hdr->msg_iovlen; i++) { + SYSCALL6(SYSCALL_SENDTO, fd, hdr->msg_iov[i].iov_base, hdr->msg_iov[i].iov_len, + flags, hdr->msg_name, hdr->msg_namelen); + if (ret == -1) { + return errno; + } + count += ret; + } + + *length = count; + return 0; +} + + +int sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + int ret, errno; + SYSCALL4(SYSCALL_PPOLL, fds, nfds, timeout, sigmask); + if (ret == -1) { + return errno; + } + + *num_events = ret; + return errno; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + return sys_ppoll(fds, count, timeout == -1 ? NULL : &ts, NULL, num_events); +} + +int sys_pause(void) { + return sys_ppoll(NULL, 0, NULL, NULL, NULL); +} + +int sys_sigsuspend(const sigset_t *set) { + return sys_ppoll(NULL, 0, NULL, set, NULL); +} + +int sys_pselect(int nfds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + struct pollfd *fds = (struct pollfd *)calloc(nfds, sizeof(struct pollfd)); + if (fds == NULL) { + return ENOMEM; + } + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set)) { + fd->events |= POLLIN; + } + if (write_set && FD_ISSET(i, write_set)) { + fd->events |= POLLOUT; + } + if (except_set && FD_ISSET(i, except_set)) { + fd->events |= POLLPRI; + } + + if (!fd->events) { + fd->fd = -1; + continue; + } + fd->fd = i; + } + + int ret = sys_ppoll(fds, nfds, timeout, sigmask, num_events); + if (ret != 0) { + free(fds); + return ret; + } + + fd_set res_read_set, res_write_set, res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set) && (fd->revents & (POLLIN | POLLERR | POLLHUP)) != 0) { + FD_SET(i, &res_read_set); + } + if (write_set && FD_ISSET(i, write_set) && (fd->revents & (POLLOUT | POLLERR | POLLHUP)) != 0) { + FD_SET(i, &res_write_set); + } + if (except_set && FD_ISSET(i, except_set) && (fd->revents & POLLPRI) != 0) { + FD_SET(i, &res_except_set); + } + } + + free(fds); + if (read_set) { + *read_set = res_read_set; + } + if (write_set) { + *write_set = res_write_set; + } + if (except_set) { + *except_set = res_except_set; + } + + return 0; +} + +int sys_sleep(time_t *secs, long *nanos) { + struct timespec time = {.tv_sec = *secs, .tv_nsec = *nanos}; + struct timespec rem = {.tv_sec = 0, .tv_nsec = 0}; + + int ret, errno; + SYSCALL4(SYSCALL_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, 0, &time, &rem); + *secs = rem.tv_sec; + *nanos = rem.tv_nsec; + return errno; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + struct utsname buf; + if (uname(&buf)) { + return -1; + } + + strncpy(buffer, buf.nodename, bufsize); + return 0; +} + +int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + int ret, errno; + if (pathname == NULL) { + pathname = ""; + flags |= AT_EMPTY_PATH; + } + + size_t path_len = strlen (pathname); + if (times == NULL) { + time_t secs; + long nsec; + ret = sys_clock_get(CLOCK_REALTIME, &secs, &nsec); + if (ret) { + return ret; + } + struct timespec times2[2] = {0, 0}; + times2[0].tv_sec = secs; + times2[0].tv_nsec = nsec; + times2[1].tv_sec = secs; + times2[1].tv_nsec = nsec; + SYSCALL5(SYSCALL_UTIMES, dirfd, pathname, path_len, ×2[0], flags); + } else { + SYSCALL5(SYSCALL_UTIMES, dirfd, pathname, path_len, times, flags); + } + + return errno; +} + +struct meminfo { + uint64_t phys_total; + uint64_t phys_available; + uint64_t phys_free; + uint64_t shared_usage; + uint64_t kernel_usage; + uint64_t table_usage; + uint64_t poison_usage; +}; + +struct cpuinfo { + uint64_t conf_cores; + uint64_t onln_cores; + char model_name[64]; + char vendor_name[64]; + uint32_t base_mhz; + uint32_t max_mhz; + uint32_t ref_mhz; +}; + +int sys_sysconf(int num, long *rret) { + struct meminfo mem; + struct cpuinfo cpu; + int ret, errno; + long secs, nanos; + + switch (num) { + case _SC_LINE_MAX: + return 2048; + case _SC_NGROUPS_MAX: + return 0x10000; + case _SC_CHILD_MAX: + return 30; + case _SC_NPROCESSORS_CONF: + SYSCALL1(SYSCALL_GETCPUINFO, &cpu); + if (ret == 0) { + *rret = cpu.conf_cores; + return 0; + } else { + return EFAULT; + } + case _SC_NPROCESSORS_ONLN: + SYSCALL1(SYSCALL_GETCPUINFO, &cpu); + if (ret == 0) { + *rret = cpu.onln_cores; + return 0; + } else { + return EFAULT; + } + case _SC_OPEN_MAX: + *rret = 1024; + return 0; + case _SC_AVPHYS_PAGES: + SYSCALL1(SYSCALL_MEMINFO, &mem); + if (ret == 0) { + *rret = mem.phys_free / getpagesize(); + return 0; + } else { + return EFAULT; + } + case _SC_PHYS_PAGES: + SYSCALL1(SYSCALL_MEMINFO, &mem); + if (ret == 0) { + *rret = mem.phys_available / getpagesize(); + return 0; + } else { + return EFAULT; + } + case _SC_TOTAL_PAGES: + SYSCALL1(SYSCALL_MEMINFO, &mem); + if (ret == 0) { + *rret = mem.phys_total / getpagesize(); + return 0; + } else { + return EFAULT; + } + case _SC_THREAD_STACK_MIN: + *rret = 0x1000; + return 0; + case _SC_CLK_TCK: + ret = sys_clock_getres(CLOCK_MONOTONIC, &secs, &nanos); + if (ret == 0) { + *rret = 1000000000 / nanos; + return 0; + } else { + return ret; + } + default: + return EINVAL; + } +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + int ret, errno; + (void)flags; + + switch (fsfdt) { + case fsfd_target::fd: { + SYSCALL5(SYSCALL_STAT, fd, "", 0, statbuf, AT_EMPTY_PATH); + break; + } + case fsfd_target::path: { + size_t len = strlen(path); + SYSCALL5(SYSCALL_STAT, AT_FDCWD, path, len, statbuf, flags); + break; + } + case fsfd_target::fd_path: { + size_t len = strlen(path); + SYSCALL5(SYSCALL_STAT, fd, path, len, statbuf, flags); + break; + } + default: { + __ensure(!"stat: Invalid fsfdt"); + __builtin_unreachable(); + } + } + + return errno; +} + +int sys_chmod(const char *pathname, mode_t mode) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL5(SYSCALL_FCHMOD, AT_FDCWD, pathname, len, mode, 0); + return errno; +} + +int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL5(SYSCALL_FCHMOD, fd, pathname, len, mode, flags); + return errno; +} + +int sys_fchmod(int fd, mode_t mode) { + int ret, errno; + SYSCALL5(SYSCALL_FCHMOD, fd, "", 0, mode, AT_EMPTY_PATH); + return errno; +} + +int sys_chown(const char *pathname, uid_t uid, gid_t gid) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL6(SYSCALL_FCHOWN, AT_FDCWD, pathname, len, uid, gid, 0); + return errno; +} + +int sys_fchownat(int fd, const char *pathname, uid_t uid, gid_t gid, int flags) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL6(SYSCALL_FCHOWN, fd, pathname, len, uid, gid, flags); + return errno; +} + +int sys_fchown(int fd, uid_t uid, gid_t gid) { + int ret, errno; + SYSCALL6(SYSCALL_FCHOWN, fd, "", 0, uid, gid, AT_EMPTY_PATH); + return errno; +} + +int sys_umask(mode_t mode, mode_t *old) { + mode_t ret; + int errno; + SYSCALL1(SYSCALL_UMASK, mode); + *old = (mode_t)ret; + return errno; +} + +int sys_fadvise(int fd, off_t offset, off_t length, int advice) { + int ret, errno; + SYSCALL4(SYSCALL_FADVISE, fd, offset, length, advice); + return errno; +} + +int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length) { + ssize_t ret; + int errno; + size_t path_len = strlen(path); + SYSCALL5(SYSCALL_READLINK, AT_FDCWD, path, path_len, buffer, max_size); + if (ret == -1) { + return errno; + } else { + *length = ret; + return 0; + } +} + +int sys_rename(const char *path, const char *new_path) { + int ret; + int errno; + size_t old_len = strlen(path); + size_t new_len = strlen(new_path); + SYSCALL7(SYSCALL_RENAME, AT_FDCWD, path, old_len, AT_FDCWD, new_path, new_len, 0); + return errno; +} + +int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + int ret; + int errno; + size_t old_len = strlen(old_path); + size_t new_len = strlen(new_path); + SYSCALL7(SYSCALL_RENAME, olddirfd, old_path, old_len, newdirfd, new_path, new_len, 0); + return errno; +} + +int sys_mknodat(int dirfd, const char *path, int mode, int dev) { + int ret; + int errno; + size_t len = strlen(path); + SYSCALL5(SYSCALL_MAKENODE, dirfd, path, len, mode, dev); + return errno; +} + +int sys_mkfifoat(int dirfd, const char *path, mode_t mode) { + return sys_mknodat(dirfd, path, S_IFIFO | mode, 0); +} + +int sys_openpt(int oflags, int *fd) { + int sfd, e; + + if (e = sys_openpty(fd, &sfd, NULL, NULL, NULL); e) { + return e; + } + sys_close(sfd); + + int fdflags = 0; + if (oflags & O_CLOEXEC) { + fdflags |= FD_CLOEXEC; + } + if (oflags & O_CLOFORK) { + fdflags |= FD_CLOFORK; + } + if (fdflags) { + fcntl(*fd, F_SETFD, fdflags); + } + + // We ignore non O_RDWR passed in oflags since that doesnt bond well with + // the openpty interface. + if (!(oflags & O_NOCTTY)) { + ioctl(*fd, TIOCSCTTY); + } + + return e; +} + +int sys_unlockpt(int fd) { + int unlock = 0; + return sys_ioctl(fd, TIOCSPTLCK, &unlock, NULL); +} + +int sys_symlink(const char *target, const char *link_path) { + return sys_symlinkat(target, AT_FDCWD, link_path); +} + +int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + int ret; + int errno; + size_t target_len = strlen(target_path); + size_t link_len = strlen(link_path); + SYSCALL5(SYSCALL_SYMLINK, dirfd, target_path, target_len, link_path, link_len); + return errno; +} + +int sys_brk(void **out) { + (void)out; + return -1; +} + +#define SC_LIST_MOUNTS 9 +struct mountinfo { + uint32_t type; + uint32_t flags; + char source[20]; + uint32_t source_length; + char location[20]; + uint32_t location_length; + uint64_t block_size; + uint64_t fragment_size; + uint64_t size_in_fragments; + uint64_t free_blocks; + uint64_t free_blocks_user; + uint64_t inode_count; + uint64_t free_inodes; + uint64_t free_inodes_user; + uint64_t max_filename; +}; + +#include + +int sys_fstatvfs(int fd, struct statvfs *out) { + (void)fd; + return sys_statvfs("/", out); +} + +int sys_statvfs(const char *path, struct statvfs *out) { + long ret, errno; + struct mountinfo *buffer = (mountinfo *)malloc(5 * sizeof(struct mountinfo)); + SYSCALL2(SYSCALL_LISTMOUNTS, buffer, 5); + if (errno) { + free(buffer); + return errno; + } else if (ret > 5) { + free(buffer); + return 1; + } + + bool best_len = 0; + int best_idx = 0; + for (int i = 0; i < ret; i++) { + if (!strncmp(path, buffer[i].location, buffer[i].location_length)) { + if (buffer[i].location_length > best_len) { + best_len = buffer[i].location_length; + best_idx = i; + } + } + } + + if (best_len == 0) { + return EINVAL; + } + + out->f_bsize = buffer[best_idx].block_size; + out->f_frsize = buffer[best_idx].fragment_size; + out->f_blocks = buffer[best_idx].size_in_fragments; + out->f_bfree = buffer[best_idx].free_blocks; + out->f_bavail = buffer[best_idx].free_blocks_user; + out->f_files = buffer[best_idx].inode_count; + out->f_ffree = buffer[best_idx].free_inodes; + out->f_favail = buffer[best_idx].free_inodes_user; + out->f_fsid = 0; + out->f_flag = buffer[best_idx].flags; + out->f_namemax = buffer[best_idx].max_filename; + + switch (buffer[best_idx].type) { + case MNT_EXT: strcpy(out->f_basetype, "ext"); break; + case MNT_FAT: strcpy(out->f_basetype, "fat"); break; + default: strcpy(out->f_basetype, "devfs"); break; + } + + return 0; +} + +int sys_shmat(void **seg_start, int shmid, const void *shmaddr, int shmflg) { + void *ret; + int errno; + SYSCALL3(SYSCALL_SHMAT, shmid, shmaddr, shmflg); + *seg_start = ret; + return errno; +} + +int sys_shmctl(int *idx, int shmid, int cmd, struct shmid_ds *buf) { + int ret, errno; + SYSCALL3(SYSCALL_SHMCTL, shmid, cmd, buf); + *idx = ret; + return errno; +} + +int sys_shmdt(const void *shmaddr) { + int ret, errno; + SYSCALL1(SYSCALL_SHMDT, shmaddr); + return errno; +} + +int sys_shmget(int *shm_id, key_t key, size_t size, int shmflg) { + int ret, errno; + SYSCALL3(SYSCALL_SHMGET, key, size, shmflg); + *shm_id = ret; + return errno; +} + +int sys_getloadavg(double *samples) { + int ret, errno; + int samples2[3]; + SYSCALL2(SYSCALL_LOADAVG, samples2, 3); + if (ret < 0) { + return errno; + } + for (int i = 0; i < 3; i++) { + samples[i] = samples2[i] / 100.0; + } + return 0; +} + +int sys_openpty(int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win) { + int ret; + int fds[2]; + SYSCALL1(SYSCALL_OPENPTY, fds); + if (errno) { + return errno; + } + *mfd = fds[0]; + *sfd = fds[1]; + + if (name != NULL) { + name = ttyname(*mfd); + if (!name) { + return errno; + } + } + + if (ios == NULL) { + struct termios termios = {}; + termios.c_iflag = BRKINT | IGNPAR | ICRNL | IXON | IMAXBEL; + termios.c_oflag = OPOST | ONLCR; + termios.c_cflag = CS8 | CREAD; + termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE; + termios.c_cc[VINTR] = CTRL('C'); + termios.c_cc[VERASE] = 127; // Delete. + termios.c_cc[VEOF] = CTRL('D'); + termios.c_cc[VSUSP] = CTRL('Z'); + termios.ibaud = 38400; + termios.obaud = 38400; + ret = tcsetattr(*mfd, TCSANOW, &termios); + } else { + ret = tcsetattr(*mfd, TCSANOW, ios); + } + if (ret) { + return errno; + } + + if (win == NULL) { + struct winsize win_size = { + .ws_row = 24, + .ws_col = 80, + .ws_xpixel = 24 * 16, + .ws_ypixel = 80 * 16 + }; + ret = ioctl(*mfd, TIOCSWINSZ, &win_size); + } else { + ret = ioctl(*mfd, TIOCSWINSZ, win); + } + + if (ret) { + return errno; + } + + return 0; +} + +#endif +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/ironclad/generic/mac.cpp b/user/include/mlibc/sysdeps/ironclad/generic/mac.cpp new file mode 100644 index 0000000..12b63d8 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/mac.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +extern "C" { + +unsigned long get_mac_capabilities(void) { + int ret; + SYSCALL0(SYSCALL_GET_MAC_CAPABILITIES); + return ret; +} + +int set_mac_capabilities(unsigned long request) { + int ret; + SYSCALL1(SYSCALL_SET_MAC_CAPABILITIES, request); + return ret; +} + +int add_mac_permissions(const char *path, int flags) { + int ret; + SYSCALL3(SYSCALL_ADD_MAC_PERMISSIONS, path, strlen(path), flags); + return ret; +} + +int set_mac_enforcement(unsigned long enforcement) { + int ret; + SYSCALL1(SYSCALL_SET_MAC_ENFORCEMENT, enforcement); + return ret; +} + +} diff --git a/user/include/mlibc/sysdeps/ironclad/generic/mntent.cpp b/user/include/mlibc/sysdeps/ironclad/generic/mntent.cpp new file mode 100644 index 0000000..7b9d6e6 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/mntent.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include + +namespace { + +char *internal_buf; +size_t internal_bufsize; + +} + +#define SENTINEL (char *)&internal_buf + +FILE *setmntent(const char *name, const char *mode) { + return fopen(name, mode); +} + +struct mntent *getmntent(FILE *f) { + static struct mntent mnt; + return getmntent_r(f, &mnt, SENTINEL, 0); +} + +int addmntent(FILE *f, const struct mntent *mnt) { + if(fseek(f, 0, SEEK_END)) { + return 1; + } + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", + mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, + mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +int endmntent(FILE *f) { + if(f) { + fclose(f); + } + return 1; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) { + return strstr(mnt->mnt_opts, opt); +} + +/* Adapted from musl */ +struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { + bool use_internal = (linebuf == SENTINEL); + + char source[60]; + char target[30]; + char fs[30]; + char options[30]; + int dump; + int pass; + + do { + if (use_internal) { + getline(&internal_buf, &internal_bufsize, f); + linebuf = internal_buf; + } else { + fgets(linebuf, buflen, f); + } + + if (feof(f) || ferror(f)) { + return 0; + } + + if (sscanf(linebuf, "%s %s %s %s %d %d\n", source, target, fs, options, + &dump, &pass) != 6) { + continue; + } + } while(linebuf[0] == '#'); + + mnt->mnt_fsname = strdup(source); + mnt->mnt_dir = strdup(target); + mnt->mnt_type = strdup(fs); + mnt->mnt_opts = strdup(options); + mnt->mnt_freq = dump; + mnt->mnt_passno = pass; + return mnt; +} diff --git a/user/include/mlibc/sysdeps/ironclad/generic/mount.cpp b/user/include/mlibc/sysdeps/ironclad/generic/mount.cpp new file mode 100644 index 0000000..feb6e4c --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/mount.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + +int mount(const char *source, const char *target, int type, int flags) { + int ret; + size_t source_len = strlen(source); + size_t target_len = strlen(target); + SYSCALL6(SYSCALL_MOUNT, source, source_len, target, target_len, type, flags); + return ret; +} + +int umount(const char *target, int flags) { + int ret; + size_t target_len = strlen(target); + SYSCALL3(SYSCALL_UMOUNT, target, target_len, flags); + return ret; +} diff --git a/user/include/mlibc/sysdeps/ironclad/generic/ptrace.cpp b/user/include/mlibc/sysdeps/ironclad/generic/ptrace.cpp new file mode 100644 index 0000000..58a8dd2 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/ptrace.cpp @@ -0,0 +1,9 @@ +#include +#include +#include + +int ptrace(int request, pid_t pid, void *addr, void *data) { + int ret; + SYSCALL4(SYSCALL_PTRACE, request, pid, addr, data); + return ret; +} diff --git a/user/include/mlibc/sysdeps/ironclad/generic/reboot.cpp b/user/include/mlibc/sysdeps/ironclad/generic/reboot.cpp new file mode 100644 index 0000000..45e8f03 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/reboot.cpp @@ -0,0 +1,9 @@ +#include +#include +#include + +int reboot(int what) { + int ret, errno; + SYSCALL2(SYSCALL_REBOOT, what, 0); + return ret; +} diff --git a/user/include/mlibc/sysdeps/ironclad/generic/thread.S b/user/include/mlibc/sysdeps/ironclad/generic/thread.S new file mode 100644 index 0000000..0f65d5e --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/thread.S @@ -0,0 +1,23 @@ +#if defined(__x86_64__) +.section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_thread_trampoline +#elif (defined(__riscv) && __riscv_xlen == 64) +.section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + ld a0, 0x0(sp) + ld a1, 0x8(sp) + ld a2, 0x10(sp) + + addi sp, sp, 24 + call __mlibc_thread_trampoline +#else +#error "Missing architecture specific code." +#endif + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/ironclad/generic/thread.cpp b/user/include/mlibc/sysdeps/ironclad/generic/thread.cpp new file mode 100644 index 0000000..9ba8f85 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/generic/thread.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_thread_trampoline(void *(*fn)(void *), Tcb *tcb, void *arg) { + while (__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) { + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + } + + tcb->invokeThreadFunc(reinterpret_cast(fn), arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +#define DEFAULT_STACK 0x20000 + +namespace mlibc { + int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + *guard_size = mlibc::page_size; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if (!*stack) { + *stack_base = mmap(NULL, *stack_size + mlibc::page_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + munmap((char *)*stack_base + *stack_size, mlibc::page_size); + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; + } +} diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/access.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/access.h new file mode 100755 index 0000000..8f0556a --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/ironclad/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/auxv.h new file mode 100755 index 0000000..f9be899 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/ironclad/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..02c7cf3 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..1745393 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..b05d507 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/dev_t.h new file mode 100755 index 0000000..e403f5b --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/errno.h new file mode 100755 index 0000000..ec9b8f6 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/ironclad/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fcntl.h new file mode 100755 index 0000000..c60789c --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/ironclad/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..c5e0d6a --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..b8925b8 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/gid_t.h new file mode 100755 index 0000000..1ee9676 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/in.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/in.h new file mode 100755 index 0000000..e10e010 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/ironclad/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ino_t.h new file mode 100755 index 0000000..8da8d60 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ioctls.h new file mode 100755 index 0000000..d532c47 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/ironclad/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ipc.h new file mode 100755 index 0000000..a98fd45 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/ironclad/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/limits.h new file mode 100755 index 0000000..9f4938c --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/ironclad/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/mode_t.h new file mode 100755 index 0000000..47764b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/mqueue.h new file mode 100755 index 0000000..394c37d --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/ironclad/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/msg.h new file mode 100755 index 0000000..7c59866 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/ironclad/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..a5c8e25 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/packet.h new file mode 100755 index 0000000..5a7a333 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/ironclad/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/pid_t.h new file mode 100755 index 0000000..36e4068 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/poll.h new file mode 100755 index 0000000..156ddd9 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/ironclad/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ptrace.h new file mode 100755 index 0000000..1260bf7 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/ironclad/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/reboot.h new file mode 100755 index 0000000..23c9af3 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/ironclad/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/resource.h new file mode 100755 index 0000000..e950420 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/ironclad/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/riscv-hwprobe.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/riscv-hwprobe.h new file mode 100755 index 0000000..cbab871 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/riscv-hwprobe.h @@ -0,0 +1 @@ +../../../../abis/ironclad/riscv-hwprobe.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..7f450a7 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..fbd0a8f --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/ironclad/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/shm.h new file mode 100755 index 0000000..f20c4fc --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/ironclad/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/sigevent.h new file mode 100755 index 0000000..88dbde3 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/ironclad/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/signal.h new file mode 100755 index 0000000..ae8aa10 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/ironclad/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/sigval.h new file mode 100755 index 0000000..9b225c0 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/ironclad/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/socket.h new file mode 100755 index 0000000..5ddea1c --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/ironclad/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..7db34a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/stat.h new file mode 100755 index 0000000..a307c32 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/ironclad/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/statvfs.h new file mode 100755 index 0000000..e0b90f0 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/ironclad/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..88197dd --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/termios.h new file mode 100755 index 0000000..a6bacb3 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/ironclad/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/time.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/time.h new file mode 100755 index 0000000..fa8e486 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/ironclad/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/uid_t.h new file mode 100755 index 0000000..1aebbe3 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..3aeac71 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/ironclad/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utmpx.h new file mode 100755 index 0000000..0a255ef --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/ironclad/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utsname.h new file mode 100755 index 0000000..0a5dbc8 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/ironclad/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..6dc4788 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/ironclad/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/wait.h new file mode 100755 index 0000000..a87457d --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/ironclad/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/ironclad/include/asm/ioctls.h b/user/include/mlibc/sysdeps/ironclad/include/asm/ioctls.h new file mode 100644 index 0000000..5136bae --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/asm/ioctls.h @@ -0,0 +1,103 @@ +#ifndef _ASM_IOCTLS_H +#define _ASM_IOCTLS_H + +/* List of all the IOCTLs supported, for further explanation on the meanings */ +/* please refer to documentation. If you did not get any, good luck! */ +/* Some IOCTL codes may be the same, in which case the device they are used in */ +/* gives them meaning. Cross-device IOCTLs have more distinct values. */ + +#define PS2MOUSE_2_1_SCALING 1 +#define PS2MOUSE_1_1_SCALING 2 +#define PS2MOUSE_SET_RES 3 +#define PS2MOUSE_SET_SAMPLE_RATE 4 +#define RTC_RD_TIME 1 +#define RTC_SET_TIME 2 +#define FIOQSIZE 0x5460 +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TCGETS2 3 +#define TCSETS2 3 +#define TCSETSW2 3 +#define TCSETSF2 3 +#define TIOCGRS485 0x542E +#define TIOCSRS485 0x542F +#define TIOCGPTN 3 +#define TIOCSPTLCK 3 +#define TIOCGDEV 3 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG 0x36 +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT 3 +#define TIOCGPTLCK 3 +#define TIOCGEXCL 3 +#define TIOCGPTPEER 3 +#define TIOCGISO7816 3 +#define TIOCSISO7816 3 +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 +#define TIOCSERGETLSR 0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B +#define TIOCMIWAIT 0x545C +#define TIOCGICOUNT 0x545D +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 +#define TIOCSER_TEMT 0x01 +#define DEV_PARTUUID 0x9821 + +#endif /* _ASM_IOCTLS_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/include/linux/fb.h b/user/include/mlibc/sysdeps/ironclad/include/linux/fb.h new file mode 100644 index 0000000..5060a53 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/linux/fb.h @@ -0,0 +1,397 @@ +#ifndef _LINUX_FB_H +#define _LINUX_FB_H + +#include + +/* Definitions of frame buffers */ + +#define FB_MAX 32 /* sufficient for now */ + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 +#define FBIO_CURSOR _IOWR('F', 0x08, struct fb_cursor) +/* 0x4607-0x460B are defined below */ +/* #define FBIOGET_MONITORSPEC 0x460C */ +/* #define FBIOPUT_MONITORSPEC 0x460D */ +/* #define FBIOSWITCH_MONIBIT 0x460E */ +#define FBIOGET_CON2FBMAP 0x460F +#define FBIOPUT_CON2FBMAP 0x4610 +#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */ +#define FBIOGET_VBLANK _IOR('F', 0x12, struct fb_vblank) +#define FBIO_ALLOC 0x4613 +#define FBIO_FREE 0x4614 +#define FBIOGET_GLYPH 0x4615 +#define FBIOGET_HWCINFO 0x4616 +#define FBIOPUT_MODEINFO 0x4617 +#define FBIOGET_DISPINFO 0x4618 + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ +#define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ +#define FB_TYPE_FOURCC 5 /* Type identified by a V4L2 FOURCC */ + +#define FB_AUX_TEXT_MDA 0 /* Monochrome text */ +#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ +#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */ +#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */ +#define FB_AUX_TEXT_SVGA_GROUP 8 /* 8-15: SVGA tileblit compatible modes */ +#define FB_AUX_TEXT_SVGA_MASK 7 /* lower three bits says step */ +#define FB_AUX_TEXT_SVGA_STEP2 8 /* SVGA text mode: text, attr */ +#define FB_AUX_TEXT_SVGA_STEP4 9 /* SVGA text mode: text, attr, 2 reserved bytes */ +#define FB_AUX_TEXT_SVGA_STEP8 10 /* SVGA text mode: text, attr, 6 reserved bytes */ +#define FB_AUX_TEXT_SVGA_STEP16 11 /* SVGA text mode: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_SVGA_LAST 15 /* reserved up to 15 */ + +#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */ +#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */ +#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ +#define FB_VISUAL_FOURCC 6 /* Visual identified by a V4L2 FOURCC */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */ +#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */ +#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */ +#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */ +#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */ +#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */ +#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */ +#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */ +#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */ +#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */ +#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */ +#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */ +#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */ +#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */ +#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */ +#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */ +#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */ +#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */ +#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */ +#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */ +#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */ +#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */ +#define FB_ACCEL_NV3 27 /* nVidia RIVA 128 */ +#define FB_ACCEL_NV4 28 /* nVidia RIVA TNT */ +#define FB_ACCEL_NV5 29 /* nVidia RIVA TNT2 */ +#define FB_ACCEL_CT_6555x 30 /* C&T 6555x */ +#define FB_ACCEL_3DFX_BANSHEE 31 /* 3Dfx Banshee */ +#define FB_ACCEL_ATI_RAGE128 32 /* ATI Rage128 family */ +#define FB_ACCEL_IGS_CYBER2000 33 /* CyberPro 2000 */ +#define FB_ACCEL_IGS_CYBER2010 34 /* CyberPro 2010 */ +#define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */ +#define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */ +#define FB_ACCEL_3DLABS_PERMEDIA3 37 /* 3Dlabs Permedia 3 */ +#define FB_ACCEL_ATI_RADEON 38 /* ATI Radeon family */ +#define FB_ACCEL_I810 39 /* Intel 810/815 */ +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 650, 740 */ +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre") */ +#define FB_ACCEL_I830 42 /* Intel 830M/845G/85x/865G */ +#define FB_ACCEL_NV_10 43 /* nVidia Arch 10 */ +#define FB_ACCEL_NV_20 44 /* nVidia Arch 20 */ +#define FB_ACCEL_NV_30 45 /* nVidia Arch 30 */ +#define FB_ACCEL_NV_40 46 /* nVidia Arch 40 */ +#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari V3XT, V5, V8 */ +#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */ +#define FB_ACCEL_OMAP1610 49 /* TI OMAP16xx */ +#define FB_ACCEL_TRIDENT_TGUI 50 /* Trident TGUI */ +#define FB_ACCEL_TRIDENT_3DIMAGE 51 /* Trident 3DImage */ +#define FB_ACCEL_TRIDENT_BLADE3D 52 /* Trident Blade3D */ +#define FB_ACCEL_TRIDENT_BLADEXP 53 /* Trident BladeXP */ +#define FB_ACCEL_CIRRUS_ALPINE 53 /* Cirrus Logic 543x/544x/5480 */ +#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ +#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */ +#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */ +#define FB_ACCEL_NEOMAGIC_NM2097 93 /* NeoMagic NM2097 */ +#define FB_ACCEL_NEOMAGIC_NM2160 94 /* NeoMagic NM2160 */ +#define FB_ACCEL_NEOMAGIC_NM2200 95 /* NeoMagic NM2200 */ +#define FB_ACCEL_NEOMAGIC_NM2230 96 /* NeoMagic NM2230 */ +#define FB_ACCEL_NEOMAGIC_NM2360 97 /* NeoMagic NM2360 */ +#define FB_ACCEL_NEOMAGIC_NM2380 98 /* NeoMagic NM2380 */ +#define FB_ACCEL_PXA3XX 99 /* PXA3xx */ + +#define FB_ACCEL_SAVAGE4 0x80 /* S3 Savage4 */ +#define FB_ACCEL_SAVAGE3D 0x81 /* S3 Savage3D */ +#define FB_ACCEL_SAVAGE3D_MV 0x82 /* S3 Savage3D-MV */ +#define FB_ACCEL_SAVAGE2000 0x83 /* S3 Savage2000 */ +#define FB_ACCEL_SAVAGE_MX_MV 0x84 /* S3 Savage/MX-MV */ +#define FB_ACCEL_SAVAGE_MX 0x85 /* S3 Savage/MX */ +#define FB_ACCEL_SAVAGE_IX_MV 0x86 /* S3 Savage/IX-MV */ +#define FB_ACCEL_SAVAGE_IX 0x87 /* S3 Savage/IX */ +#define FB_ACCEL_PROSAVAGE_PM 0x88 /* S3 ProSavage PM133 */ +#define FB_ACCEL_PROSAVAGE_KM 0x89 /* S3 ProSavage KM133 */ +#define FB_ACCEL_S3TWISTER_P 0x8a /* S3 Twister */ +#define FB_ACCEL_S3TWISTER_K 0x8b /* S3 TwisterK */ +#define FB_ACCEL_SUPERSAVAGE 0x8c /* S3 Supersavage */ +#define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ +#define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ + +#define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */ + +#define FB_CAP_FOURCC 1 /* Device supports FOURCC-based formats */ + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + uint32_t smem_len; /* Length of frame buffer mem */ + uint32_t type; /* see FB_TYPE_* */ + uint32_t type_aux; /* Interleave for interleaved Planes */ + uint32_t visual; /* see FB_VISUAL_* */ + uint16_t xpanstep; /* zero if no hardware panning */ + uint16_t ypanstep; /* zero if no hardware panning */ + uint16_t ywrapstep; /* zero if no hardware ywrap */ + uint32_t line_length; /* length of a line in bytes */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + uint32_t mmio_len; /* Length of Memory Mapped I/O */ + uint32_t accel; /* Indicate to driver which */ + /* specific chip/card we have */ + uint16_t capabilities; /* see FB_CAP_* */ + uint16_t reserved[2]; /* Reserved for future compatibility */ +}; + +/* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. + * + * For pseudocolor: offset and length should be the same for all color + * components. Offset specifies the position of the least significant bit + * of the palette index in a pixel value. Length indicates the number + * of available palette entries (i.e. # of entries = 1 << length). + */ +struct fb_bitfield { + uint32_t offset; /* beginning of bitfield */ + uint32_t length; /* length of bitfield */ + uint32_t msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ +#define FB_NONSTD_REV_PIX_IN_B 2 /* order of pixels in each byte is reversed */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ +#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ +#define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/ +#define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */ +#define FB_ACTIVATE_KD_TEXT 512 /* for KDSET vt ioctl */ + +#define FB_ACCELF_TEXT 1 /* (OBSOLETE) see fb_info.flags and vc_mode */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ +#define FB_SYNC_ON_GREEN 32 /* sync on green */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ + +/* + * Display rotation support + */ +#define FB_ROTATE_UR 0 +#define FB_ROTATE_CW 1 +#define FB_ROTATE_UD 2 +#define FB_ROTATE_CCW 3 + +#define PICOS2KHZ(a) (1000000000UL/(a)) +#define KHZ2PICOS(a) (1000000000UL/(a)) + +struct fb_var_screeninfo { + uint32_t xres; /* visible resolution */ + uint32_t yres; + uint32_t xres_virtual; /* virtual resolution */ + uint32_t yres_virtual; + uint32_t xoffset; /* offset from virtual to visible */ + uint32_t yoffset; /* resolution */ + + uint32_t bits_per_pixel; /* guess what */ + uint32_t grayscale; /* 0 = color, 1 = grayscale, */ + /* >1 = FOURCC */ + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + uint32_t nonstd; /* != 0 Non standard pixel format */ + + uint32_t activate; /* see FB_ACTIVATE_* */ + + uint32_t height; /* height of picture in mm */ + uint32_t width; /* width of picture in mm */ + + uint32_t accel_flags; /* (OBSOLETE) see fb_info.flags */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + uint32_t pixclock; /* pixel clock in ps (pico seconds) */ + uint32_t left_margin; /* time from sync to picture */ + uint32_t right_margin; /* time from picture to sync */ + uint32_t upper_margin; /* time from sync to picture */ + uint32_t lower_margin; + uint32_t hsync_len; /* length of horizontal sync */ + uint32_t vsync_len; /* length of vertical sync */ + uint32_t sync; /* see FB_SYNC_* */ + uint32_t vmode; /* see FB_VMODE_* */ + uint32_t rotate; /* angle we rotate counter clockwise */ + uint32_t colorspace; /* colorspace for FOURCC-based modes */ + uint32_t reserved[4]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + uint32_t start; /* First entry */ + uint32_t len; /* Number of entries */ + uint16_t *red; /* Red values */ + uint16_t *green; + uint16_t *blue; + uint16_t *transp; /* transparency, can be NULL */ +}; + +struct fb_con2fbmap { + uint32_t console; + uint32_t framebuffer; +}; + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + + +enum { + /* screen: unblanked, hsync: on, vsync: on */ + FB_BLANK_UNBLANK = VESA_NO_BLANKING, + + /* screen: blanked, hsync: on, vsync: on */ + FB_BLANK_NORMAL = VESA_NO_BLANKING + 1, + + /* screen: blanked, hsync: on, vsync: off */ + FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: on */ + FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: off */ + FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1 +}; + +#define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */ +#define FB_VBLANK_HBLANKING 0x002 /* currently in a horizontal blank */ +#define FB_VBLANK_HAVE_VBLANK 0x004 /* vertical blanks can be detected */ +#define FB_VBLANK_HAVE_HBLANK 0x008 /* horizontal blanks can be detected */ +#define FB_VBLANK_HAVE_COUNT 0x010 /* global retrace counter is available */ +#define FB_VBLANK_HAVE_VCOUNT 0x020 /* the vcount field is valid */ +#define FB_VBLANK_HAVE_HCOUNT 0x040 /* the hcount field is valid */ +#define FB_VBLANK_VSYNCING 0x080 /* currently in a vsync */ +#define FB_VBLANK_HAVE_VSYNC 0x100 /* verical syncs can be detected */ + +struct fb_vblank { + uint32_t flags; /* FB_VBLANK flags */ + uint32_t count; /* counter of retraces since boot */ + uint32_t vcount; /* current scanline position */ + uint32_t hcount; /* current scandot position */ + uint32_t reserved[4]; /* reserved for future compatibility */ +}; + +/* Internal HW accel */ +#define ROP_COPY 0 +#define ROP_XOR 1 + +struct fb_copyarea { + uint32_t dx; + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t sx; + uint32_t sy; +}; + +struct fb_fillrect { + uint32_t dx; /* screen-relative */ + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t color; + uint32_t rop; +}; + +struct fb_image { + uint32_t dx; /* Where to place image */ + uint32_t dy; + uint32_t width; /* Size of image */ + uint32_t height; + uint32_t fg_color; /* Only used when a mono bitmap */ + uint32_t bg_color; + uint8_t depth; /* Depth of the image */ + const char *data; /* Pointer to image data */ + struct fb_cmap cmap; /* color map info */ +}; + +/* + * hardware cursor control + */ + +#define FB_CUR_SETIMAGE 0x01 +#define FB_CUR_SETPOS 0x02 +#define FB_CUR_SETHOT 0x04 +#define FB_CUR_SETCMAP 0x08 +#define FB_CUR_SETSHAPE 0x10 +#define FB_CUR_SETSIZE 0x20 +#define FB_CUR_SETALL 0xFF + +struct fbcurpos { + uint16_t x, y; +}; + +struct fb_cursor { + uint16_t set; /* what to set */ + uint16_t enable; /* cursor on/off */ + uint16_t rop; /* bitop operation */ + const char *mask; /* cursor mask bits */ + struct fbcurpos hot; /* cursor hot spot */ + struct fb_image image; /* Cursor image */ +}; + +/* Settings for the generic backlight code */ +#define FB_BACKLIGHT_LEVELS 128 +#define FB_BACKLIGHT_MAX 0xFF + + +#endif /* _LINUX_FB_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/include/mntent.h b/user/include/mlibc/sysdeps/ironclad/include/mntent.h new file mode 100644 index 0000000..67a12ec --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/mntent.h @@ -0,0 +1,46 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#include + +/* TODO: Refer to _PATH_MOUNTED */ +#define MOUNTED "/etc/mtab" + +/* Generic mount options */ +#define MNTOPT_DEFAULTS "defaults" /* Use all default options. */ +#define MNTOPT_RO "ro" /* Read only. */ +#define MNTOPT_RW "rw" /* Read/write. */ +#define MNTOPT_SUID "suid" /* Set uid allowed. */ +#define MNTOPT_NOSUID "nosuid" /* No set uid allowed. */ +#define MNTOPT_NOAUTO "noauto" /* Do not auto mount. */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +FILE *setmntent(const char *, const char *); + +struct mntent *getmntent(FILE *); + +int addmntent(FILE *, const struct mntent *); + +int endmntent(FILE *); + +char *hasmntopt(const struct mntent *, const char *); + +struct mntent *getmntent_r(FILE *, struct mntent *, char *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _MNTENT_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/include/sys/mac.h b/user/include/mlibc/sysdeps/ironclad/include/sys/mac.h new file mode 100644 index 0000000..09da8e2 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/sys/mac.h @@ -0,0 +1,50 @@ +#ifndef _SYS_MAC_H +#define _SYS_MAC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAC_CAP_SCHED (1 << 0) +#define MAC_CAP_SPAWN (1 << 1) +#define MAC_CAP_ENTROPY (1 << 2) +#define MAC_CAP_SYS_MEM (1 << 3) +#define MAC_CAP_USE_NET (1 << 4) +#define MAC_CAP_SYS_NET (1 << 5) +#define MAC_CAP_SYS_MNT (1 << 6) +#define MAC_CAP_SYS_PWR (1 << 7) +#define MAC_CAP_PTRACE (1 << 8) +#define MAC_CAP_SETUID (1 << 9) +#define MAC_CAP_SYS_MAC (1 << 10) +#define MAC_CAP_CLOCK (1 << 11) +#define MAC_CAP_SIGNALALL (1 << 12) +#define MAC_CAP_SETGID (1 << 13) +#define MAC_CAP_IPC (1 << 14) +#define MAC_CAP_SYS_LOG (1 << 15) + +unsigned long get_mac_capabilities(void); +int set_mac_capabilities(unsigned long request); + +#define MAC_PERM_CONTENTS (1 << 0) +#define MAC_PERM_READ (1 << 1) +#define MAC_PERM_WRITE (1 << 2) +#define MAC_PERM_EXEC (1 << 3) +#define MAC_PERM_APPEND (1 << 4) +#define MAC_PERM_FLOCK (1 << 5) +#define MAC_PERM_DEV (1 << 6) +int add_mac_permissions(const char *path, int flags); + +#define MAC_DENY (1 << 0) +#define MAC_DENY_AND_SCREAM (1 << 1) +#define MAC_KILL (1 << 2) +int set_mac_enforcement(unsigned long enforcement); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MAC_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/include/sys/mount.h b/user/include/mlibc/sysdeps/ironclad/include/sys/mount.h new file mode 100644 index 0000000..946e720 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/sys/mount.h @@ -0,0 +1,26 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MNT_EXT 1 +#define MNT_FAT 2 +#define MNT_DEV 3 + +#define MS_RDONLY (1 << 0) +#define MS_REMOUNT (1 << 1) +#define MS_RELATIME (1 << 2) +#define MS_NOATIME (1 << 3) + +#define MNT_FORCE 1 + +int mount(const char *source, const char *target, int type, int flags); +int umount(const char *target, int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MOUNT_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/include/sys/ptrace.h b/user/include/mlibc/sysdeps/ironclad/include/sys/ptrace.h new file mode 100644 index 0000000..ece63b8 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/sys/ptrace.h @@ -0,0 +1,23 @@ +#ifndef _SYS_PTRACE_H +#define _SYS_PTRACE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PTRACE_ATTACH 1 +#define PTRACE_DETACH 2 +#define PTRACE_CONT 3 +#define PTRACE_SYSCALL 4 +#define PTRACE_GETREGS 5 +int ptrace(int request, pid_t pid, void *addr, void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PTRACE_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/include/sys/reboot.h b/user/include/mlibc/sysdeps/ironclad/include/sys/reboot.h new file mode 100644 index 0000000..ffc73dc --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/sys/reboot.h @@ -0,0 +1,16 @@ +#ifndef _SYS_REBOOT_H +#define _SYS_REBOOT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int reboot(int arg); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_REBOOT_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/include/sys/syscall.h b/user/include/mlibc/sysdeps/ironclad/include/sys/syscall.h new file mode 100644 index 0000000..be8b17d --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/sys/syscall.h @@ -0,0 +1,358 @@ +#ifndef _SYS_SYSCALL_H +#define _SYS_SYSCALL_H + +#include +#include + +#ifdef __cplusplus +# define __auto_type auto +#endif + +// Syscall numbers are the same on all architectures. +#define SYSCALL_EXIT 0 +#define SYSCALL_ARCH_PRCTL 1 +#define SYSCALL_OPEN 2 +#define SYSCALL_CLOSE 3 +#define SYSCALL_READ 4 +#define SYSCALL_WRITE 5 +#define SYSCALL_SEEK 6 +#define SYSCALL_MMAP 7 +#define SYSCALL_MUNMAP 8 +#define SYSCALL_GETPID 9 +#define SYSCALL_GETPPID 10 +#define SYSCALL_EXEC 11 +#define SYSCALL_FORK 12 +#define SYSCALL_WAIT 13 +#define SYSCALL_SOCKET 14 +#define SYSCALL_SETHOSTNAME 15 +#define SYSCALL_UNLINK 16 +#define SYSCALL_STAT 17 +#define SYSCALL_PIVOT_ROOT 18 +#define SYSCALL_CHDIR 19 +#define SYSCALL_IOCTL 20 +#define SYSCALL_SCHED_YIELD 21 +#define SYSCALL_GET_MIN_PRIO 22 +#define SYSCALL_PIPE 23 +#define SYSCALL_GETUID 24 +#define SYSCALL_RENAME 25 +#define SYSCALL_LISTPROCS 26 +#define SYSCALL_GETSID 27 +#define SYSCALL_GETTID 28 +#define SYSCALL_GET_MAX_PRIO 29 +#define SYSCALL_FCNTL 30 +#define SYSCALL_EXIT_THREAD 31 +#define SYSCALL_GETENTROPY 32 +#define SYSCALL_MPROTECT 33 +#define SYSCALL_SYNC 34 +#define SYSCALL_SET_MAC_CAPABILITIES 35 +#define SYSCALL_GET_MAC_CAPABILITIES 36 +#define SYSCALL_ADD_MAC_PERMISSIONS 37 +#define SYSCALL_SET_MAC_ENFORCEMENT 38 +#define SYSCALL_MOUNT 39 +#define SYSCALL_UMOUNT 40 +#define SYSCALL_READLINK 41 +#define SYSCALL_GETDENTS 42 +#define SYSCALL_MAKENODE 43 +#define SYSCALL_TRUNCATE 44 +#define SYSCALL_BIND 45 +#define SYSCALL_SYMLINK 46 +#define SYSCALL_CONNECT 47 +#define SYSCALL_OPENPTY 48 +#define SYSCALL_FSYNC 49 +#define SYSCALL_LINK 50 +#define SYSCALL_PTRACE 51 +#define SYSCALL_LISTEN 52 +#define SYSCALL_ACCEPT 53 +#define SYSCALL_RLIMIT 54 +#define SYSCALL_ACCESS 56 +#define SYSCALL_PPOLL 57 +#define SYSCALL_GETEUID 58 +#define SYSCALL_SETUIDS 59 +#define SYSCALL_FCHMOD 60 +#define SYSCALL_UMASK 61 +#define SYSCALL_REBOOT 62 +#define SYSCALL_FCHOWN 63 +#define SYSCALL_GETPGID 64 +#define SYSCALL_SETPGID 65 +#define SYSCALL_GETSOCKNAME 66 +#define SYSCALL_GETPEERNAME 67 +#define SYSCALL_SHUTDOWN 68 +#define SYSCALL_FUTEX 69 +#define SYSCALL_CLOCK 70 +#define SYSCALL_CLOCK_NANOSLEEP 71 +#define SYSCALL_GETRUSAGE 72 +#define SYSCALL_RECVFROM 73 +#define SYSCALL_SENDTO 74 +#define SYSCALL_CONFIG_NETINTER 75 +#define SYSCALL_UTIMES 76 +#define SYSCALL_GET_SCHEDULER 77 +#define SYSCALL_SET_SCHEDULER 78 +#define SYSCALL_SIGPROCMASK 79 +#define SYSCALL_SIGACTION 80 +#define SYSCALL_SEND_SIGNAL 81 +#define SYSCALL_GETPRIO 82 +#define SYSCALL_SETPRIO 83 +#define SYSCALL_GETGID 84 +#define SYSCALL_GETEGID 85 +#define SYSCALL_SETGIDS 86 +#define SYSCALL_GETGROUPS 87 +#define SYSCALL_SETGROUPS 88 +#define SYSCALL_TTYNAME 89 +#define SYSCALL_FADVISE 90 +#define SYSCALL_SHMAT 91 +#define SYSCALL_SHMCTL 92 +#define SYSCALL_SHMDT 93 +#define SYSCALL_SHMGET 94 +#define SYSCALL_GETSOCKOPT 95 +#define SYSCALL_SETSOCKOPT 96 +#define SYSCALL_GETTIDID 97 +#define SYSCALL_SETTIDID 98 +#define SYSCALL_FAILURE_POLICY 99 +#define SYSCALL_CREATE_THREAD 100 +#define SYSCALL_SIGNAL_RETURN 101 +#define SYSCALL_SIGALTSTACK 102 +#define SYSCALL_RECVSOCKCTL 103 +#define SYSCALL_LISTMOUNTS 104 +#define SYSCALL_UNAME 105 +#define SYSCALL_LISTTHREADS 106 +#define SYSCALL_SENDSOCKCTL 107 +#define SYSCALL_LISTNETINTER 108 +#define SYSCALL_DUMPLOGS 109 +#define SYSCALL_LISTFLOCKS 110 +#define SYSCALL_LOADAVG 111 +#define SYSCALL_MEMINFO 112 +#define SYSCALL_LISTPCI 113 +#define SYSCALL_GETCPUINFO 114 +#define SYSCALL_SOCKETPAIR 115 +#define SYSCALL_MADVISE 116 +#define SYSCALL_NVMM_CAPABILITY 117 +#define SYSCALL_NVMM_MACHINE_CREATE 118 +#define SYSCALL_NVMM_MACHINE_DEL 119 +#define SYSCALL_NVMM_MACHINE_CONF 120 +#define SYSCALL_NVMM_VCPU_CREATE 121 +#define SYSCALL_NVMM_VCPU_DESTROY 122 +#define SYSCALL_NVMM_VCPU_CONF 123 +#define SYSCALL_NVMM_VCPU_SETSTATE 124 +#define SYSCALL_NVMM_VCPU_GETSTATE 125 +#define SYSCALL_NVMM_VCPU_INJECT 126 +#define SYSCALL_NVMM_VCPU_RUN 127 +#define SYSCALL_NVMM_GPA_MAP 128 +#define SYSCALL_NVMM_GPA_UNMAP 129 +#define SYSCALL_NVMM_HVA_MAP 130 +#define SYSCALL_NVMM_HVA_UNMAP 131 +#define SYSCALL_NVMM_GVA2GPA 132 +#define SYSCALL_NVMM_GPA2HVA 133 +#define SYSCALL_NVMM_ASSIST_IO 134 +#define SYSCALL_NVMM_ASSIST_MEM 135 +#define SYSCALL_NVMM_VCPU_DUMP 136 +#define SYSCALL_NVMM_VCPU_STOP 137 +#define SYSCALL_SETSID 138 +#define SYSCALL_PCI_READ 139 +#define SYSCALL_PCI_WRITE 140 + +#if defined(__x86_64__) +#define SYSCALL0(NUM) ({ \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL1(NUM, ARG0) ({ \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL2(NUM, ARG0, ARG1) ({ \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL3(NUM, ARG0, ARG1, ARG2) ({ \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL4(NUM, ARG0, ARG1, ARG2, ARG3) ({ \ + register __auto_type arg_r12 asm("r12") = ARG3; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL5(NUM, ARG0, ARG1, ARG2, ARG3, ARG4) ({ \ + register __auto_type arg_r12 asm("r12") = ARG3; \ + register __auto_type arg_r8 asm("r8") = ARG4; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12), "r"(arg_r8) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL6(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) ({ \ + register __auto_type arg_r12 asm("r12") = ARG3; \ + register __auto_type arg_r8 asm("r8") = ARG4; \ + register __auto_type arg_r9 asm("r9") = ARG5; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12), "r"(arg_r8), "r"(arg_r9) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL7(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) ({ \ + register __auto_type arg_r12 asm("r12") = ARG3; \ + register __auto_type arg_r8 asm("r8") = ARG4; \ + register __auto_type arg_r9 asm("r9") = ARG5; \ + register __auto_type arg_r10 asm("r10") = ARG6; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12), "r"(arg_r8), "r"(arg_r9), "r"(arg_r10) \ + : "rcx", "r11", "memory"); \ +}) +#elif (defined(__riscv) && __riscv_xlen == 64) +#define SYSCALL0(NUM) ({ \ + register uint64_t snum asm("a7") = (NUM); \ + register __typeof(ret) re asm("a0"); \ + register uint64_t err asm("a1"); \ + asm volatile ("ecall" \ + : "=r"(re), "=r"(err) \ + : "r"(snum) \ + : "memory"); \ + ret = re; \ + errno = err; \ +}) + +#define SYSCALL1(NUM, ARG0) ({ \ + register uint64_t snum asm("a7") = (NUM); \ + register __typeof(ret) re asm("a0"); \ + register uint64_t err asm("a1"); \ + register __auto_type arg0 asm("a0") = (ARG0); \ + asm volatile ("ecall" \ + : "=r"(re), "=r"(err) \ + : "r"(snum), "r"(arg0) \ + : "memory"); \ + ret = re; \ + errno = err; \ +}) + +#define SYSCALL2(NUM, ARG0, ARG1) ({ \ + register uint64_t snum asm("a7") = (NUM); \ + register __typeof(ret) re asm("a0"); \ + register uint64_t err asm("a1"); \ + register __auto_type arg0 asm("a0") = (ARG0); \ + register __auto_type arg1 asm("a1") = (ARG1); \ + asm volatile ("ecall" \ + : "=r"(re), "=r"(err) \ + : "r"(snum), "r"(arg0), "r"(arg1) \ + : "memory"); \ + ret = re; \ + errno = err; \ +}) + +#define SYSCALL3(NUM, ARG0, ARG1, ARG2) ({ \ + register uint64_t snum asm("a7") = (NUM); \ + register __typeof(ret) re asm("a0"); \ + register uint64_t err asm("a1"); \ + register __auto_type arg0 asm("a0") = (ARG0); \ + register __auto_type arg1 asm("a1") = (ARG1); \ + register __auto_type arg2 asm("a2") = (ARG2); \ + asm volatile ("ecall" \ + : "=r"(re), "=r"(err) \ + : "r"(snum), "r"(arg0), "r"(arg1), \ + "r"(arg2) \ + : "memory"); \ + ret = re; \ + errno = err; \ +}) + +#define SYSCALL4(NUM, ARG0, ARG1, ARG2, ARG3) ({ \ + register uint64_t snum asm("a7") = (NUM); \ + register __typeof(ret) re asm("a0"); \ + register uint64_t err asm("a1"); \ + register __auto_type arg0 asm("a0") = (ARG0); \ + register __auto_type arg1 asm("a1") = (ARG1); \ + register __auto_type arg2 asm("a2") = (ARG2); \ + register __auto_type arg3 asm("a3") = (ARG3); \ + asm volatile ("ecall" \ + : "=r"(re), "=r"(err) \ + : "r"(snum), "r"(arg0), "r"(arg1), \ + "r"(arg2), "r"(arg3) \ + : "memory"); \ + ret = re; \ + errno = err; \ +}) + +#define SYSCALL5(NUM, ARG0, ARG1, ARG2, ARG3, ARG4) ({ \ + register uint64_t snum asm("a7") = (NUM); \ + register __typeof(ret) re asm("a0"); \ + register uint64_t err asm("a1"); \ + register __auto_type arg0 asm("a0") = (ARG0); \ + register __auto_type arg1 asm("a1") = (ARG1); \ + register __auto_type arg2 asm("a2") = (ARG2); \ + register __auto_type arg3 asm("a3") = (ARG3); \ + register __auto_type arg4 asm("a4") = (ARG4); \ + asm volatile ("ecall" \ + : "=r"(re), "=r"(err) \ + : "r"(snum), "r"(arg0), "r"(arg1), \ + "r"(arg2), "r"(arg3), "r"(arg4) \ + : "memory"); \ + ret = re; \ + errno = err; \ +}) + +#define SYSCALL6(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) ({ \ + register uint64_t snum asm("a7") = (NUM); \ + register __typeof(ret) re asm("a0"); \ + register uint64_t err asm("a1"); \ + register __auto_type arg0 asm("a0") = (ARG0); \ + register __auto_type arg1 asm("a1") = (ARG1); \ + register __auto_type arg2 asm("a2") = (ARG2); \ + register __auto_type arg3 asm("a3") = (ARG3); \ + register __auto_type arg4 asm("a4") = (ARG4); \ + register __auto_type arg5 asm("a5") = (ARG5); \ + asm volatile ("ecall" \ + : "=r"(re), "=r"(err) \ + : "r"(snum), "r"(arg0), "r"(arg1), \ + "r"(arg2), "r"(arg3), "r"(arg4), \ + "r"(arg5) \ + : "memory"); \ + ret = re; \ + errno = err; \ +}) + +#define SYSCALL7(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) ({ \ + register uint64_t snum asm("a7") = (NUM); \ + register __typeof(ret) re asm("a0"); \ + register uint64_t err asm("a1"); \ + register __auto_type arg0 asm("a0") = (ARG0); \ + register __auto_type arg1 asm("a1") = (ARG1); \ + register __auto_type arg2 asm("a2") = (ARG2); \ + register __auto_type arg3 asm("a3") = (ARG3); \ + register __auto_type arg4 asm("a4") = (ARG4); \ + register __auto_type arg5 asm("a5") = (ARG5); \ + register __auto_type arg6 asm("a6") = (ARG6); \ + asm volatile ("ecall" \ + : "=r"(re), "=r"(err) \ + : "r"(snum), "r"(arg0), "r"(arg1), \ + "r"(arg2), "r"(arg3), "r"(arg4), \ + "r"(arg5), "r"(arg6) \ + : "memory"); \ + ret = re; \ + errno = err; \ +}) +#else +#error "Missing architecture specific code." +#endif + +#endif /* _SYS_SYSCALL_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/include/sys/sysmacros.h b/user/include/mlibc/sysdeps/ironclad/include/sys/sysmacros.h new file mode 100644 index 0000000..9682d01 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/include/sys/sysmacros.h @@ -0,0 +1,33 @@ +#ifndef _SYS_SYSMACROS_H +#define _SYS_SYSMACROS_H + +#ifdef __cplusplus +extern "C" { +#endif + +static unsigned int __mlibc_dev_major( + unsigned long long int __dev) { + return ((__dev >> 8) & 0xfff) | ((unsigned int)(__dev >> 32) & ~0xfff); +} + +static unsigned int __mlibc_dev_minor( + unsigned long long int __dev) { + return (__dev & 0xff) | ((unsigned int)(__dev >> 12) & ~0xff); +} + +static unsigned long long int __mlibc_dev_makedev( + unsigned int __major, unsigned int __minor) { + return ((__minor & 0xff) | ((__major & 0xfff) << 8) + | (((unsigned long long int)(__minor & ~0xff)) << 12) + | (((unsigned long long int)(__major & ~0xfff)) << 32)); +} + +#define major(dev) __mlibc_dev_major(dev) +#define minor(dev) __mlibc_dev_minor(dev) +#define makedev(major, minor) __mlibc_dev_makedev(major, minor) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SYSMACROS_H */ diff --git a/user/include/mlibc/sysdeps/ironclad/meson.build b/user/include/mlibc/sysdeps/ironclad/meson.build new file mode 100644 index 0000000..ad5b573 --- /dev/null +++ b/user/include/mlibc/sysdeps/ironclad/meson.build @@ -0,0 +1,145 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': false, + 'glibc': true, + 'bsd': true, +} + +rtld_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/ptrace.cpp', + 'generic/generic.cpp', + 'generic/mntent.cpp', + 'generic/mount.cpp', + 'generic/reboot.cpp', + 'generic/thread.cpp', + 'generic/mac.cpp', + 'generic/thread.S', +) + +if not no_headers + install_headers( + 'include/abi-bits/access.h', + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + if host_machine.cpu_family() == 'riscv64' + install_headers( + 'include/abi-bits/riscv-hwprobe.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + endif + + install_headers( + 'include/sys/mac.h', + 'include/sys/syscall.h', + 'include/sys/reboot.h', + 'include/sys/mount.h', + 'include/sys/sysmacros.h', + 'include/sys/ptrace.h', + subdir: 'sys' + ) + + install_headers( + 'include/asm/ioctls.h', + subdir: 'asm' + ) + + install_headers( + 'include/linux/fb.h', + subdir: 'linux' + ) + + install_headers( + 'include/mntent.h', + ) +endif + +if not headers_only + crt = custom_target( + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: files('crt-' + host_machine.cpu_family() / 'crt1.S'), + output: 'crt1.o', + install: true, + install_dir: get_option('libdir') + ) + + crt_pie = custom_target( + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: files('crt-' + host_machine.cpu_family() / 'Scrt1.S'), + output: 'Scrt1.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target( + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: files('crt-' + host_machine.cpu_family() / 'crti.S'), + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target( + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: files('crt-' + host_machine.cpu_family() / 'crtn.S'), + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/user/include/mlibc/sysdeps/keyronex/.clang-format b/user/include/mlibc/sysdeps/keyronex/.clang-format new file mode 100644 index 0000000..4662692 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/.clang-format @@ -0,0 +1,2 @@ +--- +DisableFormat: true diff --git a/user/include/mlibc/sysdeps/keyronex/generic/entry.cpp b/user/include/mlibc/sysdeps/keyronex/generic/entry.cpp new file mode 100644 index 0000000..8e1c1f9 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/generic/entry.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern char **environ; + +namespace mlibc { +int +sys_sigentry(void *sigentry) +{ + uintptr_t ret = syscall1(kPXSysSigEntry, (uintptr_t)sigentry, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +[[noreturn]] int +sys_sigreturn(ucontext_t *context) +{ + syscall1(kPXSysSigReturn, (uintptr_t)context, NULL); + __builtin_unreachable(); +} +} + +static void +do_stacktrace(ucontext_t *ctx) +{ + size_t *base_ptr = (size_t *)ctx->uc_mcontext.gregs[REG_RBP]; + + mlibc::infoLogger() << "Stacktrace:" << frg::endlog; + mlibc::infoLogger() << " [" << (void *)ctx->uc_mcontext.gregs[REG_RIP] + << "]" << frg::endlog; + for (;;) { + size_t old_bp = base_ptr[0]; + size_t ret_addr = base_ptr[1]; + if (!ret_addr) + break; + mlibc::infoLogger() + << " [" << (void *)ret_addr << "]" << frg::endlog; + if (!old_bp) + break; + base_ptr = (size_t *)old_bp; + } +} + +static void +__mlibc_sigentry(int which, siginfo_t *siginfo, void *handler, + bool is_sigaction, ucontext_t *ret_context) +{ + if ((uintptr_t)handler == (uintptr_t)SIG_DFL) { + mlibc::infoLogger() + << "mlibc: Unhandled signal " << which << frg::endlog; + do_stacktrace(ret_context); + mlibc::sys_exit(128 + which); + } else if ((uintptr_t)handler == (uintptr_t)SIG_IGN) { + /* epsilon */ + } else { + if (is_sigaction) + ((void (*)(int, siginfo_t *, void *))handler)(which, + siginfo, ret_context); + else + ((void (*)(int))handler)(which); + } + + mlibc::sys_sigreturn(ret_context); + + __builtin_unreachable(); +} + +extern "C" void +__mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) +{ + /* communicate the signal handler entry point to the kernel */ + mlibc::sys_sigentry((void *)__mlibc_sigentry); + + // TODO: call __dlapi_enter, otherwise static builds will break (see + // Linux sysdeps) + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, + environ); + exit(result); +} diff --git a/user/include/mlibc/sysdeps/keyronex/generic/generic.cpp b/user/include/mlibc/sysdeps/keyronex/generic/generic.cpp new file mode 100644 index 0000000..fb6f3ae --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/generic/generic.cpp @@ -0,0 +1,753 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STUB_ONLY \ + { \ + __ensure(!"STUB_ONLY function was called"); \ + __builtin_unreachable(); \ + } + +namespace mlibc { + +void +sys_libc_log(const char *message) +{ + syscall1(kPXSysDebug, (uintptr_t)message, NULL); +} + +void +sys_libc_panic() +{ + sys_libc_log("\nMLIBC PANIC\n"); + for (;;) + ; + STUB_ONLY +} + +void +sys_exit(int status) +{ + syscall1(kPXSysExit, status, NULL); + mlibc::panicLogger() << "sys_exit() returned!" << frg::endlog; + __builtin_unreachable(); +} + +#ifndef MLIBC_BUILDING_RTLD +int +sys_tcgetattr(int fd, struct termios *attr) +{ + int ret; + + if (int r = sys_ioctl(fd, TCGETS, attr, &ret) != 0) { + return r; + } + + return 0; +} + +int +sys_tcsetattr(int fd, int optional_action, const struct termios *attr) +{ + int ret; + + switch (optional_action) { + case TCSANOW: + optional_action = TCSETS; + break; + case TCSADRAIN: + optional_action = TCSETSW; + break; + case TCSAFLUSH: + optional_action = TCSETSF; + break; + default: + __ensure(!"Unsupported tcsetattr"); + } + + if (int r = sys_ioctl(fd, optional_action, (void *)attr, &ret) != 0) { + return r; + } + + return 0; +} +#endif + +int +sys_tcb_set(void *pointer) +{ + return syscall1(kPXSysSetFSBase, (uintptr_t)pointer, NULL); +} + +int +sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) +{ + uintptr_t ret = syscall4(kPXSysPPoll, (uintptr_t)fds, (uintptr_t)nfds, + (uintptr_t)timeout, (uintptr_t)sigmask, NULL); + if (int e = sc_error(ret); e) + return e; + *num_events = (ssize_t)ret; + return 0; +} + +int +sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) +{ + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + return sys_ppoll(fds, count, timeout < 0 ? NULL : &ts, NULL, + num_events); +} + +#ifndef MLIBC_BUILDING_RTLD +int +sys_pselect(int nfds, fd_set *read_set, fd_set *write_set, fd_set *except_set, + const struct timespec *timeout, const sigset_t *sigmask, int *num_events) +{ + struct pollfd *fds = (struct pollfd *)malloc( + nfds * sizeof(struct pollfd)); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + memset(fd, 0, sizeof(struct pollfd)); + + if (read_set && FD_ISSET(i, read_set)) + fd->events |= POLLIN; // TODO: Additional events. + if (write_set && FD_ISSET(i, write_set)) + fd->events |= POLLOUT; // TODO: Additional events. + if (except_set && FD_ISSET(i, except_set)) + fd->events |= POLLPRI; + + if (!fd->events) { + fd->fd = -1; + continue; + } + + fd->fd = i; + } + + int e = sys_ppoll(fds, nfds, timeout, sigmask, num_events); + + if (e != 0) { + free(fds); + return e; + } + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set) && + fd->revents & (POLLIN | POLLERR | POLLHUP)) { + FD_SET(i, &res_read_set); + } + + if (write_set && FD_ISSET(i, write_set) && + fd->revents & (POLLOUT | POLLERR | POLLHUP)) { + FD_SET(i, &res_write_set); + } + + if (except_set && FD_ISSET(i, except_set) && + fd->revents & POLLPRI) { + FD_SET(i, &res_except_set); + } + } + + free(fds); + + if (read_set) + memcpy(read_set, &res_read_set, sizeof(fd_set)); + if (write_set) + memcpy(write_set, &res_write_set, sizeof(fd_set)); + if (except_set) + memcpy(except_set, &res_except_set, sizeof(fd_set)); + + return 0; +} +#endif + +int +sys_fcntl(int fd, int request, va_list args, int *result) +{ + auto ret = syscall3(kPXSysFCntl, fd, request, va_arg(args, uint64_t), + NULL); + if (int e = sc_error(ret); e) + return e; + *result = ret; + return 0; +} + +int +sys_futex_wait(int *pointer, int expected, const struct timespec *time) +{ + auto ret = syscall3(kPXSysFutexWait, (uintptr_t)pointer, expected, + (uintptr_t)time, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_futex_wake(int *pointer) +{ + auto ret = syscall1(kPXSysFutexWake, (uintptr_t)pointer, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD +int +sys_ioctl(int fd, unsigned long request, void *arg, int *result) +{ + uintptr_t r = syscall3(kPXSysIOCtl, fd, request, (uintptr_t)arg, NULL); + if (int e = sc_error(r); e) + return e; + *result = r; + return 0; +} +#endif + +int +sys_isatty(int fd) +{ + uintptr_t ret = syscall1(kPXSysIsATTY, fd, NULL); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD +int +sys_getcwd(char *buffer, size_t size) +{ + uintptr_t ret = syscall2(kPXSysGetCWD, (uintptr_t)buffer, size, NULL); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} +#endif + +int +sys_dup(int fd, int flags, int *newfd) +{ + uintptr_t ret = syscall2(kPXSysDup, fd, flags, NULL); + if (int e = sc_error(ret); e) { + return e; + } + *newfd = ret; + return 0; +} + +int +sys_dup2(int fd, int flags, int newfd) +{ + uintptr_t ret = syscall3(kPXSysDup3, fd, newfd, flags, NULL); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int +sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) +{ + uintptr_t r = syscall4(kPXSysOpenAt, dirfd, (uintptr_t)path, + (uintptr_t)flags, (uintptr_t)mode, NULL); + if (int e = sc_error(r); e) + return e; + *fd = (int)r; + return 0; +} + +int +sys_open(const char *path, int flags, mode_t mode, int *fd) +{ + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} + +int +sys_open_dir(const char *path, int *handle) +{ + return sys_open(path, O_DIRECTORY, 0, handle); +} + +int +sys_read_entries(int fd, void *buffer, size_t max_size, size_t *bytes_read) +{ + uintptr_t r = syscall3(kPXSysReadDir, fd, (uintptr_t)buffer, max_size, + NULL); + + if (int e = sc_error(r); e) + return e; + + *bytes_read = r; + return 0; +} + +int +sys_close(int fd) +{ + return (int)syscall1(kPXSysClose, fd, NULL); +} + +int +sys_link(const char *old_path, const char *new_path) +{ + uintptr_t ret = syscall2(kPXSysLink, (uintptr_t)old_path, + (uintptr_t)new_path, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_seek(int fd, off_t offset, int whence, off_t *new_offset) +{ + uintptr_t ret = syscall3(kPXSysSeek, fd, offset, whence, NULL); + if (int e = sc_error(ret); e) + return e; + *new_offset = (ssize_t)ret; + return 0; +} + +int +sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) +{ + uintptr_t ret = syscall3(kPXSysRead, fd, (uintptr_t)buf, + (uintptr_t)count, NULL); + if (int e = sc_error(ret); e) + return e; + *bytes_read = (ssize_t)ret; + return 0; +} + +int +sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) +{ + uintptr_t ret = syscall3(kPXSysWrite, fd, (uintptr_t)buf, + (uintptr_t)count, NULL); + if (int e = sc_error(ret); e) + return e; + *bytes_written = (ssize_t)ret; + return 0; +} + +int +sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length) +{ + uintptr_t ret = syscall3(kPXSysReadLink, (uintptr_t)path, + (uintptr_t)buffer, (uintptr_t)max_size, NULL); + if (int e = sc_error(ret); e) + return e; + *length = (ssize_t)ret; + return 0; +} + +int +sys_pipe(int *fds, int flags) +{ + uintptr_t ret = syscall2(kPXSysPipe, (uintptr_t)fds, flags, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_unlinkat(int fd, const char *path, int flags) +{ + uintptr_t ret = syscall3(kPXSysUnlinkAt, fd, (uintptr_t)path, flags, + NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, + void **window) +{ + uintptr_t r = syscall6(kPXSysMmap, (uintptr_t)hint, size, prot, flags, + fd, offset, NULL); + if (int e = sc_error(r); e) + return e; + *window = (void *)r; + return 0; +} + +int +sys_vm_unmap(void *pointer, size_t size) +{ + uintptr_t r = syscall2(kPXSysMunmap, (uintptr_t)pointer, size, NULL); + if (int e = sc_error(r); e) + return e; + return 0; +} + +int +sys_vm_protect(void *pointer, size_t size, int prot) +{ + + mlibc::infoLogger() << "mlibc: sys_vm_protect(" << pointer << ", " + << size << ", " << prot << "); stub!\n" + << frg::endlog; + return 0; +} + +int +sys_anon_allocate(size_t size, void **pointer) +{ + return sys_vm_map(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_ANONYMOUS, -1, 0, pointer); +} + +int +sys_anon_free(void *pointer, size_t size) +{ + return sys_vm_unmap(pointer, size); +} + +pid_t +sys_getpid() +{ + return syscall0(kPXSysGetPID, NULL); +} + +pid_t +sys_getppid() +{ + return syscall0(kPXSysGetPPID, NULL); +} + +uid_t +sys_getuid() +{ + return 0; +} + +uid_t +sys_geteuid() +{ + return 0; +} + +gid_t +sys_getgid() +{ + return 0; +} + +int +sys_getsid(pid_t pid, pid_t *sid) +{ + auto ret = syscall1(kPXSysGetSID, pid, NULL); + if (int e = sc_error(ret); e) + return e; + *sid = (pid_t)(ret); + return 0; +} + +int +sys_setgid(gid_t gid) +{ + (void)gid; + return 0; +} + +int +sys_getpgid(pid_t pid, pid_t *out) +{ + auto ret = syscall1(kPXSysGetPGID, pid, NULL); + if (int e = sc_error(ret); e) + return e; + *out = (pid_t)(ret); + return 0; +} + +int +sys_setpgid(pid_t pid, pid_t pgid) +{ + auto ret = syscall2(kPXSysSetPGID, pid, pgid, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_setsid(pid_t *sid) +{ + auto ret = syscall0(kPXSysSetSID, NULL); + if (int e = sc_error(ret); e) + return e; + *sid = (pid_t)ret; + return 0; +} + +gid_t +sys_getegid() +{ + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" + << frg::endlog; + return 0; +} + +pid_t +sys_gettid() +{ + return syscall0(kPXSysGetTID, NULL); +} + +int +sys_clock_get(int clock, time_t *secs, long *nanos) +{ + auto ret = syscall1(kPXSysClockGet, clock, NULL); + *secs = ret / 1000000000; + *nanos = ret % 1000000000; + return 0; +} + +int +sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf) +{ + uintptr_t r; + enum posix_stat_kind kind; + + switch (fsfdt) { + case fsfd_target::fd: + kind = kPXStatKindFD; + break; + + case fsfd_target::path: + kind = kPXStatKindCWD; + break; + case fsfd_target::fd_path: + kind = kPXStatKindAt; + break; + + default: + __ensure(!"stat: Invalid fsfdt"); + __builtin_unreachable(); + } + + r = syscall5(kPXSysStat, kind, fd, (uintptr_t)path, flags, + (uintptr_t)statbuf, NULL); + if (int e = sc_error(r); e) + return e; + return 0; +} + +int +sys_statfs(const char *path, struct statfs *buf) +{ + uintptr_t ret = syscall2(kPXSysStatFS, (uintptr_t)path, (uintptr_t)buf, + NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_statvfs(const char *path, struct statvfs *buf) +{ + struct statfs sb; + uintptr_t ret = syscall2(kPXSysStatFS, (uintptr_t)path, (uintptr_t)&sb, + NULL); + if (int e = sc_error(ret); e) + return e; + + buf->f_bsize = sb.f_bsize; + buf->f_frsize = sb.f_frsize; + buf->f_blocks = sb.f_blocks; + buf->f_bfree = sb.f_bfree; + buf->f_bavail = sb.f_bavail; + + buf->f_files = sb.f_files; + buf->f_ffree = sb.f_ffree; + buf->f_favail = sb.f_ffree; + + buf->f_fsid = sb.f_fsid.__val[1] | (uint64_t)sb.f_fsid.__val[0] << 32; + buf->f_flag = sb.f_flags; + buf->f_namemax = sb.f_namelen; + + return 0; +} + +int +sys_faccessat(int dirfd, const char *pathname, int mode, int flags) +{ + (void)flags; + struct stat buf; + if (int r = sys_stat(dirfd == AT_FDCWD ? fsfd_target::path : + fsfd_target::fd_path, + dirfd, pathname, mode & AT_SYMLINK_FOLLOW, &buf)) { + return r; + } + return 0; +} + +int +sys_access(const char *path, int mode) +{ + return sys_faccessat(AT_FDCWD, path, mode, 0); +} + +int +sys_fork(pid_t *child) +{ + uintptr_t ret = syscall0(kPXSysFork, NULL); + if (int e = sc_error(ret); e) + return e; + *child = (int)ret; + return 0; +} + +int +sys_execve(const char *path, char *const argv[], char *const envp[]) +{ + uintptr_t ret = syscall3(kPXSysExecVE, (uintptr_t)path, (uintptr_t)argv, + (uintptr_t)envp, NULL); + if (int e = sc_error(ret); e) + return e; + mlibc::panicLogger() << "execve returned! " << ret << frg::endlog; + __builtin_unreachable(); +} + +int +sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, + pid_t *ret_pid) +{ + (void)ru; + + uintptr_t ret = syscall3(kPXSysWaitPID, pid, (uintptr_t)status, flags, + NULL); + if (int e = sc_error(ret); e) + return e; + *ret_pid = (pid_t)ret; + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD +int +sys_sleep(time_t *sec, long *nanosec) +{ + auto ret = syscall1(kPXSysSleep, *sec * 1000000000 + *nanosec, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_uname(struct utsname *buf) +{ + uintptr_t ret = syscall1(kPXSysUTSName, (uintptr_t)buf, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_gethostname(char *buf, size_t bufsize) +{ + struct utsname uname_buf; + if (auto e = sys_uname(&uname_buf); e) + return e; + + auto node_len = strlen(uname_buf.nodename); + if (node_len >= bufsize) + return ENAMETOOLONG; + + memcpy(buf, uname_buf.nodename, node_len); + buf[node_len] = '\0'; + return 0; +} + +int +sys_fsync(int) +{ + mlibc::infoLogger() << "mlibc: fsync is a stub" << frg::endlog; + return 0; +} + +int +sys_getentropy(void *buffer, size_t length) +{ + /* todo: improve lmao */ + mlibc::infoLogger() << "mlibc: getentropy is a stub" << frg::endlog; + memset(buffer, 123, length); + return 0; +} +#endif + +int +sys_mkdir(const char *path, mode_t mode) +{ + return sys_mkdirat(AT_FDCWD, path, mode); +} + +int +sys_mkdirat(int dirfd, const char *path, mode_t mode) +{ + uintptr_t ret = syscall3(kPXSysMkDirAt, dirfd, (uintptr_t)path, mode, + NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_chdir(const char *path) +{ + uintptr_t ret = syscall1(kPXSysChDir, (uintptr_t)path, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_umask(mode_t mode, mode_t *old) +{ + uintptr_t ret = syscall1(kPXSysUMask, mode, NULL); + if (int e = sc_error(ret); e) + return e; + *old = (mode_t)ret; + return 0; +} + +int +sys_rename(const char *old_path, const char *new_path) +{ + return sys_renameat(AT_FDCWD, old_path, AT_FDCWD, new_path); +} + +int +sys_renameat(int old_dirfd, const char *old_path, int new_dirfd, + const char *new_path) +{ + auto ret = syscall4(kPXSysRenameAt, old_dirfd, (uintptr_t)old_path, + new_dirfd, (uintptr_t)new_path, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/keyronex/generic/linux.cpp b/user/include/mlibc/sysdeps/keyronex/generic/linux.cpp new file mode 100644 index 0000000..9b4a4c7 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/generic/linux.cpp @@ -0,0 +1,41 @@ +#include + +#include +#include +#include +#include +#include + +namespace mlibc { + +int +sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, + const sigset_t *sigmask, int *raised) +{ + uintptr_t ret = syscall5(kPXSysEPollWait, epfd, (uintptr_t)ev, n, + timeout, (uintptr_t)sigmask, NULL); + if (int e = sc_error(ret); e) + return e; + *raised = ret; + return 0; +} + +int +sys_epoll_create(int flags, int *fd) +{ + uintptr_t ret = syscall1(kPXSysEPollCreate, flags, NULL); + if (int e = sc_error(ret); e) + return e; + *fd = ret; + return 0; +} + +int +sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) +{ + uintptr_t ret = syscall4(kPXSysEPollCtl, epfd, mode, fd, (uintptr_t)ev, + NULL); + return sc_error(ret); +} + +} \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/generic/signal.cpp b/user/include/mlibc/sysdeps/keyronex/generic/signal.cpp new file mode 100644 index 0000000..ead3dee --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/generic/signal.cpp @@ -0,0 +1,66 @@ +#include + +#include +#include +#include +#include + +namespace mlibc { + +int +sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve) +{ + auto ret = syscall3(kPXSysSigMask, how, (uintptr_t)set, + (uintptr_t)retrieve, NULL); + if (int e = sc_error(ret); e) { + return e; + } + + return 0; +} + +int +sys_sigaction(int signal, const struct sigaction *__restrict action, + struct sigaction *__restrict oldAction) +{ + auto ret = syscall3(kPXSysSigAction, signal, (uintptr_t)action, + (uintptr_t)oldAction, NULL); + if (int e = sc_error(ret); e) { + return e; + } + + return 0; +} + +int +sys_kill(int pid, int signal) +{ + if (signal == 0) { + mlibc::infoLogger() << "Sending signal 0! Allowing" << frg::endlog; + return 0; + } + + auto ret = syscall2(kPXSysSigSend, pid, signal, NULL); + if (int e = sc_error(ret); e) { + return e; + } + + return 0; +} + +int +sys_sigsuspend(const sigset_t *set) +{ + auto ret = syscall1(kPXSysSigSuspend, (uintptr_t)set, NULL); + if (int e = sc_error(ret); e) { + return e; + } + + mlibc::panicLogger() + << "Unexpected zero return from sigsuspend()" << frg::endlog; + + return 0; +} + +} \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/generic/socket.cpp b/user/include/mlibc/sysdeps/keyronex/generic/socket.cpp new file mode 100644 index 0000000..c6453bf --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/generic/socket.cpp @@ -0,0 +1,119 @@ +#include + +#include +#include +#include +#include + +#define log_unimplemented() \ + mlibc::infoLogger() << "mlibc: " << __PRETTY_FUNCTION__ \ + << " is a stub!" << frg::endlog; + +namespace mlibc { + +int +sys_socket(int family, int type, int protocol, int *fd) +{ + auto ret = syscall3(kPXSysSocket, family, type, protocol, NULL); + if (int e = sc_error(ret); e) + return e; + *fd = ret; + return 0; +} + +int +sys_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) +{ + auto ret = syscall3(kPXSysBind, fd, (uintptr_t)addr, addrlen, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) +{ + auto ret = syscall3(kPXSysConnect, fd, (uintptr_t)addr, addrlen, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_listen(int fd, int backlog) +{ + auto ret = syscall2(kPXSysListen, fd, backlog, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_accept(int fd, int *newfd, struct sockaddr *addr, socklen_t *addrlen, + int flags) +{ + auto ret = syscall4(kPXSysAccept, fd, (uintptr_t)addr, + (uintptr_t)addrlen, flags, NULL); + if (int e = sc_error(ret); e) + return e; + *newfd = ret; + return 0; +} + +int +sys_msg_send(int fd, const struct msghdr *msg, int flags, ssize_t *length) +{ + auto ret = syscall3(kPXSysSendMsg, fd, (uintptr_t)msg, flags, NULL); + if (int e = sc_error(ret); e) + return e; + *length = ret; + return 0; +} + +int +sys_msg_recv(int fd, struct msghdr *msg, int flags, ssize_t *length) +{ + auto ret = syscall3(kPXSysRecvMsg, fd, (uintptr_t)msg, flags, NULL); + if (int e = sc_error(ret); e) + return e; + *length = ret; + return 0; +} + +int +sys_socketpair(int domain, int type_and_flags, int proto, int *fds) +{ + auto ret = syscall4(kPXSysSocketPair, domain, type_and_flags, proto, + (uintptr_t)fds, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, + socklen_t *__restrict size) +{ + (void)fd; + (void)layer; + (void)number; + (void)buffer; + (void)size; + log_unimplemented(); + return ENOSYS; +} + +int +sys_setsockopt(int fd, int layer, int number, const void *buffer, + socklen_t size) +{ + (void)fd; + (void)layer; + (void)number; + (void)buffer; + (void)size; + log_unimplemented(); + return ENOSYS; +} + +} diff --git a/user/include/mlibc/sysdeps/keyronex/generic/thread.S b/user/include/mlibc/sysdeps/keyronex/generic/thread.S new file mode 100644 index 0000000..47ab6a9 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/generic/thread.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_thread_trampoline + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/keyronex/generic/thread.cpp b/user/include/mlibc/sysdeps/keyronex/generic/thread.cpp new file mode 100644 index 0000000..cafb74a --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/generic/thread.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_thread_trampoline(void *(*fn)(void *), Tcb *tcb, void *arg) { + if (mlibc::sys_tcb_set(tcb)) { + __ensure(!"failed to set tcb for new thread"); + } + + while (__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) { + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + } + + tcb->invokeThreadFunc(reinterpret_cast(fn), arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +#define DEFAULT_STACK 0x400000 + +namespace mlibc { + +extern "C" void __mlibc_thread_entry(); + + int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + (void)tcb; + + auto ret = syscall2(kPXSysForkThread, (uintptr_t)__mlibc_thread_entry, (uintptr_t)stack, NULL); + if (int e = sc_error(ret); e) + return e; + + *tid_out = ret; + return 0; + } + + int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if (!*stack) { + *stack_base = mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; + } + + void sys_thread_exit() { + mlibc::panicLogger() << "mlibc: sys_thread_exit unimplemented!" << frg::endlog; + __builtin_unreachable(); + } + + +} diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/access.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/access.h new file mode 100755 index 0000000..cb83931 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/auxv.h new file mode 100755 index 0000000..c43f878 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..0b0ec27 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..7dc8d7c --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..6a42da5 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/dev_t.h new file mode 100755 index 0000000..bca881e --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/epoll.h new file mode 100755 index 0000000..eb4b76d --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/errno.h new file mode 100755 index 0000000..6e507de --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fcntl.h new file mode 100755 index 0000000..463e2c9 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/gid_t.h new file mode 100755 index 0000000..abce6d6 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/in.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/in.h new file mode 100755 index 0000000..418d1d5 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ino_t.h new file mode 100755 index 0000000..4c20aca --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/inotify.h new file mode 100755 index 0000000..b5cb282 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ipc.h new file mode 100755 index 0000000..553c44e --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/keyronex/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/limits.h new file mode 100755 index 0000000..6c88db2 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5d78fdf --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..bb3b625 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/packet.h new file mode 100755 index 0000000..998ef1a --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/pid_t.h new file mode 100755 index 0000000..baa90f6 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/poll.h new file mode 100755 index 0000000..8ea6a0a --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ptrace.h new file mode 100755 index 0000000..b2517b2 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/random.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/random.h new file mode 100755 index 0000000..d64e04f --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/random.h @@ -0,0 +1 @@ +../../../../abis/keyronex/random.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/reboot.h new file mode 100755 index 0000000..77013a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/resource.h new file mode 100755 index 0000000..88d7402 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/riscv-hwprobe.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/riscv-hwprobe.h new file mode 100755 index 0000000..1e1ae04 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/riscv-hwprobe.h @@ -0,0 +1 @@ +../../../../abis/keyronex/riscv-hwprobe.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..d892c7e --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/keyronex/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..df7bccf --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/shm.h new file mode 100755 index 0000000..982b856 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/keyronex/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/sigevent.h new file mode 100755 index 0000000..83d069b --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/linux/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/signal.h new file mode 100755 index 0000000..4dcb0b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/socket.h new file mode 100755 index 0000000..f1dc016 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/stat.h new file mode 100755 index 0000000..1f63b41 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/time.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/time.h new file mode 100755 index 0000000..2a02625 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/uid_t.h new file mode 100755 index 0000000..b306777 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utsname.h new file mode 100755 index 0000000..b285754 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..bbe258c --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/keyronex/include/keyronex/syscall.h b/user/include/mlibc/sysdeps/keyronex/include/keyronex/syscall.h new file mode 100644 index 0000000..9cbafd0 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/include/keyronex/syscall.h @@ -0,0 +1,213 @@ +#ifndef _KEYRONEX__SYSCALL_H +#define _KEYRONEX__SYSCALL_H + +#include + +enum posix_syscall { + /*! debug print */ + kPXSysDebug, + kPXSysMmap, + kPXSysMunmap, + + kPXSysIOCtl, + kPXSysOpenAt, + kPXSysClose, + kPXSysRead, + kPXSysReadLink, + kPXSysWrite, + kPXSysSeek, + kPXSysPPoll, + kPXSysIsATTY, + kPXSysReadDir, + kPXSysStat, + kPXSysUnlinkAt, + kPXSysGetCWD, + kPXSysPipe, + kPXSysDup, + kPXSysDup3, + kPXSysLink, + kPXSysChDir, + kPXSysUMask, + kPXSysMkDirAt, + kPXSysRenameAt, + kPXSysStatFS, + kPXSysFCntl, + + kPXSysSetFSBase, + kPXSysExecVE, + kPXSysExit, + kPXSysFork, + kPXSysWaitPID, + kPXSysGetPID, + kPXSysGetPPID, + kPXSysGetPGID, + kPXSysSetPGID, + kPXSysGetSID, + kPXSysSetSID, + kPXSysGetTID, + + kPXSysSigAction, + kPXSysSigMask, + kPXSysSigSend, + kPXSysSigSuspend, + kPXSysSigTimedWait, + + kPXSysSocket, + kPXSysBind, + kPXSysConnect, + kPXSysListen, + kPXSysAccept, + kPXSysSendMsg, + kPXSysRecvMsg, + kPXSysSocketPair, + kPXSysGetSockOpt, + kPXSysSetSockOpt, + + kPXSysEPollCreate, + kPXSysEPollCtl, + kPXSysEPollWait, + + kPXSysSleep, + kPXSysUTSName, + kPXSysClockGet, + + kPXSysForkThread, + kPXSysFutexWait, + kPXSysFutexWake, + + /*! register signal entry function */ + kPXSysSigEntry, + /*! return from a signal */ + kPXSysSigReturn, +}; + +enum posix_stat_kind { + kPXStatKindFD, + kPXStatKindAt, + kPXStatKindCWD, +}; + +#if defined(__x86_64__) +static inline uintptr_t +syscall0(uintptr_t num, uintptr_t *out) +{ + uintptr_t ret, ret2; + asm volatile("int $0x80" : "=a"(ret), "=D"(ret2) : "a"(num) : "memory"); + if (out) + *out = ret2; + return ret; +} + +static inline uintptr_t +syscall1(uintptr_t num, uintptr_t arg1, uintptr_t *out) +{ + uintptr_t ret, ret2; + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1) + : "memory"); + if (out) + *out = ret2; + return ret; +} + +static inline uintptr_t +syscall2(uintptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t *out) +{ + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline uintptr_t +syscall3(intptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + uintptr_t *out) +{ + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline uintptr_t +syscall4(intptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + uintptr_t arg4, uintptr_t *out) +{ + register uintptr_t r10 asm("r10") = arg4; + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline uintptr_t +syscall5(uintptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + uintptr_t arg4, uintptr_t arg5, uintptr_t *out) +{ + register uintptr_t r10 asm("r10") = arg4, r8 asm("r8") = arg5; + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), + "r"(r8) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline uintptr_t +syscall6(uintptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, uintptr_t *out) +{ + register uintptr_t r10 asm("r10") = arg4, r8 asm("r8") = arg5, + r9 asm("r9") = arg6; + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), + "r"(r8), "r"(r9) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline int +sc_error(uintptr_t ret) +{ + if (ret > -4096UL) + return -ret; + return 0; +} +#endif + +#endif diff --git a/user/include/mlibc/sysdeps/keyronex/meson.build b/user/include/mlibc/sysdeps/keyronex/meson.build new file mode 100644 index 0000000..89407e4 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/meson.build @@ -0,0 +1,121 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': true, + 'glibc': true, + 'bsd': true, +} + + +rtld_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/generic.cpp', + 'generic/linux.cpp', + 'generic/signal.cpp', + 'generic/socket.cpp', + 'generic/thread.cpp', + 'generic/thread.S' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/random.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + if host_machine.cpu_family() == 'riscv64' + install_headers( + 'include/abi-bits/riscv-hwprobe.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + endif + + install_headers( + 'include/keyronex/syscall.h', + subdir: 'keyronex', + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crt0.S b/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crt0.S new file mode 100644 index 0000000..d16a46f --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crt0.S @@ -0,0 +1,7 @@ +.section .text +.global _start +_start: + mov $main, %rdi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crti.S b/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crti.S new file mode 100644 index 0000000..911b078 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crtn.S b/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..0187e50 --- /dev/null +++ b/user/include/mlibc/sysdeps/keyronex/x86_64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/kirkos/dso.c b/user/include/mlibc/sysdeps/kirkos/dso.c new file mode 100644 index 0000000..1d7de0c --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/dso.c @@ -0,0 +1 @@ +void *__dso_handle = &__dso_handle; \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/entry.cpp b/user/include/mlibc/sysdeps/kirkos/entry.cpp new file mode 100644 index 0000000..eb76761 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/entry.cpp @@ -0,0 +1,15 @@ +#include +#include +#include + +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; + +extern "C" void __mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + __dlapi_enter(entry_stack); + + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} + diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/access.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/access.h new file mode 100644 index 0000000..56b3ac0 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +#endif /* _ABIBITS_ACCESS_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/auxv.h new file mode 100755 index 0000000..819b386 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/auxv.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_PLATFORM 15 +#define AT_HWCAP 16 +#define AT_CLKTCK 17 +#define AT_FPUCW 18 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_HWCAP2 26 +#define AT_HWCAP3 29 +#define AT_HWCAP4 30 +#define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 + +#endif /* _ABIBITS_AUXV_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..b104f7e --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/blkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +#include + +typedef __mlibc_int64 blkcnt_t; + +#endif /* _ABIBITS_BLKCNT_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..a65f69d --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/blksize_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +typedef long blksize_t; + +#endif /* _ABIBITS_BLKSIZE_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..90466dd --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/clockid_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef int clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/dev_t.h new file mode 100755 index 0000000..ca2f7bd --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/dev_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +#include + +typedef __mlibc_uint64 dev_t; + +#endif /* _ABIBITS_DEV_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/epoll.h new file mode 100644 index 0000000..3ffca20 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/epoll.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_EPOLL_H +#define _ABIBITS_EPOLL_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define EPOLL_CLOEXEC 02000000 /* Same as __MLIBC_O_CLOEXEC */ + +#endif /* _ABIBITS_EPOLL_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/errno.h new file mode 100755 index 0000000..61bf847 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/errno.h @@ -0,0 +1,143 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EWOULDBLOCK EAGAIN +#define ENOMSG 42 +#define EIDRM 43 +#define ECHRNG 44 +#define EL2NSYNC 45 +#define EL3HLT 46 +#define EL3RST 47 +#define ELNRNG 48 +#define EUNATCH 49 +#define ENOCSI 50 +#define EL2HLT 51 +#define EBADE 52 +#define EBADR 53 +#define EXFULL 54 +#define ENOANO 55 +#define EBADRQC 56 +#define EBADSLT 57 +#define EDEADLOCK EDEADLK +#define EBFONT 59 +#define ENOSTR 60 +#define ENODATA 61 +#define ETIME 62 +#define ENOSR 63 +#define ENONET 64 +#define ENOPKG 65 +#define EREMOTE 66 +#define ENOLINK 67 +#define EADV 68 +#define ESRMNT 69 +#define ECOMM 70 +#define EPROTO 71 +#define EMULTIHOP 72 +#define EDOTDOT 73 +#define EBADMSG 74 +#define EOVERFLOW 75 +#define ENOTUNIQ 76 +#define EBADFD 77 +#define EREMCHG 78 +#define ELIBACC 79 +#define ELIBBAD 80 +#define ELIBSCN 81 +#define ELIBMAX 82 +#define ELIBEXEC 83 +#define EILSEQ 84 +#define ERESTART 85 +#define ESTRPIPE 86 +#define EUSERS 87 +#define ENOTSOCK 88 +#define EDESTADDRREQ 89 +#define EMSGSIZE 90 +#define EPROTOTYPE 91 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP 95 +#define ENOTSUP EOPNOTSUPP +#define EPFNOSUPPORT 96 +#define EAFNOSUPPORT 97 +#define EADDRINUSE 98 +#define EADDRNOTAVAIL 99 +#define ENETDOWN 100 +#define ENETUNREACH 101 +#define ENETRESET 102 +#define ECONNABORTED 103 +#define ECONNRESET 104 +#define ENOBUFS 105 +#define EISCONN 106 +#define ENOTCONN 107 +#define ESHUTDOWN 108 +#define ETOOMANYREFS 109 +#define ETIMEDOUT 110 +#define ECONNREFUSED 111 +#define EHOSTDOWN 112 +#define EHOSTUNREACH 113 +#define EALREADY 114 +#define EINPROGRESS 115 +#define ESTALE 116 +#define EUCLEAN 117 +#define ENOTNAM 118 +#define ENAVAIL 119 +#define EISNAM 120 +#define EREMOTEIO 121 +#define EDQUOT 122 +#define ENOMEDIUM 123 +#define EMEDIUMTYPE 124 +#define ECANCELED 125 +#define ENOKEY 126 +#define EKEYEXPIRED 127 +#define EKEYREVOKED 128 +#define EKEYREJECTED 129 +#define EOWNERDEAD 130 +#define ENOTRECOVERABLE 131 +#define ERFKILL 132 +#define EHWPOISON 133 + + +/* This is mlibc-specific. */ +#define EIEIO 4095 + +#endif /* _ABIBITS_ERRNO_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fcntl.h new file mode 100755 index 0000000..bcee906 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fcntl.h @@ -0,0 +1,124 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +#include +#include + +#define O_PATH 010000000 + +#define O_ACCMODE (03 | O_PATH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_LARGEFILE 0100000 +#define O_NOATIME 01000000 +#define O_TMPFILE 020000000 + +#define O_EXEC O_PATH +#define O_SEARCH O_PATH + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLK64 F_SETLK +#define F_SETLKW 7 +#define F_SETLKW64 F_SETLKW + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 + +#define F_SETLEASE 1024 +#define F_GETLEASE 1025 +#define F_NOTIFY 1026 +#define F_DUPFD_CLOEXEC 1030 +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define F_SEAL_SEAL 0x0001 +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 + +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define FD_CLOEXEC 1 + +#define AT_FDCWD -100 +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 +#define AT_NO_AUTOMOUNT 0x800 +#define AT_EMPTY_PATH 0x1000 + +#if __MLIBC_LINUX_OPTION + +#define DN_ACCESS 1 +#define DN_MODIFY 2 +#define DN_CREATE 4 +#define DN_DELETE 8 +#define DN_RENAME 16 +#define DN_ATTRIB 32 +#define DN_MULTISHOT 0x80000000 + +#define AT_STATX_SYNC_AS_STAT 0x0000 +#define AT_STATX_FORCE_SYNC 0x2000 +#define AT_STATX_DONT_SYNC 0x4000 +#define AT_STATX_SYNC_TYPE 0x6000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#if defined(_GNU_SOURCE) +struct f_owner_ex { + int type; + pid_t pid; +}; +#endif /* _GNU_SOURCE */ + +#define F_OWNER_TID 0 +#define F_OWNER_PID 1 +#define F_OWNER_PGRP 2 + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 + +#endif /* _ABIBITS_FCNTL_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fd_set.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fd_set.h new file mode 100644 index 0000000..dbbcdba --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fd_set.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_FD_SET_H +#define _ABIBITS_FD_SET_H + +#include + +#define FD_SETSIZE 1024 + +typedef struct __attribute__((__aligned__(__alignof__(long)))) { + __mlibc_uint8 fds_bits[128]; +} fd_set; + +#endif /* _ABIBITS_FD_SET_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fsblkcnt_t.h new file mode 100644 index 0000000..ecb5ca4 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSBLKCNT_T_H +#define _ABIBITS_FSBLKCNT_T_H + +#include + +typedef __mlibc_uint64 fsblkcnt_t; + +#endif /* _ABIBITS_FSBLKCNT_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fsfilcnt_t.h new file mode 100644 index 0000000..d7e3cb6 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSFILCNT_T_H +#define _ABIBITS_FSFILCNT_T_H + +#include + +typedef __mlibc_uint64 fsfilcnt_t; + +#endif /* _ABIBITS_FSFILCNT_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/gid_t.h new file mode 100755 index 0000000..b6cf2fa --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/gid_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif /* _ABIBITS_GID_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/in.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/in.h new file mode 100644 index 0000000..5b48c31 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/in.h @@ -0,0 +1,235 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t sin_zero[8]; +}; + +#if !__MLIBC_LINUX_OPTION || (!defined(_UAPI_LINUX_IN6_H) && !defined(_UAPI_IPV6_H)) +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; +#endif /* !__MLIBC_LINUX_OPTION || (!defined(_UAPI_LINUX_IN6_H) && !defined(_UAPI_IPV6_H)) */ + +#define MCAST_INCLUDE 1 + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_req { + uint32_t gr_interface; + struct sockaddr_storage gr_group; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#define INADDR_ANY ((in_addr_t) 0x00000000) +#define INADDR_BROADCAST ((in_addr_t) 0xffffffff) +#define INADDR_NONE ((in_addr_t) 0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t) 0x7f000001) + +#define INADDR_UNSPEC_GROUP ((in_addr_t) 0xe0000000) +#define INADDR_ALLHOSTS_GROUP ((in_addr_t) 0xe0000001) +#define INADDR_ALLRTRS_GROUP ((in_addr_t) 0xe0000002) +#define INADDR_ALLSNOOPERS_GROUP ((in_addr_t) 0xe000006a) +#define INADDR_MAX_LOCAL_GROUP ((in_addr_t) 0xe00000ff) + +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + +#define IPPORT_RESERVED 1024 + +#define IPPROTO_IP 0 +#define IPPROTO_HOPOPTS 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_IGMP 2 +#define IPPROTO_IPIP 4 +#define IPPROTO_TCP 6 +#define IPPROTO_EGP 8 +#define IPPROTO_PUP 12 +#define IPPROTO_UDP 17 +#define IPPROTO_IDP 22 +#define IPPROTO_TP 29 +#define IPPROTO_DCCP 33 +#define IPPROTO_IPV6 41 +#define IPPROTO_ROUTING 43 +#define IPPROTO_FRAGMENT 44 +#define IPPROTO_RSVP 46 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_NONE 59 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_MTP 92 +#define IPPROTO_BEETPH 94 +#define IPPROTO_ENCAP 98 +#define IPPROTO_PIM 103 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_MH 135 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MPLS 137 +#define IPPROTO_RAW 255 +#define IPPROTO_MAX 256 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_HDRINCL 3 +#define IP_OPTIONS 4 +#define IP_RECVOPTS 6 +#define IP_RETOPTS 7 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_MTU 14 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define IP_UNICAST_IF 50 + +#define IPV6_2292PKTOPTIONS 6 +#define IPV6_2292HOPLIMIT 8 +#define IPV6_UNICAST_HOPS 16 +#define IPV6_MULTICAST_IF 17 +#define IPV6_MULTICAST_HOPS 18 +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_JOIN_GROUP 20 +#define IPV6_LEAVE_GROUP 21 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_MTU 24 +#define IPV6_RECVERR 25 +#define IPV6_V6ONLY 26 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 + +#define IPV6_RECVTCLASS 66 +#define IPV6_TCLASS 67 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#define IPV6_PMTUDISC_DONT 0 +#define IPV6_PMTUDISC_WANT 1 +#define IPV6_PMTUDISC_DO 2 +#define IPV6_PMTUDISC_PROBE 3 +#define IPV6_PMTUDISC_INTERFACE 4 +#define IPV6_PMTUDISC_OMIT 5 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_WANT 1 +#define IP_PMTUDISC_DO 2 +#define IP_PMTUDISC_PROBE 3 +#define IP_PMTUDISC_INTERFACE 4 +#define IP_PMTUDISC_OMIT 5 + +#define MCAST_JOIN_GROUP 42 +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#if __MLIBC_LINUX_OPTION + +#define __UAPI_DEF_IN_ADDR 0 +#define __UAPI_DEF_IN_CLASS 0 +#define __UAPI_DEF_IN_IPPROTO 0 +#define __UAPI_DEF_IN_PKTINFO 0 +#define __UAPI_DEF_IP_MREQ 0 +#define __UAPI_DEF_SOCKADDR_IN 0 + +#define __UAPI_DEF_IN6_ADDR 0 +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#define __UAPI_DEF_IN6_PKTINFO 0 +#define __UAPI_DEF_IP6_MTUINFO 0 +#define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_MREQ 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 +#define __UAPI_DEF_SOCKADDR_IN6 0 + +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABITBITS_IN_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ino_t.h new file mode 100755 index 0000000..b76b8b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ino_t.h @@ -0,0 +1,10 @@ + +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +#include + +typedef __mlibc_uint64 ino_t; +typedef ino_t ino64_t; + +#endif /* _ABIBITS_INO_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/inotify.h new file mode 100644 index 0000000..a745bcf --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/inotify.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_INOTIFY_H +#define _ABIBITS_INOTIFY_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#include + +#define IN_CLOEXEC O_CLOEXEC +#define IN_NONBLOCK O_NONBLOCK + +#endif /* _ABIBITS_INOTIFY_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ioctls.h new file mode 100644 index 0000000..d33a41e --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ioctls.h @@ -0,0 +1,20 @@ +#ifndef _ABIBITS_IOCTLS_H +#define _ABIBITS_IOCTLS_H + +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D + +#define SIOCPROTOPRIVATE 0x89E0 +#define SIOCGSTAMP 0x8906 +#define SIOCGIFNAME 0x8910 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFADDR 0x8915 +#define SIOCGIFINDEX 0x8933 +#define SIOCATMARK 0x8905 +#define SIOCGIFHWADDR 0x8927 +#define SIOCGIFBRDADDR 0x8919 +#define SIOCGIFNETMASK 0x891B + +#endif /* _ABIBITS_IOCTLS_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ipc.h new file mode 100644 index 0000000..09d3f80 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ipc.h @@ -0,0 +1,50 @@ +#ifndef _ABIBITS_IPC_H +#define _ABIBITS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) || defined(__m68k__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc64_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + int __ipc_perm_seq; + long __unused[2]; +}; + +#define ipc_perm ipc64_perm + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/limits.h new file mode 100755 index 0000000..472b3ec --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/limits.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 +#define LOGIN_NAME_MAX 256 +#define HOST_NAME_MAX 64 +#define NAME_MAX 255 +#define OPEN_MAX 256 + +#endif /*_ABIBITS_LIMITS_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5f6fb06 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/mode_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef unsigned int mode_t; + +#endif /* _ABIBITS_MODE_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/mqueue.h new file mode 100644 index 0000000..18596db --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/mqueue.h @@ -0,0 +1,20 @@ +#ifndef _ABIBITS_MQUEUE_H +#define _ABIBITS_MQUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct mq_attr { + long mq_flags; + long mq_maxmsg; + long mq_msgsize; + long mq_curmsgs; + long __pad[4]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MQUEUE_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/msg.h new file mode 100644 index 0000000..a9aa285 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/msg.h @@ -0,0 +1,44 @@ +#ifndef _ABIBITS_MSG_H +#define _ABIBITS_MSG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long msglen_t; +typedef unsigned long msgqnum_t; + +struct msqid64_ds { + struct ipc64_perm msg_perm; +#if (UINTPTR_MAX == UINT64_MAX) /* || x32 ABI */ + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; +#else + unsigned long msg_stime; + unsigned long msg_stime_high; + unsigned long msg_rtime; + unsigned long msg_rtime_high; + unsigned long msg_ctime; + unsigned long msg_ctime_high; +#endif + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; +}; + +#define msqid_ds msqid64_ds + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MSG_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..c9d4d45 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/nlink_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef unsigned long nlink_t; + +#endif /* _ABIBITS_NLINK_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/packet.h new file mode 100644 index 0000000..7597eb7 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif /* _ABIBITS_PACKET_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/pid_t.h new file mode 100755 index 0000000..b7e8ec7 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/pid_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif /* _ABIBITS_PID_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/poll.h new file mode 100644 index 0000000..8a31198 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 +#define POLLRDNORM 0x0040 +#define POLLRDBAND 0x0080 +#define POLLWRNORM 0x0100 +#define POLLWRBAND 0x0200 +#define POLLRDHUP 0x2000 + +#endif /* _ABIBITS_POLL_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ptrace.h new file mode 100644 index 0000000..c57c4cb --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/ptrace.h @@ -0,0 +1,65 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error "ptrace() is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_POKEUSER 6 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 +#define PTRACE_EVENT_STOP 128 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif /* _ABIBITS_PTRACE_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/random.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/random.h new file mode 100644 index 0000000..228533e --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/random.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_RANDOM_H +#define _ABIBITS_RANDOM_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error "getrandom() is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define GRND_NONBLOCK 0x0001 +#define GRND_RANDOM 0x0002 +#define GRND_INSECURE 0x0004 + +#endif /* _ABIBITS_RANDOM_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/reboot.h new file mode 100644 index 0000000..a27d9be --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/reboot.h @@ -0,0 +1,18 @@ +#ifndef _ABIBITS_REBOOT_H +#define _ABIBITS_REBOOT_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + +#endif /* _ABIBITS_REBOOT_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/resource.h new file mode 100644 index 0000000..46f7a12 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/resource.h @@ -0,0 +1,54 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN -1 + +#define RLIMIT_CPU 0 +#define RLIMIT_FSIZE 1 +#define RLIMIT_DATA 2 +#define RLIMIT_STACK 3 +#define RLIMIT_CORE 4 +#define RLIMIT_RSS 5 +#define RLIMIT_NPROC 6 +#define RLIMIT_NOFILE 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_AS 9 +#define RLIMIT_LOCKS 10 +#define RLIMIT_SIGPENDING 11 +#define RLIMIT_MSGQUEUE 12 +#define RLIMIT_NICE 13 +#define RLIMIT_RTPRIO 14 +#define RLIMIT_RTTIME 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RESOURCE_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/riscv-hwprobe.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/riscv-hwprobe.h new file mode 100644 index 0000000..fc7fdee --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/riscv-hwprobe.h @@ -0,0 +1,107 @@ +#ifndef _ABIBITS_RISCV_HWPROBE_H +#define _ABIBITS_RISCV_HWPROBE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct riscv_hwprobe { + signed long long int key; + unsigned long long int value; +}; + +#define RISCV_HWPROBE_KEY_MVENDORID 0 +#define RISCV_HWPROBE_KEY_MARCHID 1 +#define RISCV_HWPROBE_KEY_MIMPID 2 +#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3 +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0) +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 +#define RISCV_HWPROBE_IMA_FD (1 << 0) +#define RISCV_HWPROBE_IMA_C (1 << 1) +#define RISCV_HWPROBE_IMA_V (1 << 2) +#define RISCV_HWPROBE_EXT_ZBA (1 << 3) +#define RISCV_HWPROBE_EXT_ZBB (1 << 4) +#define RISCV_HWPROBE_EXT_ZBS (1 << 5) +#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) +#define RISCV_HWPROBE_EXT_ZBC (1 << 7) +#define RISCV_HWPROBE_EXT_ZBKB (1 << 8) +#define RISCV_HWPROBE_EXT_ZBKC (1 << 9) +#define RISCV_HWPROBE_EXT_ZBKX (1 << 10) +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#define RISCV_HWPROBE_EXT_ZKNH (1 << 13) +#define RISCV_HWPROBE_EXT_ZKSED (1 << 14) +#define RISCV_HWPROBE_EXT_ZKSH (1 << 15) +#define RISCV_HWPROBE_EXT_ZKT (1 << 16) +#define RISCV_HWPROBE_EXT_ZVBB (1 << 17) +#define RISCV_HWPROBE_EXT_ZVBC (1 << 18) +#define RISCV_HWPROBE_EXT_ZVKB (1 << 19) +#define RISCV_HWPROBE_EXT_ZVKG (1 << 20) +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22) +#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23) +#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24) +#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25) +#define RISCV_HWPROBE_EXT_ZVKT (1 << 26) +#define RISCV_HWPROBE_EXT_ZFH (1 << 27) +#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) +#define RISCV_HWPROBE_EXT_ZVFH (1 << 30) +#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31) +#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) +#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) +#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) +#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) +#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36) +#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37) +#define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38) +#define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39) +#define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40) +#define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41) +#define RISCV_HWPROBE_EXT_ZIMOP (1ULL << 42) +#define RISCV_HWPROBE_EXT_ZCA (1ULL << 43) +#define RISCV_HWPROBE_EXT_ZCB (1ULL << 44) +#define RISCV_HWPROBE_EXT_ZCD (1ULL << 45) +#define RISCV_HWPROBE_EXT_ZCF (1ULL << 46) +#define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47) +#define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48) +#define RISCV_HWPROBE_EXT_SUPM (1ULL << 49) +#define RISCV_HWPROBE_EXT_ZICNTR (1ULL << 50) +#define RISCV_HWPROBE_EXT_ZIHPM (1ULL << 51) +#define RISCV_HWPROBE_EXT_ZFBFMIN (1ULL << 52) +#define RISCV_HWPROBE_EXT_ZVFBFMIN (1ULL << 53) +#define RISCV_HWPROBE_EXT_ZVFBFWMA (1ULL << 54) +#define RISCV_HWPROBE_EXT_ZICBOM (1ULL << 55) +#define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) +#define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) +#define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58) +#define RISCV_HWPROBE_KEY_CPUPERF_0 5 +#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) +#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) +#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0) +#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) +#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) +#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7 +#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8 +#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0 11 +#define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE 12 +#define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0 13 + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_RISCV_HWPROBE_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/rlim_t.h new file mode 100644 index 0000000..7a13862 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/rlim_t.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_RLIM_T_H +#define _ABIBITS_RLIM_T_H + +#if __INTPTR_WIDTH__ == 32 +typedef unsigned long long int rlim_t; +#else +typedef unsigned long int rlim_t; +#endif + +#endif /* _ABIBITS_RLIM_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sa_family_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sa_family_t.h new file mode 100644 index 0000000..7775dfd --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sa_family_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_SA_FAMILY_T_H +#define _ABIBITS_SA_FAMILY_T_H + +typedef unsigned short sa_family_t; + +#endif /* _ABIBITS_SA_FAMILY_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..c0a13c0 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/seek-whence.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_DATA 3 +#define SEEK_HOLE 4 + +#endif /* _ABIBITS_SEEK_WHENCE_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sem.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sem.h new file mode 100644 index 0000000..85dae90 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sem.h @@ -0,0 +1,30 @@ +#ifndef _ABIBITS_SEM_H +#define _ABIBITS_SEM_H + +#include +#include + +#define GETPID 11 +#define GETVAL 12 +#define GETALL 13 +#define SETVAL 16 +#define SETALL 17 + +#define SEM_UNDO 0x1000 + +struct sembuf { + unsigned short int sem_num; + short int sem_op; + short int sem_flg; +}; + +struct semid_ds { + struct ipc_perm sem_perm; + time_t sem_otime; + time_t sem_ctime; + + unsigned long sem_nsems; + unsigned long __unused[2]; +}; + +#endif /* _ABIBITS_SEM_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/shm.h new file mode 100755 index 0000000..5f32528 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/shm.h @@ -0,0 +1,107 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +#if defined(__i386__) || defined(__m68k__) +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + unsigned long __shm_atime_lo; + unsigned long __shm_atime_hi; + unsigned long __shm_dtime_lo; + unsigned long __shm_dtime_hi; + unsigned long __shm_ctime_lo; + unsigned long __shm_ctime_hi; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __unused[3]; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; +}; +#elif defined(__x86_64__) || defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch64) +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; + unsigned long __unused[2]; +}; +#else +#error "Missing architecture specific code." +#endif + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sig-limits.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sig-limits.h new file mode 100644 index 0000000..ab4ef8c --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sig-limits.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_SIG_LIMITS_H +#define _ABIBITS_SIG_LIMITS_H + +#include + +#define NSIG_MAX 1024 + +#if defined(_DEFAULT_SOURCE) || __MLIBC_XOPEN +#define NZERO 20 +#endif /* defined(_DEFAULT_SOURCE) || __MLIBC_XOPEN */ + +#endif /*_ABIBITS_SIG_LIMITS_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sigevent.h new file mode 100755 index 0000000..ab836d4 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sigevent.h @@ -0,0 +1,24 @@ +#ifndef _ABIBITS_SIGEVENT_H +#define _ABIBITS_SIGEVENT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sigevent { + union sigval sigev_value; + int sigev_notify; + int sigev_signo; + void (*sigev_notify_function)(union sigval); + struct __mlibc_threadattr *sigev_notify_attributes; + pid_t sigev_notify_thread_id; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGEVENT_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/signal.h new file mode 100755 index 0000000..df8da4a --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/signal.h @@ -0,0 +1,647 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#include +#include +#include +#include +#include +#include + +#define POLL_IN 1 +#define POLL_OUT 2 +#define POLL_MSG 3 +#define POLL_ERR 4 +#define POLL_PRI 5 +#define POLL_HUP 6 + +/* struct taken from musl. */ + +typedef struct { + int si_signo, si_errno, si_code; + union { + char __pad[128 - 2*sizeof(int) - sizeof(long)]; + struct { + union { + struct { + pid_t si_pid; + uid_t si_uid; + } __piduid; + struct { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union { + union sigval si_value; + struct { + int si_status; + clock_t si_utime, si_stime; + } __sigchld; + } __second; + } __si_common; + struct { + void *si_addr; + short si_addr_lsb; + union { + struct { + void *si_lower; + void *si_upper; + } __addr_bnd; + unsigned si_pkey; + } __first; + } __sigfault; + struct { + long si_band; + int si_fd; + } __sigpoll; + struct { + void *si_call_addr; + int si_syscall; + unsigned si_arch; + } __sigsys; + } __si_fields; +} siginfo_t; +#define si_pid __si_fields.__si_common.__first.__piduid.si_pid +#define si_uid __si_fields.__si_common.__first.__piduid.si_uid +#define si_status __si_fields.__si_common.__second.__sigchld.si_status +#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime +#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime +#define si_value __si_fields.__si_common.__second.si_value +#define si_addr __si_fields.__sigfault.si_addr +#define si_addr_lsb __si_fields.__sigfault.si_addr_lsb +#define si_lower __si_fields.__sigfault.__first.__addr_bnd.si_lower +#define si_upper __si_fields.__sigfault.__first.__addr_bnd.si_upper +#define si_pkey __si_fields.__sigfault.__first.si_pkey +#define si_band __si_fields.__sigpoll.si_band +#define si_fd __si_fields.__sigpoll.si_fd +#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid +#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun +#define si_ptr si_value.sival_ptr +#define si_int si_value.sival_int +#define si_call_addr __si_fields.__sigsys.si_call_addr +#define si_syscall __si_fields.__sigsys.si_syscall +#define si_arch __si_fields.__sigsys.si_arch + +/* Required for sys_sigaction sysdep. */ +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +/* SA_NOMASK is an alias for SA_NODEFER */ +/* SA_ONESHOT is an alias for SA_RESETHAND */ +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +#ifdef __cplusplus +extern "C" { +#endif + +/* Argument for signal() */ +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(0)) +#define SIG_IGN ((__sighandler)(void *)(1)) + +#define SIGABRT 6 +#define SIGFPE 8 +#define SIGILL 4 +#define SIGINT 2 +#define SIGSEGV 11 +#define SIGTERM 15 +#define SIGPROF 27 +#define SIGIO 29 +#define SIGPWR 30 +#define SIGRTMIN 35 +#define SIGRTMAX 64 + +typedef struct { + unsigned long sig[1024 / (8 * sizeof(long))]; +} sigset_t; + +/* constants for sigprocmask() */ +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +#define SIGHUP 1 +#define SIGQUIT 3 +#define SIGTRAP 5 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGWINCH 28 +#define SIGPOLL 29 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS +#define SIGCANCEL 32 +#define SIGTIMER 33 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +/* constants for sigev_notify of struct sigevent */ +#define SIGEV_SIGNAL 0 +#define SIGEV_NONE 1 +#define SIGEV_THREAD 2 +#define SIGEV_THREAD_ID 4 + +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 +#define BUS_MCEERR_AR 4 +#define BUS_MCEERR_AO 5 + +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +#define NSIG 65 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +#if defined(__i386__) +#define REG_GS 0 +#define REG_FS 1 +#define REG_ES 2 +#define REG_DS 3 +#define REG_EDI 4 +#define REG_ESI 5 +#define REG_EBP 6 +#define REG_ESP 7 +#define REG_EBX 8 +#define REG_EDX 9 +#define REG_ECX 10 +#define REG_EAX 11 +#define REG_TRAPNO 12 +#define REG_ERR 13 +#define REG_EIP 14 +#define REG_CS 15 +#define REG_EFL 16 +#define REG_UESP 17 +#define REG_SS 18 +#define NGREG 19 +#elif defined(__x86_64__) +#define REG_R8 0 +#define REG_R9 1 +#define REG_R10 2 +#define REG_R11 3 +#define REG_R12 4 +#define REG_R13 5 +#define REG_R14 6 +#define REG_R15 7 +#define REG_RDI 8 +#define REG_RSI 9 +#define REG_RBP 10 +#define REG_RBX 11 +#define REG_RDX 12 +#define REG_RAX 13 +#define REG_RCX 14 +#define REG_RSP 15 +#define REG_RIP 16 +#define REG_EFL 17 +#define REG_CSGSFS 18 +#define REG_ERR 19 +#define REG_TRAPNO 20 +#define REG_OLDMASK 21 +#define REG_CR2 22 +#define NGREG 23 +#endif + +#include + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + } __sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; +}; + +#define sa_handler __sa_handler.sa_handler +#define sa_sigaction __sa_handler.sa_sigaction + +/* Taken from the linux kernel headers */ + +#if defined(__x86_64__) || defined(__i386__) + +struct _fpreg { + unsigned short significand[4]; + unsigned short exponent; +}; + +struct _fpxreg { + unsigned short significand[4]; + unsigned short exponent; + unsigned short padding[3]; +}; + +struct _xmmreg { + uint32_t element[4]; +}; + +struct _fpstate { +#if defined(__x86_64__) + uint16_t cwd; + uint16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t rdp; + uint32_t mxcsr; + uint32_t mxcr_mask; + struct _fpxreg _st[8]; + struct _xmmreg _xmm[16]; + uint32_t padding[24]; +#elif defined(__i386__) + uint32_t cw; + uint32_t sw; + uint32_t tag; + uint32_t ipoff; + uint32_t cssel; + uint32_t dataoff; + uint32_t datasel; + struct _fpreg _st[8]; + uint16_t status; + uint16_t magic; + + /* FXSR FPU */ + + uint32_t _fxsr_env[6]; + uint32_t mxscr; + uint32_t reserved; + struct _fpxreg _fxsr_st[8]; + struct _xmmreg _xmm[8]; + + uint32_t padding2[56]; +#endif +}; + +struct sigcontext { +#if defined(__x86_64__) + unsigned long r8, r9, r10, r11, r12, r13, r14, r15; + unsigned long rdi, rsi, rbp, rbx, rdx, rax, rcx, rsp, rip, eflags; + unsigned short cs, gs, fs, __pad0; + unsigned long err, trapno, oldmask, cr2; + struct _fpstate *fpstate; + unsigned long __reserved1[8]; +#elif defined(__i386__) + unsigned short gs, __gsh, fs, __fsh, es, __esh, ds, __dsh; + unsigned long edi, esi, ebp, esp, ebx, edx, ecx, eax; + unsigned long trapno, err, eip; + unsigned short cs, __csh; + unsigned long eflags, esp_at_signal; + unsigned short ss, __ssh; + struct _fpstate *fpstate; + unsigned long oldmask, cr2; +#endif +}; + +typedef struct { + unsigned long gregs[NGREG]; + struct _fpstate *fpregs; + unsigned long __reserved1[8]; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#elif defined(__riscv) && __riscv_xlen == 64 +/* Definitions from Linux kernel headers. */ + +#define NGREG 32 + +enum { + REG_PC = 0, +#define REG_PC REG_PC + REG_RA = 1, +#define REG_RA REG_RA + REG_SP = 2, +#define REG_SP REG_SP + REG_TP = 4, +#define REG_TP REG_TP + REG_S0 = 8, +#define REG_S0 REG_S0 + REG_A0 = 10 +#define REG_A0 REG_A0 +}; + +struct __riscv_f_ext_state { + uint32_t f[32]; + uint32_t fcsr; +}; + +struct __riscv_d_ext_state { + uint64_t f[32]; + uint32_t fcsr; +}; + +struct __riscv_q_ext_state { + uint64_t f[64] __attribute__((__aligned__(16))); + uint32_t fcsr; + uint32_t reserved[3]; +}; + +union __riscv_fp_state { + struct __riscv_f_ext_state f; + struct __riscv_d_ext_state d; + struct __riscv_q_ext_state q; +}; + +typedef unsigned long __riscv_mc_gp_state[NGREG]; + +typedef struct sigcontext { + __riscv_mc_gp_state gregs; + union __riscv_fp_state fpregs; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + uint8_t __unused[1024 / 8 - sizeof(sigset_t)]; +#pragma GCC diagnostic pop + mcontext_t uc_mcontext; +} ucontext_t; + +#elif defined (__aarch64__) + +#define NGREG 34 + +typedef struct sigcontext { + uint64_t fault_address; + uint64_t regs[31]; + uint64_t sp; + uint64_t pc; + uint64_t pstate; + uint8_t __reserved[4096]; +} mcontext_t; + +#define FPSIMD_MAGIC 0x46508001 +#define ESR_MAGIC 0x45535201 +#define EXTRA_MAGIC 0x45585401 +#define SVE_MAGIC 0x53564501 +struct _aarch64_ctx { + uint32_t magic; + uint32_t size; +}; +struct fpsimd_context { + struct _aarch64_ctx head; + uint32_t fpsr; + uint32_t fpcr; + __uint128_t vregs[32]; +}; +struct esr_context { + struct _aarch64_ctx head; + uint64_t esr; +}; +struct extra_context { + struct _aarch64_ctx head; + uint64_t datap; + uint32_t size; + uint32_t __reserved[3]; +}; +struct sve_context { + struct _aarch64_ctx head; + uint16_t vl; + uint16_t __reserved[3]; +}; +#define SVE_VQ_BYTES 16 +#define SVE_VQ_MIN 1 +#define SVE_VQ_MAX 512 +#define SVE_VL_MIN (SVE_VQ_MIN * SVE_VQ_BYTES) +#define SVE_VL_MAX (SVE_VQ_MAX * SVE_VQ_BYTES) +#define SVE_NUM_ZREGS 32 +#define SVE_NUM_PREGS 16 +#define sve_vl_valid(vl) \ + ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX) +#define sve_vq_from_vl(vl) ((vl) / SVE_VQ_BYTES) +#define sve_vl_from_vq(vq) ((vq) * SVE_VQ_BYTES) +#define SVE_SIG_ZREG_SIZE(vq) ((unsigned)(vq) * SVE_VQ_BYTES) +#define SVE_SIG_PREG_SIZE(vq) ((unsigned)(vq) * (SVE_VQ_BYTES / 8)) +#define SVE_SIG_FFR_SIZE(vq) SVE_SIG_PREG_SIZE(vq) +#define SVE_SIG_REGS_OFFSET \ + ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1)) \ + / SVE_VQ_BYTES * SVE_VQ_BYTES) +#define SVE_SIG_ZREGS_OFFSET SVE_SIG_REGS_OFFSET +#define SVE_SIG_ZREG_OFFSET(vq, n) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n)) +#define SVE_SIG_ZREGS_SIZE(vq) \ + (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET) +#define SVE_SIG_PREGS_OFFSET(vq) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq)) +#define SVE_SIG_PREG_OFFSET(vq, n) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n)) +#define SVE_SIG_PREGS_SIZE(vq) \ + (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq)) +#define SVE_SIG_FFR_OFFSET(vq) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq)) +#define SVE_SIG_REGS_SIZE(vq) \ + (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET) +#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq)) + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + mcontext_t uc_mcontext; +} ucontext_t; + +#elif defined (__m68k__) + +/* taken from musl */ + +#if defined(_GNU_SOURCE) || defined(__MLIBC_BUILDING_MLIBC) +enum { R_D0 = 0 }; +#define R_D0 R_D0 +enum { R_D1 = 1 }; +#define R_D1 R_D1 +enum { R_D2 = 2 }; +#define R_D2 R_D2 +enum { R_D3 = 3 }; +#define R_D3 R_D3 +enum { R_D4 = 4 }; +#define R_D4 R_D4 +enum { R_D5 = 5 }; +#define R_D5 R_D5 +enum { R_D6 = 6 }; +#define R_D6 R_D6 +enum { R_D7 = 7 }; +#define R_D7 R_D7 +enum { R_A0 = 8 }; +#define R_A0 R_A0 +enum { R_A1 = 9 }; +#define R_A1 R_A1 +enum { R_A2 = 10 }; +#define R_A2 R_A2 +enum { R_A3 = 11 }; +#define R_A3 R_A3 +enum { R_A4 = 12 }; +#define R_A4 R_A4 +enum { R_A5 = 13 }; +#define R_A5 R_A5 +enum { R_A6 = 14 }; +#define R_A6 R_A6 +enum { R_A7 = 15 }; +#define R_A7 R_A7 +enum { R_SP = 15 }; +#define R_SP R_SP +enum { R_PC = 16 }; +#define R_PC R_PC +enum { R_PS = 17 }; +#define R_PS R_PS +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(__MLIBC_BUILDING_MLIBC) + +struct sigcontext { + unsigned long sc_mask, sc_usp, sc_d0, sc_d1, sc_a0, sc_a1; + unsigned short sc_sr; + unsigned long sc_pc; + unsigned short sc_formatvec; + unsigned long sc_fpregs[6], sc_fpcntl[3]; + unsigned char sc_fpstate[216]; +}; + +typedef int greg_t, gregset_t[18]; +typedef struct { + int f_pcr, f_psr, f_fpiaddr, f_fpregs[8][3]; +} fpregset_t; + +typedef struct { + int version; + gregset_t gregs; + fpregset_t fpregs; +} mcontext_t; +#else +typedef struct { + int __version; + int __gregs[18]; + int __fpregs[27]; +} mcontext_t; +#endif + +struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + long __reserved[80]; + sigset_t uc_sigmask; +} ucontext_t; + +#elif defined(__loongarch64) +/* Taken from musl. */ + +#define NGREG 32 +#define REG_RA 1 +#define REG_SP 3 +#define REG_S0 23 +#define REG_S1 24 +#define REG_A0 4 +#define REG_S2 25 +#define REG_NARGS 8 + +typedef unsigned long greg_t, gregset_t[32]; + +struct sigcontext { + unsigned long sc_pc; + unsigned long sc_regs[32]; + unsigned sc_flags; + unsigned long sc_extcontext[1] __attribute__((__aligned__(16))); +}; + +typedef struct { + unsigned long pc; + unsigned long gregs[32]; + unsigned flags; + unsigned long extcontext[1] __attribute__((__aligned__(16))); +} mcontext_t; + +struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +}; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + long __uc_pad; + mcontext_t uc_mcontext; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGNAL_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sigval.h new file mode 100755 index 0000000..627b624 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sigval.h @@ -0,0 +1,17 @@ +#ifndef _ABIBITS_SIGVAL_H +#define _ABIBITS_SIGVAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +union sigval { + int sival_int; + void *sival_ptr; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SIGVAL_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sockaddr_storage.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sockaddr_storage.h new file mode 100644 index 0000000..576a65a --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/sockaddr_storage.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_SOCKADDR_STORAGE_H +#define _ABIBITS_SOCKADDR_STORAGE_H + +#include + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t) - sizeof(long)]; + long __force_alignment; +}; + +#endif /* _ABIBITS_SOCKADDR_STORAGE_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/socket.h new file mode 100755 index 0000000..a1c6710 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/socket.h @@ -0,0 +1,329 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned short sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + size_t msg_iovlen; /* int in POSIX */ + void *msg_control; + size_t msg_controllen; /* socklen_t in POSIX */ + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t) - sizeof(long)]; + long __force_alignment; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + size_t cmsg_len; /* socklen_t in POSIX */ + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_CREDENTIALS 2 + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#ifndef SOCK_STREAM +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#endif + +#define SOCK_RAW 3 +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 +#define SOCK_DCCP 6 +#define SOCK_PACKET 10 + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 02000000 +#define SOCK_NONBLOCK 04000 +#endif + +#define PF_UNSPEC 0 +#define PF_LOCAL 1 +#define PF_UNIX PF_LOCAL +#define PF_FILE PF_LOCAL +#define PF_INET 2 +#define PF_AX25 3 +#define PF_IPX 4 +#define PF_APPLETALK 5 +#define PF_NETROM 6 +#define PF_BRIDGE 7 +#define PF_ATMPVC 8 +#define PF_X25 9 +#define PF_INET6 10 +#define PF_ROSE 11 +#define PF_DECnet 12 +#define PF_NETBEUI 13 +#define PF_SECURITY 14 +#define PF_KEY 15 +#define PF_NETLINK 16 +#define PF_ROUTE PF_NETLINK +#define PF_PACKET 17 +#define PF_ASH 18 +#define PF_ECONET 19 +#define PF_ATMSVC 20 +#define PF_RDS 21 +#define PF_SNA 22 +#define PF_IRDA 23 +#define PF_PPPOX 24 +#define PF_WANPIPE 25 +#define PF_LLC 26 +#define PF_IB 27 +#define PF_MPLS 28 +#define PF_CAN 29 +#define PF_TIPC 30 +#define PF_BLUETOOTH 31 +#define PF_IUCV 32 +#define PF_RXRPC 33 +#define PF_ISDN 34 +#define PF_PHONET 35 +#define PF_IEEE802154 36 +#define PF_CAIF 37 +#define PF_ALG 38 +#define PF_NFC 39 +#define PF_VSOCK 40 +#define PF_KCM 41 +#define PF_QIPCRTR 42 +#define PF_SMC 43 +#define PF_XDP 44 +#define PF_MAX 45 + +#define AF_UNSPEC PF_UNSPEC +#define AF_LOCAL PF_LOCAL +#define AF_UNIX AF_LOCAL +#define AF_FILE AF_LOCAL +#define AF_INET PF_INET +#define AF_AX25 PF_AX25 +#define AF_IPX PF_IPX +#define AF_APPLETALK PF_APPLETALK +#define AF_NETROM PF_NETROM +#define AF_BRIDGE PF_BRIDGE +#define AF_ATMPVC PF_ATMPVC +#define AF_X25 PF_X25 +#define AF_INET6 PF_INET6 +#define AF_ROSE PF_ROSE +#define AF_DECnet PF_DECnet +#define AF_NETBEUI PF_NETBEUI +#define AF_SECURITY PF_SECURITY +#define AF_KEY PF_KEY +#define AF_NETLINK PF_NETLINK +#define AF_ROUTE PF_ROUTE +#define AF_PACKET PF_PACKET +#define AF_ASH PF_ASH +#define AF_ECONET PF_ECONET +#define AF_ATMSVC PF_ATMSVC +#define AF_RDS PF_RDS +#define AF_SNA PF_SNA +#define AF_IRDA PF_IRDA +#define AF_PPPOX PF_PPPOX +#define AF_WANPIPE PF_WANPIPE +#define AF_LLC PF_LLC +#define AF_IB PF_IB +#define AF_MPLS PF_MPLS +#define AF_CAN PF_CAN +#define AF_TIPC PF_TIPC +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_IUCV PF_IUCV +#define AF_RXRPC PF_RXRPC +#define AF_ISDN PF_ISDN +#define AF_PHONET PF_PHONET +#define AF_IEEE802154 PF_IEEE802154 +#define AF_CAIF PF_CAIF +#define AF_ALG PF_ALG +#define AF_NFC PF_NFC +#define AF_VSOCK PF_VSOCK +#define AF_KCM PF_KCM +#define AF_QIPCRTR PF_QIPCRTR +#define AF_SMC PF_SMC +#define AF_XDP PF_XDP +#define AF_MAX PF_MAX + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +#define SO_REUSEPORT 15 +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_ACCEPTCONN 30 +#define SO_PEERSEC 31 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 + +#ifndef SO_RCVTIMEO +#if __LONG_MAX == 0x7fffffff +#define SO_RCVTIMEO 66 +#else +#define SO_RCVTIMEO 20 +#endif +#endif + +#ifndef SO_RCVTIMEO_OLD +#define SO_RCVTIMEO_OLD 20 +#endif + +#ifndef SO_SNDTIMEO +#if __LONG_MAX == 0x7fffffff +#define SO_SNDTIMEO 67 +#else +#define SO_SNDTIMEO 21 +#endif +#endif + +#ifndef SO_SNDTIMEO_OLD +#define SO_SNDTIMEO_OLD 21 +#endif + +#ifndef SO_TIMESTAMP +#if __LONG_MAX == 0x7fffffff +#define SO_TIMESTAMP 63 +#define SO_TIMESTAMPNS 64 +#define SO_TIMESTAMPING 65 +#else +#define SO_TIMESTAMP 29 +#define SO_TIMESTAMPNS 35 +#define SO_TIMESTAMPING 37 +#endif +#endif + +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 +#define SO_GET_FILTER SO_ATTACH_FILTER + +#define SO_PEERNAME 28 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SO_PASSSEC 34 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS +#define SO_MARK 36 +#define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 +#define SO_NOFCS 43 +#define SO_LOCK_FILTER 44 +#define SO_SELECT_ERR_QUEUE 45 +#define SO_BUSY_POLL 46 +#define SO_MAX_PACING_RATE 47 +#define SO_BPF_EXTENSIONS 48 +#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#define SO_ATTACH_REUSEPORT_CBPF 51 +#define SO_ATTACH_REUSEPORT_EBPF 52 +#define SO_CNX_ADVICE 53 +#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_MEMINFO 55 +#define SO_INCOMING_NAPI_ID 56 +#define SO_COOKIE 57 +#define SCM_TIMESTAMPING_PKTINFO 58 +#define SO_PEERGROUPS 59 +#define SO_ZEROCOPY 60 +#define SO_TXTIME 61 +#define SCM_TXTIME SO_TXTIME +#define SO_BINDTOIFINDEX 62 +#define SO_DETACH_REUSEPORT_BPF 68 + +#define SOL_SOCKET 1 + +#define SOL_IP 0 +#define SOL_IPV6 41 +#define SOL_ICMPV6 58 + +#define SOL_RAW 255 +#define SOL_DECNET 261 +#define SOL_X25 262 +#define SOL_PACKET 263 +#define SOL_ATM 264 +#define SOL_AAL 265 +#define SOL_IRDA 266 +#define SOL_NETBEUI 267 +#define SOL_LLC 268 +#define SOL_DCCP 269 +#define SOL_NETLINK 270 +#define SOL_TIPC 271 +#define SOL_RXRPC 272 +#define SOL_PPPOL2TP 273 +#define SOL_BLUETOOTH 274 +#define SOL_PNPIPE 275 +#define SOL_RDS 276 +#define SOL_IUCV 277 +#define SOL_CAIF 278 +#define SOL_ALG 279 +#define SOL_NFC 280 +#define SOL_KCM 281 +#define SOL_TLS 282 +#define SOL_XDP 283 + +#define SOMAXCONN 128 + +#define MSG_OOB 0x0001 +#define MSG_PEEK 0x0002 +#define MSG_DONTROUTE 0x0004 +#define MSG_CTRUNC 0x0008 +#define MSG_PROXY 0x0010 +#define MSG_TRUNC 0x0020 +#define MSG_DONTWAIT 0x0040 +#define MSG_EOR 0x0080 +#define MSG_WAITALL 0x0100 +#define MSG_FIN 0x0200 +#define MSG_SYN 0x0400 +#define MSG_CONFIRM 0x0800 +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 +#define MSG_NOSIGNAL 0x4000 +#define MSG_MORE 0x8000 +#define MSG_WAITFORONE 0x10000 +#define MSG_BATCH 0x40000 +#define MSG_ZEROCOPY 0x4000000 +#define MSG_FASTOPEN 0x20000000 +#define MSG_CMSG_CLOEXEC 0x40000000 + +#endif \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..382e738 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/socklen_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_SOCKLEN_T_H +#define _ABIBITS_SOCKLEN_T_H + +typedef unsigned socklen_t; + +#endif /* _ABIBITS_SOCKLEN_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/stat.h new file mode 100755 index 0000000..e9a2885 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/stat.h @@ -0,0 +1,148 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__x86_64__) + +struct stat { + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; + unsigned int __pad0; + dev_t st_rdev; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + long __unused[3]; +}; + +#elif (defined(__riscv) && __riscv_xlen == 64) || defined (__aarch64__) || defined(__loongarch64) + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + dev_t __pad1; + off_t st_size; + blksize_t st_blksize; + int __pad2; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + int __pad3[2]; +}; + +#elif defined(__i386__) + +struct stat { + dev_t st_dev; + int __st_dev_padding; + long __st_ino_truncated; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + int __st_rdev_padding; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct { + long tv_sec; + long tv_nsec; + } __st_atim32, __st_mtim32, __st_ctim32; + ino_t st_ino; + + /* These fields are not in the ABI. Their values are */ + /* copied from __st_atim32, __st_mtim32, __st_ctim32 */ + /* accordingly. */ + + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; +}; +#elif defined (__m68k__) + +struct stat { + dev_t st_dev; + unsigned char __st_dev_padding[2]; + unsigned long __st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + unsigned char __st_rdev_padding; + long long st_size; /* TODO: off64_t? */ + blksize_t st_blksize; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + ino_t st_ino; +}; + +#endif + +#define stat64 stat + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_STAT_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statfs.h new file mode 100755 index 0000000..d568866 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statfs.h @@ -0,0 +1,49 @@ +#ifndef _ABIBITS_STATFS_H +#define _ABIBITS_STATFS_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error "statfs() is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#include +#include + +typedef struct __mlibc_fsid { + int __val[2]; +} fsid_t; + +/* WARNING: keep `statfs` and `statfs64` in sync or bad things will happen! */ +struct statfs { + unsigned long f_type; + unsigned long f_bsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsid_t f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_flags; + unsigned long __f_spare[4]; +}; + +/* WARNING: keep `statfs` and `statfs64` in sync or bad things will happen! */ +struct statfs64 { + unsigned long f_type; + unsigned long f_bsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsid_t f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_flags; + unsigned long __f_spare[4]; +}; + +#endif /* _ABIBITS_STATFS_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1e2b0ea --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statvfs.h @@ -0,0 +1,51 @@ +#ifndef _ABIBITS_STATVFS_H +#define _ABIBITS_STATVFS_H + +#include +#include + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_NODEV 4 +#define ST_NOEXEC 8 +#define ST_SYNCHRONOUS 16 +#define ST_MANDLOCK 64 +#define ST_WRITE 128 +#define ST_APPEND 256 +#define ST_IMMUTABLE 512 +#define ST_NOATIME 1024 +#define ST_NODIRATIME 2048 + +/* On Linux, this struct is not directly used by the kernel. */ + +/* WARNING: keep `statvfs` and `statvfs64` in sync or bad things will happen! */ +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; + +/* WARNING: keep `statvfs` and `statvfs64` in sync or bad things will happen! */ +struct statvfs64 { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; + +#endif /* _ABIBITS_STATVFS_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statx.h new file mode 100755 index 0000000..63160db --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/statx.h @@ -0,0 +1,77 @@ +#ifndef _ABIBITS_STATX_H +#define _ABIBITS_STATX_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error "statx() is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#include + +struct statx_timestamp { + __mlibc_int64 tv_sec; + __mlibc_uint32 tv_nsec; + __mlibc_uint32 __padding; +}; + +#define STATX_TYPE 0x1 +#define STATX_MODE 0x2 +#define STATX_NLINK 0x4 +#define STATX_UID 0x8 +#define STATX_GID 0x10 +#define STATX_ATIME 0x20 +#define STATX_MTIME 0x40 +#define STATX_CTIME 0x80 +#define STATX_INO 0x100 +#define STATX_SIZE 0x200 +#define STATX_BLOCKS 0x400 +#define STATX_BASIC_STATS 0x7ff +#define STATX_BTIME 0x800 +#define STATX_MNT_ID 0x1000 +#define STATX_DIOALIGN 0x2000 +#define STATX_ALL 0xfff + +#define STATX_ATTR_COMPRESSED 0x4 +#define STATX_ATTR_IMMUTABLE 0x10 +#define STATX_ATTR_APPEND 0x20 +#define STATX_ATTR_NODUMP 0x40 +#define STATX_ATTR_ENCRYPTED 0x800 +#define STATX_ATTR_AUTOMOUNT 0x1000 +#define STATX_ATTR_MOUNT_ROOT 0x2000 +#define STATX_ATTR_VERITY 0x100000 +#define STATX_ATTR_DAX 0x200000 + +struct statx { + __mlibc_uint32 stx_mask; + + __mlibc_uint32 stx_blksize; + __mlibc_uint64 stx_attributes; + __mlibc_uint32 stx_nlink; + __mlibc_uint32 stx_uid; + __mlibc_uint32 stx_gid; + __mlibc_uint16 stx_mode; + __mlibc_uint16 __padding; + __mlibc_uint64 stx_ino; + __mlibc_uint64 stx_size; + __mlibc_uint64 stx_blocks; + __mlibc_uint64 stx_attributes_mask; + + struct statx_timestamp stx_atime; + struct statx_timestamp stx_btime; + struct statx_timestamp stx_ctime; + struct statx_timestamp stx_mtime; + + __mlibc_uint32 stx_rdev_major; + __mlibc_uint32 stx_rdev_minor; + __mlibc_uint32 stx_dev_major; + __mlibc_uint32 stx_dev_minor; + + __mlibc_uint64 stx_mnt_id; + __mlibc_uint32 stx_dio_mem_align; + __mlibc_uint32 stx_dio_offset_align; + + __mlibc_uint64 __padding1[12]; +}; + +#endif \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..06d8a2c --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/suseconds_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SUSECONDS_T_H +#define _ABIBITS_SUSECONDS_T_H + +#include + +typedef long suseconds_t; + +#endif /* _ABIBITS_SUSECONDS_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/termios.h new file mode 100755 index 0000000..668e9fd --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/termios.h @@ -0,0 +1,155 @@ +#ifndef _ABIBITS_TERMIOS_H +#define _ABIBITS_TERMIOS_H + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +/* indices for the c_cc array in struct termios */ +#define NCCS 32 +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* bitwise flags for c_iflag in struct termios */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* bitwise flags for c_oflag in struct termios */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE) + +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 + +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 + +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 + +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 + +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +#endif + +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 + +/* bitwise constants for c_cflag in struct termios */ +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 + +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 + +/* bitwise constants for c_lflag in struct termios */ +#define ISIG 0000001 +#define ICANON 0000002 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define IEXTEN 0100000 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define EXTA 0000016 +#define EXTB 0000017 +#define CBAUD 0010017 +#define CBAUDEX 0010000 +#define CIBAUD 002003600000 +#define CMSPAR 010000000000 +#define CRTSCTS 020000000000 + +#define XCASE 0000004 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define EXTPROC 0200000 + +#define XTABS 0014000 + +#endif + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; + unsigned short c_oflag; + unsigned short c_cflag; + unsigned short c_lflag; + unsigned char c_line; + unsigned char c_cc[NCC]; +}; + +#endif \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/time.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/time.h new file mode 100755 index 0000000..403066a --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif /* _ABIBITS_TIME_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/uid_t.h new file mode 100755 index 0000000..f026b71 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/uid_t.h @@ -0,0 +1,7 @@ + +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif /* _ABIBITS_UID_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..d7a6dba --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utmp-defines.h @@ -0,0 +1,25 @@ +#ifndef _ABIBITS_UTMP_DEFINES_H +#define _ABIBITS_UTMP_DEFINES_H + +#include + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +#ifdef _GNU_SOURCE +#define ACCOUNTING 9 +#endif + +#if __MLIBC_LINUX_OPTION +#define UTMP_FILE "/var/run/utmp" +#define WTMP_FILE "/var/log/wtmp" +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABIBITS_UTMP_DEFINES_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utmpx.h new file mode 100755 index 0000000..353cca9 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utmpx.h @@ -0,0 +1,36 @@ +#ifndef _ABIBITS_UTMPX_H +#define _ABIBITS_UTMPX_H + +#include +#include + +#define __UT_HOSTSIZE 256 +#define __UT_NAMESIZE 32 +#define __UT_LINESIZE 32 + +/* Struct definition taken from musl */ +struct utmpx { + short ut_type; + short __ut_pad1; + pid_t ut_pid; + char ut_line[__UT_LINESIZE]; + char ut_id[4]; + char ut_user[__UT_NAMESIZE]; + char ut_host[__UT_HOSTSIZE]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + int ut_session, __ut_pad2; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +#define e_exit __e_exit +#define e_termination __e_termination + +#define UTMPX_FILE "/var/run/utmp" +#define WTMPX_FILE "/var/log/wtmp" + +#endif /* _ABIBITS_UTMPX_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utsname.h new file mode 100755 index 0000000..fcfedc1 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/utsname.h @@ -0,0 +1,13 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +#endif /* _ABIBITS_UTSNAME_T_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..a7652db --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/vm-flags.h @@ -0,0 +1,81 @@ +#ifndef _ABIBITS_VM_FLAGS_H +#define _ABIBITS_VM_FLAGS_H + +#include + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS 0x20 + +#if __MLIBC_LINUX_OPTION + +#define MAP_GROWSDOWN 0x100 +#define MAP_DENYWRITE 0x800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_NORESERVE 0x4000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_SYNC 0x80000 +#define MAP_FIXED_NOREPLACE 0x100000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#define MS_ASYNC 0x01 +#define MS_INVALIDATE 0x02 +#define MS_SYNC 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 0 +#define POSIX_MADV_RANDOM 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_WILLNEED 3 +#define POSIX_MADV_DONTNEED 4 + +#if __MLIBC_LINUX_OPTION + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_REMOVE 9 +#define MADV_DONTFORK 10 +#define MADV_DOFORK 11 +#define MADV_MERGEABLE 12 +#define MADV_UNMERGEABLE 13 +#define MADV_HUGEPAGE 14 +#define MADV_NOHUGEPAGE 15 +#define MADV_DONTDUMP 16 +#define MADV_DODUMP 17 +#define MADV_WIPEONFORK 18 +#define MADV_KEEPONFORK 19 +#define MADV_COLD 20 +#define MADV_PAGEOUT 21 +#define MADV_HWPOISON 100 +#define MADV_SOFT_OFFLINE 101 + +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U +#define MFD_HUGETLB 4U + +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABIBITS_VM_FLAGS_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/vt.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/vt.h new file mode 100755 index 0000000..968fe0c --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/vt.h @@ -0,0 +1,82 @@ +#ifndef _ABIBITS_VT_H +#define _ABIBITS_VT_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +#define MIN_NR_CONSOLES 1 +#define MAX_NR_CONSOLES 63 + +#define VT_OPENQRY 0x5600 +#define VT_GETMODE 0x5601 +#define VT_SETMODE 0x5602 +#define VT_GETSTATE 0x5603 +#define VT_SENDSIG 0x5604 +#define VT_RELDISP 0x5605 +#define VT_ACTIVATE 0x5606 +#define VT_WAITACTIVE 0x5607 +#define VT_DISALLOCATE 0x5608 +#define VT_RESIZE 0x5609 +#define VT_RESIZEX 0x560A +#define VT_LOCKSWITCH 0x560B +#define VT_UNLOCKSWITCH 0x560C +#define VT_GETHIFONTMASK 0x560D +#define VT_WAITEVENT 0x560E +#define VT_SETACTIVATE 0x560F + +struct vt_mode { + char mode; + char waitv; + short relsig; + short acqsig; + short frsig; +}; + +#define VT_AUTO 0x00 +#define VT_PROCESS 0x01 +#define VT_ACKACQ 0x02 + +struct vt_stat { + unsigned short v_active; + unsigned short v_signal; + unsigned short v_state; +}; + +struct vt_sizes { + unsigned short v_rows; + unsigned short v_cols; + unsigned short v_scrollsize; +}; + +struct vt_consize { + unsigned short v_rows; + unsigned short v_cols; + unsigned short v_vlin; + unsigned short v_clin; + unsigned short v_vcol; + unsigned short v_ccol; +}; + +#define VT_EVENT_SWITCH 0x0001 +#define VT_EVENT_BLANK 0x0002 +#define VT_EVENT_UNBLANK 0x0004 +#define VT_EVENT_RESIZE 0x0008 +#define VT_MAX_EVENT 0x000F + +struct vt_event { + unsigned int event; + + unsigned int oldev; + unsigned int newev; + unsigned int pad[4]; +}; + +struct vt_setactivate { + unsigned int console; + struct vt_mode mode; +}; + +#endif /* _ABIBITS_VT_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/wait.h new file mode 100755 index 0000000..5a91795 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/wait.h @@ -0,0 +1,34 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#include + +#define WNOHANG 1 +#define WUNTRACED 2 +#define WSTOPPED 2 +#define WEXITED 4 +#define WCONTINUED 8 +#define WNOWAIT 0x01000000 + +#if __MLIBC_LINUX_OPTION + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) (((x) & 0xff00) >> 8) +#define WTERMSIG(x) ((x) & 0x7f) +#define WSTOPSIG(x) WEXITSTATUS(x) +#define WIFEXITED(x) (WTERMSIG(x) == 0) +#define WIFSIGNALED(x) (((signed char) (((x) & 0x7f) + 1) >> 1) > 0) +#define WIFSTOPPED(x) (((x) & 0xff) == 0x7f) +#define WIFCONTINUED(x) ((x) == 0xffff) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +/* glibc extension, but also useful for kernels */ +#define W_EXITCODE(ret, sig) (((ret) << 8) | (sig)) + +#endif /*_ABIBITS_WAIT_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/xattr.h new file mode 100755 index 0000000..7ca7ea3 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/abi-bits/xattr.h @@ -0,0 +1,27 @@ +#ifndef MLIBC_ABIS_LINUX_XATTR_H +#define MLIBC_ABIS_LINUX_XATTR_H + +#include + +#if !__MLIBC_LINUX_OPTION +# error " is inherently Linux specific. Enable the Linux option or do not use this header." +#endif /* !__MLIBC_LINUX_OPTION */ + +/* __USE_KERNEL_XATTR_DEFS is exported when XATTR_* are emitted, and + * __UAPI_DEF_XATTR is used to determine the behaviour of the + * header (through ), if it's set + * to 1, the header exports xattr defines and __USE_KERNEL_XATTR_DEFS. + * This applies for pretty much all other defines in libc-compat.h + * AFAICT. + */ +#ifndef __USE_KERNEL_XATTR_DEFS +enum { + XATTR_CREATE = 1, +#define XATTR_CREATE XATTR_CREATE + XATTR_REPLACE = 2 +#define XATTR_REPLACE XATTR_REPLACE +}; +# define __UAPI_DEF_XATTR 0 +#endif + +#endif /* MLIBC_ABIS_LINUX_XATTR_H */ \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/bits/syscall.h b/user/include/mlibc/sysdeps/kirkos/include/bits/syscall.h new file mode 100644 index 0000000..c7dbfb7 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/bits/syscall.h @@ -0,0 +1,100 @@ +#ifndef _MLIBC_SYSCALL_H +#define _MLIBC_SYSCALL_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long __sc_word_t; + +/* These functions are implemented in syscall.cpp. */ +__sc_word_t __do_syscall0(long); +__sc_word_t __do_syscall1(long, __sc_word_t); +__sc_word_t __do_syscall2(long, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall3(long, __sc_word_t, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall4(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall5(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t); +__sc_word_t __do_syscall6(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall7(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t, __sc_word_t, __sc_word_t); +long __do_syscall_ret(unsigned long); + +#ifdef __cplusplus +extern "C++" { + +/* Defining a syscall as a macro is more problematic in C++, since there's a high chance of + * a name collision e.g foo.syscall() or foo::syscall. + */ +inline long syscall(long n) { + return __do_syscall_ret(__do_syscall0(n)); +} +template +long syscall(long n, Arg0 a0) { + return __do_syscall_ret(__do_syscall1(n, (long)a0)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1) { + return __do_syscall_ret(__do_syscall2(n, (long)a0, (long)a1)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2) { + return __do_syscall_ret(__do_syscall3(n, (long)a0, (long)a1, (long)a2)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3) { + return __do_syscall_ret(__do_syscall4(n, (long)a0, (long)a1, (long)a2, (long)a3)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) { + return __do_syscall_ret(__do_syscall5(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) { + return __do_syscall_ret(__do_syscall6(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4, (long)a5)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) { + return __do_syscall_ret(__do_syscall7(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4, (long)a5, (long)a6)); +} + +} /* extern C++ */ +#else + +/* + * Variadic macros are not supported in C89. + * glibc implements syscall() as a variadic function, which we've ruled out. + * musl uses them without checking the C standard in use. So suppressing + * the check here seems reasonable. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" + +/* These syscall macros were copied from musl. */ +#define __scc(x) ((__sc_word_t)(x)) +#define __syscall0(n) __do_syscall0(n) +#define __syscall1(n,a) __do_syscall1(n,__scc(a)) +#define __syscall2(n,a,b) __do_syscall2(n,__scc(a),__scc(b)) +#define __syscall3(n,a,b,c) __do_syscall3(n,__scc(a),__scc(b),__scc(c)) +#define __syscall4(n,a,b,c,d) __do_syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d)) +#define __syscall5(n,a,b,c,d,e) __do_syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) +#define __syscall6(n,a,b,c,d,e,f) __do_syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#define __syscall7(n,a,b,c,d,e,f,g) __do_syscall7(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f),__scc(g)) +#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n +#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,) +#define __SYSCALL_CONCAT_X(a,b) a##b +#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b) +#define __SYSCALL_DISP(b,...) __SYSCALL_CONCAT(b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) +#define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__) +#define syscall(...) __do_syscall_ret(__syscall(__VA_ARGS__)) + +#pragma GCC diagnostic pop + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _MLIBC_SYSCALL_H */ diff --git a/user/include/mlibc/sysdeps/kirkos/include/bits/syscall_aliases.h b/user/include/mlibc/sysdeps/kirkos/include/bits/syscall_aliases.h new file mode 100644 index 0000000..236a0e2 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/bits/syscall_aliases.h @@ -0,0 +1,1856 @@ +#ifndef __MLIBC_SYSCALL_ALIAS_BIT +#define __MLIBC_SYSCALL_ALIAS_BIT +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#ifdef __NR__llseek +# define SYS__llseek __NR__llseek +#endif +#ifdef __NR__newselect +# define SYS__newselect __NR__newselect +#endif +#ifdef __NR__sysctl +# define SYS__sysctl __NR__sysctl +#endif +#ifdef __NR_accept +# define SYS_accept __NR_accept +#endif +#ifdef __NR_accept4 +# define SYS_accept4 __NR_accept4 +#endif +#ifdef __NR_access +# define SYS_access __NR_access +#endif +#ifdef __NR_acct +# define SYS_acct __NR_acct +#endif +#ifdef __NR_add_key +# define SYS_add_key __NR_add_key +#endif +#ifdef __NR_adjtimex +# define SYS_adjtimex __NR_adjtimex +#endif +#ifdef __NR_alarm +# define SYS_alarm __NR_alarm +#endif +#ifdef __NR_arc_gettls +# define SYS_arc_gettls __NR_arc_gettls +#endif +#ifdef __NR_arc_settls +# define SYS_arc_settls __NR_arc_settls +#endif +#ifdef __NR_arc_usr_cmpxchg +# define SYS_arc_usr_cmpxchg __NR_arc_usr_cmpxchg +#endif +#ifdef __NR_arch_prctl +# define SYS_arch_prctl __NR_arch_prctl +#endif +#ifdef __NR_arm_fadvise64_64 +# define SYS_arm_fadvise64_64 __NR_arm_fadvise64_64 +#endif +#ifdef __NR_atomic_barrier +# define SYS_atomic_barrier __NR_atomic_barrier +#endif +#ifdef __NR_atomic_cmpxchg_32 +# define SYS_atomic_cmpxchg_32 __NR_atomic_cmpxchg_32 +#endif +#ifdef __NR_bdflush +# define SYS_bdflush __NR_bdflush +#endif +#ifdef __NR_bind +# define SYS_bind __NR_bind +#endif +#ifdef __NR_bpf +# define SYS_bpf __NR_bpf +#endif +#ifdef __NR_brk +# define SYS_brk __NR_brk +#endif +#ifdef __NR_cachectl +# define SYS_cachectl __NR_cachectl +#endif +#ifdef __NR_cacheflush +# define SYS_cacheflush __NR_cacheflush +#endif +#ifdef __NR_cachestat +# define SYS_cachestat __NR_cachestat +#endif +#ifdef __NR_capget +# define SYS_capget __NR_capget +#endif +#ifdef __NR_capset +# define SYS_capset __NR_capset +#endif +#ifdef __NR_chdir +# define SYS_chdir __NR_chdir +#endif +#ifdef __NR_chmod +# define SYS_chmod __NR_chmod +#endif +#ifdef __NR_chown +# define SYS_chown __NR_chown +#endif +#ifdef __NR_chown32 +# define SYS_chown32 __NR_chown32 +#endif +#ifdef __NR_chroot +# define SYS_chroot __NR_chroot +#endif +#ifdef __NR_clock_adjtime +# define SYS_clock_adjtime __NR_clock_adjtime +#endif +#ifdef __NR_clock_adjtime64 +# define SYS_clock_adjtime64 __NR_clock_adjtime64 +#endif +#ifdef __NR_clock_getres +# define SYS_clock_getres __NR_clock_getres +#endif +#ifdef __NR_clock_getres_time64 +# define SYS_clock_getres_time64 __NR_clock_getres_time64 +#endif +#ifdef __NR_clock_gettime +# define SYS_clock_gettime __NR_clock_gettime +#endif +#ifdef __NR_clock_gettime64 +# define SYS_clock_gettime64 __NR_clock_gettime64 +#endif +#ifdef __NR_clock_nanosleep +# define SYS_clock_nanosleep __NR_clock_nanosleep +#endif +#ifdef __NR_clock_nanosleep_time64 +# define SYS_clock_nanosleep_time64 __NR_clock_nanosleep_time64 +#endif +#ifdef __NR_clock_settime +# define SYS_clock_settime __NR_clock_settime +#endif +#ifdef __NR_clock_settime64 +# define SYS_clock_settime64 __NR_clock_settime64 +#endif +#ifdef __NR_clone +# define SYS_clone __NR_clone +#endif +#ifdef __NR_clone3 +# define SYS_clone3 __NR_clone3 +#endif +#ifdef __NR_close +# define SYS_close __NR_close +#endif +#ifdef __NR_close_range +# define SYS_close_range __NR_close_range +#endif +#ifdef __NR_connect +# define SYS_connect __NR_connect +#endif +#ifdef __NR_copy_file_range +# define SYS_copy_file_range __NR_copy_file_range +#endif +#ifdef __NR_creat +# define SYS_creat __NR_creat +#endif +#ifdef __NR_create_module +# define SYS_create_module __NR_create_module +#endif +#ifdef __NR_delete_module +# define SYS_delete_module __NR_delete_module +#endif +#ifdef __NR_dipc +# define SYS_dipc __NR_dipc +#endif +#ifdef __NR_dup +# define SYS_dup __NR_dup +#endif +#ifdef __NR_dup2 +# define SYS_dup2 __NR_dup2 +#endif +#ifdef __NR_dup3 +# define SYS_dup3 __NR_dup3 +#endif +#ifdef __NR_epoll_create +# define SYS_epoll_create __NR_epoll_create +#endif +#ifdef __NR_epoll_create1 +# define SYS_epoll_create1 __NR_epoll_create1 +#endif +#ifdef __NR_epoll_ctl +# define SYS_epoll_ctl __NR_epoll_ctl +#endif +#ifdef __NR_epoll_ctl_old +# define SYS_epoll_ctl_old __NR_epoll_ctl_old +#endif +#ifdef __NR_epoll_pwait +# define SYS_epoll_pwait __NR_epoll_pwait +#endif +#ifdef __NR_epoll_pwait2 +# define SYS_epoll_pwait2 __NR_epoll_pwait2 +#endif +#ifdef __NR_epoll_wait +# define SYS_epoll_wait __NR_epoll_wait +#endif +#ifdef __NR_epoll_wait_old +# define SYS_epoll_wait_old __NR_epoll_wait_old +#endif +#ifdef __NR_eventfd +# define SYS_eventfd __NR_eventfd +#endif +#ifdef __NR_eventfd2 +# define SYS_eventfd2 __NR_eventfd2 +#endif +#ifdef __NR_exec_with_loader +# define SYS_exec_with_loader __NR_exec_with_loader +#endif +#ifdef __NR_execv +# define SYS_execv __NR_execv +#endif +#ifdef __NR_execve +# define SYS_execve __NR_execve +#endif +#ifdef __NR_execveat +# define SYS_execveat __NR_execveat +#endif +#ifdef __NR_exit +# define SYS_exit __NR_exit +#endif +#ifdef __NR_exit_group +# define SYS_exit_group __NR_exit_group +#endif +#ifdef __NR_faccessat +# define SYS_faccessat __NR_faccessat +#endif +#ifdef __NR_faccessat2 +# define SYS_faccessat2 __NR_faccessat2 +#endif +#ifdef __NR_fadvise64 +# define SYS_fadvise64 __NR_fadvise64 +#endif +#ifdef __NR_fadvise64_64 +# define SYS_fadvise64_64 __NR_fadvise64_64 +#endif +#ifdef __NR_fallocate +# define SYS_fallocate __NR_fallocate +#endif +#ifdef __NR_fanotify_init +# define SYS_fanotify_init __NR_fanotify_init +#endif +#ifdef __NR_fanotify_mark +# define SYS_fanotify_mark __NR_fanotify_mark +#endif +#ifdef __NR_fchdir +# define SYS_fchdir __NR_fchdir +#endif +#ifdef __NR_fchmod +# define SYS_fchmod __NR_fchmod +#endif +#ifdef __NR_fchmodat +# define SYS_fchmodat __NR_fchmodat +#endif +#ifdef __NR_fchmodat2 +# define SYS_fchmodat2 __NR_fchmodat2 +#endif +#ifdef __NR_fchown +# define SYS_fchown __NR_fchown +#endif +#ifdef __NR_fchown32 +# define SYS_fchown32 __NR_fchown32 +#endif +#ifdef __NR_fchownat +# define SYS_fchownat __NR_fchownat +#endif +#ifdef __NR_fcntl +# define SYS_fcntl __NR_fcntl +#endif +#ifdef __NR_fcntl64 +# define SYS_fcntl64 __NR_fcntl64 +#endif +#ifdef __NR_fdatasync +# define SYS_fdatasync __NR_fdatasync +#endif +#ifdef __NR_fgetxattr +# define SYS_fgetxattr __NR_fgetxattr +#endif +#ifdef __NR_finit_module +# define SYS_finit_module __NR_finit_module +#endif +#ifdef __NR_flistxattr +# define SYS_flistxattr __NR_flistxattr +#endif +#ifdef __NR_flock +# define SYS_flock __NR_flock +#endif +#ifdef __NR_fork +# define SYS_fork __NR_fork +#endif +#ifdef __NR_fremovexattr +# define SYS_fremovexattr __NR_fremovexattr +#endif +#ifdef __NR_fsconfig +# define SYS_fsconfig __NR_fsconfig +#endif +#ifdef __NR_fsetxattr +# define SYS_fsetxattr __NR_fsetxattr +#endif +#ifdef __NR_fsmount +# define SYS_fsmount __NR_fsmount +#endif +#ifdef __NR_fsopen +# define SYS_fsopen __NR_fsopen +#endif +#ifdef __NR_fspick +# define SYS_fspick __NR_fspick +#endif +#ifdef __NR_fstat +# define SYS_fstat __NR_fstat +#endif +#ifdef __NR_fstat64 +# define SYS_fstat64 __NR_fstat64 +#endif +#ifdef __NR_fstatat64 +# define SYS_fstatat64 __NR_fstatat64 +#endif +#ifdef __NR_fstatfs +# define SYS_fstatfs __NR_fstatfs +#endif +#ifdef __NR_fstatfs64 +# define SYS_fstatfs64 __NR_fstatfs64 +#endif +#ifdef __NR_fsync +# define SYS_fsync __NR_fsync +#endif +#ifdef __NR_ftruncate +# define SYS_ftruncate __NR_ftruncate +#endif +#ifdef __NR_ftruncate64 +# define SYS_ftruncate64 __NR_ftruncate64 +#endif +#ifdef __NR_futex +# define SYS_futex __NR_futex +#endif +#ifdef __NR_futex_requeue +# define SYS_futex_requeue __NR_futex_requeue +#endif +#ifdef __NR_futex_time64 +# define SYS_futex_time64 __NR_futex_time64 +#endif +#ifdef __NR_futex_wait +# define SYS_futex_wait __NR_futex_wait +#endif +#ifdef __NR_futex_waitv +# define SYS_futex_waitv __NR_futex_waitv +#endif +#ifdef __NR_futex_wake +# define SYS_futex_wake __NR_futex_wake +#endif +#ifdef __NR_futimesat +# define SYS_futimesat __NR_futimesat +#endif +#ifdef __NR_get_kernel_syms +# define SYS_get_kernel_syms __NR_get_kernel_syms +#endif +#ifdef __NR_get_mempolicy +# define SYS_get_mempolicy __NR_get_mempolicy +#endif +#ifdef __NR_get_robust_list +# define SYS_get_robust_list __NR_get_robust_list +#endif +#ifdef __NR_get_thread_area +# define SYS_get_thread_area __NR_get_thread_area +#endif +#ifdef __NR_getcpu +# define SYS_getcpu __NR_getcpu +#endif +#ifdef __NR_getcwd +# define SYS_getcwd __NR_getcwd +#endif +#ifdef __NR_getdents +# define SYS_getdents __NR_getdents +#endif +#ifdef __NR_getdents64 +# define SYS_getdents64 __NR_getdents64 +#endif +#ifdef __NR_getdomainname +# define SYS_getdomainname __NR_getdomainname +#endif +#ifdef __NR_getdtablesize +# define SYS_getdtablesize __NR_getdtablesize +#endif +#ifdef __NR_getegid +# define SYS_getegid __NR_getegid +#endif +#ifdef __NR_getegid32 +# define SYS_getegid32 __NR_getegid32 +#endif +#ifdef __NR_geteuid +# define SYS_geteuid __NR_geteuid +#endif +#ifdef __NR_geteuid32 +# define SYS_geteuid32 __NR_geteuid32 +#endif +#ifdef __NR_getgid +# define SYS_getgid __NR_getgid +#endif +#ifdef __NR_getgid32 +# define SYS_getgid32 __NR_getgid32 +#endif +#ifdef __NR_getgroups +# define SYS_getgroups __NR_getgroups +#endif +#ifdef __NR_getgroups32 +# define SYS_getgroups32 __NR_getgroups32 +#endif +#ifdef __NR_gethostname +# define SYS_gethostname __NR_gethostname +#endif +#ifdef __NR_getitimer +# define SYS_getitimer __NR_getitimer +#endif +#ifdef __NR_getpagesize +# define SYS_getpagesize __NR_getpagesize +#endif +#ifdef __NR_getpeername +# define SYS_getpeername __NR_getpeername +#endif +#ifdef __NR_getpgid +# define SYS_getpgid __NR_getpgid +#endif +#ifdef __NR_getpgrp +# define SYS_getpgrp __NR_getpgrp +#endif +#ifdef __NR_getpid +# define SYS_getpid __NR_getpid +#endif +#ifdef __NR_getpmsg +# define SYS_getpmsg __NR_getpmsg +#endif +#ifdef __NR_getppid +# define SYS_getppid __NR_getppid +#endif +#ifdef __NR_getpriority +# define SYS_getpriority __NR_getpriority +#endif +#ifdef __NR_getrandom +# define SYS_getrandom __NR_getrandom +#endif +#ifdef __NR_getresgid +# define SYS_getresgid __NR_getresgid +#endif +#ifdef __NR_getresgid32 +# define SYS_getresgid32 __NR_getresgid32 +#endif +#ifdef __NR_getresuid +# define SYS_getresuid __NR_getresuid +#endif +#ifdef __NR_getresuid32 +# define SYS_getresuid32 __NR_getresuid32 +#endif +#ifdef __NR_getrlimit +# define SYS_getrlimit __NR_getrlimit +#endif +#ifdef __NR_getrusage +# define SYS_getrusage __NR_getrusage +#endif +#ifdef __NR_getsid +# define SYS_getsid __NR_getsid +#endif +#ifdef __NR_getsockname +# define SYS_getsockname __NR_getsockname +#endif +#ifdef __NR_getsockopt +# define SYS_getsockopt __NR_getsockopt +#endif +#ifdef __NR_gettid +# define SYS_gettid __NR_gettid +#endif +#ifdef __NR_gettimeofday +# define SYS_gettimeofday __NR_gettimeofday +#endif +#ifdef __NR_getuid +# define SYS_getuid __NR_getuid +#endif +#ifdef __NR_getuid32 +# define SYS_getuid32 __NR_getuid32 +#endif +#ifdef __NR_getxattr +# define SYS_getxattr __NR_getxattr +#endif +#ifdef __NR_getxattrat +# define SYS_getxattrat __NR_getxattrat +#endif +#ifdef __NR_getxgid +# define SYS_getxgid __NR_getxgid +#endif +#ifdef __NR_getxpid +# define SYS_getxpid __NR_getxpid +#endif +#ifdef __NR_getxuid +# define SYS_getxuid __NR_getxuid +#endif +#ifdef __NR_idle +# define SYS_idle __NR_idle +#endif +#ifdef __NR_init_module +# define SYS_init_module __NR_init_module +#endif +#ifdef __NR_inotify_add_watch +# define SYS_inotify_add_watch __NR_inotify_add_watch +#endif +#ifdef __NR_inotify_init +# define SYS_inotify_init __NR_inotify_init +#endif +#ifdef __NR_inotify_init1 +# define SYS_inotify_init1 __NR_inotify_init1 +#endif +#ifdef __NR_inotify_rm_watch +# define SYS_inotify_rm_watch __NR_inotify_rm_watch +#endif +#ifdef __NR_io_cancel +# define SYS_io_cancel __NR_io_cancel +#endif +#ifdef __NR_io_destroy +# define SYS_io_destroy __NR_io_destroy +#endif +#ifdef __NR_io_getevents +# define SYS_io_getevents __NR_io_getevents +#endif +#ifdef __NR_io_pgetevents +# define SYS_io_pgetevents __NR_io_pgetevents +#endif +#ifdef __NR_io_pgetevents_time64 +# define SYS_io_pgetevents_time64 __NR_io_pgetevents_time64 +#endif +#ifdef __NR_io_setup +# define SYS_io_setup __NR_io_setup +#endif +#ifdef __NR_io_submit +# define SYS_io_submit __NR_io_submit +#endif +#ifdef __NR_io_uring_enter +# define SYS_io_uring_enter __NR_io_uring_enter +#endif +#ifdef __NR_io_uring_register +# define SYS_io_uring_register __NR_io_uring_register +#endif +#ifdef __NR_io_uring_setup +# define SYS_io_uring_setup __NR_io_uring_setup +#endif +#ifdef __NR_ioctl +# define SYS_ioctl __NR_ioctl +#endif +#ifdef __NR_ioperm +# define SYS_ioperm __NR_ioperm +#endif +#ifdef __NR_iopl +# define SYS_iopl __NR_iopl +#endif +#ifdef __NR_ioprio_get +# define SYS_ioprio_get __NR_ioprio_get +#endif +#ifdef __NR_ioprio_set +# define SYS_ioprio_set __NR_ioprio_set +#endif +#ifdef __NR_ipc +# define SYS_ipc __NR_ipc +#endif +#ifdef __NR_kcmp +# define SYS_kcmp __NR_kcmp +#endif +#ifdef __NR_kern_features +# define SYS_kern_features __NR_kern_features +#endif +#ifdef __NR_kexec_file_load +# define SYS_kexec_file_load __NR_kexec_file_load +#endif +#ifdef __NR_kexec_load +# define SYS_kexec_load __NR_kexec_load +#endif +#ifdef __NR_keyctl +# define SYS_keyctl __NR_keyctl +#endif +#ifdef __NR_kill +# define SYS_kill __NR_kill +#endif +#ifdef __NR_landlock_add_rule +# define SYS_landlock_add_rule __NR_landlock_add_rule +#endif +#ifdef __NR_landlock_create_ruleset +# define SYS_landlock_create_ruleset __NR_landlock_create_ruleset +#endif +#ifdef __NR_landlock_restrict_self +# define SYS_landlock_restrict_self __NR_landlock_restrict_self +#endif +#ifdef __NR_lchown +# define SYS_lchown __NR_lchown +#endif +#ifdef __NR_lchown32 +# define SYS_lchown32 __NR_lchown32 +#endif +#ifdef __NR_lgetxattr +# define SYS_lgetxattr __NR_lgetxattr +#endif +#ifdef __NR_link +# define SYS_link __NR_link +#endif +#ifdef __NR_linkat +# define SYS_linkat __NR_linkat +#endif +#ifdef __NR_listen +# define SYS_listen __NR_listen +#endif +#ifdef __NR_listmount +# define SYS_listmount __NR_listmount +#endif +#ifdef __NR_listxattr +# define SYS_listxattr __NR_listxattr +#endif +#ifdef __NR_listxattrat +# define SYS_listxattrat __NR_listxattrat +#endif +#ifdef __NR_llistxattr +# define SYS_llistxattr __NR_llistxattr +#endif +#ifdef __NR_llseek +# define SYS_llseek __NR_llseek +#endif +#ifdef __NR_lookup_dcookie +# define SYS_lookup_dcookie __NR_lookup_dcookie +#endif +#ifdef __NR_lremovexattr +# define SYS_lremovexattr __NR_lremovexattr +#endif +#ifdef __NR_lseek +# define SYS_lseek __NR_lseek +#endif +#ifdef __NR_lsetxattr +# define SYS_lsetxattr __NR_lsetxattr +#endif +#ifdef __NR_lsm_get_self_attr +# define SYS_lsm_get_self_attr __NR_lsm_get_self_attr +#endif +#ifdef __NR_lsm_list_modules +# define SYS_lsm_list_modules __NR_lsm_list_modules +#endif +#ifdef __NR_lsm_set_self_attr +# define SYS_lsm_set_self_attr __NR_lsm_set_self_attr +#endif +#ifdef __NR_lstat +# define SYS_lstat __NR_lstat +#endif +#ifdef __NR_lstat64 +# define SYS_lstat64 __NR_lstat64 +#endif +#ifdef __NR_madvise +# define SYS_madvise __NR_madvise +#endif +#ifdef __NR_map_shadow_stack +# define SYS_map_shadow_stack __NR_map_shadow_stack +#endif +#ifdef __NR_mbind +# define SYS_mbind __NR_mbind +#endif +#ifdef __NR_membarrier +# define SYS_membarrier __NR_membarrier +#endif +#ifdef __NR_memfd_create +# define SYS_memfd_create __NR_memfd_create +#endif +#ifdef __NR_memfd_secret +# define SYS_memfd_secret __NR_memfd_secret +#endif +#ifdef __NR_memory_ordering +# define SYS_memory_ordering __NR_memory_ordering +#endif +#ifdef __NR_migrate_pages +# define SYS_migrate_pages __NR_migrate_pages +#endif +#ifdef __NR_mincore +# define SYS_mincore __NR_mincore +#endif +#ifdef __NR_mkdir +# define SYS_mkdir __NR_mkdir +#endif +#ifdef __NR_mkdirat +# define SYS_mkdirat __NR_mkdirat +#endif +#ifdef __NR_mknod +# define SYS_mknod __NR_mknod +#endif +#ifdef __NR_mknodat +# define SYS_mknodat __NR_mknodat +#endif +#ifdef __NR_mlock +# define SYS_mlock __NR_mlock +#endif +#ifdef __NR_mlock2 +# define SYS_mlock2 __NR_mlock2 +#endif +#ifdef __NR_mlockall +# define SYS_mlockall __NR_mlockall +#endif +#ifdef __NR_mmap +# define SYS_mmap __NR_mmap +#endif +#ifdef __NR_mmap2 +# define SYS_mmap2 __NR_mmap2 +#endif +#ifdef __NR_modify_ldt +# define SYS_modify_ldt __NR_modify_ldt +#endif +#ifdef __NR_mount +# define SYS_mount __NR_mount +#endif +#ifdef __NR_mount_setattr +# define SYS_mount_setattr __NR_mount_setattr +#endif +#ifdef __NR_move_mount +# define SYS_move_mount __NR_move_mount +#endif +#ifdef __NR_move_pages +# define SYS_move_pages __NR_move_pages +#endif +#ifdef __NR_mprotect +# define SYS_mprotect __NR_mprotect +#endif +#ifdef __NR_mq_getsetattr +# define SYS_mq_getsetattr __NR_mq_getsetattr +#endif +#ifdef __NR_mq_notify +# define SYS_mq_notify __NR_mq_notify +#endif +#ifdef __NR_mq_open +# define SYS_mq_open __NR_mq_open +#endif +#ifdef __NR_mq_timedreceive +# define SYS_mq_timedreceive __NR_mq_timedreceive +#endif +#ifdef __NR_mq_timedreceive_time64 +# define SYS_mq_timedreceive_time64 __NR_mq_timedreceive_time64 +#endif +#ifdef __NR_mq_timedsend +# define SYS_mq_timedsend __NR_mq_timedsend +#endif +#ifdef __NR_mq_timedsend_time64 +# define SYS_mq_timedsend_time64 __NR_mq_timedsend_time64 +#endif +#ifdef __NR_mq_unlink +# define SYS_mq_unlink __NR_mq_unlink +#endif +#ifdef __NR_mremap +# define SYS_mremap __NR_mremap +#endif +#ifdef __NR_mseal +# define SYS_mseal __NR_mseal +#endif +#ifdef __NR_msgctl +# define SYS_msgctl __NR_msgctl +#endif +#ifdef __NR_msgget +# define SYS_msgget __NR_msgget +#endif +#ifdef __NR_msgrcv +# define SYS_msgrcv __NR_msgrcv +#endif +#ifdef __NR_msgsnd +# define SYS_msgsnd __NR_msgsnd +#endif +#ifdef __NR_msync +# define SYS_msync __NR_msync +#endif +#ifdef __NR_multiplexer +# define SYS_multiplexer __NR_multiplexer +#endif +#ifdef __NR_munlock +# define SYS_munlock __NR_munlock +#endif +#ifdef __NR_munlockall +# define SYS_munlockall __NR_munlockall +#endif +#ifdef __NR_munmap +# define SYS_munmap __NR_munmap +#endif +#ifdef __NR_name_to_handle_at +# define SYS_name_to_handle_at __NR_name_to_handle_at +#endif +#ifdef __NR_nanosleep +# define SYS_nanosleep __NR_nanosleep +#endif +#ifdef __NR_newfstatat +# define SYS_newfstatat __NR_newfstatat +#endif +#ifdef __NR_nfsservctl +# define SYS_nfsservctl __NR_nfsservctl +#endif +#ifdef __NR_nice +# define SYS_nice __NR_nice +#endif +#ifdef __NR_old_adjtimex +# define SYS_old_adjtimex __NR_old_adjtimex +#endif +#ifdef __NR_oldfstat +# define SYS_oldfstat __NR_oldfstat +#endif +#ifdef __NR_oldlstat +# define SYS_oldlstat __NR_oldlstat +#endif +#ifdef __NR_oldolduname +# define SYS_oldolduname __NR_oldolduname +#endif +#ifdef __NR_oldstat +# define SYS_oldstat __NR_oldstat +#endif +#ifdef __NR_oldumount +# define SYS_oldumount __NR_oldumount +#endif +#ifdef __NR_olduname +# define SYS_olduname __NR_olduname +#endif +#ifdef __NR_open +# define SYS_open __NR_open +#endif +#ifdef __NR_open_by_handle_at +# define SYS_open_by_handle_at __NR_open_by_handle_at +#endif +#ifdef __NR_open_tree +# define SYS_open_tree __NR_open_tree +#endif +#ifdef __NR_openat +# define SYS_openat __NR_openat +#endif +#ifdef __NR_openat2 +# define SYS_openat2 __NR_openat2 +#endif +#ifdef __NR_or1k_atomic +# define SYS_or1k_atomic __NR_or1k_atomic +#endif +#ifdef __NR_osf_adjtime +# define SYS_osf_adjtime __NR_osf_adjtime +#endif +#ifdef __NR_osf_afs_syscall +# define SYS_osf_afs_syscall __NR_osf_afs_syscall +#endif +#ifdef __NR_osf_alt_plock +# define SYS_osf_alt_plock __NR_osf_alt_plock +#endif +#ifdef __NR_osf_alt_setsid +# define SYS_osf_alt_setsid __NR_osf_alt_setsid +#endif +#ifdef __NR_osf_alt_sigpending +# define SYS_osf_alt_sigpending __NR_osf_alt_sigpending +#endif +#ifdef __NR_osf_asynch_daemon +# define SYS_osf_asynch_daemon __NR_osf_asynch_daemon +#endif +#ifdef __NR_osf_audcntl +# define SYS_osf_audcntl __NR_osf_audcntl +#endif +#ifdef __NR_osf_audgen +# define SYS_osf_audgen __NR_osf_audgen +#endif +#ifdef __NR_osf_chflags +# define SYS_osf_chflags __NR_osf_chflags +#endif +#ifdef __NR_osf_execve +# define SYS_osf_execve __NR_osf_execve +#endif +#ifdef __NR_osf_exportfs +# define SYS_osf_exportfs __NR_osf_exportfs +#endif +#ifdef __NR_osf_fchflags +# define SYS_osf_fchflags __NR_osf_fchflags +#endif +#ifdef __NR_osf_fdatasync +# define SYS_osf_fdatasync __NR_osf_fdatasync +#endif +#ifdef __NR_osf_fpathconf +# define SYS_osf_fpathconf __NR_osf_fpathconf +#endif +#ifdef __NR_osf_fstat +# define SYS_osf_fstat __NR_osf_fstat +#endif +#ifdef __NR_osf_fstatfs +# define SYS_osf_fstatfs __NR_osf_fstatfs +#endif +#ifdef __NR_osf_fstatfs64 +# define SYS_osf_fstatfs64 __NR_osf_fstatfs64 +#endif +#ifdef __NR_osf_fuser +# define SYS_osf_fuser __NR_osf_fuser +#endif +#ifdef __NR_osf_getaddressconf +# define SYS_osf_getaddressconf __NR_osf_getaddressconf +#endif +#ifdef __NR_osf_getdirentries +# define SYS_osf_getdirentries __NR_osf_getdirentries +#endif +#ifdef __NR_osf_getdomainname +# define SYS_osf_getdomainname __NR_osf_getdomainname +#endif +#ifdef __NR_osf_getfh +# define SYS_osf_getfh __NR_osf_getfh +#endif +#ifdef __NR_osf_getfsstat +# define SYS_osf_getfsstat __NR_osf_getfsstat +#endif +#ifdef __NR_osf_gethostid +# define SYS_osf_gethostid __NR_osf_gethostid +#endif +#ifdef __NR_osf_getitimer +# define SYS_osf_getitimer __NR_osf_getitimer +#endif +#ifdef __NR_osf_getlogin +# define SYS_osf_getlogin __NR_osf_getlogin +#endif +#ifdef __NR_osf_getmnt +# define SYS_osf_getmnt __NR_osf_getmnt +#endif +#ifdef __NR_osf_getrusage +# define SYS_osf_getrusage __NR_osf_getrusage +#endif +#ifdef __NR_osf_getsysinfo +# define SYS_osf_getsysinfo __NR_osf_getsysinfo +#endif +#ifdef __NR_osf_gettimeofday +# define SYS_osf_gettimeofday __NR_osf_gettimeofday +#endif +#ifdef __NR_osf_kloadcall +# define SYS_osf_kloadcall __NR_osf_kloadcall +#endif +#ifdef __NR_osf_kmodcall +# define SYS_osf_kmodcall __NR_osf_kmodcall +#endif +#ifdef __NR_osf_lstat +# define SYS_osf_lstat __NR_osf_lstat +#endif +#ifdef __NR_osf_memcntl +# define SYS_osf_memcntl __NR_osf_memcntl +#endif +#ifdef __NR_osf_mincore +# define SYS_osf_mincore __NR_osf_mincore +#endif +#ifdef __NR_osf_mount +# define SYS_osf_mount __NR_osf_mount +#endif +#ifdef __NR_osf_mremap +# define SYS_osf_mremap __NR_osf_mremap +#endif +#ifdef __NR_osf_msfs_syscall +# define SYS_osf_msfs_syscall __NR_osf_msfs_syscall +#endif +#ifdef __NR_osf_msleep +# define SYS_osf_msleep __NR_osf_msleep +#endif +#ifdef __NR_osf_mvalid +# define SYS_osf_mvalid __NR_osf_mvalid +#endif +#ifdef __NR_osf_mwakeup +# define SYS_osf_mwakeup __NR_osf_mwakeup +#endif +#ifdef __NR_osf_naccept +# define SYS_osf_naccept __NR_osf_naccept +#endif +#ifdef __NR_osf_nfssvc +# define SYS_osf_nfssvc __NR_osf_nfssvc +#endif +#ifdef __NR_osf_ngetpeername +# define SYS_osf_ngetpeername __NR_osf_ngetpeername +#endif +#ifdef __NR_osf_ngetsockname +# define SYS_osf_ngetsockname __NR_osf_ngetsockname +#endif +#ifdef __NR_osf_nrecvfrom +# define SYS_osf_nrecvfrom __NR_osf_nrecvfrom +#endif +#ifdef __NR_osf_nrecvmsg +# define SYS_osf_nrecvmsg __NR_osf_nrecvmsg +#endif +#ifdef __NR_osf_nsendmsg +# define SYS_osf_nsendmsg __NR_osf_nsendmsg +#endif +#ifdef __NR_osf_ntp_adjtime +# define SYS_osf_ntp_adjtime __NR_osf_ntp_adjtime +#endif +#ifdef __NR_osf_ntp_gettime +# define SYS_osf_ntp_gettime __NR_osf_ntp_gettime +#endif +#ifdef __NR_osf_old_creat +# define SYS_osf_old_creat __NR_osf_old_creat +#endif +#ifdef __NR_osf_old_fstat +# define SYS_osf_old_fstat __NR_osf_old_fstat +#endif +#ifdef __NR_osf_old_getpgrp +# define SYS_osf_old_getpgrp __NR_osf_old_getpgrp +#endif +#ifdef __NR_osf_old_killpg +# define SYS_osf_old_killpg __NR_osf_old_killpg +#endif +#ifdef __NR_osf_old_lstat +# define SYS_osf_old_lstat __NR_osf_old_lstat +#endif +#ifdef __NR_osf_old_open +# define SYS_osf_old_open __NR_osf_old_open +#endif +#ifdef __NR_osf_old_sigaction +# define SYS_osf_old_sigaction __NR_osf_old_sigaction +#endif +#ifdef __NR_osf_old_sigblock +# define SYS_osf_old_sigblock __NR_osf_old_sigblock +#endif +#ifdef __NR_osf_old_sigreturn +# define SYS_osf_old_sigreturn __NR_osf_old_sigreturn +#endif +#ifdef __NR_osf_old_sigsetmask +# define SYS_osf_old_sigsetmask __NR_osf_old_sigsetmask +#endif +#ifdef __NR_osf_old_sigvec +# define SYS_osf_old_sigvec __NR_osf_old_sigvec +#endif +#ifdef __NR_osf_old_stat +# define SYS_osf_old_stat __NR_osf_old_stat +#endif +#ifdef __NR_osf_old_vadvise +# define SYS_osf_old_vadvise __NR_osf_old_vadvise +#endif +#ifdef __NR_osf_old_vtrace +# define SYS_osf_old_vtrace __NR_osf_old_vtrace +#endif +#ifdef __NR_osf_old_wait +# define SYS_osf_old_wait __NR_osf_old_wait +#endif +#ifdef __NR_osf_oldquota +# define SYS_osf_oldquota __NR_osf_oldquota +#endif +#ifdef __NR_osf_pathconf +# define SYS_osf_pathconf __NR_osf_pathconf +#endif +#ifdef __NR_osf_pid_block +# define SYS_osf_pid_block __NR_osf_pid_block +#endif +#ifdef __NR_osf_pid_unblock +# define SYS_osf_pid_unblock __NR_osf_pid_unblock +#endif +#ifdef __NR_osf_plock +# define SYS_osf_plock __NR_osf_plock +#endif +#ifdef __NR_osf_priocntlset +# define SYS_osf_priocntlset __NR_osf_priocntlset +#endif +#ifdef __NR_osf_profil +# define SYS_osf_profil __NR_osf_profil +#endif +#ifdef __NR_osf_proplist_syscall +# define SYS_osf_proplist_syscall __NR_osf_proplist_syscall +#endif +#ifdef __NR_osf_reboot +# define SYS_osf_reboot __NR_osf_reboot +#endif +#ifdef __NR_osf_revoke +# define SYS_osf_revoke __NR_osf_revoke +#endif +#ifdef __NR_osf_sbrk +# define SYS_osf_sbrk __NR_osf_sbrk +#endif +#ifdef __NR_osf_security +# define SYS_osf_security __NR_osf_security +#endif +#ifdef __NR_osf_select +# define SYS_osf_select __NR_osf_select +#endif +#ifdef __NR_osf_set_program_attributes +# define SYS_osf_set_program_attributes __NR_osf_set_program_attributes +#endif +#ifdef __NR_osf_set_speculative +# define SYS_osf_set_speculative __NR_osf_set_speculative +#endif +#ifdef __NR_osf_sethostid +# define SYS_osf_sethostid __NR_osf_sethostid +#endif +#ifdef __NR_osf_setitimer +# define SYS_osf_setitimer __NR_osf_setitimer +#endif +#ifdef __NR_osf_setlogin +# define SYS_osf_setlogin __NR_osf_setlogin +#endif +#ifdef __NR_osf_setsysinfo +# define SYS_osf_setsysinfo __NR_osf_setsysinfo +#endif +#ifdef __NR_osf_settimeofday +# define SYS_osf_settimeofday __NR_osf_settimeofday +#endif +#ifdef __NR_osf_shmat +# define SYS_osf_shmat __NR_osf_shmat +#endif +#ifdef __NR_osf_signal +# define SYS_osf_signal __NR_osf_signal +#endif +#ifdef __NR_osf_sigprocmask +# define SYS_osf_sigprocmask __NR_osf_sigprocmask +#endif +#ifdef __NR_osf_sigsendset +# define SYS_osf_sigsendset __NR_osf_sigsendset +#endif +#ifdef __NR_osf_sigstack +# define SYS_osf_sigstack __NR_osf_sigstack +#endif +#ifdef __NR_osf_sigwaitprim +# define SYS_osf_sigwaitprim __NR_osf_sigwaitprim +#endif +#ifdef __NR_osf_sstk +# define SYS_osf_sstk __NR_osf_sstk +#endif +#ifdef __NR_osf_stat +# define SYS_osf_stat __NR_osf_stat +#endif +#ifdef __NR_osf_statfs +# define SYS_osf_statfs __NR_osf_statfs +#endif +#ifdef __NR_osf_statfs64 +# define SYS_osf_statfs64 __NR_osf_statfs64 +#endif +#ifdef __NR_osf_subsys_info +# define SYS_osf_subsys_info __NR_osf_subsys_info +#endif +#ifdef __NR_osf_swapctl +# define SYS_osf_swapctl __NR_osf_swapctl +#endif +#ifdef __NR_osf_swapon +# define SYS_osf_swapon __NR_osf_swapon +#endif +#ifdef __NR_osf_syscall +# define SYS_osf_syscall __NR_osf_syscall +#endif +#ifdef __NR_osf_sysinfo +# define SYS_osf_sysinfo __NR_osf_sysinfo +#endif +#ifdef __NR_osf_table +# define SYS_osf_table __NR_osf_table +#endif +#ifdef __NR_osf_uadmin +# define SYS_osf_uadmin __NR_osf_uadmin +#endif +#ifdef __NR_osf_usleep_thread +# define SYS_osf_usleep_thread __NR_osf_usleep_thread +#endif +#ifdef __NR_osf_uswitch +# define SYS_osf_uswitch __NR_osf_uswitch +#endif +#ifdef __NR_osf_utc_adjtime +# define SYS_osf_utc_adjtime __NR_osf_utc_adjtime +#endif +#ifdef __NR_osf_utc_gettime +# define SYS_osf_utc_gettime __NR_osf_utc_gettime +#endif +#ifdef __NR_osf_utimes +# define SYS_osf_utimes __NR_osf_utimes +#endif +#ifdef __NR_osf_utsname +# define SYS_osf_utsname __NR_osf_utsname +#endif +#ifdef __NR_osf_wait4 +# define SYS_osf_wait4 __NR_osf_wait4 +#endif +#ifdef __NR_osf_waitid +# define SYS_osf_waitid __NR_osf_waitid +#endif +#ifdef __NR_pause +# define SYS_pause __NR_pause +#endif +#ifdef __NR_pciconfig_iobase +# define SYS_pciconfig_iobase __NR_pciconfig_iobase +#endif +#ifdef __NR_pciconfig_read +# define SYS_pciconfig_read __NR_pciconfig_read +#endif +#ifdef __NR_pciconfig_write +# define SYS_pciconfig_write __NR_pciconfig_write +#endif +#ifdef __NR_perf_event_open +# define SYS_perf_event_open __NR_perf_event_open +#endif +#ifdef __NR_perfctr +# define SYS_perfctr __NR_perfctr +#endif +#ifdef __NR_personality +# define SYS_personality __NR_personality +#endif +#ifdef __NR_pidfd_getfd +# define SYS_pidfd_getfd __NR_pidfd_getfd +#endif +#ifdef __NR_pidfd_open +# define SYS_pidfd_open __NR_pidfd_open +#endif +#ifdef __NR_pidfd_send_signal +# define SYS_pidfd_send_signal __NR_pidfd_send_signal +#endif +#ifdef __NR_pipe +# define SYS_pipe __NR_pipe +#endif +#ifdef __NR_pipe2 +# define SYS_pipe2 __NR_pipe2 +#endif +#ifdef __NR_pivot_root +# define SYS_pivot_root __NR_pivot_root +#endif +#ifdef __NR_pkey_alloc +# define SYS_pkey_alloc __NR_pkey_alloc +#endif +#ifdef __NR_pkey_free +# define SYS_pkey_free __NR_pkey_free +#endif +#ifdef __NR_pkey_mprotect +# define SYS_pkey_mprotect __NR_pkey_mprotect +#endif +#ifdef __NR_poll +# define SYS_poll __NR_poll +#endif +#ifdef __NR_ppoll +# define SYS_ppoll __NR_ppoll +#endif +#ifdef __NR_ppoll_time64 +# define SYS_ppoll_time64 __NR_ppoll_time64 +#endif +#ifdef __NR_prctl +# define SYS_prctl __NR_prctl +#endif +#ifdef __NR_pread64 +# define SYS_pread64 __NR_pread64 +#endif +#ifdef __NR_preadv +# define SYS_preadv __NR_preadv +#endif +#ifdef __NR_preadv2 +# define SYS_preadv2 __NR_preadv2 +#endif +#ifdef __NR_prlimit64 +# define SYS_prlimit64 __NR_prlimit64 +#endif +#ifdef __NR_process_madvise +# define SYS_process_madvise __NR_process_madvise +#endif +#ifdef __NR_process_mrelease +# define SYS_process_mrelease __NR_process_mrelease +#endif +#ifdef __NR_process_vm_readv +# define SYS_process_vm_readv __NR_process_vm_readv +#endif +#ifdef __NR_process_vm_writev +# define SYS_process_vm_writev __NR_process_vm_writev +#endif +#ifdef __NR_pselect6 +# define SYS_pselect6 __NR_pselect6 +#endif +#ifdef __NR_pselect6_time64 +# define SYS_pselect6_time64 __NR_pselect6_time64 +#endif +#ifdef __NR_ptrace +# define SYS_ptrace __NR_ptrace +#endif +#ifdef __NR_pwrite64 +# define SYS_pwrite64 __NR_pwrite64 +#endif +#ifdef __NR_pwritev +# define SYS_pwritev __NR_pwritev +#endif +#ifdef __NR_pwritev2 +# define SYS_pwritev2 __NR_pwritev2 +#endif +#ifdef __NR_query_module +# define SYS_query_module __NR_query_module +#endif +#ifdef __NR_quotactl +# define SYS_quotactl __NR_quotactl +#endif +#ifdef __NR_quotactl_fd +# define SYS_quotactl_fd __NR_quotactl_fd +#endif +#ifdef __NR_read +# define SYS_read __NR_read +#endif +#ifdef __NR_readahead +# define SYS_readahead __NR_readahead +#endif +#ifdef __NR_readdir +# define SYS_readdir __NR_readdir +#endif +#ifdef __NR_readlink +# define SYS_readlink __NR_readlink +#endif +#ifdef __NR_readlinkat +# define SYS_readlinkat __NR_readlinkat +#endif +#ifdef __NR_readv +# define SYS_readv __NR_readv +#endif +#ifdef __NR_reboot +# define SYS_reboot __NR_reboot +#endif +#ifdef __NR_recv +# define SYS_recv __NR_recv +#endif +#ifdef __NR_recvfrom +# define SYS_recvfrom __NR_recvfrom +#endif +#ifdef __NR_recvmmsg +# define SYS_recvmmsg __NR_recvmmsg +#endif +#ifdef __NR_recvmmsg_time64 +# define SYS_recvmmsg_time64 __NR_recvmmsg_time64 +#endif +#ifdef __NR_recvmsg +# define SYS_recvmsg __NR_recvmsg +#endif +#ifdef __NR_remap_file_pages +# define SYS_remap_file_pages __NR_remap_file_pages +#endif +#ifdef __NR_removexattr +# define SYS_removexattr __NR_removexattr +#endif +#ifdef __NR_removexattrat +# define SYS_removexattrat __NR_removexattrat +#endif +#ifdef __NR_rename +# define SYS_rename __NR_rename +#endif +#ifdef __NR_renameat +# define SYS_renameat __NR_renameat +#endif +#ifdef __NR_renameat2 +# define SYS_renameat2 __NR_renameat2 +#endif +#ifdef __NR_request_key +# define SYS_request_key __NR_request_key +#endif +#ifdef __NR_restart_syscall +# define SYS_restart_syscall __NR_restart_syscall +#endif +#ifdef __NR_riscv_flush_icache +# define SYS_riscv_flush_icache __NR_riscv_flush_icache +#endif +#ifdef __NR_riscv_hwprobe +# define SYS_riscv_hwprobe __NR_riscv_hwprobe +#endif +#ifdef __NR_rmdir +# define SYS_rmdir __NR_rmdir +#endif +#ifdef __NR_rseq +# define SYS_rseq __NR_rseq +#endif +#ifdef __NR_rt_sigaction +# define SYS_rt_sigaction __NR_rt_sigaction +#endif +#ifdef __NR_rt_sigpending +# define SYS_rt_sigpending __NR_rt_sigpending +#endif +#ifdef __NR_rt_sigprocmask +# define SYS_rt_sigprocmask __NR_rt_sigprocmask +#endif +#ifdef __NR_rt_sigqueueinfo +# define SYS_rt_sigqueueinfo __NR_rt_sigqueueinfo +#endif +#ifdef __NR_rt_sigreturn +# define SYS_rt_sigreturn __NR_rt_sigreturn +#endif +#ifdef __NR_rt_sigsuspend +# define SYS_rt_sigsuspend __NR_rt_sigsuspend +#endif +#ifdef __NR_rt_sigtimedwait +# define SYS_rt_sigtimedwait __NR_rt_sigtimedwait +#endif +#ifdef __NR_rt_sigtimedwait_time64 +# define SYS_rt_sigtimedwait_time64 __NR_rt_sigtimedwait_time64 +#endif +#ifdef __NR_rt_tgsigqueueinfo +# define SYS_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo +#endif +#ifdef __NR_rtas +# define SYS_rtas __NR_rtas +#endif +#ifdef __NR_s390_guarded_storage +# define SYS_s390_guarded_storage __NR_s390_guarded_storage +#endif +#ifdef __NR_s390_pci_mmio_read +# define SYS_s390_pci_mmio_read __NR_s390_pci_mmio_read +#endif +#ifdef __NR_s390_pci_mmio_write +# define SYS_s390_pci_mmio_write __NR_s390_pci_mmio_write +#endif +#ifdef __NR_s390_runtime_instr +# define SYS_s390_runtime_instr __NR_s390_runtime_instr +#endif +#ifdef __NR_s390_sthyi +# define SYS_s390_sthyi __NR_s390_sthyi +#endif +#ifdef __NR_sched_get_affinity +# define SYS_sched_get_affinity __NR_sched_get_affinity +#endif +#ifdef __NR_sched_get_priority_max +# define SYS_sched_get_priority_max __NR_sched_get_priority_max +#endif +#ifdef __NR_sched_get_priority_min +# define SYS_sched_get_priority_min __NR_sched_get_priority_min +#endif +#ifdef __NR_sched_getaffinity +# define SYS_sched_getaffinity __NR_sched_getaffinity +#endif +#ifdef __NR_sched_getattr +# define SYS_sched_getattr __NR_sched_getattr +#endif +#ifdef __NR_sched_getparam +# define SYS_sched_getparam __NR_sched_getparam +#endif +#ifdef __NR_sched_getscheduler +# define SYS_sched_getscheduler __NR_sched_getscheduler +#endif +#ifdef __NR_sched_rr_get_interval +# define SYS_sched_rr_get_interval __NR_sched_rr_get_interval +#endif +#ifdef __NR_sched_rr_get_interval_time64 +# define SYS_sched_rr_get_interval_time64 __NR_sched_rr_get_interval_time64 +#endif +#ifdef __NR_sched_set_affinity +# define SYS_sched_set_affinity __NR_sched_set_affinity +#endif +#ifdef __NR_sched_setaffinity +# define SYS_sched_setaffinity __NR_sched_setaffinity +#endif +#ifdef __NR_sched_setattr +# define SYS_sched_setattr __NR_sched_setattr +#endif +#ifdef __NR_sched_setparam +# define SYS_sched_setparam __NR_sched_setparam +#endif +#ifdef __NR_sched_setscheduler +# define SYS_sched_setscheduler __NR_sched_setscheduler +#endif +#ifdef __NR_sched_yield +# define SYS_sched_yield __NR_sched_yield +#endif +#ifdef __NR_seccomp +# define SYS_seccomp __NR_seccomp +#endif +#ifdef __NR_select +# define SYS_select __NR_select +#endif +#ifdef __NR_semctl +# define SYS_semctl __NR_semctl +#endif +#ifdef __NR_semget +# define SYS_semget __NR_semget +#endif +#ifdef __NR_semop +# define SYS_semop __NR_semop +#endif +#ifdef __NR_semtimedop +# define SYS_semtimedop __NR_semtimedop +#endif +#ifdef __NR_semtimedop_time64 +# define SYS_semtimedop_time64 __NR_semtimedop_time64 +#endif +#ifdef __NR_send +# define SYS_send __NR_send +#endif +#ifdef __NR_sendfile +# define SYS_sendfile __NR_sendfile +#endif +#ifdef __NR_sendfile64 +# define SYS_sendfile64 __NR_sendfile64 +#endif +#ifdef __NR_sendmmsg +# define SYS_sendmmsg __NR_sendmmsg +#endif +#ifdef __NR_sendmsg +# define SYS_sendmsg __NR_sendmsg +#endif +#ifdef __NR_sendto +# define SYS_sendto __NR_sendto +#endif +#ifdef __NR_set_mempolicy +# define SYS_set_mempolicy __NR_set_mempolicy +#endif +#ifdef __NR_set_mempolicy_home_node +# define SYS_set_mempolicy_home_node __NR_set_mempolicy_home_node +#endif +#ifdef __NR_set_robust_list +# define SYS_set_robust_list __NR_set_robust_list +#endif +#ifdef __NR_set_thread_area +# define SYS_set_thread_area __NR_set_thread_area +#endif +#ifdef __NR_set_tid_address +# define SYS_set_tid_address __NR_set_tid_address +#endif +#ifdef __NR_setdomainname +# define SYS_setdomainname __NR_setdomainname +#endif +#ifdef __NR_setfsgid +# define SYS_setfsgid __NR_setfsgid +#endif +#ifdef __NR_setfsgid32 +# define SYS_setfsgid32 __NR_setfsgid32 +#endif +#ifdef __NR_setfsuid +# define SYS_setfsuid __NR_setfsuid +#endif +#ifdef __NR_setfsuid32 +# define SYS_setfsuid32 __NR_setfsuid32 +#endif +#ifdef __NR_setgid +# define SYS_setgid __NR_setgid +#endif +#ifdef __NR_setgid32 +# define SYS_setgid32 __NR_setgid32 +#endif +#ifdef __NR_setgroups +# define SYS_setgroups __NR_setgroups +#endif +#ifdef __NR_setgroups32 +# define SYS_setgroups32 __NR_setgroups32 +#endif +#ifdef __NR_sethae +# define SYS_sethae __NR_sethae +#endif +#ifdef __NR_sethostname +# define SYS_sethostname __NR_sethostname +#endif +#ifdef __NR_setitimer +# define SYS_setitimer __NR_setitimer +#endif +#ifdef __NR_setns +# define SYS_setns __NR_setns +#endif +#ifdef __NR_setpgid +# define SYS_setpgid __NR_setpgid +#endif +#ifdef __NR_setpgrp +# define SYS_setpgrp __NR_setpgrp +#endif +#ifdef __NR_setpriority +# define SYS_setpriority __NR_setpriority +#endif +#ifdef __NR_setregid +# define SYS_setregid __NR_setregid +#endif +#ifdef __NR_setregid32 +# define SYS_setregid32 __NR_setregid32 +#endif +#ifdef __NR_setresgid +# define SYS_setresgid __NR_setresgid +#endif +#ifdef __NR_setresgid32 +# define SYS_setresgid32 __NR_setresgid32 +#endif +#ifdef __NR_setresuid +# define SYS_setresuid __NR_setresuid +#endif +#ifdef __NR_setresuid32 +# define SYS_setresuid32 __NR_setresuid32 +#endif +#ifdef __NR_setreuid +# define SYS_setreuid __NR_setreuid +#endif +#ifdef __NR_setreuid32 +# define SYS_setreuid32 __NR_setreuid32 +#endif +#ifdef __NR_setrlimit +# define SYS_setrlimit __NR_setrlimit +#endif +#ifdef __NR_setsid +# define SYS_setsid __NR_setsid +#endif +#ifdef __NR_setsockopt +# define SYS_setsockopt __NR_setsockopt +#endif +#ifdef __NR_settimeofday +# define SYS_settimeofday __NR_settimeofday +#endif +#ifdef __NR_setuid +# define SYS_setuid __NR_setuid +#endif +#ifdef __NR_setuid32 +# define SYS_setuid32 __NR_setuid32 +#endif +#ifdef __NR_setxattr +# define SYS_setxattr __NR_setxattr +#endif +#ifdef __NR_setxattrat +# define SYS_setxattrat __NR_setxattrat +#endif +#ifdef __NR_sgetmask +# define SYS_sgetmask __NR_sgetmask +#endif +#ifdef __NR_shmat +# define SYS_shmat __NR_shmat +#endif +#ifdef __NR_shmctl +# define SYS_shmctl __NR_shmctl +#endif +#ifdef __NR_shmdt +# define SYS_shmdt __NR_shmdt +#endif +#ifdef __NR_shmget +# define SYS_shmget __NR_shmget +#endif +#ifdef __NR_shutdown +# define SYS_shutdown __NR_shutdown +#endif +#ifdef __NR_sigaction +# define SYS_sigaction __NR_sigaction +#endif +#ifdef __NR_sigaltstack +# define SYS_sigaltstack __NR_sigaltstack +#endif +#ifdef __NR_signal +# define SYS_signal __NR_signal +#endif +#ifdef __NR_signalfd +# define SYS_signalfd __NR_signalfd +#endif +#ifdef __NR_signalfd4 +# define SYS_signalfd4 __NR_signalfd4 +#endif +#ifdef __NR_sigpending +# define SYS_sigpending __NR_sigpending +#endif +#ifdef __NR_sigprocmask +# define SYS_sigprocmask __NR_sigprocmask +#endif +#ifdef __NR_sigreturn +# define SYS_sigreturn __NR_sigreturn +#endif +#ifdef __NR_sigsuspend +# define SYS_sigsuspend __NR_sigsuspend +#endif +#ifdef __NR_socket +# define SYS_socket __NR_socket +#endif +#ifdef __NR_socketcall +# define SYS_socketcall __NR_socketcall +#endif +#ifdef __NR_socketpair +# define SYS_socketpair __NR_socketpair +#endif +#ifdef __NR_spill +# define SYS_spill __NR_spill +#endif +#ifdef __NR_splice +# define SYS_splice __NR_splice +#endif +#ifdef __NR_spu_create +# define SYS_spu_create __NR_spu_create +#endif +#ifdef __NR_spu_run +# define SYS_spu_run __NR_spu_run +#endif +#ifdef __NR_ssetmask +# define SYS_ssetmask __NR_ssetmask +#endif +#ifdef __NR_stat +# define SYS_stat __NR_stat +#endif +#ifdef __NR_stat64 +# define SYS_stat64 __NR_stat64 +#endif +#ifdef __NR_statfs +# define SYS_statfs __NR_statfs +#endif +#ifdef __NR_statfs64 +# define SYS_statfs64 __NR_statfs64 +#endif +#ifdef __NR_statmount +# define SYS_statmount __NR_statmount +#endif +#ifdef __NR_statx +# define SYS_statx __NR_statx +#endif +#ifdef __NR_stime +# define SYS_stime __NR_stime +#endif +#ifdef __NR_subpage_prot +# define SYS_subpage_prot __NR_subpage_prot +#endif +#ifdef __NR_swapcontext +# define SYS_swapcontext __NR_swapcontext +#endif +#ifdef __NR_swapoff +# define SYS_swapoff __NR_swapoff +#endif +#ifdef __NR_swapon +# define SYS_swapon __NR_swapon +#endif +#ifdef __NR_switch_endian +# define SYS_switch_endian __NR_switch_endian +#endif +#ifdef __NR_symlink +# define SYS_symlink __NR_symlink +#endif +#ifdef __NR_symlinkat +# define SYS_symlinkat __NR_symlinkat +#endif +#ifdef __NR_sync +# define SYS_sync __NR_sync +#endif +#ifdef __NR_sync_file_range +# define SYS_sync_file_range __NR_sync_file_range +#endif +#ifdef __NR_sync_file_range2 +# define SYS_sync_file_range2 __NR_sync_file_range2 +#endif +#ifdef __NR_syncfs +# define SYS_syncfs __NR_syncfs +#endif +#ifdef __NR_sys_debug_setcontext +# define SYS_sys_debug_setcontext __NR_sys_debug_setcontext +#endif +#ifdef __NR_syscall +# define SYS_syscall __NR_syscall +#endif +#ifdef __NR_sysfs +# define SYS_sysfs __NR_sysfs +#endif +#ifdef __NR_sysinfo +# define SYS_sysinfo __NR_sysinfo +#endif +#ifdef __NR_syslog +# define SYS_syslog __NR_syslog +#endif +#ifdef __NR_sysmips +# define SYS_sysmips __NR_sysmips +#endif +#ifdef __NR_tee +# define SYS_tee __NR_tee +#endif +#ifdef __NR_tgkill +# define SYS_tgkill __NR_tgkill +#endif +#ifdef __NR_time +# define SYS_time __NR_time +#endif +#ifdef __NR_timer_create +# define SYS_timer_create __NR_timer_create +#endif +#ifdef __NR_timer_delete +# define SYS_timer_delete __NR_timer_delete +#endif +#ifdef __NR_timer_getoverrun +# define SYS_timer_getoverrun __NR_timer_getoverrun +#endif +#ifdef __NR_timer_gettime +# define SYS_timer_gettime __NR_timer_gettime +#endif +#ifdef __NR_timer_gettime64 +# define SYS_timer_gettime64 __NR_timer_gettime64 +#endif +#ifdef __NR_timer_settime +# define SYS_timer_settime __NR_timer_settime +#endif +#ifdef __NR_timer_settime64 +# define SYS_timer_settime64 __NR_timer_settime64 +#endif +#ifdef __NR_timerfd +# define SYS_timerfd __NR_timerfd +#endif +#ifdef __NR_timerfd_create +# define SYS_timerfd_create __NR_timerfd_create +#endif +#ifdef __NR_timerfd_gettime +# define SYS_timerfd_gettime __NR_timerfd_gettime +#endif +#ifdef __NR_timerfd_gettime64 +# define SYS_timerfd_gettime64 __NR_timerfd_gettime64 +#endif +#ifdef __NR_timerfd_settime +# define SYS_timerfd_settime __NR_timerfd_settime +#endif +#ifdef __NR_timerfd_settime64 +# define SYS_timerfd_settime64 __NR_timerfd_settime64 +#endif +#ifdef __NR_times +# define SYS_times __NR_times +#endif +#ifdef __NR_tkill +# define SYS_tkill __NR_tkill +#endif +#ifdef __NR_truncate +# define SYS_truncate __NR_truncate +#endif +#ifdef __NR_truncate64 +# define SYS_truncate64 __NR_truncate64 +#endif +#ifdef __NR_ugetrlimit +# define SYS_ugetrlimit __NR_ugetrlimit +#endif +#ifdef __NR_umask +# define SYS_umask __NR_umask +#endif +#ifdef __NR_umount +# define SYS_umount __NR_umount +#endif +#ifdef __NR_umount2 +# define SYS_umount2 __NR_umount2 +#endif +#ifdef __NR_uname +# define SYS_uname __NR_uname +#endif +#ifdef __NR_unlink +# define SYS_unlink __NR_unlink +#endif +#ifdef __NR_unlinkat +# define SYS_unlinkat __NR_unlinkat +#endif +#ifdef __NR_unshare +# define SYS_unshare __NR_unshare +#endif +#ifdef __NR_uretprobe +# define SYS_uretprobe __NR_uretprobe +#endif +#ifdef __NR_uselib +# define SYS_uselib __NR_uselib +#endif +#ifdef __NR_userfaultfd +# define SYS_userfaultfd __NR_userfaultfd +#endif +#ifdef __NR_ustat +# define SYS_ustat __NR_ustat +#endif +#ifdef __NR_utime +# define SYS_utime __NR_utime +#endif +#ifdef __NR_utimensat +# define SYS_utimensat __NR_utimensat +#endif +#ifdef __NR_utimensat_time64 +# define SYS_utimensat_time64 __NR_utimensat_time64 +#endif +#ifdef __NR_utimes +# define SYS_utimes __NR_utimes +#endif +#ifdef __NR_utrap_install +# define SYS_utrap_install __NR_utrap_install +#endif +#ifdef __NR_vfork +# define SYS_vfork __NR_vfork +#endif +#ifdef __NR_vhangup +# define SYS_vhangup __NR_vhangup +#endif +#ifdef __NR_vm86 +# define SYS_vm86 __NR_vm86 +#endif +#ifdef __NR_vm86old +# define SYS_vm86old __NR_vm86old +#endif +#ifdef __NR_vmsplice +# define SYS_vmsplice __NR_vmsplice +#endif +#ifdef __NR_wait4 +# define SYS_wait4 __NR_wait4 +#endif +#ifdef __NR_waitid +# define SYS_waitid __NR_waitid +#endif +#ifdef __NR_waitpid +# define SYS_waitpid __NR_waitpid +#endif +#ifdef __NR_write +# define SYS_write __NR_write +#endif +#ifdef __NR_writev +# define SYS_writev __NR_writev +#endif +#endif /* __MLIBC_SYSCALL_ALIAS_BIT */ diff --git a/user/include/mlibc/sysdeps/kirkos/include/mlibc/sysdeps.hpp b/user/include/mlibc/sysdeps/kirkos/include/mlibc/sysdeps.hpp new file mode 100644 index 0000000..fe6e50e --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/mlibc/sysdeps.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace mlibc { + +struct KirkSysdepTags + : public LibcLog, + public LibcPanic, + public Isatty, + public Write, + public TcbSet, + public AnonAllocate, + public AnonFree, + public Seek, + public Exit, + public Close, + public FutexWake, + public FutexWait, + public Read, + public Open, + public VmMap, + public VmUnmap, + public ClockGet +{ }; + +template +using Sysdeps = SysdepOf; + +} // namespace mlibc \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/include/mlibc/thread-entry.hpp b/user/include/mlibc/sysdeps/kirkos/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..a20cab5 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/mlibc/thread-entry.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_THREAD_ENTRY + +#include + +extern "C" int __mlibc_spawn_thread(int flags, void *stack, void *pid_out, void *child_tid, void *tcb); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg); + +namespace mlibc { + void *prepare_stack(void *entry, void *user_arg); +} + +#endif // MLIBC_THREAD_ENTRY diff --git a/user/include/mlibc/sysdeps/kirkos/include/sys/syscall.h b/user/include/mlibc/sysdeps/kirkos/include/sys/syscall.h new file mode 100644 index 0000000..aeb8991 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/sys/syscall.h @@ -0,0 +1,14 @@ +#ifndef _SYS_SYSCALL_H +#define _SYS_SYSCALL_H + +/* On GNU/Linux, this header provides includes __NR_-prefixed syscall numbers, + * and their SYS_ aliases. We defer to kernel headers for the numbers + * (linux-headers, or an autogenerated stub while building), and an + * autogenerated file containing SYS_ defines. + */ +/* clang-format off */ +#include +#include +/* clang-format on */ + +#endif /* _SYS_SYSCALL_H */ diff --git a/user/include/mlibc/sysdeps/kirkos/include/syscall.h b/user/include/mlibc/sysdeps/kirkos/include/syscall.h new file mode 100644 index 0000000..89d0c88 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/include/syscall.h @@ -0,0 +1,27 @@ +#pragma once + +#define SYS_READ 0 +#define SYS_WRITE 1 +#define SYS_OPEN 2 +#define SYS_CLOSE 3 +#define SYS_MMAP 9 +#define SYS_MUNMAP 11 +#define SYS_BRK 12 +#define SYS_SIGACTION 13 /* rt_sigaction on Linux */ +#define SYS_SIGPROCMASK 14 /* rt_sigprocmask on Linux */ +#define SYS_SCHED_YIELD 24 +#define SYS_GETPID 39 + +#define SYS_NICE 34 +#define SYS_FORK 57 +#define SYS_EXECVE 59 +#define SYS_EXIT 60 +#define SYS_KILL 62 + +#define SYS_GETPPID 110 +#define SYS_SCHED_GETSCHEDULER 138 +#define SYS_SCHED_SETSCHEDULER 139 +#define SYS_FUTEX 202 +#define SYS_EXIT_GROUP 231 +#define SYS_TCB_SET 300 + diff --git a/user/include/mlibc/sysdeps/kirkos/meson.build b/user/include/mlibc/sysdeps/kirkos/meson.build new file mode 100644 index 0000000..758ef97 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/meson.build @@ -0,0 +1,100 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': false, + 'glibc': true, + 'bsd': true, +} + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/riscv-hwprobe.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sa_family_t.h', + 'include/abi-bits/sockaddr_storage.h', + 'include/abi-bits/sig-limits.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/in.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/fd_set.h', + 'include/abi-bits/sem.h', + 'include/abi-bits/time.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/utmp-defines.h', + 'include/abi-bits/utmpx.h', + subdir: 'abi-bits', + follow_symlinks: true + ) +endif + +if not headers_only + crtstuff = ['crt0'] + if host_machine.cpu_family() in ['x86_64', 'aarch64', 'riscv64'] + crtstuff += [ + 'crt1', + 'crti', + 'crtn' + ] + endif + foreach crtthing : crtstuff + crtf = crtthing + '.S' + crt_src = files(host_machine.cpu_family() / 'crt-src' / crtf) + crt = custom_target( + crtthing, + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: crt_src, + output: crtthing + '.o', + install: true, + install_dir: get_option('libdir') + ) + endforeach + +endif + +rtld_sources += files( + 'sysdeps.cpp', + 'syscall.cpp', + 'dso.c', +) +rtld_include_dirs += include_directories('include') + +libc_sources += files( + 'entry.cpp', + 'sysdeps.cpp', + 'syscall.cpp', + 'dso.c', +) +libc_include_dirs += include_directories('include') diff --git a/user/include/mlibc/sysdeps/kirkos/syscall.cpp b/user/include/mlibc/sysdeps/kirkos/syscall.cpp new file mode 100644 index 0000000..43646a9 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/syscall.cpp @@ -0,0 +1,124 @@ +#include +#include + +extern "C" long __do_syscall_ret(unsigned long ret) { + return ret; +} + +using sc_word_t = long; + +sc_word_t __do_syscall0(long sc) { + register long sc_reg asm("rax") = sc; + register sc_word_t ret asm("rax"); + asm volatile ("syscall" : "=r"(ret) : "r"(sc_reg) : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall1(long sc, sc_word_t arg1) { + register long sc_reg asm("rax") = sc; + register sc_word_t arg1_reg asm("rdi") = arg1; + register sc_word_t ret asm("rax"); + asm volatile ("syscall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall2(long sc, sc_word_t arg1, sc_word_t arg2) { + register long sc_reg asm("rax") = sc; + register sc_word_t arg1_reg asm("rdi") = arg1; + register sc_word_t arg2_reg asm("rsi") = arg2; + register sc_word_t ret asm("rax"); + asm volatile ("syscall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + register long sc_reg asm("rax") = sc; + register sc_word_t arg1_reg asm("rdi") = arg1; + register sc_word_t arg2_reg asm("rsi") = arg2; + register sc_word_t arg3_reg asm("rdx") = arg3; + register sc_word_t ret asm("rax"); + asm volatile ("syscall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + register long sc_reg asm("rax") = sc; + register sc_word_t arg1_reg asm("rdi") = arg1; + register sc_word_t arg2_reg asm("rsi") = arg2; + register sc_word_t arg3_reg asm("rdx") = arg3; + register sc_word_t arg4_reg asm("r10") = arg4; // arg4 must be in r10 on x86_64 + register sc_word_t ret asm("rax"); + asm volatile ("syscall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + register long sc_reg asm("rax") = sc; + register sc_word_t arg1_reg asm("rdi") = arg1; + register sc_word_t arg2_reg asm("rsi") = arg2; + register sc_word_t arg3_reg asm("rdx") = arg3; + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + register sc_word_t ret asm("rax"); + asm volatile ("syscall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + register long sc_reg asm("rax") = sc; + register sc_word_t arg1_reg asm("rdi") = arg1; + register sc_word_t arg2_reg asm("rsi") = arg2; + register sc_word_t arg3_reg asm("rdx") = arg3; + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + register sc_word_t arg6_reg asm("r9") = arg6; + register sc_word_t ret asm("rax"); + asm volatile ("syscall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg), + "r"(arg6_reg) + : "rcx", "r11", "memory"); + return ret; +} + +/* x86_64 only supports 6 arguments in the syscall ABI. The 7th argument is ignored + * (no syscall in Linux or your kernel uses 7 scalar arguments). */ +sc_word_t __do_syscall7(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6, + sc_word_t arg7) { + (void)arg7; + return __do_syscall6(sc, arg1, arg2, arg3, arg4, arg5, arg6); +} \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/sysdeps.cpp b/user/include/mlibc/sysdeps/kirkos/sysdeps.cpp new file mode 100644 index 0000000..506b3f0 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/sysdeps.cpp @@ -0,0 +1,141 @@ +#include "mlibc/tcb.hpp" +#include +#include +#include +#include +#include + +#include + +#include "syscall.h" +#define SYS_EXIT 60 +#define SYS_READ 0 +#define SYS_WRITE 1 + +#define STUB() \ + ({ \ + __ensure(!"STUB function was called"); \ + __builtin_unreachable(); \ + }) + +namespace mlibc { + +void sys_libc_log(const char *msg) { + ssize_t dummy; + sys_write(1, msg, strlen(msg), &dummy); +} + +void sys_libc_panic() { + sys_libc_log("!!! mlibc panic !!!\n"); + sys_exit(1); + __builtin_trap(); +} + +int sys_isatty(int fd) { + return 0; // everything is a tty for now +} + +int sys_write(int fd, const void *buf, size_t size, ssize_t *ret) { + long r = syscall(SYS_WRITE, fd, (uintptr_t)buf, size); + if (ret) *ret = r; + return r >= 0 ? 0 : -r; +} + +int sys_read(int fd, void *buf, size_t size, ssize_t *ret) { + long r = syscall(SYS_READ, fd, (uintptr_t)buf, size); + if (ret) *ret = r; + return r >= 0 ? 0 : -r; +} + +void sys_exit(int status) { + syscall(SYS_EXIT, status); + __builtin_unreachable(); +} + +int sys_close(int fd) { + long r = syscall(SYS_CLOSE, fd); + return r >= 0 ? 0 : -r; +} + +// ───────────────────────────────────────────────────────────────────────────── +// Memory +// ───────────────────────────────────────────────────────────────────────────── + +int sys_anon_allocate(size_t size, void **pointer) { + long r = syscall(SYS_MMAP, 0, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + *pointer = (void*)r; + return (r == (long)MAP_FAILED) ? ENOMEM : 0; +} + +int sys_anon_free(void *ptr, size_t size) { + if (!ptr || size == 0) return 0; + long r = syscall(SYS_MUNMAP, (uintptr_t)ptr, size); + return r == 0 ? 0 : ENOMEM; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, + int fd, off_t offset, void **out) { + long r = syscall(SYS_MMAP, + (uintptr_t)hint, + size, + prot, + flags, + fd, + offset); + + if (r < 0) + return -r; + + *out = (void *)r; + return 0; +} + +int sys_vm_unmap(void *addr, size_t size) { + long r = syscall(SYS_MUNMAP, (uintptr_t)addr, size); + return (r == 0) ? 0 : -r; +} + +// ───────────────────────────────────────────────────────────────────────────── +// Others +// ───────────────────────────────────────────────────────────────────────────── + +int sys_seek(int, off_t, int, off_t *) { + return ESPIPE; // no real files yet +} + +int sys_tcb_set(void *pointer) { + sys_libc_log("[sysdeps] sys_tcb_set called"); + + long ret = syscall(SYS_TCB_SET, (uintptr_t)pointer); + if (ret < 0) + return -ret; + + sys_libc_log("[sysdeps] TCB set via syscall.\n"); + return 0; +} + +int sys_open(const char *path, int flags, unsigned int mode, int *fd) { + (void)flags; (void)mode; + long r = syscall(SYS_OPEN, (uintptr_t)path); + if (r < 0) return -r; + *fd = (int)r; + return 0; +} + +// Futexes +int sys_futex_wait(int *ptr, int expected, const timespec *time) { + long r = syscall(SYS_FUTEX, ptr, 0, expected, time); + return (r < 0) ? -r : 0; +} + +int sys_futex_wake(int *ptr) { + long r = syscall(SYS_FUTEX, ptr, 1, 1, 0); + return (r < 0) ? -r : 0; +} + +int sys_clock_get(int, time_t *, long *) { return ENOSYS; } + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/Scrt1.S new file mode 100644 index 0000000..71993ae --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/Scrt1.S @@ -0,0 +1,7 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + lea main(%rip), %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crt0.S b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crt0.S new file mode 100644 index 0000000..566fda2 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crt0.S @@ -0,0 +1,9 @@ + +.section .text +.global _start +_start: + mov %rsp, %rdi + mov $main, %rsi + call __mlibc_entry + +.section .note.GNU-stack,"",%progbits \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crt1.S b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crt1.S new file mode 100644 index 0000000..02ffea3 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crt1.S @@ -0,0 +1,7 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + mov $main, %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crti.S b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crti.S new file mode 100644 index 0000000..c4e7c0e --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crti.S @@ -0,0 +1,10 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crtn.S b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..9813a26 --- /dev/null +++ b/user/include/mlibc/sysdeps/kirkos/x86_64/crt-src/crtn.S @@ -0,0 +1,8 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/.clang-format b/user/include/mlibc/sysdeps/lemon/.clang-format new file mode 100644 index 0000000..4662692 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/.clang-format @@ -0,0 +1,2 @@ +--- +DisableFormat: true diff --git a/user/include/mlibc/sysdeps/lemon/crt-x86_64/crt0.S b/user/include/mlibc/sysdeps/lemon/crt-x86_64/crt0.S new file mode 100755 index 0000000..62298e3 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/crt-x86_64/crt0.S @@ -0,0 +1,10 @@ +.section .text + +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + +.size _start, . - _start +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/lemon/generic/entry.cpp b/user/include/mlibc/sysdeps/lemon/generic/entry.cpp new file mode 100644 index 0000000..d49998b --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/generic/entry.cpp @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +extern char **environ; + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux sysdeps) + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} diff --git a/user/include/mlibc/sysdeps/lemon/generic/filesystem.cpp b/user/include/mlibc/sysdeps/lemon/generic/filesystem.cpp new file mode 100755 index 0000000..f000b7e --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/generic/filesystem.cpp @@ -0,0 +1,406 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace mlibc{ + +typedef struct { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + uid_t st_gid; + dev_t st_rdev; + off_t st_size; + int64_t st_blksize; + int64_t st_blocks; +} lemon_stat_t; + +int sys_write(int fd, const void* buffer, size_t count, ssize_t* written){ + long ret = syscall(SYS_WRITE, fd, (uintptr_t)buffer, count); + + if(ret < 0) + return -ret; + + *written = ret; + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + long ret = syscall(SYS_READ, fd, (uintptr_t)buf, count); + + if(ret < 0){ + *bytes_read = 0; + return -ret; + } + + *bytes_read = ret; + return 0; +} + +int sys_pwrite(int fd, const void* buffer, size_t count, off_t off, ssize_t* written){ + int ret = syscall(SYS_PWRITE, fd, (uintptr_t)buffer, count, 0, off); + + + if(ret < 0){ + return -ret; + } + + *written = ret; + return 0; +} + +int sys_pread(int fd, void *buf, size_t count, off_t off, ssize_t *bytes_read) { + int ret = syscall(SYS_PREAD, fd, (uintptr_t)buf, count, 0, off); + + if(ret < 0){ + return -ret; + } + + *bytes_read = ret; + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + long ret = syscall(SYS_LSEEK, fd, offset, whence); + + if(ret < 0){ + return -ret; + } + + *new_offset = ret; + return 0; +} + + +int sys_open(const char* filename, int flags, mode_t mode, int* fd){ + long ret = syscall(SYS_OPEN, (uintptr_t)filename, flags); + + if(ret < 0) + return -ret; + + *fd = ret; + + return 0; +} + +int sys_close(int fd){ + syscall(SYS_CLOSE, fd); + return 0; +} + +int sys_access(const char* filename, int mode){ + int fd; + if(int e = sys_open(filename, O_RDONLY, 0, &fd)){ + return e; + } + + sys_close(fd); + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf){ + long ret = 0; + + lemon_stat_t lemonStat; + switch(fsfdt){ + case fsfd_target::fd: + ret = syscall(SYS_FSTAT, &lemonStat, fd); + break; + case fsfd_target::path: + ret = syscall(SYS_STAT, &lemonStat, path); + break; + default: + mlibc::infoLogger() << "mlibc warning: sys_stat: unsupported fsfd target" << frg::endlog; + return EINVAL; + } + + statbuf->st_dev = lemonStat.st_dev; + statbuf->st_ino = lemonStat.st_ino; + statbuf->st_mode = lemonStat.st_mode; + statbuf->st_nlink = lemonStat.st_nlink; + statbuf->st_uid = lemonStat.st_uid; + statbuf->st_gid = lemonStat.st_gid; + statbuf->st_rdev = lemonStat.st_rdev; + statbuf->st_size = lemonStat.st_size; + statbuf->st_blksize = lemonStat.st_blksize; + statbuf->st_blocks = lemonStat.st_blocks; + + return -ret; +} + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result){ + long ret = syscall(SYS_IOCTL, fd, request, arg, result); + + if(ret < 0) + return -ret; + + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events){ + long ret = syscall(SYS_POLL, fds, count, timeout); + + if(ret < 0){ + return -ret; + } + + *num_events = ret; + + return 0; +} + +int sys_mkdir(const char* path, mode_t){ + long ret = syscall(SYS_MKDIR, path); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_rmdir(const char* path){ + long ret = syscall(SYS_RMDIR, path); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_link(const char* srcpath, const char* destpath){ + long ret = syscall(SYS_LINK, srcpath, destpath); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + long ret = syscall(SYS_UNLINK, fd, path, flags); + + if(ret < 0) { + return -ret; + } + + return 0; +} + +typedef struct lemon_dirent { + uint32_t inode; // Inode number + uint32_t type; + char name[NAME_MAX]; // Filename +} lemon_dirent_t; + +int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read){ + lemon_dirent_t lemonDirent; + long ret = syscall(SYS_READDIR_NEXT, handle, &lemonDirent); + + if(!ret){ + *bytes_read = 0; + return 0; + } else if(ret > 0){ + dirent* dir = (dirent*)buffer; + strcpy(dir->d_name, lemonDirent.name); + dir->d_ino = lemonDirent.inode; + dir->d_off = 0; + dir->d_reclen = sizeof(dirent); + dir->d_type = lemonDirent.type; + + *bytes_read = sizeof(dirent); + return 0; + } else { + return -ret; + } +} + +int sys_open_dir(const char* path, int* handle){ + return sys_open(path, O_DIRECTORY, 0, handle); +} + +int sys_rename(const char* path, const char* new_path){ + return -syscall(SYS_RENAME, path, new_path); +} + +int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length){ + long ret = syscall(SYS_READLINK, path, buffer, max_size); + if(ret < 0){ + return -ret; + } + + *length = ret; + return 0; +} + +int sys_dup(int fd, int flags, int* newfd){ + int ret = syscall(SYS_DUP, fd, flags, -1); + if(ret < 0){ + return -ret; + } + + *newfd = ret; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd){ + int ret = syscall(SYS_DUP, fd, flags, newfd); + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_fcntl(int fd, int request, va_list args, int* result){ + if(request == F_DUPFD){ + return sys_dup(fd, 0, result); + } else if (request == F_DUPFD_CLOEXEC) { + return sys_dup(fd, O_CLOEXEC, result); + } else if(request == F_GETFD){ + *result = 0; + return 0; + } else if(request == F_SETFD){ + if(va_arg(args, int) & FD_CLOEXEC) { + return sys_ioctl(fd, FIOCLEX, NULL, result); + } else { + return sys_ioctl(fd, FIONCLEX, NULL, result); + } + } else if(request == F_GETFL){ + int ret = syscall(SYS_GET_FILE_STATUS_FLAGS, fd); + if(ret < 0){ + return -ret; + } + + *result = ret; + return 0; + } else if(request == F_SETFL){ + int ret = syscall(SYS_SET_FILE_STATUS_FLAGS, fd, va_arg(args, int)); + return -ret; + } else { + infoLogger() << "mlibc: sys_fcntl unsupported request (" << request << ")" << frg::endlog; + return EINVAL; + } +} + +int sys_pselect(int nfds, fd_set* readfds, fd_set* writefds, + fd_set *exceptfds, const struct timespec* timeout, const sigset_t* sigmask, int *num_events){ + int ret = syscall(SYS_SELECT, nfds, readfds, writefds, exceptfds, timeout); + if(ret < 0){ + return -ret; + } + + *num_events = ret; + return 0; +} + +int sys_chmod(const char *pathname, mode_t mode){ + int ret = syscall(SYS_CHMOD, pathname, mode); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_pipe(int *fds, int flags){ + return -syscall(SYS_PIPE, fds, flags); +} + +int sys_epoll_create(int flags, int *fd) { + int ret = syscall(SYS_EPOLL_CREATE, flags); + + if(ret < 0){ + return -ret; + } + + *fd = ret; + + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + int ret = syscall(SYS_EPOLL_CTL, epfd, mode, fd, ev); + + if(ret < 0) { + return -ret; + } + + return 0; +} + +int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, + int timeout, const sigset_t *sigmask, int *raised) { + int ret = syscall(SYS_EPOLL_WAIT, epfd, ev, n, timeout, sigmask); + + if(ret < 0) { + return -ret; + } + + *raised = ret; + + return 0; +} + +int sys_ttyname(int tty, char *buf, size_t size) { + char path[PATH_MAX] = {"/dev/pts/"}; + + struct stat stat; + if(int e = sys_stat(fsfd_target::fd, tty, nullptr, 0, &stat)) { + return e; + } + + if(!S_ISCHR(stat.st_mode)) { + return ENOTTY; // Not a char device, isn't a tty + } + + if(sys_isatty(tty)) { + return ENOTTY; + } + + // Look for tty in /dev/pts + int ptDir = open("/dev/pts", O_DIRECTORY); + __ensure(ptDir >= 0); + + struct dirent dirent; + size_t direntBytesRead; + while(!sys_read_entries(ptDir, &dirent, sizeof(dirent), &direntBytesRead) && direntBytesRead) { + // Compare the inodes + if(dirent.d_ino == stat.st_ino) { + __ensure(strlen(path) + strlen(dirent.d_name) < PATH_MAX); + strcat(path, dirent.d_name); + + strncpy(buf, path, size); + return 0; + } + } + + // Could not find corresponding TTY in /dev/pts + return ENODEV; +} + +int sys_fchdir(int fd) { + return syscall(SYS_FCHDIR, fd); +} +#endif + +} diff --git a/user/include/mlibc/sysdeps/lemon/generic/lemon.cpp b/user/include/mlibc/sysdeps/lemon/generic/lemon.cpp new file mode 100644 index 0000000..c3cbe06 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/generic/lemon.cpp @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc{ + +int sys_futex_tid(){ + return syscall(SYS_GETTID); +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time){ + return syscall(SYS_FUTEX_WAIT, pointer, expected); +} + +int sys_futex_wake(int *pointer) { + return syscall(SYS_FUTEX_WAKE, pointer); +} + +int sys_tcb_set(void* pointer){ + syscall(SYS_SET_FS_BASE, (uintptr_t)pointer); + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + __ensure(flags & MAP_ANONYMOUS); + + return syscall(SYS_MMAP, (uintptr_t)window, (size + 0xFFF) & ~static_cast(0xFFF), (uintptr_t)hint, flags); +} + +int sys_vm_unmap(void* address, size_t size) { + __ensure(!(size & 0xFFF)); + + long ret = syscall(SYS_MUNMAP, (uintptr_t)address, (size + 0xFFF) & ~static_cast(0xFFF)); + + return ret; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +void sys_libc_panic(){ + sys_libc_log("libc panic!"); + __builtin_trap(); + for(;;); +} + +void sys_libc_log(const char* msg){ + syscall(0, (uintptr_t)msg); +} + +#ifndef MLIBC_BUILDING_RTLD + +void sys_exit(int status){ + syscall(SYS_EXIT, status); + + __builtin_unreachable(); +} + +pid_t sys_getpid(){ + uint64_t _pid; + syscall(SYS_GETPID, (uintptr_t)&_pid); + + pid_t pid = _pid; + return pid; +} + +pid_t sys_getppid(){ + return syscall(SYS_GETPPID); +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + syscall(SYS_UPTIME, nanos); + + *secs = (*nanos) / 1000000000; + *nanos = (*nanos) - (*secs) * 1000000000; + + return 0; +} + +int sys_getcwd(char *buffer, size_t size){ + return syscall(SYS_GET_CWD, buffer, size); +} + +int sys_chdir(const char *path){ + syscall(SYS_CHDIR, path); + return 0; +} + +int sys_sleep(time_t* sec, long* nanosec){ + syscall(SYS_NANO_SLEEP, (*sec) * 1000000000 + (*nanosec)); + return 0; +} + +uid_t sys_getuid(){ + return syscall(SYS_GETUID); +} + +uid_t sys_geteuid(){ + return syscall(SYS_GETEUID); +} + +int sys_setuid(uid_t uid){ + return -syscall(SYS_SETUID, uid); +} + +int sys_seteuid(uid_t euid){ + return -syscall(SYS_SETEUID, euid); +} + +gid_t sys_getgid(){ + return syscall(SYS_GETGID); +} + +gid_t sys_getegid(){ + return syscall(SYS_GETEGID); +} + +int sys_setgid(gid_t gid){ + mlibc::infoLogger() << "mlibc: sys_setgid is a stub" << frg::endlog; + return 0; +} + +int sys_setegid(gid_t egid){ + mlibc::infoLogger() << "mlibc: sys_setegid is a stub" << frg::endlog; + return 0; +} + +void sys_yield(){ + syscall(SYS_YIELD); +} + +int sys_clone(void *tcb, pid_t *tid_out, void *stack){ + pid_t tid = syscall(SYS_SPAWN_THREAD, __mlibc_start_thread, stack); + + if(tid < 0){ + errno = tid; + return -1; + } + + *tid_out = tid; + + return 0; +} + +void sys_thread_exit(){ + syscall(SYS_EXIT_THREAD); + + __builtin_unreachable(); +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid){ + if(ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + + pid_t ret = syscall(SYS_WAIT_PID, pid, status, flags); + + if(ret < 0){ + return -ret; + } + + *ret_pid = ret; + + return 0; +} + +int sys_fork(pid_t *child){ + long pid = syscall(SYS_FORK, 0); + if(pid < 0){ + errno = pid; + return -1; + } + + *child = pid; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]){ + return -syscall(SYS_EXECVE, path, argv, envp); +} + +int sys_getentropy(void *buffer, size_t length){ + return -syscall(SYS_GETENTROPY, buffer, length); +} +#endif + +} diff --git a/user/include/mlibc/sysdeps/lemon/generic/pty.cpp b/user/include/mlibc/sysdeps/lemon/generic/pty.cpp new file mode 100644 index 0000000..794f74f --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/generic/pty.cpp @@ -0,0 +1,63 @@ +#include +#include + +#include + +#include +#include +#include + +#include + +namespace mlibc { + +int sys_isatty(int fd) { + struct winsize ws; + long ret = sys_ioctl(fd, TIOCGWINSZ, &ws, 0); + + if(!ret) return 0; + + return ENOTTY; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + if(int e = sys_isatty(fd)) + return e; + + int ret; + sys_ioctl(fd, TCGETS, attr, &ret); + + if(ret) + return -ret; + + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + if(int e = sys_isatty(fd)) + return e; + + if(optional_action){ + mlibc::infoLogger() << "mlibc warning: sys_tcsetattr ignores optional_action" << frg::endlog; + } + + int ret; + sys_ioctl(fd, TCSETS, const_cast(attr), &ret); + + if(ret) + return -ret; + + return 0; +} + +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if(int e = sys_ioctl(fd, TIOCGPTN, &index, NULL); e) + return e; + if((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +} diff --git a/user/include/mlibc/sysdeps/lemon/generic/signals.cpp b/user/include/mlibc/sysdeps/lemon/generic/signals.cpp new file mode 100644 index 0000000..46b4714 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/generic/signals.cpp @@ -0,0 +1,38 @@ +#include + +#include + +#include + +namespace mlibc{ + +int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve){ + int ret = syscall(SYS_SIGPROCMASK, how, set, retrieve); + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_sigaction(int signal, const struct sigaction *__restrict action, + struct sigaction *__restrict oldAction) { + int ret = syscall(SYS_SIGNAL_ACTION, signal, action, oldAction); + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_kill(int pid, int signal){ + int ret = syscall(SYS_KILL, pid, signal); + if(ret < 0){ + return -ret; + } + + return 0; +} + +} \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/generic/sockets.cpp b/user/include/mlibc/sysdeps/lemon/generic/sockets.cpp new file mode 100755 index 0000000..7244218 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/generic/sockets.cpp @@ -0,0 +1,132 @@ +#include + +#include +#include +#include + +#include + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +namespace mlibc{ + +int sys_socket(int domain, int type, int protocol, int *fd){ + long ret = syscall(SYS_SOCKET, domain, type, protocol); + + if(ret < 0){ + return -ret; + } + + *fd = ret; + + return 0; +} + +int sys_bind(int sockfd, const struct sockaddr *addr_ptr, socklen_t addrlen){ + return syscall(SYS_BIND, sockfd, addr_ptr, addrlen); +} + +int sys_connect(int sockfd, const struct sockaddr *addr_ptr, socklen_t addrlen){ + return syscall(SYS_CONNECT, sockfd, addr_ptr, addrlen); +} + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags){ + long ret = syscall(SYS_ACCEPT, fd); + + if(ret < 0){ + return -ret; + } + + *newfd = ret; + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_listen(int fd, int backlog){ + return syscall(SYS_LISTEN, fd, backlog); +} + +int sys_msg_recv(int sockfd, struct msghdr *hdr, int flags, ssize_t *length){ + long ret = syscall(SYS_RECVMSG, sockfd, hdr, flags); + + if(ret < 0){ + return -ret; + } + + *length = ret; + + return 0; +} + +int sys_msg_send(int sockfd, const struct msghdr *hdr, int flags, ssize_t *length){ + long ret = syscall(SYS_SENDMSG, sockfd, hdr, flags); + + if(ret < 0){ + return -ret; + } + + *length = ret; + + return 0; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size){ + long ret = syscall(SYS_SET_SOCKET_OPTIONS, fd, layer, number, buffer, size); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size){ + long ret = syscall(SYS_GET_SOCKET_OPTIONS, fd, layer, number, buffer, size); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds){ + return -syscall(SYS_SOCKETPAIR, domain, type_and_flags, proto, fds); +} + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + return -syscall(SYS_SOCKNAME, fd, addr_ptr, max_addr_length); +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + return -syscall(SYS_PEERNAME, fd, addr_ptr, max_addr_length); +} + +} diff --git a/user/include/mlibc/sysdeps/lemon/generic/thread.cpp b/user/include/mlibc/sysdeps/lemon/generic/thread.cpp new file mode 100644 index 0000000..42cd758 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/generic/thread.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while(!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} //namespace mlibc diff --git a/user/include/mlibc/sysdeps/lemon/generic/thread_entry.S b/user/include/mlibc/sysdeps/lemon/generic/thread_entry.S new file mode 100644 index 0000000..51e703b --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/generic/thread_entry.S @@ -0,0 +1,11 @@ + +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/access.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/access.h new file mode 100755 index 0000000..3f44365 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/lemon/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/auxv.h new file mode 100755 index 0000000..0f14415 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/lemon/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..10063ad --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..70b4ee1 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..4137906 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/dev_t.h new file mode 100755 index 0000000..90d89bb --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/epoll.h new file mode 100755 index 0000000..63afbc2 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/lemon/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/errno.h new file mode 100755 index 0000000..fe116e1 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/lemon/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/fcntl.h new file mode 100755 index 0000000..1787554 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/lemon/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/gid_t.h new file mode 100755 index 0000000..5a7f444 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/in.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/in.h new file mode 100755 index 0000000..6e14a10 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/lemon/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/ino_t.h new file mode 100755 index 0000000..24ad7b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/inotify.h new file mode 100755 index 0000000..81e2056 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/lemon/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/ipc.h new file mode 100755 index 0000000..a315d4d --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/lemon/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/limits.h new file mode 100755 index 0000000..5637cbf --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/lemon/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/mode_t.h new file mode 100755 index 0000000..77df7aa --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..886296d --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/packet.h new file mode 100755 index 0000000..a8a8412 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/lemon/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/pid_t.h new file mode 100755 index 0000000..8adf206 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/poll.h new file mode 100755 index 0000000..b6769ad --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/lemon/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/ptrace.h new file mode 100755 index 0000000..5be23ef --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/lemon/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/random.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/random.h new file mode 100755 index 0000000..4bcfa99 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/random.h @@ -0,0 +1 @@ +../../../../abis/lemon/random.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/reboot.h new file mode 100755 index 0000000..77013a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/resource.h new file mode 100755 index 0000000..f7d9afe --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/lemon/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..7f52713 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..df7bccf --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/shm.h new file mode 100755 index 0000000..17c7fae --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/lemon/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/sigevent.h new file mode 100755 index 0000000..83d069b --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/linux/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/signal.h new file mode 100755 index 0000000..4dcb0b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/socket.h new file mode 100755 index 0000000..f1dc016 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/stat.h new file mode 100755 index 0000000..f47a84f --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/lemon/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/time.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/time.h new file mode 100755 index 0000000..9b1f9ce --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/lemon/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/uid_t.h new file mode 100755 index 0000000..73b726e --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/lemon/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/utsname.h new file mode 100755 index 0000000..a10e03e --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/lemon/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..43eed29 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/lemon/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/lemon/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/lemon/include/lemon/syscall.h b/user/include/mlibc/sysdeps/lemon/include/lemon/syscall.h new file mode 100644 index 0000000..495dbe8 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/lemon/syscall.h @@ -0,0 +1,194 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#include + +#define SYS_EXIT 1 +#define SYS_EXEC 2 +#define SYS_READ 3 +#define SYS_WRITE 4 +#define SYS_OPEN 5 +#define SYS_CLOSE 6 +#define SYS_SLEEP 7 +#define SYS_CREATE 8 +#define SYS_LINK 9 +#define SYS_UNLINK 10 +#define SYS_EXECVE 11 +#define SYS_CHDIR 12 +#define SYS_TIME 13 +#define SYS_MAP_FB 14 +#define SYS_GETTID 15 +#define SYS_CHMOD 16 +#define SYS_FSTAT 17 +#define SYS_STAT 18 +#define SYS_LSEEK 19 +#define SYS_GETPID 20 +#define SYS_MOUNT 21 +#define SYS_MKDIR 22 +#define SYS_RMDIR 23 +#define SYS_RENAME 24 +#define SYS_YIELD 25 +#define SYS_READDIR_NEXT 26 +#define SYS_SEND_MESSAGE 28 +#define SYS_RECEIVE_MESSAGE 29 +#define SYS_UPTIME 30 +#define SYS_GET_VIDEO_MODE 31 +#define SYS_UNAME 32 +#define SYS_READDIR 33 +#define SYS_SET_FS_BASE 34 +#define SYS_MMAP 35 +#define SYS_GET_CWD 37 +#define SYS_WAIT_PID 38 +#define SYS_NANO_SLEEP 39 +#define SYS_PREAD 40 +#define SYS_PWRITE 41 +#define SYS_IOCTL 42 +#define SYS_INFO 43 +#define SYS_MUNMAP 44 +#define SYS_CREATE_SHARED_MEMORY 45 +#define SYS_MAP_SHARED_MEMORY 46 +#define SYS_UNMAP_SHARED_MEMORY 47 +#define SYS_DESTROY_SHARED_MEMORY 48 +#define SYS_SOCKET 49 +#define SYS_BIND 50 +#define SYS_LISTEN 51 +#define SYS_ACCEPT 52 +#define SYS_CONNECT 53 +#define SYS_SEND 54 +#define SYS_SENDTO 55 +#define SYS_RECEIVE 56 +#define SYS_RECEIVEFROM 57 +#define SYS_GETUID 58 +#define SYS_SETUID 59 +#define SYS_POLL 60 +#define SYS_SENDMSG 61 +#define SYS_RECVMSG 62 +#define SYS_GETEUID 63 +#define SYS_SETEUID 64 +#define SYS_GET_PROCESS_INFO 65 +#define SYS_GET_NEXT_PROCESS_INFO 66 +#define SYS_READLINK 67 +#define SYS_SPAWN_THREAD 68 +#define SYS_EXIT_THREAD 69 +#define SYS_FUTEX_WAKE 70 +#define SYS_FUTEX_WAIT 71 +#define SYS_DUP 72 +#define SYS_GET_FILE_STATUS_FLAGS 73 +#define SYS_SET_FILE_STATUS_FLAGS 74 +#define SYS_SELECT 75 +#define SYS_CREATE_SERVICE 76 +#define SYS_CREATE_INTERFACE 77 +#define SYS_INTERFACE_ACCEPT 78 +#define SYS_INTERFACE_CONNECT 79 +#define SYS_ENDPOINT_QUEUE 80 +#define SYS_ENDPOINT_DEQUEUE 81 +#define SYS_ENDPOINT_CALL 82 +#define SYS_ENDPOINT_INFO 83 +#define SYS_KERNELOBJECT_WAIT_ONE 84 +#define SYS_KERNELOBJECT_WAIT 85 +#define SYS_KERNELOBJECT_DESTROY 86 +#define SYS_SET_SOCKET_OPTIONS 87 +#define SYS_GET_SOCKET_OPTIONS 88 +#define SYS_DEVICE_MANAGEMENT 89 +#define SYS_INTERRUPT_THREAD 90 +#define SYS_LOAD_KERNEL_MODULE 91 +#define SYS_UNLOAD_KERNEL_MODULE 92 +#define SYS_FORK 93 +#define SYS_GETGID 94 +#define SYS_GETEGID 95 +#define SYS_GETPPID 96 +#define SYS_PIPE 97 +#define SYS_GETENTROPY 98 +#define SYS_SOCKETPAIR 99 +#define SYS_PEERNAME 100 +#define SYS_SOCKNAME 101 +#define SYS_SIGNAL_ACTION 102 +#define SYS_SIGPROCMASK 103 +#define SYS_KILL 104 +#define SYS_SIGNAL_RETURN 105 +#define SYS_ALARM 106 +#define SYS_GET_RESOURCE_LIMIT 107 +#define SYS_EPOLL_CREATE 108 +#define SYS_EPOLL_CTL 109 +#define SYS_EPOLL_WAIT 110 +#define SYS_FCHDIR 111 + +#ifdef __cplusplus +extern "C"{ +#endif + +__attribute__((__always_inline__)) +static inline long syscalln0(uint64_t call) { + volatile long ret; + asm volatile("int $0x69" : "=a"(ret) : "a"(call)); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln1(uint64_t call, uint64_t arg0) { + volatile long ret; + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln2(uint64_t call, uint64_t arg0, uint64_t arg1) { + volatile long ret; + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln3(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2) { + volatile long ret; + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1), "d"(arg2) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln4(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) { + volatile long ret; + register uint64_t arg3r asm("r10") = arg3; /* put arg3 in r10 */ + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1), "d"(arg2), "r"(arg3r) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln5(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { + volatile long ret; + register uint64_t arg3r asm("r10") = arg3; /* put arg3 in r10 */ + register uint64_t arg4r asm("r9") = arg4; /* put arg4 in r9 */ + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1), "d"(arg2), "r"(arg3r), "r"(arg4r) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln6(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { + volatile long ret; + register uint64_t arg3r asm("r10") = arg3; /* put arg3 in r10 */ + register uint64_t arg4r asm("r9") = arg4; /* put arg4 in r9 */ + register uint64_t arg5r asm("r8") = arg5; /* put arg5 in r8 */ + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1), "d"(arg2), "r"(arg3r), "r"(arg4r), "r"(arg5r) : "memory"); + return ret; +} + +#ifdef __cplusplus +} + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call) { return syscalln0(call); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0) { return syscalln1(call, arg0); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1) { return syscalln2(call, arg0, arg1); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2) { return syscalln3(call, arg0, arg1, arg2); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) { return syscalln4(call, arg0, arg1, arg2, arg3); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { return syscalln5(call, arg0, arg1, arg2, arg3, arg4); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { return syscalln6(call, arg0, arg1, arg2, arg3, arg4, arg5); } + + template + __attribute__((__always_inline__)) static inline long syscall(uint64_t call, T... args){ + return _syscall(call, (uint64_t)(args)...); + } +#else + #define GET_SYSCALL(a0, a1, a2, a3, a4, a5, a6, name, ...) name + #define syscall(...) GET_SYSCALL(__VA_ARGS__, syscalln6, syscalln5, syscalln4, syscalln3, syscalln2, syscalln1, syscalln0)(__VA_ARGS__) +#endif + +#endif diff --git a/user/include/mlibc/sysdeps/lemon/include/mlibc/thread-entry.hpp b/user/include/mlibc/sysdeps/lemon/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..2dd88a6 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/include/mlibc/thread-entry.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +extern "C" void __mlibc_start_thread(void); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb); + +namespace mlibc { + void *prepare_stack(void *entry, void *user_arg, void *tcb); +} diff --git a/user/include/mlibc/sysdeps/lemon/meson.build b/user/include/mlibc/sysdeps/lemon/meson.build new file mode 100644 index 0000000..76cda55 --- /dev/null +++ b/user/include/mlibc/sysdeps/lemon/meson.build @@ -0,0 +1,95 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': true, + 'glibc': true, + 'bsd': true, +} + +rtld_sources += files( + 'generic/filesystem.cpp', + 'generic/lemon.cpp', +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/filesystem.cpp', + 'generic/lemon.cpp', + 'generic/pty.cpp', + 'generic/signals.cpp', + 'generic/sockets.cpp', + 'generic/thread_entry.S', + 'generic/thread.cpp' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/random.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + install_headers( + 'include/lemon/syscall.h', + subdir: 'lemon' + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/user/include/mlibc/sysdeps/linux/aarch64/arch-syscall.cpp b/user/include/mlibc/sysdeps/linux/aarch64/arch-syscall.cpp new file mode 100644 index 0000000..b178538 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/arch-syscall.cpp @@ -0,0 +1,117 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +sc_word_t __do_syscall0(long sc) { + register int sc_reg asm("x8") = sc; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : "r"(sc_reg) : "memory"); + return ret; +} + +sc_word_t __do_syscall1(long sc, + sc_word_t arg1) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall2(long sc, + sc_word_t arg1, sc_word_t arg2) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t arg3_reg asm("x2") = arg3; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t arg3_reg asm("x2") = arg3; + register sc_word_t arg4_reg asm("x3") = arg4; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t arg3_reg asm("x2") = arg3; + register sc_word_t arg4_reg asm("x3") = arg4; + register sc_word_t arg5_reg asm("x4") = arg5; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t arg3_reg asm("x2") = arg3; + register sc_word_t arg4_reg asm("x3") = arg4; + register sc_word_t arg5_reg asm("x4") = arg5; + register sc_word_t arg6_reg asm("x5") = arg6; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg), + "r"(arg6_reg) + : "memory" + ); + return ret; +} diff --git a/user/include/mlibc/sysdeps/linux/aarch64/assembly-asserts.cpp b/user/include/mlibc/sysdeps/linux/aarch64/assembly-asserts.cpp new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/sysdeps/linux/aarch64/cp_syscall.S b/user/include/mlibc/sysdeps/linux/aarch64/cp_syscall.S new file mode 100644 index 0000000..98690c7 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/cp_syscall.S @@ -0,0 +1,31 @@ +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + mov x8, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + mov x4, x5 + mov x5, x6 + + mrs x7, tpidr_el0 + ldr w7, [x7, #-80] // Tcb::cancelBits. See asserts in tcb.hpp. +__mlibc_syscall_begin: + // tcbCancelEnableBit && tcbCancelTriggerBit + mov x9, #((1 << 0) | (1 << 2)) + and x7, x7, x9 + cmp x7, x9 + b.eq cancel + svc 0 +__mlibc_syscall_end: + ret + +cancel: + bl __mlibc_do_cancel + brk #0 +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/aarch64/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/linux/aarch64/crt-src/Scrt1.S new file mode 100644 index 0000000..547499e --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/crt-src/Scrt1.S @@ -0,0 +1,11 @@ +.section .text +.global _start +_start: + mov x0, sp + adr x1, main + + bl __mlibc_entry + brk #0 + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crt1.S b/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crt1.S new file mode 100644 index 0000000..6550612 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crt1.S @@ -0,0 +1,9 @@ +.section .text +.global _start +_start: + mov x0, sp + adrp x1, main + add x1, x1, :lo12:main + bl __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crti.S b/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crti.S new file mode 100644 index 0000000..0f5ca0f --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crti.S @@ -0,0 +1,13 @@ +.section .init +.global _init +_init: + stp x29, x30, [sp, -16]! + mov x29, sp + +.section .fini +.global _fini +_fini: + stp x29, x30, [sp, -16]! + mov x29, sp +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crtn.S b/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crtn.S new file mode 100644 index 0000000..cd95321 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + ldp x29, x30, [sp], #16 + ret + +.section .fini + ldp x29, x30, [sp], #16 + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/aarch64/signals.S b/user/include/mlibc/sysdeps/linux/aarch64/signals.S new file mode 100644 index 0000000..923d8d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/signals.S @@ -0,0 +1,12 @@ +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + mov x8,#139 // SYS_rt_sigreturn + svc 0 +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/aarch64/syscallnos.h b/user/include/mlibc/sysdeps/linux/aarch64/syscallnos.h new file mode 100644 index 0000000..d1a7161 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/syscallnos.h @@ -0,0 +1,327 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_io_setup 0 +#define __NR_io_destroy 1 +#define __NR_io_submit 2 +#define __NR_io_cancel 3 +#define __NR_io_getevents 4 +#define __NR_setxattr 5 +#define __NR_lsetxattr 6 +#define __NR_fsetxattr 7 +#define __NR_getxattr 8 +#define __NR_lgetxattr 9 +#define __NR_fgetxattr 10 +#define __NR_listxattr 11 +#define __NR_llistxattr 12 +#define __NR_flistxattr 13 +#define __NR_removexattr 14 +#define __NR_lremovexattr 15 +#define __NR_fremovexattr 16 +#define __NR_getcwd 17 +#define __NR_lookup_dcookie 18 +#define __NR_eventfd2 19 +#define __NR_epoll_create1 20 +#define __NR_epoll_ctl 21 +#define __NR_epoll_pwait 22 +#define __NR_dup 23 +#define __NR_dup3 24 +#define __NR_fcntl 25 +#define __NR_inotify_init1 26 +#define __NR_inotify_add_watch 27 +#define __NR_inotify_rm_watch 28 +#define __NR_ioctl 29 +#define __NR_ioprio_set 30 +#define __NR_ioprio_get 31 +#define __NR_flock 32 +#define __NR_mknodat 33 +#define __NR_mkdirat 34 +#define __NR_unlinkat 35 +#define __NR_symlinkat 36 +#define __NR_linkat 37 +#define __NR_renameat 38 +#define __NR_umount2 39 +#define __NR_mount 40 +#define __NR_pivot_root 41 +#define __NR_nfsservctl 42 +#define __NR_statfs 43 +#define __NR_fstatfs 44 +#define __NR_truncate 45 +#define __NR_ftruncate 46 +#define __NR_fallocate 47 +#define __NR_faccessat 48 +#define __NR_chdir 49 +#define __NR_fchdir 50 +#define __NR_chroot 51 +#define __NR_fchmod 52 +#define __NR_fchmodat 53 +#define __NR_fchownat 54 +#define __NR_fchown 55 +#define __NR_openat 56 +#define __NR_close 57 +#define __NR_vhangup 58 +#define __NR_pipe2 59 +#define __NR_quotactl 60 +#define __NR_getdents64 61 +#define __NR_lseek 62 +#define __NR_read 63 +#define __NR_write 64 +#define __NR_readv 65 +#define __NR_writev 66 +#define __NR_pread64 67 +#define __NR_pwrite64 68 +#define __NR_preadv 69 +#define __NR_pwritev 70 +#define __NR_sendfile 71 +#define __NR_pselect6 72 +#define __NR_ppoll 73 +#define __NR_signalfd4 74 +#define __NR_vmsplice 75 +#define __NR_splice 76 +#define __NR_tee 77 +#define __NR_readlinkat 78 +#define __NR_newfstatat 79 +#define __NR_fstat 80 +#define __NR_sync 81 +#define __NR_fsync 82 +#define __NR_fdatasync 83 +#define __NR_sync_file_range 84 +#define __NR_timerfd_create 85 +#define __NR_timerfd_settime 86 +#define __NR_timerfd_gettime 87 +#define __NR_utimensat 88 +#define __NR_acct 89 +#define __NR_capget 90 +#define __NR_capset 91 +#define __NR_personality 92 +#define __NR_exit 93 +#define __NR_exit_group 94 +#define __NR_waitid 95 +#define __NR_set_tid_address 96 +#define __NR_unshare 97 +#define __NR_futex 98 +#define __NR_set_robust_list 99 +#define __NR_get_robust_list 100 +#define __NR_nanosleep 101 +#define __NR_getitimer 102 +#define __NR_setitimer 103 +#define __NR_kexec_load 104 +#define __NR_init_module 105 +#define __NR_delete_module 106 +#define __NR_timer_create 107 +#define __NR_timer_gettime 108 +#define __NR_timer_getoverrun 109 +#define __NR_timer_settime 110 +#define __NR_timer_delete 111 +#define __NR_clock_settime 112 +#define __NR_clock_gettime 113 +#define __NR_clock_getres 114 +#define __NR_clock_nanosleep 115 +#define __NR_syslog 116 +#define __NR_ptrace 117 +#define __NR_sched_setparam 118 +#define __NR_sched_setscheduler 119 +#define __NR_sched_getscheduler 120 +#define __NR_sched_getparam 121 +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#define __NR_sched_yield 124 +#define __NR_sched_get_priority_max 125 +#define __NR_sched_get_priority_min 126 +#define __NR_sched_rr_get_interval 127 +#define __NR_restart_syscall 128 +#define __NR_kill 129 +#define __NR_tkill 130 +#define __NR_tgkill 131 +#define __NR_sigaltstack 132 +#define __NR_rt_sigsuspend 133 +#define __NR_rt_sigaction 134 +#define __NR_rt_sigprocmask 135 +#define __NR_rt_sigpending 136 +#define __NR_rt_sigtimedwait 137 +#define __NR_rt_sigqueueinfo 138 +#define __NR_rt_sigreturn 139 +#define __NR_setpriority 140 +#define __NR_getpriority 141 +#define __NR_reboot 142 +#define __NR_setregid 143 +#define __NR_setgid 144 +#define __NR_setreuid 145 +#define __NR_setuid 146 +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#define __NR_setfsuid 151 +#define __NR_setfsgid 152 +#define __NR_times 153 +#define __NR_setpgid 154 +#define __NR_getpgid 155 +#define __NR_getsid 156 +#define __NR_setsid 157 +#define __NR_getgroups 158 +#define __NR_setgroups 159 +#define __NR_uname 160 +#define __NR_sethostname 161 +#define __NR_setdomainname 162 +#define __NR_getrlimit 163 +#define __NR_setrlimit 164 +#define __NR_getrusage 165 +#define __NR_umask 166 +#define __NR_prctl 167 +#define __NR_getcpu 168 +#define __NR_gettimeofday 169 +#define __NR_settimeofday 170 +#define __NR_adjtimex 171 +#define __NR_getpid 172 +#define __NR_getppid 173 +#define __NR_getuid 174 +#define __NR_geteuid 175 +#define __NR_getgid 176 +#define __NR_getegid 177 +#define __NR_gettid 178 +#define __NR_sysinfo 179 +#define __NR_mq_open 180 +#define __NR_mq_unlink 181 +#define __NR_mq_timedsend 182 +#define __NR_mq_timedreceive 183 +#define __NR_mq_notify 184 +#define __NR_mq_getsetattr 185 +#define __NR_msgget 186 +#define __NR_msgctl 187 +#define __NR_msgrcv 188 +#define __NR_msgsnd 189 +#define __NR_semget 190 +#define __NR_semctl 191 +#define __NR_semtimedop 192 +#define __NR_semop 193 +#define __NR_shmget 194 +#define __NR_shmctl 195 +#define __NR_shmat 196 +#define __NR_shmdt 197 +#define __NR_socket 198 +#define __NR_socketpair 199 +#define __NR_bind 200 +#define __NR_listen 201 +#define __NR_accept 202 +#define __NR_connect 203 +#define __NR_getsockname 204 +#define __NR_getpeername 205 +#define __NR_sendto 206 +#define __NR_recvfrom 207 +#define __NR_setsockopt 208 +#define __NR_getsockopt 209 +#define __NR_shutdown 210 +#define __NR_sendmsg 211 +#define __NR_recvmsg 212 +#define __NR_readahead 213 +#define __NR_brk 214 +#define __NR_munmap 215 +#define __NR_mremap 216 +#define __NR_add_key 217 +#define __NR_request_key 218 +#define __NR_keyctl 219 +#define __NR_clone 220 +#define __NR_execve 221 +#define __NR_mmap 222 +#define __NR_fadvise64 223 +#define __NR_swapon 224 +#define __NR_swapoff 225 +#define __NR_mprotect 226 +#define __NR_msync 227 +#define __NR_mlock 228 +#define __NR_munlock 229 +#define __NR_mlockall 230 +#define __NR_munlockall 231 +#define __NR_mincore 232 +#define __NR_madvise 233 +#define __NR_remap_file_pages 234 +#define __NR_mbind 235 +#define __NR_get_mempolicy 236 +#define __NR_set_mempolicy 237 +#define __NR_migrate_pages 238 +#define __NR_move_pages 239 +#define __NR_rt_tgsigqueueinfo 240 +#define __NR_perf_event_open 241 +#define __NR_accept4 242 +#define __NR_recvmmsg 243 +#define __NR_wait4 260 +#define __NR_prlimit64 261 +#define __NR_fanotify_init 262 +#define __NR_fanotify_mark 263 +#define __NR_name_to_handle_at 264 +#define __NR_open_by_handle_at 265 +#define __NR_clock_adjtime 266 +#define __NR_syncfs 267 +#define __NR_setns 268 +#define __NR_sendmmsg 269 +#define __NR_process_vm_readv 270 +#define __NR_process_vm_writev 271 +#define __NR_kcmp 272 +#define __NR_finit_module 273 +#define __NR_sched_setattr 274 +#define __NR_sched_getattr 275 +#define __NR_renameat2 276 +#define __NR_seccomp 277 +#define __NR_getrandom 278 +#define __NR_memfd_create 279 +#define __NR_bpf 280 +#define __NR_execveat 281 +#define __NR_userfaultfd 282 +#define __NR_membarrier 283 +#define __NR_mlock2 284 +#define __NR_copy_file_range 285 +#define __NR_preadv2 286 +#define __NR_pwritev2 287 +#define __NR_pkey_mprotect 288 +#define __NR_pkey_alloc 289 +#define __NR_pkey_free 290 +#define __NR_statx 291 +#define __NR_io_pgetevents 292 +#define __NR_rseq 293 +#define __NR_kexec_file_load 294 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_memfd_secret 447 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_cachestat 451 +#define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 +#define __NR_statmount 457 +#define __NR_listmount 458 +#define __NR_lsm_get_self_attr 459 +#define __NR_lsm_set_self_attr 460 +#define __NR_lsm_list_modules 461 +#define __NR_mseal 462 +#define __NR_setxattrat 463 +#define __NR_getxattrat 464 +#define __NR_listxattrat 465 +#define __NR_removexattrat 466 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/user/include/mlibc/sysdeps/linux/aarch64/thread_entry.S b/user/include/mlibc/sysdeps/linux/aarch64/thread_entry.S new file mode 100644 index 0000000..a47a048 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/aarch64/thread_entry.S @@ -0,0 +1,27 @@ +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +__mlibc_spawn_thread: + // __mlibc_spawn_thread(flags, stack, pid_out, child_tid, tls) + // x0, x1, x2, x3, x4 + // syscall(NR_clone, flags, stack, ptid, tls, ctid) + // x8, x0, x1, x2, x3, x4 + + // Swap x3 <-> x4 + mov x5, x4 + mov x4, x3 + mov x3, x5 + + mov x8, 220 // NR_clone + svc 0 + cbnz x0, .parent + + ldp x0, x1, [sp], #16 + + bl __mlibc_enter_thread + brk #0 + +.parent: + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/generic/cxx-syscall.hpp b/user/include/mlibc/sysdeps/linux/generic/cxx-syscall.hpp new file mode 100644 index 0000000..afc7648 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/generic/cxx-syscall.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +using sc_word_t = __sc_word_t; + +extern "C" { + extern sc_word_t __mlibc_do_asm_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4, sc_word_t arg5, sc_word_t arg6); + + extern void __mlibc_do_cancel(); +} + +namespace mlibc { + // C++ wrappers for the extern "C" functions. + inline sc_word_t do_nargs_syscall(int sc) { + return __do_syscall0(sc); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1) { + return __do_syscall1(sc, arg1); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2) { + return __do_syscall2(sc, arg1, arg2); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + return __do_syscall3(sc, arg1, arg2, arg3); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + return __do_syscall4(sc, arg1, arg2, arg3, arg4); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + return __do_syscall5(sc, arg1, arg2, arg3, arg4, arg5); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + return __do_syscall6(sc, arg1, arg2, arg3, arg4, arg5, arg6); + } + + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1) { + return __mlibc_do_asm_cp_syscall(sc, arg1, 0, 0, 0, 0, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, 0, 0, 0, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, arg3, 0, 0, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, arg3, arg4, 0, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, arg3, arg4, arg5, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, arg3, arg4, arg5, arg6); + } + + // Type-safe syscall result type. + enum class sc_result_t : sc_word_t { }; + + // Cast to the argument type of the extern "C" functions. + inline sc_word_t sc_cast(long x) { return x; } + inline sc_word_t sc_cast(const void *x) { return reinterpret_cast(x); } + + template + sc_result_t do_syscall(int sc, T... args) { + return static_cast(do_nargs_syscall(sc, sc_cast(args)...)); + } + + inline int sc_error(sc_result_t ret) { + auto v = static_cast(ret); + if(static_cast(v) > -4096UL) + return -v; + return 0; + } + + template + sc_result_t do_cp_syscall(int sc, T... args) { +#if __MLIBC_POSIX_OPTION && !MLIBC_BUILDING_RTLD + auto result = static_cast(do_nargs_cp_syscall(sc, sc_cast(args)...)); + if (int e = sc_error(result); e) { + auto tcb = reinterpret_cast(get_current_tcb()); + if (tcb_cancelled(tcb->cancelBits) && e == EINTR) { + __mlibc_do_cancel(); + __builtin_unreachable(); + } + } + return result; +#else + return do_syscall(sc, std::forward(args)...); +#endif // __MLIBC_POSIX_OPTION || !MLIBC_BUILDING_RTLD + } + // Cast from the syscall result type. + template + T sc_int_result(sc_result_t ret) { + auto v = static_cast(ret); + return v; + } + + template + T *sc_ptr_result(sc_result_t ret) { + auto v = static_cast(ret); + return reinterpret_cast(v); + } +} diff --git a/user/include/mlibc/sysdeps/linux/generic/entry.cpp b/user/include/mlibc/sysdeps/linux/generic/entry.cpp new file mode 100644 index 0000000..7e54e4e --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/generic/entry.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include + +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; + +size_t __hwcap; + +extern "C" void __mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + __dlapi_enter(entry_stack); + __hwcap = getauxval(AT_HWCAP); + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} diff --git a/user/include/mlibc/sysdeps/linux/generic/sysdeps.cpp b/user/include/mlibc/sysdeps/linux/generic/sysdeps.cpp new file mode 100644 index 0000000..3981c70 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/generic/sysdeps.cpp @@ -0,0 +1,2522 @@ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#if __MLIBC_LINUX_OPTION +# include +#endif +#include +#include +#include +#include +#include +#include +#include "cxx-syscall.hpp" + +#if (__MLIBC_POSIX_OPTION || __MLIBC_LINUX_OPTION) && !defined(MLIBC_BUILDING_RTLD) + +#include "generic-helpers/netlink.hpp" + +#endif + +#define STUB_ONLY { __ensure(!"STUB_ONLY function was called"); __builtin_unreachable(); } +#define UNUSED(x) (void)(x); + +#ifndef MLIBC_BUILDING_RTLD +extern "C" long __do_syscall_ret(unsigned long ret) { + if(ret > -4096UL) { + errno = -ret; + return -1; + } + return ret; +} +#endif + +namespace mlibc { + +void sys_libc_log(const char *message) { + size_t n = 0; + while(message[n]) + n++; + do_syscall(SYS_write, 2, message, n); + char lf = '\n'; + do_syscall(SYS_write, 2, &lf, 1); +} + +void sys_libc_panic() { + __builtin_trap(); +} + +#if defined(__i386__) + +struct user_desc { + unsigned int entry_number; + unsigned long base_addr; + unsigned int limit; + unsigned int seg_32bit: 1; + unsigned int contents: 2; + unsigned int read_exec_only: 1; + unsigned int limit_in_pages: 1; + unsigned int seg_not_present: 1; + unsigned int useable: 1; +}; + +#endif + +#if defined(__m68k__) +extern "C" void *__m68k_read_tp() { + auto ret = do_syscall(__NR_get_thread_area, 0); + return (void *)ret; +} +#elif defined(__riscv) +int sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, unsigned int flags) { + auto ret = do_syscall(SYS_riscv_hwprobe, pairs, pair_count, cpusetsize, cpus, flags); + if(int e = sc_error(ret); e) + return -e; + return sc_int_result(ret); +} +#endif + +int sys_tcb_set(void *pointer) { +#if defined(__x86_64__) + auto ret = do_syscall(SYS_arch_prctl, 0x1002 /* ARCH_SET_FS */, pointer); + if(int e = sc_error(ret); e) + return e; +#elif defined(__i386__) + struct user_desc desc = { + .entry_number = static_cast(-1), + .base_addr = uintptr_t(pointer), + .limit = 0xfffff, + .seg_32bit = 1, + .contents = 0, + .read_exec_only = 0, + .limit_in_pages = 1, + .seg_not_present = 0, + .useable = 1, + }; + auto ret = do_syscall(SYS_set_thread_area, &desc); + __ensure(!sc_error(ret)); + asm volatile ("movw %w0, %%gs" : : "q"(desc.entry_number * 8 + 3) :); +#elif defined(__riscv) + uintptr_t thread_data = reinterpret_cast(pointer) + sizeof(Tcb); + asm volatile ("mv tp, %0" :: "r"(thread_data)); +#elif defined (__aarch64__) + uintptr_t thread_data = reinterpret_cast(pointer) + sizeof(Tcb) - 0x10; + asm volatile ("msr tpidr_el0, %0" :: "r"(thread_data)); +#elif defined (__m68k__) + auto ret = do_syscall(__NR_set_thread_area, (uintptr_t)pointer + 0x7000 + sizeof(Tcb)); + if(int e = sc_error(ret); e) + return e; +#elif defined(__loongarch64) + uintptr_t thread_data = reinterpret_cast(pointer) + sizeof(Tcb); + asm volatile ("move $tp, %0" :: "r"(thread_data)); +#else +#error "Missing architecture specific code." +#endif + return 0; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0, pointer); +} +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +int sys_fadvise(int fd, off_t offset, off_t length, int advice) { + auto ret = do_syscall(SYS_fadvise64, fd, offset, length, advice); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + auto ret = do_cp_syscall(SYS_openat, AT_FDCWD, path, flags, mode); + if(int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + auto ret = do_syscall(SYS_openat, dirfd, path, flags, mode); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_close(int fd) { + auto ret = do_cp_syscall(SYS_close, fd); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + auto ret = do_cp_syscall(SYS_dup3, fd, newfd, flags); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_read(int fd, void *buffer, size_t size, ssize_t *bytes_read) { + auto ret = do_cp_syscall(SYS_read, fd, buffer, size); + if(int e = sc_error(ret); e) + return e; + *bytes_read = sc_int_result(ret); + return 0; +} + +int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read) { + auto ret = do_cp_syscall(SYS_readv, fd, iovs, iovc); + if(int e = sc_error(ret); e) + return e; + *bytes_read = sc_int_result(ret); + return 0; +} + +int sys_write(int fd, const void *buffer, size_t size, ssize_t *bytes_written) { + auto ret = do_cp_syscall(SYS_write, fd, buffer, size); + if(int e = sc_error(ret); e) + return e; + if(bytes_written) + *bytes_written = sc_int_result(ret); + return 0; +} + +int sys_writev(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written) { + auto ret = do_cp_syscall(SYS_writev, fd, iovs, iovc); + if(int e = sc_error(ret); e) + return e; + if(bytes_written) + *bytes_written = sc_int_result(ret); + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + auto ret = do_syscall(SYS_lseek, fd, offset, whence); + if(int e = sc_error(ret); e) + return e; + *new_offset = sc_int_result(ret); + return 0; +} + +int sys_chmod(const char *pathname, mode_t mode) { + auto ret = do_cp_syscall(SYS_fchmodat, AT_FDCWD, pathname, mode); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fchmod(int fd, mode_t mode) { + auto ret = do_cp_syscall(SYS_fchmod, fd, mode); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + auto ret = do_cp_syscall(SYS_fchmodat, fd, pathname, mode, flags); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { + auto ret = do_cp_syscall(SYS_fchownat, dirfd, pathname, owner, group, flags); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + auto ret = do_cp_syscall(SYS_utimensat, dirfd, pathname, times, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, + int fd, off_t offset, void **window) { + if(offset % 4096) + return EINVAL; + if(size >= PTRDIFF_MAX) + return ENOMEM; +#if defined(SYS_mmap2) + auto ret = do_syscall(SYS_mmap2, hint, size, prot, flags, fd, offset/4096); +#else + auto ret = do_syscall(SYS_mmap, hint, size, prot, flags, fd, offset); +#endif + // TODO: musl fixes up EPERM errors from the kernel. + if(int e = sc_error(ret); e) + return e; + *window = sc_ptr_result(ret); + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + auto ret = do_syscall(SYS_munmap, pointer, size); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + auto ret = do_syscall(SYS_mprotect, pointer, size, prot); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +// All remaining functions are disabled in ldso. +#ifndef MLIBC_BUILDING_RTLD + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec tp = {}; + auto ret = do_syscall(SYS_clock_gettime, clock, &tp); + if (int e = sc_error(ret); e) + return e; + *secs = tp.tv_sec; + *nanos = tp.tv_nsec; + return 0; +} + +int sys_clock_getres(int clock, time_t *secs, long *nanos) { + struct timespec tp = {}; + auto ret = do_syscall(SYS_clock_getres, clock, &tp); + if (int e = sc_error(ret); e) + return e; + *secs = tp.tv_sec; + *nanos = tp.tv_nsec; + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + if (fsfdt == fsfd_target::path) + fd = AT_FDCWD; + else if (fsfdt == fsfd_target::fd) + flags |= AT_EMPTY_PATH; + else + __ensure(fsfdt == fsfd_target::fd_path); + +#if defined(SYS_newfstatat) + auto ret = do_cp_syscall(SYS_newfstatat, fd, path, statbuf, flags); +#else + auto ret = do_cp_syscall(SYS_fstatat64, fd, path, statbuf, flags); +#endif + if (int e = sc_error(ret); e) { + return e; + } + +#if defined(__i386__) + statbuf->st_atim.tv_sec = statbuf->__st_atim32.tv_sec; + statbuf->st_atim.tv_nsec = statbuf->__st_atim32.tv_nsec; + statbuf->st_mtim.tv_sec = statbuf->__st_mtim32.tv_sec; + statbuf->st_mtim.tv_nsec = statbuf->__st_mtim32.tv_nsec; + statbuf->st_ctim.tv_sec = statbuf->__st_ctim32.tv_sec; + statbuf->st_ctim.tv_nsec = statbuf->__st_ctim32.tv_nsec; +#endif + + return 0; +} + +#if __MLIBC_LINUX_OPTION +static_assert(sizeof(struct statx) == 0x100); // Linux kernel requires it to be precisely 256 bytes. + +int sys_statx(int dirfd, const char *path, int flags, unsigned int mask, struct statx *statxbuf) { + auto ret = do_cp_syscall(SYS_statx, dirfd, path, flags, mask, statxbuf); + if (int e = sc_error(ret); e) + return e; + return 0; +} +#endif + +int sys_statfs(const char *path, struct statfs *buf) { + auto ret = do_cp_syscall(SYS_statfs, path, buf); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fstatfs(int fd, struct statfs *buf) { + auto ret = do_cp_syscall(SYS_fstatfs, fd, buf); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +extern "C" void __mlibc_signal_restore(void); +extern "C" void __mlibc_signal_restore_rt(void); + +int sys_sigaction(int signum, const struct sigaction *act, + struct sigaction *oldact) { + struct ksigaction { + void (*handler)(int); + unsigned long flags; + void (*restorer)(void); + uint32_t mask[2]; + }; + + struct ksigaction kernel_act, kernel_oldact; + if (act) { + kernel_act.handler = act->sa_handler; + kernel_act.flags = act->sa_flags | SA_RESTORER; + kernel_act.restorer = (act->sa_flags & SA_SIGINFO) ? __mlibc_signal_restore_rt : __mlibc_signal_restore; + memcpy(&kernel_act.mask, &act->sa_mask, sizeof(kernel_act.mask)); + } + + static_assert(sizeof(kernel_act.mask) == 8); + + auto ret = do_syscall(SYS_rt_sigaction, signum, act ? + &kernel_act : nullptr, oldact ? + &kernel_oldact : nullptr, sizeof(kernel_act.mask)); + if (int e = sc_error(ret); e) + return e; + + if (oldact) { + oldact->sa_handler = kernel_oldact.handler; + oldact->sa_flags = kernel_oldact.flags; + oldact->sa_restorer = kernel_oldact.restorer; + memcpy(&oldact->sa_mask, &kernel_oldact.mask, sizeof(kernel_oldact.mask)); + } + return 0; +} + +int sys_socket(int domain, int type, int protocol, int *fd) { + auto ret = do_syscall(SYS_socket, domain, type, protocol); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_msg_send(int sockfd, const struct msghdr *msg, int flags, ssize_t *length) { + auto ret = do_cp_syscall(SYS_sendmsg, sockfd, msg, flags); + if (int e = sc_error(ret); e) + return e; + *length = sc_int_result(ret); + return 0; +} + +ssize_t sys_sendto(int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length) { + auto ret = do_cp_syscall(SYS_sendto, fd, buffer, size, flags, sock_addr, addr_length); + if(int e = sc_error(ret); e) { + return e; + } + *length = sc_int_result(ret); + return 0; +} + +ssize_t sys_recvfrom(int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length) { + auto ret = do_cp_syscall(SYS_recvfrom, fd, buffer, size, flags, sock_addr, addr_length); + if(int e = sc_error(ret); e) { + return e; + } + *length = sc_int_result(ret); + return 0; +} + +int sys_msg_recv(int sockfd, struct msghdr *msg, int flags, ssize_t *length) { + auto ret = do_cp_syscall(SYS_recvmsg, sockfd, msg, flags); + if (int e = sc_error(ret); e) + return e; + *length = sc_int_result(ret); + return 0; +} + +int sys_fcntl(int fd, int cmd, va_list args, int *result) { + auto arg = va_arg(args, unsigned long); + // TODO: the api for linux differs for each command so fcntl()s might fail with -EINVAL + // we should implement all the different fcntl()s + // TODO(geert): only some fcntl()s can fail with -EINTR, making do_cp_syscall useless + // on most fcntls(). Another reason to handle different fcntl()s seperately. + auto ret = do_cp_syscall(SYS_fcntl, fd, cmd, arg); + if (int e = sc_error(ret); e) + return e; + *result = sc_int_result(ret); + return 0; +} + +int sys_getcwd(char *buf, size_t size) { + auto ret = do_syscall(SYS_getcwd, buf, size); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_unlinkat(int dfd, const char *path, int flags) { + auto ret = do_syscall(SYS_unlinkat, dfd, path, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sleep(time_t *secs, long *nanos) { + struct timespec req = { + .tv_sec = *secs, + .tv_nsec = *nanos + }; + struct timespec rem = {}; + + auto ret = do_cp_syscall(SYS_nanosleep, &req, &rem); + if (int e = sc_error(ret); e) + return e; + + *secs = rem.tv_sec; + *nanos = rem.tv_nsec; + return 0; +} + +int sys_isatty(int fd) { + unsigned short winsizeHack[4]; + auto ret = do_syscall(SYS_ioctl, fd, 0x5413 /* TIOCGWINSZ */, &winsizeHack); + if (int e = sc_error(ret); e) + return e; + auto res = sc_int_result(ret); + if(!res) return 0; + return 1; +} + +#if __MLIBC_POSIX_OPTION + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + auto ret = do_syscall(SYS_ioctl, fd, request, arg); + if (int e = sc_error(ret); e) + return e; + if (result) + *result = sc_int_result(ret); + return 0; +} + +int sys_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + auto ret = do_cp_syscall(SYS_connect, sockfd, addr, addrlen); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_pselect(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + // The Linux kernel sometimes modifies the timeout argument. + struct timespec local_timeout; + if(timeout) + local_timeout = *timeout; + + // The Linux kernel really wants 7 arguments, even tho this is not supported + // To fix that issue, they use a struct as the last argument. + // See the man page of pselect and the glibc source code + struct { + const sigset_t *sigmask; + size_t ss_len; + } data; + data.sigmask = sigmask; + data.ss_len = NSIG / 8; + + auto ret = do_cp_syscall(SYS_pselect6, nfds, readfds, writefds, + exceptfds, timeout ? &local_timeout : nullptr, &data); + if (int e = sc_error(ret); e) + return e; + *num_events = sc_int_result(ret); + return 0; +} + +int sys_pipe(int *fds, int flags) { + if(flags) { + auto ret = do_syscall(SYS_pipe2, fds, flags); + if (int e = sc_error(ret); e) + return e; + return 0; + } else { + auto ret = do_syscall(SYS_pipe2, fds, 0); + if (int e = sc_error(ret); e) + return e; + return 0; + } +} + +int sys_fork(pid_t *child) { + auto ret = do_syscall(SYS_clone, SIGCHLD, 0); + if (int e = sc_error(ret); e) + return e; + *child = sc_int_result(ret); + return 0; +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + auto ret = do_syscall(SYS_wait4, pid, status, flags, ru); + if (int e = sc_error(ret); e) + return e; + *ret_pid = sc_int_result(ret); + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + auto ret = do_syscall(SYS_execve, path, argv, envp); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sigprocmask(int how, const sigset_t *set, sigset_t *old) { + auto ret = do_syscall(SYS_rt_sigprocmask, how, set, old, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) { + auto ret = do_syscall(SYS_setresuid, ruid, euid, suid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + auto ret = do_syscall(SYS_setresgid, rgid, egid, sgid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + auto ret = do_syscall(SYS_getresuid, ruid, euid, suid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + auto ret = do_syscall(SYS_getresgid, rgid, egid, sgid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setreuid(uid_t ruid, uid_t euid) { + auto ret = do_syscall(SYS_setreuid, ruid, euid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setregid(gid_t rgid, gid_t egid) { + auto ret = do_syscall(SYS_setregid, rgid, egid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sysinfo(struct sysinfo *info) { + auto ret = do_syscall(SYS_sysinfo, info); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +void sys_yield() { + do_syscall(SYS_sched_yield); +} + +int sys_clone(void *tcb, pid_t *pid_out, void *stack) { + unsigned long flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND + | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS + | CLONE_PARENT_SETTID; + +#if defined(__riscv) || defined(__loongarch64) + // TP should point to the address immediately after the TCB. + // TODO: We should change the sysdep so that we don't need to do this. + auto tls = reinterpret_cast(tcb) + sizeof(Tcb); + tcb = reinterpret_cast(tls); +#elif defined(__aarch64__) + // TP should point to the address 16 bytes before the end of the TCB. + // TODO: We should change the sysdep so that we don't need to do this. + auto tp = reinterpret_cast(tcb) + sizeof(Tcb) - 0x10; + tcb = reinterpret_cast(tp); +#elif defined(__i386__) + /* get the entry number, as we don't request a new one here */ + uint32_t gs; + asm volatile("movw %%gs, %w0" : "=q"(gs)); + + auto user_desc = reinterpret_cast(getAllocator().allocate(sizeof(struct user_desc))); + + user_desc->entry_number = (gs & 0xffff) >> 3; + user_desc->base_addr = uintptr_t(tcb); + user_desc->limit = 0xfffff; + user_desc->seg_32bit = 1; + user_desc->contents = 0; + user_desc->read_exec_only = 0; + user_desc->limit_in_pages = 1; + user_desc->seg_not_present = 0; + user_desc->useable = 1; + + tcb = reinterpret_cast(user_desc); +#endif + + auto ret = __mlibc_spawn_thread(flags, stack, pid_out, nullptr, tcb); + if (ret < 0) + return ret; + + return 0; +} + +extern "C" const char __mlibc_syscall_begin[1]; +extern "C" const char __mlibc_syscall_end[1]; + +#if defined(__riscv) +// Disable UBSan here to work around qemu-user misaligning ucontext_t. +// https://github.com/qemu/qemu/blob/2bf40d0841b942e7ba12953d515e62a436f0af84/linux-user/riscv/signal.c#L68-L69 +[[gnu::no_sanitize("undefined")]] +#endif +int sys_before_cancellable_syscall(ucontext_t *uct) { +#if defined(__x86_64__) + auto pc = reinterpret_cast(uct->uc_mcontext.gregs[REG_RIP]); +#elif defined(__i386__) + auto pc = reinterpret_cast(uct->uc_mcontext.gregs[REG_EIP]); +#elif defined(__riscv) + auto pc = reinterpret_cast(uct->uc_mcontext.gregs[REG_PC]); +#elif defined(__aarch64__) + auto pc = reinterpret_cast(uct->uc_mcontext.pc); +#elif defined(__m68k__) + auto pc = reinterpret_cast(uct->uc_mcontext.gregs[R_PC]); +#elif defined(__loongarch64) + auto pc = reinterpret_cast(uct->uc_mcontext.pc); +#else +#error "Missing architecture specific code." +#endif + if (pc < __mlibc_syscall_begin || pc > __mlibc_syscall_end) + return 0; + return 1; +} + +int sys_tgkill(int tgid, int tid, int sig) { + auto ret = do_syscall(SYS_tgkill, tgid, tid, sig); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + auto ret = do_syscall(SYS_ioctl, fd, TCGETS, attr); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int req; + + switch (optional_action) { + case TCSANOW: req = TCSETS; break; + case TCSADRAIN: req = TCSETSW; break; + case TCSAFLUSH: req = TCSETSF; break; + default: return EINVAL; + } + + auto ret = do_syscall(SYS_ioctl, fd, req, attr); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcflush(int fd, int queue) { + auto ret = do_syscall(SYS_ioctl, fd, TCFLSH, queue); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcdrain(int fd) { + auto ret = do_syscall(SYS_ioctl, fd, TCSBRK, 1); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcflow(int fd, int action) { + auto ret = do_syscall(SYS_ioctl, fd, TCXONC, action); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_access(const char *path, int mode) { + auto ret = do_syscall(SYS_faccessat, AT_FDCWD, path, mode, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + auto ret = do_syscall(SYS_faccessat, dirfd, pathname, mode, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + auto ret = do_syscall(SYS_accept4, fd, addr_ptr, addr_length, flags); + if (int e = sc_error(ret); e) + return e; + *newfd = sc_int_result(ret); + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + auto ret = do_syscall(SYS_bind, fd, addr_ptr, addr_length, 0, 0, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + auto ret = do_syscall(SYS_setsockopt, fd, layer, number, buffer, size, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + auto ret = do_syscall(SYS_getsockname, fd, addr_ptr, &max_addr_length); + if (int e = sc_error(ret); e) + return e; + *actual_length = max_addr_length; + return 0; +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + auto ret = do_syscall(SYS_getpeername, fd, addr_ptr, &max_addr_length); + if (int e = sc_error(ret); e) + return e; + *actual_length = max_addr_length; + return 0; +} + +int sys_listen(int fd, int backlog) { + auto ret = do_syscall(SYS_listen, fd, backlog, 0, 0, 0, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_shutdown(int sockfd, int how) { + auto ret = do_syscall(SYS_shutdown, sockfd, how); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_getpriority(int which, id_t who, int *value) { + auto ret = do_syscall(SYS_getpriority, which, who); + if (int e = sc_error(ret); e) { + return e; + } + *value = 20 - sc_int_result(ret); + return 0; +} + +int sys_setpriority(int which, id_t who, int prio) { + auto ret = do_syscall(SYS_setpriority, which, who, prio); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +// the first argument of the get/set priority calls is a PRIO_PROCESS constant. +// the actual macro is not used at the moment because of a wrong #define +// FIXME once the abi fix PR is merged +int sys_nice(int increment, int *new_nice) { + int current; + if (int e = sys_getpriority(0, 0, ¤t); e) + return e; + + if (increment == 0) { + *new_nice = current; + return 0; + } + + // the system call silently clamps the value to the nice range + if (int e = sys_setpriority(0, 0, current + increment); e) + return e; + + if (int e = sys_getpriority(0, 0, ¤t); e) + return e; + + // NOTE: according to man 2 getpriority, the internal priority values in linux are + // in the range 40..1. So we have to convert it. + *new_nice = 20 - current; + return 0; +} + +int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + auto ret = do_syscall(SYS_setitimer, which, new_value, old_value); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +/* Linux' uapi does some weird union stuff in place of `sigev_tid`, which we conveniently ignore */ +struct linux_uapi_sigevent { + union sigval sigev_value; + int sigev_signo; + int sigev_notify; + int sigev_tid; +}; + +namespace { + +bool timerThreadInit = false; + +struct PosixTimerContext { + int setupSem = 0; + int workerSem = 0; + sigevent *sigev; +}; + +void timer_handle(int, siginfo_t *, void *) { +} + +void *timer_setup(void *arg) { + auto ctx = reinterpret_cast(arg); + + sigset_t set; + sigaddset(&set, SIGTIMER); + + // wait for parent setup to be complete + while(__atomic_load_n(&ctx->setupSem, __ATOMIC_RELAXED) == 0); + pthread_testcancel(); + + // copy out the function and argument, as the lifetime of the context ends with + // incrementing workerSem + auto notify = ctx->sigev->sigev_notify_function; + union sigval val = ctx->sigev->sigev_value; + + // notify the parent that the context can be dropped + __atomic_store_n(&ctx->workerSem, 1, __ATOMIC_RELEASE); + + siginfo_t si; + int signo; + + while(true) { + while(sys_sigtimedwait(&set, &si, nullptr, &signo)); + if(si.si_code == SI_TIMER && signo == SIGTIMER) + notify(val); + pthread_testcancel(); + } + + return nullptr; +} + +} // namespace + +int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res) { + struct linux_uapi_sigevent ksev; + struct linux_uapi_sigevent *ksevp = nullptr; + int timer_id; + + switch(evp ? evp->sigev_notify : SIGEV_SIGNAL) { + case SIGEV_NONE: + case SIGEV_SIGNAL: + case SIGEV_THREAD_ID: { + if(evp) { + ksev.sigev_value = evp->sigev_value; + ksev.sigev_signo = evp->sigev_signo; + ksev.sigev_notify = evp->sigev_notify; + ksev.sigev_tid = (evp && evp->sigev_notify == SIGEV_THREAD_ID) ? evp->sigev_notify_thread_id : 0; + ksevp = &ksev; + } + + auto ret = do_syscall(SYS_timer_create, clk, ksevp, &timer_id); + if (int e = sc_error(ret); e) { + return e; + } + *res = (void *) (intptr_t) timer_id; + break; + } + case SIGEV_THREAD: { + if(!timerThreadInit) { + struct sigaction sa{}; + sa.sa_flags = SA_SIGINFO | SA_RESTART; + sa.sa_sigaction = timer_handle; + sys_sigaction(SIGTIMER, &sa, nullptr); + timerThreadInit = true; + } + + pthread_attr_t attr; + if(evp->sigev_notify_attributes) + attr = *evp->sigev_notify_attributes; + else + pthread_attr_init(&attr); + + int ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if(ret) + return ret; + + PosixTimerContext context{}; + context.sigev = evp; + + // mask for all signals except the libc-reserved RT signal range + sigset_t mask = { + #if ULONG_MAX == 0xFFFF'FFFF + 0x7FFF'FFFF, 0xFFFF'FFFC + #else + 0xFFFF'FFFC'7FFF'FFFF + #endif + }; + // but also mask SIGTIMER + sigaddset(&mask, SIGTIMER); + sigset_t original_set; + do_syscall(SYS_rt_sigprocmask, SIG_BLOCK, &mask, &original_set, _NSIG / 8); + + pthread_t pthread; + ret = pthread_create(&pthread, &attr, timer_setup, &context); + + // restore previous signal mask + do_syscall(SYS_rt_sigprocmask, SIG_SETMASK, &original_set, 0, _NSIG / 8); + + if(ret) + return ret; + + auto tid = reinterpret_cast(pthread)->tid; + + linux_uapi_sigevent sigev{ + .sigev_value = { .sival_ptr = nullptr }, + .sigev_signo = SIGTIMER, + .sigev_notify = SIGEV_THREAD_ID, + .sigev_tid = tid, + }; + ksevp = &sigev; + + auto syscallret = do_syscall(SYS_timer_create, clk, ksevp, &timer_id); + if (int e = sc_error(syscallret); e) { + pthread_cancel(pthread); + __atomic_store_n(&context.setupSem, 1, __ATOMIC_RELEASE); + return e; + } + + // notify worker that setup is complete + __atomic_store_n(&context.setupSem, 1, __ATOMIC_RELEASE); + // await worker setup to let the context go out of scope + while(__atomic_load_n(&context.workerSem, __ATOMIC_RELAXED) == 0); + + *res = (void *) (intptr_t) timer_id; + break; + } + default: + return EINVAL; + } + + return 0; +} + +int sys_timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old) { + auto ret = do_syscall(SYS_timer_settime, t, flags, val, old); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_timer_gettime(timer_t t, struct itimerspec *val) { + auto ret = do_syscall(SYS_timer_gettime, t, val); + if (int e = sc_error(ret); e) + return e; + + return 0; +} + +int sys_timer_delete(timer_t t) { + __ensure((intptr_t) t >= 0); + auto ret = do_syscall(SYS_timer_delete, t); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out) { + auto ret = do_syscall(SYS_ptrace, req, pid, addr, data); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_open_dir(const char *path, int *fd) { + return sys_open(path, O_DIRECTORY, 0, fd); +} + +int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read) { + auto ret = do_syscall(SYS_getdents64, handle, buffer, max_size); + if(int e = sc_error(ret); e) + return e; + *bytes_read = sc_int_result(ret); + return 0; +} + +int sys_prctl(int op, va_list ap, int *out) { + unsigned long x[4]; + for(int i = 0; i < 4; i++) + x[i] = va_arg(ap, unsigned long); + + auto ret = do_syscall(SYS_prctl, op, x[0], x[1], x[2], x[3]); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_uname(struct utsname *buf) { + auto ret = do_syscall(SYS_uname, buf); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_gethostname(char *buf, size_t bufsize) { + struct utsname uname_buf; + if (auto e = sys_uname(&uname_buf); e) + return e; + + auto node_len = strlen(uname_buf.nodename); + if (node_len >= bufsize) + return ENAMETOOLONG; + + memcpy(buf, uname_buf.nodename, node_len); + buf[node_len] = '\0'; + return 0; +} + +int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + auto ret = do_syscall(SYS_pread64, fd, buf, n, off); + if (int e = sc_error(ret); e) + return e; + *bytes_read = sc_int_result(ret); + return 0; +} + +int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { + auto ret = do_syscall(SYS_pwrite64, fd, buf, n, off); + if (int e = sc_error(ret); e) + return e; + *bytes_written = sc_int_result(ret); + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec tm; + tm.tv_sec = timeout / 1000; + tm.tv_nsec = timeout % 1000 * 1000000; + auto ret = do_syscall(SYS_ppoll, fds, count, timeout >= 0 ? &tm : nullptr, 0, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + *num_events = sc_int_result(ret); + return 0; +} + +int sys_getrusage(int scope, struct rusage *usage) { + auto ret = do_syscall(SYS_getrusage, scope, usage); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_madvise(void *addr, size_t length, int advice) { + auto ret = do_syscall(SYS_madvise, addr, length, advice); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_posix_madvise(void *addr, size_t length, int advice) { + if(advice == POSIX_MADV_DONTNEED) { + // POSIX_MADV_DONTNEED is a no-op in both glibc and musl. + return 0; + } + switch(advice) { + case POSIX_MADV_NORMAL: + advice = MADV_NORMAL; + break; + case POSIX_MADV_RANDOM: + advice = MADV_RANDOM; + break; + case POSIX_MADV_SEQUENTIAL: + advice = MADV_SEQUENTIAL; + break; + case POSIX_MADV_WILLNEED: + advice = MADV_WILLNEED; + break; + default: + return EINVAL; + } + return sys_madvise(addr, length, advice); +} + +int sys_msync(void *addr, size_t length, int flags) { + auto ret = do_syscall(SYS_msync, addr, length, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_swapon(const char *path, int flags) { + auto ret = do_syscall(SYS_swapon, path, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_swapoff(const char *path) { + auto ret = do_syscall(SYS_swapoff, path); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { + auto ret = do_syscall(SYS_sched_getaffinity, pid, cpusetsize, mask); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data) { + auto ret = do_syscall(SYS_mount, source, target, fstype, flags, data); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_umount2(const char *target, int flags) { + auto ret = do_syscall(SYS_umount2, target, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sethostname(const char *buffer, size_t bufsize) { + auto ret = do_syscall(SYS_sethostname, buffer, bufsize); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_epoll_create(int flags, int *fd) { + auto ret = do_syscall(SYS_epoll_create1, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + auto ret = do_syscall(SYS_epoll_ctl, epfd, mode, fd, ev); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, const sigset_t *sigmask, int *raised) { + auto ret = do_syscall(SYS_epoll_pwait, epfd, ev, n, timeout, sigmask, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + *raised = sc_int_result(ret); + return 0; +} + +int sys_eventfd_create(unsigned int initval, int flags, int *fd) { + auto ret = do_syscall(SYS_eventfd2, initval, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_signalfd_create(const sigset_t *masks, int flags, int *fd) { + auto ret = do_syscall(SYS_signalfd4, *fd, masks, NSIG / 8, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_timerfd_create(int clockid, int flags, int *fd) { + auto ret = do_syscall(SYS_timerfd_create, clockid, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_timerfd_settime(int fd, int flags, const struct itimerspec *value, struct itimerspec *oldvalue) { + auto ret = do_syscall(SYS_timerfd_settime, fd, flags, value, oldvalue); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_timerfd_gettime(int fd, struct itimerspec *its) { + auto ret = do_syscall(SYS_timerfd_gettime, fd, its); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_inotify_create(int flags, int *fd) { + auto ret = do_syscall(SYS_inotify_init1, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_init_module(void *module, unsigned long length, const char *args) { + auto ret = do_syscall(SYS_init_module, module, length, args); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_delete_module(const char *name, unsigned flags) { + auto ret = do_syscall(SYS_delete_module, name, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_klogctl(int type, char *bufp, int len, int *out) { + auto ret = do_syscall(SYS_syslog, type, bufp, len); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_getcpu(int *cpu) { + auto ret = do_syscall(SYS_getcpu, cpu, NULL, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + auto ret = do_syscall(SYS_socketpair, domain, type_and_flags, proto, fds, 0, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { + auto ret = do_syscall(SYS_getsockopt, fd, layer, number, buffer, size, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd) { + auto ret = do_syscall(SYS_inotify_add_watch, ifd, path, mask); + if (int e = sc_error(ret); e) + return e; + *wd = sc_int_result(ret); + return 0; +} + +int sys_inotify_rm_watch(int ifd, int wd) { + auto ret = do_syscall(SYS_inotify_rm_watch, ifd, wd); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_ttyname(int fd, char *buf, size_t size) { + if (!isatty(fd)) + return errno; + + char *procname; + if(int e = asprintf(&procname, "/proc/self/fd/%i", fd); e) + return ENOMEM; + __ensure(procname); + + ssize_t l = readlink(procname, buf, size); + free(procname); + + if (l < 0) + return errno; + else if ((size_t)l >= size) + return ERANGE; + + buf[l] = '\0'; + struct stat st1; + struct stat st2; + + if (stat(buf, &st1) || fstat(fd, &st2)) + return errno; + if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) + return ENODEV; + + return 0; +} + +int sys_pause() { +#ifdef SYS_pause + auto ret = do_syscall(SYS_pause); +#else + auto ret = do_syscall(SYS_ppoll, 0, 0, 0, 0); +#endif + if (int e = sc_error(ret); e) + return e; + return EINTR; +} + +int sys_mlockall(int flags) { + auto ret = do_syscall(SYS_mlockall, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_get_min_priority(int policy, int *out) { + auto ret = do_syscall(SYS_sched_get_priority_min, policy); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + + return 0; +} + +int sys_getschedparam(void *tcb, int *policy, struct sched_param *param) { + auto t = reinterpret_cast(tcb); + + if(!t->tid) { + return ESRCH; + } + + auto ret_param = do_syscall(SYS_sched_getparam, t->tid, param); + if (int e = sc_error(ret_param); e) + return e; + + auto ret_sched = do_syscall(SYS_sched_getscheduler, t->tid, param); + if (int e = sc_error(ret_sched); e) + return e; + *policy = sc_int_result(ret_sched); + + return 0; +} + +int sys_setschedparam(void *tcb, int policy, const struct sched_param *param) { + auto t = reinterpret_cast(tcb); + + if(!t->tid) { + return ESRCH; + } + + auto ret = do_syscall(SYS_sched_setscheduler, t->tid, policy, param); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getparam(pid_t pid, struct sched_param *param) { + auto ret = do_syscall(SYS_sched_getparam, pid, param); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setparam(pid_t pid, const struct sched_param *param) { + auto ret = do_syscall(SYS_sched_setparam, pid, param); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_if_indextoname(unsigned int index, char *name) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if(r) + return r; + + struct ifreq ifr; + ifr.ifr_ifindex = index; + + int ret = sys_ioctl(fd, SIOCGIFNAME, &ifr, nullptr); + close(fd); + + if(ret) { + if(ret == ENODEV) + return ENXIO; + return ret; + } + + strncpy(name, ifr.ifr_name, IF_NAMESIZE); + + return 0; +} + +int sys_if_nametoindex(const char *name, unsigned int *ret) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if(r) + return r; + + struct ifreq ifr; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + + r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, nullptr); + close(fd); + + if(r) { + return r; + } + + *ret = ifr.ifr_ifindex; + + return 0; +} + +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if(int e = sys_ioctl(fd, TIOCGPTN, &index, nullptr); e) + return e; + if((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +int sys_unlockpt(int fd) { + int unlock = 0; + + if(int e = sys_ioctl(fd, TIOCSPTLCK, &unlock, nullptr); e) + return e; + + return 0; +} + +int sys_thread_setname(void *tcb, const char *name) { + if(strlen(name) > 15) { + return ERANGE; + } + + auto t = reinterpret_cast(tcb); + char *path; + int cs = 0; + + if(asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) { + return ENOMEM; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + int fd; + if(int e = sys_open(path, O_WRONLY, 0, &fd); e) { + return e; + } + + if(int e = sys_write(fd, name, strlen(name) + 1, nullptr)) { + return e; + } + + sys_close(fd); + + pthread_setcancelstate(cs, nullptr); + + return 0; +} + +int sys_thread_getname(void *tcb, char *name, size_t size) { + auto t = reinterpret_cast(tcb); + char *path; + int cs = 0; + ssize_t real_size = 0; + + if(asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) { + return ENOMEM; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + int fd; + if(int e = sys_open(path, O_RDONLY | O_CLOEXEC, 0, &fd); e) { + return e; + } + + if(int e = sys_read(fd, name, size, &real_size)) { + return e; + } + + name[real_size - 1] = 0; + sys_close(fd); + + pthread_setcancelstate(cs, nullptr); + + if(static_cast(size) <= real_size) { + return ERANGE; + } + + return 0; +} + +int sys_mlock(const void *addr, size_t length) { + auto ret = do_syscall(SYS_mlock, addr, length); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_munlock(const void *addr, size_t length) { + auto ret = do_syscall(SYS_munlock, addr, length); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_munlockall(void) { + auto ret = do_syscall(SYS_munlockall); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mincore(void *addr, size_t length, unsigned char *vec) { + auto ret = do_syscall(SYS_mincore, addr, length, vec); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_memfd_create(const char *name, int flags, int *fd) { + auto ret = do_syscall(SYS_memfd_create, name, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_fallocate(int fd, off_t offset, size_t size) { + auto ret = do_syscall(SYS_fallocate, fd, 0, offset, size); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_flock(int fd, int options) { + auto ret = do_syscall(SYS_flock, fd, options); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_seteuid(uid_t euid) { + return sys_setresuid(-1, euid, -1); +} + +int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window) { + auto ret = do_syscall(SYS_mremap, pointer, size, new_size, MREMAP_MAYMOVE); + // TODO: musl fixes up EPERM errors from the kernel. + if(int e = sc_error(ret); e) + return e; + *window = sc_ptr_result(ret); + return 0; +} + +int sys_link(const char *old_path, const char *new_path) { +#ifdef SYS_link + auto ret = do_syscall(SYS_link, old_path, new_path); + if (int e = sc_error(ret); e) + return e; + return 0; +#else + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); +#endif +} + +int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + auto ret = do_syscall(SYS_linkat, olddirfd, old_path, newdirfd, new_path, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +// Inspired by musl (src/stat/statvfs.c:28 fixup function) +static void statfs_to_statvfs(struct statfs *from, struct statvfs *to) { + *to = { + .f_bsize = from->f_bsize, + .f_frsize = from->f_frsize ? from->f_frsize : from->f_bsize, + .f_blocks = from->f_blocks, + .f_bfree = from->f_bfree, + .f_bavail = from->f_bavail, + .f_files = from->f_files, + .f_ffree = from->f_ffree, + .f_favail = from->f_ffree, + .f_fsid = (unsigned long) from->f_fsid.__val[0], + .f_flag = from->f_flags, + .f_namemax = from->f_namelen, + }; +} + +int sys_statvfs(const char *path, struct statvfs *out) { + struct statfs buf; + if(auto ret = sys_statfs(path, &buf); ret != 0) { + return ret; + } + statfs_to_statvfs(&buf, out); + return 0; +} + +int sys_fstatvfs(int fd, struct statvfs *out) { + struct statfs buf; + if(auto ret = sys_fstatfs(fd, &buf); ret != 0) { + return ret; + } + statfs_to_statvfs(&buf, out); + return 0; +} + +int sys_sysconf(int num, long *ret) { + switch(num) { + case _SC_OPEN_MAX: { + struct rlimit ru; + if(int e = sys_getrlimit(RLIMIT_NOFILE, &ru); e) { + return e; + } + *ret = (ru.rlim_cur == RLIM_INFINITY) ? -1 : ru.rlim_cur; + break; + } + case _SC_NPROCESSORS_ONLN: { + cpu_set_t set; + CPU_ZERO(&set); + if(int e = sys_getaffinity(0, sizeof(set), &set); e) { + return e; + } + *ret = CPU_COUNT(&set); + break; + } + case _SC_PHYS_PAGES: { + struct sysinfo info; + if(int e = sys_sysinfo(&info); e) { + return e; + } + unsigned unit = (info.mem_unit) ? info.mem_unit : 1; + *ret = std::min(long((info.totalram * unit) / PAGE_SIZE), LONG_MAX); + break; + } + case _SC_CHILD_MAX: { + struct rlimit ru; + if(int e = sys_getrlimit(RLIMIT_NPROC, &ru); e) { + return e; + } + *ret = (ru.rlim_cur == RLIM_INFINITY) ? -1 : ru.rlim_cur; + break; + } + case _SC_LINE_MAX: { + *ret = -1; + break; + } + default: { + return EINVAL; + } + } + + return 0; +} + +int sys_semget(key_t key, int n, int fl, int *id) { + auto ret = do_syscall(SYS_semget, key, n, fl); + if(int e = sc_error(ret); e) + return e; + *id = sc_int_result(ret); + return 0; +} + +int sys_semctl(int semid, int semnum, int cmd, void *semun, int *out) { + auto ret = do_syscall(SYS_semctl, semid, semnum, cmd | IPC_64, semun); + if(int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) { + auto ret = do_syscall(SYS_waitid, idtype, id, info, options, 0); + if(int e = sc_error(ret); e) + return e; + return sc_int_result(ret); +} + +int sys_clock_set(int clock, time_t secs, long nanos) { + struct timespec tp{}; + tp.tv_sec = secs; + tp.tv_nsec = nanos; + auto ret = do_syscall(SYS_clock_settime, clock, &tp); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +#endif // __MLIBC_POSIX_OPTION + +#if __MLIBC_LINUX_OPTION + +#include + +int sys_reboot(int cmd) { + auto ret = do_syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, nullptr); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getifaddrs(struct ifaddrs **out) { + *out = nullptr; + + NetlinkHelper nl; + bool link_ret = nl.send_request(RTM_GETLINK) && nl.recv(&getifaddrs_callback, out); + __ensure(link_ret); + bool addr_ret = nl.send_request(RTM_GETADDR) && nl.recv(&getifaddrs_callback, out); + __ensure(addr_ret); + + return 0; +} + +int sys_pidfd_open(pid_t pid, unsigned int flags, int *outfd) { + auto ret = do_syscall(SYS_pidfd_open, pid, flags); + if (int e = sc_error(ret); e) + return e; + *outfd = sc_int_result(ret); + return 0; +} + +namespace { + +char *pidfdGetPidLine = nullptr; +size_t pidfdGetPidLineSize = 0; + +} // namespace + +int sys_pidfd_getpid(int fd, pid_t *outpid) { + char *path = nullptr; + asprintf(&path, "/proc/self/fdinfo/%d", fd); + + FILE *fdinfo = fopen(path, "r"); + if (!fdinfo) + return errno; + + while (getline(&pidfdGetPidLine, &pidfdGetPidLineSize, fdinfo) != -1) { + pid_t pid; + int ret = sscanf(pidfdGetPidLine, "Pid: %d\n", &pid); + + if(ret != 1) + continue; + + if (pid == 0) + return EREMOTE; + else if (pid == -1) + return ESRCH; + + *outpid = pid; + return 0; + } + + free(path); + return EBADF; +} + +int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags) { + auto ret = do_syscall(SYS_pidfd_send_signal, pidfd, sig, info, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_process_vm_readv(pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags, ssize_t *out) { + auto ret = do_syscall(SYS_process_vm_readv, pid, local_iov, liovcnt, + remote_iov, riovcnt, flags); + if(int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_process_vm_writev(pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags, ssize_t *out) { + auto ret = do_syscall(SYS_process_vm_writev, pid, local_iov, liovcnt, + remote_iov, riovcnt, flags); + if(int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_ppoll(struct pollfd *fds, nfds_t count, const struct timespec *ts, const sigset_t *mask, int *num_events) { + auto ret = do_syscall(SYS_ppoll, fds, count, ts, mask, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + *num_events = sc_int_result(ret); + return 0; +} + +#endif // __MLIBC_LINUX_OPTION + +int sys_times(struct tms *tms, clock_t *out) { + auto ret = do_syscall(SYS_times, tms); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +pid_t sys_getpid() { + auto ret = do_syscall(SYS_getpid); + // getpid() always succeeds. + return sc_int_result(ret); +} + +pid_t sys_gettid() { + auto ret = do_syscall(SYS_gettid); + // gettid() always succeeds. + return sc_int_result(ret); +} + +uid_t sys_getuid() { + auto ret = do_syscall(SYS_getuid); + // getuid() always succeeds. + return sc_int_result(ret); +} + +uid_t sys_geteuid() { + auto ret = do_syscall(SYS_geteuid); + // geteuid() always succeeds. + return sc_int_result(ret); +} + +gid_t sys_getgid() { + auto ret = do_syscall(SYS_getgid); + // getgid() always succeeds. + return sc_int_result(ret); +} + +gid_t sys_getegid() { + auto ret = do_syscall(SYS_getegid); + // getegid() always succeeds. + return sc_int_result(ret); +} + +int sys_kill(int pid, int sig) { + auto ret = do_syscall(SYS_kill, pid, sig); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +void sys_thread_exit() { + do_syscall(SYS_exit, 0); + __builtin_trap(); +} + +void sys_exit(int status) { + do_syscall(SYS_exit_group, status); + __builtin_trap(); +} + +#endif // MLIBC_BUILDING_RTLD + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +int sys_futex_tid() { + auto ret = do_syscall(SYS_gettid); + // gettid() always succeeds. + return sc_int_result(ret); +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + auto ret = do_cp_syscall(SYS_futex, pointer, FUTEX_WAIT, expected, time); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_futex_wake(int *pointer) { + auto ret = do_syscall(SYS_futex, pointer, FUTEX_WAKE, INT_MAX); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sigsuspend(const sigset_t *set) { + auto ret = do_syscall(SYS_rt_sigsuspend, set, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + auto ret = do_syscall(SYS_sigaltstack, ss, oss); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mkdir(const char *path, mode_t mode) { + auto ret = do_syscall(SYS_mkdirat, AT_FDCWD, path, mode); + if (int e = sc_error(ret); e) + return e; + return 0; +} + + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + auto ret = do_syscall(SYS_mkdirat, dirfd, path, mode); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mknodat(int dirfd, const char *path, int mode, int dev) { + auto ret = do_syscall(SYS_mknodat, dirfd, path, mode, dev); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mkfifoat(int dirfd, const char *path, mode_t mode) { + return sys_mknodat(dirfd, path, mode | S_IFIFO, 0); +} + +int sys_symlink(const char *target_path, const char *link_path) { + auto ret = do_syscall(SYS_symlinkat, target_path, AT_FDCWD, link_path); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + auto ret = do_syscall(SYS_symlinkat, target_path, dirfd, link_path); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_umask(mode_t mode, mode_t *old) { + auto ret = do_syscall(SYS_umask, mode); + if (int e = sc_error(ret); e) + return e; + *old = sc_int_result(ret); + return 0; +} + +int sys_chdir(const char *path) { + auto ret = do_syscall(SYS_chdir, path); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fchdir(int fd) { + auto ret = do_syscall(SYS_fchdir, fd); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_rename(const char *old_path, const char *new_path) { + return sys_renameat(AT_FDCWD, old_path, AT_FDCWD, new_path); +} + +int sys_renameat(int old_dirfd, const char *old_path, int new_dirfd, const char *new_path) { +#ifdef SYS_renameat2 + auto ret = do_syscall(SYS_renameat2, old_dirfd, old_path, new_dirfd, new_path, 0); +#else + auto ret = do_syscall(SYS_renameat, old_dirfd, old_path, new_dirfd, new_path); +#endif /* defined(SYS_renameat2) */ + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_rmdir(const char *path) { + auto ret = do_syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_ftruncate(int fd, size_t size) { + auto ret = do_syscall(SYS_ftruncate, fd, size); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_readlink(const char *path, void *buf, size_t bufsiz, ssize_t *len) { + auto ret = do_syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsiz); + if (int e = sc_error(ret); e) + return e; + *len = sc_int_result(ret); + return 0; +} + +#if __MLIBC_BSD_OPTION +// getloadavg() adapted from musl +int sys_getloadavg(double *samples) { + struct sysinfo si; + if (int e = sys_sysinfo(&si); e) + return e; + for (int i = 0; i < 3; i++) + samples[i] = 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[i]; + return 0; +} +#endif /* __MLIBC_BSD_OPTION */ + +int sys_getrlimit(int resource, struct rlimit *limit) { + auto ret = do_syscall(SYS_prlimit64, 0, resource, 0, limit); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setrlimit(int resource, const struct rlimit *limit) { + auto ret = do_syscall(SYS_prlimit64, 0, resource, limit, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +pid_t sys_getppid() { + auto ret = do_syscall(SYS_getppid); + // getppid() always succeeds. + return sc_int_result(ret); +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + auto ret = do_syscall(SYS_setpgid, pid, pgid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getsid(pid_t pid, pid_t *sid) { + auto ret = do_syscall(SYS_getsid, pid); + if (int e = sc_error(ret); e) + return e; + *sid = sc_int_result(ret); + return 0; +} + +int sys_setsid(pid_t *sid) { + auto ret = do_syscall(SYS_setsid); + if (int e = sc_error(ret); e) + return e; + *sid = sc_int_result(ret); + return 0; +} + +int sys_setuid(uid_t uid) { + auto ret = do_syscall(SYS_setuid, uid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setgid(gid_t gid) { + auto ret = do_syscall(SYS_setgid, gid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getpgid(pid_t pid, pid_t *out) { + auto ret = do_syscall(SYS_getpgid, pid); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_getgroups(size_t size, gid_t *list, int *retval) { + auto ret = do_syscall(SYS_getgroups, size, list); + if (int e = sc_error(ret); e) + return e; + *retval = sc_int_result(ret); + return 0; +} + +int sys_dup(int fd, int flags, int *newfd) { + __ensure(!flags); + auto ret = do_cp_syscall(SYS_dup, fd); + if (int e = sc_error(ret); e) + return e; + *newfd = sc_int_result(ret); + return 0; +} + +void sys_sync() { + do_syscall(SYS_sync); +} + +int sys_fsync(int fd) { + auto ret = do_syscall(SYS_fsync, fd); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fdatasync(int fd) { + auto ret = do_syscall(SYS_fdatasync, fd); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getrandom(void *buffer, size_t length, int flags, ssize_t *bytes_written) { + auto ret = do_syscall(SYS_getrandom, buffer, length, flags); + if (int e = sc_error(ret); e) + return e; + *bytes_written = sc_int_result(ret); + return 0; +} + +int sys_getentropy(void *buffer, size_t length) { + ssize_t written; + return sys_getrandom(buffer, length, 0, &written); +} + +int sys_setxattr(const char *path, const char *name, const void *val, + size_t size, int flags) { + auto ret = do_syscall(SYS_setxattr, path, name, val, size, flags); + return sc_error(ret); +} + +int sys_lsetxattr(const char *path, const char *name, const void *val, + size_t size, int flags) { + auto ret = do_syscall(SYS_lsetxattr, path, name, val, size, flags); + return sc_error(ret); +} + +int sys_fsetxattr(int fd, const char *name, const void *val, + size_t size, int flags) { + auto ret = do_syscall(SYS_fsetxattr, fd, name, val, size, flags); + return sc_error(ret); +} + +int sys_getxattr(const char *path, const char *name, void *val, size_t size, + ssize_t *nread) { + auto ret = do_syscall(SYS_getxattr, path, name, val, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_lgetxattr(const char *path, const char *name, void *val, size_t size, + ssize_t *nread) { + auto ret = do_syscall(SYS_lgetxattr, path, name, val, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_fgetxattr(int fd, const char *name, void *val, size_t size, + ssize_t *nread) { + auto ret = do_syscall(SYS_fgetxattr, fd, name, val, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_removexattr(const char *path, const char *name) { + auto ret = do_syscall(SYS_removexattr, path, name); + return sc_error(ret); +} + +int sys_lremovexattr(const char *path, const char *name) { + auto ret = do_syscall(SYS_lremovexattr, path, name); + return sc_error(ret); +} + +int sys_fremovexattr(int fd, const char *name) { + auto ret = do_syscall(SYS_fremovexattr, fd, name); + return sc_error(ret); +} + +int sys_listxattr(const char *path, char *list, size_t size, ssize_t *nread) { + auto ret = do_syscall(SYS_listxattr, path, list, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_llistxattr(const char *path, char *list, size_t size, ssize_t *nread) { + auto ret = do_syscall(SYS_llistxattr, path, list, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_flistxattr(int fd, char *list, size_t size, ssize_t *nread) { + auto ret = do_syscall(SYS_flistxattr, fd, list, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal) { + auto ret = do_syscall(SYS_rt_sigtimedwait, set, info, timeout, NSIG / 8); + + if (int e = sc_error(ret); e) + return e; + + *out_signal = sc_int_result(ret); + + return 0; +} + +int sys_sendfile(int outfd, int infd, off_t *offset, size_t count, ssize_t *out) { + auto ret = do_syscall(SYS_sendfile, outfd, infd, offset, count); + if(int e = sc_error(ret); e) { + return e; + } + *out = sc_int_result(ret); + return 0; +} + +int sys_syncfs(int fd) { + auto ret = do_syscall(SYS_syncfs, fd); + if(int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_name_to_handle_at(int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags) { + auto ret = do_syscall(SYS_name_to_handle_at, dirfd, pathname, handle, mount_id, flags); + if (int e = sc_error(ret); e) + return e; + return sc_int_result(ret); +} + +int sys_splice(int in_fd, off_t *in_off, int out_fd, off_t *out_off, size_t size, unsigned int flags, ssize_t *out) { + auto ret = do_syscall(SYS_copy_file_range, in_fd, in_off, out_fd, out_off, size, flags); + if(int e = sc_error(ret); e) { + return e; + } + *out = sc_int_result(ret); + return 0; +} + +int sys_unshare(int flags) { + auto ret = do_syscall(SYS_unshare, flags); + if(int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_setns(int fd, int nstype) { + auto ret = do_syscall(SYS_setns, fd, nstype); + if(int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_setgroups(size_t size, const gid_t *list) { + auto ret = do_syscall(SYS_setgroups, size, list); + if(int e = sc_error(ret); e) { + return e; + } + return 0; +} + +#if __MLIBC_BSD_OPTION +int sys_brk(void **out) { + auto ret = do_syscall(SYS_brk, 0); + if(int e = sc_error(ret); e) { + return e; + } + + *out = (void *) sc_int_result(ret); + return 0; +} +#endif // __MLIBC_BSD_OPTION + +#if __MLIBC_GLIBC_OPTION + +int sys_personality(unsigned long persona, int *out) { + auto ret = do_syscall(SYS_personality, persona); + + if(int e = sc_error(ret); e) { + return e; + } + + *out = sc_int_result(ret); + return 0; +} + +int sys_ioperm(unsigned long int from, unsigned long int num, int turn_on) { +#if defined(SYS_ioperm) + auto ret = do_syscall(SYS_ioperm, from, num, turn_on); + + if(int e = sc_error(ret); e) { + return e; + } + + return 0; +#else + (void) from; + (void) num; + (void) turn_on; + return ENOSYS; +#endif +} + +int sys_iopl(int level) { +#if defined(SYS_iopl) + auto ret = do_syscall(SYS_iopl, level); + + if(int e = sc_error(ret); e) { + return e; + } + + return 0; +#else + (void) level; + return ENOSYS; +#endif +} + +#endif // __MLIBC_GLIBC_OPTION + +#if __MLIBC_POSIX_OPTION + +int sys_shmat(void **seg_start, int shmid, const void *shmaddr, int shmflg) { + auto ret = do_syscall(SYS_shmat, shmid, shmaddr, shmflg); + if (int e = sc_error(ret); e) + return e; + *seg_start = sc_ptr_result(ret); + return 0; +} + +int sys_shmctl(int *idx, int shmid, int cmd, struct shmid_ds *buf) { + auto ret = do_syscall(SYS_shmctl, shmid, cmd, buf); + if (int e = sc_error(ret); e) + return e; + *idx = sc_int_result(ret); + return 0; +} + +int sys_shmdt(const void *shmaddr) { + auto ret = do_syscall(SYS_shmdt, shmaddr); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_shmget(int *shm_id, key_t key, size_t size, int shmflg) { + auto ret = do_syscall(SYS_shmget, key, size, shmflg); + if (int e = sc_error(ret); e) + return e; + *shm_id = sc_int_result(ret); + return 0; +} + +#if !defined(MLIBC_BUILDING_RTLD) +int sys_inet_configured(bool *ipv4, bool *ipv6) { + struct context { + bool *ipv4; + bool *ipv6; + } context = { + .ipv4 = ipv4, + .ipv6 = ipv6 + }; + + NetlinkHelper nl; + if (!nl.send_request(RTM_GETADDR)) { + *ipv4 = false; + *ipv6 = false; + return 0; + } + + auto ret = nl.recv([](void *data, const nlmsghdr *hdr) { + if (hdr->nlmsg_type == RTM_NEWADDR || hdr->nlmsg_len >= sizeof(struct ifaddrmsg)) { + const struct ifaddrmsg *ifaddr = reinterpret_cast(NLMSG_DATA(hdr)); + struct context *ctx = reinterpret_cast(data); + + char name[IF_NAMESIZE]; + auto interfaceNameResult = sys_if_indextoname(ifaddr->ifa_index, name); + + if (interfaceNameResult || !strncmp(name, "lo", IF_NAMESIZE)) + return; + + if (ifaddr->ifa_family == AF_INET) + *ctx->ipv4 = true; + else if (ifaddr->ifa_family == AF_INET6) + *ctx->ipv6 = true; + } + }, &context); + + if (!ret) { + *ipv4 = false; + *ipv6 = false; + return 0; + } + + return 0; +} +#endif // !defined(MLIBC_BUILDING_RTLD) + +#endif // __MLIBC_POSIX_OPTION + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/linux/generic/thread.cpp b/user/include/mlibc/sysdeps/linux/generic/thread.cpp new file mode 100644 index 0000000..e413e4f --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/generic/thread.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg) { + // The linux kernel already sets the TCB in sys_clone(). + auto tcb = mlibc::get_current_tcb(); + + // Wait until our parent sets up the TID. + while(!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + tcb->invokeThreadFunc(entry, user_arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + (void)tcb; + if (!*stack_size) + *stack_size = default_stacksize; + + uintptr_t map; + if (*stack) { + map = reinterpret_cast(*stack); + *guard_size = 0; + } else { + map = reinterpret_cast( + mmap(nullptr, *stack_size + *guard_size, + PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) + ); + if (reinterpret_cast(map) == MAP_FAILED) + return EAGAIN; + int ret = mprotect(reinterpret_cast(map + *guard_size), *stack_size, + PROT_READ | PROT_WRITE); + if(ret) + return EAGAIN; + } + + *stack_base = reinterpret_cast(map); + auto sp = reinterpret_cast(map + *guard_size + *stack_size); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/linux/include-internal/linux/unistd.h b/user/include/mlibc/sysdeps/linux/include-internal/linux/unistd.h new file mode 100644 index 0000000..6a8020e --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include-internal/linux/unistd.h @@ -0,0 +1,2 @@ +/* stub header not present in practice, redirects to our internal syscallnos */ +#include diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/access.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/access.h new file mode 100755 index 0000000..cb83931 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/auxv.h new file mode 100755 index 0000000..c43f878 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..0b0ec27 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..7dc8d7c --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..6a42da5 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/dev_t.h new file mode 100755 index 0000000..bca881e --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/epoll.h new file mode 100755 index 0000000..eb4b76d --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/errno.h new file mode 100755 index 0000000..6e507de --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/fcntl.h new file mode 100755 index 0000000..463e2c9 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/gid_t.h new file mode 100755 index 0000000..abce6d6 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/in.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/in.h new file mode 100755 index 0000000..418d1d5 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/ino_t.h new file mode 100755 index 0000000..4c20aca --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/inotify.h new file mode 100755 index 0000000..b5cb282 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/ipc.h new file mode 100755 index 0000000..2c7ffc4 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/linux/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/limits.h new file mode 100755 index 0000000..6c88db2 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5d78fdf --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..bb3b625 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/packet.h new file mode 100755 index 0000000..998ef1a --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/pid_t.h new file mode 100755 index 0000000..baa90f6 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/poll.h new file mode 100755 index 0000000..8ea6a0a --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/ptrace.h new file mode 100755 index 0000000..b2517b2 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/random.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/random.h new file mode 100755 index 0000000..83fc3d9 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/random.h @@ -0,0 +1 @@ +../../../../abis/linux/random.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/reboot.h new file mode 100755 index 0000000..77013a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/resource.h new file mode 100755 index 0000000..88d7402 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/riscv-hwprobe.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/riscv-hwprobe.h new file mode 100755 index 0000000..e651325 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/riscv-hwprobe.h @@ -0,0 +1 @@ +../../../../abis/linux/riscv-hwprobe.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..e92eb5f --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/linux/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..df7bccf --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/shm.h new file mode 100755 index 0000000..067d8c4 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/sigevent.h new file mode 100755 index 0000000..83d069b --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/linux/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/signal.h new file mode 100755 index 0000000..4dcb0b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/socket.h new file mode 100755 index 0000000..f1dc016 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/stat.h new file mode 100755 index 0000000..1f63b41 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/time.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/time.h new file mode 100755 index 0000000..2a02625 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/uid_t.h new file mode 100755 index 0000000..b306777 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/utsname.h new file mode 100755 index 0000000..b285754 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..bbe258c --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/vt.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/vt.h new file mode 100755 index 0000000..5798a4a --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/vt.h @@ -0,0 +1 @@ +../../../../abis/linux/vt.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/linux/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/linux/include/bits/syscall.h b/user/include/mlibc/sysdeps/linux/include/bits/syscall.h new file mode 100644 index 0000000..680bb8c --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/bits/syscall.h @@ -0,0 +1,100 @@ +#ifndef _MLIBC_SYSCALL_H +#define _MLIBC_SYSCALL_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long __sc_word_t; + +/* These functions are implemented in arch-syscall.cpp. */ +__sc_word_t __do_syscall0(long); +__sc_word_t __do_syscall1(long, __sc_word_t); +__sc_word_t __do_syscall2(long, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall3(long, __sc_word_t, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall4(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall5(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t); +__sc_word_t __do_syscall6(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall7(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t, __sc_word_t, __sc_word_t); +long __do_syscall_ret(unsigned long); + +#ifdef __cplusplus +extern "C++" { + +/* Defining a syscall as a macro is more problematic in C++, since there's a high chance of + * a name collision e.g foo.syscall() or foo::syscall. + */ +inline long syscall(long n) { + return __do_syscall_ret(__do_syscall0(n)); +} +template +long syscall(long n, Arg0 a0) { + return __do_syscall_ret(__do_syscall1(n, (long)a0)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1) { + return __do_syscall_ret(__do_syscall2(n, (long)a0, (long)a1)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2) { + return __do_syscall_ret(__do_syscall3(n, (long)a0, (long)a1, (long)a2)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3) { + return __do_syscall_ret(__do_syscall4(n, (long)a0, (long)a1, (long)a2, (long)a3)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) { + return __do_syscall_ret(__do_syscall5(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) { + return __do_syscall_ret(__do_syscall6(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4, (long)a5)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) { + return __do_syscall_ret(__do_syscall7(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4, (long)a5, (long)a6)); +} + +} /* extern C++ */ +#else + +/* + * Variadic macros are not supported in C89. + * glibc implements syscall() as a variadic function, which we've ruled out. + * musl uses them without checking the C standard in use. So suppressing + * the check here seems reasonable. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" + +/* These syscall macros were copied from musl. */ +#define __scc(x) ((__sc_word_t)(x)) +#define __syscall0(n) __do_syscall0(n) +#define __syscall1(n,a) __do_syscall1(n,__scc(a)) +#define __syscall2(n,a,b) __do_syscall2(n,__scc(a),__scc(b)) +#define __syscall3(n,a,b,c) __do_syscall3(n,__scc(a),__scc(b),__scc(c)) +#define __syscall4(n,a,b,c,d) __do_syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d)) +#define __syscall5(n,a,b,c,d,e) __do_syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) +#define __syscall6(n,a,b,c,d,e,f) __do_syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#define __syscall7(n,a,b,c,d,e,f,g) __do_syscall7(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f),__scc(g)) +#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n +#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,) +#define __SYSCALL_CONCAT_X(a,b) a##b +#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b) +#define __SYSCALL_DISP(b,...) __SYSCALL_CONCAT(b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) +#define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__) +#define syscall(...) __do_syscall_ret(__syscall(__VA_ARGS__)) + +#pragma GCC diagnostic pop + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _MLIBC_SYSCALL_H */ diff --git a/user/include/mlibc/sysdeps/linux/include/bits/syscall_aliases.h b/user/include/mlibc/sysdeps/linux/include/bits/syscall_aliases.h new file mode 100644 index 0000000..236a0e2 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/bits/syscall_aliases.h @@ -0,0 +1,1856 @@ +#ifndef __MLIBC_SYSCALL_ALIAS_BIT +#define __MLIBC_SYSCALL_ALIAS_BIT +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#ifdef __NR__llseek +# define SYS__llseek __NR__llseek +#endif +#ifdef __NR__newselect +# define SYS__newselect __NR__newselect +#endif +#ifdef __NR__sysctl +# define SYS__sysctl __NR__sysctl +#endif +#ifdef __NR_accept +# define SYS_accept __NR_accept +#endif +#ifdef __NR_accept4 +# define SYS_accept4 __NR_accept4 +#endif +#ifdef __NR_access +# define SYS_access __NR_access +#endif +#ifdef __NR_acct +# define SYS_acct __NR_acct +#endif +#ifdef __NR_add_key +# define SYS_add_key __NR_add_key +#endif +#ifdef __NR_adjtimex +# define SYS_adjtimex __NR_adjtimex +#endif +#ifdef __NR_alarm +# define SYS_alarm __NR_alarm +#endif +#ifdef __NR_arc_gettls +# define SYS_arc_gettls __NR_arc_gettls +#endif +#ifdef __NR_arc_settls +# define SYS_arc_settls __NR_arc_settls +#endif +#ifdef __NR_arc_usr_cmpxchg +# define SYS_arc_usr_cmpxchg __NR_arc_usr_cmpxchg +#endif +#ifdef __NR_arch_prctl +# define SYS_arch_prctl __NR_arch_prctl +#endif +#ifdef __NR_arm_fadvise64_64 +# define SYS_arm_fadvise64_64 __NR_arm_fadvise64_64 +#endif +#ifdef __NR_atomic_barrier +# define SYS_atomic_barrier __NR_atomic_barrier +#endif +#ifdef __NR_atomic_cmpxchg_32 +# define SYS_atomic_cmpxchg_32 __NR_atomic_cmpxchg_32 +#endif +#ifdef __NR_bdflush +# define SYS_bdflush __NR_bdflush +#endif +#ifdef __NR_bind +# define SYS_bind __NR_bind +#endif +#ifdef __NR_bpf +# define SYS_bpf __NR_bpf +#endif +#ifdef __NR_brk +# define SYS_brk __NR_brk +#endif +#ifdef __NR_cachectl +# define SYS_cachectl __NR_cachectl +#endif +#ifdef __NR_cacheflush +# define SYS_cacheflush __NR_cacheflush +#endif +#ifdef __NR_cachestat +# define SYS_cachestat __NR_cachestat +#endif +#ifdef __NR_capget +# define SYS_capget __NR_capget +#endif +#ifdef __NR_capset +# define SYS_capset __NR_capset +#endif +#ifdef __NR_chdir +# define SYS_chdir __NR_chdir +#endif +#ifdef __NR_chmod +# define SYS_chmod __NR_chmod +#endif +#ifdef __NR_chown +# define SYS_chown __NR_chown +#endif +#ifdef __NR_chown32 +# define SYS_chown32 __NR_chown32 +#endif +#ifdef __NR_chroot +# define SYS_chroot __NR_chroot +#endif +#ifdef __NR_clock_adjtime +# define SYS_clock_adjtime __NR_clock_adjtime +#endif +#ifdef __NR_clock_adjtime64 +# define SYS_clock_adjtime64 __NR_clock_adjtime64 +#endif +#ifdef __NR_clock_getres +# define SYS_clock_getres __NR_clock_getres +#endif +#ifdef __NR_clock_getres_time64 +# define SYS_clock_getres_time64 __NR_clock_getres_time64 +#endif +#ifdef __NR_clock_gettime +# define SYS_clock_gettime __NR_clock_gettime +#endif +#ifdef __NR_clock_gettime64 +# define SYS_clock_gettime64 __NR_clock_gettime64 +#endif +#ifdef __NR_clock_nanosleep +# define SYS_clock_nanosleep __NR_clock_nanosleep +#endif +#ifdef __NR_clock_nanosleep_time64 +# define SYS_clock_nanosleep_time64 __NR_clock_nanosleep_time64 +#endif +#ifdef __NR_clock_settime +# define SYS_clock_settime __NR_clock_settime +#endif +#ifdef __NR_clock_settime64 +# define SYS_clock_settime64 __NR_clock_settime64 +#endif +#ifdef __NR_clone +# define SYS_clone __NR_clone +#endif +#ifdef __NR_clone3 +# define SYS_clone3 __NR_clone3 +#endif +#ifdef __NR_close +# define SYS_close __NR_close +#endif +#ifdef __NR_close_range +# define SYS_close_range __NR_close_range +#endif +#ifdef __NR_connect +# define SYS_connect __NR_connect +#endif +#ifdef __NR_copy_file_range +# define SYS_copy_file_range __NR_copy_file_range +#endif +#ifdef __NR_creat +# define SYS_creat __NR_creat +#endif +#ifdef __NR_create_module +# define SYS_create_module __NR_create_module +#endif +#ifdef __NR_delete_module +# define SYS_delete_module __NR_delete_module +#endif +#ifdef __NR_dipc +# define SYS_dipc __NR_dipc +#endif +#ifdef __NR_dup +# define SYS_dup __NR_dup +#endif +#ifdef __NR_dup2 +# define SYS_dup2 __NR_dup2 +#endif +#ifdef __NR_dup3 +# define SYS_dup3 __NR_dup3 +#endif +#ifdef __NR_epoll_create +# define SYS_epoll_create __NR_epoll_create +#endif +#ifdef __NR_epoll_create1 +# define SYS_epoll_create1 __NR_epoll_create1 +#endif +#ifdef __NR_epoll_ctl +# define SYS_epoll_ctl __NR_epoll_ctl +#endif +#ifdef __NR_epoll_ctl_old +# define SYS_epoll_ctl_old __NR_epoll_ctl_old +#endif +#ifdef __NR_epoll_pwait +# define SYS_epoll_pwait __NR_epoll_pwait +#endif +#ifdef __NR_epoll_pwait2 +# define SYS_epoll_pwait2 __NR_epoll_pwait2 +#endif +#ifdef __NR_epoll_wait +# define SYS_epoll_wait __NR_epoll_wait +#endif +#ifdef __NR_epoll_wait_old +# define SYS_epoll_wait_old __NR_epoll_wait_old +#endif +#ifdef __NR_eventfd +# define SYS_eventfd __NR_eventfd +#endif +#ifdef __NR_eventfd2 +# define SYS_eventfd2 __NR_eventfd2 +#endif +#ifdef __NR_exec_with_loader +# define SYS_exec_with_loader __NR_exec_with_loader +#endif +#ifdef __NR_execv +# define SYS_execv __NR_execv +#endif +#ifdef __NR_execve +# define SYS_execve __NR_execve +#endif +#ifdef __NR_execveat +# define SYS_execveat __NR_execveat +#endif +#ifdef __NR_exit +# define SYS_exit __NR_exit +#endif +#ifdef __NR_exit_group +# define SYS_exit_group __NR_exit_group +#endif +#ifdef __NR_faccessat +# define SYS_faccessat __NR_faccessat +#endif +#ifdef __NR_faccessat2 +# define SYS_faccessat2 __NR_faccessat2 +#endif +#ifdef __NR_fadvise64 +# define SYS_fadvise64 __NR_fadvise64 +#endif +#ifdef __NR_fadvise64_64 +# define SYS_fadvise64_64 __NR_fadvise64_64 +#endif +#ifdef __NR_fallocate +# define SYS_fallocate __NR_fallocate +#endif +#ifdef __NR_fanotify_init +# define SYS_fanotify_init __NR_fanotify_init +#endif +#ifdef __NR_fanotify_mark +# define SYS_fanotify_mark __NR_fanotify_mark +#endif +#ifdef __NR_fchdir +# define SYS_fchdir __NR_fchdir +#endif +#ifdef __NR_fchmod +# define SYS_fchmod __NR_fchmod +#endif +#ifdef __NR_fchmodat +# define SYS_fchmodat __NR_fchmodat +#endif +#ifdef __NR_fchmodat2 +# define SYS_fchmodat2 __NR_fchmodat2 +#endif +#ifdef __NR_fchown +# define SYS_fchown __NR_fchown +#endif +#ifdef __NR_fchown32 +# define SYS_fchown32 __NR_fchown32 +#endif +#ifdef __NR_fchownat +# define SYS_fchownat __NR_fchownat +#endif +#ifdef __NR_fcntl +# define SYS_fcntl __NR_fcntl +#endif +#ifdef __NR_fcntl64 +# define SYS_fcntl64 __NR_fcntl64 +#endif +#ifdef __NR_fdatasync +# define SYS_fdatasync __NR_fdatasync +#endif +#ifdef __NR_fgetxattr +# define SYS_fgetxattr __NR_fgetxattr +#endif +#ifdef __NR_finit_module +# define SYS_finit_module __NR_finit_module +#endif +#ifdef __NR_flistxattr +# define SYS_flistxattr __NR_flistxattr +#endif +#ifdef __NR_flock +# define SYS_flock __NR_flock +#endif +#ifdef __NR_fork +# define SYS_fork __NR_fork +#endif +#ifdef __NR_fremovexattr +# define SYS_fremovexattr __NR_fremovexattr +#endif +#ifdef __NR_fsconfig +# define SYS_fsconfig __NR_fsconfig +#endif +#ifdef __NR_fsetxattr +# define SYS_fsetxattr __NR_fsetxattr +#endif +#ifdef __NR_fsmount +# define SYS_fsmount __NR_fsmount +#endif +#ifdef __NR_fsopen +# define SYS_fsopen __NR_fsopen +#endif +#ifdef __NR_fspick +# define SYS_fspick __NR_fspick +#endif +#ifdef __NR_fstat +# define SYS_fstat __NR_fstat +#endif +#ifdef __NR_fstat64 +# define SYS_fstat64 __NR_fstat64 +#endif +#ifdef __NR_fstatat64 +# define SYS_fstatat64 __NR_fstatat64 +#endif +#ifdef __NR_fstatfs +# define SYS_fstatfs __NR_fstatfs +#endif +#ifdef __NR_fstatfs64 +# define SYS_fstatfs64 __NR_fstatfs64 +#endif +#ifdef __NR_fsync +# define SYS_fsync __NR_fsync +#endif +#ifdef __NR_ftruncate +# define SYS_ftruncate __NR_ftruncate +#endif +#ifdef __NR_ftruncate64 +# define SYS_ftruncate64 __NR_ftruncate64 +#endif +#ifdef __NR_futex +# define SYS_futex __NR_futex +#endif +#ifdef __NR_futex_requeue +# define SYS_futex_requeue __NR_futex_requeue +#endif +#ifdef __NR_futex_time64 +# define SYS_futex_time64 __NR_futex_time64 +#endif +#ifdef __NR_futex_wait +# define SYS_futex_wait __NR_futex_wait +#endif +#ifdef __NR_futex_waitv +# define SYS_futex_waitv __NR_futex_waitv +#endif +#ifdef __NR_futex_wake +# define SYS_futex_wake __NR_futex_wake +#endif +#ifdef __NR_futimesat +# define SYS_futimesat __NR_futimesat +#endif +#ifdef __NR_get_kernel_syms +# define SYS_get_kernel_syms __NR_get_kernel_syms +#endif +#ifdef __NR_get_mempolicy +# define SYS_get_mempolicy __NR_get_mempolicy +#endif +#ifdef __NR_get_robust_list +# define SYS_get_robust_list __NR_get_robust_list +#endif +#ifdef __NR_get_thread_area +# define SYS_get_thread_area __NR_get_thread_area +#endif +#ifdef __NR_getcpu +# define SYS_getcpu __NR_getcpu +#endif +#ifdef __NR_getcwd +# define SYS_getcwd __NR_getcwd +#endif +#ifdef __NR_getdents +# define SYS_getdents __NR_getdents +#endif +#ifdef __NR_getdents64 +# define SYS_getdents64 __NR_getdents64 +#endif +#ifdef __NR_getdomainname +# define SYS_getdomainname __NR_getdomainname +#endif +#ifdef __NR_getdtablesize +# define SYS_getdtablesize __NR_getdtablesize +#endif +#ifdef __NR_getegid +# define SYS_getegid __NR_getegid +#endif +#ifdef __NR_getegid32 +# define SYS_getegid32 __NR_getegid32 +#endif +#ifdef __NR_geteuid +# define SYS_geteuid __NR_geteuid +#endif +#ifdef __NR_geteuid32 +# define SYS_geteuid32 __NR_geteuid32 +#endif +#ifdef __NR_getgid +# define SYS_getgid __NR_getgid +#endif +#ifdef __NR_getgid32 +# define SYS_getgid32 __NR_getgid32 +#endif +#ifdef __NR_getgroups +# define SYS_getgroups __NR_getgroups +#endif +#ifdef __NR_getgroups32 +# define SYS_getgroups32 __NR_getgroups32 +#endif +#ifdef __NR_gethostname +# define SYS_gethostname __NR_gethostname +#endif +#ifdef __NR_getitimer +# define SYS_getitimer __NR_getitimer +#endif +#ifdef __NR_getpagesize +# define SYS_getpagesize __NR_getpagesize +#endif +#ifdef __NR_getpeername +# define SYS_getpeername __NR_getpeername +#endif +#ifdef __NR_getpgid +# define SYS_getpgid __NR_getpgid +#endif +#ifdef __NR_getpgrp +# define SYS_getpgrp __NR_getpgrp +#endif +#ifdef __NR_getpid +# define SYS_getpid __NR_getpid +#endif +#ifdef __NR_getpmsg +# define SYS_getpmsg __NR_getpmsg +#endif +#ifdef __NR_getppid +# define SYS_getppid __NR_getppid +#endif +#ifdef __NR_getpriority +# define SYS_getpriority __NR_getpriority +#endif +#ifdef __NR_getrandom +# define SYS_getrandom __NR_getrandom +#endif +#ifdef __NR_getresgid +# define SYS_getresgid __NR_getresgid +#endif +#ifdef __NR_getresgid32 +# define SYS_getresgid32 __NR_getresgid32 +#endif +#ifdef __NR_getresuid +# define SYS_getresuid __NR_getresuid +#endif +#ifdef __NR_getresuid32 +# define SYS_getresuid32 __NR_getresuid32 +#endif +#ifdef __NR_getrlimit +# define SYS_getrlimit __NR_getrlimit +#endif +#ifdef __NR_getrusage +# define SYS_getrusage __NR_getrusage +#endif +#ifdef __NR_getsid +# define SYS_getsid __NR_getsid +#endif +#ifdef __NR_getsockname +# define SYS_getsockname __NR_getsockname +#endif +#ifdef __NR_getsockopt +# define SYS_getsockopt __NR_getsockopt +#endif +#ifdef __NR_gettid +# define SYS_gettid __NR_gettid +#endif +#ifdef __NR_gettimeofday +# define SYS_gettimeofday __NR_gettimeofday +#endif +#ifdef __NR_getuid +# define SYS_getuid __NR_getuid +#endif +#ifdef __NR_getuid32 +# define SYS_getuid32 __NR_getuid32 +#endif +#ifdef __NR_getxattr +# define SYS_getxattr __NR_getxattr +#endif +#ifdef __NR_getxattrat +# define SYS_getxattrat __NR_getxattrat +#endif +#ifdef __NR_getxgid +# define SYS_getxgid __NR_getxgid +#endif +#ifdef __NR_getxpid +# define SYS_getxpid __NR_getxpid +#endif +#ifdef __NR_getxuid +# define SYS_getxuid __NR_getxuid +#endif +#ifdef __NR_idle +# define SYS_idle __NR_idle +#endif +#ifdef __NR_init_module +# define SYS_init_module __NR_init_module +#endif +#ifdef __NR_inotify_add_watch +# define SYS_inotify_add_watch __NR_inotify_add_watch +#endif +#ifdef __NR_inotify_init +# define SYS_inotify_init __NR_inotify_init +#endif +#ifdef __NR_inotify_init1 +# define SYS_inotify_init1 __NR_inotify_init1 +#endif +#ifdef __NR_inotify_rm_watch +# define SYS_inotify_rm_watch __NR_inotify_rm_watch +#endif +#ifdef __NR_io_cancel +# define SYS_io_cancel __NR_io_cancel +#endif +#ifdef __NR_io_destroy +# define SYS_io_destroy __NR_io_destroy +#endif +#ifdef __NR_io_getevents +# define SYS_io_getevents __NR_io_getevents +#endif +#ifdef __NR_io_pgetevents +# define SYS_io_pgetevents __NR_io_pgetevents +#endif +#ifdef __NR_io_pgetevents_time64 +# define SYS_io_pgetevents_time64 __NR_io_pgetevents_time64 +#endif +#ifdef __NR_io_setup +# define SYS_io_setup __NR_io_setup +#endif +#ifdef __NR_io_submit +# define SYS_io_submit __NR_io_submit +#endif +#ifdef __NR_io_uring_enter +# define SYS_io_uring_enter __NR_io_uring_enter +#endif +#ifdef __NR_io_uring_register +# define SYS_io_uring_register __NR_io_uring_register +#endif +#ifdef __NR_io_uring_setup +# define SYS_io_uring_setup __NR_io_uring_setup +#endif +#ifdef __NR_ioctl +# define SYS_ioctl __NR_ioctl +#endif +#ifdef __NR_ioperm +# define SYS_ioperm __NR_ioperm +#endif +#ifdef __NR_iopl +# define SYS_iopl __NR_iopl +#endif +#ifdef __NR_ioprio_get +# define SYS_ioprio_get __NR_ioprio_get +#endif +#ifdef __NR_ioprio_set +# define SYS_ioprio_set __NR_ioprio_set +#endif +#ifdef __NR_ipc +# define SYS_ipc __NR_ipc +#endif +#ifdef __NR_kcmp +# define SYS_kcmp __NR_kcmp +#endif +#ifdef __NR_kern_features +# define SYS_kern_features __NR_kern_features +#endif +#ifdef __NR_kexec_file_load +# define SYS_kexec_file_load __NR_kexec_file_load +#endif +#ifdef __NR_kexec_load +# define SYS_kexec_load __NR_kexec_load +#endif +#ifdef __NR_keyctl +# define SYS_keyctl __NR_keyctl +#endif +#ifdef __NR_kill +# define SYS_kill __NR_kill +#endif +#ifdef __NR_landlock_add_rule +# define SYS_landlock_add_rule __NR_landlock_add_rule +#endif +#ifdef __NR_landlock_create_ruleset +# define SYS_landlock_create_ruleset __NR_landlock_create_ruleset +#endif +#ifdef __NR_landlock_restrict_self +# define SYS_landlock_restrict_self __NR_landlock_restrict_self +#endif +#ifdef __NR_lchown +# define SYS_lchown __NR_lchown +#endif +#ifdef __NR_lchown32 +# define SYS_lchown32 __NR_lchown32 +#endif +#ifdef __NR_lgetxattr +# define SYS_lgetxattr __NR_lgetxattr +#endif +#ifdef __NR_link +# define SYS_link __NR_link +#endif +#ifdef __NR_linkat +# define SYS_linkat __NR_linkat +#endif +#ifdef __NR_listen +# define SYS_listen __NR_listen +#endif +#ifdef __NR_listmount +# define SYS_listmount __NR_listmount +#endif +#ifdef __NR_listxattr +# define SYS_listxattr __NR_listxattr +#endif +#ifdef __NR_listxattrat +# define SYS_listxattrat __NR_listxattrat +#endif +#ifdef __NR_llistxattr +# define SYS_llistxattr __NR_llistxattr +#endif +#ifdef __NR_llseek +# define SYS_llseek __NR_llseek +#endif +#ifdef __NR_lookup_dcookie +# define SYS_lookup_dcookie __NR_lookup_dcookie +#endif +#ifdef __NR_lremovexattr +# define SYS_lremovexattr __NR_lremovexattr +#endif +#ifdef __NR_lseek +# define SYS_lseek __NR_lseek +#endif +#ifdef __NR_lsetxattr +# define SYS_lsetxattr __NR_lsetxattr +#endif +#ifdef __NR_lsm_get_self_attr +# define SYS_lsm_get_self_attr __NR_lsm_get_self_attr +#endif +#ifdef __NR_lsm_list_modules +# define SYS_lsm_list_modules __NR_lsm_list_modules +#endif +#ifdef __NR_lsm_set_self_attr +# define SYS_lsm_set_self_attr __NR_lsm_set_self_attr +#endif +#ifdef __NR_lstat +# define SYS_lstat __NR_lstat +#endif +#ifdef __NR_lstat64 +# define SYS_lstat64 __NR_lstat64 +#endif +#ifdef __NR_madvise +# define SYS_madvise __NR_madvise +#endif +#ifdef __NR_map_shadow_stack +# define SYS_map_shadow_stack __NR_map_shadow_stack +#endif +#ifdef __NR_mbind +# define SYS_mbind __NR_mbind +#endif +#ifdef __NR_membarrier +# define SYS_membarrier __NR_membarrier +#endif +#ifdef __NR_memfd_create +# define SYS_memfd_create __NR_memfd_create +#endif +#ifdef __NR_memfd_secret +# define SYS_memfd_secret __NR_memfd_secret +#endif +#ifdef __NR_memory_ordering +# define SYS_memory_ordering __NR_memory_ordering +#endif +#ifdef __NR_migrate_pages +# define SYS_migrate_pages __NR_migrate_pages +#endif +#ifdef __NR_mincore +# define SYS_mincore __NR_mincore +#endif +#ifdef __NR_mkdir +# define SYS_mkdir __NR_mkdir +#endif +#ifdef __NR_mkdirat +# define SYS_mkdirat __NR_mkdirat +#endif +#ifdef __NR_mknod +# define SYS_mknod __NR_mknod +#endif +#ifdef __NR_mknodat +# define SYS_mknodat __NR_mknodat +#endif +#ifdef __NR_mlock +# define SYS_mlock __NR_mlock +#endif +#ifdef __NR_mlock2 +# define SYS_mlock2 __NR_mlock2 +#endif +#ifdef __NR_mlockall +# define SYS_mlockall __NR_mlockall +#endif +#ifdef __NR_mmap +# define SYS_mmap __NR_mmap +#endif +#ifdef __NR_mmap2 +# define SYS_mmap2 __NR_mmap2 +#endif +#ifdef __NR_modify_ldt +# define SYS_modify_ldt __NR_modify_ldt +#endif +#ifdef __NR_mount +# define SYS_mount __NR_mount +#endif +#ifdef __NR_mount_setattr +# define SYS_mount_setattr __NR_mount_setattr +#endif +#ifdef __NR_move_mount +# define SYS_move_mount __NR_move_mount +#endif +#ifdef __NR_move_pages +# define SYS_move_pages __NR_move_pages +#endif +#ifdef __NR_mprotect +# define SYS_mprotect __NR_mprotect +#endif +#ifdef __NR_mq_getsetattr +# define SYS_mq_getsetattr __NR_mq_getsetattr +#endif +#ifdef __NR_mq_notify +# define SYS_mq_notify __NR_mq_notify +#endif +#ifdef __NR_mq_open +# define SYS_mq_open __NR_mq_open +#endif +#ifdef __NR_mq_timedreceive +# define SYS_mq_timedreceive __NR_mq_timedreceive +#endif +#ifdef __NR_mq_timedreceive_time64 +# define SYS_mq_timedreceive_time64 __NR_mq_timedreceive_time64 +#endif +#ifdef __NR_mq_timedsend +# define SYS_mq_timedsend __NR_mq_timedsend +#endif +#ifdef __NR_mq_timedsend_time64 +# define SYS_mq_timedsend_time64 __NR_mq_timedsend_time64 +#endif +#ifdef __NR_mq_unlink +# define SYS_mq_unlink __NR_mq_unlink +#endif +#ifdef __NR_mremap +# define SYS_mremap __NR_mremap +#endif +#ifdef __NR_mseal +# define SYS_mseal __NR_mseal +#endif +#ifdef __NR_msgctl +# define SYS_msgctl __NR_msgctl +#endif +#ifdef __NR_msgget +# define SYS_msgget __NR_msgget +#endif +#ifdef __NR_msgrcv +# define SYS_msgrcv __NR_msgrcv +#endif +#ifdef __NR_msgsnd +# define SYS_msgsnd __NR_msgsnd +#endif +#ifdef __NR_msync +# define SYS_msync __NR_msync +#endif +#ifdef __NR_multiplexer +# define SYS_multiplexer __NR_multiplexer +#endif +#ifdef __NR_munlock +# define SYS_munlock __NR_munlock +#endif +#ifdef __NR_munlockall +# define SYS_munlockall __NR_munlockall +#endif +#ifdef __NR_munmap +# define SYS_munmap __NR_munmap +#endif +#ifdef __NR_name_to_handle_at +# define SYS_name_to_handle_at __NR_name_to_handle_at +#endif +#ifdef __NR_nanosleep +# define SYS_nanosleep __NR_nanosleep +#endif +#ifdef __NR_newfstatat +# define SYS_newfstatat __NR_newfstatat +#endif +#ifdef __NR_nfsservctl +# define SYS_nfsservctl __NR_nfsservctl +#endif +#ifdef __NR_nice +# define SYS_nice __NR_nice +#endif +#ifdef __NR_old_adjtimex +# define SYS_old_adjtimex __NR_old_adjtimex +#endif +#ifdef __NR_oldfstat +# define SYS_oldfstat __NR_oldfstat +#endif +#ifdef __NR_oldlstat +# define SYS_oldlstat __NR_oldlstat +#endif +#ifdef __NR_oldolduname +# define SYS_oldolduname __NR_oldolduname +#endif +#ifdef __NR_oldstat +# define SYS_oldstat __NR_oldstat +#endif +#ifdef __NR_oldumount +# define SYS_oldumount __NR_oldumount +#endif +#ifdef __NR_olduname +# define SYS_olduname __NR_olduname +#endif +#ifdef __NR_open +# define SYS_open __NR_open +#endif +#ifdef __NR_open_by_handle_at +# define SYS_open_by_handle_at __NR_open_by_handle_at +#endif +#ifdef __NR_open_tree +# define SYS_open_tree __NR_open_tree +#endif +#ifdef __NR_openat +# define SYS_openat __NR_openat +#endif +#ifdef __NR_openat2 +# define SYS_openat2 __NR_openat2 +#endif +#ifdef __NR_or1k_atomic +# define SYS_or1k_atomic __NR_or1k_atomic +#endif +#ifdef __NR_osf_adjtime +# define SYS_osf_adjtime __NR_osf_adjtime +#endif +#ifdef __NR_osf_afs_syscall +# define SYS_osf_afs_syscall __NR_osf_afs_syscall +#endif +#ifdef __NR_osf_alt_plock +# define SYS_osf_alt_plock __NR_osf_alt_plock +#endif +#ifdef __NR_osf_alt_setsid +# define SYS_osf_alt_setsid __NR_osf_alt_setsid +#endif +#ifdef __NR_osf_alt_sigpending +# define SYS_osf_alt_sigpending __NR_osf_alt_sigpending +#endif +#ifdef __NR_osf_asynch_daemon +# define SYS_osf_asynch_daemon __NR_osf_asynch_daemon +#endif +#ifdef __NR_osf_audcntl +# define SYS_osf_audcntl __NR_osf_audcntl +#endif +#ifdef __NR_osf_audgen +# define SYS_osf_audgen __NR_osf_audgen +#endif +#ifdef __NR_osf_chflags +# define SYS_osf_chflags __NR_osf_chflags +#endif +#ifdef __NR_osf_execve +# define SYS_osf_execve __NR_osf_execve +#endif +#ifdef __NR_osf_exportfs +# define SYS_osf_exportfs __NR_osf_exportfs +#endif +#ifdef __NR_osf_fchflags +# define SYS_osf_fchflags __NR_osf_fchflags +#endif +#ifdef __NR_osf_fdatasync +# define SYS_osf_fdatasync __NR_osf_fdatasync +#endif +#ifdef __NR_osf_fpathconf +# define SYS_osf_fpathconf __NR_osf_fpathconf +#endif +#ifdef __NR_osf_fstat +# define SYS_osf_fstat __NR_osf_fstat +#endif +#ifdef __NR_osf_fstatfs +# define SYS_osf_fstatfs __NR_osf_fstatfs +#endif +#ifdef __NR_osf_fstatfs64 +# define SYS_osf_fstatfs64 __NR_osf_fstatfs64 +#endif +#ifdef __NR_osf_fuser +# define SYS_osf_fuser __NR_osf_fuser +#endif +#ifdef __NR_osf_getaddressconf +# define SYS_osf_getaddressconf __NR_osf_getaddressconf +#endif +#ifdef __NR_osf_getdirentries +# define SYS_osf_getdirentries __NR_osf_getdirentries +#endif +#ifdef __NR_osf_getdomainname +# define SYS_osf_getdomainname __NR_osf_getdomainname +#endif +#ifdef __NR_osf_getfh +# define SYS_osf_getfh __NR_osf_getfh +#endif +#ifdef __NR_osf_getfsstat +# define SYS_osf_getfsstat __NR_osf_getfsstat +#endif +#ifdef __NR_osf_gethostid +# define SYS_osf_gethostid __NR_osf_gethostid +#endif +#ifdef __NR_osf_getitimer +# define SYS_osf_getitimer __NR_osf_getitimer +#endif +#ifdef __NR_osf_getlogin +# define SYS_osf_getlogin __NR_osf_getlogin +#endif +#ifdef __NR_osf_getmnt +# define SYS_osf_getmnt __NR_osf_getmnt +#endif +#ifdef __NR_osf_getrusage +# define SYS_osf_getrusage __NR_osf_getrusage +#endif +#ifdef __NR_osf_getsysinfo +# define SYS_osf_getsysinfo __NR_osf_getsysinfo +#endif +#ifdef __NR_osf_gettimeofday +# define SYS_osf_gettimeofday __NR_osf_gettimeofday +#endif +#ifdef __NR_osf_kloadcall +# define SYS_osf_kloadcall __NR_osf_kloadcall +#endif +#ifdef __NR_osf_kmodcall +# define SYS_osf_kmodcall __NR_osf_kmodcall +#endif +#ifdef __NR_osf_lstat +# define SYS_osf_lstat __NR_osf_lstat +#endif +#ifdef __NR_osf_memcntl +# define SYS_osf_memcntl __NR_osf_memcntl +#endif +#ifdef __NR_osf_mincore +# define SYS_osf_mincore __NR_osf_mincore +#endif +#ifdef __NR_osf_mount +# define SYS_osf_mount __NR_osf_mount +#endif +#ifdef __NR_osf_mremap +# define SYS_osf_mremap __NR_osf_mremap +#endif +#ifdef __NR_osf_msfs_syscall +# define SYS_osf_msfs_syscall __NR_osf_msfs_syscall +#endif +#ifdef __NR_osf_msleep +# define SYS_osf_msleep __NR_osf_msleep +#endif +#ifdef __NR_osf_mvalid +# define SYS_osf_mvalid __NR_osf_mvalid +#endif +#ifdef __NR_osf_mwakeup +# define SYS_osf_mwakeup __NR_osf_mwakeup +#endif +#ifdef __NR_osf_naccept +# define SYS_osf_naccept __NR_osf_naccept +#endif +#ifdef __NR_osf_nfssvc +# define SYS_osf_nfssvc __NR_osf_nfssvc +#endif +#ifdef __NR_osf_ngetpeername +# define SYS_osf_ngetpeername __NR_osf_ngetpeername +#endif +#ifdef __NR_osf_ngetsockname +# define SYS_osf_ngetsockname __NR_osf_ngetsockname +#endif +#ifdef __NR_osf_nrecvfrom +# define SYS_osf_nrecvfrom __NR_osf_nrecvfrom +#endif +#ifdef __NR_osf_nrecvmsg +# define SYS_osf_nrecvmsg __NR_osf_nrecvmsg +#endif +#ifdef __NR_osf_nsendmsg +# define SYS_osf_nsendmsg __NR_osf_nsendmsg +#endif +#ifdef __NR_osf_ntp_adjtime +# define SYS_osf_ntp_adjtime __NR_osf_ntp_adjtime +#endif +#ifdef __NR_osf_ntp_gettime +# define SYS_osf_ntp_gettime __NR_osf_ntp_gettime +#endif +#ifdef __NR_osf_old_creat +# define SYS_osf_old_creat __NR_osf_old_creat +#endif +#ifdef __NR_osf_old_fstat +# define SYS_osf_old_fstat __NR_osf_old_fstat +#endif +#ifdef __NR_osf_old_getpgrp +# define SYS_osf_old_getpgrp __NR_osf_old_getpgrp +#endif +#ifdef __NR_osf_old_killpg +# define SYS_osf_old_killpg __NR_osf_old_killpg +#endif +#ifdef __NR_osf_old_lstat +# define SYS_osf_old_lstat __NR_osf_old_lstat +#endif +#ifdef __NR_osf_old_open +# define SYS_osf_old_open __NR_osf_old_open +#endif +#ifdef __NR_osf_old_sigaction +# define SYS_osf_old_sigaction __NR_osf_old_sigaction +#endif +#ifdef __NR_osf_old_sigblock +# define SYS_osf_old_sigblock __NR_osf_old_sigblock +#endif +#ifdef __NR_osf_old_sigreturn +# define SYS_osf_old_sigreturn __NR_osf_old_sigreturn +#endif +#ifdef __NR_osf_old_sigsetmask +# define SYS_osf_old_sigsetmask __NR_osf_old_sigsetmask +#endif +#ifdef __NR_osf_old_sigvec +# define SYS_osf_old_sigvec __NR_osf_old_sigvec +#endif +#ifdef __NR_osf_old_stat +# define SYS_osf_old_stat __NR_osf_old_stat +#endif +#ifdef __NR_osf_old_vadvise +# define SYS_osf_old_vadvise __NR_osf_old_vadvise +#endif +#ifdef __NR_osf_old_vtrace +# define SYS_osf_old_vtrace __NR_osf_old_vtrace +#endif +#ifdef __NR_osf_old_wait +# define SYS_osf_old_wait __NR_osf_old_wait +#endif +#ifdef __NR_osf_oldquota +# define SYS_osf_oldquota __NR_osf_oldquota +#endif +#ifdef __NR_osf_pathconf +# define SYS_osf_pathconf __NR_osf_pathconf +#endif +#ifdef __NR_osf_pid_block +# define SYS_osf_pid_block __NR_osf_pid_block +#endif +#ifdef __NR_osf_pid_unblock +# define SYS_osf_pid_unblock __NR_osf_pid_unblock +#endif +#ifdef __NR_osf_plock +# define SYS_osf_plock __NR_osf_plock +#endif +#ifdef __NR_osf_priocntlset +# define SYS_osf_priocntlset __NR_osf_priocntlset +#endif +#ifdef __NR_osf_profil +# define SYS_osf_profil __NR_osf_profil +#endif +#ifdef __NR_osf_proplist_syscall +# define SYS_osf_proplist_syscall __NR_osf_proplist_syscall +#endif +#ifdef __NR_osf_reboot +# define SYS_osf_reboot __NR_osf_reboot +#endif +#ifdef __NR_osf_revoke +# define SYS_osf_revoke __NR_osf_revoke +#endif +#ifdef __NR_osf_sbrk +# define SYS_osf_sbrk __NR_osf_sbrk +#endif +#ifdef __NR_osf_security +# define SYS_osf_security __NR_osf_security +#endif +#ifdef __NR_osf_select +# define SYS_osf_select __NR_osf_select +#endif +#ifdef __NR_osf_set_program_attributes +# define SYS_osf_set_program_attributes __NR_osf_set_program_attributes +#endif +#ifdef __NR_osf_set_speculative +# define SYS_osf_set_speculative __NR_osf_set_speculative +#endif +#ifdef __NR_osf_sethostid +# define SYS_osf_sethostid __NR_osf_sethostid +#endif +#ifdef __NR_osf_setitimer +# define SYS_osf_setitimer __NR_osf_setitimer +#endif +#ifdef __NR_osf_setlogin +# define SYS_osf_setlogin __NR_osf_setlogin +#endif +#ifdef __NR_osf_setsysinfo +# define SYS_osf_setsysinfo __NR_osf_setsysinfo +#endif +#ifdef __NR_osf_settimeofday +# define SYS_osf_settimeofday __NR_osf_settimeofday +#endif +#ifdef __NR_osf_shmat +# define SYS_osf_shmat __NR_osf_shmat +#endif +#ifdef __NR_osf_signal +# define SYS_osf_signal __NR_osf_signal +#endif +#ifdef __NR_osf_sigprocmask +# define SYS_osf_sigprocmask __NR_osf_sigprocmask +#endif +#ifdef __NR_osf_sigsendset +# define SYS_osf_sigsendset __NR_osf_sigsendset +#endif +#ifdef __NR_osf_sigstack +# define SYS_osf_sigstack __NR_osf_sigstack +#endif +#ifdef __NR_osf_sigwaitprim +# define SYS_osf_sigwaitprim __NR_osf_sigwaitprim +#endif +#ifdef __NR_osf_sstk +# define SYS_osf_sstk __NR_osf_sstk +#endif +#ifdef __NR_osf_stat +# define SYS_osf_stat __NR_osf_stat +#endif +#ifdef __NR_osf_statfs +# define SYS_osf_statfs __NR_osf_statfs +#endif +#ifdef __NR_osf_statfs64 +# define SYS_osf_statfs64 __NR_osf_statfs64 +#endif +#ifdef __NR_osf_subsys_info +# define SYS_osf_subsys_info __NR_osf_subsys_info +#endif +#ifdef __NR_osf_swapctl +# define SYS_osf_swapctl __NR_osf_swapctl +#endif +#ifdef __NR_osf_swapon +# define SYS_osf_swapon __NR_osf_swapon +#endif +#ifdef __NR_osf_syscall +# define SYS_osf_syscall __NR_osf_syscall +#endif +#ifdef __NR_osf_sysinfo +# define SYS_osf_sysinfo __NR_osf_sysinfo +#endif +#ifdef __NR_osf_table +# define SYS_osf_table __NR_osf_table +#endif +#ifdef __NR_osf_uadmin +# define SYS_osf_uadmin __NR_osf_uadmin +#endif +#ifdef __NR_osf_usleep_thread +# define SYS_osf_usleep_thread __NR_osf_usleep_thread +#endif +#ifdef __NR_osf_uswitch +# define SYS_osf_uswitch __NR_osf_uswitch +#endif +#ifdef __NR_osf_utc_adjtime +# define SYS_osf_utc_adjtime __NR_osf_utc_adjtime +#endif +#ifdef __NR_osf_utc_gettime +# define SYS_osf_utc_gettime __NR_osf_utc_gettime +#endif +#ifdef __NR_osf_utimes +# define SYS_osf_utimes __NR_osf_utimes +#endif +#ifdef __NR_osf_utsname +# define SYS_osf_utsname __NR_osf_utsname +#endif +#ifdef __NR_osf_wait4 +# define SYS_osf_wait4 __NR_osf_wait4 +#endif +#ifdef __NR_osf_waitid +# define SYS_osf_waitid __NR_osf_waitid +#endif +#ifdef __NR_pause +# define SYS_pause __NR_pause +#endif +#ifdef __NR_pciconfig_iobase +# define SYS_pciconfig_iobase __NR_pciconfig_iobase +#endif +#ifdef __NR_pciconfig_read +# define SYS_pciconfig_read __NR_pciconfig_read +#endif +#ifdef __NR_pciconfig_write +# define SYS_pciconfig_write __NR_pciconfig_write +#endif +#ifdef __NR_perf_event_open +# define SYS_perf_event_open __NR_perf_event_open +#endif +#ifdef __NR_perfctr +# define SYS_perfctr __NR_perfctr +#endif +#ifdef __NR_personality +# define SYS_personality __NR_personality +#endif +#ifdef __NR_pidfd_getfd +# define SYS_pidfd_getfd __NR_pidfd_getfd +#endif +#ifdef __NR_pidfd_open +# define SYS_pidfd_open __NR_pidfd_open +#endif +#ifdef __NR_pidfd_send_signal +# define SYS_pidfd_send_signal __NR_pidfd_send_signal +#endif +#ifdef __NR_pipe +# define SYS_pipe __NR_pipe +#endif +#ifdef __NR_pipe2 +# define SYS_pipe2 __NR_pipe2 +#endif +#ifdef __NR_pivot_root +# define SYS_pivot_root __NR_pivot_root +#endif +#ifdef __NR_pkey_alloc +# define SYS_pkey_alloc __NR_pkey_alloc +#endif +#ifdef __NR_pkey_free +# define SYS_pkey_free __NR_pkey_free +#endif +#ifdef __NR_pkey_mprotect +# define SYS_pkey_mprotect __NR_pkey_mprotect +#endif +#ifdef __NR_poll +# define SYS_poll __NR_poll +#endif +#ifdef __NR_ppoll +# define SYS_ppoll __NR_ppoll +#endif +#ifdef __NR_ppoll_time64 +# define SYS_ppoll_time64 __NR_ppoll_time64 +#endif +#ifdef __NR_prctl +# define SYS_prctl __NR_prctl +#endif +#ifdef __NR_pread64 +# define SYS_pread64 __NR_pread64 +#endif +#ifdef __NR_preadv +# define SYS_preadv __NR_preadv +#endif +#ifdef __NR_preadv2 +# define SYS_preadv2 __NR_preadv2 +#endif +#ifdef __NR_prlimit64 +# define SYS_prlimit64 __NR_prlimit64 +#endif +#ifdef __NR_process_madvise +# define SYS_process_madvise __NR_process_madvise +#endif +#ifdef __NR_process_mrelease +# define SYS_process_mrelease __NR_process_mrelease +#endif +#ifdef __NR_process_vm_readv +# define SYS_process_vm_readv __NR_process_vm_readv +#endif +#ifdef __NR_process_vm_writev +# define SYS_process_vm_writev __NR_process_vm_writev +#endif +#ifdef __NR_pselect6 +# define SYS_pselect6 __NR_pselect6 +#endif +#ifdef __NR_pselect6_time64 +# define SYS_pselect6_time64 __NR_pselect6_time64 +#endif +#ifdef __NR_ptrace +# define SYS_ptrace __NR_ptrace +#endif +#ifdef __NR_pwrite64 +# define SYS_pwrite64 __NR_pwrite64 +#endif +#ifdef __NR_pwritev +# define SYS_pwritev __NR_pwritev +#endif +#ifdef __NR_pwritev2 +# define SYS_pwritev2 __NR_pwritev2 +#endif +#ifdef __NR_query_module +# define SYS_query_module __NR_query_module +#endif +#ifdef __NR_quotactl +# define SYS_quotactl __NR_quotactl +#endif +#ifdef __NR_quotactl_fd +# define SYS_quotactl_fd __NR_quotactl_fd +#endif +#ifdef __NR_read +# define SYS_read __NR_read +#endif +#ifdef __NR_readahead +# define SYS_readahead __NR_readahead +#endif +#ifdef __NR_readdir +# define SYS_readdir __NR_readdir +#endif +#ifdef __NR_readlink +# define SYS_readlink __NR_readlink +#endif +#ifdef __NR_readlinkat +# define SYS_readlinkat __NR_readlinkat +#endif +#ifdef __NR_readv +# define SYS_readv __NR_readv +#endif +#ifdef __NR_reboot +# define SYS_reboot __NR_reboot +#endif +#ifdef __NR_recv +# define SYS_recv __NR_recv +#endif +#ifdef __NR_recvfrom +# define SYS_recvfrom __NR_recvfrom +#endif +#ifdef __NR_recvmmsg +# define SYS_recvmmsg __NR_recvmmsg +#endif +#ifdef __NR_recvmmsg_time64 +# define SYS_recvmmsg_time64 __NR_recvmmsg_time64 +#endif +#ifdef __NR_recvmsg +# define SYS_recvmsg __NR_recvmsg +#endif +#ifdef __NR_remap_file_pages +# define SYS_remap_file_pages __NR_remap_file_pages +#endif +#ifdef __NR_removexattr +# define SYS_removexattr __NR_removexattr +#endif +#ifdef __NR_removexattrat +# define SYS_removexattrat __NR_removexattrat +#endif +#ifdef __NR_rename +# define SYS_rename __NR_rename +#endif +#ifdef __NR_renameat +# define SYS_renameat __NR_renameat +#endif +#ifdef __NR_renameat2 +# define SYS_renameat2 __NR_renameat2 +#endif +#ifdef __NR_request_key +# define SYS_request_key __NR_request_key +#endif +#ifdef __NR_restart_syscall +# define SYS_restart_syscall __NR_restart_syscall +#endif +#ifdef __NR_riscv_flush_icache +# define SYS_riscv_flush_icache __NR_riscv_flush_icache +#endif +#ifdef __NR_riscv_hwprobe +# define SYS_riscv_hwprobe __NR_riscv_hwprobe +#endif +#ifdef __NR_rmdir +# define SYS_rmdir __NR_rmdir +#endif +#ifdef __NR_rseq +# define SYS_rseq __NR_rseq +#endif +#ifdef __NR_rt_sigaction +# define SYS_rt_sigaction __NR_rt_sigaction +#endif +#ifdef __NR_rt_sigpending +# define SYS_rt_sigpending __NR_rt_sigpending +#endif +#ifdef __NR_rt_sigprocmask +# define SYS_rt_sigprocmask __NR_rt_sigprocmask +#endif +#ifdef __NR_rt_sigqueueinfo +# define SYS_rt_sigqueueinfo __NR_rt_sigqueueinfo +#endif +#ifdef __NR_rt_sigreturn +# define SYS_rt_sigreturn __NR_rt_sigreturn +#endif +#ifdef __NR_rt_sigsuspend +# define SYS_rt_sigsuspend __NR_rt_sigsuspend +#endif +#ifdef __NR_rt_sigtimedwait +# define SYS_rt_sigtimedwait __NR_rt_sigtimedwait +#endif +#ifdef __NR_rt_sigtimedwait_time64 +# define SYS_rt_sigtimedwait_time64 __NR_rt_sigtimedwait_time64 +#endif +#ifdef __NR_rt_tgsigqueueinfo +# define SYS_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo +#endif +#ifdef __NR_rtas +# define SYS_rtas __NR_rtas +#endif +#ifdef __NR_s390_guarded_storage +# define SYS_s390_guarded_storage __NR_s390_guarded_storage +#endif +#ifdef __NR_s390_pci_mmio_read +# define SYS_s390_pci_mmio_read __NR_s390_pci_mmio_read +#endif +#ifdef __NR_s390_pci_mmio_write +# define SYS_s390_pci_mmio_write __NR_s390_pci_mmio_write +#endif +#ifdef __NR_s390_runtime_instr +# define SYS_s390_runtime_instr __NR_s390_runtime_instr +#endif +#ifdef __NR_s390_sthyi +# define SYS_s390_sthyi __NR_s390_sthyi +#endif +#ifdef __NR_sched_get_affinity +# define SYS_sched_get_affinity __NR_sched_get_affinity +#endif +#ifdef __NR_sched_get_priority_max +# define SYS_sched_get_priority_max __NR_sched_get_priority_max +#endif +#ifdef __NR_sched_get_priority_min +# define SYS_sched_get_priority_min __NR_sched_get_priority_min +#endif +#ifdef __NR_sched_getaffinity +# define SYS_sched_getaffinity __NR_sched_getaffinity +#endif +#ifdef __NR_sched_getattr +# define SYS_sched_getattr __NR_sched_getattr +#endif +#ifdef __NR_sched_getparam +# define SYS_sched_getparam __NR_sched_getparam +#endif +#ifdef __NR_sched_getscheduler +# define SYS_sched_getscheduler __NR_sched_getscheduler +#endif +#ifdef __NR_sched_rr_get_interval +# define SYS_sched_rr_get_interval __NR_sched_rr_get_interval +#endif +#ifdef __NR_sched_rr_get_interval_time64 +# define SYS_sched_rr_get_interval_time64 __NR_sched_rr_get_interval_time64 +#endif +#ifdef __NR_sched_set_affinity +# define SYS_sched_set_affinity __NR_sched_set_affinity +#endif +#ifdef __NR_sched_setaffinity +# define SYS_sched_setaffinity __NR_sched_setaffinity +#endif +#ifdef __NR_sched_setattr +# define SYS_sched_setattr __NR_sched_setattr +#endif +#ifdef __NR_sched_setparam +# define SYS_sched_setparam __NR_sched_setparam +#endif +#ifdef __NR_sched_setscheduler +# define SYS_sched_setscheduler __NR_sched_setscheduler +#endif +#ifdef __NR_sched_yield +# define SYS_sched_yield __NR_sched_yield +#endif +#ifdef __NR_seccomp +# define SYS_seccomp __NR_seccomp +#endif +#ifdef __NR_select +# define SYS_select __NR_select +#endif +#ifdef __NR_semctl +# define SYS_semctl __NR_semctl +#endif +#ifdef __NR_semget +# define SYS_semget __NR_semget +#endif +#ifdef __NR_semop +# define SYS_semop __NR_semop +#endif +#ifdef __NR_semtimedop +# define SYS_semtimedop __NR_semtimedop +#endif +#ifdef __NR_semtimedop_time64 +# define SYS_semtimedop_time64 __NR_semtimedop_time64 +#endif +#ifdef __NR_send +# define SYS_send __NR_send +#endif +#ifdef __NR_sendfile +# define SYS_sendfile __NR_sendfile +#endif +#ifdef __NR_sendfile64 +# define SYS_sendfile64 __NR_sendfile64 +#endif +#ifdef __NR_sendmmsg +# define SYS_sendmmsg __NR_sendmmsg +#endif +#ifdef __NR_sendmsg +# define SYS_sendmsg __NR_sendmsg +#endif +#ifdef __NR_sendto +# define SYS_sendto __NR_sendto +#endif +#ifdef __NR_set_mempolicy +# define SYS_set_mempolicy __NR_set_mempolicy +#endif +#ifdef __NR_set_mempolicy_home_node +# define SYS_set_mempolicy_home_node __NR_set_mempolicy_home_node +#endif +#ifdef __NR_set_robust_list +# define SYS_set_robust_list __NR_set_robust_list +#endif +#ifdef __NR_set_thread_area +# define SYS_set_thread_area __NR_set_thread_area +#endif +#ifdef __NR_set_tid_address +# define SYS_set_tid_address __NR_set_tid_address +#endif +#ifdef __NR_setdomainname +# define SYS_setdomainname __NR_setdomainname +#endif +#ifdef __NR_setfsgid +# define SYS_setfsgid __NR_setfsgid +#endif +#ifdef __NR_setfsgid32 +# define SYS_setfsgid32 __NR_setfsgid32 +#endif +#ifdef __NR_setfsuid +# define SYS_setfsuid __NR_setfsuid +#endif +#ifdef __NR_setfsuid32 +# define SYS_setfsuid32 __NR_setfsuid32 +#endif +#ifdef __NR_setgid +# define SYS_setgid __NR_setgid +#endif +#ifdef __NR_setgid32 +# define SYS_setgid32 __NR_setgid32 +#endif +#ifdef __NR_setgroups +# define SYS_setgroups __NR_setgroups +#endif +#ifdef __NR_setgroups32 +# define SYS_setgroups32 __NR_setgroups32 +#endif +#ifdef __NR_sethae +# define SYS_sethae __NR_sethae +#endif +#ifdef __NR_sethostname +# define SYS_sethostname __NR_sethostname +#endif +#ifdef __NR_setitimer +# define SYS_setitimer __NR_setitimer +#endif +#ifdef __NR_setns +# define SYS_setns __NR_setns +#endif +#ifdef __NR_setpgid +# define SYS_setpgid __NR_setpgid +#endif +#ifdef __NR_setpgrp +# define SYS_setpgrp __NR_setpgrp +#endif +#ifdef __NR_setpriority +# define SYS_setpriority __NR_setpriority +#endif +#ifdef __NR_setregid +# define SYS_setregid __NR_setregid +#endif +#ifdef __NR_setregid32 +# define SYS_setregid32 __NR_setregid32 +#endif +#ifdef __NR_setresgid +# define SYS_setresgid __NR_setresgid +#endif +#ifdef __NR_setresgid32 +# define SYS_setresgid32 __NR_setresgid32 +#endif +#ifdef __NR_setresuid +# define SYS_setresuid __NR_setresuid +#endif +#ifdef __NR_setresuid32 +# define SYS_setresuid32 __NR_setresuid32 +#endif +#ifdef __NR_setreuid +# define SYS_setreuid __NR_setreuid +#endif +#ifdef __NR_setreuid32 +# define SYS_setreuid32 __NR_setreuid32 +#endif +#ifdef __NR_setrlimit +# define SYS_setrlimit __NR_setrlimit +#endif +#ifdef __NR_setsid +# define SYS_setsid __NR_setsid +#endif +#ifdef __NR_setsockopt +# define SYS_setsockopt __NR_setsockopt +#endif +#ifdef __NR_settimeofday +# define SYS_settimeofday __NR_settimeofday +#endif +#ifdef __NR_setuid +# define SYS_setuid __NR_setuid +#endif +#ifdef __NR_setuid32 +# define SYS_setuid32 __NR_setuid32 +#endif +#ifdef __NR_setxattr +# define SYS_setxattr __NR_setxattr +#endif +#ifdef __NR_setxattrat +# define SYS_setxattrat __NR_setxattrat +#endif +#ifdef __NR_sgetmask +# define SYS_sgetmask __NR_sgetmask +#endif +#ifdef __NR_shmat +# define SYS_shmat __NR_shmat +#endif +#ifdef __NR_shmctl +# define SYS_shmctl __NR_shmctl +#endif +#ifdef __NR_shmdt +# define SYS_shmdt __NR_shmdt +#endif +#ifdef __NR_shmget +# define SYS_shmget __NR_shmget +#endif +#ifdef __NR_shutdown +# define SYS_shutdown __NR_shutdown +#endif +#ifdef __NR_sigaction +# define SYS_sigaction __NR_sigaction +#endif +#ifdef __NR_sigaltstack +# define SYS_sigaltstack __NR_sigaltstack +#endif +#ifdef __NR_signal +# define SYS_signal __NR_signal +#endif +#ifdef __NR_signalfd +# define SYS_signalfd __NR_signalfd +#endif +#ifdef __NR_signalfd4 +# define SYS_signalfd4 __NR_signalfd4 +#endif +#ifdef __NR_sigpending +# define SYS_sigpending __NR_sigpending +#endif +#ifdef __NR_sigprocmask +# define SYS_sigprocmask __NR_sigprocmask +#endif +#ifdef __NR_sigreturn +# define SYS_sigreturn __NR_sigreturn +#endif +#ifdef __NR_sigsuspend +# define SYS_sigsuspend __NR_sigsuspend +#endif +#ifdef __NR_socket +# define SYS_socket __NR_socket +#endif +#ifdef __NR_socketcall +# define SYS_socketcall __NR_socketcall +#endif +#ifdef __NR_socketpair +# define SYS_socketpair __NR_socketpair +#endif +#ifdef __NR_spill +# define SYS_spill __NR_spill +#endif +#ifdef __NR_splice +# define SYS_splice __NR_splice +#endif +#ifdef __NR_spu_create +# define SYS_spu_create __NR_spu_create +#endif +#ifdef __NR_spu_run +# define SYS_spu_run __NR_spu_run +#endif +#ifdef __NR_ssetmask +# define SYS_ssetmask __NR_ssetmask +#endif +#ifdef __NR_stat +# define SYS_stat __NR_stat +#endif +#ifdef __NR_stat64 +# define SYS_stat64 __NR_stat64 +#endif +#ifdef __NR_statfs +# define SYS_statfs __NR_statfs +#endif +#ifdef __NR_statfs64 +# define SYS_statfs64 __NR_statfs64 +#endif +#ifdef __NR_statmount +# define SYS_statmount __NR_statmount +#endif +#ifdef __NR_statx +# define SYS_statx __NR_statx +#endif +#ifdef __NR_stime +# define SYS_stime __NR_stime +#endif +#ifdef __NR_subpage_prot +# define SYS_subpage_prot __NR_subpage_prot +#endif +#ifdef __NR_swapcontext +# define SYS_swapcontext __NR_swapcontext +#endif +#ifdef __NR_swapoff +# define SYS_swapoff __NR_swapoff +#endif +#ifdef __NR_swapon +# define SYS_swapon __NR_swapon +#endif +#ifdef __NR_switch_endian +# define SYS_switch_endian __NR_switch_endian +#endif +#ifdef __NR_symlink +# define SYS_symlink __NR_symlink +#endif +#ifdef __NR_symlinkat +# define SYS_symlinkat __NR_symlinkat +#endif +#ifdef __NR_sync +# define SYS_sync __NR_sync +#endif +#ifdef __NR_sync_file_range +# define SYS_sync_file_range __NR_sync_file_range +#endif +#ifdef __NR_sync_file_range2 +# define SYS_sync_file_range2 __NR_sync_file_range2 +#endif +#ifdef __NR_syncfs +# define SYS_syncfs __NR_syncfs +#endif +#ifdef __NR_sys_debug_setcontext +# define SYS_sys_debug_setcontext __NR_sys_debug_setcontext +#endif +#ifdef __NR_syscall +# define SYS_syscall __NR_syscall +#endif +#ifdef __NR_sysfs +# define SYS_sysfs __NR_sysfs +#endif +#ifdef __NR_sysinfo +# define SYS_sysinfo __NR_sysinfo +#endif +#ifdef __NR_syslog +# define SYS_syslog __NR_syslog +#endif +#ifdef __NR_sysmips +# define SYS_sysmips __NR_sysmips +#endif +#ifdef __NR_tee +# define SYS_tee __NR_tee +#endif +#ifdef __NR_tgkill +# define SYS_tgkill __NR_tgkill +#endif +#ifdef __NR_time +# define SYS_time __NR_time +#endif +#ifdef __NR_timer_create +# define SYS_timer_create __NR_timer_create +#endif +#ifdef __NR_timer_delete +# define SYS_timer_delete __NR_timer_delete +#endif +#ifdef __NR_timer_getoverrun +# define SYS_timer_getoverrun __NR_timer_getoverrun +#endif +#ifdef __NR_timer_gettime +# define SYS_timer_gettime __NR_timer_gettime +#endif +#ifdef __NR_timer_gettime64 +# define SYS_timer_gettime64 __NR_timer_gettime64 +#endif +#ifdef __NR_timer_settime +# define SYS_timer_settime __NR_timer_settime +#endif +#ifdef __NR_timer_settime64 +# define SYS_timer_settime64 __NR_timer_settime64 +#endif +#ifdef __NR_timerfd +# define SYS_timerfd __NR_timerfd +#endif +#ifdef __NR_timerfd_create +# define SYS_timerfd_create __NR_timerfd_create +#endif +#ifdef __NR_timerfd_gettime +# define SYS_timerfd_gettime __NR_timerfd_gettime +#endif +#ifdef __NR_timerfd_gettime64 +# define SYS_timerfd_gettime64 __NR_timerfd_gettime64 +#endif +#ifdef __NR_timerfd_settime +# define SYS_timerfd_settime __NR_timerfd_settime +#endif +#ifdef __NR_timerfd_settime64 +# define SYS_timerfd_settime64 __NR_timerfd_settime64 +#endif +#ifdef __NR_times +# define SYS_times __NR_times +#endif +#ifdef __NR_tkill +# define SYS_tkill __NR_tkill +#endif +#ifdef __NR_truncate +# define SYS_truncate __NR_truncate +#endif +#ifdef __NR_truncate64 +# define SYS_truncate64 __NR_truncate64 +#endif +#ifdef __NR_ugetrlimit +# define SYS_ugetrlimit __NR_ugetrlimit +#endif +#ifdef __NR_umask +# define SYS_umask __NR_umask +#endif +#ifdef __NR_umount +# define SYS_umount __NR_umount +#endif +#ifdef __NR_umount2 +# define SYS_umount2 __NR_umount2 +#endif +#ifdef __NR_uname +# define SYS_uname __NR_uname +#endif +#ifdef __NR_unlink +# define SYS_unlink __NR_unlink +#endif +#ifdef __NR_unlinkat +# define SYS_unlinkat __NR_unlinkat +#endif +#ifdef __NR_unshare +# define SYS_unshare __NR_unshare +#endif +#ifdef __NR_uretprobe +# define SYS_uretprobe __NR_uretprobe +#endif +#ifdef __NR_uselib +# define SYS_uselib __NR_uselib +#endif +#ifdef __NR_userfaultfd +# define SYS_userfaultfd __NR_userfaultfd +#endif +#ifdef __NR_ustat +# define SYS_ustat __NR_ustat +#endif +#ifdef __NR_utime +# define SYS_utime __NR_utime +#endif +#ifdef __NR_utimensat +# define SYS_utimensat __NR_utimensat +#endif +#ifdef __NR_utimensat_time64 +# define SYS_utimensat_time64 __NR_utimensat_time64 +#endif +#ifdef __NR_utimes +# define SYS_utimes __NR_utimes +#endif +#ifdef __NR_utrap_install +# define SYS_utrap_install __NR_utrap_install +#endif +#ifdef __NR_vfork +# define SYS_vfork __NR_vfork +#endif +#ifdef __NR_vhangup +# define SYS_vhangup __NR_vhangup +#endif +#ifdef __NR_vm86 +# define SYS_vm86 __NR_vm86 +#endif +#ifdef __NR_vm86old +# define SYS_vm86old __NR_vm86old +#endif +#ifdef __NR_vmsplice +# define SYS_vmsplice __NR_vmsplice +#endif +#ifdef __NR_wait4 +# define SYS_wait4 __NR_wait4 +#endif +#ifdef __NR_waitid +# define SYS_waitid __NR_waitid +#endif +#ifdef __NR_waitpid +# define SYS_waitpid __NR_waitpid +#endif +#ifdef __NR_write +# define SYS_write __NR_write +#endif +#ifdef __NR_writev +# define SYS_writev __NR_writev +#endif +#endif /* __MLIBC_SYSCALL_ALIAS_BIT */ diff --git a/user/include/mlibc/sysdeps/linux/include/mlibc/thread-entry.hpp b/user/include/mlibc/sysdeps/linux/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..a20cab5 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/mlibc/thread-entry.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_THREAD_ENTRY + +#include + +extern "C" int __mlibc_spawn_thread(int flags, void *stack, void *pid_out, void *child_tid, void *tcb); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg); + +namespace mlibc { + void *prepare_stack(void *entry, void *user_arg); +} + +#endif // MLIBC_THREAD_ENTRY diff --git a/user/include/mlibc/sysdeps/linux/include/sys/syscall.h b/user/include/mlibc/sysdeps/linux/include/sys/syscall.h new file mode 100644 index 0000000..aeb8991 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/sys/syscall.h @@ -0,0 +1,14 @@ +#ifndef _SYS_SYSCALL_H +#define _SYS_SYSCALL_H + +/* On GNU/Linux, this header provides includes __NR_-prefixed syscall numbers, + * and their SYS_ aliases. We defer to kernel headers for the numbers + * (linux-headers, or an autogenerated stub while building), and an + * autogenerated file containing SYS_ defines. + */ +/* clang-format off */ +#include +#include +/* clang-format on */ + +#endif /* _SYS_SYSCALL_H */ diff --git a/user/include/mlibc/sysdeps/linux/include/syscall.h b/user/include/mlibc/sysdeps/linux/include/syscall.h new file mode 100644 index 0000000..4c30578 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/include/syscall.h @@ -0,0 +1 @@ +#include diff --git a/user/include/mlibc/sysdeps/linux/loongarch64/arch-syscall.cpp b/user/include/mlibc/sysdeps/linux/loongarch64/arch-syscall.cpp new file mode 100644 index 0000000..3d65fd0 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/loongarch64/arch-syscall.cpp @@ -0,0 +1,117 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +sc_word_t __do_syscall0(long sc) { + register int sc_reg asm("a7") = sc; + register sc_word_t ret asm("a0"); + asm volatile ("syscall 0" : "=r"(ret) : "r"(sc_reg) : "memory", "a1"); + return ret; +} + +sc_word_t __do_syscall1(long sc, + sc_word_t arg1) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t ret asm("a0"); + asm volatile ("syscall 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg) + : "memory", "a1"); + return ret; +} + +sc_word_t __do_syscall2(long sc, + sc_word_t arg1, sc_word_t arg2) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t ret asm("a0"); + asm volatile ("syscall 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t ret asm("a0"); + asm volatile ("syscall 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t ret asm("a0"); + asm volatile ("syscall 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t arg5_reg asm("a4") = arg5; + register sc_word_t ret asm("a0"); + asm volatile ("syscall 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t arg5_reg asm("a4") = arg5; + register sc_word_t arg6_reg asm("a5") = arg6; + register sc_word_t ret asm("a0"); + asm volatile ("syscall 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg), + "r"(arg6_reg) + : "memory" + ); + return ret; +} diff --git a/user/include/mlibc/sysdeps/linux/loongarch64/assembly-asserts.cpp b/user/include/mlibc/sysdeps/linux/loongarch64/assembly-asserts.cpp new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/sysdeps/linux/loongarch64/cp_syscall.S b/user/include/mlibc/sysdeps/linux/loongarch64/cp_syscall.S new file mode 100644 index 0000000..48eec47 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/loongarch64/cp_syscall.S @@ -0,0 +1,30 @@ +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + st.d $a7, $sp, -8 + move $a7, $a0 + move $a0, $a1 + move $a1, $a2 + move $a2, $a3 + move $a3, $a4 + move $a4, $a5 + move $a5, $a6 + move $a6, $a7 + ld.w $t0, $tp, -96 // Tcb::cancelBits. See asserts in tcb.hpp. +__mlibc_syscall_begin: + // tcbCancelEnableBit && tcbCancelTriggerBit + addi.d $t1, $r0, (1 << 0) | (1 << 2) + and $t0, $t0, $t1 + beq $t0, $t1, cancel + syscall 0 +__mlibc_syscall_end: + ret + +cancel: + la.local $t2, __mlibc_do_cancel + jr $t2 +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/loongarch64/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/linux/loongarch64/crt-src/Scrt1.S new file mode 100644 index 0000000..d1fbfc7 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/loongarch64/crt-src/Scrt1.S @@ -0,0 +1,11 @@ +.extern __mlibc_entry@plt + +.section .text +.global _start +_start: + move $a0, $sp + la $a1, main + bl %plt(__mlibc_entry) + break 0 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/loongarch64/crt-src/crt1.S b/user/include/mlibc/sysdeps/linux/loongarch64/crt-src/crt1.S new file mode 100644 index 0000000..d76ded2 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/loongarch64/crt-src/crt1.S @@ -0,0 +1,11 @@ +.extern __mlibc_entry + +.section .text +.global _start +_start: + move $a0, $sp + la $a1, main + b __mlibc_entry + break 0 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/loongarch64/signals.S b/user/include/mlibc/sysdeps/linux/loongarch64/signals.S new file mode 100644 index 0000000..6e76a7c --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/loongarch64/signals.S @@ -0,0 +1,12 @@ +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + li.w $a7, 139 // __NR_rt_sigreturn + syscall 0 +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/loongarch64/syscallnos.h b/user/include/mlibc/sysdeps/linux/loongarch64/syscallnos.h new file mode 100644 index 0000000..271a79c --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/loongarch64/syscallnos.h @@ -0,0 +1,323 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_io_setup 0 +#define __NR_io_destroy 1 +#define __NR_io_submit 2 +#define __NR_io_cancel 3 +#define __NR_io_getevents 4 +#define __NR_setxattr 5 +#define __NR_lsetxattr 6 +#define __NR_fsetxattr 7 +#define __NR_getxattr 8 +#define __NR_lgetxattr 9 +#define __NR_fgetxattr 10 +#define __NR_listxattr 11 +#define __NR_llistxattr 12 +#define __NR_flistxattr 13 +#define __NR_removexattr 14 +#define __NR_lremovexattr 15 +#define __NR_fremovexattr 16 +#define __NR_getcwd 17 +#define __NR_lookup_dcookie 18 +#define __NR_eventfd2 19 +#define __NR_epoll_create1 20 +#define __NR_epoll_ctl 21 +#define __NR_epoll_pwait 22 +#define __NR_dup 23 +#define __NR_dup3 24 +#define __NR_fcntl 25 +#define __NR_inotify_init1 26 +#define __NR_inotify_add_watch 27 +#define __NR_inotify_rm_watch 28 +#define __NR_ioctl 29 +#define __NR_ioprio_set 30 +#define __NR_ioprio_get 31 +#define __NR_flock 32 +#define __NR_mknodat 33 +#define __NR_mkdirat 34 +#define __NR_unlinkat 35 +#define __NR_symlinkat 36 +#define __NR_linkat 37 +#define __NR_umount2 39 +#define __NR_mount 40 +#define __NR_pivot_root 41 +#define __NR_nfsservctl 42 +#define __NR_statfs 43 +#define __NR_fstatfs 44 +#define __NR_truncate 45 +#define __NR_ftruncate 46 +#define __NR_fallocate 47 +#define __NR_faccessat 48 +#define __NR_chdir 49 +#define __NR_fchdir 50 +#define __NR_chroot 51 +#define __NR_fchmod 52 +#define __NR_fchmodat 53 +#define __NR_fchownat 54 +#define __NR_fchown 55 +#define __NR_openat 56 +#define __NR_close 57 +#define __NR_vhangup 58 +#define __NR_pipe2 59 +#define __NR_quotactl 60 +#define __NR_getdents64 61 +#define __NR_lseek 62 +#define __NR_read 63 +#define __NR_write 64 +#define __NR_readv 65 +#define __NR_writev 66 +#define __NR_pread64 67 +#define __NR_pwrite64 68 +#define __NR_preadv 69 +#define __NR_pwritev 70 +#define __NR_sendfile 71 +#define __NR_pselect6 72 +#define __NR_ppoll 73 +#define __NR_signalfd4 74 +#define __NR_vmsplice 75 +#define __NR_splice 76 +#define __NR_tee 77 +#define __NR_readlinkat 78 +#define __NR_newfstatat 79 +#define __NR_fstat 80 +#define __NR_sync 81 +#define __NR_fsync 82 +#define __NR_fdatasync 83 +#define __NR_sync_file_range 84 +#define __NR_timerfd_create 85 +#define __NR_timerfd_settime 86 +#define __NR_timerfd_gettime 87 +#define __NR_utimensat 88 +#define __NR_acct 89 +#define __NR_capget 90 +#define __NR_capset 91 +#define __NR_personality 92 +#define __NR_exit 93 +#define __NR_exit_group 94 +#define __NR_waitid 95 +#define __NR_set_tid_address 96 +#define __NR_unshare 97 +#define __NR_futex 98 +#define __NR_set_robust_list 99 +#define __NR_get_robust_list 100 +#define __NR_nanosleep 101 +#define __NR_getitimer 102 +#define __NR_setitimer 103 +#define __NR_kexec_load 104 +#define __NR_init_module 105 +#define __NR_delete_module 106 +#define __NR_timer_create 107 +#define __NR_timer_gettime 108 +#define __NR_timer_getoverrun 109 +#define __NR_timer_settime 110 +#define __NR_timer_delete 111 +#define __NR_clock_settime 112 +#define __NR_clock_gettime 113 +#define __NR_clock_getres 114 +#define __NR_clock_nanosleep 115 +#define __NR_syslog 116 +#define __NR_ptrace 117 +#define __NR_sched_setparam 118 +#define __NR_sched_setscheduler 119 +#define __NR_sched_getscheduler 120 +#define __NR_sched_getparam 121 +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#define __NR_sched_yield 124 +#define __NR_sched_get_priority_max 125 +#define __NR_sched_get_priority_min 126 +#define __NR_sched_rr_get_interval 127 +#define __NR_restart_syscall 128 +#define __NR_kill 129 +#define __NR_tkill 130 +#define __NR_tgkill 131 +#define __NR_sigaltstack 132 +#define __NR_rt_sigsuspend 133 +#define __NR_rt_sigaction 134 +#define __NR_rt_sigprocmask 135 +#define __NR_rt_sigpending 136 +#define __NR_rt_sigtimedwait 137 +#define __NR_rt_sigqueueinfo 138 +#define __NR_rt_sigreturn 139 +#define __NR_setpriority 140 +#define __NR_getpriority 141 +#define __NR_reboot 142 +#define __NR_setregid 143 +#define __NR_setgid 144 +#define __NR_setreuid 145 +#define __NR_setuid 146 +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#define __NR_setfsuid 151 +#define __NR_setfsgid 152 +#define __NR_times 153 +#define __NR_setpgid 154 +#define __NR_getpgid 155 +#define __NR_getsid 156 +#define __NR_setsid 157 +#define __NR_getgroups 158 +#define __NR_setgroups 159 +#define __NR_uname 160 +#define __NR_sethostname 161 +#define __NR_setdomainname 162 +#define __NR_getrusage 165 +#define __NR_umask 166 +#define __NR_prctl 167 +#define __NR_getcpu 168 +#define __NR_gettimeofday 169 +#define __NR_settimeofday 170 +#define __NR_adjtimex 171 +#define __NR_getpid 172 +#define __NR_getppid 173 +#define __NR_getuid 174 +#define __NR_geteuid 175 +#define __NR_getgid 176 +#define __NR_getegid 177 +#define __NR_gettid 178 +#define __NR_sysinfo 179 +#define __NR_mq_open 180 +#define __NR_mq_unlink 181 +#define __NR_mq_timedsend 182 +#define __NR_mq_timedreceive 183 +#define __NR_mq_notify 184 +#define __NR_mq_getsetattr 185 +#define __NR_msgget 186 +#define __NR_msgctl 187 +#define __NR_msgrcv 188 +#define __NR_msgsnd 189 +#define __NR_semget 190 +#define __NR_semctl 191 +#define __NR_semtimedop 192 +#define __NR_semop 193 +#define __NR_shmget 194 +#define __NR_shmctl 195 +#define __NR_shmat 196 +#define __NR_shmdt 197 +#define __NR_socket 198 +#define __NR_socketpair 199 +#define __NR_bind 200 +#define __NR_listen 201 +#define __NR_accept 202 +#define __NR_connect 203 +#define __NR_getsockname 204 +#define __NR_getpeername 205 +#define __NR_sendto 206 +#define __NR_recvfrom 207 +#define __NR_setsockopt 208 +#define __NR_getsockopt 209 +#define __NR_shutdown 210 +#define __NR_sendmsg 211 +#define __NR_recvmsg 212 +#define __NR_readahead 213 +#define __NR_brk 214 +#define __NR_munmap 215 +#define __NR_mremap 216 +#define __NR_add_key 217 +#define __NR_request_key 218 +#define __NR_keyctl 219 +#define __NR_clone 220 +#define __NR_execve 221 +#define __NR_mmap 222 +#define __NR_fadvise64 223 +#define __NR_swapon 224 +#define __NR_swapoff 225 +#define __NR_mprotect 226 +#define __NR_msync 227 +#define __NR_mlock 228 +#define __NR_munlock 229 +#define __NR_mlockall 230 +#define __NR_munlockall 231 +#define __NR_mincore 232 +#define __NR_madvise 233 +#define __NR_remap_file_pages 234 +#define __NR_mbind 235 +#define __NR_get_mempolicy 236 +#define __NR_set_mempolicy 237 +#define __NR_migrate_pages 238 +#define __NR_move_pages 239 +#define __NR_rt_tgsigqueueinfo 240 +#define __NR_perf_event_open 241 +#define __NR_accept4 242 +#define __NR_recvmmsg 243 +#define __NR_wait4 260 +#define __NR_prlimit64 261 +#define __NR_fanotify_init 262 +#define __NR_fanotify_mark 263 +#define __NR_name_to_handle_at 264 +#define __NR_open_by_handle_at 265 +#define __NR_clock_adjtime 266 +#define __NR_syncfs 267 +#define __NR_setns 268 +#define __NR_sendmmsg 269 +#define __NR_process_vm_readv 270 +#define __NR_process_vm_writev 271 +#define __NR_kcmp 272 +#define __NR_finit_module 273 +#define __NR_sched_setattr 274 +#define __NR_sched_getattr 275 +#define __NR_renameat2 276 +#define __NR_seccomp 277 +#define __NR_getrandom 278 +#define __NR_memfd_create 279 +#define __NR_bpf 280 +#define __NR_execveat 281 +#define __NR_userfaultfd 282 +#define __NR_membarrier 283 +#define __NR_mlock2 284 +#define __NR_copy_file_range 285 +#define __NR_preadv2 286 +#define __NR_pwritev2 287 +#define __NR_pkey_mprotect 288 +#define __NR_pkey_alloc 289 +#define __NR_pkey_free 290 +#define __NR_statx 291 +#define __NR_io_pgetevents 292 +#define __NR_rseq 293 +#define __NR_kexec_file_load 294 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_cachestat 451 +#define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 +#define __NR_statmount 457 +#define __NR_listmount 458 +#define __NR_lsm_get_self_attr 459 +#define __NR_lsm_set_self_attr 460 +#define __NR_lsm_list_modules 461 +#define __NR_mseal 462 +#define __NR_setxattrat 463 +#define __NR_getxattrat 464 +#define __NR_listxattrat 465 +#define __NR_removexattrat 466 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/user/include/mlibc/sysdeps/linux/loongarch64/thread_entry.S b/user/include/mlibc/sysdeps/linux/loongarch64/thread_entry.S new file mode 100644 index 0000000..52ffb3a --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/loongarch64/thread_entry.S @@ -0,0 +1,24 @@ +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +__mlibc_spawn_thread: + // __mlibc_spawn_thread(flags, stack, pid_out, child_tid, tls) + // a0, a1, a2, a3, a4 + // syscall(NR_clone, flags, stack, ptid, ctid, tls) + // a7, a0, a1, a2, a3, a4 + + addi.d $a7, $zero, 220 // NR_clone + syscall 0 + bnez $a0, .parent + + ld.d $a0, $sp, 0 + ld.d $a1, $sp, 8 + addi.d $sp, $sp, 8 + bstrins.d $sp, $sp, 3, 0 + b __mlibc_enter_thread + break 0 + +.parent: + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/m68k/arch-syscall.cpp b/user/include/mlibc/sysdeps/linux/m68k/arch-syscall.cpp new file mode 100644 index 0000000..57b944e --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/arch-syscall.cpp @@ -0,0 +1,117 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +sc_word_t __do_syscall0(long sc) { + register int sc_reg asm("d0") = sc; + register sc_word_t ret asm("d0"); + asm volatile ("trap #0" : "=r"(ret) : "r"(sc_reg) : "memory"); + return ret; +} + +sc_word_t __do_syscall1(long sc, + sc_word_t arg1) { + register int sc_reg asm("d0") = sc; + register sc_word_t arg1_reg asm("d1") = arg1; + register sc_word_t ret asm("d0"); + asm volatile ("trap #0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall2(long sc, + sc_word_t arg1, sc_word_t arg2) { + register int sc_reg asm("d0") = sc; + register sc_word_t arg1_reg asm("d1") = arg1; + register sc_word_t arg2_reg asm("d2") = arg2; + register sc_word_t ret asm("d0"); + asm volatile ("trap #0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + register int sc_reg asm("d0") = sc; + register sc_word_t arg1_reg asm("d1") = arg1; + register sc_word_t arg2_reg asm("d2") = arg2; + register sc_word_t arg3_reg asm("d3") = arg3; + register sc_word_t ret asm("d0"); + asm volatile ("trap #0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + register int sc_reg asm("d0") = sc; + register sc_word_t arg1_reg asm("d1") = arg1; + register sc_word_t arg2_reg asm("d2") = arg2; + register sc_word_t arg3_reg asm("d3") = arg3; + register sc_word_t arg4_reg asm("d4") = arg4; + register sc_word_t ret asm("d0"); + asm volatile ("trap #0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + register int sc_reg asm("d0") = sc; + register sc_word_t arg1_reg asm("d1") = arg1; + register sc_word_t arg2_reg asm("d2") = arg2; + register sc_word_t arg3_reg asm("d3") = arg3; + register sc_word_t arg4_reg asm("d4") = arg4; + register sc_word_t arg5_reg asm("d5") = arg5; + register sc_word_t ret asm("d0"); + asm volatile ("trap #0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + register int sc_reg asm("d0") = sc; + register sc_word_t arg1_reg asm("d1") = arg1; + register sc_word_t arg2_reg asm("d2") = arg2; + register sc_word_t arg3_reg asm("d3") = arg3; + register sc_word_t arg4_reg asm("d4") = arg4; + register sc_word_t arg5_reg asm("d5") = arg5; + register sc_word_t arg6_reg asm("a0") = arg6; + register sc_word_t ret asm("d0"); + asm volatile ("trap #0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg), + "r"(arg6_reg) + : "memory" + ); + return ret; +} diff --git a/user/include/mlibc/sysdeps/linux/m68k/assembly-asserts.cpp b/user/include/mlibc/sysdeps/linux/m68k/assembly-asserts.cpp new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/sysdeps/linux/m68k/cp_syscall.S b/user/include/mlibc/sysdeps/linux/m68k/cp_syscall.S new file mode 100644 index 0000000..03db16d --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/cp_syscall.S @@ -0,0 +1,28 @@ + +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + movem.l %d2-%d5, -(%sp) + jbsr __m68k_read_tp@PLTPC + /* cancelBits is at TP - 0x7030; LSB at -0x702d */ + move.b -0x702d(%a0), %d0 +__mlibc_syscall_begin: + /* tcbCancelEnableBit && tcbCancelTriggerBit */ + andi.b #0x5, %d0 + cmpi.b #0x5, %d0 + beq cancel + movem.l 20(%sp), %d0-%d5/%a0 + trap #0 +__mlibc_syscall_end: + movem.l (%sp)+, %d2-%d5 + rts + +cancel: + movem.l (%sp)+, %d2-%d5 + jbsr __mlibc_do_cancel@PLTPC + illegal + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/m68k/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/linux/m68k/crt-src/Scrt1.S new file mode 100644 index 0000000..be9555e --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/crt-src/Scrt1.S @@ -0,0 +1,16 @@ +.section .text +.global _start + +.type _start, %function +.type main, %function +.type __mlibc_entry, %function + +_start: + suba.l %fp, %fp + move.l %sp, %d0 + lea _GLOBAL_OFFSET_TABLE_@GOTPC (%pc), %a5 + move.l main@GOT(%a5), -(%sp) + move.l %d0, -(%sp) + jbsr __mlibc_entry@PLTPC + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/m68k/crt-src/crt1.S b/user/include/mlibc/sysdeps/linux/m68k/crt-src/crt1.S new file mode 100644 index 0000000..ef4f4e8 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/crt-src/crt1.S @@ -0,0 +1,15 @@ +.section .text +.global _start + +.type _start, %function +.type main, %function +.type __mlibc_entry, %function + +_start: + suba.l %fp, %fp + move.l %sp, %d0 + move.l #main, -(%sp) + move.l %d0, -(%sp) + jsr __mlibc_entry + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/m68k/crt-src/crti.S b/user/include/mlibc/sysdeps/linux/m68k/crt-src/crti.S new file mode 100644 index 0000000..94dc4c4 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/crt-src/crti.S @@ -0,0 +1,9 @@ +.section ".init" +.global _init +_init: + +.section ".fini" +.globl _fini +_fini: + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/m68k/crt-src/crtn.S b/user/include/mlibc/sysdeps/linux/m68k/crt-src/crtn.S new file mode 100644 index 0000000..d8d7346 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/crt-src/crtn.S @@ -0,0 +1,7 @@ +.section .init + rts + +.section .fini + rts + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/m68k/signals.S b/user/include/mlibc/sysdeps/linux/m68k/signals.S new file mode 100644 index 0000000..ae42e79 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/signals.S @@ -0,0 +1,19 @@ +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: + move.l (%sp)+, %d1 + move.l #119, %d0 + trap #0 + illegal + +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + move.l (%sp)+, %d1 + move.l #173, %d0 + trap #0 + illegal + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/m68k/syscallnos.h b/user/include/mlibc/sysdeps/linux/m68k/syscallnos.h new file mode 100644 index 0000000..5dc7dcd --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/syscallnos.h @@ -0,0 +1,442 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_setpgid 57 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_vhangup 111 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_cacheflush 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_getpagesize 166 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread64 180 +#define __NR_pwrite64 181 +#define __NR_lchown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 +#define __NR_vfork 190 +#define __NR_ugetrlimit 191 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_chown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_lchown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 +#define __NR_getdents64 220 +#define __NR_gettid 221 +#define __NR_tkill 222 +#define __NR_setxattr 223 +#define __NR_lsetxattr 224 +#define __NR_fsetxattr 225 +#define __NR_getxattr 226 +#define __NR_lgetxattr 227 +#define __NR_fgetxattr 228 +#define __NR_listxattr 229 +#define __NR_llistxattr 230 +#define __NR_flistxattr 231 +#define __NR_removexattr 232 +#define __NR_lremovexattr 233 +#define __NR_fremovexattr 234 +#define __NR_futex 235 +#define __NR_sendfile64 236 +#define __NR_mincore 237 +#define __NR_madvise 238 +#define __NR_fcntl64 239 +#define __NR_readahead 240 +#define __NR_io_setup 241 +#define __NR_io_destroy 242 +#define __NR_io_getevents 243 +#define __NR_io_submit 244 +#define __NR_io_cancel 245 +#define __NR_fadvise64 246 +#define __NR_exit_group 247 +#define __NR_lookup_dcookie 248 +#define __NR_epoll_create 249 +#define __NR_epoll_ctl 250 +#define __NR_epoll_wait 251 +#define __NR_remap_file_pages 252 +#define __NR_set_tid_address 253 +#define __NR_timer_create 254 +#define __NR_timer_settime 255 +#define __NR_timer_gettime 256 +#define __NR_timer_getoverrun 257 +#define __NR_timer_delete 258 +#define __NR_clock_settime 259 +#define __NR_clock_gettime 260 +#define __NR_clock_getres 261 +#define __NR_clock_nanosleep 262 +#define __NR_statfs64 263 +#define __NR_fstatfs64 264 +#define __NR_tgkill 265 +#define __NR_utimes 266 +#define __NR_fadvise64_64 267 +#define __NR_mbind 268 +#define __NR_get_mempolicy 269 +#define __NR_set_mempolicy 270 +#define __NR_mq_open 271 +#define __NR_mq_unlink 272 +#define __NR_mq_timedsend 273 +#define __NR_mq_timedreceive 274 +#define __NR_mq_notify 275 +#define __NR_mq_getsetattr 276 +#define __NR_waitid 277 +#define __NR_add_key 279 +#define __NR_request_key 280 +#define __NR_keyctl 281 +#define __NR_ioprio_set 282 +#define __NR_ioprio_get 283 +#define __NR_inotify_init 284 +#define __NR_inotify_add_watch 285 +#define __NR_inotify_rm_watch 286 +#define __NR_migrate_pages 287 +#define __NR_openat 288 +#define __NR_mkdirat 289 +#define __NR_mknodat 290 +#define __NR_fchownat 291 +#define __NR_futimesat 292 +#define __NR_fstatat64 293 +#define __NR_unlinkat 294 +#define __NR_renameat 295 +#define __NR_linkat 296 +#define __NR_symlinkat 297 +#define __NR_readlinkat 298 +#define __NR_fchmodat 299 +#define __NR_faccessat 300 +#define __NR_pselect6 301 +#define __NR_ppoll 302 +#define __NR_unshare 303 +#define __NR_set_robust_list 304 +#define __NR_get_robust_list 305 +#define __NR_splice 306 +#define __NR_sync_file_range 307 +#define __NR_tee 308 +#define __NR_vmsplice 309 +#define __NR_move_pages 310 +#define __NR_sched_setaffinity 311 +#define __NR_sched_getaffinity 312 +#define __NR_kexec_load 313 +#define __NR_getcpu 314 +#define __NR_epoll_pwait 315 +#define __NR_utimensat 316 +#define __NR_signalfd 317 +#define __NR_timerfd_create 318 +#define __NR_eventfd 319 +#define __NR_fallocate 320 +#define __NR_timerfd_settime 321 +#define __NR_timerfd_gettime 322 +#define __NR_signalfd4 323 +#define __NR_eventfd2 324 +#define __NR_epoll_create1 325 +#define __NR_dup3 326 +#define __NR_pipe2 327 +#define __NR_inotify_init1 328 +#define __NR_preadv 329 +#define __NR_pwritev 330 +#define __NR_rt_tgsigqueueinfo 331 +#define __NR_perf_event_open 332 +#define __NR_get_thread_area 333 +#define __NR_set_thread_area 334 +#define __NR_atomic_cmpxchg_32 335 +#define __NR_atomic_barrier 336 +#define __NR_fanotify_init 337 +#define __NR_fanotify_mark 338 +#define __NR_prlimit64 339 +#define __NR_name_to_handle_at 340 +#define __NR_open_by_handle_at 341 +#define __NR_clock_adjtime 342 +#define __NR_syncfs 343 +#define __NR_setns 344 +#define __NR_process_vm_readv 345 +#define __NR_process_vm_writev 346 +#define __NR_kcmp 347 +#define __NR_finit_module 348 +#define __NR_sched_setattr 349 +#define __NR_sched_getattr 350 +#define __NR_renameat2 351 +#define __NR_getrandom 352 +#define __NR_memfd_create 353 +#define __NR_bpf 354 +#define __NR_execveat 355 +#define __NR_socket 356 +#define __NR_socketpair 357 +#define __NR_bind 358 +#define __NR_connect 359 +#define __NR_listen 360 +#define __NR_accept4 361 +#define __NR_getsockopt 362 +#define __NR_setsockopt 363 +#define __NR_getsockname 364 +#define __NR_getpeername 365 +#define __NR_sendto 366 +#define __NR_sendmsg 367 +#define __NR_recvfrom 368 +#define __NR_recvmsg 369 +#define __NR_shutdown 370 +#define __NR_recvmmsg 371 +#define __NR_sendmmsg 372 +#define __NR_userfaultfd 373 +#define __NR_membarrier 374 +#define __NR_mlock2 375 +#define __NR_copy_file_range 376 +#define __NR_preadv2 377 +#define __NR_pwritev2 378 +#define __NR_statx 379 +#define __NR_seccomp 380 +#define __NR_pkey_mprotect 381 +#define __NR_pkey_alloc 382 +#define __NR_pkey_free 383 +#define __NR_rseq 384 +#define __NR_semget 393 +#define __NR_semctl 394 +#define __NR_shmget 395 +#define __NR_shmctl 396 +#define __NR_shmat 397 +#define __NR_shmdt 398 +#define __NR_msgget 399 +#define __NR_msgsnd 400 +#define __NR_msgrcv 401 +#define __NR_msgctl 402 +#define __NR_clock_gettime64 403 +#define __NR_clock_settime64 404 +#define __NR_clock_adjtime64 405 +#define __NR_clock_getres_time64 406 +#define __NR_clock_nanosleep_time64 407 +#define __NR_timer_gettime64 408 +#define __NR_timer_settime64 409 +#define __NR_timerfd_gettime64 410 +#define __NR_timerfd_settime64 411 +#define __NR_utimensat_time64 412 +#define __NR_pselect6_time64 413 +#define __NR_ppoll_time64 414 +#define __NR_io_pgetevents_time64 416 +#define __NR_recvmmsg_time64 417 +#define __NR_mq_timedsend_time64 418 +#define __NR_mq_timedreceive_time64 419 +#define __NR_semtimedop_time64 420 +#define __NR_rt_sigtimedwait_time64 421 +#define __NR_futex_time64 422 +#define __NR_sched_rr_get_interval_time64 423 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_cachestat 451 +#define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 +#define __NR_statmount 457 +#define __NR_listmount 458 +#define __NR_lsm_get_self_attr 459 +#define __NR_lsm_set_self_attr 460 +#define __NR_lsm_list_modules 461 +#define __NR_mseal 462 +#define __NR_setxattrat 463 +#define __NR_getxattrat 464 +#define __NR_listxattrat 465 +#define __NR_removexattrat 466 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/user/include/mlibc/sysdeps/linux/m68k/thread_entry.S b/user/include/mlibc/sysdeps/linux/m68k/thread_entry.S new file mode 100644 index 0000000..702869f --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/m68k/thread_entry.S @@ -0,0 +1,24 @@ +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +/* int (int flags, void *stack, void *pid_out, void *child_tid, void *tcb); */ +__mlibc_spawn_thread: + movem.l %d2-%d5, -(%sp) + + move.l #120, %d0 + movem.l 20(%sp), %d1-%d5 + addi.l #0x7048, %d5 + trap #0 + + tst.l %d0 + beq 1f + + movem.l (%sp)+, %d2-%d5 + rts + +1: + jbsr __mlibc_enter_thread@PLTPC + illegal + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/meson.build b/user/include/mlibc/sysdeps/linux/meson.build new file mode 100644 index 0000000..2a71a2b --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/meson.build @@ -0,0 +1,170 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': true, + 'glibc': true, + 'bsd': true, +} + +rtld_dso_sources += files( + host_machine.cpu_family() / 'arch-syscall.cpp', + 'generic/sysdeps.cpp', +) + +linux_include_dirs = [ + include_directories(host_machine.cpu_family()), + include_directories('include-internal/'), +] + +rtld_include_dirs += linux_include_dirs +libc_include_dirs += linux_include_dirs +libc_sources += files( + host_machine.cpu_family() / 'signals.S', + host_machine.cpu_family() / 'arch-syscall.cpp', + host_machine.cpu_family() / 'assembly-asserts.cpp', + 'generic/entry.cpp', + 'generic/sysdeps.cpp', +) + +if get_option('posix_option').allowed() + libc_sources += files( + 'generic/thread.cpp', + host_machine.cpu_family() / 'cp_syscall.S', + host_machine.cpu_family() / 'thread_entry.S' + ) +endif + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/vt.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/random.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + if host_machine.cpu_family() == 'riscv64' + install_headers( + 'include/abi-bits/riscv-hwprobe.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + endif + + install_headers('include/syscall.h') + install_headers('include/sys/syscall.h', subdir: 'sys') + install_headers( + 'include/bits/syscall.h', + 'include/bits/syscall_aliases.h', + subdir: 'bits' + ) +endif + +if not headers_only + crt = custom_target('crt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crt1.S', + output: 'crt1.o', + install: true, + install_dir: get_option('libdir') + ) + + crt_pie = custom_target('Scrt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-fPIE', '-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/Scrt1.S', + output: 'Scrt1.o', + install: true, + install_dir: get_option('libdir') + ) + + # On RISC-V and LoongArch, crti.o and crtn.o are provided by GCC. + if host_machine.cpu_family() != 'riscv64' and host_machine.cpu_family() != 'loongarch64' + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) + endif + + wrapper_conf = configuration_data() + wrapper_conf.set('LIBDIR', get_option('libdir')) + wrapper_conf.set('PREFIX', get_option('prefix')) + specs = configure_file(input: 'mlibc-gcc.specs.in', + output: 'mlibc-gcc.specs', + configuration: wrapper_conf) + + wrapper_script = configure_file(input: 'mlibc-gcc.in', + output: 'mlibc-gcc', + configuration: wrapper_conf) + + install_data(specs, + install_dir: get_option('libdir') + ) + + install_data(wrapper_script, + install_dir: get_option('bindir') + ) +endif diff --git a/user/include/mlibc/sysdeps/linux/mlibc-gcc.in b/user/include/mlibc/sysdeps/linux/mlibc-gcc.in new file mode 100755 index 0000000..6236bd6 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/mlibc-gcc.in @@ -0,0 +1,2 @@ +#!/bin/sh +exec "${REALGCC:-gcc}" "$@" -specs "@PREFIX@/@LIBDIR@/mlibc-gcc.specs" diff --git a/user/include/mlibc/sysdeps/linux/mlibc-gcc.specs.in b/user/include/mlibc/sysdeps/linux/mlibc-gcc.specs.in new file mode 100644 index 0000000..4304c4d --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/mlibc-gcc.specs.in @@ -0,0 +1,32 @@ +%rename cpp_options old_cpp_options + +*cpp_options: +-nostdinc -isystem @PREFIX@/include -isystem include%s %(old_cpp_options) + +*cc1: +%(cc1_cpu) -nostdinc -isystem @PREFIX@/include -isystem include%s + +*link_libgcc: +-L@PREFIX@/@LIBDIR@ -L .%s + +*libgcc: +libgcc.a%s %:if-exists(libgcc_eh.a%s) + +*startfile: +%{!shared: @PREFIX@/@LIBDIR@/Scrt1.o} @PREFIX@/@LIBDIR@/crti.o crtbeginS.o%s + +*endfile: +crtendS.o%s @PREFIX@/@LIBDIR@/crtn.o + +*link: +-dynamic-linker @PREFIX@/@LIBDIR@/ld.so -rpath @PREFIX@/@LIBDIR@ -nostdlib %{shared:-shared} %{static:-static} %{rdynamic:-export-dynamic} + +*esp_link: + + +*esp_options: + + +*esp_cpp_options: + + diff --git a/user/include/mlibc/sysdeps/linux/riscv64/arch-syscall.cpp b/user/include/mlibc/sysdeps/linux/riscv64/arch-syscall.cpp new file mode 100644 index 0000000..18ac6b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/riscv64/arch-syscall.cpp @@ -0,0 +1,117 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +sc_word_t __do_syscall0(long sc) { + register int sc_reg asm("a7") = sc; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : "r"(sc_reg) : "memory", "a1"); + return ret; +} + +sc_word_t __do_syscall1(long sc, + sc_word_t arg1) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg) + : "memory", "a1"); + return ret; +} + +sc_word_t __do_syscall2(long sc, + sc_word_t arg1, sc_word_t arg2) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t arg5_reg asm("a4") = arg5; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t arg5_reg asm("a4") = arg5; + register sc_word_t arg6_reg asm("a5") = arg6; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg), + "r"(arg6_reg) + : "memory" + ); + return ret; +} diff --git a/user/include/mlibc/sysdeps/linux/riscv64/assembly-asserts.cpp b/user/include/mlibc/sysdeps/linux/riscv64/assembly-asserts.cpp new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/sysdeps/linux/riscv64/cp_syscall.S b/user/include/mlibc/sysdeps/linux/riscv64/cp_syscall.S new file mode 100644 index 0000000..8d3175d --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/riscv64/cp_syscall.S @@ -0,0 +1,30 @@ +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + sd a7, -8(sp) + mv a7, a0 + mv a0, a1 + mv a1, a2 + mv a2, a3 + mv a3, a4 + mv a4, a5 + mv a5, a6 + ld a6, -8(sp) // a7 + lw t0, -96(tp) // Tcb::cancelBits. See asserts in tcb.hpp. +__mlibc_syscall_begin: + // tcbCancelEnableBit && tcbCancelTriggerBit + li t1, (1 << 0) | (1 << 2) + and t0, t0, t1 + beq t0, t1, cancel + ecall +__mlibc_syscall_end: + ret + +cancel: + call __mlibc_do_cancel + unimp +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/riscv64/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/linux/riscv64/crt-src/Scrt1.S new file mode 100644 index 0000000..17cc3fd --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/riscv64/crt-src/Scrt1.S @@ -0,0 +1,30 @@ +.weak __global_pointer$ +.hidden __global_pointer$ + +.section .text +.global _start +_start: + # Load gp. +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + + mv a0, sp + la a1, main + call __mlibc_entry@plt + unimp + +# Load gp from .preinit_array since it may be used by the executable's .init_array. +# We still load it in _start to account for static binaries. This matches glibc's behavior. +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + +.section .preinit_array,"aw" + .dword load_gp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/riscv64/crt-src/crt1.S b/user/include/mlibc/sysdeps/linux/riscv64/crt-src/crt1.S new file mode 100644 index 0000000..faaf407 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/riscv64/crt-src/crt1.S @@ -0,0 +1,30 @@ +.weak __global_pointer$ +.hidden __global_pointer$ + +.section .text +.global _start +_start: + # Load gp. +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + + mv a0, sp + la a1, main + call __mlibc_entry + unimp + +# Load gp from .preinit_array since it may be used by the executable's .init_array. +# We still load it in _start to account for static binaries. This matches glibc's behavior. +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + +.section .preinit_array,"aw" + .dword load_gp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/riscv64/signals.S b/user/include/mlibc/sysdeps/linux/riscv64/signals.S new file mode 100644 index 0000000..7769043 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/riscv64/signals.S @@ -0,0 +1,12 @@ +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + li a7, 139 + ecall +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/riscv64/syscallnos.h b/user/include/mlibc/sysdeps/linux/riscv64/syscallnos.h new file mode 100644 index 0000000..49f5db4 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/riscv64/syscallnos.h @@ -0,0 +1,328 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_io_setup 0 +#define __NR_io_destroy 1 +#define __NR_io_submit 2 +#define __NR_io_cancel 3 +#define __NR_io_getevents 4 +#define __NR_setxattr 5 +#define __NR_lsetxattr 6 +#define __NR_fsetxattr 7 +#define __NR_getxattr 8 +#define __NR_lgetxattr 9 +#define __NR_fgetxattr 10 +#define __NR_listxattr 11 +#define __NR_llistxattr 12 +#define __NR_flistxattr 13 +#define __NR_removexattr 14 +#define __NR_lremovexattr 15 +#define __NR_fremovexattr 16 +#define __NR_getcwd 17 +#define __NR_lookup_dcookie 18 +#define __NR_eventfd2 19 +#define __NR_epoll_create1 20 +#define __NR_epoll_ctl 21 +#define __NR_epoll_pwait 22 +#define __NR_dup 23 +#define __NR_dup3 24 +#define __NR_fcntl 25 +#define __NR_inotify_init1 26 +#define __NR_inotify_add_watch 27 +#define __NR_inotify_rm_watch 28 +#define __NR_ioctl 29 +#define __NR_ioprio_set 30 +#define __NR_ioprio_get 31 +#define __NR_flock 32 +#define __NR_mknodat 33 +#define __NR_mkdirat 34 +#define __NR_unlinkat 35 +#define __NR_symlinkat 36 +#define __NR_linkat 37 +#define __NR_umount2 39 +#define __NR_mount 40 +#define __NR_pivot_root 41 +#define __NR_nfsservctl 42 +#define __NR_statfs 43 +#define __NR_fstatfs 44 +#define __NR_truncate 45 +#define __NR_ftruncate 46 +#define __NR_fallocate 47 +#define __NR_faccessat 48 +#define __NR_chdir 49 +#define __NR_fchdir 50 +#define __NR_chroot 51 +#define __NR_fchmod 52 +#define __NR_fchmodat 53 +#define __NR_fchownat 54 +#define __NR_fchown 55 +#define __NR_openat 56 +#define __NR_close 57 +#define __NR_vhangup 58 +#define __NR_pipe2 59 +#define __NR_quotactl 60 +#define __NR_getdents64 61 +#define __NR_lseek 62 +#define __NR_read 63 +#define __NR_write 64 +#define __NR_readv 65 +#define __NR_writev 66 +#define __NR_pread64 67 +#define __NR_pwrite64 68 +#define __NR_preadv 69 +#define __NR_pwritev 70 +#define __NR_sendfile 71 +#define __NR_pselect6 72 +#define __NR_ppoll 73 +#define __NR_signalfd4 74 +#define __NR_vmsplice 75 +#define __NR_splice 76 +#define __NR_tee 77 +#define __NR_readlinkat 78 +#define __NR_newfstatat 79 +#define __NR_fstat 80 +#define __NR_sync 81 +#define __NR_fsync 82 +#define __NR_fdatasync 83 +#define __NR_sync_file_range 84 +#define __NR_timerfd_create 85 +#define __NR_timerfd_settime 86 +#define __NR_timerfd_gettime 87 +#define __NR_utimensat 88 +#define __NR_acct 89 +#define __NR_capget 90 +#define __NR_capset 91 +#define __NR_personality 92 +#define __NR_exit 93 +#define __NR_exit_group 94 +#define __NR_waitid 95 +#define __NR_set_tid_address 96 +#define __NR_unshare 97 +#define __NR_futex 98 +#define __NR_set_robust_list 99 +#define __NR_get_robust_list 100 +#define __NR_nanosleep 101 +#define __NR_getitimer 102 +#define __NR_setitimer 103 +#define __NR_kexec_load 104 +#define __NR_init_module 105 +#define __NR_delete_module 106 +#define __NR_timer_create 107 +#define __NR_timer_gettime 108 +#define __NR_timer_getoverrun 109 +#define __NR_timer_settime 110 +#define __NR_timer_delete 111 +#define __NR_clock_settime 112 +#define __NR_clock_gettime 113 +#define __NR_clock_getres 114 +#define __NR_clock_nanosleep 115 +#define __NR_syslog 116 +#define __NR_ptrace 117 +#define __NR_sched_setparam 118 +#define __NR_sched_setscheduler 119 +#define __NR_sched_getscheduler 120 +#define __NR_sched_getparam 121 +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#define __NR_sched_yield 124 +#define __NR_sched_get_priority_max 125 +#define __NR_sched_get_priority_min 126 +#define __NR_sched_rr_get_interval 127 +#define __NR_restart_syscall 128 +#define __NR_kill 129 +#define __NR_tkill 130 +#define __NR_tgkill 131 +#define __NR_sigaltstack 132 +#define __NR_rt_sigsuspend 133 +#define __NR_rt_sigaction 134 +#define __NR_rt_sigprocmask 135 +#define __NR_rt_sigpending 136 +#define __NR_rt_sigtimedwait 137 +#define __NR_rt_sigqueueinfo 138 +#define __NR_rt_sigreturn 139 +#define __NR_setpriority 140 +#define __NR_getpriority 141 +#define __NR_reboot 142 +#define __NR_setregid 143 +#define __NR_setgid 144 +#define __NR_setreuid 145 +#define __NR_setuid 146 +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#define __NR_setfsuid 151 +#define __NR_setfsgid 152 +#define __NR_times 153 +#define __NR_setpgid 154 +#define __NR_getpgid 155 +#define __NR_getsid 156 +#define __NR_setsid 157 +#define __NR_getgroups 158 +#define __NR_setgroups 159 +#define __NR_uname 160 +#define __NR_sethostname 161 +#define __NR_setdomainname 162 +#define __NR_getrlimit 163 +#define __NR_setrlimit 164 +#define __NR_getrusage 165 +#define __NR_umask 166 +#define __NR_prctl 167 +#define __NR_getcpu 168 +#define __NR_gettimeofday 169 +#define __NR_settimeofday 170 +#define __NR_adjtimex 171 +#define __NR_getpid 172 +#define __NR_getppid 173 +#define __NR_getuid 174 +#define __NR_geteuid 175 +#define __NR_getgid 176 +#define __NR_getegid 177 +#define __NR_gettid 178 +#define __NR_sysinfo 179 +#define __NR_mq_open 180 +#define __NR_mq_unlink 181 +#define __NR_mq_timedsend 182 +#define __NR_mq_timedreceive 183 +#define __NR_mq_notify 184 +#define __NR_mq_getsetattr 185 +#define __NR_msgget 186 +#define __NR_msgctl 187 +#define __NR_msgrcv 188 +#define __NR_msgsnd 189 +#define __NR_semget 190 +#define __NR_semctl 191 +#define __NR_semtimedop 192 +#define __NR_semop 193 +#define __NR_shmget 194 +#define __NR_shmctl 195 +#define __NR_shmat 196 +#define __NR_shmdt 197 +#define __NR_socket 198 +#define __NR_socketpair 199 +#define __NR_bind 200 +#define __NR_listen 201 +#define __NR_accept 202 +#define __NR_connect 203 +#define __NR_getsockname 204 +#define __NR_getpeername 205 +#define __NR_sendto 206 +#define __NR_recvfrom 207 +#define __NR_setsockopt 208 +#define __NR_getsockopt 209 +#define __NR_shutdown 210 +#define __NR_sendmsg 211 +#define __NR_recvmsg 212 +#define __NR_readahead 213 +#define __NR_brk 214 +#define __NR_munmap 215 +#define __NR_mremap 216 +#define __NR_add_key 217 +#define __NR_request_key 218 +#define __NR_keyctl 219 +#define __NR_clone 220 +#define __NR_execve 221 +#define __NR_mmap 222 +#define __NR_fadvise64 223 +#define __NR_swapon 224 +#define __NR_swapoff 225 +#define __NR_mprotect 226 +#define __NR_msync 227 +#define __NR_mlock 228 +#define __NR_munlock 229 +#define __NR_mlockall 230 +#define __NR_munlockall 231 +#define __NR_mincore 232 +#define __NR_madvise 233 +#define __NR_remap_file_pages 234 +#define __NR_mbind 235 +#define __NR_get_mempolicy 236 +#define __NR_set_mempolicy 237 +#define __NR_migrate_pages 238 +#define __NR_move_pages 239 +#define __NR_rt_tgsigqueueinfo 240 +#define __NR_perf_event_open 241 +#define __NR_accept4 242 +#define __NR_recvmmsg 243 +#define __NR_riscv_hwprobe 258 +#define __NR_riscv_flush_icache 259 +#define __NR_wait4 260 +#define __NR_prlimit64 261 +#define __NR_fanotify_init 262 +#define __NR_fanotify_mark 263 +#define __NR_name_to_handle_at 264 +#define __NR_open_by_handle_at 265 +#define __NR_clock_adjtime 266 +#define __NR_syncfs 267 +#define __NR_setns 268 +#define __NR_sendmmsg 269 +#define __NR_process_vm_readv 270 +#define __NR_process_vm_writev 271 +#define __NR_kcmp 272 +#define __NR_finit_module 273 +#define __NR_sched_setattr 274 +#define __NR_sched_getattr 275 +#define __NR_renameat2 276 +#define __NR_seccomp 277 +#define __NR_getrandom 278 +#define __NR_memfd_create 279 +#define __NR_bpf 280 +#define __NR_execveat 281 +#define __NR_userfaultfd 282 +#define __NR_membarrier 283 +#define __NR_mlock2 284 +#define __NR_copy_file_range 285 +#define __NR_preadv2 286 +#define __NR_pwritev2 287 +#define __NR_pkey_mprotect 288 +#define __NR_pkey_alloc 289 +#define __NR_pkey_free 290 +#define __NR_statx 291 +#define __NR_io_pgetevents 292 +#define __NR_rseq 293 +#define __NR_kexec_file_load 294 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_memfd_secret 447 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_cachestat 451 +#define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 +#define __NR_statmount 457 +#define __NR_listmount 458 +#define __NR_lsm_get_self_attr 459 +#define __NR_lsm_set_self_attr 460 +#define __NR_lsm_list_modules 461 +#define __NR_mseal 462 +#define __NR_setxattrat 463 +#define __NR_getxattrat 464 +#define __NR_listxattrat 465 +#define __NR_removexattrat 466 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/user/include/mlibc/sysdeps/linux/riscv64/thread_entry.S b/user/include/mlibc/sysdeps/linux/riscv64/thread_entry.S new file mode 100644 index 0000000..fe170fa --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/riscv64/thread_entry.S @@ -0,0 +1,29 @@ +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +__mlibc_spawn_thread: + // __mlibc_spawn_thread(flags, stack, pid_out, child_tid, tls) + // a0, a1, a2, a3, a4 + // syscall(NR_clone, flags, stack, ptid, tls, ctid) + // a7, a0, a1, a2, a3, a4 + + // Swap a3 <-> a4 + mv a5, a4 + mv a4, a3 + mv a3, a5 + + li a7, 220 // NR_clone + ecall + bnez a0, .parent + + ld a0, 0(sp) + ld a1, 8(sp) + addi sp, sp, 8 + andi sp, sp, -16 + call __mlibc_enter_thread + unimp + +.parent: + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/update-syscall-list.py b/user/include/mlibc/sysdeps/linux/update-syscall-list.py new file mode 100755 index 0000000..ee6937a --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/update-syscall-list.py @@ -0,0 +1,333 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MIT + +import argparse +import hashlib +import io +import json +import logging +import os +import os.path as path +import pathlib +import subprocess +import tarfile +import tempfile +import urllib.request as urr +from dataclasses import dataclass + +KERNEL_RELEASES = "https://www.kernel.org/releases.json" +NR_PREFIX = "__NR_" +logging.basicConfig(level=logging.DEBUG) +LOGGER = logging.getLogger(__name__) + +# ADD NEW ARCHITECTURES HERE: these should match directory names in Linuxes arch/ +# directory or the second element of one of the harnesses below +WANTED_ARCHES = ["riscv64", "x86_64", "arm64", "i386", "m68k", "loongarch64"] +# How to translate from Linux arch directory names to gnutools architecture fields +LINUX_GNU_TRANSLATION = { + "arm64": "aarch64", + "i386": "x86", + "loongarch": "loongarch64", +} + +argp = argparse.ArgumentParser() +argp.add_argument("kver", help="Kernel version to download", default="latest") + + +@dataclass +class Kernel: + version: str + srchash: str + srcdir: pathlib.Path + + +@dataclass +class Context: + dirpath: pathlib.Path + + +def run(args: list[str], **kwargs): + LOGGER.debug("running %s", args) + subprocess.check_call(args, **kwargs) + + +def collect(args: list[str], **kwargs): + LOGGER.debug("running %s (kw: %s)", args, kwargs) + kwargs.setdefault("text", True) + return subprocess.check_output(args, **kwargs) + + +def fetch_kernel(ctx: Context, kver: str) -> Kernel: + LOGGER.debug("fetching %s", KERNEL_RELEASES) + with urr.urlopen(KERNEL_RELEASES) as f: + if f.status != 200: + LOGGER.error("meta fetch failed: %s", f) + raise RuntimeError("failed to get kernel meta") + metadata = json.load(f) + + if kver == "latest": + kver = metadata["latest_stable"]["version"] + + LOGGER.debug("figured out kernel version: %s", kver) + + for rel in metadata["releases"]: + if rel["version"] == kver: + kernel_release = rel + break + else: + raise RuntimeError("failed to find kver " + kver) + + kurl = kernel_release["source"] + LOGGER.debug("kernel src url: %s", kurl) + source_path = ctx.dirpath / ("source.tar" + path.splitext(kurl)[1]) + + with urr.urlopen(kurl) as f, open(source_path, "wb") as g: + if f.status != 200: + LOGGER.error("ksrc fetch failed: %s", f) + raise RuntimeError("failed to get kernel source") + + hasher = hashlib.blake2b() + while buf := f.read(16 * 1024): + hasher.update(buf) + g.write(buf) + + srchash = hasher.hexdigest() + srcpath = ctx.dirpath / "src" + + with tarfile.open(source_path) as srctar: + memb: tarfile.TarInfo + for memb in srctar: + if not memb.name.startswith("linux-"): + raise RuntimeError( + "malformed tar member in %s (%s): %s has bad prefix".format( + kurl, srchash, memb.name + ) + ) + memb.name = "./" + memb.name[memb.name.find("/") + 1 :] + srctar.extract(memb, path=srcpath) + + return Kernel( + version=kver, + srchash=srchash, + srcdir=srcpath, + ) + + +def run_harness(ctx: Context, kernel: Kernel, harness: (str, str)) -> dict[str, int]: + LOGGER.debug("running harness %s", harness) + (archdir, arch, defines) = harness + flags = [f"-D{x}" for x in defines] + archout = ctx.dirpath / "headers" / archdir + if not archout.exists(): + run( + [ + "make", + "-sC", + kernel.srcdir, + f"ARCH={archdir}", + f"O={archout}", + "headers_install", + ] + ) + + hdrdir = archout / "usr/include" + callset = set() + for x in collect( + ["gcc", "-E", "-dM", "-I", hdrdir, *flags, "-"], input="#include " + ).splitlines(): + x = x.split(maxsplit=2) + if len(x) < 2 or x[0] != "#define": + # skip invalid lines + continue + + defname = x[1] + if not defname.startswith(NR_PREFIX): + # not a syscall + continue + + defname = defname[len(NR_PREFIX) :] + + if ( + "SYSCALL" in defname + or defname.startswith("available") + or defname.startswith("reserved") + or defname.startswith("unused") + ): + continue + + # dead syscalls + if defname in [ + "Linux", + "afs_syscall", + "break", + "ftime", + "gtty", + "lock", + "mpx", + "oldwait4", + "prof", + "profil", + "putpmsg", + "security", + "stty", + "tuxcall", + "ulimit", + "vserver", + "arm_sync_file_range", + "utimesat", + "ni_syscall", + "xtensa", + ]: + continue + callset.add(defname) + + # alright, we have the set of all syscalls, time to produce their numbers + syscall_dumper = """ +/* my sincerest apologies */ +#include +""" + + for x in defines: + syscall_dumper += "#define {}\n".format(x.replace("=", " ")) + + syscall_dumper += """ +#include + +int main() { + puts("{"); + """ + + comma = "" + for x in callset: + syscall_dumper += 'printf("{comma}\\"{sc}\\": %d\\n", {pfx}{sc});\n '.format( + sc=x, comma=comma, pfx=NR_PREFIX + ) + comma = "," + + syscall_dumper += """ + puts("}"); +} +""" + + dumper = archout / "dumper" + with tempfile.NamedTemporaryFile(suffix=".c") as src: + src.write(syscall_dumper.encode()) + run(["gcc", "-o", dumper, "-I", hdrdir, src.name]) + return json.loads(collect([dumper])) + + +def main(ctx: Context): + args = argp.parse_args() + kernel = fetch_kernel(ctx, args.kver) + + LOGGER.info("got kernel version %s (%s)", kernel.version, kernel.srchash) + + archlist = os.listdir(kernel.srcdir / "arch") + archlist.remove("Kconfig") + archlist.remove("um") + + # harnesses converted from + # https://github.com/hrw/syscalls-table/blob/c638834d9b5d71bb40a555755ea07735cace58f2/do_all_tables.sh + # (arch_dirname, archname, list[defines]) + harnesses: (str, str, list[str]) + harnesses = [ + (arch,) + x + for arch in archlist + if not arch.startswith(".") + for x in { + # arch specific overrides + # format: (archname, list[defines]), gets prefixed with archdir outside + "arm": [ + ("armoabi", []), + ("arm", ["__ARM_EABI_"]), + ], + "loongarch": [ + ("loongarch64", ["_LOONGARCH_SZLONG=64"]), + ], + "mips": [ + ("mipso32", ["_MIPS_SIM=_MIPS_SIM_ABI32"]), + ("mips64n32", ["_MIPS_SIM=_MIPS_SIM_NABI32"]), + ("mips64", ["_MIPS_SIM=_MIPS_SIM_ABI64"]), + ], + "powerpc": [ + ("powerpc", []), + ("powerpc64", []), + ], + "riscv": [ + ("riscv32", ["__SIZEOF_POINTER__=4"]), + ("riscv64", ["__LP64__"]), + ], + "s390": [ + ("s390", []), + ("s390x", []), + ], + "sparc": [ + ("sparc", ["__32bit_syscall_numbers__"]), + ("sparc64", ["__arch64__"]), + ], + "tile": [ + ("tile", []), + ("tile64", ["__LP64__", "__tilegx__"]), + ], + "x86": [ + ("i386", ["__i386__"]), + ("x32", ["__ILP32__"]), + ("x86_64", ["__LP64__"]), + ], + }.get(arch, [(arch, [])]) + ] + + syscall_set = set() + + for x in harnesses: + syscalls = run_harness(ctx, kernel, x) + syscall_set |= syscalls.keys() + + wanted_arch = x[1] + if wanted_arch not in WANTED_ARCHES: + continue + + wanted_arch = LINUX_GNU_TRANSLATION.get(wanted_arch, wanted_arch) + + pathlib.Path(wanted_arch).mkdir(exist_ok=True) + + with open(wanted_arch + "/syscallnos.h", "w") as f: + print("#ifndef __MLIBC_SYSCALLNOS_h", file=f) + print("#define __MLIBC_SYSCALLNOS_h", file=f) + print("/* This file is autogenerated. Don't bother. */", file=f) + print( + "/* Generator script: sysdeps/linux/update-syscall-list.py. */", file=f + ) + + for name, num in sorted(syscalls.items(), key=lambda x: x[1]): + print("#define {p}{sc} {n}".format(p=NR_PREFIX, sc=name, n=num), file=f) + + print("#endif /* __MLIBC_SYSCALLNOS_h */", file=f) + + with open("include/bits/syscall_aliases.h", "w") as f: + print("#ifndef __MLIBC_SYSCALL_ALIAS_BIT", file=f) + print("#define __MLIBC_SYSCALL_ALIAS_BIT", file=f) + print("/* This file is autogenerated. Don't bother. */", file=f) + print("/* Generator script: sysdeps/linux/update-syscall-list.py. */", file=f) + + for x in sorted(list(syscall_set)): + print( + f"""\ +#ifdef\t{NR_PREFIX}{x} +#\tdefine SYS_{x} {NR_PREFIX}{x} +#endif +""", + end="", + file=f, + ) + + print("#endif /* __MLIBC_SYSCALL_ALIAS_BIT */", file=f) + + +if __name__ == "__main__": + with tempfile.TemporaryDirectory() as td: + main( + Context( + dirpath=pathlib.Path(td), + ) + ) diff --git a/user/include/mlibc/sysdeps/linux/x86/arch-syscall.cpp b/user/include/mlibc/sysdeps/linux/x86/arch-syscall.cpp new file mode 100644 index 0000000..35fc8aa --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/arch-syscall.cpp @@ -0,0 +1,90 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +// Note: ebx is used for PIC (it holds a reference to the GOT), so we can't clobber it with gcc apparently, +// and also need to make sure to restore it after a syscall + +sc_word_t __do_syscall0(long sc) { + sc_word_t ret; + asm volatile("int $0x80" : "=a"(ret) : "a"(sc) : "memory"); + return ret; +} + +sc_word_t __do_syscall1(long sc, sc_word_t arg1) { + sc_word_t ret; + asm volatile("xchg %%ebx, %%edi;" + "int $0x80;" + "xchg %%edi, %%ebx;" + : "=a"(ret) + : "a"(sc), "D"(arg1) + : "memory"); + return ret; +} + +sc_word_t __do_syscall2(long sc, sc_word_t arg1, sc_word_t arg2) { + sc_word_t ret; + asm volatile("xchg %%ebx, %%edi;" + "int $0x80;" + "xchg %%edi, %%ebx;" + : "=a"(ret) + : "a"(sc), "D"(arg1), "c"(arg2) + : "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + sc_word_t ret; + asm volatile("xchg %%ebx, %%edi;" + "int $0x80;" + "xchg %%edi, %%ebx;" + : "=a"(ret) + : "a"(sc), "D"(arg1), "c"(arg2), "d"(arg3) + : "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, sc_word_t arg4) { + sc_word_t ret; + asm volatile("xchg %%ebx, %%edi;" + "int $0x80;" + "xchg %%edi, %%ebx;" + : "=a"(ret) + : "a"(sc), "D"(arg1), "c"(arg2), "d"(arg3), "S"(arg4) + : "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, sc_word_t arg4, + sc_word_t arg5) { + sc_word_t ret; + asm volatile("pushl %2;" + "push %%ebx;" + "mov 4(%%esp), %%ebx;" + "int $0x80;" + "pop %%ebx;" + "add $4, %%esp;" + : "=a"(ret) + : "a"(sc), "g"(arg1), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5) + : "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, sc_word_t arg4, + sc_word_t arg5, sc_word_t arg6) { + sc_word_t ret; + sc_word_t a1a6[2] = { arg1, arg6 }; + asm volatile ("pushl %1;" + "push %%ebx;" + "push %%ebp;" + "mov 8(%%esp),%%ebx;" + "mov 4(%%ebx),%%ebp;" + "mov (%%ebx),%%ebx;" + "int $0x80;" + "pop %%ebp;" + "pop %%ebx;" + "add $4,%%esp;" + : "=a"(ret) : "g"(&a1a6), "a"(sc), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5) : "memory"); + return ret; +} diff --git a/user/include/mlibc/sysdeps/linux/x86/assembly-asserts.cpp b/user/include/mlibc/sysdeps/linux/x86/assembly-asserts.cpp new file mode 100644 index 0000000..e69de29 diff --git a/user/include/mlibc/sysdeps/linux/x86/cp_syscall.S b/user/include/mlibc/sysdeps/linux/x86/cp_syscall.S new file mode 100644 index 0000000..b89e1f4 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/cp_syscall.S @@ -0,0 +1,42 @@ + +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + push %ebx + push %esi + push %edi + push %ebp + ; mov 16(%esp), %eax + mov 24(%esp), %ebx + mov 28(%esp), %ecx + mov 32(%esp), %edx + mov 36(%esp), %esi + mov 40(%esp), %edi + mov 44(%esp), %ebp + mov %gs:0x18, %al +__mlibc_syscall_begin: + /* tcbCancelEnableBit && tcbCancelTriggerBit */ + and $((1 << 0) | (1 << 2)), %al + cmp $((1 << 0) | (1 << 2)), %al + je cancel + mov 20(%esp), %eax + int $0x80 +__mlibc_syscall_end: + pop %ebp + pop %edi + pop %esi + pop %ebx + ret + +cancel: + pop %ebp + pop %edi + pop %esi + pop %ebx + call __mlibc_do_cancel@PLT + hlt + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/x86/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/linux/x86/crt-src/Scrt1.S new file mode 100644 index 0000000..a62b127 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/crt-src/Scrt1.S @@ -0,0 +1,29 @@ +.section .text + +.type __stack_chk_fail_local, %function +.weak __stack_chk_fail_local +__stack_chk_fail_local: + call __stack_chk_fail@plt + +.global _start + +.type _start, %function +.type main, %function +.type __mlibc_entry, %function + +.cfi_startproc +_start: +.cfi_undefined eip + xor %ebp, %ebp + mov %esp, %edi + call 1f + +1: + pop %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + push main@GOT(%ebx) + push %edi + call __mlibc_entry@plt +.cfi_endproc + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/x86/crt-src/crt1.S b/user/include/mlibc/sysdeps/linux/x86/crt-src/crt1.S new file mode 100644 index 0000000..ed45da3 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/crt-src/crt1.S @@ -0,0 +1,18 @@ +.section .text +.global _start + +.type _start, %function +.type main, %function +.type __mlibc_entry, %function + +.cfi_startproc +_start: +.cfi_undefined eip + xor %ebp, %ebp + mov %esp, %ecx + push $main + push %ecx + call __mlibc_entry +.cfi_endproc + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/x86/crt-src/crti.S b/user/include/mlibc/sysdeps/linux/x86/crt-src/crti.S new file mode 100644 index 0000000..e232557 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + pushl %eax + +.section .fini +.global _fini +_fini: + pushl %eax + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/x86/crt-src/crtn.S b/user/include/mlibc/sysdeps/linux/x86/crt-src/crtn.S new file mode 100644 index 0000000..d890289 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + popl %eax + ret + +.section .fini + popl %eax + ret + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/x86/signals.S b/user/include/mlibc/sysdeps/linux/x86/signals.S new file mode 100644 index 0000000..8127ee4 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/signals.S @@ -0,0 +1,18 @@ +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: + popl %eax + mov $119, %eax + int $0x80 + ud2 + +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + mov $173, %eax + int $0x80 + ud2 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/x86/syscallnos.h b/user/include/mlibc/sysdeps/linux/x86/syscallnos.h new file mode 100644 index 0000000..e4376c4 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/syscallnos.h @@ -0,0 +1,449 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_lchown 16 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_setpgid 57 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl 110 +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86old 113 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_vm86 166 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread64 180 +#define __NR_pwrite64 181 +#define __NR_chown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 +#define __NR_vfork 190 +#define __NR_ugetrlimit 191 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_lchown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_chown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 +#define __NR_mincore 218 +#define __NR_madvise 219 +#define __NR_getdents64 220 +#define __NR_fcntl64 221 +#define __NR_gettid 224 +#define __NR_readahead 225 +#define __NR_setxattr 226 +#define __NR_lsetxattr 227 +#define __NR_fsetxattr 228 +#define __NR_getxattr 229 +#define __NR_lgetxattr 230 +#define __NR_fgetxattr 231 +#define __NR_listxattr 232 +#define __NR_llistxattr 233 +#define __NR_flistxattr 234 +#define __NR_removexattr 235 +#define __NR_lremovexattr 236 +#define __NR_fremovexattr 237 +#define __NR_tkill 238 +#define __NR_sendfile64 239 +#define __NR_futex 240 +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 +#define __NR_set_thread_area 243 +#define __NR_get_thread_area 244 +#define __NR_io_setup 245 +#define __NR_io_destroy 246 +#define __NR_io_getevents 247 +#define __NR_io_submit 248 +#define __NR_io_cancel 249 +#define __NR_fadvise64 250 +#define __NR_exit_group 252 +#define __NR_lookup_dcookie 253 +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 +#define __NR_remap_file_pages 257 +#define __NR_set_tid_address 258 +#define __NR_timer_create 259 +#define __NR_timer_settime 260 +#define __NR_timer_gettime 261 +#define __NR_timer_getoverrun 262 +#define __NR_timer_delete 263 +#define __NR_clock_settime 264 +#define __NR_clock_gettime 265 +#define __NR_clock_getres 266 +#define __NR_clock_nanosleep 267 +#define __NR_statfs64 268 +#define __NR_fstatfs64 269 +#define __NR_tgkill 270 +#define __NR_utimes 271 +#define __NR_fadvise64_64 272 +#define __NR_mbind 274 +#define __NR_get_mempolicy 275 +#define __NR_set_mempolicy 276 +#define __NR_mq_open 277 +#define __NR_mq_unlink 278 +#define __NR_mq_timedsend 279 +#define __NR_mq_timedreceive 280 +#define __NR_mq_notify 281 +#define __NR_mq_getsetattr 282 +#define __NR_kexec_load 283 +#define __NR_waitid 284 +#define __NR_add_key 286 +#define __NR_request_key 287 +#define __NR_keyctl 288 +#define __NR_ioprio_set 289 +#define __NR_ioprio_get 290 +#define __NR_inotify_init 291 +#define __NR_inotify_add_watch 292 +#define __NR_inotify_rm_watch 293 +#define __NR_migrate_pages 294 +#define __NR_openat 295 +#define __NR_mkdirat 296 +#define __NR_mknodat 297 +#define __NR_fchownat 298 +#define __NR_futimesat 299 +#define __NR_fstatat64 300 +#define __NR_unlinkat 301 +#define __NR_renameat 302 +#define __NR_linkat 303 +#define __NR_symlinkat 304 +#define __NR_readlinkat 305 +#define __NR_fchmodat 306 +#define __NR_faccessat 307 +#define __NR_pselect6 308 +#define __NR_ppoll 309 +#define __NR_unshare 310 +#define __NR_set_robust_list 311 +#define __NR_get_robust_list 312 +#define __NR_splice 313 +#define __NR_sync_file_range 314 +#define __NR_tee 315 +#define __NR_vmsplice 316 +#define __NR_move_pages 317 +#define __NR_getcpu 318 +#define __NR_epoll_pwait 319 +#define __NR_utimensat 320 +#define __NR_signalfd 321 +#define __NR_timerfd_create 322 +#define __NR_eventfd 323 +#define __NR_fallocate 324 +#define __NR_timerfd_settime 325 +#define __NR_timerfd_gettime 326 +#define __NR_signalfd4 327 +#define __NR_eventfd2 328 +#define __NR_epoll_create1 329 +#define __NR_dup3 330 +#define __NR_pipe2 331 +#define __NR_inotify_init1 332 +#define __NR_preadv 333 +#define __NR_pwritev 334 +#define __NR_rt_tgsigqueueinfo 335 +#define __NR_perf_event_open 336 +#define __NR_recvmmsg 337 +#define __NR_fanotify_init 338 +#define __NR_fanotify_mark 339 +#define __NR_prlimit64 340 +#define __NR_name_to_handle_at 341 +#define __NR_open_by_handle_at 342 +#define __NR_clock_adjtime 343 +#define __NR_syncfs 344 +#define __NR_sendmmsg 345 +#define __NR_setns 346 +#define __NR_process_vm_readv 347 +#define __NR_process_vm_writev 348 +#define __NR_kcmp 349 +#define __NR_finit_module 350 +#define __NR_sched_setattr 351 +#define __NR_sched_getattr 352 +#define __NR_renameat2 353 +#define __NR_seccomp 354 +#define __NR_getrandom 355 +#define __NR_memfd_create 356 +#define __NR_bpf 357 +#define __NR_execveat 358 +#define __NR_socket 359 +#define __NR_socketpair 360 +#define __NR_bind 361 +#define __NR_connect 362 +#define __NR_listen 363 +#define __NR_accept4 364 +#define __NR_getsockopt 365 +#define __NR_setsockopt 366 +#define __NR_getsockname 367 +#define __NR_getpeername 368 +#define __NR_sendto 369 +#define __NR_sendmsg 370 +#define __NR_recvfrom 371 +#define __NR_recvmsg 372 +#define __NR_shutdown 373 +#define __NR_userfaultfd 374 +#define __NR_membarrier 375 +#define __NR_mlock2 376 +#define __NR_copy_file_range 377 +#define __NR_preadv2 378 +#define __NR_pwritev2 379 +#define __NR_pkey_mprotect 380 +#define __NR_pkey_alloc 381 +#define __NR_pkey_free 382 +#define __NR_statx 383 +#define __NR_arch_prctl 384 +#define __NR_io_pgetevents 385 +#define __NR_rseq 386 +#define __NR_semget 393 +#define __NR_semctl 394 +#define __NR_shmget 395 +#define __NR_shmctl 396 +#define __NR_shmat 397 +#define __NR_shmdt 398 +#define __NR_msgget 399 +#define __NR_msgsnd 400 +#define __NR_msgrcv 401 +#define __NR_msgctl 402 +#define __NR_clock_gettime64 403 +#define __NR_clock_settime64 404 +#define __NR_clock_adjtime64 405 +#define __NR_clock_getres_time64 406 +#define __NR_clock_nanosleep_time64 407 +#define __NR_timer_gettime64 408 +#define __NR_timer_settime64 409 +#define __NR_timerfd_gettime64 410 +#define __NR_timerfd_settime64 411 +#define __NR_utimensat_time64 412 +#define __NR_pselect6_time64 413 +#define __NR_ppoll_time64 414 +#define __NR_io_pgetevents_time64 416 +#define __NR_recvmmsg_time64 417 +#define __NR_mq_timedsend_time64 418 +#define __NR_mq_timedreceive_time64 419 +#define __NR_semtimedop_time64 420 +#define __NR_rt_sigtimedwait_time64 421 +#define __NR_futex_time64 422 +#define __NR_sched_rr_get_interval_time64 423 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_memfd_secret 447 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_cachestat 451 +#define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 +#define __NR_statmount 457 +#define __NR_listmount 458 +#define __NR_lsm_get_self_attr 459 +#define __NR_lsm_set_self_attr 460 +#define __NR_lsm_list_modules 461 +#define __NR_mseal 462 +#define __NR_setxattrat 463 +#define __NR_getxattrat 464 +#define __NR_listxattrat 465 +#define __NR_removexattrat 466 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/user/include/mlibc/sysdeps/linux/x86/thread_entry.S b/user/include/mlibc/sysdeps/linux/x86/thread_entry.S new file mode 100644 index 0000000..031a6aa --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86/thread_entry.S @@ -0,0 +1,61 @@ +#define FLAGS 4 +#define STACK FLAGS+4 +#define PTID STACK+4 +#define CTID PTID+4 +#define TLS CTID+4 + +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +.cfi_startproc +__mlibc_spawn_thread: + push %ebx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ebx, 0 + push %esi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset esi, 0 + push %edi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset edi, 0 + + xor %eax, %eax + mov 12+FLAGS(%esp), %ebx + mov 12+STACK(%esp), %ecx + mov 12+PTID(%esp), %edx + /* On x86-32 tls and child_tid have to be reversed */ + mov 12+TLS(%esp), %esi + mov 12+CTID(%esp), %edi + mov $120, %al + + int $0x80 + + test %eax, %eax + jnz .parent_exit + + xor %ebp, %ebp + .cfi_undefined %eip + .cfi_undefined %ebp + + call 1f +1: + pop %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + + call __mlibc_enter_thread@plt + hlt + +.parent_exit: + pop %edi + .cfi_adjust_cfa_offset -4 + .cfi_restore edi + pop %esi + .cfi_adjust_cfa_offset -4 + .cfi_restore esi + pop %ebx + .cfi_adjust_cfa_offset -4 + .cfi_restore ebx + ret +.cfi_endproc + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/linux/x86_64/arch-syscall.cpp b/user/include/mlibc/sysdeps/linux/x86_64/arch-syscall.cpp new file mode 100644 index 0000000..d2ebbe7 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/arch-syscall.cpp @@ -0,0 +1,78 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +sc_word_t __do_syscall0(long sc) { + sc_word_t ret; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall1(long sc, + sc_word_t arg1) { + sc_word_t ret; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall2(long sc, + sc_word_t arg1, sc_word_t arg2) { + sc_word_t ret; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + sc_word_t ret; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + sc_word_t ret; + register sc_word_t arg4_reg asm("r10") = arg4; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), + "r"(arg4_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + sc_word_t ret; + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), + "r"(arg4_reg), "r"(arg5_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + sc_word_t ret; + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + register sc_word_t arg6_reg asm("r9") = arg6; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), + "r"(arg4_reg), "r"(arg5_reg), "r"(arg6_reg) + : "rcx", "r11", "memory"); + return ret; +} diff --git a/user/include/mlibc/sysdeps/linux/x86_64/assembly-asserts.cpp b/user/include/mlibc/sysdeps/linux/x86_64/assembly-asserts.cpp new file mode 100644 index 0000000..cb3a61d --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/assembly-asserts.cpp @@ -0,0 +1,23 @@ +#include +#include +#include "context-offsets.h" + +// offsets int ucontext_t as used in signals.S +static_assert(offsetof(ucontext_t, uc_mcontext) == UCONTEXT_GREGS_OFFSET); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R8]) == UCONTEXT_OFFSET_R8); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R9]) == UCONTEXT_OFFSET_R9); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R10]) == UCONTEXT_OFFSET_R10); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R11]) == UCONTEXT_OFFSET_R11); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R12]) == UCONTEXT_OFFSET_R12); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R13]) == UCONTEXT_OFFSET_R13); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R14]) == UCONTEXT_OFFSET_R14); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R15]) == UCONTEXT_OFFSET_R15); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RDI]) == UCONTEXT_OFFSET_RDI); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RSI]) == UCONTEXT_OFFSET_RSI); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RBP]) == UCONTEXT_OFFSET_RBP); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RBX]) == UCONTEXT_OFFSET_RBX); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RDX]) == UCONTEXT_OFFSET_RDX); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RAX]) == UCONTEXT_OFFSET_RAX); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RCX]) == UCONTEXT_OFFSET_RCX); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RSP]) == UCONTEXT_OFFSET_RSP); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RIP]) == UCONTEXT_OFFSET_RIP); diff --git a/user/include/mlibc/sysdeps/linux/x86_64/context-offsets.h b/user/include/mlibc/sysdeps/linux/x86_64/context-offsets.h new file mode 100644 index 0000000..30ca74a --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/context-offsets.h @@ -0,0 +1,21 @@ +#pragma once + +#define UCONTEXT_GREGS_OFFSET 40 + +#define UCONTEXT_OFFSET_R8 (UCONTEXT_GREGS_OFFSET + 0) +#define UCONTEXT_OFFSET_R9 (UCONTEXT_GREGS_OFFSET + 8) +#define UCONTEXT_OFFSET_R10 (UCONTEXT_GREGS_OFFSET + 16) +#define UCONTEXT_OFFSET_R11 (UCONTEXT_GREGS_OFFSET + 24) +#define UCONTEXT_OFFSET_R12 (UCONTEXT_GREGS_OFFSET + 32) +#define UCONTEXT_OFFSET_R13 (UCONTEXT_GREGS_OFFSET + 40) +#define UCONTEXT_OFFSET_R14 (UCONTEXT_GREGS_OFFSET + 48) +#define UCONTEXT_OFFSET_R15 (UCONTEXT_GREGS_OFFSET + 56) +#define UCONTEXT_OFFSET_RDI (UCONTEXT_GREGS_OFFSET + 64) +#define UCONTEXT_OFFSET_RSI (UCONTEXT_GREGS_OFFSET + 72) +#define UCONTEXT_OFFSET_RBP (UCONTEXT_GREGS_OFFSET + 80) +#define UCONTEXT_OFFSET_RBX (UCONTEXT_GREGS_OFFSET + 88) +#define UCONTEXT_OFFSET_RDX (UCONTEXT_GREGS_OFFSET + 96) +#define UCONTEXT_OFFSET_RAX (UCONTEXT_GREGS_OFFSET + 104) +#define UCONTEXT_OFFSET_RCX (UCONTEXT_GREGS_OFFSET + 112) +#define UCONTEXT_OFFSET_RSP (UCONTEXT_GREGS_OFFSET + 120) +#define UCONTEXT_OFFSET_RIP (UCONTEXT_GREGS_OFFSET + 128) diff --git a/user/include/mlibc/sysdeps/linux/x86_64/cp_syscall.S b/user/include/mlibc/sysdeps/linux/x86_64/cp_syscall.S new file mode 100644 index 0000000..5db1f1d --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/cp_syscall.S @@ -0,0 +1,29 @@ + +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + mov %rdi, %rax + mov %rsi, %rdi + mov %rdx, %rsi + mov %rcx, %rdx + mov %r8, %r10 + mov %r9, %r8 + mov 8(%rsp), %r9 + mov %fs:0x30, %r11 +__mlibc_syscall_begin: + /* tcbCancelEnableBit && tcbCancelTriggerBit */ + and $((1 << 0) | (1 << 2)), %r11 + cmp $((1 << 0) | (1 << 2)), %r11 + je cancel + syscall +__mlibc_syscall_end: + ret + +cancel: + call __mlibc_do_cancel + hlt +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/x86_64/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/linux/x86_64/crt-src/Scrt1.S new file mode 100644 index 0000000..d0e8213 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/crt-src/Scrt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + lea main(%rip), %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crt1.S b/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crt1.S new file mode 100644 index 0000000..9b77ee7 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + mov $main, %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crti.S b/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crti.S new file mode 100644 index 0000000..911b078 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crtn.S b/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..0187e50 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/linux/x86_64/signals.S b/user/include/mlibc/sysdeps/linux/x86_64/signals.S new file mode 100644 index 0000000..7d38af0 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/signals.S @@ -0,0 +1,36 @@ +#include "mlibc-asm/dwarf-helpers.h" +#include "mlibc-asm/helpers.h" +#include "context-offsets.h" +#include "syscallnos.h" + +.section .text +.cfi_startproc +.cfi_signal_frame + cfi_set_cfa_to_ptr_with_offset DWARF_REG_RSP, UCONTEXT_OFFSET_RSP + cfi_set_prev_reg_value DWARF_REG_R8, DWARF_REG_RSP, UCONTEXT_OFFSET_R8 + cfi_set_prev_reg_value DWARF_REG_R9, DWARF_REG_RSP, UCONTEXT_OFFSET_R9 + cfi_set_prev_reg_value DWARF_REG_R10, DWARF_REG_RSP, UCONTEXT_OFFSET_R10 + cfi_set_prev_reg_value DWARF_REG_R11, DWARF_REG_RSP, UCONTEXT_OFFSET_R11 + cfi_set_prev_reg_value DWARF_REG_R12, DWARF_REG_RSP, UCONTEXT_OFFSET_R12 + cfi_set_prev_reg_value DWARF_REG_R13, DWARF_REG_RSP, UCONTEXT_OFFSET_R13 + cfi_set_prev_reg_value DWARF_REG_R14, DWARF_REG_RSP, UCONTEXT_OFFSET_R14 + cfi_set_prev_reg_value DWARF_REG_R15, DWARF_REG_RSP, UCONTEXT_OFFSET_R15 + cfi_set_prev_reg_value DWARF_REG_RDI, DWARF_REG_RSP, UCONTEXT_OFFSET_RDI + cfi_set_prev_reg_value DWARF_REG_RSI, DWARF_REG_RSP, UCONTEXT_OFFSET_RSI + cfi_set_prev_reg_value DWARF_REG_RBP, DWARF_REG_RSP, UCONTEXT_OFFSET_RBP + cfi_set_prev_reg_value DWARF_REG_RBX, DWARF_REG_RSP, UCONTEXT_OFFSET_RBX + cfi_set_prev_reg_value DWARF_REG_RDX, DWARF_REG_RSP, UCONTEXT_OFFSET_RDX + cfi_set_prev_reg_value DWARF_REG_RAX, DWARF_REG_RSP, UCONTEXT_OFFSET_RAX + cfi_set_prev_reg_value DWARF_REG_RCX, DWARF_REG_RSP, UCONTEXT_OFFSET_RCX + cfi_set_prev_reg_value DWARF_REG_RETURN_ADDRESS, DWARF_REG_RSP, UCONTEXT_OFFSET_RIP + nop + +PROC_START_NOCFI(__mlibc_signal_restore) +PROC_ALIAS(__mlibc_signal_restore, __mlibc_signal_restore_rt) + mov $__NR_rt_sigreturn, %rax + syscall + ud2 +PROC_END(__mlibc_signal_restore) + +GNU_STACK_NOTE() + diff --git a/user/include/mlibc/sysdeps/linux/x86_64/syscallnos.h b/user/include/mlibc/sysdeps/linux/x86_64/syscallnos.h new file mode 100644 index 0000000..641aa67 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/syscallnos.h @@ -0,0 +1,379 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_read 0 +#define __NR_write 1 +#define __NR_open 2 +#define __NR_close 3 +#define __NR_stat 4 +#define __NR_fstat 5 +#define __NR_lstat 6 +#define __NR_poll 7 +#define __NR_lseek 8 +#define __NR_mmap 9 +#define __NR_mprotect 10 +#define __NR_munmap 11 +#define __NR_brk 12 +#define __NR_rt_sigaction 13 +#define __NR_rt_sigprocmask 14 +#define __NR_rt_sigreturn 15 +#define __NR_ioctl 16 +#define __NR_pread64 17 +#define __NR_pwrite64 18 +#define __NR_readv 19 +#define __NR_writev 20 +#define __NR_access 21 +#define __NR_pipe 22 +#define __NR_select 23 +#define __NR_sched_yield 24 +#define __NR_mremap 25 +#define __NR_msync 26 +#define __NR_mincore 27 +#define __NR_madvise 28 +#define __NR_shmget 29 +#define __NR_shmat 30 +#define __NR_shmctl 31 +#define __NR_dup 32 +#define __NR_dup2 33 +#define __NR_pause 34 +#define __NR_nanosleep 35 +#define __NR_getitimer 36 +#define __NR_alarm 37 +#define __NR_setitimer 38 +#define __NR_getpid 39 +#define __NR_sendfile 40 +#define __NR_socket 41 +#define __NR_connect 42 +#define __NR_accept 43 +#define __NR_sendto 44 +#define __NR_recvfrom 45 +#define __NR_sendmsg 46 +#define __NR_recvmsg 47 +#define __NR_shutdown 48 +#define __NR_bind 49 +#define __NR_listen 50 +#define __NR_getsockname 51 +#define __NR_getpeername 52 +#define __NR_socketpair 53 +#define __NR_setsockopt 54 +#define __NR_getsockopt 55 +#define __NR_clone 56 +#define __NR_fork 57 +#define __NR_vfork 58 +#define __NR_execve 59 +#define __NR_exit 60 +#define __NR_wait4 61 +#define __NR_kill 62 +#define __NR_uname 63 +#define __NR_semget 64 +#define __NR_semop 65 +#define __NR_semctl 66 +#define __NR_shmdt 67 +#define __NR_msgget 68 +#define __NR_msgsnd 69 +#define __NR_msgrcv 70 +#define __NR_msgctl 71 +#define __NR_fcntl 72 +#define __NR_flock 73 +#define __NR_fsync 74 +#define __NR_fdatasync 75 +#define __NR_truncate 76 +#define __NR_ftruncate 77 +#define __NR_getdents 78 +#define __NR_getcwd 79 +#define __NR_chdir 80 +#define __NR_fchdir 81 +#define __NR_rename 82 +#define __NR_mkdir 83 +#define __NR_rmdir 84 +#define __NR_creat 85 +#define __NR_link 86 +#define __NR_unlink 87 +#define __NR_symlink 88 +#define __NR_readlink 89 +#define __NR_chmod 90 +#define __NR_fchmod 91 +#define __NR_chown 92 +#define __NR_fchown 93 +#define __NR_lchown 94 +#define __NR_umask 95 +#define __NR_gettimeofday 96 +#define __NR_getrlimit 97 +#define __NR_getrusage 98 +#define __NR_sysinfo 99 +#define __NR_times 100 +#define __NR_ptrace 101 +#define __NR_getuid 102 +#define __NR_syslog 103 +#define __NR_getgid 104 +#define __NR_setuid 105 +#define __NR_setgid 106 +#define __NR_geteuid 107 +#define __NR_getegid 108 +#define __NR_setpgid 109 +#define __NR_getppid 110 +#define __NR_getpgrp 111 +#define __NR_setsid 112 +#define __NR_setreuid 113 +#define __NR_setregid 114 +#define __NR_getgroups 115 +#define __NR_setgroups 116 +#define __NR_setresuid 117 +#define __NR_getresuid 118 +#define __NR_setresgid 119 +#define __NR_getresgid 120 +#define __NR_getpgid 121 +#define __NR_setfsuid 122 +#define __NR_setfsgid 123 +#define __NR_getsid 124 +#define __NR_capget 125 +#define __NR_capset 126 +#define __NR_rt_sigpending 127 +#define __NR_rt_sigtimedwait 128 +#define __NR_rt_sigqueueinfo 129 +#define __NR_rt_sigsuspend 130 +#define __NR_sigaltstack 131 +#define __NR_utime 132 +#define __NR_mknod 133 +#define __NR_uselib 134 +#define __NR_personality 135 +#define __NR_ustat 136 +#define __NR_statfs 137 +#define __NR_fstatfs 138 +#define __NR_sysfs 139 +#define __NR_getpriority 140 +#define __NR_setpriority 141 +#define __NR_sched_setparam 142 +#define __NR_sched_getparam 143 +#define __NR_sched_setscheduler 144 +#define __NR_sched_getscheduler 145 +#define __NR_sched_get_priority_max 146 +#define __NR_sched_get_priority_min 147 +#define __NR_sched_rr_get_interval 148 +#define __NR_mlock 149 +#define __NR_munlock 150 +#define __NR_mlockall 151 +#define __NR_munlockall 152 +#define __NR_vhangup 153 +#define __NR_modify_ldt 154 +#define __NR_pivot_root 155 +#define __NR__sysctl 156 +#define __NR_prctl 157 +#define __NR_arch_prctl 158 +#define __NR_adjtimex 159 +#define __NR_setrlimit 160 +#define __NR_chroot 161 +#define __NR_sync 162 +#define __NR_acct 163 +#define __NR_settimeofday 164 +#define __NR_mount 165 +#define __NR_umount2 166 +#define __NR_swapon 167 +#define __NR_swapoff 168 +#define __NR_reboot 169 +#define __NR_sethostname 170 +#define __NR_setdomainname 171 +#define __NR_iopl 172 +#define __NR_ioperm 173 +#define __NR_create_module 174 +#define __NR_init_module 175 +#define __NR_delete_module 176 +#define __NR_get_kernel_syms 177 +#define __NR_query_module 178 +#define __NR_quotactl 179 +#define __NR_nfsservctl 180 +#define __NR_getpmsg 181 +#define __NR_gettid 186 +#define __NR_readahead 187 +#define __NR_setxattr 188 +#define __NR_lsetxattr 189 +#define __NR_fsetxattr 190 +#define __NR_getxattr 191 +#define __NR_lgetxattr 192 +#define __NR_fgetxattr 193 +#define __NR_listxattr 194 +#define __NR_llistxattr 195 +#define __NR_flistxattr 196 +#define __NR_removexattr 197 +#define __NR_lremovexattr 198 +#define __NR_fremovexattr 199 +#define __NR_tkill 200 +#define __NR_time 201 +#define __NR_futex 202 +#define __NR_sched_setaffinity 203 +#define __NR_sched_getaffinity 204 +#define __NR_set_thread_area 205 +#define __NR_io_setup 206 +#define __NR_io_destroy 207 +#define __NR_io_getevents 208 +#define __NR_io_submit 209 +#define __NR_io_cancel 210 +#define __NR_get_thread_area 211 +#define __NR_lookup_dcookie 212 +#define __NR_epoll_create 213 +#define __NR_epoll_ctl_old 214 +#define __NR_epoll_wait_old 215 +#define __NR_remap_file_pages 216 +#define __NR_getdents64 217 +#define __NR_set_tid_address 218 +#define __NR_restart_syscall 219 +#define __NR_semtimedop 220 +#define __NR_fadvise64 221 +#define __NR_timer_create 222 +#define __NR_timer_settime 223 +#define __NR_timer_gettime 224 +#define __NR_timer_getoverrun 225 +#define __NR_timer_delete 226 +#define __NR_clock_settime 227 +#define __NR_clock_gettime 228 +#define __NR_clock_getres 229 +#define __NR_clock_nanosleep 230 +#define __NR_exit_group 231 +#define __NR_epoll_wait 232 +#define __NR_epoll_ctl 233 +#define __NR_tgkill 234 +#define __NR_utimes 235 +#define __NR_mbind 237 +#define __NR_set_mempolicy 238 +#define __NR_get_mempolicy 239 +#define __NR_mq_open 240 +#define __NR_mq_unlink 241 +#define __NR_mq_timedsend 242 +#define __NR_mq_timedreceive 243 +#define __NR_mq_notify 244 +#define __NR_mq_getsetattr 245 +#define __NR_kexec_load 246 +#define __NR_waitid 247 +#define __NR_add_key 248 +#define __NR_request_key 249 +#define __NR_keyctl 250 +#define __NR_ioprio_set 251 +#define __NR_ioprio_get 252 +#define __NR_inotify_init 253 +#define __NR_inotify_add_watch 254 +#define __NR_inotify_rm_watch 255 +#define __NR_migrate_pages 256 +#define __NR_openat 257 +#define __NR_mkdirat 258 +#define __NR_mknodat 259 +#define __NR_fchownat 260 +#define __NR_futimesat 261 +#define __NR_newfstatat 262 +#define __NR_unlinkat 263 +#define __NR_renameat 264 +#define __NR_linkat 265 +#define __NR_symlinkat 266 +#define __NR_readlinkat 267 +#define __NR_fchmodat 268 +#define __NR_faccessat 269 +#define __NR_pselect6 270 +#define __NR_ppoll 271 +#define __NR_unshare 272 +#define __NR_set_robust_list 273 +#define __NR_get_robust_list 274 +#define __NR_splice 275 +#define __NR_tee 276 +#define __NR_sync_file_range 277 +#define __NR_vmsplice 278 +#define __NR_move_pages 279 +#define __NR_utimensat 280 +#define __NR_epoll_pwait 281 +#define __NR_signalfd 282 +#define __NR_timerfd_create 283 +#define __NR_eventfd 284 +#define __NR_fallocate 285 +#define __NR_timerfd_settime 286 +#define __NR_timerfd_gettime 287 +#define __NR_accept4 288 +#define __NR_signalfd4 289 +#define __NR_eventfd2 290 +#define __NR_epoll_create1 291 +#define __NR_dup3 292 +#define __NR_pipe2 293 +#define __NR_inotify_init1 294 +#define __NR_preadv 295 +#define __NR_pwritev 296 +#define __NR_rt_tgsigqueueinfo 297 +#define __NR_perf_event_open 298 +#define __NR_recvmmsg 299 +#define __NR_fanotify_init 300 +#define __NR_fanotify_mark 301 +#define __NR_prlimit64 302 +#define __NR_name_to_handle_at 303 +#define __NR_open_by_handle_at 304 +#define __NR_clock_adjtime 305 +#define __NR_syncfs 306 +#define __NR_sendmmsg 307 +#define __NR_setns 308 +#define __NR_getcpu 309 +#define __NR_process_vm_readv 310 +#define __NR_process_vm_writev 311 +#define __NR_kcmp 312 +#define __NR_finit_module 313 +#define __NR_sched_setattr 314 +#define __NR_sched_getattr 315 +#define __NR_renameat2 316 +#define __NR_seccomp 317 +#define __NR_getrandom 318 +#define __NR_memfd_create 319 +#define __NR_kexec_file_load 320 +#define __NR_bpf 321 +#define __NR_execveat 322 +#define __NR_userfaultfd 323 +#define __NR_membarrier 324 +#define __NR_mlock2 325 +#define __NR_copy_file_range 326 +#define __NR_preadv2 327 +#define __NR_pwritev2 328 +#define __NR_pkey_mprotect 329 +#define __NR_pkey_alloc 330 +#define __NR_pkey_free 331 +#define __NR_statx 332 +#define __NR_io_pgetevents 333 +#define __NR_rseq 334 +#define __NR_uretprobe 335 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_memfd_secret 447 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_cachestat 451 +#define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 +#define __NR_statmount 457 +#define __NR_listmount 458 +#define __NR_lsm_get_self_attr 459 +#define __NR_lsm_set_self_attr 460 +#define __NR_lsm_list_modules 461 +#define __NR_mseal 462 +#define __NR_setxattrat 463 +#define __NR_getxattrat 464 +#define __NR_listxattrat 465 +#define __NR_removexattrat 466 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/user/include/mlibc/sysdeps/linux/x86_64/thread_entry.S b/user/include/mlibc/sysdeps/linux/x86_64/thread_entry.S new file mode 100644 index 0000000..d990972 --- /dev/null +++ b/user/include/mlibc/sysdeps/linux/x86_64/thread_entry.S @@ -0,0 +1,26 @@ +#include "mlibc-asm/helpers.h" +#include "syscallnos.h" + +.section .text + +PROC_START(__mlibc_spawn_thread) + xor %eax, %eax + /* The rest of the args are already in the right registers, + * only need to fixup rcx to r10 + */ + mov %rcx, %r10 + mov $__NR_clone, %rax + syscall + test %eax, %eax + jnz 1f + xor %ebp, %ebp + pop %rdi + pop %rsi + call __mlibc_enter_thread + hlt +1: + ret +PROC_END(__mlibc_spawn_thread) + +GNU_STACK_NOTE() + diff --git a/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/Scrt1.S new file mode 100644 index 0000000..3e56608 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/Scrt1.S @@ -0,0 +1,10 @@ +.section .text +.global _start +_start: + mov x0, sp + adr x1, main + + bl __mlibc_entry + brk #0 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crt0.S b/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crt0.S new file mode 100644 index 0000000..5e59593 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crt0.S @@ -0,0 +1,11 @@ + +.section .text +.global _start +_start: + mov x0, sp + adrp x1, main + add x1, x1, :lo12:main + bl __mlibc_entry + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crti.S b/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crti.S new file mode 100644 index 0000000..4307dfb --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crti.S @@ -0,0 +1,15 @@ + .ident "aarch64-managarm-mlibc crti" + + .section .init + .global _init +_init: + stp x29, x30, [sp, -16]! + mov x29, sp + + .section .fini + .global _fini +_fini: + stp x29, x30, [sp, -16]! + mov x29, sp + + .section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crtn.S b/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crtn.S new file mode 100644 index 0000000..005d870 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/aarch64/crt-src/crtn.S @@ -0,0 +1,11 @@ + .ident "aarch64-managarm-mlibc crtn" + + .section .init + ldp x29, x30, [sp], #16 + ret + + .section .fini + ldp x29, x30, [sp], #16 + ret + + .section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/aarch64/signals.S b/user/include/mlibc/sysdeps/managarm/aarch64/signals.S new file mode 100644 index 0000000..044767d --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/aarch64/signals.S @@ -0,0 +1,10 @@ + +.section .text +.global __mlibc_signal_restore +__mlibc_signal_restore: + ldr x0, =0x80000006 + svc 0 + brk #1 + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/managarm/aarch64/thread.cpp b/user/include/mlibc/sysdeps/managarm/aarch64/thread.cpp new file mode 100644 index 0000000..129267d --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/aarch64/thread.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while (!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if (mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack( + void **stack, + void *entry, + void *user_arg, + void *tcb, + size_t *stack_size, + size_t *guard_size, + void **stack_base +) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = + mmap(nullptr, *stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } + + uintptr_t *sp = + reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/aarch64/thread_entry.S b/user/include/mlibc/sysdeps/managarm/aarch64/thread_entry.S new file mode 100644 index 0000000..4cfcb4c --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/aarch64/thread_entry.S @@ -0,0 +1,11 @@ + +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + ldp x0, x1, [sp] + ldr x2, [sp, #16] + add sp, sp, #24 + bl __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/managarm/generic/drm.cpp b/user/include/mlibc/sysdeps/managarm/generic/drm.cpp new file mode 100644 index 0000000..b770f67 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/drm.cpp @@ -0,0 +1,1309 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace mlibc { + +int ioctl_drm(int fd, unsigned long request, void *arg, int *result, HelHandle handle) { + managarm::fs::IoctlRequest ioctl_req(getSysdepsAllocator()); + + switch (request) { + case DRM_IOCTL_VERSION: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->version_major = resp.drm_version_major(); + param->version_minor = resp.drm_version_minor(); + param->version_patchlevel = resp.drm_version_patchlevel(); + + if (param->name) + memcpy( + param->name, + resp.drm_driver_name().data(), + frg::min(param->name_len, resp.drm_driver_name().size()) + ); + if (param->date) + memcpy( + param->date, + resp.drm_driver_date().data(), + frg::min(param->date_len, resp.drm_driver_date().size()) + ); + if (param->desc) + memcpy( + param->desc, + resp.drm_driver_desc().data(), + frg::min(param->desc_len, resp.drm_driver_desc().size()) + ); + + param->name_len = resp.drm_driver_name().size(); + param->date_len = resp.drm_driver_date().size(); + param->desc_len = resp.drm_driver_desc().size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_GET_CAP: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_capability(param->capability); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->value = resp.drm_value(); + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_SET_CLIENT_CAP: { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_SET_CLIENT_CAP(" << param->capability + << ") ignores its value\e[39m" << frg::endlog; + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_capability(param->capability); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->value = resp.drm_value(); + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_GET_MAGIC: { + auto param = reinterpret_cast(arg); + mlibc::infoLogger( + ) << "\e[31mmlibc: DRM_IOCTL_GET_MAGIC is not implemented correctly\e[39m" + << frg::endlog; + param->magic = 1; + *result = 0; + return 0; + } + case DRM_IOCTL_AUTH_MAGIC: { + mlibc::infoLogger( + ) << "\e[31mmlibc: DRM_IOCTL_AUTH_MAGIC is not implemented correctly\e[39m" + << frg::endlog; + *result = 0; + return 0; + } + case DRM_IOCTL_SET_MASTER: { + mlibc::infoLogger( + ) << "\e[31mmlibc: DRM_IOCTL_SET_MASTER is not implemented correctly\e[39m" + << frg::endlog; + *result = 0; + return 0; + } + case DRM_IOCTL_DROP_MASTER: { + mlibc::infoLogger( + ) << "\e[31mmlibc: DRM_IOCTL_DROP_MASTER is not implemented correctly\e[39m" + << frg::endlog; + *result = 0; + return 0; + } + case DRM_IOCTL_MODE_GETRESOURCES: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + if (recv_resp.error() == kHelErrDismissed) { + return EINVAL; + } + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + for (size_t i = 0; i < resp.drm_fb_ids_size(); i++) { + if (i >= param->count_fbs) + break; + auto dest = reinterpret_cast(param->fb_id_ptr); + dest[i] = resp.drm_fb_ids(i); + } + param->count_fbs = resp.drm_fb_ids_size(); + + for (size_t i = 0; i < resp.drm_crtc_ids_size(); i++) { + if (i >= param->count_crtcs) + break; + auto dest = reinterpret_cast(param->crtc_id_ptr); + dest[i] = resp.drm_crtc_ids(i); + } + param->count_crtcs = resp.drm_crtc_ids_size(); + + for (size_t i = 0; i < resp.drm_connector_ids_size(); i++) { + if (i >= param->count_connectors) + break; + auto dest = reinterpret_cast(param->connector_id_ptr); + dest[i] = resp.drm_connector_ids(i); + } + param->count_connectors = resp.drm_connector_ids_size(); + + for (size_t i = 0; i < resp.drm_encoder_ids_size(); i++) { + if (i >= param->count_encoders) + continue; + auto dest = reinterpret_cast(param->encoder_id_ptr); + dest[i] = resp.drm_encoder_ids(i); + } + param->count_encoders = resp.drm_encoder_ids_size(); + + param->min_width = resp.drm_min_width(); + param->max_width = resp.drm_max_width(); + param->min_height = resp.drm_min_height(); + param->max_height = resp.drm_max_height(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETCONNECTOR: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_connector_id(param->connector_id); + req.set_drm_max_modes(param->count_modes); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_list] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer( + reinterpret_cast(param->modes_ptr), + param->count_modes * sizeof(drm_mode_modeinfo) + ) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + if (recv_resp.error() == kHelErrDismissed) + return EINVAL; + + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_list.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + for (size_t i = 0; i < resp.drm_encoders_size(); i++) { + if (i >= param->count_encoders) + continue; + auto dest = reinterpret_cast(param->encoders_ptr); + dest[i] = resp.drm_encoders(i); + } + + param->encoder_id = resp.drm_encoder_id(); + param->connector_type = resp.drm_connector_type(); + param->connector_type_id = resp.drm_connector_type_id(); + param->connection = resp.drm_connection(); + param->mm_width = resp.drm_mm_width(); + param->mm_height = resp.drm_mm_height(); + param->subpixel = resp.drm_subpixel(); + param->pad = 0; + param->count_encoders = resp.drm_encoders_size(); + param->count_modes = resp.drm_num_modes(); + + if (param->props_ptr) { + auto id_ptr = reinterpret_cast(param->props_ptr); + auto val_ptr = reinterpret_cast(param->prop_values_ptr); + + for (size_t i = 0; + i < frg::min( + static_cast(param->count_props), resp.drm_obj_property_ids_size() + ); + i++) { + id_ptr[i] = resp.drm_obj_property_ids(i); + val_ptr[i] = resp.drm_obj_property_values(i); + } + } + + param->count_props = resp.drm_obj_property_ids_size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETPROPERTY: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_property_id(param->prop_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::fs::Errors::SUCCESS) { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_MODE_GETPROPERTY(" << param->prop_id + << ") error " << (int)resp.error() << "\e[39m" << frg::endlog; + *result = 0; + return EINVAL; + } + + memcpy(param->name, resp.drm_property_name().data(), resp.drm_property_name().size()); + param->count_values = resp.drm_property_vals_size(); + param->flags = resp.drm_property_flags(); + + for (size_t i = 0; + i < param->count_values && i < resp.drm_property_vals_size() && param->values_ptr; + i++) { + auto dest = reinterpret_cast(param->values_ptr); + dest[i] = resp.drm_property_vals(i); + } + + __ensure(resp.drm_enum_name_size() == resp.drm_enum_value_size()); + + for (size_t i = 0; i < param->count_enum_blobs && i < resp.drm_enum_name_size() + && i < resp.drm_enum_value_size(); + i++) { + auto dest = reinterpret_cast(param->enum_blob_ptr); + dest[i].value = resp.drm_enum_value(i); + strncpy(dest[i].name, resp.drm_enum_name(i).data(), DRM_PROP_NAME_LEN); + } + + param->count_enum_blobs = resp.drm_enum_name_size(); + + *result = 0; + return 0; + } + case DRM_IOCTL_MODE_SETPROPERTY: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_property_id(param->prop_id); + req.set_drm_property_value(param->value); + req.set_drm_obj_id(param->connector_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::fs::Errors::SUCCESS) { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_MODE_SETPROPERTY(" << param->prop_id + << ") error " << (int)resp.error() << "\e[39m" << frg::endlog; + *result = 0; + return EINVAL; + } + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETPROPBLOB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_blob_id(param->blob_id); + req.set_drm_blob_size(param->length); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + auto conversation = offer.descriptor(); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + uint8_t *dest = reinterpret_cast(param->data); + auto [recv_data] = exchangeMsgsSync( + conversation.getHandle(), + helix_ng::recvBuffer(dest, std::min(param->length, resp.drm_property_blob_size())) + ); + HEL_CHECK(recv_data.error()); + + if (resp.error() != managarm::fs::Errors::SUCCESS) { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_MODE_GETPROPBLOB(" << param->blob_id + << ") error " << (int)resp.error() << "\e[39m" << frg::endlog; + *result = 0; + return EINVAL; + } + + param->length = resp.drm_property_blob_size(); + + *result = 0; + return 0; + } + case DRM_IOCTL_MODE_GETPLANE: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_plane_id(param->plane_id); + req.set_drm_format_types(param->count_format_types); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + auto conversation = offer.descriptor(); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + param->crtc_id = resp.drm_crtc_id(); + param->fb_id = resp.drm_fb_id(); + param->possible_crtcs = resp.drm_possible_crtcs(); + param->gamma_size = resp.drm_gamma_size(); + + auto dest = reinterpret_cast(param->format_type_ptr); + auto [recv_formats] = exchangeMsgsSync( + conversation.getHandle(), + helix_ng::recvBuffer( + dest, + std::min(resp.drm_format_types(), param->count_format_types) * sizeof(uint32_t) + ) + ); + HEL_CHECK(recv_formats.error()); + + param->count_format_types = resp.drm_format_types(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETPLANERESOURCES: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + // FIXME: send this via a helix_ng buffer + for (size_t i = 0; i < resp.drm_plane_res_size(); i++) { + if (i >= param->count_planes) { + continue; + } + auto dest = reinterpret_cast(param->plane_id_ptr); + dest[i] = resp.drm_plane_res(i); + } + + param->count_planes = resp.drm_plane_res_size(); + + *result = resp.result(); + + return 0; + } + case DRM_IOCTL_MODE_GETENCODER: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_encoder_id(param->encoder_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + param->encoder_type = resp.drm_encoder_type(); + param->crtc_id = resp.drm_crtc_id(); + param->possible_crtcs = resp.drm_possible_crtcs(); + param->possible_clones = resp.drm_possible_clones(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_CREATE_DUMB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_bpp(param->bpp); + req.set_drm_flags(param->flags); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->handle = resp.drm_handle(); + param->pitch = resp.drm_pitch(); + param->size = resp.drm_size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_ADDFB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_pitch(param->pitch); + req.set_drm_bpp(param->bpp); + req.set_drm_depth(param->depth); + req.set_drm_handle(param->handle); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->fb_id = resp.drm_fb_id(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETFB2: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(DRM_IOCTL_MODE_GETFB2); + req.set_drm_fb_id(param->fb_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + memset(param->handles, 0, sizeof(param->handles)); + memset(param->pitches, 0, sizeof(param->pitches)); + memset(param->offsets, 0, sizeof(param->offsets)); + + param->width = resp.drm_width(); + param->height = resp.drm_height(); + param->pixel_format = resp.pixel_format(); + param->modifier[0] = resp.modifier(); + memcpy( + param->handles, + resp.drm_handles().data(), + sizeof(uint32_t) * resp.drm_handles_size() + ); + memcpy( + param->pitches, + resp.drm_pitches().data(), + sizeof(uint32_t) * resp.drm_pitches_size() + ); + memcpy( + param->offsets, + resp.drm_offsets().data(), + sizeof(uint32_t) * resp.drm_offsets_size() + ); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_ADDFB2: { + auto param = reinterpret_cast(arg); + + __ensure(!param->flags || param->flags == DRM_MODE_FB_MODIFIERS); + __ensure(!param->offsets[0]); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(DRM_IOCTL_MODE_ADDFB2); + + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_pitch(param->pitches[0]); + req.set_drm_fourcc(param->pixel_format); + req.set_drm_handle(param->handles[0]); + if (param->flags & DRM_MODE_FB_MODIFIERS) + req.set_drm_modifier(param->modifier[0]); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->fb_id = resp.drm_fb_id(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_RMFB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_fb_id(*param); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_MAP_DUMB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_handle(param->handle); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->offset = resp.drm_offset(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETCRTC: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_crtc_id(param->crtc_id); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_data] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(¶m->mode, sizeof(drm_mode_modeinfo)) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + param->fb_id = resp.drm_fb_id(); + param->x = resp.drm_x(); + param->y = resp.drm_y(); + param->gamma_size = resp.drm_gamma_size(); + param->mode_valid = resp.drm_mode_valid(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_SETCRTC: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + for (size_t i = 0; i < param->count_connectors; i++) { + auto dest = reinterpret_cast(param->set_connectors_ptr); + req.add_drm_connector_ids(dest[i]); + } + req.set_drm_x(param->x); + req.set_drm_y(param->y); + req.set_drm_crtc_id(param->crtc_id); + req.set_drm_fb_id(param->fb_id); + req.set_drm_mode_valid(param->mode_valid); + + auto [offer, send_ioctl_req, send_req, send_mode, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(¶m->mode, sizeof(drm_mode_modeinfo)), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_mode.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_OBJ_GETPROPERTIES: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_count_props(param->count_props); + req.set_drm_obj_id(param->obj_id); + req.set_drm_obj_type(param->obj_type); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + auto props = reinterpret_cast(param->props_ptr); + auto prop_vals = reinterpret_cast(param->prop_values_ptr); + + for (size_t i = 0; i < resp.drm_obj_property_ids_size(); i++) { + if (i >= param->count_props) { + break; + } + props[i] = resp.drm_obj_property_ids(i); + prop_vals[i] = resp.drm_obj_property_values(i); + } + + param->count_props = resp.drm_obj_property_ids_size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_PAGE_FLIP: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + __ensure(!(param->flags & ~DRM_MODE_PAGE_FLIP_EVENT)); + req.set_drm_crtc_id(param->crtc_id); + req.set_drm_fb_id(param->fb_id); + req.set_drm_cookie(param->user_data); + req.set_drm_flags(param->flags); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_DIRTYFB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_fb_id(param->fb_id); + req.set_drm_flags(param->flags); + req.set_drm_color(param->color); + for (size_t i = 0; i < param->num_clips; i++) { + auto dest = reinterpret_cast(param->clips_ptr); + managarm::fs::Rect clip(getSysdepsAllocator()); + clip.set_x1(dest->x1); + clip.set_y1(dest->y1); + clip.set_x2(dest->x2); + clip.set_y2(dest->y2); + req.add_drm_clips(std::move(clip)); + } + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_MODE_CURSOR: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_flags(param->flags); + req.set_drm_crtc_id(param->crtc_id); + + if (param->flags == DRM_MODE_CURSOR_MOVE) { + req.set_drm_x(param->x); + req.set_drm_y(param->y); + } else if (param->flags == DRM_MODE_CURSOR_BO) { + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_handle(param->handle); + } else { + mlibc::infoLogger() + << "\e[35mmlibc: invalid flags in DRM_IOCTL_MODE_CURSOR\e[39m" << frg::endlog; + return EINVAL; + } + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::fs::Errors::NO_BACKING_DEVICE) { + return ENXIO; + } else if (resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else { + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_MODE_CURSOR2: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_flags(param->flags); + req.set_drm_crtc_id(param->crtc_id); + req.set_drm_x(param->x); + req.set_drm_y(param->y); + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_handle(param->handle); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::fs::Errors::NO_BACKING_DEVICE) { + return ENXIO; + } else if (resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else { + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_MODE_DESTROY_DUMB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_handle(param->handle); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_CREATEPROPBLOB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_blob_size(param->length); + + auto [offer, send_ioctl_req, send_req, blob_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(reinterpret_cast(param->data), param->length), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(blob_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->blob_id = resp.drm_blob_id(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_DESTROYPROPBLOB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_blob_id(param->blob_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_ATOMIC: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_flags(param->flags); + req.set_drm_cookie(param->user_data); + + size_t prop_count = 0; + auto objs_ptr = reinterpret_cast(param->objs_ptr); + auto count_props_ptr = reinterpret_cast(param->count_props_ptr); + auto props_ptr = reinterpret_cast(param->props_ptr); + auto prop_values_ptr = reinterpret_cast(param->prop_values_ptr); + + for (size_t i = 0; i < param->count_objs; i++) { + /* list of modeobjs and their property count */ + req.add_drm_obj_ids(objs_ptr[i]); + req.add_drm_prop_counts(count_props_ptr[i]); + prop_count += count_props_ptr[i]; + } + + for (size_t i = 0; i < prop_count; i++) { + /* array of property IDs */ + req.add_drm_props(props_ptr[i]); + /* array of property values */ + req.add_drm_prop_values(prop_values_ptr[i]); + } + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_LIST_LESSEES: { + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_MODE_LIST_LESSEES" + " is not implemented correctly\e[39m" + << frg::endlog; + return EINVAL; + } + case DRM_IOCTL_MODE_SETGAMMA: { + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_MODE_SETGAMMA" + " is not implemented correctly\e[39m" + << frg::endlog; + return 0; + } + case DRM_IOCTL_MODE_CREATE_LEASE: { + auto param = reinterpret_cast(arg); + + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_MODE_CREATE_LEASE" + " is a noop\e[39m" + << frg::endlog; + param->lessee_id = 1; + param->fd = fd; + *result = 0; + return 0; + } + case DRM_IOCTL_GEM_CLOSE: { + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_GEM_CLOSE" + " is a noop\e[39m" + << frg::endlog; + *result = 0; + return 0; + } + case DRM_IOCTL_WAIT_VBLANK: { + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_WAIT_VBLANK" + " is a noop\e[39m" + << frg::endlog; + return EOPNOTSUPP; + } + case DRM_IOCTL_PRIME_HANDLE_TO_FD: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_prime_handle(param->handle); + req.set_drm_flags(param->flags); + + auto [offer, send_ioctl_req, send_req, send_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->fd = resp.drm_prime_fd(); + *result = resp.result(); + return 0; + } + case DRM_IOCTL_PRIME_FD_TO_HANDLE: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_flags(param->flags); + + auto [offer, send_ioctl_req, send_req, send_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(getHandleForFd(param->fd)), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::FILE_NOT_FOUND) { + return EBADF; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + } + + param->handle = resp.drm_prime_handle(); + *result = resp.result(); + return 0; + } + } + + mlibc::infoLogger() << "mlibc: Unexpected DRM ioctl with" + << ", number: 0x" << frg::hex_fmt(_IOC_NR(request)) + << " (raw request: " << frg::hex_fmt(request) << ")" << frg::endlog; + __ensure(!"Illegal ioctl request"); + __builtin_unreachable(); +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/ensure.cpp b/user/include/mlibc/sysdeps/managarm/generic/ensure.cpp new file mode 100644 index 0000000..79316e0 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/ensure.cpp @@ -0,0 +1,37 @@ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +void __frigg_assert_fail( + const char *assertion, const char *file, unsigned int line, const char *function +) { + mlibc::panicLogger() << "In function " << function << ", file " << file << ":" << line << "\n" + << "__ensure(" << assertion << ") failed" << frg::endlog; +} + +namespace mlibc { +void sys_libc_log(const char *message) { + // This implementation is inherently signal-safe. + size_t n = 0; + while (message[n]) + n++; + HEL_CHECK(helLog(kHelLogSeverityInfo, message, n)); +} + +void sys_libc_panic() { + // This implementation is inherently signal-safe. + const char *message = "mlibc: Panic!"; + size_t n = 0; + while (message[n]) + n++; + helPanic(message, n); +} +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/entry.cpp b/user/include/mlibc/sysdeps/managarm/generic/entry.cpp new file mode 100644 index 0000000..fcc3eca --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/entry.cpp @@ -0,0 +1,135 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +extern "C" uintptr_t *__dlapi_entrystack(); +extern "C" void __dlapi_enter(uintptr_t *); + +// declared in posix-pipe.hpp +thread_local Queue globalQueue; + +// TODO: clock tracker page and file table don't need to be thread-local! +thread_local HelHandle __mlibc_posix_lane; +thread_local void *__mlibc_clk_tracker_page; + +namespace { +thread_local unsigned __mlibc_gsf_nesting; +thread_local posix::ThreadPage *__mlibc_cached_thread_page; +thread_local HelHandle *cachedFileTable; + +// This construction is a bit weird: Even though the variables above +// are thread_local we still protect their initialization with a pthread_once_t +// (instead of using a C++ constructor). +// We do this in order to able to clear the pthread_once_t after a fork. +thread_local pthread_once_t has_cached_infos = PTHREAD_ONCE_INIT; + +void actuallyCacheInfos() { + posix::ManagarmProcessData data; + HEL_CHECK( + helSyscall1(kHelCallSuper + posix::superGetProcessData, reinterpret_cast(&data)) + ); + + __mlibc_posix_lane = data.posixLane; + __mlibc_cached_thread_page = data.threadPage; + cachedFileTable = data.fileTable; + __mlibc_clk_tracker_page = data.clockTrackerPage; +} +} // namespace + +SignalGuard::SignalGuard() { + pthread_once(&has_cached_infos, &actuallyCacheInfos); + if (!__mlibc_cached_thread_page) + return; + + if (!__mlibc_gsf_nesting) + __atomic_store_n(&__mlibc_cached_thread_page->globalSignalFlag, 1, __ATOMIC_RELAXED); + __mlibc_gsf_nesting++; +} + +SignalGuard::~SignalGuard() { + pthread_once(&has_cached_infos, &actuallyCacheInfos); + if (!__mlibc_cached_thread_page) + return; + + __ensure(__mlibc_gsf_nesting > 0); + __mlibc_gsf_nesting--; + if (!__mlibc_gsf_nesting) { + unsigned int result = + __atomic_exchange_n(&__mlibc_cached_thread_page->globalSignalFlag, 0, __ATOMIC_RELAXED); + if (result == 2) { + HEL_CHECK(helSyscall0(kHelCallSuper + posix::superSigRaise)); + } else { + __ensure(result == 1); + } + } +} + +MemoryAllocator &getSysdepsAllocator() { + // use frg::eternal to prevent a call to __cxa_atexit(). + // this is necessary because __cxa_atexit() call this function. + static frg::eternal virtualAllocator; + static frg::eternal heap{virtualAllocator.get()}; + static frg::eternal singleton{&heap.get()}; + return singleton.get(); +} + +HelHandle getPosixLane() { + cacheFileTable(); + return __mlibc_posix_lane; +} + +HelHandle *cacheFileTable() { + // TODO: Make sure that this is signal-safe (it is called e.g. by sys_clock_get()). + pthread_once(&has_cached_infos, &actuallyCacheInfos); + return cachedFileTable; +} + +HelHandle getHandleForFd(int fd) { + if (fd >= 512) + return 0; + + return cacheFileTable()[fd]; +} + +void clearCachedInfos() { has_cached_infos = PTHREAD_ONCE_INIT; } + +void resetCancellationId() { + pthread_once(&has_cached_infos, &actuallyCacheInfos); + __atomic_store_n(&__mlibc_cached_thread_page->cancellationId, 0, __ATOMIC_RELEASE); +} + +void setCancellationId(uint64_t id, HelHandle handle, int fd) { + pthread_once(&has_cached_infos, &actuallyCacheInfos); + + __mlibc_cached_thread_page->lane = handle; + __mlibc_cached_thread_page->fd = fd; + + __atomic_store_n(&__mlibc_cached_thread_page->cancellationId, id, __ATOMIC_RELEASE); +} + +namespace { +thread_local uint64_t cancellationId = 1; +} // namespace + +uint64_t allocateCancellationId() { return cancellationId++; } + +extern char **environ; + +extern "C" void +__mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + __dlapi_enter(entry_stack); + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} diff --git a/user/include/mlibc/sysdeps/managarm/generic/file.cpp b/user/include/mlibc/sysdeps/managarm/generic/file.cpp new file mode 100644 index 0000000..7597e3d --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/file.cpp @@ -0,0 +1,3014 @@ +#ifdef _GNU_SOURCE +#undef _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +HelHandle __mlibc_getPassthrough(int fd) { + auto handle = getHandleForFd(fd); + __ensure(handle); + return handle; +} + +namespace mlibc { + +int sys_chdir(const char *path) { + SignalGuard sguard; + + managarm::posix::ChdirRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_req, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::ChdirResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_fchdir(int fd) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::FCHDIR); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + return 0; +} + +int sys_chroot(const char *path) { + SignalGuard sguard; + + managarm::posix::ChrootRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_req, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::ChrootResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + return 0; +} + +int sys_mkdir(const char *path, mode_t mode) { return sys_mkdirat(AT_FDCWD, path, mode); } + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + SignalGuard sguard; + + managarm::posix::MkdirAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_mode(mode); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_symlink(const char *target_path, const char *link_path) { + return sys_symlinkat(target_path, AT_FDCWD, link_path); +} + +int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + SignalGuard sguard; + + managarm::posix::SymlinkAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), link_path)); + req.set_target_path(frg::string(getSysdepsAllocator(), target_path)); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_link(const char *old_path, const char *new_path) { + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); +} + +int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + SignalGuard sguard; + + managarm::posix::LinkAtRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), old_path)); + req.set_target_path(frg::string(getSysdepsAllocator(), new_path)); + req.set_fd(olddirfd); + req.set_newfd(newdirfd); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_rename(const char *path, const char *new_path) { + return sys_renameat(AT_FDCWD, path, AT_FDCWD, new_path); +} + +int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + SignalGuard sguard; + + managarm::posix::RenameAtRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), old_path)); + req.set_target_path(frg::string(getSysdepsAllocator(), new_path)); + req.set_fd(olddirfd); + req.set_newfd(newdirfd); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +} // namespace mlibc + +namespace mlibc { + +int do_dup2(int fd, int flags, int newfd, bool fcntl_mode, int *outfd) { + SignalGuard sguard; + + managarm::posix::Dup2Request req(getSysdepsAllocator()); + req.set_fd(fd); + req.set_newfd(newfd); + req.set_flags(flags); + req.set_fcntl_mode(fcntl_mode); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::Dup2Response resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + if (outfd) + *outfd = resp.fd(); + + return 0; +} + +int sys_fcntl(int fd, int request, va_list args, int *result) { + SignalGuard sguard; + if (request == F_DUPFD) { + int newfd; + int wantedFd = va_arg(args, int); + if (int e = do_dup2(fd, 0, wantedFd, true, &newfd); e) + return e; + *result = newfd; + return 0; + } else if (request == F_DUPFD_CLOEXEC) { + int newfd; + int wantedFd = va_arg(args, int); + if (int e = do_dup2(fd, O_CLOEXEC, wantedFd, true, &newfd); e) + return e; + *result = newfd; + return 0; + } else if (request == F_GETFD) { + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::FD_GET_FLAGS); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *result = resp.flags(); + return 0; + } else if (request == F_SETFD) { + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::FD_SET_FLAGS); + req.set_fd(fd); + req.set_flags(va_arg(args, int)); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *result = static_cast(resp.error()); + return 0; + } else if (request == F_GETFL) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_GET_FILE_FLAGS); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger() << "\e[31mmlibc: fcntl(F_GETFL) unimplemented for this file\e[39m" + << frg::endlog; + return EINVAL; + } else if (resp.error() != managarm::fs::Errors::SUCCESS) { + return resp.error() | toErrno; + } + + *result = resp.flags(); + return 0; + } else if (request == F_SETFL) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_SET_FILE_FLAGS); + req.set_fd(fd); + req.set_flags(va_arg(args, int)); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger() << "\e[31mmlibc: fcntl(F_SETFL) unimplemented for this file\e[39m" + << frg::endlog; + return EINVAL; + } else if (resp.error() != managarm::fs::Errors::SUCCESS) { + return resp.error() | toErrno; + } + + *result = 0; + return 0; + } else if (request == F_SETLK) { + mlibc::infoLogger() << "\e[31mmlibc: F_SETLK\e[39m" << frg::endlog; + return 0; + } else if (request == F_SETLKW) { + mlibc::infoLogger() << "\e[31mmlibc: F_SETLKW\e[39m" << frg::endlog; + return 0; + } else if (request == F_GETLK) { + struct flock *lock = va_arg(args, struct flock *); + lock->l_type = F_UNLCK; + mlibc::infoLogger() << "\e[31mmlibc: F_GETLK is stubbed!\e[39m" << frg::endlog; + return 0; + } else if (request == F_OFD_SETLK) { + mlibc::infoLogger() << "\e[31mmlibc: F_OFD_SETLK\e[39m" << frg::endlog; + return 0; + } else if (request == F_OFD_SETLKW) { + mlibc::infoLogger() << "\e[31mmlibc: F_OFD_SETLKW\e[39m" << frg::endlog; + return 0; + } else if (request == F_OFD_GETLK) { + struct flock *lock = va_arg(args, struct flock *); + lock->l_type = F_UNLCK; + mlibc::infoLogger() << "\e[31mmlibc: F_OFD_GETLK is stubbed!\e[39m" << frg::endlog; + return 0; + } else if (request == F_ADD_SEALS) { + auto seals = va_arg(args, int); + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_ADD_SEALS); + req.set_fd(fd); + req.set_seals(seals); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::RecvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger( + ) << "\e[31mmlibc: fcntl(F_ADD_SEALS) unimplemented for this file\e[39m" + << frg::endlog; + return EINVAL; + } else if (resp.error() != managarm::fs::Errors::SUCCESS) { + return resp.error() | toErrno; + } + + *result = resp.seals(); + return 0; + } else if (request == F_GET_SEALS) { + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_GET_SEALS); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::RecvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger( + ) << "\e[31mmlibc: fcntl(F_GET_SEALS) unimplemented for this file\e[39m" + << frg::endlog; + return EINVAL; + } else if (resp.error() != managarm::fs::Errors::SUCCESS) { + return resp.error() | toErrno; + } + + *result = resp.seals(); + return 0; + } else { + mlibc::infoLogger() << "\e[31mmlibc: Unexpected fcntl() request: " << request << "\e[39m" + << frg::endlog; + return EINVAL; + } +} + +int sys_open_dir(const char *path, int *handle) { return sys_open(path, 0, 0, handle); } + +int sys_read_entries(int fd, void *buffer, size_t max_size, size_t *bytes_read) { + SignalGuard sguard; + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::ReadEntriesRequest req(getSysdepsAllocator()); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + auto conversation = offer.descriptor(); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + auto preamble = bragi::read_preamble(recv_resp); + __ensure(!preamble.error()); + + frg::vector tailBuffer{getSysdepsAllocator()}; + tailBuffer.resize(preamble.tail_size()); + auto [recv_tail] = exchangeMsgsSync( + conversation.getHandle(), helix_ng::recvBuffer(tailBuffer.data(), tailBuffer.size()) + ); + + HEL_CHECK(recv_tail.error()); + + auto resp = *bragi::parse_head_tail( + recv_resp, tailBuffer, getSysdepsAllocator() + ); + recv_resp.reset(); + + if (resp.error() == managarm::fs::Errors::END_OF_FILE) { + *bytes_read = 0; + return 0; + } else if (resp.error() != managarm::fs::Errors::SUCCESS) { + return resp.error() | toErrno; + } + + __ensure(max_size > sizeof(struct dirent)); + auto ent = new (buffer) struct dirent; + memset(ent, 0, sizeof(struct dirent)); + memcpy(ent->d_name, resp.path().data(), resp.path().size()); + ent->d_reclen = sizeof(struct dirent); + *bytes_read = sizeof(struct dirent); + return 0; +} + +int sys_ttyname(int fd, char *buf, size_t size) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::TTY_NAME); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + __ensure(size >= resp.path().size() + 1); + memcpy(buf, resp.path().data(), size); + buf[resp.path().size()] = '\0'; + return 0; +} + +int sys_fdatasync(int) { + mlibc::infoLogger() << "\e[35mmlibc: fdatasync() is a no-op\e[39m" << frg::endlog; + return 0; +} + +int sys_getcwd(char *buffer, size_t size) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::GETCWD); + req.set_size(size); + + auto [offer, send_req, recv_resp, recv_path] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(buffer, size) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_path.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + if (static_cast(resp.size()) >= size) + return ERANGE; + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + SignalGuard sguard; + + managarm::posix::VmMapRequest req(getSysdepsAllocator()); + req.set_address_hint(reinterpret_cast(hint)); + req.set_size(size); + req.set_mode(prot); + req.set_flags(flags); + req.set_fd(fd); + req.set_rel_offset(offset); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *window = reinterpret_cast(resp.offset()); + return 0; +} + +int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::VM_REMAP); + req.set_address(reinterpret_cast(pointer)); + req.set_size(size); + req.set_new_size(new_size); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *window = reinterpret_cast(resp.offset()); + return 0; +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::VM_PROTECT); + req.set_address(reinterpret_cast(pointer)); + req.set_size(size); + req.set_mode(prot); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::VM_UNMAP); + req.set_address(reinterpret_cast(pointer)); + req.set_size(size); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_setsid(pid_t *sid) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::SETSID); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) { + *sid = -1; + return resp.error() | toErrno; + } + + *sid = resp.sid(); + return 0; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int result; + if (int e = sys_ioctl(fd, TCGETS, attr, &result); e) + return e; + return 0; +} + +int sys_tcsetattr(int fd, int when, const struct termios *attr) { + if (when < TCSANOW || when > TCSAFLUSH) + return EINVAL; + + if (int e = sys_ioctl(fd, TCSETS, const_cast(attr), nullptr); e) + return e; + return 0; +} + +int sys_tcdrain(int) { + mlibc::infoLogger() << "\e[35mmlibc: tcdrain() is a stub\e[39m" << frg::endlog; + return 0; +} + +int sys_socket(int domain, int type_and_flags, int proto, int *fd) { + constexpr int type_mask = int(0xF); + constexpr int flags_mask = ~int(0xF); + + SignalGuard sguard; + + managarm::posix::SocketRequest req(getSysdepsAllocator()); + req.set_domain(domain); + req.set_socktype(type_and_flags & type_mask); + req.set_protocol(proto); + req.set_flags(type_and_flags & flags_mask); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *fd = resp.fd(); + return 0; +} + +int sys_pipe(int *fds, int flags) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::PIPE_CREATE); + req.set_flags(flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + __ensure(resp.fds_size() == 2); + fds[0] = resp.fds(0); + fds[1] = resp.fds(1); + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + constexpr int type_mask = int(0xF); + constexpr int flags_mask = ~int(0xF); + __ensure(!((type_and_flags & flags_mask) & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))); + + SignalGuard sguard; + + managarm::posix::SockpairRequest req(getSysdepsAllocator()); + req.set_domain(domain); + req.set_socktype(type_and_flags & type_mask); + req.set_protocol(proto); + req.set_flags(type_and_flags & flags_mask); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + __ensure(resp.fds_size() == 2); + fds[0] = resp.fds(0); + fds[1] = resp.fds(1); + return 0; +} + +int sys_msg_send(int sockfd, const struct msghdr *hdr, int flags, ssize_t *length) { + frg::small_vector sglist{getSysdepsAllocator()}; + auto handle = getHandleForFd(sockfd); + if (!handle) + return EBADF; + + size_t overall_size = 0; + for (size_t i = 0; i < hdr->msg_iovlen; i++) { + HelSgItem item{ + .buffer = hdr->msg_iov[i].iov_base, + .length = hdr->msg_iov[i].iov_len, + }; + sglist.push_back(item); + overall_size += hdr->msg_iov[i].iov_len; + } + + SignalGuard sguard; + + managarm::fs::SendMsgRequest req(getSysdepsAllocator()); + req.set_flags(flags); + req.set_size(overall_size); + + req.set_has_cmsg_creds(false); + req.set_has_cmsg_rights(false); + for (auto cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) { + __ensure(cmsg->cmsg_level == SOL_SOCKET); + __ensure(cmsg->cmsg_len >= sizeof(struct cmsghdr)); + if (cmsg->cmsg_type == SCM_CREDENTIALS) { + req.set_has_cmsg_creds(true); + size_t size = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); + __ensure(size == sizeof(struct ucred)); + struct ucred creds; + memcpy(&creds, CMSG_DATA(cmsg), sizeof(struct ucred)); + req.set_creds_pid(creds.pid); + req.set_creds_uid(creds.uid); + req.set_creds_gid(creds.gid); + } else if (cmsg->cmsg_type == SCM_RIGHTS) { + req.set_has_cmsg_rights(true); + size_t size = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); + __ensure(!(size % sizeof(int))); + for (size_t off = 0; off < size; off += sizeof(int)) { + int fd; + memcpy(&fd, CMSG_DATA(cmsg) + off, sizeof(int)); + req.add_fds(fd); + } + } else { + mlibc::infoLogger( + ) << "mlibc: sys_msg_send only supports SCM_RIGHTS or SCM_CREDENTIALS, got: " + << cmsg->cmsg_type << "!" << frg::endlog; + return EINVAL; + } + } + + auto [offer, send_head, send_tail, send_data, imbue_creds, send_addr, recv_resp] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::sendBufferSg(sglist.data(), hdr->msg_iovlen), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(hdr->msg_name, hdr->msg_namelen), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(send_data.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_addr.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SendMsgReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + *length = resp.size(); + return 0; +} + +int sys_msg_recv(int sockfd, struct msghdr *hdr, int flags, ssize_t *length) { + if (!hdr->msg_iovlen) { + return EMSGSIZE; + } + + auto handle = getHandleForFd(sockfd); + if (!handle) + return EBADF; + + SignalGuard sguard; + + managarm::fs::RecvMsgRequest req(getSysdepsAllocator()); + req.set_flags(flags); + req.set_size(hdr->msg_iov[0].iov_len); + req.set_addr_size(hdr->msg_namelen); + req.set_ctrl_size(hdr->msg_controllen); + + auto [offer, send_req, imbue_creds, recv_resp, recv_addr, recv_data, recv_ctrl] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline(), + helix_ng::recvBuffer(hdr->msg_name, hdr->msg_namelen), + helix_ng::recvBuffer(hdr->msg_iov[0].iov_base, hdr->msg_iov[0].iov_len), + helix_ng::recvBuffer(hdr->msg_control, hdr->msg_controllen) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::RecvMsgReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::fs::Errors::SUCCESS) { + return resp.error() | toErrno; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + HEL_CHECK(recv_addr.error()); + HEL_CHECK(recv_data.error()); + HEL_CHECK(recv_ctrl.error()); + + hdr->msg_namelen = resp.addr_size(); + hdr->msg_controllen = recv_ctrl.actualLength(); + hdr->msg_flags = resp.flags(); + *length = resp.ret_val(); + return 0; + } +} + +int sys_pselect( + int, + fd_set *read_set, + fd_set *write_set, + fd_set *except_set, + const struct timespec *timeout, + const sigset_t *sigmask, + int *num_events +) { + // TODO: Do not keep errors from epoll (?). + int fd = epoll_create1(0); + if (fd == -1) + return -1; + + for (int k = 0; k < FD_SETSIZE; k++) { + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + + if (read_set && FD_ISSET(k, read_set)) + ev.events |= EPOLLIN; // TODO: Additional events. + if (write_set && FD_ISSET(k, write_set)) + ev.events |= EPOLLOUT; // TODO: Additional events. + if (except_set && FD_ISSET(k, except_set)) + ev.events |= EPOLLPRI; + + if (!ev.events) + continue; + ev.data.u32 = k; + + if (epoll_ctl(fd, EPOLL_CTL_ADD, k, &ev)) + return -1; + } + + struct epoll_event evnts[16]; + int n = epoll_pwait( + fd, evnts, 16, timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 100) : -1, sigmask + ); + if (n == -1) + return -1; + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + int m = 0; + + for (int i = 0; i < n; i++) { + int k = evnts[i].data.u32; + + if (read_set && FD_ISSET(k, read_set) + && evnts[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_read_set); + m++; + } + + if (write_set && FD_ISSET(k, write_set) + && evnts[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_write_set); + m++; + } + + if (except_set && FD_ISSET(k, except_set) && evnts[i].events & EPOLLPRI) { + FD_SET(k, &res_except_set); + m++; + } + } + + if (close(fd)) + __ensure("close() failed on epoll file"); + + if (read_set) + memcpy(read_set, &res_read_set, sizeof(fd_set)); + if (write_set) + memcpy(write_set, &res_write_set, sizeof(fd_set)); + if (except_set) + memcpy(except_set, &res_except_set, sizeof(fd_set)); + + *num_events = m; + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + __ensure(timeout >= 0 || timeout == -1); // TODO: Report errors correctly. + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::EPOLL_CALL); + req.set_timeout(timeout > 0 ? int64_t{timeout} * 1000000 : timeout); + req.set_cancellation_id(allocateCancellationId()); + + for (nfds_t i = 0; i < count; i++) { + req.add_fds(fds[i].fd); + req.add_events(fds[i].events); + } + + auto [offer, send_req, recv_resp] = exchangeMsgsSyncCancellable( + getPosixLane(), + req.cancellation_id(), + -1, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) { + return resp.error() | toErrno; + } else { + __ensure(resp.events_size() == count); + + int m = 0; + for (nfds_t i = 0; i < count; i++) { + if (resp.events(i)) + m++; + fds[i].revents = resp.events(i); + } + + *num_events = m; + return 0; + } +} + +int sys_epoll_create(int flags, int *fd) { + // Some applications assume EPOLL_CLOEXEC and O_CLOEXEC to be the same. + // They are on linux, but not yet on managarm. + __ensure(!(flags & ~(EPOLL_CLOEXEC | O_CLOEXEC))); + + SignalGuard sguard; + + uint32_t proto_flags = 0; + if (flags & EPOLL_CLOEXEC || flags & O_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::EPOLL_CREATE); + req.set_flags(proto_flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *fd = resp.fd(); + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + if (mode == EPOLL_CTL_ADD) { + __ensure(ev); + req.set_request_type(managarm::posix::CntReqType::EPOLL_ADD); + req.set_flags(ev->events); + req.set_cookie(ev->data.u64); + } else if (mode == EPOLL_CTL_MOD) { + __ensure(ev); + req.set_request_type(managarm::posix::CntReqType::EPOLL_MODIFY); + req.set_flags(ev->events); + req.set_cookie(ev->data.u64); + } else if (mode == EPOLL_CTL_DEL) { + req.set_request_type(managarm::posix::CntReqType::EPOLL_DELETE); + } else { + mlibc::panicLogger() << "\e[31mmlibc: Illegal epoll_ctl() mode\e[39m" << frg::endlog; + } + req.set_fd(epfd); + req.set_newfd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_epoll_pwait( + int epfd, struct epoll_event *ev, int n, int timeout, const sigset_t *sigmask, int *raised +) { + if (!(timeout >= 0 || timeout == -1)) + return EINVAL; + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::EPOLL_WAIT); + req.set_fd(epfd); + req.set_size(n); + req.set_timeout(timeout > 0 ? int64_t{timeout} * 1000000 : timeout); + if (sigmask != nullptr) { + req.set_sigmask(*reinterpret_cast(sigmask)); + req.set_sigmask_needed(true); + } else { + req.set_sigmask_needed(false); + } + + auto [offer, send_req, recv_resp, recv_data] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(ev, n * sizeof(struct epoll_event)) + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + __ensure(!(recv_data.actualLength() % sizeof(struct epoll_event))); + *raised = recv_data.actualLength() / sizeof(struct epoll_event); + return 0; +} + +int sys_timerfd_create(int clockid, int flags, int *fd) { + SignalGuard sguard; + + managarm::posix::TimerFdCreateRequest req(getSysdepsAllocator()); + req.set_clock(clockid); + req.set_flags(flags); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::TimerFdCreateResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *fd = resp.fd(); + return 0; +} + +int sys_timerfd_settime( + int fd, int flags, const struct itimerspec *value, struct itimerspec *oldvalue +) { + SignalGuard sguard; + + managarm::posix::TimerFdSetRequest req(getSysdepsAllocator()); + req.set_fd(fd); + req.set_flags(flags); + req.set_value_sec(value->it_value.tv_sec); + req.set_value_nsec(value->it_value.tv_nsec); + req.set_interval_sec(value->it_interval.tv_sec); + req.set_interval_nsec(value->it_interval.tv_nsec); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::TimerFdSetResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + if (oldvalue) { + oldvalue->it_value.tv_sec = resp.value_sec(); + oldvalue->it_value.tv_nsec = resp.value_nsec(); + oldvalue->it_interval.tv_sec = resp.interval_sec(); + oldvalue->it_interval.tv_nsec = resp.interval_nsec(); + } + + return 0; +} + +int sys_timerfd_gettime(int fd, struct itimerspec *its) { + SignalGuard sguard; + + managarm::posix::TimerFdGetRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::TimerFdGetResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + if (its) { + its->it_value.tv_sec = resp.value_sec(); + its->it_value.tv_nsec = resp.value_nsec(); + its->it_interval.tv_sec = resp.interval_sec(); + its->it_interval.tv_nsec = resp.interval_nsec(); + } else { + return EFAULT; + } + + return 0; +} + +int sys_signalfd_create(const sigset_t *masks, int flags, int *fd) { + __ensure(!(flags & ~(SFD_CLOEXEC | SFD_NONBLOCK))); + + uint32_t proto_flags = 0; + if (flags & SFD_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + if (flags & SFD_NONBLOCK) + proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::SIGNALFD_CREATE); + req.set_flags(proto_flags); + req.set_sigset(*reinterpret_cast(masks)); + req.set_fd(*fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *fd = resp.fd(); + return 0; +} + +int sys_pidfd_open(pid_t pid, unsigned int flags, int *outfd) { + SignalGuard sguard; + + managarm::posix::PidfdOpenRequest req(getSysdepsAllocator()); + req.set_pid(pid); + req.set_flags(flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::PidfdOpenResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *outfd = resp.fd(); + return 0; +} + +int sys_pidfd_getpid(int pidfd, pid_t *outpid) { + SignalGuard sguard; + + managarm::posix::PidfdGetPidRequest req(getSysdepsAllocator()); + req.set_pidfd(pidfd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::PidfdGetPidResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *outpid = resp.pid(); + return 0; +} + +int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags) { + SignalGuard sguard; + + if (info) { + mlibc::infoLogger() << "mlibc: pidfd_send_signal does not support passing siginfo_t info" + << frg::endlog; + return EINVAL; + } + + managarm::posix::PidfdSendSignalRequest req(getSysdepsAllocator()); + req.set_pidfd(pidfd); + req.set_signal(sig); + req.set_flags(flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::PidfdSendSignalResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_reboot(int command) { + if (command != RB_POWER_OFF && command != RB_AUTOBOOT) { + mlibc::infoLogger( + ) << "mlibc: Anything other than power off or reboot is not supported yet!" + << frg::endlog; + return EINVAL; + } + + SignalGuard sguard; + + managarm::posix::RebootRequest req(getSysdepsAllocator()); + req.set_cmd(command); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + return 0; +} + +int sys_inotify_create(int flags, int *fd) { + __ensure(!(flags & ~(IN_CLOEXEC | IN_NONBLOCK))); + + SignalGuard sguard; + + uint32_t proto_flags = 0; + if (flags & IN_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + if (flags & IN_NONBLOCK) + proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; + + managarm::posix::InotifyCreateRequest req(getSysdepsAllocator()); + req.set_flags(proto_flags); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *fd = resp.fd(); + return 0; +} + +int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd) { + SignalGuard sguard; + + managarm::posix::InotifyAddRequest req(getSysdepsAllocator()); + req.set_fd(ifd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_flags(mask); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *wd = resp.wd(); + return 0; +} + +int sys_inotify_rm_watch(int ifd, int wd) { + SignalGuard sguard; + + managarm::posix::InotifyRmRequest req(getSysdepsAllocator()); + req.set_ifd(ifd); + req.set_wd(wd); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::InotifyRmReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_eventfd_create(unsigned int initval, int flags, int *fd) { + if (flags & ~(EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE)) + return EINVAL; + + SignalGuard sguard; + + uint32_t proto_flags = 0; + if (flags & EFD_NONBLOCK) + proto_flags |= managarm::posix::EventFdFlags::NONBLOCK; + if (flags & EFD_CLOEXEC) + proto_flags |= managarm::posix::EventFdFlags::CLOEXEC; + if (flags & EFD_SEMAPHORE) + proto_flags |= managarm::posix::EventFdFlags::SEMAPHORE; + + managarm::posix::EventfdCreateRequest req(getSysdepsAllocator()); + req.set_flags(proto_flags); + req.set_initval(initval); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *fd = resp.fd(); + return 0; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + SignalGuard sguard; + + // We do not support O_TMPFILE. + if (flags & O_TMPFILE) + return EOPNOTSUPP; + + uint32_t proto_flags = 0; + if (flags & O_APPEND) + proto_flags |= managarm::posix::OpenFlags::OF_APPEND; + if (flags & O_CREAT) + proto_flags |= managarm::posix::OpenFlags::OF_CREATE; + if (flags & O_EXCL) + proto_flags |= managarm::posix::OpenFlags::OF_EXCLUSIVE; + if (flags & O_NONBLOCK) + proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; + if (flags & O_TRUNC) + proto_flags |= managarm::posix::OpenFlags::OF_TRUNC; + + if (flags & O_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + if (flags & O_NOCTTY) + proto_flags |= managarm::posix::OpenFlags::OF_NOCTTY; + if (flags & O_NOFOLLOW) + proto_flags |= managarm::posix::OpenFlags::OF_NOFOLLOW; + if (flags & O_DIRECTORY) + proto_flags |= managarm::posix::OpenFlags::OF_DIRECTORY; + + if (flags & O_PATH) + proto_flags |= managarm::posix::OpenFlags::OF_PATH; + else if ((flags & O_ACCMODE) == O_RDONLY) + proto_flags |= managarm::posix::OpenFlags::OF_RDONLY; + else if ((flags & O_ACCMODE) == O_WRONLY) + proto_flags |= managarm::posix::OpenFlags::OF_WRONLY; + else if ((flags & O_ACCMODE) == O_RDWR) + proto_flags |= managarm::posix::OpenFlags::OF_RDWR; + + managarm::posix::OpenAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_flags(proto_flags); + req.set_mode(mode); + + auto [offer, sendHead, sendTail, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendHead.error()); + HEL_CHECK(sendTail.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *fd = resp.fd(); + return 0; +} + +int sys_mkfifoat(int dirfd, const char *path, mode_t mode) { + SignalGuard sguard; + + managarm::posix::MkfifoAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_mode(mode); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_mknodat(int dirfd, const char *path, int mode, int dev) { + SignalGuard sguard; + + managarm::posix::MknodAtRequest req(getSysdepsAllocator()); + req.set_dirfd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_mode(mode); + req.set_device(dev); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::READ); + req.set_fd(fd); + req.set_size(max_size); + req.set_cancellation_id(allocateCancellationId()); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, imbue_creds, recv_resp, recv_data] = exchangeMsgsSyncCancellable( + handle, + req.cancellation_id(), + fd, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::recvInline(), + helix_ng::recvBuffer(data, max_size) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + HEL_CHECK(recv_data.error()); + + *bytes_read = recv_data.actualLength(); + return resp.error() | toErrno; +} + +int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read) { + for (int i = 0; i < iovc; i++) { + ssize_t intermed = 0; + + if (int e = sys_read(fd, iovs[i].iov_base, iovs[i].iov_len, &intermed); e) + return e; + else if (intermed == 0) + break; + + *bytes_read += intermed; + } + + return 0; +} + +int sys_write(int fd, const void *data, size_t size, ssize_t *bytes_written) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::WRITE); + req.set_fd(fd); + req.set_size(size); + + auto [offer, send_req, imbue_creds, send_data, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(data, size), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_data.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + if (bytes_written) + *bytes_written = resp.size(); + + return 0; +} + +int sys_writev(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written) { + frg::small_vector sglist{getSysdepsAllocator()}; + + size_t overall_size = 0; + for (int i = 0; i < iovc; i++) { + HelSgItem item{ + .buffer = iovs[i].iov_base, + .length = iovs[i].iov_len, + }; + sglist.push_back(item); + overall_size += iovs[i].iov_len; + } + + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::WRITE); + req.set_fd(fd); + req.set_size(overall_size); + + auto [offer, send_req, imbue_creds, send_data, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::sendBufferSg(sglist.data(), iovc), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_data.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + if (bytes_written) + *bytes_written = resp.size(); + + return 0; +} + +int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_PREAD); + req.set_fd(fd); + req.set_size(n); + req.set_offset(off); + + auto [offer, send_req, imbue_creds, recv_resp, recv_data] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline(), + helix_ng::recvBuffer(buf, n) + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::END_OF_FILE) { + *bytes_read = 0; + return 0; + } else if (resp.error() == managarm::fs::Errors::SUCCESS) { + HEL_CHECK(recv_data.error()); + *bytes_read = recv_data.actualLength(); + return 0; + } + + return resp.error() | toErrno; +} + +int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_PWRITE); + req.set_fd(fd); + req.set_size(n); + req.set_offset(off); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_head, imbue_creds, to_write, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(buf, n), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(to_write.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + *bytes_written = n; + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_fd(fd); + req.set_rel_offset(offset); + + if (whence == SEEK_SET) { + req.set_req_type(managarm::fs::CntReqType::SEEK_ABS); + } else if (whence == SEEK_CUR) { + req.set_req_type(managarm::fs::CntReqType::SEEK_REL); + } else if (whence == SEEK_END) { + req.set_req_type(managarm::fs::CntReqType::SEEK_EOF); + } else { + return EINVAL; + } + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer(helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + *new_offset = resp.offset(); + return 0; +} + +int sys_close(int fd) { + SignalGuard sguard; + + managarm::posix::CloseRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + + return resp.error() | toErrno; +} + +int sys_dup(int fd, int flags, int *newfd) { + SignalGuard sguard; + + __ensure(!(flags & ~(O_CLOEXEC))); + + uint32_t proto_flags = 0; + if (flags & O_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::DUP); + req.set_fd(fd); + req.set_flags(proto_flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *newfd = resp.fd(); + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { return do_dup2(fd, flags, newfd, false, nullptr); } + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *result) { + SignalGuard sguard; + + managarm::posix::FstatAtRequest req(getSysdepsAllocator()); + if (fsfdt == fsfd_target::path) { + req.set_fd(AT_FDCWD); + req.set_path(frg::string(getSysdepsAllocator(), path)); + } else if (fsfdt == fsfd_target::fd) { + flags |= AT_EMPTY_PATH; + req.set_fd(fd); + } else { + __ensure(fsfdt == fsfd_target::fd_path); + req.set_fd(fd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + } + + if (!(flags & AT_EMPTY_PATH) && (!path || !strlen(path))) { + return ENOENT; + } + + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + memset(result, 0, sizeof(struct stat)); + + switch (resp.file_type()) { + case managarm::posix::FileType::FT_REGULAR: + result->st_mode = S_IFREG; + break; + case managarm::posix::FileType::FT_DIRECTORY: + result->st_mode = S_IFDIR; + break; + case managarm::posix::FileType::FT_SYMLINK: + result->st_mode = S_IFLNK; + break; + case managarm::posix::FileType::FT_CHAR_DEVICE: + result->st_mode = S_IFCHR; + break; + case managarm::posix::FileType::FT_BLOCK_DEVICE: + result->st_mode = S_IFBLK; + break; + case managarm::posix::FileType::FT_SOCKET: + result->st_mode = S_IFSOCK; + break; + case managarm::posix::FileType::FT_FIFO: + result->st_mode = S_IFIFO; + break; + default: + __ensure(!resp.file_type()); + } + + result->st_dev = 1; + result->st_ino = resp.fs_inode(); + result->st_mode |= resp.mode(); + result->st_nlink = resp.num_links(); + result->st_uid = resp.uid(); + result->st_gid = resp.gid(); + result->st_rdev = resp.ref_devnum(); + result->st_size = resp.file_size(); + result->st_atim.tv_sec = resp.atime_secs(); + result->st_atim.tv_nsec = resp.atime_nanos(); + result->st_mtim.tv_sec = resp.mtime_secs(); + result->st_mtim.tv_nsec = resp.mtime_nanos(); + result->st_ctim.tv_sec = resp.ctime_secs(); + result->st_ctim.tv_nsec = resp.ctime_nanos(); + result->st_blksize = 4096; + result->st_blocks = resp.file_size() / 512 + 1; + return 0; +} + +int +sys_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf) { + SignalGuard sguard; + + managarm::posix::FstatAtRequest req(getSysdepsAllocator()); + if (pathname) + req.set_path(frg::string(getSysdepsAllocator(), pathname)); + req.set_fd(dirfd); + + if (flags + & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT + | AT_STATX_FORCE_SYNC | AT_STATX_DONT_SYNC)) { + return EINVAL; + } + + if (!(flags & AT_EMPTY_PATH) && (!pathname || !strlen(pathname))) { + return ENOENT; + } + + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + memset(statxbuf, 0, sizeof(struct statx)); + + switch (resp.file_type()) { + case managarm::posix::FileType::FT_REGULAR: + statxbuf->stx_mode = S_IFREG; + break; + case managarm::posix::FileType::FT_DIRECTORY: + statxbuf->stx_mode = S_IFDIR; + break; + case managarm::posix::FileType::FT_SYMLINK: + statxbuf->stx_mode = S_IFLNK; + break; + case managarm::posix::FileType::FT_CHAR_DEVICE: + statxbuf->stx_mode = S_IFCHR; + break; + case managarm::posix::FileType::FT_BLOCK_DEVICE: + statxbuf->stx_mode = S_IFBLK; + break; + case managarm::posix::FileType::FT_SOCKET: + statxbuf->stx_mode = S_IFSOCK; + break; + case managarm::posix::FileType::FT_FIFO: + statxbuf->stx_mode = S_IFIFO; + break; + default: + __ensure(!resp.file_type()); + } + + statxbuf->stx_mask = mask; // TODO: Properly? + // statxbuf->st_dev = 1; + statxbuf->stx_ino = resp.fs_inode(); + statxbuf->stx_mode |= resp.mode(); + statxbuf->stx_nlink = resp.num_links(); + statxbuf->stx_uid = resp.uid(); + statxbuf->stx_gid = resp.gid(); + statxbuf->stx_rdev_major = major(resp.ref_devnum()); + statxbuf->stx_rdev_minor = minor(resp.ref_devnum()); + statxbuf->stx_size = resp.file_size(); + statxbuf->stx_atime.tv_sec = resp.atime_secs(); + statxbuf->stx_atime.tv_nsec = resp.atime_nanos(); + statxbuf->stx_mtime.tv_sec = resp.mtime_secs(); + statxbuf->stx_mtime.tv_nsec = resp.mtime_nanos(); + statxbuf->stx_ctime.tv_sec = resp.ctime_secs(); + statxbuf->stx_ctime.tv_nsec = resp.ctime_nanos(); + statxbuf->stx_blksize = 4096; + statxbuf->stx_blocks = resp.file_size() / 512 + 1; + return 0; + } +} + +int sys_readlink(const char *path, void *data, size_t max_size, ssize_t *length) { + return sys_readlinkat(AT_FDCWD, path, data, max_size, length); +} + +int sys_readlinkat(int dirfd, const char *path, void *data, size_t max_size, ssize_t *length) { + SignalGuard sguard; + + managarm::posix::ReadlinkAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_head, send_tail, recv_resp, recv_data] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(data, max_size) + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *length = recv_data.actualLength(); + return 0; +} + +int sys_rmdir(const char *path) { + SignalGuard sguard; + + managarm::posix::RmdirRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_ftruncate(int fd, size_t size) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_TRUNCATE); + req.set_size(size); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_fallocate(int fd, off_t offset, size_t size) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_FALLOCATE); + req.set_rel_offset(offset); + req.set_size(size); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + SignalGuard sguard; + + managarm::posix::UnlinkAtRequest req(getSysdepsAllocator()); + req.set_fd(fd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_access(const char *path, int mode) { return sys_faccessat(AT_FDCWD, path, mode, 0); } + +int sys_faccessat(int dirfd, const char *pathname, int, int flags) { + SignalGuard sguard; + + managarm::posix::AccessAtRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), pathname)); + req.set_fd(dirfd); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_flock(int fd, int opts) { + SignalGuard sguard; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::FLOCK); + req.set_fd(fd); + req.set_flock_flags(opts); + auto handle = getHandleForFd(fd); + if (!handle) { + return EBADF; + } + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_isatty(int fd) { + SignalGuard sguard; + + managarm::posix::IsTtyRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + if (resp.mode()) + return 0; + return ENOTTY; +} + +int sys_chmod(const char *pathname, mode_t mode) { + return sys_fchmodat(AT_FDCWD, pathname, mode, 0); +} + +int sys_fchmod(int fd, mode_t mode) { return sys_fchmodat(fd, "", mode, AT_EMPTY_PATH); } + +int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + SignalGuard sguard; + + managarm::posix::FchmodAtRequest req(getSysdepsAllocator()); + req.set_fd(fd); + req.set_path(frg::string(getSysdepsAllocator(), pathname)); + req.set_mode(mode); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { + (void)dirfd; + (void)pathname; + (void)owner; + (void)group; + (void)flags; + mlibc::infoLogger() << "mlibc: sys_fchownat is a stub!" << frg::endlog; + return 0; +} + +int sys_umask(mode_t mode, mode_t *old) { + SignalGuard sguard; + + managarm::posix::UmaskRequest req(getSysdepsAllocator()); + req.set_newmask(mode); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::UmaskResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + *old = resp.oldmask(); + + return 0; +} + +int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + SignalGuard sguard; + + managarm::posix::UtimensAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + if (pathname != nullptr) + req.set_path(frg::string(getSysdepsAllocator(), pathname)); + if (times) { + req.set_atimeSec(times[0].tv_sec); + req.set_atimeNsec(times[0].tv_nsec); + req.set_mtimeSec(times[1].tv_sec); + req.set_mtimeNsec(times[1].tv_nsec); + } else { + req.set_atimeSec(UTIME_NOW); + req.set_atimeNsec(UTIME_NOW); + req.set_mtimeSec(UTIME_NOW); + req.set_mtimeNsec(UTIME_NOW); + } + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_getentropy(void *buffer, size_t length) { + SignalGuard sguard; + auto p = reinterpret_cast(buffer); + size_t n = 0; + + while (n < length) { + size_t chunk; + HEL_CHECK(helGetRandomBytes(p + n, length - n, &chunk)); + n += chunk; + } + + return 0; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + SignalGuard sguard; + mlibc::infoLogger() << "mlibc: gethostname always returns managarm" << frg::endlog; + char name[10] = "managarm\0"; + if (bufsize < 10) + return ENAMETOOLONG; + strncpy(buffer, name, 10); + return 0; +} + +int sys_fsync(int fd) { + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + mlibc::infoLogger() << "mlibc: fsync is a stub" << frg::endlog; + return 0; +} + +int sys_memfd_create(const char *name, int flags, int *fd) { + SignalGuard sguard; + + managarm::posix::MemFdCreateRequest req(getSysdepsAllocator()); + req.set_name(frg::string(getSysdepsAllocator(), name)); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *fd = resp.fd(); + return 0; +} + +int sys_uname(struct utsname *buf) { + __ensure(buf); + mlibc::infoLogger() << "\e[31mmlibc: uname() returns static information\e[39m" << frg::endlog; + strcpy(buf->sysname, "Managarm"); + strcpy(buf->nodename, "managarm"); + strcpy(buf->release, "0.0.1-rolling"); + strcpy(buf->version, "Managarm is not Managram"); +#if defined(__x86_64__) + strcpy(buf->machine, "x86_64"); +#elif defined(__aarch64__) + strcpy(buf->machine, "aarch64"); +#elif defined(__riscv) + strcpy(buf->machine, "riscv64"); +#else +#error Unknown architecture +#endif + + return 0; +} + +int sys_madvise(void *, size_t, int) { + mlibc::infoLogger() << "mlibc: sys_madvise is a stub!" << frg::endlog; + return 0; +} + +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if (int e = sys_ioctl(fd, TIOCGPTN, &index, nullptr); e) + return e; + if ((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +int sys_unlockpt(int fd) { + int unlock = 0; + + if (int e = sys_ioctl(fd, TIOCSPTLCK, &unlock, nullptr); e) + return e; + + return 0; +} + +int sys_setrlimit(int resource, const struct rlimit *limit) { + switch (resource) { + case RLIMIT_NOFILE: { + SignalGuard sguard; + + managarm::posix::SetResourceLimitRequest req(getSysdepsAllocator()); + req.set_resource(resource); + req.set_cur(limit->rlim_cur); + req.set_max(limit->rlim_max); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SetResourceLimitResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + return resp.error() | toErrno; + } + default: + mlibc::infoLogger() << "mlibc: unhandled rlimit resource " << resource << frg::endlog; + return EINVAL; + } +} + +int sys_getrlimit(int resource, struct rlimit *limit) { + switch (resource) { + case RLIMIT_NOFILE: + /* TODO: change this once we support more than 512 */ + limit->rlim_cur = 512; + limit->rlim_max = 512; + return 0; + default: + return EINVAL; + } +} + +int sys_sysconf(int num, long *ret) { + switch (num) { + case _SC_OPEN_MAX: { + struct rlimit ru; + if (int e = sys_getrlimit(RLIMIT_NOFILE, &ru); e) { + return e; + } + *ret = (ru.rlim_cur == RLIM_INFINITY) ? -1 : ru.rlim_cur; + break; + } + case _SC_PHYS_PAGES: + case _SC_AVPHYS_PAGES: { + // defer these to the generic implementation. + return EINVAL; + } + default: { + SignalGuard sguard; + + managarm::posix::SysconfRequest req(getSysdepsAllocator()); + req.set_num(num); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SysconfResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *ret = resp.value(); + return 0; + } + } + + return 0; +} + +int sys_sysinfo(struct sysinfo *info) { + SignalGuard sguard; + + managarm::posix::GetMemoryInformationRequest req(getSysdepsAllocator()); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::GetMemoryInformationResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + FILE *uptime = fopen("/proc/uptime", "r"); + __ensure(uptime); + int uptime_sec; + int uptime_msec; + int idle_sec; + int idle_msec; + fscanf(uptime, "%d.%d %d.%d", &uptime_sec, &uptime_msec, &idle_sec, &idle_msec); + fclose(uptime); + + // TODO: fill in missing fields. + *info = {}; + info->uptime = uptime_sec; + info->totalram = resp.total_usable_memory(); + info->freeram = resp.available_memory(); + info->mem_unit = resp.memory_unit(); + + return 0; +} + +int sys_fstatfs(int fd, struct statfs *buf) { + SignalGuard sguard; + + managarm::posix::FstatfsRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::FstatfsResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + memset(buf, NULL, sizeof(struct statfs)); + buf->f_type = resp.fstype(); + return 0; +} + +int sys_prctl(int option, va_list va, int *out) { + switch (option) { + case PR_CAPBSET_READ: + // TODO: Implement PR_CAPBSET read if we ever support capabilities + *out = 1; + return 0; + case PR_SET_NAME: { + const auto name = va_arg(va, char *); + *out = 0; + return pthread_setname_np(pthread_self(), name); + } + case PR_GET_NAME: { + const auto name = va_arg(va, char *); + *out = 0; + return pthread_getname_np(pthread_self(), name, 16); + } + case PR_SET_PDEATHSIG: { + managarm::posix::ParentDeathSignalRequest req{getSysdepsAllocator()}; + const auto value = va_arg(va, int); + req.set_signal(value); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::ParentDeathSignalResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *out = 0; + return 0; + } + case PR_GET_DUMPABLE: { + managarm::posix::ProcessDumpableRequest req{getSysdepsAllocator()}; + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::ProcessDumpableResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + *out = resp.value(); + return 0; + } + case PR_SET_DUMPABLE: { + const auto dumpable = va_arg(va, long); + managarm::posix::ProcessDumpableRequest req{getSysdepsAllocator()}; + req.set_set(1); + req.set_new_value(dumpable); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::ProcessDumpableResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + return 0; + } + default: + mlibc::infoLogger() << "mlibc: prctl: operation: " << option << " unimplemented!" + << frg::endlog; + return EINVAL; + } +} + +int sys_statfs(const char *path, struct statfs *buf) { + SignalGuard sguard; + + managarm::posix::FstatfsRequest req(getSysdepsAllocator()); + req.set_fd(-1); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::FstatfsResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + memset(buf, NULL, sizeof(struct statfs)); + buf->f_type = resp.fstype(); + return 0; +} + +int sys_getpriority(int, id_t, int *value) { + mlibc::infoLogger() << "\e[35mmlibc: getpriority() always returns 0\e[39m" << frg::endlog; + *value = 0; + return 0; +} + +int sys_setpriority(int, id_t, int) { + mlibc::infoLogger() << "\e[35mmlibc: setpriority() is a stub\e[39m" << frg::endlog; + return 0; +} + +// We don't support extended attributes yet +int sys_removexattr(const char *, const char *) { return ENOSYS; } + +int sys_lgetxattr(const char *, const char *, void *, size_t, ssize_t *) { return ENOSYS; } + +int sys_setxattr(const char *, const char *, const void *, size_t, int) { return ENOSYS; } + +// We don't implement name_to_handle_at +int sys_name_to_handle_at(int, const char *, struct file_handle *, int *, int) { return ENOSYS; } + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/fork-exec.cpp b/user/include/mlibc/sysdeps/managarm/generic/fork-exec.cpp new file mode 100644 index 0000000..03ac9c9 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/fork-exec.cpp @@ -0,0 +1,791 @@ + +// for _Exit() +#include +#include + +#include +#include + +// for fork() and execve() +#include +// for sched_yield() +#include +#include +// for getrusage() +#include +// for waitpid() +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +int sys_futex_tid() { + HelWord tid = 0; + HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superGetTid, &tid)); + + return tid; +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + // This implementation is inherently signal-safe. + if (time) { + if (helFutexWait(pointer, expected, time->tv_nsec + time->tv_sec * 1000000000)) + return -1; + return 0; + } + if (helFutexWait(pointer, expected, -1)) + return -1; + return 0; +} + +int sys_futex_wake(int *pointer) { + // This implementation is inherently signal-safe. + if (helFutexWake(pointer)) + return -1; + return 0; +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + SignalGuard sguard; + + if (ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::WAIT); + req.set_pid(pid); + req.set_flags(flags); + req.set_cancellation_id(allocateCancellationId()); + + auto [offer, send_head, recv_resp] = exchangeMsgsSyncCancellable( + getPosixLane(), + req.cancellation_id(), + -1, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *ret_pid = resp.pid(); + if (*ret_pid == 0) + return 0; + + if (status) + *status = resp.mode(); + + if (ru != nullptr) { + ru->ru_utime.tv_sec = resp.ru_user_time() / 1'000'000'000; + ru->ru_utime.tv_usec = (resp.ru_user_time() % 1'000'000'000) / 1'000; + } + + return 0; +} + +int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) { + SignalGuard sguard; + + managarm::posix::WaitIdRequest req(getSysdepsAllocator()); + + req.set_idtype(idtype); + req.set_id(id); + req.set_flags(options); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::WaitIdResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + info->si_pid = resp.pid(); + info->si_uid = resp.uid(); + info->si_code = resp.sig_code(); + switch (info->si_code) { + case CLD_EXITED: + info->si_status = WEXITSTATUS(resp.sig_status()); + break; + case CLD_KILLED: + case CLD_DUMPED: + case CLD_STOPPED: + info->si_signo = WSTOPSIG(resp.sig_status()); + break; + case CLD_CONTINUED: + info->si_signo = SIGCHLD; + break; + } + return 0; +} + +void sys_exit(int status) { + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall1(kHelCallSuper + posix::superExit, status)); + __builtin_trap(); +} + +void sys_yield() { + // This implementation is inherently signal-safe. + HEL_CHECK(helYield()); +} + +int sys_sleep(time_t *secs, long *nanos) { + SignalGuard sguard; + globalQueue.trim(); + + uint64_t now; + HEL_CHECK(helGetClock(&now)); + + uint64_t async_id; + HEL_CHECK(helSubmitAwaitClock( + now + uint64_t(*secs) * 1000000000 + uint64_t(*nanos), globalQueue.getQueue(), 0, &async_id + )); + + auto element = globalQueue.dequeueSingle(); + auto result = parseSimple(element); + HEL_CHECK(result->error); + + *secs = 0; + *nanos = 0; + + return 0; +} + +int sys_fork(pid_t *child) { + // This implementation is inherently signal-safe. + int res; + + sigset_t full_sigset; + res = sigfillset(&full_sigset); + __ensure(!res); + + sigset_t former_sigset; + res = sigprocmask(SIG_SETMASK, &full_sigset, &former_sigset); + __ensure(!res); + + HelWord out; + HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superFork, &out)); + *child = out; + + if (!out) { + clearCachedInfos(); + globalQueue.recreateQueue(); + } + + res = sigprocmask(SIG_SETMASK, &former_sigset, nullptr); + __ensure(!res); + + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + // TODO: Make this function signal-safe! + frg::string args_area(getSysdepsAllocator()); + for (auto it = argv; *it; ++it) + args_area += frg::string_view{*it, strlen(*it) + 1}; + + frg::string env_area(getSysdepsAllocator()); + for (auto it = envp; *it; ++it) + env_area += frg::string_view{*it, strlen(*it) + 1}; + + uintptr_t out; + + HEL_CHECK(helSyscall6_1( + kHelCallSuper + posix::superExecve, + reinterpret_cast(path), + strlen(path), + reinterpret_cast(args_area.data()), + args_area.size(), + reinterpret_cast(env_area.data()), + env_area.size(), + &out + )); + + return out; +} + +gid_t sys_getgid() { + SignalGuard sguard; + + managarm::posix::GetGidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.uid(); +} + +int sys_setgid(gid_t gid) { + SignalGuard sguard; + + managarm::posix::SetGidRequest req(getSysdepsAllocator()); + + req.set_uid(gid); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +gid_t sys_getegid() { + SignalGuard sguard; + + managarm::posix::GetEgidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.uid(); +} + +int sys_setegid(gid_t egid) { + SignalGuard sguard; + + managarm::posix::SetEgidRequest req(getSysdepsAllocator()); + + req.set_uid(egid); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + // TODO: handle saved set-user-ID + (void)sgid; + + int real = sys_setgid(rgid); + if (real) + return real; + + int effective = sys_setegid(egid); + if (effective) + return effective; + + return 0; +} + +uid_t sys_getuid() { + SignalGuard sguard; + + managarm::posix::GetUidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.uid(); +} + +int sys_setuid(uid_t uid) { + SignalGuard sguard; + + managarm::posix::SetUidRequest req(getSysdepsAllocator()); + + req.set_uid(uid); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +uid_t sys_geteuid() { + SignalGuard sguard; + + managarm::posix::GetEuidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.uid(); +} + +int sys_seteuid(uid_t euid) { + SignalGuard sguard; + + managarm::posix::SetEuidRequest req(getSysdepsAllocator()); + + req.set_uid(euid); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) { + // TODO: handle saved set-user-ID + (void)suid; + + int real = sys_setuid(ruid); + if (real) + return real; + + int effective = sys_seteuid(euid); + if (effective) + return effective; + + return 0; +} + +int sys_setreuid(uid_t ruid, uid_t euid) { + int real = sys_setuid(ruid); + if (real) + return real; + + int effective = sys_seteuid(euid); + if (effective) + return effective; + + return 0; +} + +int sys_setregid(gid_t rgid, gid_t egid) { + int real = sys_setgid(rgid); + if (real) + return real; + + int effective = sys_setegid(egid); + if (effective) + return effective; + + return 0; +} + +pid_t sys_gettid() { + HelWord tid = 0; + HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superGetTid, &tid)); + + return tid; +} + +pid_t sys_getpid() { + SignalGuard sguard; + + managarm::posix::GetPidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.pid(); +} + +pid_t sys_getppid() { + SignalGuard sguard; + + managarm::posix::GetPpidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.pid(); +} + +int sys_getsid(pid_t pid, pid_t *sid) { + SignalGuard sguard; + + managarm::posix::GetSidRequest req(getSysdepsAllocator()); + req.set_pid(pid); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::posix::Errors::NO_SUCH_RESOURCE) { + *sid = 0; + return ESRCH; + } else if (resp.error() != managarm::posix::Errors::SUCCESS) { + return resp.error() | toErrno; + } + + *sid = resp.pid(); + return 0; +} + +int sys_getpgid(pid_t pid, pid_t *pgid) { + SignalGuard sguard; + + managarm::posix::GetPgidRequest req(getSysdepsAllocator()); + req.set_pid(pid); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::posix::Errors::NO_SUCH_RESOURCE) { + *pgid = 0; + return ESRCH; + } else if (resp.error() != managarm::posix::Errors::SUCCESS) { + return resp.error() | toErrno; + } + + *pgid = resp.pid(); + return 0; +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + SignalGuard sguard; + + managarm::posix::SetPgidRequest req(getSysdepsAllocator()); + + req.set_pid(pid); + req.set_pgid(pgid); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +int sys_getrusage(int scope, struct rusage *usage) { + memset(usage, 0, sizeof(struct rusage)); + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::GET_RESOURCE_USAGE); + req.set_mode(scope); + + auto [offer, send_head, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + usage->ru_utime.tv_sec = resp.ru_user_time() / 1'000'000'000; + usage->ru_utime.tv_usec = (resp.ru_user_time() % 1'000'000'000) / 1'000; + + return 0; +} + +int sys_getschedparam(void *tcb, int *policy, struct sched_param *param) { + if (tcb != mlibc::get_current_tcb()) { + return ESRCH; + } + + *policy = SCHED_OTHER; + int prio = 0; + // TODO(no92): use helGetPriority(kHelThisThread) here + mlibc::infoLogger() << "\e[31mlibc: sys_getschedparam always returns priority 0\e[39m" + << frg::endlog; + param->sched_priority = prio; + + return 0; +} + +int sys_setschedparam(void *tcb, int policy, const struct sched_param *param) { + if (tcb != mlibc::get_current_tcb()) { + return ESRCH; + } + + if (policy != SCHED_OTHER) { + return EINVAL; + } + + HEL_CHECK(helSetPriority(kHelThisThread, param->sched_priority)); + + return 0; +} + +int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + (void)tcb; + + HelWord posixErr = 0; + HelWord tid = 0; + posix::superCloneArgs args{ + .flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD), + }; + + HEL_CHECK(helSyscall3_2( + kHelCallSuper + posix::superClone, + reinterpret_cast(__mlibc_start_thread), + reinterpret_cast(stack), + reinterpret_cast(&args), + &posixErr, + &tid + )); + + if (posixErr) + return managarm::posix::Errors(posixErr) | toErrno; + + if (tid_out) + *tid_out = tid; + + return 0; +} + +int sys_tcb_set(void *pointer) { +#if defined(__x86_64__) + HEL_CHECK(helWriteFsBase(pointer)); +#elif defined(__aarch64__) + uintptr_t addr = reinterpret_cast(pointer); + addr += sizeof(Tcb) - 0x10; + asm volatile("msr tpidr_el0, %0" ::"r"(addr)); +#elif defined(__riscv) && __riscv_xlen == 64 + uintptr_t tp = reinterpret_cast(pointer) + sizeof(Tcb); + asm volatile("mv tp, %0" : : "r"(tp) : "memory"); +#else +#error Unknown architecture +#endif + return 0; +} + +void sys_thread_exit() { + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall1(kHelCallSuper + posix::superThreadExit, 0)); + __builtin_trap(); +} + +int sys_thread_setname(void *tcb, const char *name) { + if (strlen(name) > 15) { + return ERANGE; + } + + auto t = reinterpret_cast(tcb); + char *path; + int cs = 0; + + if (asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) { + return ENOMEM; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + int fd; + if (int e = sys_open(path, O_WRONLY, 0, &fd); e) { + return e; + } + + if (int e = sys_write(fd, name, strlen(name) + 1, nullptr)) { + return e; + } + + sys_close(fd); + + pthread_setcancelstate(cs, nullptr); + + return 0; +} + +int sys_thread_getname(void *tcb, char *name, size_t size) { + auto t = reinterpret_cast(tcb); + char *path; + int cs = 0; + ssize_t real_size = 0; + + if (asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) { + return ENOMEM; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + int fd; + if (int e = sys_open(path, O_RDONLY | O_CLOEXEC, 0, &fd); e) { + return e; + } + + if (int e = sys_read(fd, name, size, &real_size)) { + return e; + } + + name[real_size - 1] = 0; + sys_close(fd); + + pthread_setcancelstate(cs, nullptr); + + if (static_cast(size) <= real_size) { + return ERANGE; + } + + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/ioctl.cpp b/user/include/mlibc/sysdeps/managarm/generic/ioctl.cpp new file mode 100644 index 0000000..11ccf51 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/ioctl.cpp @@ -0,0 +1,1224 @@ +#ifdef _GNU_SOURCE +#undef _GNU_SOURCE +#endif + +#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 + +#define SIOCETHTOOL 0x8946 +#define SIOCGSKNS 0x894C +#define TFD_IOC_SET_TICKS _IOW('T', 0, __u64) + +namespace mlibc { + +static constexpr bool logIoctls = false; + +int ioctl_drm(int fd, unsigned long request, void *arg, int *result, HelHandle handle); + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + if (logIoctls) + mlibc::infoLogger() << "mlibc: ioctl with" + << " type: 0x" << frg::hex_fmt(_IOC_TYPE(request)) << ", number: 0x" + << frg::hex_fmt(_IOC_NR(request)) + << " (raw request: " << frg::hex_fmt(request) << ")" + << " on fd " << fd << frg::endlog; + + SignalGuard sguard; + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + if (_IOC_TYPE(request) == 'd') { + return ioctl_drm(fd, request, arg, result, handle); + } + + auto handle_siocgif = + [&arg, &request, &result]( + void (*req_setup)(managarm::fs::IfreqRequest &req, struct ifreq *ifr), + int (*resp_parse)(managarm::fs::IfreqReply &resp, struct ifreq *ifr) + ) -> int { + if (!arg) + return EFAULT; + + auto ifr = reinterpret_cast(arg); + + managarm::posix::NetserverRequest token_req(getSysdepsAllocator()); + managarm::fs::IfreqRequest req(getSysdepsAllocator()); + req.set_command(request); + + req_setup(req, ifr); + + auto [offer, send_token_req, send_req, send_req_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(token_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_token_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_req_tail.error()); + HEL_CHECK(recv_resp.error()); + + auto preamble = bragi::read_preamble(recv_resp); + + frg::vector tailBuffer{getSysdepsAllocator()}; + tailBuffer.resize(preamble.tail_size()); + auto [recv_tail] = exchangeMsgsSync( + offer.descriptor().getHandle(), + helix_ng::recvBuffer(tailBuffer.data(), tailBuffer.size()) + ); + + HEL_CHECK(recv_tail.error()); + + auto resp = *bragi::parse_head_tail( + recv_resp, tailBuffer, getSysdepsAllocator() + ); + recv_resp.reset(); + + int ret = resp_parse(resp, ifr); + + if (result) + *result = 0; + return ret; + }; + + managarm::fs::IoctlRequest ioctl_req(getSysdepsAllocator()); + + switch (request) { + case FIONBIO: { + auto mode = reinterpret_cast(arg); + int flags = fcntl(fd, F_GETFL, 0); + if (*mode) { + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } else { + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + } + return 0; + } + case FIONREAD: { + auto argp = reinterpret_cast(arg); + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + if (!argp) + return EINVAL; + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(FIONREAD); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::NOT_CONNECTED) { + return ENOTCONN; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *argp = resp.fionread_count(); + + return 0; + } + } + case FIOCLEX: { + managarm::posix::IoctlFioclexRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + if (recvResp.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } + case TCGETS: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_attrs] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(param, sizeof(struct termios)) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_attrs.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + __ensure(recv_attrs.actualLength() == sizeof(struct termios)); + *result = resp.result(); + return 0; + } + case TCSETS: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, send_attrs, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(param, sizeof(struct termios)), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(send_attrs.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + if (result) + *result = resp.result(); + return 0; + } + case TIOCSCTTY: { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else if (resp.error() == managarm::fs::Errors::INSUFFICIENT_PERMISSIONS) { + return EPERM; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } + case TIOCGWINSZ: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return ENOTTY; + HEL_CHECK(send_req.error()); + if (recv_resp.error() == kHelErrDismissed) + return ENOTTY; + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + *result = resp.result(); + param->ws_col = resp.pts_width(); + param->ws_row = resp.pts_height(); + param->ws_xpixel = resp.pts_pixel_width(); + param->ws_ypixel = resp.pts_pixel_height(); + return 0; + } + case TIOCSWINSZ: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_pts_width(param->ws_col); + req.set_pts_height(param->ws_row); + req.set_pts_pixel_width(param->ws_xpixel); + req.set_pts_pixel_height(param->ws_ypixel); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case TIOCGPTN: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *param = resp.pts_index(); + if (result) + *result = resp.result(); + return 0; + } + case TIOCGPGRP: { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error()) + return EINVAL; + HEL_CHECK(send_req.error()); + if (imbue_creds.error()) { + infoLogger( + ) << "mlibc: TIOCGPGRP used on unexpected socket, returning EINVAL (FIXME)" + << frg::endlog; + return EINVAL; + } + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + *result = resp.result(); + *static_cast(arg) = resp.pid(); + return 0; + } + case TIOCSPGRP: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_pgid(*param); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::INSUFFICIENT_PERMISSIONS) { + return EPERM; + } else if (resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } + case TIOCGSID: { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + if (send_ioctl_req.error()) + return EINVAL; + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error()) + return EINVAL; + HEL_CHECK(send_req.error()); + if (imbue_creds.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::NOT_A_TERMINAL) { + return ENOTTY; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + *static_cast(arg) = resp.pid(); + return 0; + } + case CDROM_GET_CAPABILITY: { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + if (send_ioctl_req.error()) + return EINVAL; + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error()) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::NOT_A_TERMINAL) { + return ENOTTY; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } + case SIOCETHTOOL: + mlibc::infoLogger() << "\e[35mmlibc: SIOCETHTOOL is a stub" << frg::endlog; + *result = 0; + return ENOSYS; + case SIOCGSKNS: + mlibc::infoLogger() << "\e[35mmlibc: SIOCGSKNS is a stub" << frg::endlog; + *result = 0; + return ENOSYS; + case SG_IO: + mlibc::infoLogger() << "\e[35mmlibc: SG_IO is a stub" << frg::endlog; + *result = 0; + return ENOSYS; + } // end of switch() + + if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGVERSION)) { + *reinterpret_cast(arg) = EV_VERSION; + *result = 0; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGID)) { + memset(arg, 0, sizeof(struct input_id)); + auto param = reinterpret_cast(arg); + + managarm::fs::EvioGetIdRequest req(getSysdepsAllocator()); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + auto conversation = offer.descriptor(); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + auto resp = + *bragi::parse_head_only(recv_resp, getSysdepsAllocator()); + recv_resp.reset(); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->bustype = resp.bustype(); + param->vendor = resp.vendor(); + param->product = resp.product(); + param->version = resp.version(); + + *result = 0; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGNAME(0))) { + managarm::fs::EvioGetNameRequest req(getSysdepsAllocator()); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + auto conversation = offer.descriptor(); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + auto preamble = bragi::read_preamble(recv_resp); + __ensure(!preamble.error()); + + frg::vector tailBuffer{getSysdepsAllocator()}; + tailBuffer.resize(preamble.tail_size()); + auto [recv_tail] = exchangeMsgsSync( + conversation.getHandle(), helix_ng::recvBuffer(tailBuffer.data(), tailBuffer.size()) + ); + + HEL_CHECK(recv_tail.error()); + + auto resp = *bragi::parse_head_tail( + recv_resp, tailBuffer, getSysdepsAllocator() + ); + recv_resp.reset(); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + auto chunk = frg::min(_IOC_SIZE(request), resp.name().size() + 1); + memcpy(arg, resp.name().data(), chunk); + *result = chunk; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGRAB)) { + mlibc::infoLogger() << "mlibc: EVIOCGRAB is a no-op" << frg::endlog; + *result = 0; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGPHYS(0))) { + // Returns the sysfs path of the device. + const char *s = "input0"; + auto chunk = frg::min(_IOC_SIZE(request), strlen(s) + 1); + memcpy(arg, s, chunk); + *result = chunk; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGUNIQ(0))) { + // Returns a unique ID for the device. + const char *s = "0"; + auto chunk = frg::min(_IOC_SIZE(request), strlen(s) + 1); + memcpy(arg, s, chunk); + *result = chunk; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGPROP(0))) { + // Returns a bitmask of properties of the device. + auto size = _IOC_SIZE(request); + memset(arg, 0, size); + *result = size; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGKEY(0))) { + // Returns the current key state. + auto size = _IOC_SIZE(request); + memset(arg, 0, size); + *result = size; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGMTSLOTS(0))) { + // this ioctl is completely, utterly undocumented + // the _IOC_SIZE is a buffer size in bytes, which should be a multiple of int32_t + // bytes should be at least sizeof(int32_t) large. + // the argument (the pointer to the buffer) is an array of int32_t + // the first entry is the number of values supplied, followed by the values + // this would have been worthwhile to document ffs + + // the length argument is the buffer size, in bytes + auto bytes = _IOC_SIZE(request); + // the length argument should be a multiple of int32_t + if (!bytes || bytes % sizeof(int32_t)) + return EINVAL; + + // the number of entries the buffer can hold + auto entries = (bytes / sizeof(int32_t)) - 1; + + managarm::fs::EvioGetMultitouchSlotsRequest req(getSysdepsAllocator()); + req.set_code(*reinterpret_cast(arg)); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + auto conversation = offer.descriptor(); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + auto preamble = bragi::read_preamble(recv_resp); + __ensure(!preamble.error()); + + frg::vector tailBuffer{getSysdepsAllocator()}; + tailBuffer.resize(preamble.tail_size()); + auto [recv_tail] = exchangeMsgsSync( + conversation.getHandle(), helix_ng::recvBuffer(tailBuffer.data(), tailBuffer.size()) + ); + + HEL_CHECK(recv_tail.error()); + + auto resp = *bragi::parse_head_tail( + recv_resp, tailBuffer, getSysdepsAllocator() + ); + recv_resp.reset(); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + auto param = reinterpret_cast(arg); + + for (size_t i = 0; i < resp.values_size() && i < entries; i++) { + param[i + 1] = resp.values(i); + } + + param[0] = resp.values_size(); + + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGLED(0))) { + // Returns the current LED state. + auto size = _IOC_SIZE(request); + memset(arg, 0, size); + *result = size; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGSW(0))) { + auto size = _IOC_SIZE(request); + memset(arg, 0, size); + *result = size; + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) >= _IOC_NR(EVIOCGBIT(0, 0)) + && _IOC_NR(request) <= _IOC_NR(EVIOCGBIT(EV_MAX, 0))) { + // Returns a bitmask of capabilities of the device. + // If type is zero, return a mask of supported types. + // As EV_SYN is zero, this implies that it is impossible + // to get the mask of supported synthetic events. + auto type = _IOC_NR(request) - _IOC_NR(EVIOCGBIT(0, 0)); + if (!type) { + // TODO: Check with the Linux ABI if we have to do this. + memset(arg, 0, _IOC_SIZE(request)); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(EVIOCGBIT(0, 0)); + req.set_size(_IOC_SIZE(request)); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_data] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(arg, _IOC_SIZE(request)) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = recv_data.actualLength(); + return 0; + } else { + // TODO: Check with the Linux ABI if we have to do this. + memset(arg, 0, _IOC_SIZE(request)); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(EVIOCGBIT(1, 0)); + req.set_input_type(type); + req.set_size(_IOC_SIZE(request)); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_data] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(arg, _IOC_SIZE(request)) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = recv_data.actualLength(); + return 0; + } + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCSCLOCKID)) { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_input_clock(*param); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } else if (_IOC_TYPE(request) == 'E' && _IOC_NR(request) >= _IOC_NR(EVIOCGABS(0)) + && _IOC_NR(request) <= _IOC_NR(EVIOCGABS(ABS_MAX))) { + auto param = reinterpret_cast(arg); + + auto type = _IOC_NR(request) - _IOC_NR(EVIOCGABS(0)); + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(EVIOCGABS(0)); + req.set_input_type(type); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if (send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->value = resp.input_value(); + param->minimum = resp.input_min(); + param->maximum = resp.input_max(); + param->fuzz = resp.input_fuzz(); + param->flat = resp.input_flat(); + param->resolution = resp.input_resolution(); + + *result = resp.result(); + return 0; + } else if (request == KDSETMODE) { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: KD_SETMODE(" << frg::hex_fmt(param) << ") is a no-op" + << frg::endlog; + + *result = 0; + return 0; + } else if (request == KDGETMODE) { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: KD_GETMODE is a no-op" << frg::endlog; + *param = 0; + + *result = 0; + return 0; + } else if (request == KDSKBMODE) { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: KD_SKBMODE(" << frg::hex_fmt(param) << ") is a no-op" + << frg::endlog; + + *result = 0; + return 0; + } else if (request == VT_SETMODE) { + // auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: VT_SETMODE is a no-op" << frg::endlog; + + *result = 0; + return 0; + } else if (request == VT_GETSTATE) { + auto param = reinterpret_cast(arg); + + param->v_active = 0; + param->v_signal = 0; + param->v_state = 0; + + mlibc::infoLogger() << "\e[35mmlibc: VT_GETSTATE is a no-op" << frg::endlog; + + *result = 0; + return 0; + } else if (request == VT_ACTIVATE || request == VT_WAITACTIVE) { + mlibc::infoLogger() << "\e[35mmlibc: VT_ACTIVATE/VT_WAITACTIVE are no-ops" << frg::endlog; + *result = 0; + return 0; + } else if (request == TIOCSPTLCK) { + mlibc::infoLogger() << "\e[35mmlibc: TIOCSPTLCK is a no-op" << frg::endlog; + if (result) + *result = 0; + return 0; + } else if (request == SIOCGIFNAME) { + return handle_siocgif( + [](auto req, auto ifr) { req.set_index(ifr->ifr_ifindex); }, + [](auto resp, auto ifr) { + if (resp.error() != managarm::fs::Errors::SUCCESS) + return EINVAL; + strncpy(ifr->ifr_name, resp.name().data(), IFNAMSIZ); + return 0; + } + ); + } else if (request == SIOCGIFCONF) { + if (!arg) + return EFAULT; + + auto ifc = reinterpret_cast(arg); + + managarm::posix::NetserverRequest token_req(getSysdepsAllocator()); + managarm::fs::IfreqRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_token_req, send_req, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(token_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + auto conversation = offer.descriptor(); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_token_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + auto preamble = bragi::read_preamble(recv_resp); + __ensure(!preamble.error()); + + frg::vector tailBuffer{getSysdepsAllocator()}; + tailBuffer.resize(preamble.tail_size()); + auto [recv_tail] = exchangeMsgsSync( + conversation.getHandle(), helix_ng::recvBuffer(tailBuffer.data(), tailBuffer.size()) + ); + + HEL_CHECK(recv_tail.error()); + + auto resp = *bragi::parse_head_tail( + recv_resp, tailBuffer, getSysdepsAllocator() + ); + recv_resp.reset(); + + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + if (ifc->ifc_buf == nullptr) { + ifc->ifc_len = int(resp.ifconf_size() * sizeof(struct ifreq)); + return 0; + } + + ifc->ifc_len = frg::min(int(resp.ifconf_size() * sizeof(struct ifreq)), ifc->ifc_len); + + for (size_t i = 0; i < frg::min(resp.ifconf_size(), ifc->ifc_len / sizeof(struct ifreq)); + ++i) { + auto &conf = resp.ifconf()[i]; + + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(conf.ip4()); + + ifreq *req = &ifc->ifc_req[i]; + strncpy(req->ifr_name, conf.name().data(), IFNAMSIZ); + memcpy(&req->ifr_addr, &addr, sizeof(addr)); + } + + if (result) + *result = 0; + return 0; + } else if (request == SIOCGIFNETMASK) { + return handle_siocgif( + [](auto req, auto ifr) { + req.set_name(frg::string{ifr->ifr_name, getSysdepsAllocator()}); + }, + [](auto resp, auto ifr) { + if (resp.error() != managarm::fs::Errors::SUCCESS) + return EINVAL; + + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_addr = {htonl(resp.ip4_netmask())}; + memcpy(&ifr->ifr_netmask, &addr, sizeof(addr)); + + return 0; + } + ); + } else if (request == SIOCGIFINDEX) { + return handle_siocgif( + [](auto req, auto ifr) { + req.set_name(frg::string{ifr->ifr_name, getSysdepsAllocator()}); + }, + [](auto resp, auto ifr) { + if (resp.error() != managarm::fs::Errors::SUCCESS) + return EINVAL; + ifr->ifr_ifindex = resp.index(); + return 0; + } + ); + } else if (request == SIOCGIFFLAGS) { + return handle_siocgif( + [](auto req, auto ifr) { + req.set_name(frg::string{ifr->ifr_name, getSysdepsAllocator()}); + }, + [](auto resp, auto ifr) { + if (resp.error() != managarm::fs::Errors::SUCCESS) + return EINVAL; + ifr->ifr_flags = resp.flags(); + return 0; + } + ); + } else if (request == SIOCGIFADDR) { + return handle_siocgif( + [](auto req, auto ifr) { + req.set_name(frg::string{ifr->ifr_name, getSysdepsAllocator()}); + }, + [](auto resp, auto ifr) { + if (resp.error() != managarm::fs::Errors::SUCCESS) + return EINVAL; + + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_addr = {htonl(resp.ip4_addr())}; + memcpy(&ifr->ifr_addr, &addr, sizeof(addr)); + + return 0; + } + ); + } else if (request == SIOCGIFMTU) { + return handle_siocgif( + [](auto req, auto ifr) { + req.set_name(frg::string{ifr->ifr_name, getSysdepsAllocator()}); + }, + [](auto resp, auto ifr) { + if (resp.error() != managarm::fs::Errors::SUCCESS) + return EINVAL; + + ifr->ifr_mtu = resp.mtu(); + + return 0; + } + ); + } else if (request == SIOCGIFBRDADDR) { + return handle_siocgif( + [](auto req, auto ifr) { + req.set_name(frg::string{ifr->ifr_name, getSysdepsAllocator()}); + }, + [](auto resp, auto ifr) { + if (resp.error() != managarm::fs::Errors::SUCCESS) + return EINVAL; + + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_addr = {htonl(resp.ip4_broadcast_addr())}; + memcpy(&ifr->ifr_broadaddr, &addr, sizeof(addr)); + + return 0; + } + ); + } else if (request == SIOCGIFHWADDR) { + return handle_siocgif( + [](auto req, auto ifr) { + req.set_name(frg::string{ifr->ifr_name, getSysdepsAllocator()}); + }, + [](auto resp, auto ifr) { + if (resp.error() != managarm::fs::Errors::SUCCESS) + return EINVAL; + + sockaddr addr{}; + addr.sa_family = ARPHRD_ETHER; + memcpy(addr.sa_data, resp.mac().data(), 6); + memcpy(&ifr->ifr_hwaddr, &addr, sizeof(addr)); + + return 0; + } + ); + } else if (request == IOCTL_WDM_MAX_COMMAND) { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + *param = resp.size(); + return 0; + } else if (request == NVME_IOCTL_ID) { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } else if (request == NVME_IOCTL_ADMIN_CMD) { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, send_buffer, send_data, recv_resp, recv_data] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(param, sizeof(*param)), + helix_ng::sendBuffer(reinterpret_cast(param->addr), param->data_len), + helix_ng::recvInline(), + helix_ng::recvBuffer(reinterpret_cast(param->addr), param->data_len) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_buffer.error()); + HEL_CHECK(send_data.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + param->result = resp.status(); + return 0; + } else if (request == TFD_IOC_SET_TICKS) { + if (!arg) + return EFAULT; + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_ticks(*param); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + return 0; + } else if (request == FICLONE || request == FICLONERANGE) { + mlibc::infoLogger() << "\e[35mmlibc: FICLONE/FICLONERANGE are no-ops" << frg::endlog; + *result = -1; + return EOPNOTSUPP; + } else if (request == FS_IOC_GETFLAGS) { + mlibc::infoLogger() << "\e[35mmlibc: FS_IOC_GETFLAGS is a no-op" << frg::endlog; + *result = 0; + return ENOSYS; + } else if (request == FS_IOC_FIEMAP) { + mlibc::infoLogger() << "\e[35mmlibc: FS_IOC_FIEMAP is a no-op" << frg::endlog; + *result = 0; + return ENOSYS; + } + + mlibc::infoLogger() << "mlibc: Unexpected ioctl with" + << " type: 0x" << frg::hex_fmt(_IOC_TYPE(request)) << ", number: 0x" + << frg::hex_fmt(_IOC_NR(request)) + << " (raw request: " << frg::hex_fmt(request) << ")" << frg::endlog; + + return ENOSYS; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/memory.cpp b/user/include/mlibc/sysdeps/managarm/generic/memory.cpp new file mode 100644 index 0000000..5695f0d --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/memory.cpp @@ -0,0 +1,29 @@ + +#include + +#include +#include +#include +#include + +#include +#include + +namespace mlibc { + +int sys_anon_allocate(size_t size, void **pointer) { + // This implementation is inherently signal-safe. + __ensure(!(size & 0xFFF)); + HelWord out; + HEL_CHECK(helSyscall1_1(kHelCallSuper + posix::superAnonAllocate, size, &out)); + *pointer = reinterpret_cast(out); + return 0; +} + +int sys_anon_free(void *pointer, size_t size) { + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall2(kHelCallSuper + posix::superAnonDeallocate, (HelWord)pointer, size)); + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/mount.cpp b/user/include/mlibc/sysdeps/managarm/generic/mount.cpp new file mode 100644 index 0000000..0a23d7d --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/mount.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +int +sys_mount(const char *source, const char *target, const char *fstype, unsigned long, const void *) { + SignalGuard sguard; + + managarm::posix::MountRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), source ? source : "")); + req.set_target_path(frg::string(getSysdepsAllocator(), target ? target : "")); + req.set_fs_type(frg::string(getSysdepsAllocator(), fstype ? fstype : "")); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + auto resp = + *bragi::parse_head_only(recv_resp, getSysdepsAllocator()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/net.cpp b/user/include/mlibc/sysdeps/managarm/generic/net.cpp new file mode 100644 index 0000000..4fe3fd8 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/net.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include + +#include "generic-helpers/netlink.hpp" + +namespace mlibc { + +int sys_if_indextoname(unsigned int index, char *name) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if (r) + return r; + + struct ifreq ifr; + ifr.ifr_ifindex = index; + + int res = 0; + int ret = sys_ioctl(fd, SIOCGIFNAME, &ifr, &res); + close(fd); + + if (ret) { + if (ret == ENODEV) + return ENXIO; + return ret; + } + + strncpy(name, ifr.ifr_name, IF_NAMESIZE); + + return 0; +} + +int sys_if_nametoindex(const char *name, unsigned int *ret) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if (r) + return r; + + struct ifreq ifr; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + + int res = 0; + r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, &res); + close(fd); + + if (r) + return r; + + *ret = ifr.ifr_ifindex; + + return 0; +} + +int sys_getifaddrs(struct ifaddrs **out) { + NetlinkHelper nl; + *out = nullptr; + + bool link_ret = nl.send_request(RTM_GETLINK) && nl.recv(&getifaddrs_callback, out); + __ensure(link_ret); + bool addr_ret = nl.send_request(RTM_GETADDR) && nl.recv(&getifaddrs_callback, out); + __ensure(addr_ret); + + return 0; +} + +#if !defined(MLIBC_BUILDING_RTLD) +int sys_inet_configured(bool *ipv4, bool *ipv6) { + struct context { + bool *ipv4; + bool *ipv6; + } context = {.ipv4 = ipv4, .ipv6 = ipv6}; + + NetlinkHelper nl; + if (!nl.send_request(RTM_GETADDR)) { + *ipv4 = false; + *ipv6 = false; + return 0; + } + + auto ret = nl.recv( + [](void *data, const nlmsghdr *hdr) { + if (hdr->nlmsg_type == RTM_NEWADDR || hdr->nlmsg_len >= sizeof(struct ifaddrmsg)) { + const struct ifaddrmsg *ifaddr = + reinterpret_cast(NLMSG_DATA(hdr)); + struct context *ctx = reinterpret_cast(data); + + char name[IF_NAMESIZE]; + auto interfaceNameResult = sys_if_indextoname(ifaddr->ifa_index, name); + + if (interfaceNameResult || !strncmp(name, "lo", IF_NAMESIZE)) + return; + + if (ifaddr->ifa_family == AF_INET) + *ctx->ipv4 = true; + else if (ifaddr->ifa_family == AF_INET6) + *ctx->ipv6 = true; + } + }, + &context + ); + + if (!ret) { + *ipv4 = false; + *ipv6 = false; + return 0; + } + + return 0; +} +#endif // !defined(MLIBC_BUILDING_RTLD) + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/sched.cpp b/user/include/mlibc/sysdeps/managarm/generic/sched.cpp new file mode 100644 index 0000000..0e4ca5e --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/sched.cpp @@ -0,0 +1,106 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace mlibc { + +int sys_getscheduler(pid_t, int *policy) { + *policy = SCHED_OTHER; + return 0; +} + +int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { + return sys_getthreadaffinity(pid, cpusetsize, mask); +} + +int sys_getthreadaffinity(pid_t tid, size_t cpusetsize, cpu_set_t *mask) { + SignalGuard sguard; + + managarm::posix::GetAffinityRequest req(getSysdepsAllocator()); + + req.set_pid(tid); + req.set_size(cpusetsize); + + auto [offer, send_head, recv_resp, recv_data] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(mask, cpusetsize) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } else if (resp.error() != managarm::posix::Errors::SUCCESS) { + mlibc::infoLogger() << "mlibc: got unexpected error from posix in sys_getaffinity!" + << frg::endlog; + return EIEIO; + } + HEL_CHECK(recv_data.error()); + + return 0; +} + +int sys_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask) { + return sys_setthreadaffinity(pid, cpusetsize, mask); +} + +int sys_setthreadaffinity(pid_t tid, size_t cpusetsize, const cpu_set_t *mask) { + SignalGuard sguard; + + frg::vector affinity_mask(getSysdepsAllocator()); + affinity_mask.resize(cpusetsize); + memcpy(affinity_mask.data(), mask, cpusetsize); + managarm::posix::SetAffinityRequest req(getSysdepsAllocator()); + + req.set_pid(tid); + req.set_mask(affinity_mask); + + auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } else if (resp.error() != managarm::posix::Errors::SUCCESS) { + mlibc::infoLogger() << "mlibc: got unexpected error from posix in sys_getaffinity!" + << frg::endlog; + return EIEIO; + } + + return 0; +} + +int sys_getcpu(int *cpu) { + HEL_CHECK(helGetCurrentCpu(cpu)); + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/signals.cpp b/user/include/mlibc/sysdeps/managarm/generic/signals.cpp new file mode 100644 index 0000000..594fb38 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/signals.cpp @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +extern "C" void __mlibc_signal_restore(); + +namespace mlibc { + +int sys_sigprocmask(int how, const sigset_t *set, sigset_t *retrieve) { + // This implementation is inherently signal-safe. + uint64_t former, unused; + if (set) { + HEL_CHECK(helSyscall2_2( + kHelObserveSuperCall + posix::superSigMask, + how, + *reinterpret_cast(set), + &former, + &unused + )); + } else { + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, 0, 0, &former, &unused) + ); + } + if (retrieve) + *reinterpret_cast(retrieve) = former; + return 0; +} + +int sys_sigaction( + int number, const struct sigaction *__restrict action, struct sigaction *__restrict saved_action +) { + SignalGuard sguard; + + // TODO: Respect restorer. __ensure(!(action->sa_flags & SA_RESTORER)); + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::SIG_ACTION); + req.set_sig_number(number); + if (action) { + req.set_mode(1); + req.set_flags(action->sa_flags); + req.set_sig_mask(*reinterpret_cast(&action->sa_mask)); + if (action->sa_flags & SA_SIGINFO) { + req.set_sig_handler(reinterpret_cast(action->sa_sigaction)); + } else { + req.set_sig_handler(reinterpret_cast(action->sa_handler)); + } + req.set_sig_restorer(reinterpret_cast(&__mlibc_signal_restore)); + } else { + req.set_mode(0); + } + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::posix::Errors::ILLEGAL_REQUEST) { + // This is only returned for servers, not for normal userspace. + return ENOSYS; + } else if (resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + + if (saved_action) { + saved_action->sa_flags = resp.flags(); + *reinterpret_cast(&saved_action->sa_mask) = resp.sig_mask(); + if (resp.flags() & SA_SIGINFO) { + saved_action->sa_sigaction = + reinterpret_cast(resp.sig_handler()); + } else { + saved_action->sa_handler = reinterpret_cast(resp.sig_handler()); + } + // TODO: saved_action->sa_restorer = resp.sig_restorer; + } + return 0; +} + +int sys_kill(int pid, int number) { + // This implementation is inherently signal-safe. + HelWord out; + HEL_CHECK(helSyscall2_1(kHelObserveSuperCall + posix::superSigKill, pid, number, &out)); + return out; +} + +int sys_tgkill(int, int tid, int number) { return sys_kill(tid, number); } + +int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + HelWord out; + + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall2_1( + kHelObserveSuperCall + posix::superSigAltStack, + reinterpret_cast(ss), + reinterpret_cast(oss), + &out + )); + + return out; +} + +int sys_sigsuspend(const sigset_t *set) { + // SignalGuard sguard; + uint64_t former, seq, unused; + + HEL_CHECK(helSyscall2_2( + kHelObserveSuperCall + posix::superSigMask, + SIG_SETMASK, + *reinterpret_cast(set), + &former, + &seq + )); + HEL_CHECK(helSyscall1(kHelObserveSuperCall + posix::superSigSuspend, seq)); + HEL_CHECK(helSyscall2_2( + kHelObserveSuperCall + posix::superSigMask, SIG_SETMASK, former, &unused, &unused + )); + + return EINTR; +} + +int sys_sigpending(sigset_t *set) { + uint64_t pendingMask; + + HEL_CHECK(helSyscall0_1(kHelObserveSuperCall + posix::superSigGetPending, &pendingMask)); + *reinterpret_cast(set) = pendingMask; + + return 0; +} + +int sys_pause() { + HelWord set = 0; + uint64_t former, seq; + + // no-op to obtain a seqnum + HEL_CHECK( + helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, SIG_BLOCK, set, &former, &seq) + ); + HEL_CHECK(helSyscall1(kHelObserveSuperCall + posix::superSigSuspend, seq)); + + return EINTR; +} + +int sys_sigtimedwait( + const sigset_t *__restrict set, + siginfo_t *__restrict info, + const struct timespec *__restrict timeout, + int *out_signal +) { + uint64_t nanos = timeout ? (timeout->tv_nsec + timeout->tv_sec * 1'000'000'000) : UINT64_MAX; + HelWord status; + HelWord signal; + + HEL_CHECK(helSyscall3_2( + kHelObserveSuperCall + posix::superSigTimedWait, + *reinterpret_cast(set), + nanos, + reinterpret_cast(info), + &status, + &signal + )); + + if (status) + return status; + + *out_signal = signal; + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/socket.cpp b/user/include/mlibc/sysdeps/managarm/generic/socket.cpp new file mode 100644 index 0000000..6eadf81 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/socket.cpp @@ -0,0 +1,625 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if (!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} // namespace + +namespace mlibc { + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + SignalGuard sguard; + + managarm::posix::AcceptRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) { + return resp.error() | toErrno; + } else { + *newfd = resp.fd(); + } + + if (addr_ptr && addr_length) { + if (int e = mlibc::sys_peername(*newfd, addr_ptr, *addr_length, addr_length); e) { + errno = e; + return -1; + } + } + + if (flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if (flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + SignalGuard sguard; + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_BIND); + + auto [offer, send_req, send_creds, send_buf, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(addr_ptr, addr_length), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_creds.error()); + HEL_CHECK(send_buf.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + return resp.error() | toErrno; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_CONNECT); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, imbue_creds, send_addr, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(const_cast(addr_ptr), addr_length), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_addr.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + return resp.error() | toErrno; +} + +int sys_sockname( + int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length +) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_SOCKNAME); + req.set_fd(fd); + req.set_size(max_addr_length); + + auto [offer, send_req, recv_resp, recv_addr] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(addr_ptr, max_addr_length) + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::fs::Errors::SUCCESS) { + HEL_CHECK(recv_addr.error()); + *actual_length = resp.file_size(); + return 0; + } + return resp.error() | toErrno; +} + +int sys_peername( + int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length +) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_PEERNAME); + req.set_fd(fd); + req.set_size(max_addr_length); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, sendReq, recvResp, recvData] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline(), + helix_ng::recvBuffer(addr_ptr, max_addr_length) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + if (recvResp.error() == kHelErrDismissed) + return ENOTSOCK; + HEL_CHECK(recvResp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + + if (resp.error() == managarm::fs::Errors::SUCCESS) { + HEL_CHECK(recvData.error()); + *actual_length = resp.file_size(); + return 0; + } + + return resp.error() | toErrno; +} + +namespace { + +std::array, 6> getsockopt_passthrough = {{ + {SOL_SOCKET, SO_PROTOCOL}, + {SOL_SOCKET, SO_PEERCRED}, + {SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS}, + {SOL_SOCKET, SO_TYPE}, + {SOL_SOCKET, SO_ACCEPTCONN}, + {SOL_SOCKET, SO_PEERPIDFD}, +}}; + +} // namespace + +int +sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { + SignalGuard sguard; + + if (layer == SOL_SOCKET && number == SO_SNDBUF) { + // This is really only relevant on Linux + *(int *)buffer = 4096; + return 0; + } else if (layer == SOL_SOCKET && number == SO_RCVBUF) { + // This is really only relevant on Linux + *(int *)buffer = 4096; + return 0; + } else if (layer == SOL_SOCKET && number == SO_ERROR) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is " + "unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_KEEPALIVE is " + "unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_LINGER) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_LINGER is " + "unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_PEERSEC) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_PEERSEC is " + "unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_PEERGROUPS) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_PEERGROUPS " + "is unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == IPPROTO_TCP && number == TCP_MAXSEG) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with IPPROTO_TCP and TCP_MAXSEG is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == IPPROTO_TCP && number == TCP_CONGESTION) { + mlibc::infoLogger( + ) << "\e[31mmlibc: getsockopt() call with IPPROTO_TCP and TCP_CONGESTION is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (std::find( + getsockopt_passthrough.begin(), + getsockopt_passthrough.end(), + std::pair{layer, number} + ) + != getsockopt_passthrough.end()) { + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::GetSockOpt req(getSysdepsAllocator()); + req.set_layer(layer); + req.set_number(number); + req.set_optlen(size ? *size : 0); + + auto [offer, send_req, send_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::want_lane, + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + *size = resp.size(); + + auto [recv_buffer] = + exchangeMsgsSync(offer.descriptor().getHandle(), helix_ng::recvBuffer(buffer, *size)); + HEL_CHECK(recv_buffer.error()); + + return resp.error() | toErrno; + } else { + mlibc::infoLogger() << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer + << " number: " << number << "\e[39m" << frg::endlog; + return EINVAL; + } +} + +namespace { + +std::array, 6> setsockopt_readonly = {{ + {SOL_SOCKET, SO_ACCEPTCONN}, + {SOL_SOCKET, SO_DOMAIN}, + {SOL_SOCKET, SO_ERROR}, + {SOL_SOCKET, SO_PROTOCOL}, + {SOL_SOCKET, SO_TYPE}, + {SOL_IP, SO_PEERSEC}, +}}; + +std::array, 12> setsockopt_passthrough = {{ + {SOL_PACKET, PACKET_AUXDATA}, + {SOL_SOCKET, SO_LOCK_FILTER}, + {SOL_SOCKET, SO_BINDTODEVICE}, + {SOL_SOCKET, SO_TIMESTAMP}, + {SOL_SOCKET, SO_PASSCRED}, + {SOL_SOCKET, SO_RCVTIMEO}, + {SOL_SOCKET, SO_SNDTIMEO}, + {SOL_IP, IP_PKTINFO}, + {SOL_IP, IP_RECVTTL}, + {SOL_IP, IP_RETOPTS}, + {SOL_NETLINK, NETLINK_ADD_MEMBERSHIP}, + {SOL_NETLINK, NETLINK_PKTINFO}, +}}; + +std::array, 2> setsockopt_passthrough_noopt = {{ + {SOL_SOCKET, SO_DETACH_FILTER}, +}}; + +} // namespace + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + SignalGuard sguard; + + if (std::find( + setsockopt_passthrough.begin(), + setsockopt_passthrough.end(), + std::pair{layer, number} + ) + != setsockopt_passthrough.end()) { + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::SetSockOpt req(getSysdepsAllocator()); + req.set_layer(layer); + req.set_number(number); + req.set_optlen(size); + + auto [offer, send_req, send_buf, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(buffer, size), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_buf.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + return resp.error() | toErrno; + } else if (std::find( + setsockopt_passthrough_noopt.begin(), + setsockopt_passthrough_noopt.end(), + std::pair{layer, number} + ) + != setsockopt_passthrough_noopt.end()) { + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::SetSockOpt req(getSysdepsAllocator()); + req.set_layer(layer); + req.set_number(number); + req.set_optlen(0); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + return resp.error() | toErrno; + } else if (std::find( + setsockopt_readonly.begin(), + setsockopt_readonly.end(), + std::pair{layer, number} + ) + != setsockopt_readonly.end()) { + // this is purely read-only + return ENOPROTOOPT; + } else if (layer == SOL_SOCKET && number == SO_ATTACH_FILTER) { + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + if (size != sizeof(sock_fprog)) + return EINVAL; + + auto fprog = reinterpret_cast(buffer); + + managarm::fs::SetSockOpt req(getSysdepsAllocator()); + req.set_layer(layer); + req.set_number(number); + req.set_optlen(fprog->len * sizeof(*fprog->filter)); + + auto [offer, send_req, send_buf, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(fprog->filter, req.optlen()), + helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_buf.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + return resp.error() | toErrno; + } else if (layer == SOL_SOCKET && number == SO_RCVBUFFORCE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not implemented" + " correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_SNDBUF) { + // This is really only relevant on Linux + return 0; + } else if (layer == SOL_SOCKET && number == SO_SNDBUFFORCE) { + // This is really only relevant on Linux + return 0; + } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_KEEPALIVE is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_REUSEADDR) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEADDR is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_REUSEPORT) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEPORT is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_RCVBUF) { + mlibc::infoLogger( + ) << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_RCVBUF is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == IPPROTO_TCP && number == TCP_NODELAY) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_NODELAY is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == IPPROTO_TCP && number == TCP_MAXSEG) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_NODELAY is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == IPPROTO_TCP && number == TCP_KEEPIDLE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPIDLE " + "is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_NETLINK && number == NETLINK_BROADCAST_ERROR) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and " + "NETLINK_BROADCAST_ERROR is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_NETLINK && number == NETLINK_EXT_ACK) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and " + "NETLINK_EXT_ACK is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_NETLINK && number == NETLINK_GET_STRICT_CHK) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and " + "NETLINK_EXT_ACK is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == IPPROTO_TCP && number == TCP_KEEPINTVL) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPINTVL " + "is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == IPPROTO_TCP && number == TCP_KEEPCNT) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPCNT is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_OOBINLINE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_OOBINLINE is " + "unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_PRIORITY) { + mlibc::infoLogger( + ) << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_PRIORITY is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_IP && number == IP_RECVERR) { + mlibc::infoLogger( + ) << "\e[31mmlibc: setsockopt() call with SOL_IP and IP_RECVERR is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_PASSSEC) { + mlibc::infoLogger( + ) << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_PASSSEC is unimplemented\e[39m" + << frg::endlog; + return ENOSYS; + } else { + mlibc::infoLogger() << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer + << " number: " << number << "\e[39m" << frg::endlog; + return EINVAL; + } +} + +int sys_listen(int fd, int) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_LISTEN); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer(helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + return resp.error() | toErrno; +} + +int sys_shutdown(int fd, int how) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::ShutdownSocket req(getSysdepsAllocator()); + req.set_how(how); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::fs::Errors::SUCCESS) + return resp.error() | toErrno; + + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/generic/time.cpp b/user/include/mlibc/sysdeps/managarm/generic/time.cpp new file mode 100644 index 0000000..9b0a19b --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/generic/time.cpp @@ -0,0 +1,418 @@ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "posix.frigg_bragi.hpp" + +struct TrackerPage { + uint64_t seqlock; + int32_t state; + int32_t padding; + int64_t refClock; + int64_t baseRealtime; +}; + +extern thread_local TrackerPage *__mlibc_clk_tracker_page; + +namespace mlibc { + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + // This implementation is inherently signal-safe. + if (clock == CLOCK_MONOTONIC || clock == CLOCK_MONOTONIC_RAW + || clock == CLOCK_MONOTONIC_COARSE) { + uint64_t tick; + HEL_CHECK(helGetClock(&tick)); + *secs = tick / 1000000000; + *nanos = tick % 1000000000; + } else if (clock == CLOCK_REALTIME) { + cacheFileTable(); + + // Start the seqlock read. + auto seqlock = __atomic_load_n(&__mlibc_clk_tracker_page->seqlock, __ATOMIC_ACQUIRE); + __ensure(!(seqlock & 1)); + + // Perform the actual loads. + auto ref = __atomic_load_n(&__mlibc_clk_tracker_page->refClock, __ATOMIC_RELAXED); + auto base = __atomic_load_n(&__mlibc_clk_tracker_page->baseRealtime, __ATOMIC_RELAXED); + + // Finish the seqlock read. + __atomic_thread_fence(__ATOMIC_ACQUIRE); + __ensure(__atomic_load_n(&__mlibc_clk_tracker_page->seqlock, __ATOMIC_RELAXED) == seqlock); + + // Calculate the current time. + uint64_t tick; + HEL_CHECK(helGetClock(&tick)); + __ensure( + tick >= (uint64_t)__mlibc_clk_tracker_page->refClock + ); // TODO: Respect the seqlock! + tick -= ref; + tick += base; + *secs = tick / 1000000000; + *nanos = tick % 1000000000; + } else if (clock == CLOCK_PROCESS_CPUTIME_ID) { + mlibc::infoLogger() << "\e[31mmlibc: clock_gettime does not support the CPU time clocks" + "\e[39m" + << frg::endlog; + *secs = 0; + *nanos = 0; + } else if (clock == CLOCK_BOOTTIME) { + uint64_t tick; + HEL_CHECK(helGetClock(&tick)); + + *secs = tick / 1000000000; + *nanos = tick % 1000000000; + } else { + mlibc::panicLogger() << "mlibc: Unexpected clock " << clock << frg::endlog; + } + return 0; +} + +int sys_clock_getres(int clock, time_t *secs, long *nanos) { + (void)clock; + (void)secs; + (void)nanos; + mlibc::infoLogger() << "mlibc: clock_getres is a stub" << frg::endlog; + return 0; +} + +int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + SignalGuard sguard; + + if (which != ITIMER_REAL) { + mlibc::infoLogger() << "mlibc: setitimers other than ITIMER_REAL are unsupported" + << frg::endlog; + return EINVAL; + } + + managarm::posix::SetIntervalTimerRequest req(getSysdepsAllocator()); + req.set_which(which); + req.set_value_sec(new_value->it_value.tv_sec); + req.set_value_usec(new_value->it_value.tv_usec); + req.set_interval_sec(new_value->it_interval.tv_sec); + req.set_interval_usec(new_value->it_interval.tv_usec); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SetIntervalTimerResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + + if (old_value) { + old_value->it_value.tv_sec = resp.value_sec(); + old_value->it_value.tv_usec = resp.value_usec(); + old_value->it_interval.tv_sec = resp.interval_sec(); + old_value->it_interval.tv_usec = resp.interval_usec(); + } + + return 0; +} + +namespace { + +bool timerThreadInit = false; + +struct PosixTimerContext { + int setupSem = 0; + int workerSem = 0; + sigevent *sigev; +}; + +struct TimerHandle { + uint64_t id; + int notify_type; + pthread_t thread = {}; +}; + +void timer_handle(int, siginfo_t *, void *) {} + +void *timer_setup(void *arg) { + auto ctx = reinterpret_cast(arg); + + sigset_t set = {}; + sigaddset(&set, SIGTIMER); + + // wait for parent setup to be complete + while (__atomic_load_n(&ctx->setupSem, __ATOMIC_RELAXED) == 0) + ; + pthread_testcancel(); + + // copy out the function and argument, as the lifetime of the context ends with + // incrementing workerSem + auto notify = ctx->sigev->sigev_notify_function; + union sigval val = ctx->sigev->sigev_value; + + // notify the parent that the context can be dropped + __atomic_store_n(&ctx->workerSem, 1, __ATOMIC_RELEASE); + + siginfo_t si; + int signo; + + while (true) { + pthread_testcancel(); + while (sys_sigtimedwait(&set, &si, nullptr, &signo)) + ; + pthread_testcancel(); + if (si.si_code == SI_TIMER && signo == SIGTIMER) + notify(val); + } + + return nullptr; +} + +} // namespace + +int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res) { + SignalGuard sguard; + + if (!res) + return EINVAL; + + managarm::posix::TimerCreateRequest req(getSysdepsAllocator()); + req.set_clockid(clk); + + // TODO: pass sigev_value + if (!evp) { + req.set_sigev_signo(SIGALRM); + req.set_sigev_tid(sys_gettid()); + } else if (evp->sigev_notify == SIGEV_NONE) { + req.set_sigev_signo(0); + req.set_sigev_tid(0); + } else if (evp->sigev_notify == SIGEV_SIGNAL) { + req.set_sigev_signo(evp->sigev_signo); + req.set_sigev_tid(sys_gettid()); + } else if (evp->sigev_notify == SIGEV_THREAD_ID) { + req.set_sigev_signo(evp->sigev_signo); + req.set_sigev_tid(evp->sigev_notify_thread_id); + } else if (evp->sigev_notify == SIGEV_THREAD) { + if (!timerThreadInit) { + struct sigaction sa{}; + sa.sa_flags = SA_SIGINFO | SA_RESTART; + sa.sa_sigaction = timer_handle; + sys_sigaction(SIGTIMER, &sa, nullptr); + timerThreadInit = true; + } + + pthread_attr_t attr; + if (evp->sigev_notify_attributes) + attr = *evp->sigev_notify_attributes; + else + pthread_attr_init(&attr); + + int ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (ret) + return ret; + + PosixTimerContext context{}; + context.sigev = evp; + + // mask for all signals except the libc-reserved RT signal range + sigset_t mask = { +#if ULONG_MAX == 0xFFFF'FFFF + 0x7FFF'FFFF, 0xFFFF'FFFC +#else + 0xFFFF'FFFC'7FFF'FFFF +#endif + }; + // but also mask SIGTIMER + sigaddset(&mask, SIGTIMER); + HelWord original_set; + uint64_t unused; + + HEL_CHECK(helSyscall2_2( + kHelObserveSuperCall + posix::superSigMask, + SIG_BLOCK, + *reinterpret_cast(&mask), + &original_set, + &unused + )); + + pthread_t pthread; + ret = pthread_create(&pthread, &attr, timer_setup, &context); + + // restore previous signal mask + HEL_CHECK(helSyscall2_2( + kHelObserveSuperCall + posix::superSigMask, SIG_SETMASK, original_set, &unused, &unused + )); + + if (ret) + return ret; + + req.set_sigev_signo(SIGTIMER); + req.set_sigev_tid(reinterpret_cast(pthread)->tid); + infoLogger() << "mlibc: timer_create: created timer thread " + << reinterpret_cast(pthread)->tid << frg::endlog; + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::TimerCreateResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) { + pthread_cancel(pthread); + __atomic_store_n(&context.setupSem, 1, __ATOMIC_RELEASE); + return resp.error() | toErrno; + } + + // notify worker that setup is complete + __atomic_store_n(&context.setupSem, 1, __ATOMIC_RELEASE); + // await worker setup to let the context go out of scope + while (__atomic_load_n(&context.workerSem, __ATOMIC_RELAXED) == 0) + ; + + *res = frg::construct( + getSysdepsAllocator(), resp.timer_id(), evp->sigev_notify, pthread + ); + return 0; + } else { + mlibc::infoLogger() << "mlibc: timer_create: unsupported sigevent type " + << evp->sigev_notify << frg::endlog; + return EINVAL; + } + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::TimerCreateResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + *res = frg::construct( + getSysdepsAllocator(), resp.timer_id(), evp ? evp->sigev_notify : SIGEV_SIGNAL, pthread_t{} + ); + return 0; +} + +int sys_timer_settime( + timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old +) { + SignalGuard sguard; + + auto timerHandle = reinterpret_cast(t); + managarm::posix::TimerSetRequest req(getSysdepsAllocator()); + req.set_timer(timerHandle->id); + req.set_flags(flags); + req.set_value_sec(val->it_value.tv_sec); + req.set_value_nsec(val->it_value.tv_nsec); + req.set_interval_sec(val->it_interval.tv_sec); + req.set_interval_nsec(val->it_interval.tv_nsec); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::TimerSetResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + if (old) { + old->it_value.tv_sec = resp.value_sec(); + old->it_value.tv_nsec = resp.value_nsec(); + old->it_interval.tv_sec = resp.interval_sec(); + old->it_interval.tv_nsec = resp.interval_nsec(); + } + + return 0; +} + +int sys_timer_gettime(timer_t t, struct itimerspec *val) { + SignalGuard sguard; + + auto timerHandle = reinterpret_cast(t); + managarm::posix::TimerGetRequest req(getSysdepsAllocator()); + req.set_timer((timerHandle->id)); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::TimerGetResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() != managarm::posix::Errors::SUCCESS) + return resp.error() | toErrno; + + if (val) { + val->it_value.tv_sec = resp.value_sec(); + val->it_value.tv_nsec = resp.value_nsec(); + val->it_interval.tv_sec = resp.interval_sec(); + val->it_interval.tv_nsec = resp.interval_nsec(); + } + + return 0; +} + +int sys_timer_delete(timer_t t) { + SignalGuard sguard; + + auto timerHandle = reinterpret_cast(t); + + if (timerHandle->notify_type == SIGEV_THREAD) { + pthread_cancel(timerHandle->thread); + pthread_kill(timerHandle->thread, SIGTIMER); + } + + managarm::posix::TimerDeleteRequest req(getSysdepsAllocator()); + req.set_timer(timerHandle->id); + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() + ) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::TimerDeleteResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + return resp.error() | toErrno; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/access.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/access.h new file mode 100755 index 0000000..cb83931 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/auxv.h new file mode 100755 index 0000000..e760d62 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/managarm/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..0b0ec27 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..7dc8d7c --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..6a42da5 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/dev_t.h new file mode 100755 index 0000000..bca881e --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/epoll.h new file mode 100755 index 0000000..eb4b76d --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/errno.h new file mode 100755 index 0000000..6e507de --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/fcntl.h new file mode 100755 index 0000000..463e2c9 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/gid_t.h new file mode 100755 index 0000000..abce6d6 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/in.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/in.h new file mode 100755 index 0000000..418d1d5 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/ino_t.h new file mode 100755 index 0000000..4c20aca --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/inotify.h new file mode 100755 index 0000000..b5cb282 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/ipc.h new file mode 100755 index 0000000..2c7ffc4 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/linux/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/limits.h new file mode 100755 index 0000000..6c88db2 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5d78fdf --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..bb3b625 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/packet.h new file mode 100755 index 0000000..998ef1a --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/pid_t.h new file mode 100755 index 0000000..baa90f6 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/poll.h new file mode 100755 index 0000000..8ea6a0a --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/ptrace.h new file mode 100755 index 0000000..b2517b2 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/random.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/random.h new file mode 100755 index 0000000..83fc3d9 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/random.h @@ -0,0 +1 @@ +../../../../abis/linux/random.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/reboot.h new file mode 100755 index 0000000..77013a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/resource.h new file mode 100755 index 0000000..88d7402 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/riscv-hwprobe.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/riscv-hwprobe.h new file mode 100755 index 0000000..e651325 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/riscv-hwprobe.h @@ -0,0 +1 @@ +../../../../abis/linux/riscv-hwprobe.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..e92eb5f --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/linux/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..df7bccf --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/shm.h new file mode 100755 index 0000000..067d8c4 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/sigevent.h new file mode 100755 index 0000000..83d069b --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/linux/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/signal.h new file mode 100755 index 0000000..4dcb0b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/socket.h new file mode 100755 index 0000000..f1dc016 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/stat.h new file mode 100755 index 0000000..1f63b41 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/time.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/time.h new file mode 100755 index 0000000..2a02625 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/uid_t.h new file mode 100755 index 0000000..b306777 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/utsname.h new file mode 100755 index 0000000..b285754 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..bbe258c --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/vt.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/vt.h new file mode 100755 index 0000000..5798a4a --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/vt.h @@ -0,0 +1 @@ +../../../../abis/linux/vt.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/managarm/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/managarm/include/bits/errors.hpp b/user/include/mlibc/sysdeps/managarm/include/bits/errors.hpp new file mode 100644 index 0000000..b709efe --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/bits/errors.hpp @@ -0,0 +1,167 @@ +#pragma once + +#include +#include + +#include "fs.frigg_bragi.hpp" +#include "posix.frigg_bragi.hpp" + +struct ToErrno { + template + auto operator()(E e) const { + return e | *this; + } +}; +constexpr ToErrno toErrno; + +inline int operator|(managarm::fs::Errors e, ToErrno) { + switch (e) { + case managarm::fs::Errors::SUCCESS: + return 0; + case managarm::fs::Errors::FILE_NOT_FOUND: + return ENOENT; + case managarm::fs::Errors::END_OF_FILE: + return 0; + case managarm::fs::Errors::ILLEGAL_ARGUMENT: + return EINVAL; + case managarm::fs::Errors::WOULD_BLOCK: + return EAGAIN; + case managarm::fs::Errors::SEEK_ON_PIPE: + return ESPIPE; + case managarm::fs::Errors::BROKEN_PIPE: + return EPIPE; + case managarm::fs::Errors::ACCESS_DENIED: + return EPERM; + case managarm::fs::Errors::NOT_DIRECTORY: + return ENOTDIR; + case managarm::fs::Errors::AF_NOT_SUPPORTED: + return EAFNOSUPPORT; + case managarm::fs::Errors::DESTINATION_ADDRESS_REQUIRED: + return EDESTADDRREQ; + case managarm::fs::Errors::NETWORK_UNREACHABLE: + return ENETUNREACH; + case managarm::fs::Errors::MESSAGE_TOO_LARGE: + return EMSGSIZE; + case managarm::fs::Errors::HOST_UNREACHABLE: + return EHOSTUNREACH; + case managarm::fs::Errors::INSUFFICIENT_PERMISSIONS: + return EPERM; + case managarm::fs::Errors::ADDRESS_IN_USE: + return EADDRINUSE; + case managarm::fs::Errors::ADDRESS_NOT_AVAILABLE: + return EADDRNOTAVAIL; + case managarm::fs::Errors::NOT_CONNECTED: + return ENOTCONN; + case managarm::fs::Errors::ALREADY_EXISTS: + return EEXIST; + case managarm::fs::Errors::ILLEGAL_OPERATION_TARGET: + return EINVAL; + case managarm::fs::Errors::NO_SPACE_LEFT: + return ENOSPC; + case managarm::fs::Errors::NOT_A_TERMINAL: + return ENOTTY; + case managarm::fs::Errors::NO_BACKING_DEVICE: + return ENXIO; + case managarm::fs::Errors::IS_DIRECTORY: + return EISDIR; + case managarm::fs::Errors::INVALID_PROTOCOL_OPTION: + return ENOPROTOOPT; + case managarm::fs::Errors::DIRECTORY_NOT_EMPTY: + return ENOTEMPTY; + case managarm::fs::Errors::CONNECTION_REFUSED: + return ECONNREFUSED; + case managarm::fs::Errors::ALREADY_CONNECTED: + return EISCONN; + case managarm::fs::Errors::NOT_A_SOCKET: + return ENOTSOCK; + case managarm::fs::Errors::INTERNAL_ERROR: + return EIO; + case managarm::fs::Errors::INTERRUPTED: + return EINTR; + case managarm::fs::Errors::NO_SUCH_PROCESS: + return ESRCH; + case managarm::fs::Errors::NAME_TOO_LONG: + return ENAMETOOLONG; + case managarm::fs::Errors::NO_FILE_DESCRIPTORS_AVAILABLE: + return EMFILE; + } + + mlibc::panicLogger() << "unhandled managarm::fs::Errors " << static_cast(e) + << frg::endlog; + __builtin_unreachable(); +} + +inline int operator|(managarm::posix::Errors e, ToErrno) { + switch (e) { + case managarm::posix::Errors::SUCCESS: + return 0; + case managarm::posix::Errors::FILE_NOT_FOUND: + return ENOENT; + case managarm::posix::Errors::END_OF_FILE: + return 0; + case managarm::posix::Errors::WOULD_BLOCK: + return EAGAIN; + case managarm::posix::Errors::BROKEN_PIPE: + return EPIPE; + case managarm::posix::Errors::ACCESS_DENIED: + return EPERM; + case managarm::posix::Errors::NOT_A_DIRECTORY: + return ENOTDIR; + case managarm::posix::Errors::INSUFFICIENT_PERMISSION: + return EPERM; + case managarm::posix::Errors::ALREADY_EXISTS: + return EEXIST; + case managarm::posix::Errors::ILLEGAL_OPERATION_TARGET: + return EINVAL; + case managarm::posix::Errors::NO_BACKING_DEVICE: + return ENXIO; + case managarm::posix::Errors::IS_DIRECTORY: + return EISDIR; + case managarm::posix::Errors::DIRECTORY_NOT_EMPTY: + return ENOTEMPTY; + case managarm::posix::Errors::INTERNAL_ERROR: + return EIO; + case managarm::posix::Errors::DEAD_FORK: + return EAGAIN; + case managarm::posix::Errors::ILLEGAL_REQUEST: + return ENOSYS; + case managarm::posix::Errors::ILLEGAL_ARGUMENTS: + return EINVAL; + case managarm::posix::Errors::NO_SUCH_FD: + return EBADF; + case managarm::posix::Errors::BAD_FD: + return EBADFD; + case managarm::posix::Errors::NOT_SUPPORTED: + return ENOTSUP; + case managarm::posix::Errors::RESOURCE_IN_USE: + return EBUSY; + case managarm::posix::Errors::NO_SUCH_RESOURCE: + return ESRCH; + case managarm::posix::Errors::NOT_A_TTY: + return ENOTTY; + case managarm::posix::Errors::PROTOCOL_NOT_SUPPORTED: + return EPROTONOSUPPORT; + case managarm::posix::Errors::ADDRESS_FAMILY_NOT_SUPPORTED: + return EAFNOSUPPORT; + case managarm::posix::Errors::NO_MEMORY: + return ENOMEM; + case managarm::posix::Errors::NO_CHILD_PROCESSES: + return ECHILD; + case managarm::posix::Errors::SYMBOLIC_LINK_LOOP: + return ELOOP; + case managarm::posix::Errors::ALREADY_CONNECTED: + return EISCONN; + case managarm::posix::Errors::UNSUPPORTED_SOCKET_TYPE: + return ESOCKTNOSUPPORT; + case managarm::posix::Errors::NAME_TOO_LONG: + return ENAMETOOLONG; + case managarm::posix::Errors::NO_FILE_DESCRIPTORS_AVAILABLE: + return EMFILE; + case managarm::posix::Errors::INTERRUPTED: + return EINTR; + } + + mlibc::panicLogger() << "unhandled managarm::posix::Errors " << static_cast(e) + << frg::endlog; + __builtin_unreachable(); +} diff --git a/user/include/mlibc/sysdeps/managarm/include/mlibc/posix-pipe.hpp b/user/include/mlibc/sysdeps/managarm/include/mlibc/posix-pipe.hpp new file mode 100644 index 0000000..9f36e57 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/mlibc/posix-pipe.hpp @@ -0,0 +1,336 @@ +#ifndef MLIBC_POSIX_PIPE +#define MLIBC_POSIX_PIPE + +#include +#include + +#include +#include + +#include +#include +#include +#include + +struct SignalGuard { + SignalGuard(); + + SignalGuard(const SignalGuard &) = delete; + + ~SignalGuard(); + + SignalGuard &operator=(const SignalGuard &) = delete; +}; + +// We need an allocator for message structs in sysdeps functions; the "normal" mlibc +// allocator cannot be used, as the sysdeps function might be called from a signal. +MemoryAllocator &getSysdepsAllocator(); + +struct Queue; + +struct ElementHandle { + friend void swap(ElementHandle &u, ElementHandle &v) { + using std::swap; + swap(u._queue, v._queue); + swap(u._n, v._n); + swap(u._data, v._data); + } + + ElementHandle() : _queue{nullptr}, _n{-1}, _data{nullptr} {} + + ElementHandle(Queue *queue, int n, void *data) : _queue{queue}, _n{n}, _data{data} {} + + ElementHandle(const ElementHandle &other); + + ElementHandle(ElementHandle &&other) : ElementHandle{} { swap(*this, other); } + + ~ElementHandle(); + + ElementHandle &operator=(ElementHandle other) { + swap(*this, other); + return *this; + } + + void *data() { return _data; } + + void advance(size_t size) { _data = reinterpret_cast(_data) + size; } + +private: + Queue *_queue; + int _n; + void *_data; +}; + +struct Queue { + Queue() : _handle{kHelNullHandle} { + // We do not need to protect those allocations against signals as this constructor + // is only called during library initialization. + _chunks[0] = + reinterpret_cast(getSysdepsAllocator().allocate(sizeof(HelChunk) + 4096)); + _chunks[1] = + reinterpret_cast(getSysdepsAllocator().allocate(sizeof(HelChunk) + 4096)); + + recreateQueue(); + } + + Queue(const Queue &) = delete; + + Queue &operator=(const Queue &) = delete; + + void recreateQueue() { + // Reset the internal queue state. + _retrieveIndex = 0; + _nextIndex = 0; + _lastProgress = 0; + + // Setup the queue header. + HelQueueParameters params{.flags = 0, .ringShift = 1, .numChunks = 2, .chunkSize = 4096}; + HEL_CHECK(helCreateQueue(¶ms, &_handle)); + + auto chunksOffset = (sizeof(HelQueue) + (sizeof(int) << 1) + 63) & ~size_t(63); + auto reservedPerChunk = (sizeof(HelChunk) + params.chunkSize + 63) & ~size_t(63); + auto overallSize = chunksOffset + params.numChunks * reservedPerChunk; + + void *mapping; + HEL_CHECK(helMapMemory( + _handle, + kHelNullHandle, + nullptr, + 0, + (overallSize + 0xFFF) & ~size_t(0xFFF), + kHelMapProtRead | kHelMapProtWrite, + &mapping + )); + + _queue = reinterpret_cast(mapping); + auto chunksPtr = reinterpret_cast(mapping) + chunksOffset; + for (unsigned int i = 0; i < 2; ++i) + _chunks[i] = reinterpret_cast(chunksPtr + i * reservedPerChunk); + + // Reset and enqueue the chunks. + _chunks[0]->progressFutex = 0; + _chunks[1]->progressFutex = 0; + _refCount[0] = 1; + _refCount[1] = 1; + + _queue->indexQueue[0] = 0; + _queue->indexQueue[1] = 1; + _queue->headFutex = 0; + _nextIndex = 2; + _wakeHeadFutex(); + } + + HelHandle getQueue() { return _handle; } + + void trim() {} + + frg::optional dequeueSingleUnlessCancelled() { + while (true) { + __ensure(_retrieveIndex != _nextIndex); + + auto progress = _waitProgressFutex(); + + auto n = _numberOf(_retrieveIndex); + __ensure(_refCount[n]); + + if (progress == FutexProgress::DONE) { + retire(n); + + _lastProgress = 0; + _retrieveIndex = ((_retrieveIndex + 1) & kHelHeadMask); + continue; + } + + if (progress == FutexProgress::CANCELLED) + return frg::null_opt; + + // Dequeue the next element. + auto ptr = (char *)_chunks[n] + sizeof(HelChunk) + _lastProgress; + auto element = reinterpret_cast(ptr); + _lastProgress += sizeof(HelElement) + element->length; + _refCount[n]++; + return ElementHandle{this, n, ptr + sizeof(HelElement)}; + } + } + + ElementHandle dequeueSingle() { + while (true) { + auto result = dequeueSingleUnlessCancelled(); + if (result) + return *result; + } + } + + void retire(int n) { + __ensure(_refCount[n]); + if (_refCount[n]-- > 1) + return; + + // Reset and enqueue the chunk again. + _chunks[n]->progressFutex = 0; + _refCount[n] = 1; + + _queue->indexQueue[_nextIndex & 1] = n; + _nextIndex = ((_nextIndex + 1) & kHelHeadMask); + _wakeHeadFutex(); + } + + void reference(int n) { _refCount[n]++; } + +private: + int _numberOf(int index) { return _queue->indexQueue[index & 1]; } + + HelChunk *_retrieveChunk() { return _chunks[_numberOf(_retrieveIndex)]; } + + void _wakeHeadFutex() { + auto futex = __atomic_exchange_n(&_queue->headFutex, _nextIndex, __ATOMIC_RELEASE); + if (futex & kHelHeadWaiters) + HEL_CHECK(helFutexWake(&_queue->headFutex)); + } + + enum class FutexProgress { + DONE, + PROGRESS, + CANCELLED, + }; + + FutexProgress _waitProgressFutex() { + while (true) { + auto futex = __atomic_load_n(&_retrieveChunk()->progressFutex, __ATOMIC_ACQUIRE); + __ensure(!(futex & ~(kHelProgressMask | kHelProgressWaiters | kHelProgressDone))); + do { + if (_lastProgress != (futex & kHelProgressMask)) + return FutexProgress::PROGRESS; + else if (futex & kHelProgressDone) + return FutexProgress::DONE; + + if (futex & kHelProgressWaiters) + break; // Waiters bit is already set (in a previous iteration). + } while (!__atomic_compare_exchange_n( + &_retrieveChunk()->progressFutex, + &futex, + _lastProgress | kHelProgressWaiters, + false, + __ATOMIC_ACQUIRE, + __ATOMIC_ACQUIRE + )); + + int err = helFutexWait( + &_retrieveChunk()->progressFutex, _lastProgress | kHelProgressWaiters, -1 + ); + + if (err == kHelErrCancelled) + return FutexProgress::CANCELLED; + + HEL_CHECK(err); + } + } + +private: + HelHandle _handle; + HelQueue *_queue; + HelChunk *_chunks[2]; + + // Index of the chunk that we are currently retrieving/inserting next. + int _retrieveIndex; + int _nextIndex; + + // Progress into the current chunk. + int _lastProgress; + + // Number of ElementHandle objects alive. + int _refCount[2]; +}; + +inline ElementHandle::~ElementHandle() { + if (_queue) + _queue->retire(_n); +} + +inline ElementHandle::ElementHandle(const ElementHandle &other) { + _queue = other._queue; + _n = other._n; + _data = other._data; + + _queue->reference(_n); +} + +inline HelSimpleResult *parseSimple(ElementHandle &element) { + auto result = reinterpret_cast(element.data()); + element.advance(sizeof(HelSimpleResult)); + return result; +} + +inline HelInlineResult *parseInline(ElementHandle &element) { + auto result = reinterpret_cast(element.data()); + element.advance(sizeof(HelInlineResult) + ((result->length + 7) & ~size_t(7))); + return result; +} + +inline HelLengthResult *parseLength(ElementHandle &element) { + auto result = reinterpret_cast(element.data()); + element.advance(sizeof(HelLengthResult)); + return result; +} + +inline HelHandleResult *parseHandle(ElementHandle &element) { + auto result = reinterpret_cast(element.data()); + element.advance(sizeof(HelHandleResult)); + return result; +} + +HelHandle getPosixLane(); +HelHandle *cacheFileTable(); +HelHandle getHandleForFd(int fd); +void resetCancellationId(); +void setCancellationId(uint64_t event, HelHandle handle, int fd); +void clearCachedInfos(); +uint64_t allocateCancellationId(); + +extern thread_local Queue globalQueue; + +// This include is here because it needs ElementHandle to be declared +#include + +template +auto exchangeMsgsSync(HelHandle descriptor, Args &&...args) { + auto results = helix_ng::createResultsTuple(args...); + auto actions = helix_ng::chainActionArrays(args...); + + HEL_CHECK( + helSubmitAsync(descriptor, actions.data(), actions.size(), globalQueue.getQueue(), 0, 0) + ); + + auto element = globalQueue.dequeueSingle(); + void *ptr = element.data(); + + [&](std::index_sequence) { + (results.template get

().parse(ptr, element), ...); + }(std::make_index_sequence>{}); + + return results; +} + +template +auto exchangeMsgsSyncCancellable(HelHandle descriptor, uint64_t cancelId, int fd, Args &&...args) { + auto results = helix_ng::createResultsTuple(args...); + auto actions = helix_ng::chainActionArrays(args...); + + HEL_CHECK( + helSubmitAsync(descriptor, actions.data(), actions.size(), globalQueue.getQueue(), 0, 0) + ); + setCancellationId(cancelId, descriptor, fd); + + auto element = globalQueue.dequeueSingle(); + void *ptr = element.data(); + + [&](std::index_sequence) { + (results.template get

().parse(ptr, element), ...); + }(std::make_index_sequence>{}); + + resetCancellationId(); + + return results; +} + +#endif // MLIBC_POSIX_PIPE diff --git a/user/include/mlibc/sysdeps/managarm/include/mlibc/thread-entry.hpp b/user/include/mlibc/sysdeps/managarm/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..0154307 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/include/mlibc/thread-entry.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +extern "C" void __mlibc_start_thread(void); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb); + +namespace mlibc { +void *prepare_stack(void *entry, void *user_arg, void *tcb); +} diff --git a/user/include/mlibc/sysdeps/managarm/meson.build b/user/include/mlibc/sysdeps/managarm/meson.build new file mode 100644 index 0000000..cfc10a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/meson.build @@ -0,0 +1,176 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': true, + 'glibc': true, + 'bsd': true, +} + +managarm = subproject('managarm', default_options: [ 'provide_deps=true' ]) +hel_dep = managarm.get_variable('hel_dep') +proto_posix_dep = managarm.get_variable('posix_extra_dep') + +bragi = find_program('bragi') +bragi_dep = subproject('bragi', default_options: ['install_headers=false']).get_variable('bragi_dep') + +libdrm_dep = subproject('libdrm-headers').get_variable('libdrm_dep') + +bragi_gen = generator(bragi, arguments: [ + '@INPUT@', + '-o', + '@OUTPUT@', + 'cpp', '-l', 'frigg', + '--protobuf', + ], + output: '@BASENAME@.frigg_bragi.hpp') + +fs_bragi = bragi_gen.process(managarm.get_variable('fs_bragi_files')) +posix_bragi = bragi_gen.process(managarm.get_variable('posix_bragi_files')) + +rtld_sources += files( + 'generic/ensure.cpp', + 'generic/memory.cpp', + 'rtld-generic/support.cpp', +) +rtld_sources += [ + fs_bragi, + posix_bragi, +] + +libc_deps += [ bragi_dep, hel_dep, proto_posix_dep, libdrm_dep ] +rtld_deps += [ bragi_dep, hel_dep, proto_posix_dep ] + +libc_sources += files( + 'generic/drm.cpp', + 'generic/ensure.cpp', + 'generic/entry.cpp', + 'generic/file.cpp', + 'generic/fork-exec.cpp', + 'generic/ioctl.cpp', + 'generic/memory.cpp', + 'generic/mount.cpp', + 'generic/net.cpp', + 'generic/sched.cpp', + 'generic/signals.cpp', + 'generic/socket.cpp', + 'generic/time.cpp' +) +libc_sources += [ + fs_bragi, + posix_bragi, +] + +if host_machine.cpu_family() == 'aarch64' + libc_sources += files( + 'aarch64/signals.S', + 'aarch64/thread_entry.S', + 'aarch64/thread.cpp' + ) +elif host_machine.cpu_family() == 'x86_64' + libc_sources += files( + 'x86_64/signals.S', + 'x86_64/thread_entry.S', + 'x86_64/thread.cpp', + 'x86_64/assembly-asserts.cpp', + ) +elif host_machine.cpu_family() == 'riscv64' + libc_sources += files( + 'riscv64/signals.S', + 'riscv64/thread_entry.S', + 'riscv64/thread.cpp', + ) +else + error('Unknown architecture') +endif + +if not no_headers + install_headers( + 'include/abi-bits/access.h', + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/vt.h', + 'include/abi-bits/random.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + if host_machine.cpu_family() == 'riscv64' + install_headers( + 'include/abi-bits/riscv-hwprobe.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + endif +endif + +if not headers_only + crtstuff = ['crt0'] + if host_machine.cpu_family() in ['x86_64', 'aarch64', 'riscv64'] + crtstuff += [ + 'Scrt1', + 'crti', + 'crtn' + ] + endif + foreach crtthing : crtstuff + crtf = crtthing + '.S' + crt_src = files(host_machine.cpu_family() / 'crt-src' / crtf) + crt = custom_target( + crtthing, + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: crt_src, + output: crtthing + '.o', + install: true, + install_dir: get_option('libdir') + ) + endforeach + +endif + diff --git a/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/Scrt1.S new file mode 100644 index 0000000..17cc3fd --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/Scrt1.S @@ -0,0 +1,30 @@ +.weak __global_pointer$ +.hidden __global_pointer$ + +.section .text +.global _start +_start: + # Load gp. +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + + mv a0, sp + la a1, main + call __mlibc_entry@plt + unimp + +# Load gp from .preinit_array since it may be used by the executable's .init_array. +# We still load it in _start to account for static binaries. This matches glibc's behavior. +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + +.section .preinit_array,"aw" + .dword load_gp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crt0.S b/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crt0.S new file mode 100644 index 0000000..faaf407 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crt0.S @@ -0,0 +1,30 @@ +.weak __global_pointer$ +.hidden __global_pointer$ + +.section .text +.global _start +_start: + # Load gp. +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + + mv a0, sp + la a1, main + call __mlibc_entry + unimp + +# Load gp from .preinit_array since it may be used by the executable's .init_array. +# We still load it in _start to account for static binaries. This matches glibc's behavior. +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + +.section .preinit_array,"aw" + .dword load_gp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crti.S b/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crti.S new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crti.S @@ -0,0 +1 @@ + diff --git a/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crtn.S b/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crtn.S new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/riscv64/crt-src/crtn.S @@ -0,0 +1 @@ + diff --git a/user/include/mlibc/sysdeps/managarm/riscv64/signals.S b/user/include/mlibc/sysdeps/managarm/riscv64/signals.S new file mode 100644 index 0000000..2625426 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/riscv64/signals.S @@ -0,0 +1,7 @@ +.section .text +.global __mlibc_signal_restore +__mlibc_signal_restore: + li a0, 0x80000006 + ecall + unimp +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/riscv64/thread.cpp b/user/include/mlibc/sysdeps/managarm/riscv64/thread.cpp new file mode 100644 index 0000000..fba44f7 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/riscv64/thread.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while (!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if (mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + + mlibc::sys_futex_wake(&self->didExit); + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack( + void **stack, + void *entry, + void *user_arg, + void *tcb, + size_t *stack_size, + size_t *guard_size, + void **stack_base +) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = + mmap(nullptr, *stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } + + uintptr_t *sp = + reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/riscv64/thread_entry.S b/user/include/mlibc/sysdeps/managarm/riscv64/thread_entry.S new file mode 100644 index 0000000..897a38a --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/riscv64/thread_entry.S @@ -0,0 +1,11 @@ +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + ld a0, 0x0(sp) + ld a1, 0x8(sp) + ld a2, 0x10(sp) + + addi sp, sp, 24 + call __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/rtld-generic/support.cpp b/user/include/mlibc/sysdeps/managarm/rtld-generic/support.cpp new file mode 100644 index 0000000..372a722 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/rtld-generic/support.cpp @@ -0,0 +1,497 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +// -------------------------------------------------------- +// POSIX I/O functions. +// -------------------------------------------------------- + +HelHandle posixLane; +HelHandle *fileTable; + +extern "C" [[gnu::visibility("hidden")]] void abort() { + mlibc::panicLogger() << "rtld: abort() called" << frg::endlog; + __builtin_unreachable(); +} + +void cacheFileTable() { + if (fileTable) + return; + + posix::ManagarmProcessData data; + HEL_CHECK( + helSyscall1(kHelCallSuper + posix::superGetProcessData, reinterpret_cast(&data)) + ); + posixLane = data.posixLane; + fileTable = data.fileTable; +} + +template +T load(void *ptr) { + T result; + memcpy(&result, ptr, sizeof(T)); + return result; +} + +// This Queue implementation is more simplistic than the ones in mlibc and helix. +// In fact, we only manage a single chunk; this minimizes the memory usage of the queue. +struct Queue { + Queue() : _handle{kHelNullHandle}, _lastProgress(0) { + HelQueueParameters params{.flags = 0, .ringShift = 0, .numChunks = 1, .chunkSize = 4096}; + HEL_CHECK(helCreateQueue(¶ms, &_handle)); + + auto chunksOffset = (sizeof(HelQueue) + (sizeof(int) << 0) + 63) & ~size_t(63); + auto reservedPerChunk = (sizeof(HelChunk) + params.chunkSize + 63) & ~size_t(63); + auto overallSize = chunksOffset + params.numChunks * reservedPerChunk; + + void *mapping; + HEL_CHECK(helMapMemory( + _handle, + kHelNullHandle, + nullptr, + 0, + (overallSize + 0xFFF) & ~size_t(0xFFF), + kHelMapProtRead | kHelMapProtWrite, + &mapping + )); + + _queue = reinterpret_cast(mapping); + _chunk = + reinterpret_cast(reinterpret_cast(mapping) + chunksOffset); + + // Reset and enqueue the first chunk. + _chunk->progressFutex = 0; + + _queue->indexQueue[0] = 0; + _queue->headFutex = 1; + _nextIndex = 1; + _wakeHeadFutex(); + } + + Queue(const Queue &) = delete; + + Queue &operator=(const Queue &) = delete; + + HelHandle getHandle() { return _handle; } + + void *dequeueSingle() { + while (true) { + bool done; + _waitProgressFutex(&done); + if (done) { + // Reset and enqueue the chunk again. + _chunk->progressFutex = 0; + + _queue->indexQueue[0] = 0; + _nextIndex = ((_nextIndex + 1) & kHelHeadMask); + _wakeHeadFutex(); + + _lastProgress = 0; + continue; + } + + // Dequeue the next element. + auto ptr = (char *)_chunk + sizeof(HelChunk) + _lastProgress; + auto element = load(ptr); + _lastProgress += sizeof(HelElement) + element.length; + return ptr + sizeof(HelElement); + } + } + +private: + void _wakeHeadFutex() { + auto futex = __atomic_exchange_n(&_queue->headFutex, _nextIndex, __ATOMIC_RELEASE); + if (futex & kHelHeadWaiters) + HEL_CHECK(helFutexWake(&_queue->headFutex)); + } + + void _waitProgressFutex(bool *done) { + while (true) { + auto futex = __atomic_load_n(&_chunk->progressFutex, __ATOMIC_ACQUIRE); + __ensure(!(futex & ~(kHelProgressMask | kHelProgressWaiters | kHelProgressDone))); + do { + if (_lastProgress != (futex & kHelProgressMask)) { + *done = false; + return; + } else if (futex & kHelProgressDone) { + *done = true; + return; + } + + if (futex & kHelProgressWaiters) + break; // Waiters bit is already set (in a previous iteration). + } while (!__atomic_compare_exchange_n( + &_chunk->progressFutex, + &futex, + _lastProgress | kHelProgressWaiters, + false, + __ATOMIC_ACQUIRE, + __ATOMIC_ACQUIRE + )); + + int err = helFutexWait(&_chunk->progressFutex, _lastProgress | kHelProgressWaiters, -1); + if (err == kHelErrCancelled) + continue; + HEL_CHECK(err); + } + } + +private: + HelHandle _handle; + HelQueue *_queue; + HelChunk *_chunk; + int _nextIndex; + int _lastProgress; +}; + +frg::manual_box globalQueue; + +HelSimpleResult *parseSimple(void *&element) { + auto result = reinterpret_cast(element); + element = (char *)element + sizeof(HelSimpleResult); + return result; +} + +HelInlineResult *parseInline(void *&element) { + auto result = reinterpret_cast(element); + element = (char *)element + sizeof(HelInlineResult) + ((result->length + 7) & ~size_t(7)); + return result; +} + +HelLengthResult *parseLength(void *&element) { + auto result = reinterpret_cast(element); + element = (char *)element + sizeof(HelLengthResult); + return result; +} + +HelHandleResult *parseHandle(void *&element) { + auto result = reinterpret_cast(element); + element = (char *)element + sizeof(HelHandleResult); + return result; +} + +namespace mlibc { + +int sys_tcb_set(void *pointer) { +#if defined(__x86_64__) + HEL_CHECK(helWriteFsBase(pointer)); +#elif defined(__aarch64__) + uintptr_t addr = reinterpret_cast(pointer); + addr += sizeof(Tcb) - 0x10; + asm volatile("msr tpidr_el0, %0" ::"r"(addr)); +#elif defined(__riscv) && __riscv_xlen == 64 + uintptr_t tp = reinterpret_cast(pointer) + sizeof(Tcb); + asm volatile("mv tp, %0" : : "r"(tp) : "memory"); +#else +#error Unknown architecture +#endif + return 0; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + cacheFileTable(); + HelAction actions[4]; + + managarm::posix::OpenAtRequest req(getAllocator()); + req.set_fd(AT_FDCWD); + req.set_flags(flags); + req.set_mode(mode); + req.set_path(frg::string(getAllocator(), path)); + + if (!globalQueue.valid()) + globalQueue.initialize(); + + frg::string head(getAllocator()); + frg::string tail(getAllocator()); + head.resize(req.size_of_head()); + tail.resize(req.size_of_tail()); + bragi::limited_writer headWriter{head.data(), head.size()}; + bragi::limited_writer tailWriter{tail.data(), tail.size()}; + auto headOk = req.encode_head(headWriter); + auto tailOk = req.encode_tail(tailWriter); + __ensure(headOk); + __ensure(tailOk); + + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = head.data(); + actions[1].length = head.size(); + actions[2].type = kHelActionSendFromBuffer; + actions[2].flags = kHelItemChain; + actions[2].buffer = tail.data(); + actions[2].length = tail.size(); + actions[3].type = kHelActionRecvInline; + actions[3].flags = 0; + HEL_CHECK(helSubmitAsync(posixLane, actions, 4, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_head = parseSimple(element); + auto send_tail = parseSimple(element); + auto recv_resp = parseInline(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_head->error); + HEL_CHECK(send_tail->error); + HEL_CHECK(recv_resp->error); + + managarm::posix::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + + if (resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) + return -1; + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + __ensure(whence == SEEK_SET); + + cacheFileTable(); + auto lane = fileTable[fd]; + HelAction actions[3]; + + managarm::fs::CntRequest req(getAllocator()); + req.set_req_type(managarm::fs::CntReqType::SEEK_ABS); + req.set_rel_offset(offset); + + if (!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionRecvInline; + actions[2].flags = 0; + HEL_CHECK(helSubmitAsync(lane, actions, 3, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto recv_resp = parseInline(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(recv_resp->error); + + managarm::fs::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *new_offset = offset; + return 0; +} + +int sys_read(int fd, void *data, size_t length, ssize_t *bytes_read) { + cacheFileTable(); + auto lane = fileTable[fd]; + HelAction actions[5]; + + managarm::fs::CntRequest req(getAllocator()); + req.set_req_type(managarm::fs::CntReqType::READ); + req.set_size(length); + + if (!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionImbueCredentials; + actions[2].handle = kHelThisThread; + actions[2].flags = kHelItemChain; + actions[3].type = kHelActionRecvInline; + actions[3].flags = kHelItemChain; + actions[4].type = kHelActionRecvToBuffer; + actions[4].flags = 0; + actions[4].buffer = data; + actions[4].length = length; + HEL_CHECK(helSubmitAsync(lane, actions, 5, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto imbue_creds = parseSimple(element); + auto recv_resp = parseInline(element); + auto recv_data = parseLength(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(imbue_creds->error); + HEL_CHECK(recv_resp->error); + HEL_CHECK(recv_data->error); + + managarm::fs::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *bytes_read = recv_data->length; + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + cacheFileTable(); + HelAction actions[3]; + + managarm::posix::VmMapRequest req(getAllocator()); + req.set_address_hint(reinterpret_cast(hint)); + req.set_size(size); + req.set_mode(prot); + req.set_flags(flags); + req.set_fd(fd); + req.set_rel_offset(offset); + + if (!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionRecvInline; + actions[2].flags = 0; + HEL_CHECK(helSubmitAsync(posixLane, actions, 3, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto recv_resp = parseInline(element); + + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(recv_resp->error); + + managarm::posix::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *window = reinterpret_cast(resp.offset()); + return 0; +} + +int sys_close(int fd) { + cacheFileTable(); + HelAction actions[3]; + + managarm::posix::CloseRequest req(getAllocator()); + req.set_fd(fd); + + if (!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionRecvInline; + actions[2].flags = 0; + HEL_CHECK(helSubmitAsync(posixLane, actions, 3, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto recv_resp = parseInline(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(recv_resp->error); + + managarm::posix::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +int sys_futex_tid() { + HelWord tid = 0; + HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superGetTid, &tid)); + + return tid; +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + // This implementation is inherently signal-safe. + if (time) { + if (helFutexWait(pointer, expected, time->tv_nsec + time->tv_sec * 1000000000)) + return -1; + return 0; + } + if (helFutexWait(pointer, expected, -1)) + return -1; + return 0; +} + +int sys_futex_wake(int *pointer) { + // This implementation is inherently signal-safe. + if (helFutexWake(pointer)) + return -1; + return 0; +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + managarm::posix::CntRequest req(getAllocator()); + req.set_request_type(managarm::posix::CntReqType::VM_PROTECT); + req.set_address(reinterpret_cast(pointer)); + req.set_size(size); + req.set_mode(prot); + + if (!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + + HelAction actions[3]; + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionRecvInline; + actions[2].flags = 0; + HEL_CHECK(helSubmitAsync(posixLane, actions, 3, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto recv_resp = parseInline(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(recv_resp->error); + + managarm::posix::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/assembly-asserts.cpp b/user/include/mlibc/sysdeps/managarm/x86_64/assembly-asserts.cpp new file mode 100644 index 0000000..49638f5 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/assembly-asserts.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include "context-offsets.h" + +// offsets int ucontext_t as used in signals.S +static_assert(offsetof(ucontext_t, uc_mcontext) == UCONTEXT_GREGS_OFFSET); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R8]) == UCONTEXT_OFFSET_R8); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R9]) == UCONTEXT_OFFSET_R9); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R10]) == UCONTEXT_OFFSET_R10); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R11]) == UCONTEXT_OFFSET_R11); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R12]) == UCONTEXT_OFFSET_R12); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R13]) == UCONTEXT_OFFSET_R13); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R14]) == UCONTEXT_OFFSET_R14); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_R15]) == UCONTEXT_OFFSET_R15); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RDI]) == UCONTEXT_OFFSET_RDI); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RSI]) == UCONTEXT_OFFSET_RSI); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RBP]) == UCONTEXT_OFFSET_RBP); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RBX]) == UCONTEXT_OFFSET_RBX); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RDX]) == UCONTEXT_OFFSET_RDX); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RAX]) == UCONTEXT_OFFSET_RAX); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RCX]) == UCONTEXT_OFFSET_RCX); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RSP]) == UCONTEXT_OFFSET_RSP); +static_assert(offsetof(ucontext_t, uc_mcontext.gregs[REG_RIP]) == UCONTEXT_OFFSET_RIP); diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/context-offsets.h b/user/include/mlibc/sysdeps/managarm/x86_64/context-offsets.h new file mode 100644 index 0000000..30ca74a --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/context-offsets.h @@ -0,0 +1,21 @@ +#pragma once + +#define UCONTEXT_GREGS_OFFSET 40 + +#define UCONTEXT_OFFSET_R8 (UCONTEXT_GREGS_OFFSET + 0) +#define UCONTEXT_OFFSET_R9 (UCONTEXT_GREGS_OFFSET + 8) +#define UCONTEXT_OFFSET_R10 (UCONTEXT_GREGS_OFFSET + 16) +#define UCONTEXT_OFFSET_R11 (UCONTEXT_GREGS_OFFSET + 24) +#define UCONTEXT_OFFSET_R12 (UCONTEXT_GREGS_OFFSET + 32) +#define UCONTEXT_OFFSET_R13 (UCONTEXT_GREGS_OFFSET + 40) +#define UCONTEXT_OFFSET_R14 (UCONTEXT_GREGS_OFFSET + 48) +#define UCONTEXT_OFFSET_R15 (UCONTEXT_GREGS_OFFSET + 56) +#define UCONTEXT_OFFSET_RDI (UCONTEXT_GREGS_OFFSET + 64) +#define UCONTEXT_OFFSET_RSI (UCONTEXT_GREGS_OFFSET + 72) +#define UCONTEXT_OFFSET_RBP (UCONTEXT_GREGS_OFFSET + 80) +#define UCONTEXT_OFFSET_RBX (UCONTEXT_GREGS_OFFSET + 88) +#define UCONTEXT_OFFSET_RDX (UCONTEXT_GREGS_OFFSET + 96) +#define UCONTEXT_OFFSET_RAX (UCONTEXT_GREGS_OFFSET + 104) +#define UCONTEXT_OFFSET_RCX (UCONTEXT_GREGS_OFFSET + 112) +#define UCONTEXT_OFFSET_RSP (UCONTEXT_GREGS_OFFSET + 120) +#define UCONTEXT_OFFSET_RIP (UCONTEXT_GREGS_OFFSET + 128) diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/Scrt1.S b/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/Scrt1.S new file mode 100644 index 0000000..d0e8213 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/Scrt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + lea main(%rip), %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crt0.S b/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crt0.S new file mode 100644 index 0000000..6afb421 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crt0.S @@ -0,0 +1,10 @@ + +.section .text +.global _start +_start: + mov %rsp, %rdi + mov $main, %rsi + call __mlibc_entry + +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crti.S b/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crti.S new file mode 100644 index 0000000..1ca20f2 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crti.S @@ -0,0 +1,15 @@ + .ident "x86_64-managarm-mlibc crti" + + .section .init + .globl _init + .type _init,@function +_init: + push %rax + + .section .fini + .globl _fini + .type _fini,@function +_fini: + push %rax + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crtn.S b/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..fdb309e --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/crt-src/crtn.S @@ -0,0 +1,11 @@ +.ident "x86_64-managarm-mlibc crtn" + +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/signals.S b/user/include/mlibc/sysdeps/managarm/x86_64/signals.S new file mode 100644 index 0000000..c86e170 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/signals.S @@ -0,0 +1,33 @@ +#include "mlibc-asm/dwarf-helpers.h" +#include "mlibc-asm/helpers.h" +#include "context-offsets.h" + +.section .text +.cfi_startproc +.cfi_signal_frame + cfi_set_cfa_to_ptr_with_offset DWARF_REG_RSP, UCONTEXT_OFFSET_RSP + cfi_set_prev_reg_value DWARF_REG_R8, DWARF_REG_RSP, UCONTEXT_OFFSET_R8 + cfi_set_prev_reg_value DWARF_REG_R9, DWARF_REG_RSP, UCONTEXT_OFFSET_R9 + cfi_set_prev_reg_value DWARF_REG_R10, DWARF_REG_RSP, UCONTEXT_OFFSET_R10 + cfi_set_prev_reg_value DWARF_REG_R11, DWARF_REG_RSP, UCONTEXT_OFFSET_R11 + cfi_set_prev_reg_value DWARF_REG_R12, DWARF_REG_RSP, UCONTEXT_OFFSET_R12 + cfi_set_prev_reg_value DWARF_REG_R13, DWARF_REG_RSP, UCONTEXT_OFFSET_R13 + cfi_set_prev_reg_value DWARF_REG_R14, DWARF_REG_RSP, UCONTEXT_OFFSET_R14 + cfi_set_prev_reg_value DWARF_REG_R15, DWARF_REG_RSP, UCONTEXT_OFFSET_R15 + cfi_set_prev_reg_value DWARF_REG_RDI, DWARF_REG_RSP, UCONTEXT_OFFSET_RDI + cfi_set_prev_reg_value DWARF_REG_RSI, DWARF_REG_RSP, UCONTEXT_OFFSET_RSI + cfi_set_prev_reg_value DWARF_REG_RBP, DWARF_REG_RSP, UCONTEXT_OFFSET_RBP + cfi_set_prev_reg_value DWARF_REG_RBX, DWARF_REG_RSP, UCONTEXT_OFFSET_RBX + cfi_set_prev_reg_value DWARF_REG_RDX, DWARF_REG_RSP, UCONTEXT_OFFSET_RDX + cfi_set_prev_reg_value DWARF_REG_RAX, DWARF_REG_RSP, UCONTEXT_OFFSET_RAX + cfi_set_prev_reg_value DWARF_REG_RCX, DWARF_REG_RSP, UCONTEXT_OFFSET_RCX + cfi_set_prev_reg_value DWARF_REG_RETURN_ADDRESS, DWARF_REG_RSP, UCONTEXT_OFFSET_RIP + nop + +PROC_START_NOCFI(__mlibc_signal_restore) + mov $0x80000006, %rdi + syscall + ud2 +PROC_END(__mlibc_signal_restore) + +GNU_STACK_NOTE() diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/thread.cpp b/user/include/mlibc/sysdeps/managarm/x86_64/thread.cpp new file mode 100644 index 0000000..129267d --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/thread.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while (!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if (mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack( + void **stack, + void *entry, + void *user_arg, + void *tcb, + size_t *stack_size, + size_t *guard_size, + void **stack_base +) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = + mmap(nullptr, *stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } + + uintptr_t *sp = + reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/managarm/x86_64/thread_entry.S b/user/include/mlibc/sysdeps/managarm/x86_64/thread_entry.S new file mode 100644 index 0000000..fcb5bf5 --- /dev/null +++ b/user/include/mlibc/sysdeps/managarm/x86_64/thread_entry.S @@ -0,0 +1,22 @@ +.section .text +.global __mlibc_start_thread +.type __mlibc_start_thread, "function" +.cfi_startproc +__mlibc_start_thread: + .cfi_undefined %rip + .cfi_undefined %rbp + + pop %rdi + .cfi_adjust_cfa_offset -8 + .cfi_undefined %rdi + pop %rsi + .cfi_adjust_cfa_offset -8 + .cfi_undefined %rsi + pop %rdx + .cfi_adjust_cfa_offset -8 + .cfi_undefined %rdx + call __mlibc_enter_thread + ud2 +.cfi_endproc + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/aarch64/Scrt1.S b/user/include/mlibc/sysdeps/menix/aarch64/Scrt1.S new file mode 100644 index 0000000..3e56608 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/aarch64/Scrt1.S @@ -0,0 +1,10 @@ +.section .text +.global _start +_start: + mov x0, sp + adr x1, main + + bl __mlibc_entry + brk #0 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/aarch64/crt1.S b/user/include/mlibc/sysdeps/menix/aarch64/crt1.S new file mode 100644 index 0000000..58566e7 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/aarch64/crt1.S @@ -0,0 +1,9 @@ +.section .text +.global _start +_start: + mov x0, sp + adrp x1, main + add x1, x1, :lo12:main + bl __mlibc_entry + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/aarch64/crti.S b/user/include/mlibc/sysdeps/menix/aarch64/crti.S new file mode 100644 index 0000000..0f9f2e9 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/aarch64/crti.S @@ -0,0 +1,13 @@ +.section .init +.global _init +_init: + stp x29, x30, [sp, -16]! + mov x29, sp + +.section .fini +.global _fini +_fini: + stp x29, x30, [sp, -16]! + mov x29, sp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/aarch64/crtn.S b/user/include/mlibc/sysdeps/menix/aarch64/crtn.S new file mode 100644 index 0000000..00e8591 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/aarch64/crtn.S @@ -0,0 +1,7 @@ +.section .init + ldp x29, x30, [sp], #16 + +.section .fini + ldp x29, x30, [sp], #16 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/aarch64/thread.S b/user/include/mlibc/sysdeps/menix/aarch64/thread.S new file mode 100644 index 0000000..41f8f2c --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/aarch64/thread.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + ldr x0, [sp], #8 + ldr x1, [sp], #8 + ldr x2, [sp], #8 + bl __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/generic/entry.cpp b/user/include/mlibc/sysdeps/menix/generic/entry.cpp new file mode 100644 index 0000000..8b5b2c7 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/generic/entry.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; + +extern "C" void +__mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + __dlapi_enter(entry_stack); + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} diff --git a/user/include/mlibc/sysdeps/menix/generic/internal.cpp b/user/include/mlibc/sysdeps/menix/generic/internal.cpp new file mode 100644 index 0000000..228a9fa --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/generic/internal.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +void sys_libc_log(const char *message) { + menix_syscall(SYSCALL_WRITE, 1, (size_t)message, strlen(message)); + menix_syscall(SYSCALL_WRITE, 1, (size_t)"\n", 1); +} + +[[noreturn]] void sys_libc_panic() { + sys_libc_log("mlibc panic!"); + menix_syscall(SYSCALL_EXIT, 1); + __builtin_unreachable(); +} + +int sys_tcb_set(void *pointer) { +#if defined(__x86_64__) + return menix_syscall(SYSCALL_ARCHCTL, ARCHCTL_SET_FSBASE, (size_t)pointer).error; +#elif defined(__aarch64__) + uintptr_t thread_data = reinterpret_cast(pointer) + sizeof(Tcb) - 0x10; + asm volatile("msr tpidr_el0, %0" ::"r"(thread_data)); + return 0; +#elif defined(__riscv) + uintptr_t thread_data = reinterpret_cast(pointer) + sizeof(Tcb); + asm volatile("mv tp, %0" ::"r"(thread_data)); + return 0; +#elif defined(__loongarch64) + uintptr_t thread_data = reinterpret_cast(pointer) + sizeof(Tcb); + asm volatile("move $tp, %0" ::"r"(thread_data)); + return 0; +#else +#error "Unsupported architecture!" +#endif +} + +int sys_futex_tid() { return menix_syscall(SYSCALL_GETTID).value; } + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + return menix_syscall(SYSCALL_FUTEX_WAIT, (size_t)pointer, expected, (size_t)time).error; +} + +int sys_futex_wake(int *pointer) { + return menix_syscall(SYSCALL_FUTEX_WAKE, (size_t)pointer).error; +} + +int sys_anon_allocate(size_t size, void **pointer) { + auto r = menix_syscall( + SYSCALL_MMAP, 0, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0 + ); + if (r.error) + return r.error; + *pointer = (void *)r.value; + return 0; +} + +int sys_anon_free(void *pointer, size_t size) { + return menix_syscall(SYSCALL_MUNMAP, (size_t)pointer, size).error; +} + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + auto r = menix_syscall(SYSCALL_OPENAT, dirfd, (size_t)path, flags, mode); + if (r.error) + return r.error; + *fd = (int)r.value; + return 0; +} + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, pathname, flags, mode, fd); +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + auto r = menix_syscall(SYSCALL_READ, fd, (size_t)buf, count); + if (r.error) + return r.error; + *bytes_read = (ssize_t)r.value; + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + auto r = menix_syscall(SYSCALL_SEEK, fd, offset, whence); + if (r.error) + return r.error; + *new_offset = r.value; + return 0; +} + +int sys_close(int fd) { return menix_syscall(SYSCALL_CLOSE, fd).error; } + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + switch (fsfdt) { + case fsfd_target::path: + return menix_syscall(SYSCALL_FSTATAT, AT_FDCWD, (size_t)path, (size_t)statbuf, flags) + .error; + case fsfd_target::fd_path: + return menix_syscall(SYSCALL_FSTATAT, fd, (size_t)path, (size_t)statbuf, flags).error; + case fsfd_target::fd: + return menix_syscall(SYSCALL_FSTAT, fd, (size_t)statbuf).error; + default: + return EINVAL; + } +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + auto r = menix_syscall(SYSCALL_MMAP, (size_t)hint, size, prot, flags, fd, offset); + if (r.error) + return r.error; + *window = (void *)r.value; + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + return menix_syscall(SYSCALL_MUNMAP, (size_t)pointer, size).error; +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + return menix_syscall(SYSCALL_MPROTECT, (size_t)pointer, size, prot).error; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/menix/generic/linux.cpp b/user/include/mlibc/sysdeps/menix/generic/linux.cpp new file mode 100644 index 0000000..44e425f --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/generic/linux.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +int sys_mount( + const char *source, + const char *target, + const char *fstype, + unsigned long flags, + const void *data +) { + return menix_syscall( + SYSCALL_MOUNT, (size_t)source, (size_t)target, (size_t)fstype, flags, (size_t)data + ) + .error; +} + +int sys_umount2(const char *target, int flags) { + return menix_syscall(SYSCALL_UMOUNT, (size_t)target, flags).error; +} + +int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out) { + auto r = menix_syscall(SYSCALL_PTRACE, req, pid, (size_t)addr, (size_t)data); + if (r.error) + return r.error; + *out = (long)r.value; + return 0; +} + +int sys_klogctl(int type, char *bufp, int len, int *out) { + auto r = menix_syscall(SYSCALL_SYSLOG, type, (size_t)bufp, len); + if (r.error) + return r.error; + *out = (int)r.value; + return 0; +} + +int sys_reboot(int cmd) { + return menix_syscall(SYSCALL_REBOOT, MENIX_REBOOT_MAGIC1, MENIX_REBOOT_MAGIC2, cmd).error; +} + +int sys_getcpu(int *cpu) { return menix_syscall(SYSCALL_GETCPU, (size_t)cpu, 0, 0).error; } + +int sys_sysinfo(struct sysinfo *info) { return menix_syscall(SYSCALL_SYSINFO, (size_t)info).error; } + +int sys_swapon(const char *path, int flags) { + return menix_syscall(SYSCALL_SWAPON, (size_t)path, flags).error; +} + +int sys_swapoff(const char *path) { return menix_syscall(SYSCALL_SWAPOFF, (size_t)path).error; } + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/menix/generic/posix.cpp b/user/include/mlibc/sysdeps/menix/generic/posix.cpp new file mode 100644 index 0000000..278241a --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/generic/posix.cpp @@ -0,0 +1,767 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +[[noreturn]] void sys_exit(int status) { + menix_syscall(SYSCALL_EXIT, status); + __builtin_unreachable(); +} + +[[noreturn]] void sys_thread_exit() { + menix_syscall(SYSCALL_THREAD_EXIT, 0); + __builtin_unreachable(); +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec ts; + auto r = menix_syscall(SYSCALL_CLOCK_GET, clock, (size_t)&ts); + if (r.error) + return r.error; + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + return 0; +} + +int sys_clock_getres(int clock, time_t *secs, long *nanos) { + struct timespec ts; + auto r = menix_syscall(SYSCALL_CLOCK_GETRES, clock, (size_t)&ts); + if (r.error) + return r.error; + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + return 0; +} + +int sys_flock(int fd, int options) { + auto r = menix_syscall(SYSCALL_FLOCK, fd, options); + return r.error; +} + +int sys_open_dir(const char *path, int *handle) { return sys_open(path, O_RDONLY | O_DIRECTORY, 0600, handle); } + +int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read) { + auto r = menix_syscall(SYSCALL_GETDENTS, handle, (size_t)buffer, (size_t)max_size); + if (r.error) { + return r.error; + } + *bytes_read = r.value; + return 0; +} + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + auto r = menix_syscall(SYSCALL_WRITE, fd, (size_t)buf, count); + if (r.error) + return r.error; + *bytes_written = r.value; + return 0; +} + +int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + auto r = menix_syscall(SYSCALL_PREAD, fd, (size_t)buf, n, off); + if (r.error) + return r.error; + *bytes_read = r.value; + return 0; +} + +int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_read) { + auto r = menix_syscall(SYSCALL_PWRITE, fd, (size_t)buf, n, off); + if (r.error) + return r.error; + *bytes_read = r.value; + return 0; +} + +int sys_access(const char *path, int mode) { return sys_faccessat(AT_FDCWD, path, mode, 0); } + +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + return menix_syscall(SYSCALL_FACCESSAT, dirfd, (size_t)pathname, mode, flags).error; +} + +int sys_dup(int fd, int flags, int *newfd) { + auto r = menix_syscall(SYSCALL_DUP, fd, flags); + if (r.error) + return r.error; + *newfd = r.value; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + // dup2 is roughly equal to dup3. + return menix_syscall(SYSCALL_DUP3, fd, newfd, flags).error; +} + +int sys_isatty(int fd) { + struct winsize ws; + // If we're a TTY then this call will succeed. + if (!sys_ioctl(fd, TIOCGWINSZ, &ws, 0)) + return 0; + + return ENOTTY; +} + +int sys_statvfs(const char *path, struct statvfs *out) { + return menix_syscall(SYSCALL_STATVFS, (size_t)path, (size_t)out).error; +} + +int sys_fstatvfs(int fd, struct statvfs *out) { + return menix_syscall(SYSCALL_FSTATVFS, fd, (size_t)out).error; +} + +int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length) { + return sys_readlinkat(AT_FDCWD, path, buffer, max_size, length); +} + +int sys_readlinkat(int dirfd, const char *path, void *buffer, size_t max_size, ssize_t *length) { + auto r = + menix_syscall(SYSCALL_READLINKAT, dirfd, (size_t)path, (size_t)buffer, (size_t)max_size); + if (r.error) + return r.error; + *length = r.value; + return 0; +} + +int sys_rmdir(const char *path) { + return menix_syscall(SYSCALL_RMDIRAT, AT_FDCWD, (size_t)path).error; +} + +int sys_ftruncate(int fd, size_t size) { return menix_syscall(SYSCALL_FTRUNCATE, fd, size).error; } + +int sys_fallocate(int fd, off_t offset, size_t size) { + return menix_syscall(SYSCALL_FALLOCATE, fd, offset, size).error; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + return menix_syscall(SYSCALL_UNLINKAT, fd, (size_t)path, flags).error; +} + +int sys_socket(int family, int type, int protocol, int *fd) { + auto r = menix_syscall(SYSCALL_SOCKET, family, type, protocol); + if (r.error) + return r.error; + *fd = (int)r.value; + return 0; +} + +int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length) { + auto r = menix_syscall(SYSCALL_SENDMSG, fd, (size_t)hdr, flags); + if (r.error) + return r.error; + *length = (ssize_t)r.value; + return 0; +} + +ssize_t sys_sendto( + int fd, + const void *buffer, + size_t size, + int flags, + const struct sockaddr *sock_addr, + socklen_t addr_length, + ssize_t *length +) { + auto r = menix_syscall( + SYSCALL_SENDTO, fd, (size_t)buffer, size, flags, (size_t)sock_addr, addr_length + ); + if (r.error) + return r.error; + *length = (ssize_t)r.value; + return 0; +} + +int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length) { + auto r = menix_syscall(SYSCALL_RECVMSG, fd, (size_t)hdr, flags); + if (r.error) + return r.error; + *length = (ssize_t)r.value; + return 0; +} + +ssize_t sys_recvfrom( + int fd, + void *buffer, + size_t size, + int flags, + struct sockaddr *sock_addr, + socklen_t *addr_length, + ssize_t *length +) { + auto r = menix_syscall( + SYSCALL_RECVFROM, fd, (size_t)buffer, size, flags, (size_t)sock_addr, (size_t)addr_length + ); + if (r.error) + return r.error; + *length = (ssize_t)r.value; + return 0; +} + +int sys_listen(int fd, int backlog) { return menix_syscall(SYSCALL_LISTEN, fd, backlog).error; } + +gid_t sys_getgid() { return menix_syscall(SYSCALL_GETGID).value; } +gid_t sys_getegid() { return menix_syscall(SYSCALL_GETEGID).value; } +uid_t sys_getuid() { return menix_syscall(SYSCALL_GETUID).value; } +uid_t sys_geteuid() { return menix_syscall(SYSCALL_GETEUID).value; } +pid_t sys_getpid() { return menix_syscall(SYSCALL_GETPID).value; } +pid_t sys_gettid() { return menix_syscall(SYSCALL_GETTID).value; } +pid_t sys_getppid() { return menix_syscall(SYSCALL_GETPPID).value; } + +int sys_getpgid(pid_t pid, pid_t *pgid) { + auto r = menix_syscall(SYSCALL_GETPGID, pid); + if (r.error) + return r.error; + *pgid = r.value; + return 0; +} + +int sys_getsid(pid_t pid, pid_t *sid) { + auto r = menix_syscall(SYSCALL_GETSID, pid); + if (r.error) + return r.error; + *sid = r.value; + return 0; +} + +int sys_setpgid(pid_t pid, pid_t pgid) { return menix_syscall(SYSCALL_SETPGID, pid, pgid).error; } +int sys_setuid(uid_t uid) { return menix_syscall(SYSCALL_SETUID, uid).error; } +int sys_seteuid(uid_t euid) { return menix_syscall(SYSCALL_SETEUID, euid).error; } +int sys_setgid(gid_t gid) { return menix_syscall(SYSCALL_SETGID, gid).error; } +int sys_setegid(gid_t egid) { return menix_syscall(SYSCALL_SETEGID, egid).error; } + +int sys_getgroups(size_t size, gid_t *list, int *ret) { + auto r = menix_syscall(SYSCALL_GETGROUPS, size, (size_t)list); + if (r.error) + return r.error; + *ret = (int)r.value; + return 0; +} + +int sys_setgroups(size_t size, const gid_t *list) { + return menix_syscall(SYSCALL_SETGROUPS, size, (size_t)list).error; +} + +int sys_sleep(time_t *secs, long *nanos) { + struct timespec req = {.tv_sec = *secs, .tv_nsec = *nanos}; + struct timespec rem = {}; + auto r = menix_syscall(SYSCALL_SLEEP, (size_t)&req, (size_t)&rem); + if (r.error) + return r.error; + *secs = rem.tv_sec; + *nanos = rem.tv_nsec; + return 0; +} + +void sys_yield() { menix_syscall(SYSCALL_YIELD); } + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + if (ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } +again: + auto r = menix_syscall(SYSCALL_WAITPID, pid, (size_t)status, flags); + if (r.error) { + if (r.error == EINTR) + goto again; + return r.error; + } + *ret_pid = (pid_t)r.value; + return 0; +} + +int sys_fork(pid_t *child) { + auto r = menix_syscall(SYSCALL_FORK); + if (r.error) + return r.error; + *child = r.value; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + return menix_syscall(SYSCALL_EXECVE, (size_t)path, (size_t)argv, (size_t)envp).error; +} + +int sys_pselect( + int num_fds, + fd_set *read_set, + fd_set *write_set, + fd_set *except_set, + const struct timespec *timeout, + const sigset_t *sigmask, + int *num_events +) { + auto r = menix_syscall( + SYSCALL_PSELECT, + num_fds, + (size_t)read_set, + (size_t)write_set, + (size_t)except_set, + (size_t)timeout, + (size_t)sigmask + ); + if (r.error) + return r.error; + *num_events = (int)r.value; + return 0; +} + +int sys_getrusage(int scope, struct rusage *usage) { + return menix_syscall(SYSCALL_GETRUSAGE, scope, (size_t)usage).error; +} + +int sys_getrlimit(int resource, struct rlimit *limit) { + return menix_syscall(SYSCALL_GETRLIMIT, resource, (size_t)limit).error; +} + +int sys_setrlimit(int resource, const struct rlimit *limit) { + return menix_syscall(SYSCALL_SETRLIMIT, resource, (size_t)limit).error; +} + +int sys_getpriority(int which, id_t who, int *value) { + auto r = menix_syscall(SYSCALL_GETPRIORITY, which, who); + if (r.error) + return r.error; + *value = r.value; + return 0; +} + +int sys_setpriority(int which, id_t who, int prio) { + return menix_syscall(SYSCALL_GETPRIORITY, which, who, prio).error; +} + +int sys_getparam(pid_t pid, struct sched_param *param) { + return menix_syscall(SYSCALL_SCHED_GETPARAM, pid, (size_t)param).error; +} + +int sys_setparam(pid_t pid, const struct sched_param *param) { + return menix_syscall(SYSCALL_SCHED_GETPARAM, pid, (size_t)param).error; +} + +int sys_getcwd(char *buffer, size_t size) { + return menix_syscall(SYSCALL_GETCWD, (size_t)buffer, size).error; +} + +int sys_chdir(const char *path) { return menix_syscall(SYSCALL_CHDIR, (size_t)path).error; } + +int sys_fchdir(int fd) { return menix_syscall(SYSCALL_FCHDIR, fd).error; }; + +int sys_chroot(const char *path) { return menix_syscall(SYSCALL_CHROOT, (size_t)path).error; } + +int sys_mkdir(const char *path, mode_t mode) { return sys_mkdirat(AT_FDCWD, path, mode); } + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + return menix_syscall(SYSCALL_MKDIRAT, dirfd, (size_t)path, mode).error; +} + +int sys_link(const char *old_path, const char *new_path) { + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); +} + +int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + return menix_syscall( + SYSCALL_LINKAT, olddirfd, (size_t)old_path, newdirfd, (size_t)new_path, flags + ) + .error; +} + +int sys_symlink(const char *target_path, const char *link_path) { + return sys_symlinkat(target_path, AT_FDCWD, link_path); +} + +int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + return menix_syscall(SYSCALL_SYMLINKAT, (size_t)target_path, dirfd, (size_t)link_path).error; +} + +int sys_rename(const char *path, const char *new_path) { + return sys_renameat(AT_FDCWD, path, AT_FDCWD, new_path); +} + +int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + return menix_syscall(SYSCALL_RENAMEAT, olddirfd, (size_t)old_path, newdirfd, (size_t)new_path) + .error; +} + +int sys_fcntl(int fd, int request, va_list args, int *result) { + auto r = menix_syscall(SYSCALL_FCNTL, fd, request, va_arg(args, size_t)); + if (r.error) + return r.error; + *result = (int)r.value; + return 0; +} + +int sys_ttyname(int fd, char *buf, size_t size) { + if (size >= NAME_MAX) { + mlibc::panicLogger() << "ttyname size too small" << frg::endlog; + __builtin_unreachable(); + } + + int res; + return sys_ioctl(fd, TIOCGNAME, (void *)buf, &res); +} + +void sys_sync() { menix_syscall(SYSCALL_SYNC); } + +int sys_fsync(int fd) { return menix_syscall(SYSCALL_FSYNC, fd).error; } + +int sys_fdatasync(int fd) { return menix_syscall(SYSCALL_FDATASYNC, fd).error; } + +int sys_chmod(const char *pathname, mode_t mode) { + return sys_fchmodat(AT_FDCWD, pathname, mode, 0); +} + +int sys_fchmod(int fd, mode_t mode) { return menix_syscall(SYSCALL_FCHMOD, fd, mode).error; } + +int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + return menix_syscall(SYSCALL_FCHMOD, fd, (size_t)pathname, mode, flags).error; +} + +int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + return menix_syscall(SYSCALL_UTIMENSAT, dirfd, (size_t)pathname, (size_t)times, flags).error; +} + +int sys_setsid(pid_t *sid) { + auto r = menix_syscall(SYSCALL_SETSID); + if (r.error) + return r.error; + *sid = (pid_t)r.value; + return 0; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int ret; + return sys_ioctl(fd, TCGETS, attr, &ret); +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int req; + switch (optional_action) { + case TCSANOW: + req = TCSETS; + break; + case TCSADRAIN: + req = TCSETSW; + break; + case TCSAFLUSH: + req = TCSETSF; + break; + default: + return EINVAL; + } + + int ret; + return sys_ioctl(fd, req, (void *)attr, &ret); +} + +int sys_pipe(int *fds, int flags) { return menix_syscall(SYSCALL_PIPE, (size_t)fds, flags).error; } + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + auto r = menix_syscall(SYSCALL_SOCKETPAIR, domain, type_and_flags, proto); + if (r.error) + return r.error; + *fds = (int)r.value; + return 0; +} + +int sys_ppoll( + struct pollfd *fds, + nfds_t count, + const struct timespec *timeout, + const sigset_t *sigmask, + int *num_events +) { + auto r = menix_syscall(SYSCALL_PPOLL, (size_t)fds, count, (size_t)timeout, (size_t)sigmask); + if (r.error) + return r.error; + *num_events = (int)r.value; + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + + return sys_ppoll(fds, count, timeout != -1 ? &ts : NULL, NULL, num_events); +} + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + auto r = menix_syscall(SYSCALL_IOCTL, fd, request, (size_t)arg); + if (r.error) + return r.error; + if (result) + *result = r.value; + return 0; +} + +int +sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { + return menix_syscall(SYSCALL_GETSOCKOPT, fd, layer, number, (size_t)buffer, (size_t)size).error; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + return menix_syscall(SYSCALL_SETSOCKOPT, fd, layer, number, (size_t)buffer, size).error; +} + +int sys_shutdown(int sockfd, int how) { return menix_syscall(SYSCALL_SHUTDOWN, sockfd, how).error; } + +int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + return menix_syscall(SYSCALL_SIGPROCMASK, how, (size_t)set, (size_t)retrieve).error; +} + +int +sys_sigaction(int sig, const struct sigaction *__restrict act, struct sigaction *__restrict oact) { + return menix_syscall(SYSCALL_SIGACTION, sig, (size_t)act, (size_t)oact).error; +} + +int sys_sigtimedwait( + const sigset_t *__restrict set, + siginfo_t *__restrict info, + const struct timespec *__restrict timeout, + int *out_signal +) { + auto r = menix_syscall(SYSCALL_SIGTIMEDWAIT, (size_t)set, (size_t)info, (size_t)timeout); + if (r.error) + return r.error; + *out_signal = (int)r.value; + return 0; +} + +int sys_kill(int pid, int signal) { return menix_syscall(SYSCALL_KILL, pid, signal).error; } + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + return menix_syscall( + SYSCALL_ACCEPT, fd, (size_t)newfd, (size_t)addr_ptr, (size_t)addr_length, flags + ) + .error; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + return menix_syscall(SYSCALL_BIND, fd, (size_t)addr_ptr, addr_length).error; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + return menix_syscall(SYSCALL_CONNECT, fd, (size_t)addr_ptr, addr_length).error; +} + +int sys_sockname( + int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length +) { + auto r = menix_syscall(SYSCALL_GETSOCKNAME, fd, (size_t)addr_ptr, (size_t)&max_addr_length); + if (r.error) + return r.error; + *actual_length = max_addr_length; + return 0; +} + +int sys_peername( + int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length +) { + auto r = menix_syscall(SYSCALL_GETPEERNAME, fd, (size_t)addr_ptr, (size_t)&max_addr_length); + if (r.error) + return r.error; + *actual_length = (socklen_t)max_addr_length; + return 0; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + struct utsname name; + int i = sys_uname(&name); + if (i) + return i; + if (bufsize >= sizeof(name.nodename)) + bufsize = sizeof(name.nodename) - 1; + memcpy(buffer, name.nodename, bufsize); + return 0; +} + +int sys_sethostname(const char *buffer, size_t bufsize) { + struct utsname name = {}; + if (bufsize >= sizeof(name.nodename)) + bufsize = sizeof(name.nodename) - 1; + memcpy(name.nodename, buffer, bufsize); + return menix_syscall(SYSCALL_SETUNAME, (size_t)&name).error; +} + +int sys_mkfifoat(int dirfd, const char *path, mode_t mode) { + return sys_mknodat(dirfd, path, S_IFIFO | mode, 0); +} + +int sys_getentropy(void *buffer, size_t length) { + return menix_syscall(SYSCALL_GETENTROPY, (size_t)buffer, length).error; +} + +int sys_mknodat(int dirfd, const char *path, int mode, int dev) { + return menix_syscall(SYSCALL_MKNODAT, dirfd, (size_t)path, mode, dev).error; +} + +int sys_umask(mode_t mode, mode_t *old) { + auto r = menix_syscall(SYSCALL_UMASK, mode); + if (r.error) + return r.error; + *old = (mode_t)r.value; + return 0; +} + +int sys_tgkill(int pid, int tid, int sig) { + return menix_syscall(SYSCALL_THREAD_KILL, pid, tid, sig).error; +} + +int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { + return menix_syscall(SYSCALL_FCHOWNAT, dirfd, (size_t)pathname, owner, group, flags).error; +} + +int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + return menix_syscall(SYSCALL_SIGALTSTACK, (size_t)ss, (size_t)oss).error; +} + +int sys_sigsuspend(const sigset_t *set) { + menix_syscall(SYSCALL_SIGSUSPEND, (size_t)set); + return EINTR; +} + +int sys_sigpending(sigset_t *set) { return menix_syscall(SYSCALL_SIGPENDING, (size_t)set).error; } + +int sys_madvise(void *addr, size_t length, int advice) { + return menix_syscall(SYSCALL_MADVISE, (size_t)addr, length, advice).error; +} + +int sys_getitimer(int which, struct itimerval *curr_value) { + return menix_syscall(SYSCALL_ITIMER_GET, which, (size_t)curr_value).error; +} + +int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + return menix_syscall(SYSCALL_ITIMER_SET, which, (size_t)new_value, (size_t)old_value).error; +} + +int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res) { + return menix_syscall(SYSCALL_TIMER_CREATE, (size_t)clk, (size_t)evp, (size_t)res).error; +} + +int sys_timer_settime( + timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old +) { + return menix_syscall(SYSCALL_TIMER_SET, (size_t)t, flags, (size_t)val, (size_t)old).error; +} + +int sys_timer_delete(timer_t t) { return menix_syscall(SYSCALL_TIMER_DELETE, (size_t)t).error; } + +int sys_uname(struct utsname *buf) { + auto r = menix_syscall(SYSCALL_GETUNAME, (size_t)buf); + return r.error; +} + +int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) { + return menix_syscall(SYSCALL_SETRESUID, ruid, euid, suid).error; +} + +int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + return menix_syscall(SYSCALL_SETRESGID, rgid, egid, sgid).error; +} + +int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + return menix_syscall(SYSCALL_GETRESUID, (size_t)ruid, (size_t)euid, (size_t)suid).error; +} + +int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + return menix_syscall(SYSCALL_GETRESGID, (size_t)rgid, (size_t)egid, (size_t)sgid).error; +} + +int sys_setreuid(uid_t ruid, uid_t euid) { + return menix_syscall(SYSCALL_SETREUID, ruid, euid).error; +} + +int sys_setregid(gid_t rgid, gid_t egid) { + return menix_syscall(SYSCALL_SETREGID, rgid, egid).error; +} + +int sys_unlockpt(int fd) { + int unlock = 0; + if (int e = sys_ioctl(fd, TIOCSPTLCK, &unlock, NULL); e) + return e; + return 0; +} + +int sys_thread_getname(void *tcb, char *name, size_t size) { + auto t = reinterpret_cast(tcb); + return menix_syscall(SYSCALL_THREAD_GETNAME, t->tid, (size_t)name, size).error; +} + +int sys_thread_setname(void *tcb, const char *name) { + auto t = reinterpret_cast(tcb); + return menix_syscall(SYSCALL_THREAD_SETNAME, t->tid, (size_t)name).error; +} + +int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) { + return menix_syscall(SYSCALL_WAITID, idtype, id, (size_t)info, options).error; +} + +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if (int e = sys_ioctl(fd, TIOCGPTN, &index, NULL); e) + return e; + if ((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +int sys_if_indextoname(unsigned int index, char *name) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if (r) + return r; + + struct ifreq ifr; + ifr.ifr_ifindex = index; + + int ret = sys_ioctl(fd, SIOCGIFNAME, &ifr, NULL); + close(fd); + + if (ret) { + if (ret == ENODEV) + return ENXIO; + return ret; + } + + strncpy(name, ifr.ifr_name, IF_NAMESIZE); + + return 0; +} + +int sys_if_nametoindex(const char *name, unsigned int *ret) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if (r) + return r; + + struct ifreq ifr; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + + r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, NULL); + close(fd); + + if (r) { + return r; + } + + *ret = ifr.ifr_ifindex; + + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/menix/generic/thread.cpp b/user/include/mlibc/sysdeps/menix/generic/thread.cpp new file mode 100644 index 0000000..84f4f83 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/generic/thread.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + while (__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) { + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + } + + tcb->invokeThreadFunc(entry, user_arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +// Defined in /thread.S +extern "C" void __mlibc_start_thread(); + +#define DEFAULT_STACK 0x200000 + +namespace mlibc { + +int sys_clone(void *tcb, pid_t *pid_out, void *stack) { + (void)tcb; + auto r = menix_syscall(SYSCALL_THREAD_CREATE, (size_t)__mlibc_start_thread, (size_t)stack); + if (r.error) + return r.error; + *pid_out = (pid_t)r.value; + return 0; +} + +int sys_prepare_stack( + void **stack, + void *entry, + void *arg, + void *tcb, + size_t *stack_size, + size_t *guard_size, + void **stack_base +) { + *guard_size = mlibc::page_size; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if (!*stack) { + *stack_base = mmap( + NULL, + *stack_size + mlibc::page_size, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, + -1, + 0 + ); + if (*stack_base == MAP_FAILED) { + return errno; + } + munmap((char *)*stack_base + *stack_size, mlibc::page_size); + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = tcb; // a2 + *--stack_it = arg; // a1 + *--stack_it = entry; // a0 + + *stack = (void *)stack_it; + + return 0; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/access.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/access.h new file mode 100755 index 0000000..cb83931 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/auxv.h new file mode 100755 index 0000000..c43f878 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..0b0ec27 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..7dc8d7c --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..6a42da5 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/dev_t.h new file mode 100755 index 0000000..bca881e --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/epoll.h new file mode 100755 index 0000000..eb4b76d --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/errno.h new file mode 100755 index 0000000..6e507de --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/fcntl.h new file mode 100755 index 0000000..a3031a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/menix/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/gid_t.h new file mode 100755 index 0000000..abce6d6 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/in.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/in.h new file mode 100755 index 0000000..418d1d5 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/ino_t.h new file mode 100755 index 0000000..4c20aca --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/inotify.h new file mode 100755 index 0000000..b5cb282 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/ipc.h new file mode 100755 index 0000000..2c7ffc4 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/linux/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/limits.h new file mode 100755 index 0000000..6c88db2 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5d78fdf --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..bb3b625 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/packet.h new file mode 100755 index 0000000..998ef1a --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/pid_t.h new file mode 100755 index 0000000..baa90f6 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/poll.h new file mode 100755 index 0000000..8ea6a0a --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/ptrace.h new file mode 100755 index 0000000..b2517b2 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/random.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/random.h new file mode 100755 index 0000000..83fc3d9 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/random.h @@ -0,0 +1 @@ +../../../../abis/linux/random.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/reboot.h new file mode 100755 index 0000000..3b1e7c6 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/menix/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/resource.h new file mode 100755 index 0000000..88d7402 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/riscv-hwprobe.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/riscv-hwprobe.h new file mode 100755 index 0000000..e651325 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/riscv-hwprobe.h @@ -0,0 +1 @@ +../../../../abis/linux/riscv-hwprobe.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..e92eb5f --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/linux/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..df7bccf --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/shm.h new file mode 100755 index 0000000..067d8c4 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/sigevent.h new file mode 100755 index 0000000..83d069b --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/linux/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/signal.h new file mode 100755 index 0000000..4dcb0b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/socket.h new file mode 100755 index 0000000..f1dc016 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/stat.h new file mode 100755 index 0000000..2d65cf0 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/menix/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/time.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/time.h new file mode 100755 index 0000000..2a02625 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/uid_t.h new file mode 100755 index 0000000..b306777 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/utsname.h new file mode 100755 index 0000000..b285754 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..bbe258c --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/vt.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/vt.h new file mode 100755 index 0000000..5798a4a --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/vt.h @@ -0,0 +1 @@ +../../../../abis/linux/vt.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/menix/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/menix/include/asm/ioctls.h b/user/include/mlibc/sysdeps/menix/include/asm/ioctls.h new file mode 100644 index 0000000..c84e771 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/asm/ioctls.h @@ -0,0 +1,94 @@ +#ifndef _ASM_IOCTLS_H +#define _ASM_IOCTLS_H + +#define RTC_RD_TIME 1 +#define RTC_SET_TIME 2 +#define FIOQSIZE 0x5460 +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TIOCGNAME 0x5470 +#define TCGETS2 3 +#define TCSETS2 3 +#define TCSETSW2 3 +#define TCSETSF2 3 +#define TIOCGRS485 0x542E +#define TIOCSRS485 0x542F +#define TIOCGPTN 3 +#define TIOCSPTLCK 3 +#define TIOCGDEV 3 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG 0x36 +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT 3 +#define TIOCGPTLCK 3 +#define TIOCGEXCL 3 +#define TIOCGPTPEER 3 +#define TIOCGISO7816 3 +#define TIOCSISO7816 3 +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 +#define TIOCSERGETLSR 0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B +#define TIOCMIWAIT 0x545C +#define TIOCGICOUNT 0x545D +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 +#define TIOCSER_TEMT 0x01 + +#endif /* _ASM_IOCTLS_H */ diff --git a/user/include/mlibc/sysdeps/menix/include/menix/archctl.hpp b/user/include/mlibc/sysdeps/menix/include/menix/archctl.hpp new file mode 100644 index 0000000..2db37e2 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/menix/archctl.hpp @@ -0,0 +1,8 @@ +#ifndef _MENIX_ARCHCTL_HPP +#define _MENIX_ARCHCTL_HPP + +#if defined(__x86_64__) +#define ARCHCTL_SET_FSBASE 0 +#endif + +#endif /* _MENIX_ARCHCTL_HPP */ diff --git a/user/include/mlibc/sysdeps/menix/include/menix/power.hpp b/user/include/mlibc/sysdeps/menix/include/menix/power.hpp new file mode 100644 index 0000000..7c9e268 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/menix/power.hpp @@ -0,0 +1,7 @@ +#ifndef _MENIX_POWER_HPP +#define _MENIX_POWER_HPP + +#define MENIX_REBOOT_MAGIC1 0xDEADBEEF +#define MENIX_REBOOT_MAGIC2 0x1F2E3D4C + +#endif /* _MENIX_POWER_HPP */ diff --git a/user/include/mlibc/sysdeps/menix/include/menix/syscall.hpp b/user/include/mlibc/sysdeps/menix/include/menix/syscall.hpp new file mode 100644 index 0000000..d0789fa --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/include/menix/syscall.hpp @@ -0,0 +1,225 @@ +#ifndef _MENIX_SYSCALL_HPP +#define _MENIX_SYSCALL_HPP + +#include + +#define SYSCALL_EXIT 0 +#define SYSCALL_SYSLOG 1 +#define SYSCALL_GETUNAME 2 +#define SYSCALL_SETUNAME 3 +#define SYSCALL_ARCHCTL 4 +#define SYSCALL_REBOOT 5 +#define SYSCALL_MMAP 6 +#define SYSCALL_MUNMAP 7 +#define SYSCALL_MPROTECT 8 +#define SYSCALL_MADVISE 9 +#define SYSCALL_SIGPROCMASK 10 +#define SYSCALL_SIGSUSPEND 11 +#define SYSCALL_SIGPENDING 12 +#define SYSCALL_SIGACTION 13 +#define SYSCALL_SIGTIMEDWAIT 14 +#define SYSCALL_SIGALTSTACK 15 +#define SYSCALL_EXECVE 16 +#define SYSCALL_FORK 17 +#define SYSCALL_KILL 18 +#define SYSCALL_GETTID 19 +#define SYSCALL_GETPID 20 +#define SYSCALL_GETPPID 21 +#define SYSCALL_WAITID 22 +#define SYSCALL_WAITPID 23 +#define SYSCALL_READ 24 +#define SYSCALL_PREAD 25 +#define SYSCALL_WRITE 26 +#define SYSCALL_PWRITE 27 +#define SYSCALL_SEEK 28 +#define SYSCALL_IOCTL 29 +#define SYSCALL_OPENAT 30 +#define SYSCALL_CLOSE 31 +#define SYSCALL_FSTAT 32 +#define SYSCALL_FSTATAT 33 +#define SYSCALL_STATVFS 34 +#define SYSCALL_FSTATVFS 35 +#define SYSCALL_FACCESSAT 36 +#define SYSCALL_FCNTL 37 +#define SYSCALL_FTRUNCATE 38 +#define SYSCALL_FALLOCATE 39 +#define SYSCALL_UTIMENSAT 40 +#define SYSCALL_PSELECT 41 +#define SYSCALL_MKNODAT 42 +#define SYSCALL_READDIR 43 +#define SYSCALL_GETCWD 44 +#define SYSCALL_CHDIR 45 +#define SYSCALL_FCHDIR 46 +#define SYSCALL_MKDIRAT 47 +#define SYSCALL_RMDIRAT 48 +#define SYSCALL_GETDENTS 49 +#define SYSCALL_RENAMEAT 50 +#define SYSCALL_FCHMOD 51 +#define SYSCALL_FCHMODAT 52 +#define SYSCALL_FCHOWNAT 53 +#define SYSCALL_LINKAT 54 +#define SYSCALL_SYMLINKAT 55 +#define SYSCALL_UNLINKAT 56 +#define SYSCALL_READLINKAT 57 +#define SYSCALL_FLOCK 58 +#define SYSCALL_PPOLL 59 +#define SYSCALL_DUP 60 +#define SYSCALL_DUP3 61 +#define SYSCALL_SYNC 62 +#define SYSCALL_FSYNC 63 +#define SYSCALL_FDATASYNC 64 +#define SYSCALL_GETGROUPS 65 +#define SYSCALL_SETGROUPS 66 +#define SYSCALL_GETSID 67 +#define SYSCALL_SETSID 68 +#define SYSCALL_SETUID 69 +#define SYSCALL_GETUID 70 +#define SYSCALL_SETGID 71 +#define SYSCALL_GETGID 72 +#define SYSCALL_GETEUID 73 +#define SYSCALL_SETEUID 74 +#define SYSCALL_GETEGID 75 +#define SYSCALL_SETEGID 76 +#define SYSCALL_GETPGID 77 +#define SYSCALL_SETPGID 78 +#define SYSCALL_GETRESUID 79 +#define SYSCALL_SETRESUID 80 +#define SYSCALL_GETRESGID 81 +#define SYSCALL_SETRESGID 82 +#define SYSCALL_SETREUID 83 +#define SYSCALL_SETREGID 84 +#define SYSCALL_UMASK 85 +#define SYSCALL_PIPE 86 +#define SYSCALL_FUTEX_WAIT 87 +#define SYSCALL_FUTEX_WAKE 88 +#define SYSCALL_THREAD_CREATE 89 +#define SYSCALL_THREAD_KILL 90 +#define SYSCALL_THREAD_EXIT 91 +#define SYSCALL_THREAD_SETNAME 92 +#define SYSCALL_THREAD_GETNAME 93 +#define SYSCALL_TIMER_CREATE 94 +#define SYSCALL_TIMER_SET 95 +#define SYSCALL_TIMER_DELETE 96 +#define SYSCALL_ITIMER_GET 97 +#define SYSCALL_ITIMER_SET 98 +#define SYSCALL_CLOCK_GET 99 +#define SYSCALL_CLOCK_GETRES 100 +#define SYSCALL_SLEEP 101 +#define SYSCALL_YIELD 102 +#define SYSCALL_CHROOT 103 +#define SYSCALL_MOUNT 104 +#define SYSCALL_UMOUNT 105 +#define SYSCALL_SWAPON 106 +#define SYSCALL_SWAPOFF 107 +#define SYSCALL_SOCKET 108 +#define SYSCALL_SOCKETPAIR 109 +#define SYSCALL_SHUTDOWN 110 +#define SYSCALL_BIND 111 +#define SYSCALL_CONNECT 112 +#define SYSCALL_ACCEPT 113 +#define SYSCALL_LISTEN 114 +#define SYSCALL_GETPEERNAME 115 +#define SYSCALL_GETSOCKNAME 116 +#define SYSCALL_GETSOCKOPT 117 +#define SYSCALL_SETSOCKOPT 118 +#define SYSCALL_SENDMSG 119 +#define SYSCALL_SENDTO 120 +#define SYSCALL_RECVMSG 121 +#define SYSCALL_RECVFROM 122 +#define SYSCALL_GETENTROPY 123 +#define SYSCALL_GETRUSAGE 124 +#define SYSCALL_GETRLIMIT 125 +#define SYSCALL_SETRLIMIT 126 +#define SYSCALL_GETPRIORITY 127 +#define SYSCALL_SETPRIORITY 128 +#define SYSCALL_SCHED_GETPARAM 129 +#define SYSCALL_SCHED_SETPARAM 130 +#define SYSCALL_GETCPU 131 +#define SYSCALL_SYSINFO 132 +#define SYSCALL_PTRACE 133 + +struct syscall_result { + size_t value; + size_t error; +}; +static_assert(sizeof(syscall_result) == 16); + +#ifndef __MLIBC_ABI_ONLY + +[[gnu::always_inline]] +inline syscall_result menix_syscall( + size_t num, + size_t a0 = 0, + size_t a1 = 0, + size_t a2 = 0, + size_t a3 = 0, + size_t a4 = 0, + size_t a5 = 0 +) { + syscall_result r; +#if defined(__x86_64__) + register size_t r3 asm("r10") = a3; + register size_t r4 asm("r8") = a4; + register size_t r5 asm("r9") = a5; + + asm volatile("syscall" + : "=a"(r.value), "=d"(r.error) + : "a"(num), "D"(a0), "S"(a1), "d"(a2), "r"(r3), "r"(r4), "r"(r5) + : "memory", "rcx", "r11"); +#elif defined(__aarch64__) + register size_t snum asm("x8") = num; + register size_t value asm("x0"); + register size_t error asm("x1"); + register size_t r0 asm("x0") = a0; + register size_t r1 asm("x1") = a1; + register size_t r2 asm("x2") = a2; + register size_t r3 asm("x3") = a3; + register size_t r4 asm("x4") = a4; + register size_t r5 asm("x5") = a5; + asm volatile("svc 0" + : "=r"(value), "=r"(error) + : "r"(snum), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5) + : "memory"); + r.value = value; + r.error = error; +#elif defined(__riscv) && (__riscv_xlen == 64) + register size_t snum asm("a7") = num; + register size_t value asm("a0"); + register size_t error asm("a1"); + register size_t r0 asm("a0") = a0; + register size_t r1 asm("a1") = a1; + register size_t r2 asm("a2") = a2; + register size_t r3 asm("a3") = a3; + register size_t r4 asm("a4") = a4; + register size_t r5 asm("a5") = a5; + asm volatile("ecall" + : "=r"(value), "=r"(error) + : "r"(snum), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5) + : "memory"); + r.value = value; + r.error = error; +#elif defined(__loongarch64) + register size_t snum asm("a7") = num; + register size_t value asm("a0"); + register size_t error asm("a1"); + register size_t r0 asm("a0") = a0; + register size_t r1 asm("a1") = a1; + register size_t r2 asm("a2") = a2; + register size_t r3 asm("a3") = a3; + register size_t r4 asm("a4") = a4; + register size_t r5 asm("a5") = a5; + asm volatile("syscall 0" + : "=r"(value), "=r"(error) + : "r"(snum), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5) + : "memory"); + r.value = value; + r.error = error; +#else +#error "Unsupported architecture!" +#endif + return r; +} + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif /* _MENIX_SYSCALL_HPP */ diff --git a/user/include/mlibc/sysdeps/menix/loongarch64/Scrt1.S b/user/include/mlibc/sysdeps/menix/loongarch64/Scrt1.S new file mode 100644 index 0000000..caa0cd1 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/loongarch64/Scrt1.S @@ -0,0 +1,10 @@ +.section .text +.global _start +_start: + move $fp, $zero + move $a0, $sp + la $a1, main + b %plt(__mlibc_entry) + break 0 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/loongarch64/crt1.S b/user/include/mlibc/sysdeps/menix/loongarch64/crt1.S new file mode 100644 index 0000000..4e4a745 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/loongarch64/crt1.S @@ -0,0 +1,10 @@ +.section .text +.global _start +_start: + move $fp, $zero + move $a0, $sp + la $a1, main + b __mlibc_entry + break 0 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/loongarch64/crti.S b/user/include/mlibc/sysdeps/menix/loongarch64/crti.S new file mode 100644 index 0000000..060af0c --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/loongarch64/crti.S @@ -0,0 +1,13 @@ +.section .init +.global _init +_init: + addi.d $sp, $sp, -16 + st.d $ra, $sp, 8 + +.section .fini +.global _fini +_fini: + addi.d $sp, $sp, -16 + st.d $ra, $sp, 8 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/loongarch64/crtn.S b/user/include/mlibc/sysdeps/menix/loongarch64/crtn.S new file mode 100644 index 0000000..ffb0b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/loongarch64/crtn.S @@ -0,0 +1,9 @@ +.section .init + ld.d $ra, $sp, 8 + addi.d $sp, $sp, 16 + +.section .fini + ld.d $ra, $sp, 8 + addi.d $sp, $sp, 16 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/loongarch64/thread.S b/user/include/mlibc/sysdeps/menix/loongarch64/thread.S new file mode 100644 index 0000000..6f778a7 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/loongarch64/thread.S @@ -0,0 +1,12 @@ +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + ld.d $a0, $sp, 0 + ld.d $a1, $sp, 8 + ld.d $a2, $sp, 16 + addi.d $sp, $sp, 16 + bstrins.d $sp, $sp, 3, 0 + b __mlibc_enter_thread + break 0 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/meson.build b/user/include/mlibc/sysdeps/menix/meson.build new file mode 100644 index 0000000..4c4fedf --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/meson.build @@ -0,0 +1,97 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': true, + 'glibc': true, + 'bsd': true, +} + +rtld_sources += files( + 'generic/internal.cpp', +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/internal.cpp', + 'generic/posix.cpp', + 'generic/thread.cpp', + 'generic/linux.cpp', + host_machine.cpu_family() / 'thread.S', +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/vt.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/random.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + 'include/abi-bits/riscv-hwprobe.h', + subdir: 'abi-bits', + follow_symlinks: true, + ) +endif + +if not headers_only + crtstuff = ['crt1', 'Scrt1', 'crti', 'crtn'] + foreach crtthing : crtstuff + crtf = crtthing + '.S' + crt_src = files(host_machine.cpu_family() / crtf) + crt = custom_target( + crtthing, + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: crt_src, + output: crtthing + '.o', + install: true, + install_dir: get_option('libdir'), + ) + endforeach +endif diff --git a/user/include/mlibc/sysdeps/menix/riscv64/Scrt1.S b/user/include/mlibc/sysdeps/menix/riscv64/Scrt1.S new file mode 100644 index 0000000..17cc3fd --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/riscv64/Scrt1.S @@ -0,0 +1,30 @@ +.weak __global_pointer$ +.hidden __global_pointer$ + +.section .text +.global _start +_start: + # Load gp. +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + + mv a0, sp + la a1, main + call __mlibc_entry@plt + unimp + +# Load gp from .preinit_array since it may be used by the executable's .init_array. +# We still load it in _start to account for static binaries. This matches glibc's behavior. +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + +.section .preinit_array,"aw" + .dword load_gp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/riscv64/crt1.S b/user/include/mlibc/sysdeps/menix/riscv64/crt1.S new file mode 100644 index 0000000..faaf407 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/riscv64/crt1.S @@ -0,0 +1,30 @@ +.weak __global_pointer$ +.hidden __global_pointer$ + +.section .text +.global _start +_start: + # Load gp. +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + + mv a0, sp + la a1, main + call __mlibc_entry + unimp + +# Load gp from .preinit_array since it may be used by the executable's .init_array. +# We still load it in _start to account for static binaries. This matches glibc's behavior. +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + +.section .preinit_array,"aw" + .dword load_gp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/riscv64/crti.S b/user/include/mlibc/sysdeps/menix/riscv64/crti.S new file mode 100644 index 0000000..0d6f918 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/riscv64/crti.S @@ -0,0 +1,14 @@ +.section .init +.global _init +_init: + addi sp, sp, -16 + sd ra, 8(sp) + +.section .fini +.global _fini +.type _fini, @function +_fini: + addi sp, sp, -16 + sd ra, 8(sp) + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/riscv64/crtn.S b/user/include/mlibc/sysdeps/menix/riscv64/crtn.S new file mode 100644 index 0000000..67146d3 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/riscv64/crtn.S @@ -0,0 +1,9 @@ +.section .init + ld ra, 8(sp) + addi sp, sp, 16 + +.section .fini + ld ra, 8(sp) + addi sp, sp, 16 + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/riscv64/thread.S b/user/include/mlibc/sysdeps/menix/riscv64/thread.S new file mode 100644 index 0000000..b256ad0 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/riscv64/thread.S @@ -0,0 +1,12 @@ +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + ld a0, 0(sp) + ld a1, 8(sp) + ld a2, 16(sp) + addi sp, sp, 16 + andi sp, sp, -16 + call __mlibc_enter_thread + unimp + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/x86_64/Scrt1.S b/user/include/mlibc/sysdeps/menix/x86_64/Scrt1.S new file mode 100644 index 0000000..77d7fa1 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/x86_64/Scrt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + mov main@GOTPCREL(%rip), %rsi + call *__mlibc_entry@GOTPCREL(%rip) + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/x86_64/crt1.S b/user/include/mlibc/sysdeps/menix/x86_64/crt1.S new file mode 100644 index 0000000..e8abbc4 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/x86_64/crt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + mov $main, %rsi + call __mlibc_entry + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/x86_64/crti.S b/user/include/mlibc/sysdeps/menix/x86_64/crti.S new file mode 100644 index 0000000..6e9cdb3 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/x86_64/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/x86_64/crtn.S b/user/include/mlibc/sysdeps/menix/x86_64/crtn.S new file mode 100644 index 0000000..a947906 --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/x86_64/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/menix/x86_64/thread.S b/user/include/mlibc/sysdeps/menix/x86_64/thread.S new file mode 100644 index 0000000..f026c4c --- /dev/null +++ b/user/include/mlibc/sysdeps/menix/x86_64/thread.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/nyaux/generic/entry.cpp b/user/include/mlibc/sysdeps/nyaux/generic/entry.cpp new file mode 100755 index 0000000..9d0c66a --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/generic/entry.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include + +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; + +extern "C" void __mlibc_entry(uintptr_t *entry_stack, + int (*main_fn)(int argc, char *argv[], + char *env[])) { + __dlapi_enter(entry_stack); + auto result = + main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} diff --git a/user/include/mlibc/sysdeps/nyaux/generic/generic.cpp b/user/include/mlibc/sysdeps/nyaux/generic/generic.cpp new file mode 100755 index 0000000..1d5d4f4 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/generic/generic.cpp @@ -0,0 +1,478 @@ +#include "syscall.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define STUB_ONLY \ + { \ + __ensure(!"STUB_ONLY function was called"); \ + __builtin_unreachable(); \ + } + +namespace mlibc { + +void sys_libc_log(const char *message) { + __syscall2(SYSCALL_DEBUG, (uint64_t)message, strlen(message)); +} +void sys_exit(int status) { + __syscall1(SYSCALL_EXIT, status); + __builtin_unreachable(); +}; +void sys_libc_panic() { + sys_libc_log("\nMLIBC PANIC\n"); + sys_exit(1); +} +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + struct __syscall_ret ret = __syscall6( + SYSCALL_MMAP, + (uint64_t)hint, + (uint64_t)size, + (uint64_t)prot, + (uint64_t)flags, + (uint64_t)fd, + (uint64_t)offset + ); + *window = (void *)ret.ret; + return ret.err; +}; +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0, pointer); +}; +int sys_vm_protect(void *pointer, size_t size, int prot) { return 0; } +int sys_anon_free(void *pointer, size_t size) { + __syscall2(SYSCALL_FREE, (uint64_t)pointer, size); + return 0; +}; +int sys_close(int fd) { + __syscall_ret ret = __syscall1(SYSCALL_CLOSE, fd); + + if (ret.err != 0) + return ret.err; + + return 0; +}; +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) STUB_ONLY; +int sys_futex_wake(int *pointer) { + // sys_libc_log("sys futex wake is a stub"); + return 0; +}; +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + __syscall_ret ret = __syscall4(SYSCALL_OPENAT, dirfd, (uint64_t)path, flags, mode); + + if (ret.err != 0) + return ret.err; + + *fd = (int)ret.ret; + return 0; +} + +uid_t sys_geteuid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} +int sys_gethostname(char *buffer, size_t bufsize) { + if (bufsize >= 6) { + memcpy(buffer, "nyaux", 6); + } + return 0; +} +int sys_uname(struct utsname *buf) { + + memcpy(buf->sysname, "Nyaux", sizeof("Nyaux")); + memcpy(buf->release, "1.0", sizeof("1.0")); + return 0; +} + +gid_t sys_getgid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +int sys_setgid(gid_t gid) { + (void)gid; + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +pid_t sys_getpgid(pid_t pid, pid_t *pgid) { + (void)pid; + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + *pgid = 0; + return 0; +} + +gid_t sys_getegid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + (void)pid; + (void)pgid; + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +int sys_ttyname(int fd, char *buf, size_t size) { + (void)fd; + (void)buf; + (void)size; + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return ENOSYS; +} +uid_t sys_getuid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + __syscall_ret ret = __syscall3(SYSCALL_READ, fd, (uint64_t)buf, count); + + if (ret.err != 0) { + return ret.err; + } + + *bytes_read = (ssize_t)ret.ret; + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + __syscall_ret ret = __syscall3(SYSCALL_SEEK, fd, offset, whence); + + if (ret.err != 0) { + return ret.err; + } + + *new_offset = (off_t)ret.ret; + return 0; +} +int sys_tcb_set(void *pointer) { + __syscall_ret ret = __syscall1(SYSCALL_SETFSBASE, (uint64_t)pointer); + if (ret.err != 0) { + return ret.err; + } + return 0; +}; +int sys_isatty(int fd) { + __syscall_ret ret = __syscall1(SYSCALL_ISATTY, fd); + if (ret.err != 0) { + return ret.err; + } + + return ret.ret; +} +int sys_vm_unmap(void *pointer, size_t size) STUB_ONLY; +int sys_clock_get(int clock, time_t *secs, long *nanos) { + __syscall_ret ret = __syscall3(SYSCALL_CLOCKGET, clock, (uint64_t)secs, (uint64_t)nanos); + if (ret.err != 0) + return ret.err; + return 0; +} +#ifndef MLIBC_BUILDING_RTLD +int sys_getcwd(char *buffer, size_t size) { + __syscall_ret ret = __syscall2(SYSCALL_GETCWD, (uint64_t)buffer, size); + + if (ret.err != 0) + return ret.err; + + return 0; +} +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + __syscall_ret ret = __syscall3(SYSCALL_WRITE, fd, (uint64_t)buf, count); + + if (ret.err != 0) { + return ret.err; + } + + *bytes_written = (ssize_t)ret.ret; + + return 0; +} + +pid_t sys_getpid() { + __syscall_ret ret = __syscall0(16); + return ret.ret; +} +#endif +pid_t sys_getppid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!" << frg::endlog; + + return 0; +} +#ifndef MLIBC_BUILDING_RTLD +int sys_fork(pid_t *child) { + __syscall_ret ret = __syscall0(SYSCALL_FORK); + + if (ret.err != 0) { + return ret.err; + } + + *child = (pid_t)ret.ret; + return 0; +} +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + __syscall_ret ret = __syscall3(SYSCALL_IOCTL, fd, request, (uint64_t)arg); + + if (ret.err != 0) + return ret.err; + *result = (int)ret.ret; + return 0; +} +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + __syscall_ret ret = __syscall3(SYSCALL_POLL, (uint64_t)fds, count, timeout); + if (ret.err != 0) + return ret.err; + + *num_events = (int)ret.ret; + return 0; +} +int sys_fcntl(int fd, int request, va_list args, int *result) { + // __syscall_ret ret = __syscall(12, fd, request, va_arg(args, uint64_t)); + + // if (ret.errno != 0) + // return ret.errno; + + // *result = (ssize_t)ret.ret; + // return 0; + mlibc::infoLogger() << "mlibc: fd " << fd << " request " << request << frg::endlog; + return ENOSYS; +} +int sys_ppoll( + struct pollfd *fds, + int nfds, + const struct timespec *timeout, + const sigset_t *sigmask, + int *num_events +) { + sigset_t origmask; + int timeoutr; + int ret; + + timeoutr = (timeout == NULL) ? -1 : (timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000); + pthread_sigmask(SIG_SETMASK, sigmask, &origmask); + ret = sys_poll(fds, nfds, timeoutr, num_events); + pthread_sigmask(SIG_SETMASK, &origmask, NULL); + return ret; +} +int sys_pselect( + int nfds, + fd_set *read_set, + fd_set *write_set, + fd_set *except_set, + const struct timespec *timeout, + const sigset_t *sigmask, + int *num_events +) { + // this is a stub to please bash + struct pollfd *fds = (struct pollfd *)calloc(nfds, sizeof(struct pollfd)); + if (fds == NULL) { + return ENOMEM; + } + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set)) + fd->events |= POLLIN; // TODO: Additional events. + if (write_set && FD_ISSET(i, write_set)) + fd->events |= POLLOUT; // TODO: Additional events. + if (except_set && FD_ISSET(i, except_set)) + fd->events |= POLLPRI; + + if (!fd->events) { + fd->fd = -1; + continue; + } + + fd->fd = i; + } + + int e = sys_ppoll(fds, nfds, timeout, sigmask, num_events); + + if (e != 0) { + free(fds); + return e; + } + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set) && fd->revents & (POLLIN | POLLERR | POLLHUP)) { + FD_SET(i, &res_read_set); + } + + if (write_set && FD_ISSET(i, write_set) && fd->revents & (POLLOUT | POLLERR | POLLHUP)) { + FD_SET(i, &res_write_set); + } + + if (except_set && FD_ISSET(i, except_set) && fd->revents & POLLPRI) { + FD_SET(i, &res_except_set); + } + } + + free(fds); + + if (read_set) + *read_set = res_read_set; + if (write_set) + *write_set = res_write_set; + if (except_set) + *except_set = res_except_set; + + return 0; +} +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int ret; + + switch (optional_action) { + case TCSANOW: + optional_action = TCSETS; + break; + case TCSADRAIN: + optional_action = TCSETS; + break; + case TCSAFLUSH: + optional_action = TCSETS; + break; + default: + __ensure(!"Unsupported tcsetattr"); + } + + if (int r = sys_ioctl(fd, optional_action, (void *)attr, &ret) != 0) { + return r; + } + + return 0; +} +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + if (ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + +again: + __syscall_ret ret = __syscall3(SYSCALL_WAITPID, pid, (uint64_t)status, flags); + + if (ret.err != 0) { + if (ret.err == EINTR) { + goto again; + } + + return ret.err; + } + + *ret_pid = (pid_t)ret.ret; + return 0; +} +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + __syscall_ret ret = __syscall3(SYSCALL_EXECVE, (uint64_t)path, (uint64_t)argv, (uint64_t)envp); + if (ret.ret != 0) { + return ret.err; + } else { + mlibc::infoLogger() << "mlibc: kernel failed execve syscall" << frg::endlog; + __builtin_unreachable(); + } +} +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + __syscall_ret ret = __syscall4(SYSCALL_FACCESSAT, dirfd, (uint64_t)pathname, mode, flags); + + if (ret.err != 0) { + return ret.err; + } + + return 0; +} + +int sys_access(const char *path, int mode) { return sys_faccessat(AT_FDCWD, path, mode, 0); } +#endif +int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + return ENOSYS; +} +int sys_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { + return ENOSYS; +} +int sys_tcgetattr(int fd, struct termios *attr) { + int ret; + + if (int r = sys_ioctl(fd, TCGETS, attr, &ret) != 0) { + return r; + } + + return 0; +} +int sys_dup(int fd, int flags, int *newfd) { + (void)flags; + __syscall_ret ret = __syscall2(SYSCALL_DUP, fd, flags); + + if (ret.err != 0) + return ret.err; + + *newfd = (ssize_t)ret.ret; + return 0; +} +int sys_dup2(int fd, int flags, int newfd) { + __syscall_ret ret = __syscall3(SYSCALL_DUP2, fd, newfd, flags); + + if (ret.err != 0) + return ret.err; + + return 0; +} +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + __syscall_ret ret; + switch (fsfdt) { + case fsfd_target::fd: { + ret = __syscall2(SYSCALL_FSTAT, fd, (uint64_t)statbuf); + if (ret.err != 0) { + return ret.err; + } + return ret.ret; + break; + } + case fsfd_target::path: { + int fd = 0; + int bad = sys_openat(AT_FDCWD, path, flags, O_RDONLY, &fd); + if (bad != 0) { + return bad; + } + ret = __syscall2(SYSCALL_FSTAT, fd, (uint64_t)statbuf); + bad = sys_close(fd); + // ret = __syscall(11, AT_FDCWD, path, statbuf, flags); + return ret.ret; + break; + } + case fsfd_target::fd_path: { + mlibc::infoLogger() << "mlibc: statfd_path is a stub" << frg::endlog; + // ret = __syscall(11, fd, path, statbuf, flags); + return ENOSYS; + break; + } + default: { + __ensure(!"stat: Invalid fsfdt"); + __builtin_unreachable(); + } + } + if (ret.err != 0) + return ret.err; + return ret.ret; +} + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/nyaux/generic/syscall.h b/user/include/mlibc/sysdeps/nyaux/generic/syscall.h new file mode 100755 index 0000000..05aa39d --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/generic/syscall.h @@ -0,0 +1,76 @@ +#pragma once +#include +struct __syscall_ret { + uint64_t ret; + uint64_t err; +}; + +static __syscall_ret __syscall6(int number, uint64_t arg1, uint64_t arg2, + uint64_t arg3, uint64_t arg4, uint64_t arg5, + uint64_t arg6) { + struct __syscall_ret ret; + register uint64_t arg_r8 asm("r8") = arg4; + register uint64_t arg_r9 asm("r9") = arg5; + register uint64_t arg_r10 asm("r10") = arg6; + asm volatile("syscall" + : "=a"(ret.ret), "=d"(ret.err) + : "a"(number), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg_r8), + "r"(arg_r9), "r"(arg_r10) + : "rcx", "r11", "memory"); + return ret; +} +static __syscall_ret __syscall5(int number, uint64_t arg1, uint64_t arg2, + uint64_t arg3, uint64_t arg4, uint64_t arg5) { + struct __syscall_ret ret; + register uint64_t arg_r8 asm("r8") = arg4; + register uint64_t arg_r9 asm("r9") = arg5; + asm volatile("syscall" + : "=a"(ret.ret), "=d"(ret.err) + : "a"(number), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg_r8), + "r"(arg_r9) + : "rcx", "r11", "memory"); + return ret; +} +static __syscall_ret __syscall4(int number, uint64_t arg1, uint64_t arg2, + uint64_t arg3, uint64_t arg4) { + struct __syscall_ret ret; + register uint64_t arg_r8 asm("r8") = arg4; + asm volatile("syscall" + : "=a"(ret.ret), "=d"(ret.err) + : "a"(number), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg_r8) + : "rcx", "r11", "memory"); + return ret; +} +static __syscall_ret __syscall3(int number, uint64_t arg1, uint64_t arg2, + uint64_t arg3) { + struct __syscall_ret ret; + asm volatile("syscall" + : "=a"(ret.ret), "=d"(ret.err) + : "a"(number), "D"(arg1), "S"(arg2), "d"(arg3) + : "rcx", "r11", "memory"); + return ret; +} +static __syscall_ret __syscall2(int number, uint64_t arg1, uint64_t arg2) { + struct __syscall_ret ret; + asm volatile("syscall" + : "=a"(ret.ret), "=d"(ret.err) + : "a"(number), "D"(arg1), "S"(arg2) + : "rcx", "r11", "memory"); + return ret; +} +static __syscall_ret __syscall1(int number, uint64_t arg1) { + struct __syscall_ret ret; + asm volatile("syscall" + : "=a"(ret.ret), "=d"(ret.err) + : "a"(number), "D"(arg1) + : "rcx", "r11", "memory"); + return ret; +} +static __syscall_ret __syscall0(int number) { + struct __syscall_ret ret; + asm volatile("syscall" + : "=a"(ret.ret), "=d"(ret.err) + : "a"(number) + : "rcx", "r11", "memory"); + return ret; +} \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/access.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/access.h new file mode 100755 index 0000000..cb83931 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/auxv.h new file mode 100755 index 0000000..c43f878 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..0b0ec27 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..7dc8d7c --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..6a42da5 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/dev_t.h new file mode 100755 index 0000000..bca881e --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/epoll.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/epoll.h new file mode 100755 index 0000000..eb4b76d --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/errno.h new file mode 100755 index 0000000..6e507de --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fcntl.h new file mode 100755 index 0000000..463e2c9 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/gid_t.h new file mode 100755 index 0000000..abce6d6 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/in.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/in.h new file mode 100755 index 0000000..418d1d5 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ino_t.h new file mode 100755 index 0000000..4c20aca --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/inotify.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/inotify.h new file mode 100755 index 0000000..b5cb282 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ipc.h new file mode 100755 index 0000000..2c7ffc4 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/linux/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/limits.h new file mode 100755 index 0000000..6c88db2 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5d78fdf --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..bb3b625 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/packet.h new file mode 100755 index 0000000..998ef1a --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/pid_t.h new file mode 100755 index 0000000..baa90f6 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/poll.h new file mode 100755 index 0000000..8ea6a0a --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ptrace.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ptrace.h new file mode 100755 index 0000000..b2517b2 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/random.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/random.h new file mode 100755 index 0000000..83fc3d9 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/random.h @@ -0,0 +1 @@ +../../../../abis/linux/random.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/reboot.h new file mode 100755 index 0000000..77013a4 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/resource.h new file mode 100755 index 0000000..88d7402 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..e92eb5f --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/linux/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..df7bccf --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/shm.h new file mode 100755 index 0000000..067d8c4 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/sigevent.h new file mode 100755 index 0000000..83d069b --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/linux/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/signal.h new file mode 100755 index 0000000..4dcb0b7 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/socket.h new file mode 100755 index 0000000..f1dc016 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/stat.h new file mode 100755 index 0000000..1f63b41 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statfs.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statfs.h new file mode 100755 index 0000000..e3d202f --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statvfs.h new file mode 100755 index 0000000..1fc80c2 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statx.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statx.h new file mode 100755 index 0000000..8702a1d --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/statx.h @@ -0,0 +1 @@ +../../../../abis/linux/statx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/time.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/time.h new file mode 100755 index 0000000..2a02625 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/uid_t.h new file mode 100755 index 0000000..b306777 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..8617643 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/linux/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utmpx.h new file mode 100755 index 0000000..c6a2677 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/linux/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utsname.h new file mode 100755 index 0000000..b285754 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..bbe258c --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/vt.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/vt.h new file mode 100755 index 0000000..5798a4a --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/vt.h @@ -0,0 +1 @@ +../../../../abis/linux/vt.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/abi-bits/xattr.h b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/xattr.h new file mode 100755 index 0000000..66412d7 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/include/nyaux/syscalls.h b/user/include/mlibc/sysdeps/nyaux/include/nyaux/syscalls.h new file mode 100644 index 0000000..9be5465 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/include/nyaux/syscalls.h @@ -0,0 +1,27 @@ +#ifndef _NYAUX_SYSCALL_H +#define _NYAUX_SYSCALL_H + +#define SYSCALL_EXIT 0 +#define SYSCALL_DEBUG 1 +#define SYSCALL_SETFSBASE 2 +#define SYSCALL_MMAP 3 +#define SYSCALL_OPENAT 4 +#define SYSCALL_READ 5 +#define SYSCALL_SEEK 6 +#define SYSCALL_CLOSE 7 +#define SYSCALL_ISATTY 8 +#define SYSCALL_WRITE 9 +#define SYSCALL_IOCTL 10 +#define SYSCALL_DUP 11 +#define SYSCALL_FSTAT 12 +#define SYSCALL_GETCWD 13 +#define SYSCALL_FORK 14 +#define SYSCALL_WAITPID 15 +#define SYSCALL_GETPID 16 +#define SYSCALL_FREE 17 +#define SYSCALL_EXECVE 18 +#define SYSCALL_FACCESSAT 19 +#define SYSCALL_DUP2 20 +#define SYSCALL_POLL 21 +#define SYSCALL_CLOCKGET 22 +#endif \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/nyaux/meson.build b/user/include/mlibc/sysdeps/nyaux/meson.build new file mode 100755 index 0000000..bd1bba1 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/meson.build @@ -0,0 +1,105 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': true, + 'glibc': true, + 'bsd': true, +} + +rtld_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/generic.cpp' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/random.h', + 'include/abi-bits/vt.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statx.h', + 'include/abi-bits/time.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crt0.S b/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crt0.S new file mode 100755 index 0000000..d0e8213 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crt0.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + lea main(%rip), %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crti.S b/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crti.S new file mode 100755 index 0000000..911b078 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crtn.S b/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crtn.S new file mode 100755 index 0000000..0187e50 --- /dev/null +++ b/user/include/mlibc/sysdeps/nyaux/x86_64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/vinix/.clang-format b/user/include/mlibc/sysdeps/vinix/.clang-format new file mode 100644 index 0000000..4662692 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/.clang-format @@ -0,0 +1,2 @@ +--- +DisableFormat: true diff --git a/user/include/mlibc/sysdeps/vinix/generic/entry.cpp b/user/include/mlibc/sysdeps/vinix/generic/entry.cpp new file mode 100644 index 0000000..e92186a --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/generic/entry.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "syscall.h" + +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; + +struct GPRState { + uint64_t ds; + uint64_t es; + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t rdi; + uint64_t rbp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t err; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}; + +namespace mlibc { + int sys_sigentry(void *sigentry) { + __syscall_ret ret = __syscall(27, sigentry); + if (ret.errno != 0) + return ret.errno; + return 0; + } + + [[noreturn]] int sys_sigreturn(void *context, sigset_t old_mask) { + __syscall(30, context, old_mask); + __builtin_unreachable(); + } +} + +static void __mlibc_sigentry(int which, siginfo_t *siginfo, + void (*sa)(int, siginfo_t *, void *), + GPRState *ret_context, sigset_t prev_mask) { + +/* + size_t *base_ptr = (size_t *)ret_context->rbp; + mlibc::infoLogger() << "Stacktrace:" << frg::endlog; + mlibc::infoLogger() << " [" << (void *)ret_context->rip << "]" << frg::endlog; + for (;;) { + size_t old_bp = base_ptr[0]; + size_t ret_addr = base_ptr[1]; + if (!ret_addr) + break; + size_t off; + mlibc::infoLogger() << " [" << (void *)ret_addr << "]" << frg::endlog; + if (!old_bp) + break; + base_ptr = (size_t *)old_bp; + } +*/ + + switch ((uintptr_t)sa) { + // DFL + case (uintptr_t)(-2): + mlibc::infoLogger() << "mlibc: Unhandled signal " << which << frg::endlog; + mlibc::sys_exit(128 + which); + // IGN + case (uintptr_t)(-3): + break; + default: + sa(which, siginfo, NULL); + break; + } + + mlibc::sys_sigreturn(ret_context, prev_mask); + + __builtin_unreachable(); +} + +extern "C" void __mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + mlibc::sys_sigentry((void *)__mlibc_sigentry); + + __dlapi_enter(entry_stack); + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} diff --git a/user/include/mlibc/sysdeps/vinix/generic/generic.cpp b/user/include/mlibc/sysdeps/vinix/generic/generic.cpp new file mode 100644 index 0000000..60cf70f --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/generic/generic.cpp @@ -0,0 +1,913 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "syscall.h" + +#define STUB_ONLY { \ + __ensure(!"STUB_ONLY function was called"); \ + __builtin_unreachable(); \ +} + +#ifndef MLIBC_BUILDING_RTLD + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +#endif + +namespace mlibc { + +void sys_libc_log(const char *message) { + __syscall(0, message); +} + +void sys_libc_panic() { + sys_libc_log("\nMLIBC PANIC\n"); + sys_exit(1); + __builtin_unreachable(); +} + +void sys_exit(int status) { + __syscall(15, status); + __builtin_unreachable(); +} + +#ifndef MLIBC_BUILDING_RTLD + +[[noreturn]] void sys_thread_exit() { + for (;;); + __builtin_unreachable(); +} + +extern "C" void __mlibc_thread_entry(); + +int sys_clone(void *tcb, pid_t *pid_out, void *stack) { + (void)tcb; + + __syscall_ret ret = __syscall(65, (uintptr_t)__mlibc_thread_entry, (uintptr_t)stack); + int ret_value = (int)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + + *pid_out = ret_value; + return 0; +} + +int sys_kill(pid_t pid, int signal) { + __syscall_ret ret = __syscall(26, pid, signal); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int ret; + + if (int r = sys_ioctl(fd, TCGETS, attr, &ret) != 0) { + return r; + } + + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int ret; + + switch (optional_action) { + case TCSANOW: + optional_action = TCSETS; break; + case TCSADRAIN: + optional_action = TCSETSW; break; + case TCSAFLUSH: + optional_action = TCSETSF; break; + default: + __ensure(!"Unsupported tcsetattr"); + } + + if (int r = sys_ioctl(fd, optional_action, (void *)attr, &ret) != 0) { + return r; + } + + return 0; +} + +#endif + +int sys_tcb_set(void *pointer) { + __syscall(7, pointer); + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD + +int sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + __syscall_ret ret = __syscall(36, fds, nfds, timeout, sigmask); + + if (ret.errno != 0) + return ret.errno; + + *num_events = (int)ret.ret; + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + return sys_ppoll(fds, count, timeout < 0 ? NULL : &ts, NULL, num_events); +} + +int sys_pselect(int nfds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + struct pollfd *fds = (struct pollfd *)calloc(nfds, sizeof(struct pollfd)); + if (fds == NULL) { + return ENOMEM; + } + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set)) + fd->events |= POLLIN; // TODO: Additional events. + if (write_set && FD_ISSET(i, write_set)) + fd->events |= POLLOUT; // TODO: Additional events. + if (except_set && FD_ISSET(i, except_set)) + fd->events |= POLLPRI; + + if (!fd->events) { + fd->fd = -1; + continue; + } + + fd->fd = i; + } + + int e = sys_ppoll(fds, nfds, timeout, sigmask, num_events); + + if (e != 0) { + free(fds); + return e; + } + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set) + && fd->revents & (POLLIN | POLLERR | POLLHUP)) { + FD_SET(i, &res_read_set); + } + + if (write_set && FD_ISSET(i, write_set) + && fd->revents & (POLLOUT | POLLERR | POLLHUP)) { + FD_SET(i, &res_write_set); + } + + if (except_set && FD_ISSET(i, except_set) + && fd->revents & POLLPRI) { + FD_SET(i, &res_except_set); + } + } + + free(fds); + + if (read_set) + *read_set = res_read_set; + if (write_set) + *write_set = res_write_set; + if (except_set) + *except_set = res_except_set; + + return 0; +} + +#endif + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + __syscall_ret ret = __syscall(23, pointer, expected, time); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_futex_wake(int *pointer) { + __syscall_ret ret = __syscall(24, pointer); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + __syscall_ret ret = __syscall(9, fd, request, arg); + + if (ret.errno != 0) + return ret.errno; + + *result = (int)ret.ret; + return 0; +} + +int sys_isatty(int fd) { + struct winsize ws; + int ret; + + if (!sys_ioctl(fd, TIOCGWINSZ, &ws, &ret)) + return 0; + + return ENOTTY; +} + +int sys_getcwd(char *buffer, size_t size) { + __syscall_ret ret = __syscall(25, buffer, size); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +#endif + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + __syscall_ret ret = __syscall(2, dirfd, path, flags, mode); + + if (ret.errno != 0) + return ret.errno; + + *fd = (int)ret.ret; + return 0; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} + +#ifndef MLIBC_BUILDING_RTLD + +int sys_open_dir(const char *path, int *handle) { + return sys_open(path, O_DIRECTORY, 0, handle); +} + +int sys_read_entries(int fd, void *buffer, size_t max_size, size_t *bytes_read) { + (void)max_size; + __syscall_ret ret = __syscall(19, fd, buffer); + + if (ret.ret == (uint64_t)-1 && ret.errno == 0) { + // End of directory. + *bytes_read = 0; + return 0; + } else if (ret.errno != 0) { + return ret.errno; + } + + *bytes_read = sizeof(struct dirent); + return 0; +} + +#endif + +int sys_close(int fd) { + __syscall_ret ret = __syscall(6, fd); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + __syscall_ret ret = __syscall(5, fd, offset, whence); + + if (ret.errno != 0) { + return ret.errno; + } + + *new_offset = (off_t)ret.ret; + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + __syscall_ret ret = __syscall(3, fd, buf, count); + + if (ret.errno != 0) { + return ret.errno; + } + + *bytes_read = (ssize_t)ret.ret; + return 0; +} + +#ifndef MLIBC_BUILDING_RTLD + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + __syscall_ret ret = __syscall(4, fd, buf, count); + + if (ret.errno != 0) { + return ret.errno; + } + + *bytes_written = (ssize_t)ret.ret; + return 0; +} + +int sys_readlink(const char *path, void *data, size_t max_size, ssize_t *length) { + __syscall_ret ret = __syscall(33, AT_FDCWD, path, data, max_size); + + if (ret.errno != 0) { + return ret.errno; + } + + *length = (ssize_t)ret.ret; + return 0; +} + +int sys_link(const char *old_path, const char *new_path) { + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); +} + +int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + __syscall_ret ret = __syscall(58, olddirfd, old_path, newdirfd, new_path, flags); + + if (ret.errno != 0) { + return ret.errno; + } + + return 0; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + __syscall_ret ret = __syscall(35, fd, path, flags); + + if (ret.errno != 0) { + return ret.errno; + } + + return 0; +} + +int sys_fchmod(int fd, mode_t mode) { + __syscall_ret ret = __syscall(57, fd, mode); + + if (ret.errno != 0) { + return ret.errno; + } + + return 0; +} + +int sys_rmdir(const char *path) { + __syscall_ret ret = __syscall(37, AT_FDCWD, path); + + if (ret.errno != 0) { + return ret.errno; + } + + return 0; +} + +#endif + +int sys_vm_map(void *hint, size_t size, int prot, int flags, + int fd, off_t offset, void **window) { + __syscall_ret ret = __syscall(1, hint, size, + (uint64_t)prot << 32 | (uint64_t)flags, fd, offset); + if (ret.errno != 0) + return ret.errno; + + *window = (void *)ret.ret; + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + __syscall_ret ret = __syscall(34, pointer, size); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + __syscall_ret ret = __syscall(48, pointer, size, prot); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_ANONYMOUS, -1, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +#ifndef MLIBC_BUILDING_RTLD + +pid_t sys_getpid() { + __syscall_ret ret = __syscall(31); + + return ret.ret; +} + +pid_t sys_getppid() { + __syscall_ret ret = __syscall(32); + + return ret.ret; +} + +uid_t sys_getuid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +uid_t sys_geteuid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +gid_t sys_getgid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +int sys_setgid(gid_t gid) { + (void)gid; + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +pid_t sys_getpgid(pid_t pid, pid_t *pgid) { + (void)pid; + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + *pgid = 0; + return 0; +} + +gid_t sys_getegid() { + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + (void)pid; (void)pgid; + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return 0; +} + +int sys_ttyname(int fd, char *buf, size_t size) { + (void)fd; (void)buf; (void)size; + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" << frg::endlog; + return ENOSYS; +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec ts; + __syscall_ret ret = __syscall(50, clock, &ts); + + if (ret.errno != 0) { + return ret.errno; + } + + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + __syscall_ret ret; + switch (fsfdt) { + case fsfd_target::fd: { + ret = __syscall(10, fd, statbuf); + break; + } + case fsfd_target::path: { + ret = __syscall(11, AT_FDCWD, path, statbuf, flags); + break; + } + case fsfd_target::fd_path: { + ret = __syscall(11, fd, path, statbuf, flags); + break; + } + default: { + __ensure(!"stat: Invalid fsfdt"); + __builtin_unreachable(); + } + } + if (ret.errno != 0) + return ret.errno; + return ret.ret; +} + +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + __syscall_ret ret = __syscall(20, dirfd, pathname, mode, flags); + + if (ret.errno != 0) { + return ret.errno; + } + + return 0; +} + +int sys_access(const char *path, int mode) { + return sys_faccessat(AT_FDCWD, path, mode, 0); +} + +int sys_pipe(int *fds, int flags) { + __syscall_ret ret = __syscall(21, fds, flags); + + if (ret.errno != 0) { + return ret.errno; + } + + return 0; +} + +int sys_chdir(const char *path) { + __syscall_ret ret = __syscall(18, path); + + if (ret.errno != 0) { + return ret.errno; + } + + return 0; +} + +int sys_mkdir(const char *path, mode_t mode) { + return sys_mkdirat(AT_FDCWD, path, mode); +} + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + __syscall_ret ret = __syscall(22, dirfd, path, mode); + + return ret.errno; +} + +int sys_socket(int domain, int type_and_flags, int proto, int *fd) { + __syscall_ret ret = __syscall(39, domain, type_and_flags, proto); + + if (ret.errno != 0) + return ret.errno; + + *fd = (int)ret.ret; + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + __syscall_ret ret = __syscall(46, domain, type_and_flags, proto, fds); + + return ret.errno; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + __syscall_ret ret = __syscall(40, fd, addr_ptr, addr_length); + + return ret.errno; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + __syscall_ret ret = __syscall(59, fd, addr_ptr, addr_length); + + return ret.errno; +} + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + __syscall_ret ret = __syscall(61, fd, addr_ptr, addr_length); + + if (ret.errno != 0) { + return ret.errno; + } + + *newfd = ret.ret; + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size) { + (void)fd; (void)size; + if(layer == SOL_SOCKET && number == SO_PEERCRED) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_PEERCRED is unimplemented\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else if(layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_SNDBUF is unimplemented\e[39m" << frg::endlog; + *(int *)buffer = 4096; + return 0; + }else if(layer == SOL_SOCKET && number == SO_TYPE) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_TYPE is unimplemented, hardcoding SOCK_STREAM\e[39m" << frg::endlog; + *(int *)buffer = SOCK_STREAM; + return 0; + }else if(layer == SOL_SOCKET && number == SO_ERROR) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is unimplemented, hardcoding 0\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else if(layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_KEEPALIVE is unimplemented, hardcoding 0\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else{ + mlibc::panicLogger() << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } + + return 0; +} + + +int sys_setsockopt(int fd, int layer, int number, + const void *buffer, socklen_t size) { + (void)fd; (void)buffer; (void)size; + if(layer == SOL_SOCKET && number == SO_PASSCRED) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_PASSCRED) is not implemented" + " correctly\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_ATTACH_FILTER) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_ATTACH_FILTER) is not implemented" + " correctly\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_RCVBUFFORCE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not implemented" + " correctly\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_SNDBUF is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_KEEPALIVE is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_REUSEADDR) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEADDR is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == AF_NETLINK && number == SO_ACCEPTCONN) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with AF_NETLINK and SO_ACCEPTCONN is unimplemented\e[39m" << frg::endlog; + return 0; + }else{ + mlibc::panicLogger() << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } +} + +int sys_msg_recv(int sockfd, struct msghdr *hdr, int flags, ssize_t *length) { + __syscall_ret ret = __syscall(62, sockfd, hdr, flags); + + if (ret.errno != 0) { + return ret.errno; + } + + *length = (ssize_t)ret.ret; + return 0; +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + __syscall_ret ret = __syscall(60, fd, addr_ptr, &max_addr_length); + + if (ret.errno != 0) { + return ret.errno; + } + + *actual_length = max_addr_length; + return 0; +} + +int sys_listen(int fd, int backlog) { + __syscall_ret ret = __syscall(41, fd, backlog); + + return ret.errno; +} + +int sys_inotify_create(int flags, int *fd) { + __syscall_ret ret = __syscall(42, flags); + + if (ret.errno != 0) { + return ret.errno; + } + + *fd = (int)ret.ret; + return 0; +} + +int sys_fork(pid_t *child) { + __syscall_ret ret = __syscall(14); + + if (ret.errno != 0) { + return ret.errno; + } + + *child = (pid_t)ret.ret; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + __syscall_ret ret = __syscall(17, path, argv, envp); + + return ret.errno; +} + +int sys_fcntl(int fd, int request, va_list args, int *result) { + __syscall_ret ret = __syscall(12, fd, request, va_arg(args, uint64_t)); + + if (ret.errno != 0) + return ret.errno; + + *result = (ssize_t)ret.ret; + return 0; +} + +int sys_dup(int fd, int flags, int *newfd) { + (void)flags; + __syscall_ret ret = __syscall(12, fd, F_DUPFD, 0); + + if (ret.errno != 0) + return ret.errno; + + *newfd = (ssize_t)ret.ret; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + __syscall_ret ret = __syscall(13, fd, newfd, flags); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + __syscall_ret ret = __syscall(28, how, set, retrieve); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { + __syscall_ret ret = __syscall(29, signum, act, oldact); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_signalfd_create(sigset_t mask, int flags, int *fd) { + __syscall_ret ret = __syscall(45, *fd, mask, flags); + + if (ret.errno != 0) + return ret.errno; + + *fd = (int)ret.ret; + return 0; +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + if(ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + +again: + __syscall_ret ret = __syscall(16, pid, status, flags); + + if (ret.errno != 0) { + if (ret.errno == EINTR) { + goto again; + } + + return ret.errno; + } + + *ret_pid = (pid_t)ret.ret; + return 0; +} + +int sys_getgroups(size_t size, gid_t *list, int *_ret) { + __syscall_ret ret = __syscall(38, size, list); + + if (ret.errno != 0) + return ret.errno; + + *_ret = (int)ret.ret; + return 0; +} + +int sys_mount(const char *source, const char *target, const char *fstype, unsigned long flags, const void *data) { + __syscall_ret ret = __syscall(43, source, target, fstype, flags, data); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_umount2(const char *target, int flags) { + __syscall_ret ret = __syscall(44, target, flags); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + __syscall_ret ret = __syscall(51, buffer, bufsize); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_sethostname(const char *buffer, size_t bufsize) { + __syscall_ret ret = __syscall(52, buffer, bufsize); + + if (ret.errno != 0) + return ret.errno; + + return 0; +} + +int sys_sleep(time_t *secs, long *nanos) { + struct timespec req = { + .tv_sec = *secs, + .tv_nsec = *nanos + }; + struct timespec rem = {0, 0}; + + __syscall_ret ret = __syscall(53, &req, &rem); + + if (ret.errno != 0) + return ret.errno; + + *secs = rem.tv_sec; + *nanos = rem.tv_nsec; + return 0; +} + +int sys_getitimer(int, struct itimerval *) { + mlibc::infoLogger() << "mlibc: sys_getitimer() is unimplemented" << frg::endlog; + return ENOSYS; +} + +int sys_setitimer(int, const struct itimerval *, struct itimerval *) { + mlibc::infoLogger() << "mlibc: sys_setitimer() is unimplemented" << frg::endlog; + return ENOSYS; +} + +#endif + +} // namespace mlibc diff --git a/user/include/mlibc/sysdeps/vinix/generic/mntent.cpp b/user/include/mlibc/sysdeps/vinix/generic/mntent.cpp new file mode 100644 index 0000000..d064af3 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/generic/mntent.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +namespace { + +char *internal_buf; +size_t internal_bufsize; + +} + +#define SENTINEL (char *)&internal_buf + +FILE *setmntent(const char *name, const char *mode) { + return fopen(name, mode); +} + +struct mntent *getmntent(FILE *f) { + static struct mntent mnt; + return getmntent_r(f, &mnt, SENTINEL, 0); +} + +int addmntent(FILE *f, const struct mntent *mnt) { + if(fseek(f, 0, SEEK_END)) { + return 1; + } + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", + mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, + mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +int endmntent(FILE *f) { + if(f) { + fclose(f); + } + return 1; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) { + return strstr(mnt->mnt_opts, opt); +} + +/* Adapted from musl */ +struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { + int n[8]; + bool use_internal = (linebuf == SENTINEL); + int len; + size_t i; + + mnt->mnt_freq = 0; + mnt->mnt_passno = 0; + + do { + if(use_internal) { + getline(&internal_buf, &internal_bufsize, f); + linebuf = internal_buf; + } else { + fgets(linebuf, buflen, f); + } + if(feof(f) || ferror(f)) { + return 0; + } + if(!strchr(linebuf, '\n')) { + fscanf(f, "%*[^\n]%*[\n]"); + errno = ERANGE; + return 0; + } + + len = strlen(linebuf); + if(len > INT_MAX) { + continue; + } + + for(i = 0; i < sizeof n / sizeof *n; i++) { + n[i] = len; + } + + sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + n, n + 1, n + 2, n + 3, n + 4, n + 5, n + 6, n + 7, + &mnt->mnt_freq, &mnt->mnt_passno); + } while(linebuf[n[0]] == '#' || n[1] == len); + + linebuf[n[1]] = 0; + linebuf[n[3]] = 0; + linebuf[n[5]] = 0; + linebuf[n[7]] = 0; + + mnt->mnt_fsname = linebuf + n[0]; + mnt->mnt_dir = linebuf + n[2]; + mnt->mnt_type = linebuf + n[4]; + mnt->mnt_opts = linebuf + n[6]; + + return mnt; +} diff --git a/user/include/mlibc/sysdeps/vinix/generic/mount.cpp b/user/include/mlibc/sysdeps/vinix/generic/mount.cpp new file mode 100644 index 0000000..f10254d --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/generic/mount.cpp @@ -0,0 +1,16 @@ +#include +#include +#include + +int mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data) { + return 0; +} + +int umount(const char *target) { + return umount2(target, 0); +} + +int umount2(const char *target, int flags) { + return 0; +} diff --git a/user/include/mlibc/sysdeps/vinix/generic/reboot.cpp b/user/include/mlibc/sysdeps/vinix/generic/reboot.cpp new file mode 100644 index 0000000..7c86ffd --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/generic/reboot.cpp @@ -0,0 +1,7 @@ +#include +#include +#include + +int reboot(int what) { + return 0; +} diff --git a/user/include/mlibc/sysdeps/vinix/generic/syscall.h b/user/include/mlibc/sysdeps/vinix/generic/syscall.h new file mode 100644 index 0000000..f421220 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/generic/syscall.h @@ -0,0 +1,16 @@ +#include + +struct __syscall_ret { + uint64_t ret; + uint64_t errno; +}; + +__attribute__((naked)) +static __syscall_ret __syscall(int number, ...) { + asm ( + "mov %rcx, %r10\n\t" + "syscall\n\t" + "ret" + ); + (void)number; +} diff --git a/user/include/mlibc/sysdeps/vinix/generic/thread.S b/user/include/mlibc/sysdeps/vinix/generic/thread.S new file mode 100644 index 0000000..47ab6a9 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/generic/thread.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_thread_trampoline + +.section .note.GNU-stack,"",%progbits diff --git a/user/include/mlibc/sysdeps/vinix/generic/thread.cpp b/user/include/mlibc/sysdeps/vinix/generic/thread.cpp new file mode 100644 index 0000000..5186e1f --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/generic/thread.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_thread_trampoline(void *(*fn)(void *), Tcb *tcb, void *arg) { + if (mlibc::sys_tcb_set(tcb)) { + __ensure(!"failed to set tcb for new thread"); + } + + while (__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) { + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + } + + tcb->invokeThreadFunc(reinterpret_cast(fn), arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +#define DEFAULT_STACK 0x400000 + +namespace mlibc { + int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if (!*stack) { + *stack_base = mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; + } +} diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/access.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/access.h new file mode 100755 index 0000000..cb83931 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/auxv.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/auxv.h new file mode 100755 index 0000000..c43f878 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/blkcnt_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/blkcnt_t.h new file mode 100755 index 0000000..0b0ec27 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/blksize_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/blksize_t.h new file mode 100755 index 0000000..7dc8d7c --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/clockid_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/clockid_t.h new file mode 100755 index 0000000..6a42da5 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/dev_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/dev_t.h new file mode 100755 index 0000000..bca881e --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/errno.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/errno.h new file mode 100755 index 0000000..6e507de --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/fcntl.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/fcntl.h new file mode 100755 index 0000000..463e2c9 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/fsblkcnt_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/fsblkcnt_t.h new file mode 100755 index 0000000..898dfb2 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/fsfilcnt_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/fsfilcnt_t.h new file mode 100755 index 0000000..791755c --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/gid_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/gid_t.h new file mode 100755 index 0000000..abce6d6 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/in.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/in.h new file mode 100755 index 0000000..418d1d5 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/ino_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/ino_t.h new file mode 100755 index 0000000..4c20aca --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/ioctls.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/ioctls.h new file mode 100755 index 0000000..595106b --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/ipc.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/ipc.h new file mode 100755 index 0000000..2c7ffc4 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/ipc.h @@ -0,0 +1 @@ +../../../../abis/linux/ipc.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/limits.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/limits.h new file mode 100755 index 0000000..6c88db2 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/mode_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/mode_t.h new file mode 100755 index 0000000..5d78fdf --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/mqueue.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/mqueue.h new file mode 100755 index 0000000..fa87b07 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/msg.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/msg.h new file mode 100755 index 0000000..f402b49 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/nlink_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/nlink_t.h new file mode 100755 index 0000000..bb3b625 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/packet.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/packet.h new file mode 100755 index 0000000..998ef1a --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/pid_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/pid_t.h new file mode 100755 index 0000000..baa90f6 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/poll.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/poll.h new file mode 100755 index 0000000..8ea6a0a --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/reboot.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/reboot.h new file mode 100755 index 0000000..e17dce3 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/vinix/reboot.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/resource.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/resource.h new file mode 100755 index 0000000..88d7402 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/rlim_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/rlim_t.h new file mode 100755 index 0000000..e92eb5f --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/rlim_t.h @@ -0,0 +1 @@ +../../../../abis/linux/rlim_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/seek-whence.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/seek-whence.h new file mode 100755 index 0000000..df7bccf --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/shm.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/shm.h new file mode 100755 index 0000000..067d8c4 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/sigevent.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/sigevent.h new file mode 100755 index 0000000..76ef0a2 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/sigevent.h @@ -0,0 +1 @@ +../../../../abis/vinix/sigevent.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/signal.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/signal.h new file mode 100755 index 0000000..709546b --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/vinix/signal.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/sigval.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/sigval.h new file mode 100755 index 0000000..ccd43a5 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/sigval.h @@ -0,0 +1 @@ +../../../../abis/linux/sigval.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/socket.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/socket.h new file mode 100755 index 0000000..f1dc016 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/socklen_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/socklen_t.h new file mode 100755 index 0000000..41f3b11 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/stat.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/stat.h new file mode 100755 index 0000000..1f63b41 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/statvfs.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/statvfs.h new file mode 100755 index 0000000..cb4eaf1 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/vinix/statvfs.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/suseconds_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/suseconds_t.h new file mode 100755 index 0000000..9ed6597 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/termios.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/termios.h new file mode 100755 index 0000000..ee8f0b0 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/time.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/time.h new file mode 100755 index 0000000..2a02625 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/uid_t.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/uid_t.h new file mode 100755 index 0000000..b306777 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/utmp-defines.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/utmp-defines.h new file mode 100755 index 0000000..03187cb --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/utmp-defines.h @@ -0,0 +1 @@ +../../../../abis/vinix/utmp-defines.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/utmpx.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/utmpx.h new file mode 100755 index 0000000..7478bd5 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/utmpx.h @@ -0,0 +1 @@ +../../../../abis/vinix/utmpx.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/utsname.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/utsname.h new file mode 100755 index 0000000..b285754 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/vm-flags.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/vm-flags.h new file mode 100755 index 0000000..bbe258c --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/abi-bits/wait.h b/user/include/mlibc/sysdeps/vinix/include/abi-bits/wait.h new file mode 100755 index 0000000..feb2840 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/user/include/mlibc/sysdeps/vinix/include/asm/ioctl.h b/user/include/mlibc/sysdeps/vinix/include/asm/ioctl.h new file mode 100644 index 0000000..8cbb364 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/asm/ioctl.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _ASM_GENERIC_IOCTL_H +#define _ASM_GENERIC_IOCTL_H + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +/* + * The following is for compatibility across the various Linux + * platforms. The generic ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 + +/* + * Let any architecture override either of the following before + * including this file. + */ + +#ifndef _IOC_SIZEBITS +# define _IOC_SIZEBITS 14 +#endif + +#ifndef _IOC_DIRBITS +# define _IOC_DIRBITS 2 +#endif + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) + +/* + * Direction bits, which any architecture can choose to override + * before including this file. + * + * NOTE: _IOC_WRITE means userland is writing and kernel is + * reading. _IOC_READ means userland is reading and kernel is writing. + */ + +#ifndef _IOC_NONE +# define _IOC_NONE 0U +#endif + +#ifndef _IOC_WRITE +# define _IOC_WRITE 1U +#endif + +#ifndef _IOC_READ +# define _IOC_READ 2U +#endif + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +#define _IOC_TYPECHECK(t) (sizeof(t)) + +/* + * Used to create numbers. + * + * NOTE: _IOW means userland is writing and kernel is reading. _IOR + * means userland is reading and kernel is writing. + */ +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* used to decode ioctl numbers.. */ +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the drivers/sound files... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#endif /* _ASM_GENERIC_IOCTL_H */ diff --git a/user/include/mlibc/sysdeps/vinix/include/asm/ioctls.h b/user/include/mlibc/sysdeps/vinix/include/asm/ioctls.h new file mode 100644 index 0000000..bdbba9b --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/asm/ioctls.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_GENERIC_IOCTLS_H +#define __ASM_GENERIC_IOCTLS_H + +#include + +/* + * These are the most common definitions for tty ioctl numbers. + * Most of them do not use the recommended _IOC(), but there is + * probably some source code out there hardcoding the number, + * so we might as well use them for all new platforms. + * + * The architectures that use different values here typically + * try to be compatible with some Unix variants for the same + * architecture. + */ + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TIOCSBRK 0x5427 /* BSD compatibility */ +#define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TCGETS2 _IOR('T', 0x2A, struct termios2) +#define TCSETS2 _IOW('T', 0x2B, struct termios2) +#define TCSETSW2 _IOW('T', 0x2C, struct termios2) +#define TCSETSF2 _IOW('T', 0x2D, struct termios2) +#define TIOCGRS485 0x542E +#ifndef TIOCSRS485 +#define TIOCSRS485 0x542F +#endif +#define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T', 0x32, unsigned int) /* Get primary device node of /dev/console */ +#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */ +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG _IOW('T', 0x36, int) /* pty: generate signal */ +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */ +#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ +#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ +#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ +#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) +#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) + +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port __inline__ interrupt counts */ + +/* + * Some arches already define FIOQSIZE due to a historical + * conflict with a Hayes modem-specific ioctl value. + */ +#ifndef FIOQSIZE +# define FIOQSIZE 0x5460 +#endif + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 + +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif /* __ASM_GENERIC_IOCTLS_H */ diff --git a/user/include/mlibc/sysdeps/vinix/include/linux/fb.h b/user/include/mlibc/sysdeps/vinix/include/linux/fb.h new file mode 100644 index 0000000..d5e6d88 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/linux/fb.h @@ -0,0 +1,400 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_FB_H +#define _LINUX_FB_H + +#include +#include + +/* Definitions of frame buffers */ + +#define FB_MAX 32 /* sufficient for now */ + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 +#define FBIO_CURSOR _IOWR('F', 0x08, struct fb_cursor) +/* 0x4607-0x460B are defined below */ +/* #define FBIOGET_MONITORSPEC 0x460C */ +/* #define FBIOPUT_MONITORSPEC 0x460D */ +/* #define FBIOSWITCH_MONIBIT 0x460E */ +#define FBIOGET_CON2FBMAP 0x460F +#define FBIOPUT_CON2FBMAP 0x4610 +#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */ +#define FBIOGET_VBLANK _IOR('F', 0x12, struct fb_vblank) +#define FBIO_ALLOC 0x4613 +#define FBIO_FREE 0x4614 +#define FBIOGET_GLYPH 0x4615 +#define FBIOGET_HWCINFO 0x4616 +#define FBIOPUT_MODEINFO 0x4617 +#define FBIOGET_DISPINFO 0x4618 +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, uint32_t) + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ +#define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ +#define FB_TYPE_FOURCC 5 /* Type identified by a V4L2 FOURCC */ + +#define FB_AUX_TEXT_MDA 0 /* Monochrome text */ +#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ +#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */ +#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */ +#define FB_AUX_TEXT_SVGA_GROUP 8 /* 8-15: SVGA tileblit compatible modes */ +#define FB_AUX_TEXT_SVGA_MASK 7 /* lower three bits says step */ +#define FB_AUX_TEXT_SVGA_STEP2 8 /* SVGA text mode: text, attr */ +#define FB_AUX_TEXT_SVGA_STEP4 9 /* SVGA text mode: text, attr, 2 reserved bytes */ +#define FB_AUX_TEXT_SVGA_STEP8 10 /* SVGA text mode: text, attr, 6 reserved bytes */ +#define FB_AUX_TEXT_SVGA_STEP16 11 /* SVGA text mode: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_SVGA_LAST 15 /* reserved up to 15 */ + +#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */ +#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */ +#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ +#define FB_VISUAL_FOURCC 6 /* Visual identified by a V4L2 FOURCC */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */ +#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */ +#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */ +#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */ +#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */ +#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */ +#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */ +#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */ +#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */ +#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */ +#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */ +#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */ +#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */ +#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */ +#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */ +#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */ +#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */ +#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */ +#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */ +#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */ +#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */ +#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */ +#define FB_ACCEL_NV3 27 /* nVidia RIVA 128 */ +#define FB_ACCEL_NV4 28 /* nVidia RIVA TNT */ +#define FB_ACCEL_NV5 29 /* nVidia RIVA TNT2 */ +#define FB_ACCEL_CT_6555x 30 /* C&T 6555x */ +#define FB_ACCEL_3DFX_BANSHEE 31 /* 3Dfx Banshee */ +#define FB_ACCEL_ATI_RAGE128 32 /* ATI Rage128 family */ +#define FB_ACCEL_IGS_CYBER2000 33 /* CyberPro 2000 */ +#define FB_ACCEL_IGS_CYBER2010 34 /* CyberPro 2010 */ +#define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */ +#define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */ +#define FB_ACCEL_3DLABS_PERMEDIA3 37 /* 3Dlabs Permedia 3 */ +#define FB_ACCEL_ATI_RADEON 38 /* ATI Radeon family */ +#define FB_ACCEL_I810 39 /* Intel 810/815 */ +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 650, 740 */ +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre") */ +#define FB_ACCEL_I830 42 /* Intel 830M/845G/85x/865G */ +#define FB_ACCEL_NV_10 43 /* nVidia Arch 10 */ +#define FB_ACCEL_NV_20 44 /* nVidia Arch 20 */ +#define FB_ACCEL_NV_30 45 /* nVidia Arch 30 */ +#define FB_ACCEL_NV_40 46 /* nVidia Arch 40 */ +#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari V3XT, V5, V8 */ +#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */ +#define FB_ACCEL_OMAP1610 49 /* TI OMAP16xx */ +#define FB_ACCEL_TRIDENT_TGUI 50 /* Trident TGUI */ +#define FB_ACCEL_TRIDENT_3DIMAGE 51 /* Trident 3DImage */ +#define FB_ACCEL_TRIDENT_BLADE3D 52 /* Trident Blade3D */ +#define FB_ACCEL_TRIDENT_BLADEXP 53 /* Trident BladeXP */ +#define FB_ACCEL_CIRRUS_ALPINE 53 /* Cirrus Logic 543x/544x/5480 */ +#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ +#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */ +#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */ +#define FB_ACCEL_NEOMAGIC_NM2097 93 /* NeoMagic NM2097 */ +#define FB_ACCEL_NEOMAGIC_NM2160 94 /* NeoMagic NM2160 */ +#define FB_ACCEL_NEOMAGIC_NM2200 95 /* NeoMagic NM2200 */ +#define FB_ACCEL_NEOMAGIC_NM2230 96 /* NeoMagic NM2230 */ +#define FB_ACCEL_NEOMAGIC_NM2360 97 /* NeoMagic NM2360 */ +#define FB_ACCEL_NEOMAGIC_NM2380 98 /* NeoMagic NM2380 */ +#define FB_ACCEL_PXA3XX 99 /* PXA3xx */ + +#define FB_ACCEL_SAVAGE4 0x80 /* S3 Savage4 */ +#define FB_ACCEL_SAVAGE3D 0x81 /* S3 Savage3D */ +#define FB_ACCEL_SAVAGE3D_MV 0x82 /* S3 Savage3D-MV */ +#define FB_ACCEL_SAVAGE2000 0x83 /* S3 Savage2000 */ +#define FB_ACCEL_SAVAGE_MX_MV 0x84 /* S3 Savage/MX-MV */ +#define FB_ACCEL_SAVAGE_MX 0x85 /* S3 Savage/MX */ +#define FB_ACCEL_SAVAGE_IX_MV 0x86 /* S3 Savage/IX-MV */ +#define FB_ACCEL_SAVAGE_IX 0x87 /* S3 Savage/IX */ +#define FB_ACCEL_PROSAVAGE_PM 0x88 /* S3 ProSavage PM133 */ +#define FB_ACCEL_PROSAVAGE_KM 0x89 /* S3 ProSavage KM133 */ +#define FB_ACCEL_S3TWISTER_P 0x8a /* S3 Twister */ +#define FB_ACCEL_S3TWISTER_K 0x8b /* S3 TwisterK */ +#define FB_ACCEL_SUPERSAVAGE 0x8c /* S3 Supersavage */ +#define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ +#define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ + +#define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */ + +#define FB_CAP_FOURCC 1 /* Device supports FOURCC-based formats */ + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + uint32_t smem_len; /* Length of frame buffer mem */ + uint32_t type; /* see FB_TYPE_* */ + uint32_t type_aux; /* Interleave for interleaved Planes */ + uint32_t visual; /* see FB_VISUAL_* */ + uint16_t xpanstep; /* zero if no hardware panning */ + uint16_t ypanstep; /* zero if no hardware panning */ + uint16_t ywrapstep; /* zero if no hardware ywrap */ + uint32_t line_length; /* length of a line in bytes */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + uint32_t mmio_len; /* Length of Memory Mapped I/O */ + uint32_t accel; /* Indicate to driver which */ + /* specific chip/card we have */ + uint16_t capabilities; /* see FB_CAP_* */ + uint16_t reserved[2]; /* Reserved for future compatibility */ +}; + +/* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. + * + * For pseudocolor: offset and length should be the same for all color + * components. Offset specifies the position of the least significant bit + * of the palette index in a pixel value. Length indicates the number + * of available palette entries (i.e. # of entries = 1 << length). + */ +struct fb_bitfield { + uint32_t offset; /* beginning of bitfield */ + uint32_t length; /* length of bitfield */ + uint32_t msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ +#define FB_NONSTD_REV_PIX_IN_B 2 /* order of pixels in each byte is reversed */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ +#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ +#define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/ +#define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */ +#define FB_ACTIVATE_KD_TEXT 512 /* for KDSET vt ioctl */ + +#define FB_ACCELF_TEXT 1 /* (OBSOLETE) see fb_info.flags and vc_mode */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ +#define FB_SYNC_ON_GREEN 32 /* sync on green */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ + +/* + * Display rotation support + */ +#define FB_ROTATE_UR 0 +#define FB_ROTATE_CW 1 +#define FB_ROTATE_UD 2 +#define FB_ROTATE_CCW 3 + +#define PICOS2KHZ(a) (1000000000UL/(a)) +#define KHZ2PICOS(a) (1000000000UL/(a)) + +struct fb_var_screeninfo { + uint32_t xres; /* visible resolution */ + uint32_t yres; + uint32_t xres_virtual; /* virtual resolution */ + uint32_t yres_virtual; + uint32_t xoffset; /* offset from virtual to visible */ + uint32_t yoffset; /* resolution */ + + uint32_t bits_per_pixel; /* guess what */ + uint32_t grayscale; /* 0 = color, 1 = grayscale, */ + /* >1 = FOURCC */ + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + uint32_t nonstd; /* != 0 Non standard pixel format */ + + uint32_t activate; /* see FB_ACTIVATE_* */ + + uint32_t height; /* height of picture in mm */ + uint32_t width; /* width of picture in mm */ + + uint32_t accel_flags; /* (OBSOLETE) see fb_info.flags */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + uint32_t pixclock; /* pixel clock in ps (pico seconds) */ + uint32_t left_margin; /* time from sync to picture */ + uint32_t right_margin; /* time from picture to sync */ + uint32_t upper_margin; /* time from sync to picture */ + uint32_t lower_margin; + uint32_t hsync_len; /* length of horizontal sync */ + uint32_t vsync_len; /* length of vertical sync */ + uint32_t sync; /* see FB_SYNC_* */ + uint32_t vmode; /* see FB_VMODE_* */ + uint32_t rotate; /* angle we rotate counter clockwise */ + uint32_t colorspace; /* colorspace for FOURCC-based modes */ + uint32_t reserved[4]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + uint32_t start; /* First entry */ + uint32_t len; /* Number of entries */ + uint16_t *red; /* Red values */ + uint16_t *green; + uint16_t *blue; + uint16_t *transp; /* transparency, can be NULL */ +}; + +struct fb_con2fbmap { + uint32_t console; + uint32_t framebuffer; +}; + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + + +enum { + /* screen: unblanked, hsync: on, vsync: on */ + FB_BLANK_UNBLANK = VESA_NO_BLANKING, + + /* screen: blanked, hsync: on, vsync: on */ + FB_BLANK_NORMAL = VESA_NO_BLANKING + 1, + + /* screen: blanked, hsync: on, vsync: off */ + FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: on */ + FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: off */ + FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1 +}; + +#define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */ +#define FB_VBLANK_HBLANKING 0x002 /* currently in a horizontal blank */ +#define FB_VBLANK_HAVE_VBLANK 0x004 /* vertical blanks can be detected */ +#define FB_VBLANK_HAVE_HBLANK 0x008 /* horizontal blanks can be detected */ +#define FB_VBLANK_HAVE_COUNT 0x010 /* global retrace counter is available */ +#define FB_VBLANK_HAVE_VCOUNT 0x020 /* the vcount field is valid */ +#define FB_VBLANK_HAVE_HCOUNT 0x040 /* the hcount field is valid */ +#define FB_VBLANK_VSYNCING 0x080 /* currently in a vsync */ +#define FB_VBLANK_HAVE_VSYNC 0x100 /* verical syncs can be detected */ + +struct fb_vblank { + uint32_t flags; /* FB_VBLANK flags */ + uint32_t count; /* counter of retraces since boot */ + uint32_t vcount; /* current scanline position */ + uint32_t hcount; /* current scandot position */ + uint32_t reserved[4]; /* reserved for future compatibility */ +}; + +/* Internal HW accel */ +#define ROP_COPY 0 +#define ROP_XOR 1 + +struct fb_copyarea { + uint32_t dx; + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t sx; + uint32_t sy; +}; + +struct fb_fillrect { + uint32_t dx; /* screen-relative */ + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t color; + uint32_t rop; +}; + +struct fb_image { + uint32_t dx; /* Where to place image */ + uint32_t dy; + uint32_t width; /* Size of image */ + uint32_t height; + uint32_t fg_color; /* Only used when a mono bitmap */ + uint32_t bg_color; + uint8_t depth; /* Depth of the image */ + const char *data; /* Pointer to image data */ + struct fb_cmap cmap; /* color map info */ +}; + +/* + * hardware cursor control + */ + +#define FB_CUR_SETIMAGE 0x01 +#define FB_CUR_SETPOS 0x02 +#define FB_CUR_SETHOT 0x04 +#define FB_CUR_SETCMAP 0x08 +#define FB_CUR_SETSHAPE 0x10 +#define FB_CUR_SETSIZE 0x20 +#define FB_CUR_SETALL 0xFF + +struct fbcurpos { + uint16_t x, y; +}; + +struct fb_cursor { + uint16_t set; /* what to set */ + uint16_t enable; /* cursor on/off */ + uint16_t rop; /* bitop operation */ + const char *mask; /* cursor mask bits */ + struct fbcurpos hot; /* cursor hot spot */ + struct fb_image image; /* Cursor image */ +}; + +/* Settings for the generic backlight code */ +#define FB_BACKLIGHT_LEVELS 128 +#define FB_BACKLIGHT_MAX 0xFF + + +#endif /* _LINUX_FB_H */ diff --git a/user/include/mlibc/sysdeps/vinix/include/mntent.h b/user/include/mlibc/sysdeps/vinix/include/mntent.h new file mode 100644 index 0000000..42f0184 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/mntent.h @@ -0,0 +1,50 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#include + +/* TODO: Refer to _PATH_MOUNTED */ +#define MOUNTED "/etc/mtab" + +/* Generic mount options */ +#define MNTOPT_DEFAULTS "defaults" /* Use all default options. */ +#define MNTOPT_RO "ro" /* Read only. */ +#define MNTOPT_RW "rw" /* Read/write. */ +#define MNTOPT_SUID "suid" /* Set uid allowed. */ +#define MNTOPT_NOSUID "nosuid" /* No set uid allowed. */ +#define MNTOPT_NOAUTO "noauto" /* Do not auto mount. */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +#ifndef __MLIBC_ABI_ONLY + +FILE *setmntent(const char *, const char *); + +struct mntent *getmntent(FILE *); + +int addmntent(FILE *, const struct mntent *); + +int endmntent(FILE *); + +char *hasmntopt(const struct mntent *, const char *); + +struct mntent *getmntent_r(FILE *, struct mntent *, char *, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MNTENT_H */ diff --git a/user/include/mlibc/sysdeps/vinix/include/sys/mount.h b/user/include/mlibc/sysdeps/vinix/include/sys/mount.h new file mode 100644 index 0000000..844abdb --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/sys/mount.h @@ -0,0 +1,54 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MS_RDONLY 1 +#define MS_NOSUID 2 +#define MS_NODEV 4 +#define MS_NOEXEC 8 +#define MS_SYNCHRONOUS 16 +#define MS_REMOUNT 32 +#define MS_MANDLOCK 64 +#define MS_DIRSYNC 128 +#define MS_NOSYMFOLLOW 256 +#define MS_NOATIME 1024 +#define MS_NODIRATIME 2048 +#define MS_BIND 4096 +#define MS_MOVE 8192 +#define MS_REC 16384 +#define MS_SILENT 32768 +#define MS_POSIXACL (1 << 16) +#define MS_UNBINDABLE (1 << 17) +#define MS_PRIVATE (1 << 18) +#define MS_SLAVE (1 << 19) +#define MS_SHARED (1 << 20) +#define MS_RELATIME (1 << 21) +#define MS_KERNMOUNT (1 << 22) +#define MS_I_VERSION (1 << 23) +#define MS_STRICTATIME (1 << 24) +#define MS_LAZYTIME (1 << 25) +#define MS_NOREMOTELOCK (1 << 27) +#define MS_NOSEC (1 << 28) +#define MS_BORN (1 << 29) +#define MS_ACTIVE (1 << 30) +#define MS_NOUSER (1 << 31) + +#define MNT_FORCE 1 + +#ifndef __MLIBC_ABI_ONLY + +int mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data); +int umount(const char *target); +int umount2(const char *target, int flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MOUNT_H */ diff --git a/user/include/mlibc/sysdeps/vinix/include/sys/reboot.h b/user/include/mlibc/sysdeps/vinix/include/sys/reboot.h new file mode 100644 index 0000000..0628ae4 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/sys/reboot.h @@ -0,0 +1,20 @@ +#ifndef MLIBC_SYS_REBOOT_H +#define MLIBC_SYS_REBOOT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int reboot(int arg); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_SYS_REBOOT_H */ diff --git a/user/include/mlibc/sysdeps/vinix/include/sys/sysmacros.h b/user/include/mlibc/sysdeps/vinix/include/sys/sysmacros.h new file mode 100644 index 0000000..9682d01 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/include/sys/sysmacros.h @@ -0,0 +1,33 @@ +#ifndef _SYS_SYSMACROS_H +#define _SYS_SYSMACROS_H + +#ifdef __cplusplus +extern "C" { +#endif + +static unsigned int __mlibc_dev_major( + unsigned long long int __dev) { + return ((__dev >> 8) & 0xfff) | ((unsigned int)(__dev >> 32) & ~0xfff); +} + +static unsigned int __mlibc_dev_minor( + unsigned long long int __dev) { + return (__dev & 0xff) | ((unsigned int)(__dev >> 12) & ~0xff); +} + +static unsigned long long int __mlibc_dev_makedev( + unsigned int __major, unsigned int __minor) { + return ((__minor & 0xff) | ((__major & 0xfff) << 8) + | (((unsigned long long int)(__minor & ~0xff)) << 12) + | (((unsigned long long int)(__major & ~0xfff)) << 32)); +} + +#define major(dev) __mlibc_dev_major(dev) +#define minor(dev) __mlibc_dev_minor(dev) +#define makedev(major, minor) __mlibc_dev_makedev(major, minor) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SYSMACROS_H */ diff --git a/user/include/mlibc/sysdeps/vinix/meson.build b/user/include/mlibc/sysdeps/vinix/meson.build new file mode 100644 index 0000000..146ee42 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/meson.build @@ -0,0 +1,123 @@ +sysdep_supported_options = { + 'posix': true, + 'linux': false, + 'glibc': true, + 'bsd': true, +} + +rtld_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/generic.cpp', + 'generic/mntent.cpp', + 'generic/mount.cpp', + 'generic/reboot.cpp', + 'generic/thread.cpp', + 'generic/thread.S', +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/ipc.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/rlim_t.h', + 'include/abi-bits/sigval.h', + 'include/abi-bits/sigevent.h', + 'include/abi-bits/utmpx.h', + 'include/abi-bits/utmp-defines.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + install_headers( + 'include/asm/ioctl.h', + 'include/asm/ioctls.h', + subdir: 'asm', + ) + + install_headers( + 'include/linux/fb.h', + subdir: 'linux', + ) + + install_headers( + 'include/sys/reboot.h', + 'include/sys/mount.h', + 'include/sys/sysmacros.h', + subdir: 'sys', + ) + + install_headers( + 'include/mntent.h', + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crt0.S b/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crt0.S new file mode 100644 index 0000000..d0e8213 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crt0.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + lea main(%rip), %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crti.S b/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crti.S new file mode 100644 index 0000000..911b078 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crtn.S b/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..0187e50 --- /dev/null +++ b/user/include/mlibc/sysdeps/vinix/x86_64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/user/include/mlibc/tests/ansi/abs.c b/user/include/mlibc/tests/ansi/abs.c new file mode 100644 index 0000000..492040c --- /dev/null +++ b/user/include/mlibc/tests/ansi/abs.c @@ -0,0 +1,16 @@ +#include +#include +#include + +int main(){ + assert(abs(-10) == 10); + assert(abs(2021) == 2021); + + assert(labs(-256) == 256); + assert(labs(10034890) == 10034890); + + assert(llabs(-0x2deadbeef) == 0x2deadbeef); + assert(llabs(49238706947) == 49238706947); + + return 0; +} \ No newline at end of file diff --git a/user/include/mlibc/tests/ansi/alloc.c b/user/include/mlibc/tests/ansi/alloc.c new file mode 100644 index 0000000..4f5082b --- /dev/null +++ b/user/include/mlibc/tests/ansi/alloc.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +int main() { + void *p; + + p = aligned_alloc(sizeof(void *), sizeof(void *)); + assert(p != NULL && (uintptr_t)p % sizeof(void *) == 0); + free(p); + + p = aligned_alloc(256, 256); + assert(p != NULL && (uintptr_t)p % 256 == 0); + free(p); + + // small alignments are okay + p = aligned_alloc(1, 8); + assert(p != NULL); + free(p); + p = aligned_alloc(1, 1); + assert(p != NULL); + free(p); + + // It seems that glibc doesn't report error in these cases. +#if !(defined(USE_HOST_LIBC) && defined(__GLIBC__)) + // size % align must be 0 + p = aligned_alloc(256, 1); + assert(errno == EINVAL); + assert(p == NULL); + + // align must be a 'valid alignment supported by the implementation' + p = aligned_alloc(3, 1); + assert(errno == EINVAL); + assert(p == NULL); +#endif + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/calloc.c b/user/include/mlibc/tests/ansi/calloc.c new file mode 100644 index 0000000..9b709a5 --- /dev/null +++ b/user/include/mlibc/tests/ansi/calloc.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +int main() { + errno = 0; + void *ptr = calloc((SIZE_MAX / 2) + 2, 2); + assert(!ptr); + assert(errno); + + errno = 0; + ptr = calloc(10, sizeof(size_t)); + assert(ptr); + for(size_t i = 0; i < 10; i++) { + size_t *p = ptr; + assert(!p[i]); + } + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/creal-cimag.c b/user/include/mlibc/tests/ansi/creal-cimag.c new file mode 100644 index 0000000..1529865 --- /dev/null +++ b/user/include/mlibc/tests/ansi/creal-cimag.c @@ -0,0 +1,39 @@ +#include +#include +#include + +// FIXME: We should create a proper floating point facility +// in order for other functions to be tested properly + +#define APPROXIMATELY_EQUAL(calculated, expected) fabs((calculated) - (expected)) <= 0.0000005 +#define APPROXIMATELY_EQUALF(calculated, expected) fabsf((calculated) - (expected)) <= 0.0000005f +#define APPROXIMATELY_EQUALL(calculated, expected) fabsl((calculated) - (expected)) <= 0.0000005L + +#define IS_COMPLEX_NUMBER(Z) \ + _Generic((Z), \ + double complex: 1, \ + float complex: 1, \ + long double complex: 1, \ + default: 0 \ + ) + +int main() { +#if !(defined(USE_HOST_LIBC) && defined(__clang__)) + assert(IS_COMPLEX_NUMBER(CMPLX(5.2, 4.3))); + double complex cz = CMPLX(5.2, 4.3); + assert(APPROXIMATELY_EQUAL(creal(cz), 5.2)); + assert(APPROXIMATELY_EQUAL(cimag(cz), 4.3)); + + assert(IS_COMPLEX_NUMBER(CMPLXF(1.2f, 2.5f))); + float complex czf = CMPLXF(1.2f, 2.5f); + assert(APPROXIMATELY_EQUALF(crealf(czf), 1.2f)); + assert(APPROXIMATELY_EQUALF(cimagf(czf), 2.5f)); + + assert(IS_COMPLEX_NUMBER(CMPLXL(0.1L, 123.54L))); + long double complex czl = CMPLXL(0.1L, 123.54L); + assert(APPROXIMATELY_EQUALL(creall(czl), 0.1L)); + assert(APPROXIMATELY_EQUALL(cimagl(czl), 123.54L)); +#endif + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/fenv.c b/user/include/mlibc/tests/ansi/fenv.c new file mode 100644 index 0000000..0dfaff0 --- /dev/null +++ b/user/include/mlibc/tests/ansi/fenv.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include + +/* qemu-m68k < version 9.1.0 cannot run the test due to missing FPU logic. */ +#ifdef __m68k__ +int main() { + return 0; +} +#else +#define NO_OPTIMIZE(x) asm volatile("" :: "r,m" (x) : "memory") + +static void div_by_zero() { + volatile float zero = 0.0f; + NO_OPTIMIZE(69.0f / zero); +} + +static bool float_cmp(float a, float b) { + return a == b || fabs(a - b) < (fabs(a) + fabs(b)) * FLT_EPSILON; +} + +static void test_rounding(float expectation1, float expectation2) { + float x; + volatile float f = 1.968750f; + volatile float m = 0x1.0p23f; + + NO_OPTIMIZE(x = f + m); + assert(float_cmp(expectation1, x)); + NO_OPTIMIZE(x = x - m); + assert(x == expectation2); +} + +void test0() { + // test whether the divide-by-zero exception is raised + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + + div_by_zero(); + int raised = fetestexcept(FE_DIVBYZERO); + assert((raised & FE_DIVBYZERO)); +} + +void test1() { + // test various rounding modes + feclearexcept(FE_DIVBYZERO); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + + fesetround(FE_UPWARD); + assert(fegetround() == FE_UPWARD); + test_rounding(8388610.0f, 2.0f); + + fesetround(FE_DOWNWARD); + assert(fegetround() == FE_DOWNWARD); + test_rounding(8388609.0f, 1.0f); + + fesetround(FE_TONEAREST); + assert(fegetround() == FE_TONEAREST); + test_rounding(8388610.0f, 2.0f); + + fesetround(FE_TOWARDZERO); + assert(fegetround() == FE_TOWARDZERO); + test_rounding(8388609.0f, 1.0f); +} + +void test2() { + // test feraiseexcept + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + assert(feraiseexcept(FE_DIVBYZERO | FE_OVERFLOW) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW)); +} + +void test3() { + // test fe{get,set}env + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + assert(feraiseexcept(FE_OVERFLOW) == 0); + + fenv_t state; + assert(fegetenv(&state) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW); + + div_by_zero(); + assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW)); + + assert(fesetenv(&state) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW); +} + +int main() { + test0(); + test1(); + test2(); + test3(); + + return 0; +} +#endif diff --git a/user/include/mlibc/tests/ansi/fgetpos.c b/user/include/mlibc/tests/ansi/fgetpos.c new file mode 100644 index 0000000..66ea2e8 --- /dev/null +++ b/user/include/mlibc/tests/ansi/fgetpos.c @@ -0,0 +1,35 @@ +#include +#include + +int main(int argc, char *argv[]) { + (void) argc; + + FILE *f = fopen(argv[0], "r"); + assert(f); + + int ret = fseek(f, 0, SEEK_SET); + assert(!ret); + + fpos_t start_pos; + ret = fgetpos(f, &start_pos); + assert(!ret); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + + long end_off = ftell(f); + + fpos_t end_pos; + ret = fgetpos(f, &end_pos); + assert(!ret); + + ret = fsetpos(f, &start_pos); + assert(!ret); + assert(ftell(f) == 0); + + ret = fsetpos(f, &end_pos); + assert(!ret); + assert(ftell(f) == end_off); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/fopen.c b/user/include/mlibc/tests/ansi/fopen.c new file mode 100644 index 0000000..f4818b2 --- /dev/null +++ b/user/include/mlibc/tests/ansi/fopen.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "fopen-host-libc.tmp" +#else +#define TEST_FILE "fopen.tmp" +#endif + +int main() { + FILE *file; + char str[] = "mlibc fopen test"; + char str2[] = " mlibc appending"; + char completestr[] = "mlibc fopen test mlibc appending"; + char buffer[100]; + char buffer2[100]; + + // Clear all the buffers to zero. + memset(buffer, 0, sizeof(buffer)); + memset(buffer2, 0, sizeof(buffer2)); + + // Open the file for writing. + file = fopen(TEST_FILE, "w"); + assert(file); + + // Write string minus null terminator, flush and close. + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + // Open the file for reading. + file = fopen(TEST_FILE, "r"); + assert(file); + + // Verify that we read back the written string and close the file. + assert(fread(buffer, 1, sizeof(str) - 1, file)); + assert(!strcmp(buffer, str)); + fclose(file); + + // Open the file in appending mode, append string 2 (minus the null terminator) to the file, flush and close. + file = fopen(TEST_FILE, "a"); + fwrite(str2, 1, sizeof(str2) - 1, file); + fflush(file); + fclose(file); + + // Open the file for reading again, verify the contents, close the file and return. + file = fopen(TEST_FILE, "r"); + assert(fread(buffer2, 1, sizeof(completestr) - 1, file)); + assert(!strcmp(buffer2, completestr)); + fclose(file); + + // Check that stdout, stdin and stderr can be closed by the application (issue #12). + fclose(stdout); + fclose(stdin); + fclose(stderr); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/fputs.c b/user/include/mlibc/tests/ansi/fputs.c new file mode 100644 index 0000000..7868bc7 --- /dev/null +++ b/user/include/mlibc/tests/ansi/fputs.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "fputs-host-libc.tmp" +#else +#define TEST_FILE "fputs.tmp" +#endif + +int main() { + FILE *file; + char str[] = "mlibc fputs test"; + char buffer[100]; + + // Clear the buffer to zero. + memset(buffer, 0, sizeof(buffer)); + + // Open the file for writing. + file = fopen(TEST_FILE, "w"); + assert(file); + + // Verify that we can write an empty string. + assert(fputs("", file) != EOF); + + // Write string, flush and close. + assert(fputs(str, file) != EOF); + fflush(file); + fclose(file); + + // Open the file for reading. + file = fopen(TEST_FILE, "r"); + assert(file); + + // Verify that we read back the written string and close. + assert(fread(buffer, 1, sizeof(str) - 1, file)); + assert(!strcmp(buffer, str)); + fclose(file); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/freopen.c b/user/include/mlibc/tests/ansi/freopen.c new file mode 100644 index 0000000..c91577f --- /dev/null +++ b/user/include/mlibc/tests/ansi/freopen.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "freopen-host-libc.tmp" +#else +#define TEST_FILE "freopen.tmp" +#endif + +int main() { + FILE *file = fopen(TEST_FILE, "w"); + assert(file); + + assert(freopen("/dev/null", "w", file)); + + char str[] = "mlibc freopen test"; + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + file = fopen(TEST_FILE, "r"); + assert(file); + + char buf[sizeof(str)]; + memset(buf, 0, sizeof(buf)); + int ret = fread(buf, 1, sizeof(buf) - 1, file); + fprintf(stderr, "ret %d\n", ret); + assert(ret == 0); + fclose(file); + + file = fopen("/dev/null", "w"); + assert(file); + + assert(freopen(TEST_FILE, "w", file)); + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + memset(buf, 0, sizeof(buf)); + file = fopen(TEST_FILE, "r"); + assert(fread(buf, 1, sizeof(buf) - 1, file)); + + fprintf(stderr, "buffer content '%s'\n", buf); + assert(!strcmp(buf, "mlibc freopen test")); + fclose(file); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/ftell.c b/user/include/mlibc/tests/ansi/ftell.c new file mode 100644 index 0000000..5d4c501 --- /dev/null +++ b/user/include/mlibc/tests/ansi/ftell.c @@ -0,0 +1,72 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "ftell-host-libc.tmp" +#else +#define TEST_FILE "ftell.tmp" +#endif + +int main() { + FILE *file; + char str[] = "mlibc ftell test"; + size_t str_size = sizeof(str) - 1; + char buffer[20]; + + // Clear buffer to zero + memset(buffer, 0, sizeof(buffer)); + + // Open the file for writing in binary mode, because ftell is unspecified + // in text mode. + file = fopen(TEST_FILE, "wb"); + assert(file); + + // Write string minus null terminator, flush and close. + assert(fwrite(str, 1, str_size, file) == str_size); + fflush(file); + fclose(file); + + // Open the file for reading in binary mode. + file = fopen(TEST_FILE, "rb"); + assert(file); + + // Check position indicator at the start of the file. + assert(ftell(file) == 0); + + // Read 4 bytes and check fread and ftell. + assert(fread(buffer, 1, 4, file) == 4); + assert(ftell(file) == 4); + + // Rewind and check position indicator at the start of the file. + rewind(file); + assert(ftell(file) == 0); + + // Read the entire file and check fread and ftell. + assert(fread(buffer, 1, str_size, file) == str_size); + assert((size_t) ftell(file) == str_size); + + // Rewind and check how ftell interacts with getc. + rewind(file); + assert(fgetc(file) == 'm'); + assert(ftell(file) == 1); + assert(fgetc(file) == 'l'); + assert(ftell(file) == 2); + assert(fgetc(file) == 'i'); + assert(ftell(file) == 3); + + // Check whether ftell is decremented after ungetc + assert(ungetc('X', file) == 'X'); + int ftell_after_ungetc = ftell(file); + fprintf(stderr, "ftell_after_ungetc: %d\n", ftell_after_ungetc); + assert(ftell_after_ungetc == 2); + ungetc('Y', file); + assert(ftell(file) == 1); + + // Check if rewind undoes ungetc's effects on ftell + rewind(file); + assert(ftell(file) == 0); + + fclose(file); + return 0; +} diff --git a/user/include/mlibc/tests/ansi/locale.c b/user/include/mlibc/tests/ansi/locale.c new file mode 100644 index 0000000..175f68e --- /dev/null +++ b/user/include/mlibc/tests/ansi/locale.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include + +int main() { + wchar_t c = 0xC9; + unsigned char buf[MB_LEN_MAX] = { 0 }; + setlocale(LC_ALL, ""); + if (sprintf(buf, "%lc", c) < 0) + return -1; + + assert(buf[0] == 0xc3 && buf[1] == 0x89 + && buf[2] == '\0' && buf[3] == '\0'); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/longjmp.c b/user/include/mlibc/tests/ansi/longjmp.c new file mode 100644 index 0000000..9fde66a --- /dev/null +++ b/user/include/mlibc/tests/ansi/longjmp.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +jmp_buf buf; + +noreturn void do_jump(int arg) { + longjmp(buf, 2 * arg); +} + +int main(void) { + volatile int times_called = 0; + + if (setjmp(buf) != 8) { + do_jump(++times_called); + } + + assert(times_called == 4); + + times_called = 0; + int ret = setjmp(buf); + assert(ret == times_called); + + if (!ret) { + times_called = 1; + longjmp(buf, 0); + } + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/mbrtoc32.c b/user/include/mlibc/tests/ansi/mbrtoc32.c new file mode 100644 index 0000000..a71bf02 --- /dev/null +++ b/user/include/mlibc/tests/ansi/mbrtoc32.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +struct { + size_t ret; + char32_t c32; + uint8_t bytes[4]; +} expected_results[] = { + {1, 0x7A, {0x7A, 0, 0, 0}}, + {2, 0xDF, {0xC3, 0x9F, 0, 0}}, + {3, 0x6C34, {0xE6, 0xB0, 0xB4, 0}}, + {4, 0x1F34C, {0xF0, 0x9F, 0x8D, 0x8C}}, +}; + +int main() { + setlocale(LC_ALL, "en_US.utf8"); + + size_t ret = 0; + + char *str = "z\u00df\u6c34\U0001F34C"; + + fprintf(stderr, "string: '%s'\n", str); + + mbstate_t state = {}; + char32_t c32; + size_t loop = 0; + while((ret = mbrtoc32(&c32, str, strlen(str), &state))) { + assert(ret != (size_t)-3); + if(ret == (size_t)-1) + break; + if(ret == (size_t)-2) + break; + + fprintf(stderr, "Next UTF-32 char: 0x%x obtained from %zu bytes [", c32, ret); + for(size_t n = 0; n < ret; ++n) { + fprintf(stderr, " 0x%02x ", (uint8_t) str[n]); + } + fprintf(stderr, "]\n"); + + assert(ret == expected_results[loop].ret); + assert(c32 == expected_results[loop].c32); + for(size_t n = 0; n < ret; ++n) { + assert((uint8_t) str[n] == expected_results[loop].bytes[n]); + } + + str += ret; + loop++; + } + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/memmem.c b/user/include/mlibc/tests/ansi/memmem.c new file mode 100644 index 0000000..c210a16 --- /dev/null +++ b/user/include/mlibc/tests/ansi/memmem.c @@ -0,0 +1,24 @@ +#include +#include + +int main() { + char *haystack = "abc123\0x45"; + + char *needle1 = "abc"; + void *rv = memmem(haystack, strlen(haystack), needle1, strlen(needle1)); + assert(rv == haystack); + + char *needle2 = "123"; + rv = memmem(haystack, strlen(haystack), needle2, strlen(needle2)); + assert(rv == haystack + 3); + + char *needle3 = "1234"; + rv = memmem(haystack, strlen(haystack), needle3, strlen(needle3)); + assert(rv == NULL); + + char *needle4 = "23\0x45"; + rv = memmem(haystack, 10, needle4, 6); + assert(rv == haystack + 4); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/qsort.c b/user/include/mlibc/tests/ansi/qsort.c new file mode 100644 index 0000000..bb48a23 --- /dev/null +++ b/user/include/mlibc/tests/ansi/qsort.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +static const char *arr[] = { "xyz", "abc", "ghi", "def" }; + +static const size_t magic = 0xDEADBEEF; + +static int cmpstringp(const void *p1, const void *p2, void *ctx) { + /* The actual arguments to this function are "pointers to + * pointers to char", but strcmp(3) arguments are "pointers + * to char", hence the following cast plus dereference. */ + assert(*(size_t *) ctx == magic); + return strcmp(*(const char **) p1, *(const char **) p2); +} + +int main() { + qsort_r(&arr[0], sizeof(arr) / sizeof(*arr), sizeof(char *), cmpstringp, (void *) &magic); + + assert(!strcmp(arr[0], "abc")); + assert(!strcmp(arr[1], "def")); + assert(!strcmp(arr[2], "ghi")); + assert(!strcmp(arr[3], "xyz")); + + for(size_t i = 0; i < sizeof(arr) / sizeof(*arr); i++) { + fprintf(stderr, "%s\n", arr[i]); + } + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/snprintf.c b/user/include/mlibc/tests/ansi/snprintf.c new file mode 100644 index 0000000..360d86e --- /dev/null +++ b/user/include/mlibc/tests/ansi/snprintf.c @@ -0,0 +1,424 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + char buffer[10]; + int ret = snprintf(buffer, 10, "%d", 123456789); + assert(strncmp("123456789", buffer, 10) == 0); + assert(ret == 9); + + // We deliberately induce a warning here. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-truncation" + ret = snprintf(buffer, 10, "%d", 1234567890); + assert(strncmp("123456789", buffer, 10) == 0); + assert(ret == 10); +#pragma GCC diagnostic pop + + // mlibc issue #118. + ret = snprintf(NULL, 0, "%d", 123456789); + assert(ret == 9); + + char buf[128]; + assert(snprintf(buf, 2, "a") == 1); + assert(strcmp(buf, "a") == 0); + assert(snprintf(buf, 3, "abc") == 3); + assert(strcmp(buf, "ab") == 0); + assert(snprintf(buf, 128, "%%") == 1); + assert(strcmp(buf, "%") == 0); + assert(snprintf(buf, 128, "a%cc%c", 'b', 'd') == 4); + assert(strcmp(buf, "abcd") == 0); + assert(snprintf(buf, 128, "a%lcc%lc", (wint_t)L'b', (wint_t)L'd') == 4); + assert(strcmp(buf, "abcd") == 0); + assert(snprintf(buf, 128, "%s", "hello") == 5); + assert(strcmp(buf, "hello") == 0); + assert(snprintf(buf, 128, "%ls", L"hello") == 5); + assert(strcmp(buf, "hello") == 0); + + assert(snprintf(buf, 128, "%d", 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%d", 0) == 1); + assert(strcmp(buf, "0") == 0); + assert(snprintf(buf, 128, "%d", -1234) == 5); + assert(strcmp(buf, "-1234") == 0); + assert(snprintf(buf, 128, "%hhd", 123) == 3); + assert(strcmp(buf, "123") == 0); + assert(snprintf(buf, 128, "%hd", 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%ld", 1234L) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%lld", 1234LL) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%jd", (intmax_t) 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%zd", (ssize_t) 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%td", (ptrdiff_t) 1234) == 4); + assert(strcmp(buf, "1234") == 0); + + assert(snprintf(buf, 128, "%i", 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%i", 0) == 1); + assert(strcmp(buf, "0") == 0); + assert(snprintf(buf, 128, "%i", -1234) == 5); + assert(strcmp(buf, "-1234") == 0); + assert(snprintf(buf, 128, "%hhi", 123) == 3); + assert(strcmp(buf, "123") == 0); + assert(snprintf(buf, 128, "%hi", 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%li", 1234L) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%lli", 1234LL) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%ji", (intmax_t) 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%zi", (ssize_t) 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%ti", (ptrdiff_t) 1234) == 4); + assert(strcmp(buf, "1234") == 0); + + assert(snprintf(buf, 128, "%b", 0b1011) == 4); + assert(strcmp(buf, "1011") == 0); + assert(snprintf(buf, 128, "%b", 0) == 1); + assert(strcmp(buf, "0") == 0); + assert(snprintf(buf, 128, "%hhb", 0b1011) == 4); + assert(strcmp(buf, "1011") == 0); + assert(snprintf(buf, 128, "%hb", 0b1011) == 4); + assert(strcmp(buf, "1011") == 0); + assert(snprintf(buf, 128, "%lb", 0b1011UL) == 4); + assert(strcmp(buf, "1011") == 0); + assert(snprintf(buf, 128, "%llb", 0b1011ULL) == 4); + assert(strcmp(buf, "1011") == 0); + assert(snprintf(buf, 128, "%jb", (uintmax_t) 0b1011) == 4); + assert(strcmp(buf, "1011") == 0); + assert(snprintf(buf, 128, "%zb", (size_t) 0b1011) == 4); + assert(strcmp(buf, "1011") == 0); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(snprintf(buf, 128, "%tb", 0b1011UL) == 4); + assert(strcmp(buf, "1011") == 0); +#pragma GCC diagnostic pop + + assert(snprintf(buf, 128, "%o", 01234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%o", 0) == 1); + assert(strcmp(buf, "0") == 0); + assert(snprintf(buf, 128, "%o", -01234) == 11); + assert(strcmp(buf, "37777776544") == 0); + assert(snprintf(buf, 128, "%hho", 012) == 2); + assert(strcmp(buf, "12") == 0); + assert(snprintf(buf, 128, "%ho", 01234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%lo", 01234UL) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%llo", 01234ULL) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%jo", (uintmax_t) 01234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%zo", (size_t) 01234) == 4); + assert(strcmp(buf, "1234") == 0); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(snprintf(buf, 128, "%to", 01234UL) == 4); + assert(strcmp(buf, "1234") == 0); +#pragma GCC diagnostic pop + + assert(snprintf(buf, 128, "%x", 0x1234AB) == 6); + assert(strcmp(buf, "1234ab") == 0); + assert(snprintf(buf, 128, "%x", 0) == 1); + assert(strcmp(buf, "0") == 0); + assert(snprintf(buf, 128, "%x", -0x1234AB) == 8); + assert(strcmp(buf, "ffedcb55") == 0); + assert(snprintf(buf, 128, "%X", 0x1234AB) == 6); + assert(strcmp(buf, "1234AB") == 0); + assert(snprintf(buf, 128, "%hhx", 0xAB) == 2); + assert(strcmp(buf, "ab") == 0); + assert(snprintf(buf, 128, "%hx", 0x12AB) == 4); + assert(strcmp(buf, "12ab") == 0); + assert(snprintf(buf, 128, "%lx", 0x1234ABUL) == 6); + assert(strcmp(buf, "1234ab") == 0); + assert(snprintf(buf, 128, "%llx", 0x1234ABULL) == 6); + assert(strcmp(buf, "1234ab") == 0); + assert(snprintf(buf, 128, "%jx", (uintmax_t) 0x1234AB) == 6); + assert(strcmp(buf, "1234ab") == 0); + assert(snprintf(buf, 128, "%zx", (size_t) 0x1234AB) == 6); + assert(strcmp(buf, "1234ab") == 0); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(snprintf(buf, 128, "%tx", 0x1234ABUL) == 6); + assert(strcmp(buf, "1234ab") == 0); +#pragma GCC diagnostic pop + + assert(snprintf(buf, 128, "%u", 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%u", 0) == 1); + assert(strcmp(buf, "0") == 0); + assert(snprintf(buf, 128, "%u", -1234) == 10); + assert(strcmp(buf, "4294966062") == 0); + assert(snprintf(buf, 128, "%hhu", 123) == 3); + assert(strcmp(buf, "123") == 0); + assert(snprintf(buf, 128, "%hu", 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%lu", 1234UL) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%llu", 1234ULL) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%ju", (uintmax_t) 1234) == 4); + assert(strcmp(buf, "1234") == 0); + assert(snprintf(buf, 128, "%zu", (size_t) 1234) == 4); + assert(strcmp(buf, "1234") == 0); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(snprintf(buf, 128, "%tu", 1234UL) == 4); + assert(strcmp(buf, "1234") == 0); +#pragma GCC diagnostic pop + + assert(snprintf(buf, 128, "%f", 1234.1234567) == 11); + assert(strcmp(buf, "1234.123457") == 0); + assert(snprintf(buf, 128, "%f", 0.0) == 8); + assert(strcmp(buf, "0.000000") == 0); + assert(snprintf(buf, 128, "%f", -1234.123456) == 12); + assert(strcmp(buf, "-1234.123456") == 0); + assert(snprintf(buf, 128, "%f", INFINITY) == 3); + assert(strcmp(buf, "inf") == 0); + assert(snprintf(buf, 128, "%04f", INFINITY) == 4); + assert(strcmp(buf, " inf") == 0); + assert(snprintf(buf, 128, "%-4f", INFINITY) == 4); + assert(strcmp(buf, "inf ") == 0); + assert(snprintf(buf, 128, "%f", NAN) == 3); + assert(strcmp(buf, "nan") == 0); + assert(snprintf(buf, 128, "%lf", 1234.123456) == 11); + assert(strcmp(buf, "1234.123456") == 0); + assert(snprintf(buf, 128, "%Lf", 1234.123456L) == 11); + assert(strcmp(buf, "1234.123456") == 0); + assert(snprintf(buf, 128, "%F", 1234.123456) == 11); + assert(strcmp(buf, "1234.123456") == 0); + assert(snprintf(buf, 128, "%F", INFINITY) == 3); + assert(strcmp(buf, "INF") == 0); + assert(snprintf(buf, 128, "%F", NAN) == 3); + assert(strcmp(buf, "NAN") == 0); + assert(snprintf(buf, 128, "%lF", 1234.123456) == 11); + assert(strcmp(buf, "1234.123456") == 0); + assert(snprintf(buf, 128, "%LF", 1234.123456L) == 11); + assert(strcmp(buf, "1234.123456") == 0); + + assert(snprintf(buf, 128, "%e", 1.123456) == 12); + assert(strcmp(buf, "1.123456e+00") == 0); + assert(snprintf(buf, 128, "%e", 0.0) == 12); + assert(strcmp(buf, "0.000000e+00") == 0); + assert(snprintf(buf, 128, "%e", -1.123456) == 13); + assert(strcmp(buf, "-1.123456e+00") == 0); + assert(snprintf(buf, 128, "%e", 1.123456e12) == 12); + assert(strcmp(buf, "1.123456e+12") == 0); + assert(snprintf(buf, 128, "%e", -1.123456e12) == 13); + assert(strcmp(buf, "-1.123456e+12") == 0); + assert(snprintf(buf, 128, "%e", -1.123456e-12) == 13); + assert(strcmp(buf, "-1.123456e-12") == 0); + assert(snprintf(buf, 128, "%e", INFINITY) == 3); + assert(strcmp(buf, "inf") == 0); + assert(snprintf(buf, 128, "%e", NAN) == 3); + assert(strcmp(buf, "nan") == 0); + assert(snprintf(buf, 128, "%le", 1.123456e12) == 12); + assert(strcmp(buf, "1.123456e+12") == 0); + assert(snprintf(buf, 128, "%Le", 1.123456e12L) == 12); + assert(strcmp(buf, "1.123456e+12") == 0); + assert(snprintf(buf, 128, "%E", 1.123456e12) == 12); + assert(strcmp(buf, "1.123456E+12") == 0); + assert(snprintf(buf, 128, "%E", INFINITY) == 3); + assert(strcmp(buf, "INF") == 0); + assert(snprintf(buf, 128, "%E", NAN) == 3); + assert(strcmp(buf, "NAN") == 0); + assert(snprintf(buf, 128, "%lE", 1.123456e12) == 12); + assert(strcmp(buf, "1.123456E+12") == 0); + assert(snprintf(buf, 128, "%LE", 1.123456e12L) == 12); + assert(strcmp(buf, "1.123456E+12") == 0); + + /*assert(snprintf(buf, 128, "%a", 0x1.123456p0) == 13); + assert(strcmp(buf, "0x1.123456p+0") == 0); + assert(snprintf(buf, 128, "%a", 0.0) == 6); + assert(strcmp(buf, "0x0p+0") == 0); + assert(snprintf(buf, 128, "%a", 0x1.123456p12) == 14); + assert(strcmp(buf, "0x1.123456p+12") == 0); + assert(snprintf(buf, 128, "%a", -0x1.123456p-12) == 15); + assert(strcmp(buf, "-0x1.123456p-12") == 0); + assert(snprintf(buf, 128, "%a", INFINITY) == 3); + assert(strcmp(buf, "inf") == 0); + assert(snprintf(buf, 128, "%a", NAN) == 3); + assert(strcmp(buf, "nan") == 0); + assert(snprintf(buf, 128, "%la", 0x1.123456p12) == 14); + assert(strcmp(buf, "0x1.123456p+12") == 0); + assert(snprintf(buf, 128, "%La", 0x1.123456p12L) == 12); + assert(strcmp(buf, "0x8.91a2bp+9") == 0); + assert(snprintf(buf, 128, "%A", 0x1.123456p12) == 14); + assert(strcmp(buf, "0X1.123456P+12") == 0); + assert(snprintf(buf, 128, "%A", INFINITY) == 3); + assert(strcmp(buf, "INF") == 0); + assert(snprintf(buf, 128, "%A", NAN) == 3); + assert(strcmp(buf, "NAN") == 0); + assert(snprintf(buf, 128, "%lA", 0x1.123456p12) == 14); + assert(strcmp(buf, "0X1.123456P+12") == 0); + assert(snprintf(buf, 128, "%LA", 0x1.123456p12L) == 12); + assert(strcmp(buf, "0X8.91A2BP+9") == 0);*/ + + assert(snprintf(buf, 128, "%g", 1.1234) == 6); + assert(strcmp(buf, "1.1234") == 0); + assert(snprintf(buf, 128, "%g", 0.0) == 1); + assert(strcmp(buf, "0") == 0); + assert(snprintf(buf, 128, "%g", -1.1234) == 7); + assert(strcmp(buf, "-1.1234") == 0); + assert(snprintf(buf, 128, "%g", 1.1234e12) == 10); + assert(strcmp(buf, "1.1234e+12") == 0); + assert(snprintf(buf, 128, "%g", -1.1234e-12) == 11); + assert(strcmp(buf, "-1.1234e-12") == 0); + assert(snprintf(buf, 128, "%g", INFINITY) == 3); + assert(strcmp(buf, "inf") == 0); + assert(snprintf(buf, 128, "%g", NAN) == 3); + assert(strcmp(buf, "nan") == 0); + assert(snprintf(buf, 128, "%lg", 1.1234e12) == 10); + assert(strcmp(buf, "1.1234e+12") == 0); + assert(snprintf(buf, 128, "%Lg", 1.1234e12L) == 10); + assert(strcmp(buf, "1.1234e+12") == 0); + assert(snprintf(buf, 128, "%G", 1.1234) == 6); + assert(strcmp(buf, "1.1234") == 0); + assert(snprintf(buf, 128, "%G", 1.1234e12) == 10); + assert(strcmp(buf, "1.1234E+12") == 0); + assert(snprintf(buf, 128, "%G", INFINITY) == 3); + assert(strcmp(buf, "INF") == 0); + assert(snprintf(buf, 128, "%G", NAN) == 3); + assert(strcmp(buf, "NAN") == 0); + assert(snprintf(buf, 128, "%lG", 1.1234e12) == 10); + assert(strcmp(buf, "1.1234E+12") == 0); + assert(snprintf(buf, 128, "%LG", 1.1234e12L) == 10); + assert(strcmp(buf, "1.1234E+12") == 0); + + signed char char_value = 0; + assert(snprintf(buf, 128, "ab%hhnc", &char_value) == 3); + assert(strcmp(buf, "abc") == 0); + assert(char_value == 2); + short short_value = 0; + assert(snprintf(buf, 128, "ab%hnc", &short_value) == 3); + assert(strcmp(buf, "abc") == 0); + assert(short_value == 2); + int int_value = 0; + assert(snprintf(buf, 128, "ab%nc", &int_value) == 3); + assert(strcmp(buf, "abc") == 0); + assert(int_value == 2); + long long_value = 0; + assert(snprintf(buf, 128, "ab%lnc", &long_value) == 3); + assert(strcmp(buf, "abc") == 0); + assert(long_value == 2); + long long long_long_value = 0; + assert(snprintf(buf, 128, "ab%llnc", &long_long_value) == 3); + assert(strcmp(buf, "abc") == 0); + assert(long_long_value == 2); + intmax_t intmax_value = 0; + assert(snprintf(buf, 128, "ab%jnc", &intmax_value) == 3); + assert(strcmp(buf, "abc") == 0); + assert(intmax_value == 2); + ssize_t size_value = 0; + assert(snprintf(buf, 128, "ab%znc", &size_value) == 3); + assert(strcmp(buf, "abc") == 0); + assert(size_value == 2); + ptrdiff_t ptrdiff_value = 0; + assert(snprintf(buf, 128, "ab%tnc", &ptrdiff_value) == 3); + assert(strcmp(buf, "abc") == 0); + assert(ptrdiff_value == 2); + +#if UINTPTR_MAX == UINT64_MAX + uintptr_t ptr_value = 0xFFFFFFFFFFFFFFFF; + assert(snprintf(buf, 128, "%p", (void *)ptr_value) == 18); + assert(strcmp(buf, "0xffffffffffffffff") == 0); +#else + uintptr_t ptr_value = 0xFFFFFFFF; + assert(snprintf(buf, 128, "%p", (void*)ptr_value) == 10); + assert(strcmp(buf, "0xffffffff") == 0); +#endif + + ptr_value = 0xFFFF; + assert(snprintf(buf, 128, "%p", (void*)ptr_value) == 6); + assert(strcmp(buf, "0xffff") == 0); + + assert(snprintf(buf, 128, "%-4dhello", 12) == 9); + assert(strcmp(buf, "12 hello") == 0); + + assert(snprintf(buf, 128, "%-4dhello", -12) == 9); + assert(strcmp(buf, "-12 hello") == 0); + + assert(snprintf(buf, 128, "%#-4xhello", 0x12) == 9); + assert(strcmp(buf, "0x12hello") == 0); + assert(snprintf(buf, 128, "%#-4Xhello", 0x12) == 9); + assert(strcmp(buf, "0X12hello") == 0); + + assert(snprintf(buf, 128, "%#b", 0b1011) == 6); + assert(strcmp(buf, "0b1011") == 0); + assert(snprintf(buf, 128, "%#B", 0b1011) == 6); + assert(strcmp(buf, "0B1011") == 0); + + assert(snprintf(buf, 128, "%+d", 1234) == 5); + assert(strcmp(buf, "+1234") == 0); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(snprintf(buf, 128, "%+ d", 1234) == 5); + assert(strcmp(buf, "+1234") == 0); +#pragma GCC diagnostic pop + + assert(snprintf(buf, 128, "% d", 1234) == 5); + assert(strcmp(buf, " 1234") == 0); + + assert(snprintf(buf, 128, "%4dhello", 12) == 9); + assert(strcmp(buf, " 12hello") == 0); + assert(snprintf(buf, 128, "%2dhello", 1234) == 9); + assert(strcmp(buf, "1234hello") == 0); + int width = 4; + assert(snprintf(buf, 128, "%*dhello", width, 12) == 9); + assert(strcmp(buf, " 12hello") == 0); + width = -4; + assert(snprintf(buf, 128, "%*dhello", width, 12) == 9); + assert(strcmp(buf, "12 hello") == 0); + + assert(snprintf(buf, 128, "%04dhello", 12) == 9); + assert(strcmp(buf, "0012hello") == 0); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(snprintf(buf, 128, "%-04dhello", 12) == 9); + assert(strcmp(buf, "12 hello") == 0); + assert(snprintf(buf, 128, "%04.2dhello", 1) == 9); + assert(strcmp(buf, " 01hello") == 0); +#pragma GCC diagnostic pop + assert(snprintf(buf, 128, "%.d", 0) == 0); + assert(strcmp(buf, "") == 0); + assert(snprintf(buf, 128, "%.0d", 0) == 0); + assert(strcmp(buf, "") == 0); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(snprintf(buf, 128, "%04.d", 0) == 4); + assert(strcmp(buf, " ") == 0); + assert(snprintf(buf, 128, "%#04.x", 0) == 4); + assert(strcmp(buf, " ") == 0); + assert(snprintf(buf, 128, "%+04.d", 0) == 4); + assert(strcmp(buf, " +") == 0); + assert(snprintf(buf, 128, "%+0.d", 0) == 1); + assert(strcmp(buf, "+") == 0); +#pragma GCC diagnostic pop + int precision = 0; + assert(snprintf(buf, 128, "%.*d", precision, 0) == 0); + assert(strcmp(buf, "") == 0); + precision = -1; + assert(snprintf(buf, 128, "%.*d", precision, 0) == 1); + assert(strcmp(buf, "0") == 0); + assert(snprintf(buf, 128, "%.6d", 1234) == 6); + assert(strcmp(buf, "001234") == 0); + + assert(snprintf(buf, 128, "%.o", 0) == 0); + assert(strcmp(buf, "") == 0); + assert(snprintf(buf, 128, "%.0o", 0) == 0); + assert(strcmp(buf, "") == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/sprintf.c b/user/include/mlibc/tests/ansi/sprintf.c new file mode 100644 index 0000000..f157c9f --- /dev/null +++ b/user/include/mlibc/tests/ansi/sprintf.c @@ -0,0 +1,371 @@ +#include +#include +#include +#include +#include + +int main() { + char buf[64] = { 0 }; + sprintf(buf, "%d", 12); + assert(!strcmp(buf, "12")); + + sprintf(buf, "%f", 3.14); + assert(!strcmp(buf, "3.140000")); + sprintf(buf, "%.1f", 0.0); + assert(!strcmp(buf, "0.0")); + + // Test %g + sprintf(buf, "%g", 0.0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%.2g", 0.01234); + assert(!strcmp(buf, "0.012")); + sprintf(buf, "%.3g", 1.1); + assert(!strcmp(buf, "1.1")); + sprintf(buf, "%#.5g", 1.1); + assert(!strcmp(buf, "1.1000")); + sprintf(buf, "%g", 0.0000123); + assert(!strcmp(buf, "1.23e-05")); + + // Test %e + sprintf(buf, "%4.3e", 0.0); + assert(!strcmp(buf, "0.000e+00")); + sprintf(buf, "%.3e", 6.9e27); + assert(!strcmp(buf, "6.900e+27")); + + // Test %c right padding. + sprintf(buf, "%-2c", 'a'); + assert(!strcmp(buf, "a ")); + + // Test %c left padding. + sprintf(buf, "%2c", 'a'); + assert(!strcmp(buf, " a")); + + // Test %d right padding - mlibc issue #58. + sprintf(buf, "%-2d", 1); + assert(!strcmp(buf, "1 ")); + sprintf(buf, "%-2.2d", 1); + assert(!strcmp(buf, "01")); + sprintf(buf, "%-3.2d", 1); + assert(!strcmp(buf, "01 ")); + sprintf(buf, "%-3.2d", 12); + assert(!strcmp(buf, "12 ")); + sprintf(buf, "%-3.2d", 123); + assert(!strcmp(buf, "123")); + sprintf(buf, "%-3.2u", 12); + assert(!strcmp(buf, "12 ")); + + // Test %d left padding. + sprintf(buf, "%2d", 1); + assert(!strcmp(buf, " 1")); + sprintf(buf, "%3.2d", 1); + assert(!strcmp(buf, " 01")); + sprintf(buf, "%3.2d", 12); + assert(!strcmp(buf, " 12")); + sprintf(buf, "%3.2d", 123); + assert(!strcmp(buf, "123")); + sprintf(buf, "%3.2u", 12); + assert(!strcmp(buf, " 12")); + // Disable -Wformat here since we deliberately induce some warnings. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + sprintf(buf, "%04.3u", 12); + assert(!strcmp(buf, " 012")); +#pragma GCC diagnostic pop + sprintf(buf, "%+04d", 0); + assert(!strcmp(buf, "+000")); + + // Test %f padding. + // TODO: Test printing of huge numbers (larger than 2^64) + sprintf(buf, "%2.f", 1.2); + assert(!strcmp(buf, " 1")); + sprintf(buf, "%2.f", 12.3); + assert(!strcmp(buf, "12")); + sprintf(buf, "%5.2f", 1.0); + assert(!strcmp(buf, " 1.00")); + sprintf(buf, "%.1f", -4.0); + assert(!strcmp(buf, "-4.0")); + sprintf(buf, "%-3.f", 8.0); + assert(!strcmp(buf, "8 ")); + sprintf(buf, "%4f", INFINITY); + assert(!strcmp(buf, " inf") || !strcmp(buf, "infinity")); + sprintf(buf, "%4f", NAN); + assert(!strcmp(buf, " nan")); + sprintf(buf, "%4F", INFINITY); + assert(!strcmp(buf, " INF") || !strcmp(buf, "INFINITY")); + sprintf(buf, "%4F", NAN); + assert(!strcmp(buf, " NAN")); + sprintf(buf, "%05.2f", 1.0); + assert(!strcmp(buf, "01.00")); + sprintf(buf, "%09f", INFINITY); // 0 ignored when padding infs + assert(!strcmp(buf, " inf") || !strcmp(buf, " infinity")); + + // Test %f rounding + sprintf(buf, "%5.2f", 1.2); + assert(!strcmp(buf, " 1.20")); + sprintf(buf, "%5.2f", 1.23); + assert(!strcmp(buf, " 1.23")); + sprintf(buf, "%5.2f", 1.234); + assert(!strcmp(buf, " 1.23")); + sprintf(buf, "%5.2f", 12.345); + assert(!strcmp(buf, "12.35")); + sprintf(buf, "%-5.2f", 1.2); + assert(!strcmp(buf, "1.20 ")); + + // Test '+' and ' ' flags - mlibc issue #229. + // Disable -Wformat here since we deliberately induce some warnings. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + sprintf(buf, "%+d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "% d", 12); + assert(!strcmp(buf, " 12")); + sprintf(buf, "% +d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "%+ d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "%+d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "% d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "% +d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "%+ d", -12); + assert(!strcmp(buf, "-12")); +#pragma GCC diagnostic pop + + // Test '#' flag. + // TODO: Test with a, A, e, E, f, F, g, G conversions. + sprintf(buf, "%#x", 12); + assert(!strcmp(buf, "0xc")); + sprintf(buf, "%#X", 12); + assert(!strcmp(buf, "0XC")); + sprintf(buf, "%#o", 12); + assert(!strcmp(buf, "014")); + + sprintf(buf, "%#x", 0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%#X", 0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%#o", 0); + assert(!strcmp(buf, "0")); + + // Disable -Wformat here because the compiler might not know about the b specifier. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + sprintf(buf, "%#b", 12); + assert(!strcmp(buf, "0b1100")); + sprintf(buf, "%#B", 12); + assert(!strcmp(buf, "0B1100")); + sprintf(buf, "%#b", 0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%#B", 0); + assert(!strcmp(buf, "0")); +#pragma GCC diagnostic pop + + // Test 'd' with different size mods to see + // if they work + sprintf(buf, "%d", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%ld", 12L); + assert(!strcmp(buf, "12")); + sprintf(buf, "%lld", 12LL); + assert(!strcmp(buf, "12")); + sprintf(buf, "%zd", (size_t)12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%hd", (short) 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%hhd", (char) 12); + assert(!strcmp(buf, "12")); + + // Test 'x' with different size mods to see + // if they work + sprintf(buf, "%x", 12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%lx", 12L); + assert(!strcmp(buf, "c")); + sprintf(buf, "%llx", 12LL); + assert(!strcmp(buf, "c")); + sprintf(buf, "%zx", (size_t)12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%hx", (unsigned short) 12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%hhx", (unsigned char) 12); + assert(!strcmp(buf, "c")); + + // Test 'X' with different size mods to see + // if they work + sprintf(buf, "%X", 12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%lX", 12L); + assert(!strcmp(buf, "C")); + sprintf(buf, "%llX", 12LL); + assert(!strcmp(buf, "C")); + sprintf(buf, "%zX", (size_t)12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%hX", (unsigned short) 12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%hhX", (unsigned char) 12); + assert(!strcmp(buf, "C")); + + // Test 'o' with different size mods to see + // if they work + sprintf(buf, "%o", 12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%lo", 12L); + assert(!strcmp(buf, "14")); + sprintf(buf, "%llo", 12LL); + assert(!strcmp(buf, "14")); + sprintf(buf, "%zo", (size_t)12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%ho", (unsigned short) 12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%hho", (unsigned char) 12); + assert(!strcmp(buf, "14")); + + // Disable -Wformat here because the compiler might not know about the b specifier. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + // Test 'b' with different size mods to see + // if they work + sprintf(buf, "%b", 12); + assert(!strcmp(buf, "1100")); + sprintf(buf, "%lb", 12L); + assert(!strcmp(buf, "1100")); + sprintf(buf, "%llb", 12LL); + assert(!strcmp(buf, "1100")); + sprintf(buf, "%zb", (size_t)12); + assert(!strcmp(buf, "1100")); + sprintf(buf, "%hb", (unsigned short) 12); + assert(!strcmp(buf, "1100")); + sprintf(buf, "%hhb", (unsigned char) 12); + assert(!strcmp(buf, "1100")); +#pragma GCC diagnostic pop + + // Test %n$ syntax. + sprintf(buf, "%1$d", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%1$d %1$d", 12); + assert(!strcmp(buf, "12 12")); + sprintf(buf, "%1$d %2$d %1$d", 12, 14); + assert(!strcmp(buf, "12 14 12")); + sprintf(buf, "%1$d %2$s %2$s", 12, "foo"); + assert(!strcmp(buf, "12 foo foo")); + + sprintf(buf, "%1$s%5$s%6$s%3$s%4$s%2$s", "a", "b", "u", "n", "h", "N"); + assert(!strcmp(buf, "ahNunb")); + + // test negative precision + sprintf(buf, "%.*g", -2, 15.1234567); + assert(!strcmp(buf, "15.1235")); + sprintf(buf, "%*g", -5, 15.1); + assert(!strcmp(buf, "15.1 ")); + // Disable -Wformat as the compiler rightfully warns that the '0' flag is ignored + // when the '0' flag is used +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + sprintf(buf, "%0-6g", 69.2); + assert(!strcmp(buf, "69.2 ")); +#pragma GCC diagnostic pop + + // More extensive floating point tests. + // Test zero and negative zero + sprintf(buf, "%f", 0.0); + assert(!strcmp(buf, "0.000000")); + sprintf(buf, "%f", -0.0); + assert(!strcmp(buf, "-0.000000")); + sprintf(buf, "%e", 0.0); + assert(!strcmp(buf, "0.000000e+00")); + sprintf(buf, "%e", -0.0); + assert(!strcmp(buf, "-0.000000e+00")); + sprintf(buf, "%g", 0.0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%g", -0.0); + assert(!strcmp(buf, "-0")); + + // Test rounding + sprintf(buf, "%.2f", 1.235); + assert(!strcmp(buf, "1.24")); + sprintf(buf, "%.2f", -1.235); + assert(!strcmp(buf, "-1.24")); + // 1.2349999999999998 is a double literal that is slightly less than 1.235 + sprintf(buf, "%.2f", 1.2349999999999998); + assert(!strcmp(buf, "1.23")); + sprintf(buf, "%.0f", 0.49); + assert(!strcmp(buf, "0")); + sprintf(buf, "%.0f", -0.49); + assert(!strcmp(buf, "-0")); + + // Test round-to-even behavior + fesetround(FE_TONEAREST); + + sprintf(buf, "%.0f", 0.5); + assert(!strcmp(buf, "0")); + sprintf(buf, "%.0f", -0.5); + assert(!strcmp(buf, "-0")); + sprintf(buf, "%.0f", 0.51); + assert(!strcmp(buf, "1")); + sprintf(buf, "%.0f", -0.51); + assert(!strcmp(buf, "-1")); + sprintf(buf, "%.0f", 2.5); + assert(!strcmp(buf, "2")); + sprintf(buf, "%.0f", -2.5); + assert(!strcmp(buf, "-2")); + sprintf(buf, "%.0f", 2.51); + assert(!strcmp(buf, "3")); + sprintf(buf, "%.0f", -2.51); + assert(!strcmp(buf, "-3")); + + // Test %e/%E + sprintf(buf, "%.3e", 12345.0); + assert(!strcmp(buf, "1.234e+04")); + sprintf(buf, "%.3E", 12345.0); + assert(!strcmp(buf, "1.234E+04")); + sprintf(buf, "%.3e", 0.00012345); + assert(!strcmp(buf, "1.234e-04")); + sprintf(buf, "%.3E", -0.00012345); + assert(!strcmp(buf, "-1.234E-04")); + + // Test %g/%G behavior + sprintf(buf, "%g", 123456.0); // Should not use e-notation + assert(!strcmp(buf, "123456")); + sprintf(buf, "%g", 1234567.0); // Should use e-notation + assert(!strcmp(buf, "1.23457e+06")); + sprintf(buf, "%g", 12345.0); + assert(!strcmp(buf, "12345")); + sprintf(buf, "%g", 1.2345); + assert(!strcmp(buf, "1.2345")); + sprintf(buf, "%g", 0.00012345); // Should not use e-notation + assert(!strcmp(buf, "0.00012345")); + sprintf(buf, "%g", 0.000012345); // Should use e-notation + assert(!strcmp(buf, "1.2345e-05")); + + // %g precision + sprintf(buf, "%.3g", 12345.0); + assert(!strcmp(buf, "1.23e+04")); + sprintf(buf, "%.3G", 12345.0); + assert(!strcmp(buf, "1.23E+04")); + sprintf(buf, "%.3g", 1.234); + assert(!strcmp(buf, "1.23")); + sprintf(buf, "%.3g", 0.001234); + assert(!strcmp(buf, "0.00123")); + sprintf(buf, "%.3g", 0.0001234); // Should not use e-notation + assert(!strcmp(buf, "0.000123")); + sprintf(buf, "%.3g", 0.00001234); // Should use e-notation + assert(!strcmp(buf, "1.23e-05")); + sprintf(buf, "%08.1g", 69.2); + assert(!strcmp(buf, "0007e+01")); + sprintf(buf, "%#08.4g", 69.29854); + assert(!strcmp(buf, "00069.30")); + + // %g trailing zeros + sprintf(buf, "%g", 1.200); + assert(!strcmp(buf, "1.2")); + sprintf(buf, "%#g", 1.200); + assert(!strcmp(buf, "1.20000")); + sprintf(buf, "%g", 1200.0); + assert(!strcmp(buf, "1200")); + sprintf(buf, "%#g", 1200.0); + assert(!strcmp(buf, "1200.00")); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/sscanf.c b/user/include/mlibc/tests/ansi/sscanf.c new file mode 100644 index 0000000..90be0d0 --- /dev/null +++ b/user/include/mlibc/tests/ansi/sscanf.c @@ -0,0 +1,516 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct format_test_cases { + const char *format; + const char *data; + int expected_int; + enum { + T_INT, + T_UINT, + T_CHAR, + T_NONE, + } type; + int ret; +} formats[] = { + {"%i", "0x420", 0x420, T_INT, 1}, + {"%i", "0420", 0420, T_INT, 1}, + {"%i", "420", 420, T_INT, 1}, + {"%i", "-420", -420, T_INT, 1}, + {"%d", "-12345", -12345, T_INT, 1}, + {"%u", "69", 69, T_UINT, 1}, + {"%u", "0420", 420, T_UINT, 1}, + {"%o", "0420", 0420, T_UINT, 1}, + {"%x", "0xCB7", 0xCB7, T_UINT, 1}, +#ifndef USE_HOST_LIBC + {"%b", "0b1011", 0b1011, T_UINT, 1}, + {"%b", "0B1011", 0b1011, T_UINT, 1}, +#endif + {"%%", "%", 0, T_NONE, 0}, + {"%c", " I am not a fan of this solution.", ' ', T_CHAR, 1}, + {" %c", " CBT (capybara therapy)", 'C', T_CHAR, 1}, + {"%d %d %d", " 111111 I<3Managarm 1234", 111111, T_UINT, 1}, + {"%c %d", "C", 'C', T_CHAR, 1} +}; + +#pragma GCC diagnostic ignored "-Wformat-security" + +static void test_matrix() { + for(size_t i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { + struct format_test_cases *f = &formats[i]; + int ret = -1; + int data_int; + unsigned int data_uint; + char data_char; + + switch(f->type) { + case T_INT: { + ret = sscanf(f->data, f->format, &data_int); + assert(data_int == f->expected_int); + break; + } + case T_UINT: { + ret = sscanf(f->data, f->format, &data_uint); + assert(data_uint == (unsigned int) f->expected_int); + break; + } + case T_CHAR: { + ret = sscanf(f->data, f->format, &data_char); + assert(data_char == (unsigned char) f->expected_int); + break; + } + case T_NONE: { + ret = sscanf(f->data, f->format); + break; + } + + } + + assert(ret == f->ret); + } +} + +int main() { + { + int x = 0; + char buf[] = "12345"; + sscanf(buf, "%d", &x); + assert(x == 12345); + } + + { + char c; + int n1; + int n2; + char buf[] = "z$ 7 5 440";; + int count = sscanf(buf, "%*c%c %d %*d %d", &c, &n1, &n2); + assert(count == 3); + assert(c == '$'); + assert(n1 == 7); + assert(n2 == 440); + } + + { + // From dsda-doom + char buf[] = "process_priority 0\n"; + char def[80], strparm[128]; + memset(def, '!', 80); + memset(strparm, '!', 128); + sscanf(buf, "%s %[^\n]\n", def, strparm); + assert(!strcmp(def, "process_priority")); + assert(!strcmp(strparm, "0")); + } + + { + char buf[] = "fffff100"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0xfffff100); + } + +#if !defined(__i386__) && !defined(__m68k__) + { + char buf[] = "fffffffff100"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0xfffffffff100); + } +#endif + + { + char buf[] = "410dc000"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0x410dc000); + } + + { + // From webkitgtk + char buf[] = "MemTotal: 16299664 kB\n"; + char token[51] = {0}; + size_t amount = 0; + int ret = sscanf(buf, "%50s%zukB", token, &amount); + assert(ret == 2); + assert(!strcmp(token, "MemTotal:")); + assert(amount == 16299664); + } + + { + char buf[] = "SIGINT"; + int sig; + int ret = sscanf(buf, "%d", &sig); + assert(!ret); + } + + { + char buf[50]; + int ret = sscanf("", "%s", buf); + assert(ret == EOF); + } + + { + char *str = NULL; + int ret = sscanf("Managarm", "%ms", &str); + assert(ret == 1); + assert(str != NULL); + assert(!strcmp(str, "Managarm")); + free(str); + } + + test_matrix(); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-zero-length" + assert(sscanf("", "") == 0); +#pragma GCC diagnostic pop + assert(sscanf("", "a") == EOF); + assert(sscanf(" \t\na", " a") == 0); + assert(sscanf("a%", "a%%") == 0); + assert(sscanf("ab", "abcd") == EOF); + assert(sscanf("abab", "abcd") == 0); + + char char_value[8]; + wchar_t wchar_value[8]; + + assert(sscanf("a", "%c", char_value) == 1); + assert(char_value[0] == 'a'); + assert(sscanf("a", "%lc", wchar_value) == 1); + assert(wchar_value[0] == L'a'); + assert(sscanf("hello", "%s", char_value) == 1); + assert(strcmp(char_value, "hello") == 0); + assert(sscanf("", "%s", char_value) == EOF); + assert(sscanf(" ", "%s", char_value) == EOF); + assert(sscanf(" a", "%sb", char_value) == 1); + assert(sscanf("hello", "%ls", wchar_value) == 1); + assert(wcscmp(wchar_value, L"hello") == 0); + assert(sscanf("abcd", "%[ac]bcd", char_value) == 1); + assert(strcmp(char_value, "a") == 0); + assert(sscanf("abcd", "%l[ac]bcd", wchar_value) == 1); + assert(wcscmp(wchar_value, L"a") == 0); + assert(sscanf("aacd", "%[ac]bcd", char_value) == 1); + assert(strcmp(char_value, "aac") == 0); + assert(sscanf("aacd", "%[ac]bcd", char_value) == 1); + assert(strcmp(char_value, "aac") == 0); + assert(sscanf("]", "%[]]", char_value) == 1); + assert(strcmp(char_value, "]") == 0); + assert(sscanf("]", "%[^]]", char_value) == 0); + assert(sscanf("abcd", "%[^ac]bcd", char_value) == 0); + assert(sscanf("aacd", "%[^ac]bcd", char_value) == 0); + assert(sscanf("aacd", "%[^ac]bcd", char_value) == 0); + assert(sscanf("ddd", "%[^ac]bcd", char_value) == 1); + assert(strcmp(char_value, "ddd") == 0); + assert(sscanf("abcd", "%[0-9]", char_value) == 0); + assert(sscanf("2a", "%[0-9]", char_value) == 1); + assert(strcmp(char_value, "2") == 0); + + unsigned char uchar_value; + signed char schar_value; + unsigned short ushort_value; + short short_value; + unsigned int uint_value; + int int_value; + unsigned long ulong_value; + long long_value; + unsigned long long ulonglong_value; + long long longlong_value; + uintmax_t uintmax_value; + intmax_t intmax_value; + size_t size_value; + ptrdiff_t ptrdiff_value; + + assert(sscanf("1234abc", "%d", &int_value) == 1); + assert(int_value == 1234); + assert(sscanf("123", "%hhd", &schar_value) == 1); + assert(schar_value == 123); + assert(sscanf("1234", "%hd", &short_value) == 1); + assert(short_value == 1234); + assert(sscanf("1234", "%ld", &long_value) == 1); + assert(long_value == 1234); + assert(sscanf("1234", "%lld", &longlong_value) == 1); + assert(longlong_value == 1234); + assert(sscanf("1234", "%jd", &intmax_value) == 1); + assert(intmax_value == 1234); + assert(sscanf("1234", "%zd", &size_value) == 1); + assert(size_value == 1234); + assert(sscanf("1234", "%td", &ptrdiff_value) == 1); + assert(ptrdiff_value == 1234); + assert(sscanf(" 1235abc", "%d", &int_value) == 1); + assert(int_value == 1235); + assert(sscanf("+1234abc", "%d", &int_value) == 1); + assert(int_value == 1234); + assert(sscanf("-1234abc", "%d", &int_value) == 1); + assert(int_value == -1234); + assert(sscanf("-abc", "%d", &int_value) == 0); + assert(sscanf("-", "%d", &int_value) == 0); + + assert(sscanf("1234abc", "%i", &int_value) == 1); + assert(int_value == 1234); + assert(sscanf("123", "%hhi", &schar_value) == 1); + assert(schar_value == 123); + assert(sscanf("1234", "%hi", &short_value) == 1); + assert(short_value == 1234); + assert(sscanf("1234", "%li", &long_value) == 1); + assert(long_value == 1234); + assert(sscanf("1234", "%lli", &longlong_value) == 1); + assert(longlong_value == 1234); + assert(sscanf("1234", "%ji", &intmax_value) == 1); + assert(intmax_value == 1234); + assert(sscanf("1234", "%zi", &size_value) == 1); + assert(size_value == 1234); + assert(sscanf("1234", "%ti", &ptrdiff_value) == 1); + assert(ptrdiff_value == 1234); + assert(sscanf(" 1235abc", "%i", &int_value) == 1); + assert(int_value == 1235); + assert(sscanf("+1234abc", "%i", &int_value) == 1); + assert(int_value == 1234); + assert(sscanf("-1234abc", "%i", &int_value) == 1); + assert(int_value == -1234); + assert(sscanf("-abc", "%i", &int_value) == 0); + + assert(sscanf(" 0b1011", "%i", &int_value) == 1); + assert(int_value == 0b1011); + assert(sscanf(" 0B1010", "%i", &int_value) == 1); + assert(int_value == 0b1010); + assert(sscanf(" +0b1011", "%i", &int_value) == 1); + assert(int_value == 0b1011); + assert(sscanf(" -0b1111", "%i", &int_value) == 1); + assert(int_value == -0b1111); + + assert(sscanf(" 01234", "%i", &int_value) == 1); + assert(int_value == 01234); + assert(sscanf(" +01234", "%i", &int_value) == 1); + assert(int_value == 01234); + assert(sscanf(" -01234", "%i", &int_value) == 1); + assert(int_value == -01234); + + assert(sscanf(" 0xab12", "%i", &int_value) == 1); + assert(int_value == 0xAB12); + assert(sscanf(" 0xAB12", "%i", &int_value) == 1); + assert(int_value == 0xAB12); + assert(sscanf(" 0Xab12", "%i", &int_value) == 1); + assert(int_value == 0xAB12); + assert(sscanf(" +0xab12", "%i", &int_value) == 1); + assert(int_value == 0xAB12); + assert(sscanf(" -0xab12", "%i", &int_value) == 1); + assert(int_value == -0xAB12); + + assert(sscanf("1234abc", "%u", &uint_value) == 1); + assert(uint_value == 1234); + assert(sscanf("123", "%hhu", &uchar_value) == 1); + assert(uchar_value == 123); + assert(sscanf("1234", "%hu", &ushort_value) == 1); + assert(ushort_value == 1234); + assert(sscanf("1234", "%lu", &ulong_value) == 1); + assert(ulong_value == 1234); + assert(sscanf("1234", "%llu", &ulonglong_value) == 1); + assert(ulonglong_value == 1234); + assert(sscanf("1234", "%ju", &uintmax_value) == 1); + assert(uintmax_value == 1234); + assert(sscanf("1234", "%zu", &size_value) == 1); + assert(size_value == 1234); + assert(sscanf("1234", "%tu", &ptrdiff_value) == 1); + assert(ptrdiff_value == 1234); + assert(sscanf(" 1235abc", "%u", &int_value) == 1); + assert(int_value == 1235); + assert(sscanf("+1234abc", "%u", &int_value) == 1); + assert(int_value == 1234); + assert(sscanf("-1234abc", "%u", &int_value) == 1); + assert(int_value == -1234); + assert(sscanf("-abc", "%d", &int_value) == 0); + + assert(sscanf(" 12345", "%o", &int_value) == 1); + assert(int_value == 012345); + assert(sscanf("12", "%hho", &uchar_value) == 1); + assert(uchar_value == 012); + assert(sscanf("1234", "%ho", &ushort_value) == 1); + assert(ushort_value == 01234); + assert(sscanf("1234", "%lo", &ulong_value) == 1); + assert(ulong_value == 01234); + assert(sscanf("1234", "%llo", &ulonglong_value) == 1); + assert(ulonglong_value == 01234); + assert(sscanf("1234", "%jo", &uintmax_value) == 1); + assert(uintmax_value == 01234); + assert(sscanf("1234", "%zo", &size_value) == 1); + assert(size_value == 01234); + assert(sscanf("1234", "%to", &ptrdiff_value) == 1); + assert(ptrdiff_value == 01234); + assert(sscanf(" 01234", "%o", &int_value) == 1); + assert(int_value == 01234); + assert(sscanf(" +01234", "%o", &int_value) == 1); + assert(int_value == 01234); + assert(sscanf(" -01234", "%o", &int_value) == 1); + assert(int_value == -01234); + + assert(sscanf(" 1234ab", "%x", &int_value) == 1); + assert(int_value == 0x1234AB); + assert(sscanf("12", "%hhx", &uchar_value) == 1); + assert(uchar_value == 0x12); + assert(sscanf("1234", "%hx", &ushort_value) == 1); + assert(ushort_value == 0x1234); + assert(sscanf("1234", "%lx", &ulong_value) == 1); + assert(ulong_value == 0x1234); + assert(sscanf("1234", "%llx", &ulonglong_value) == 1); + assert(ulonglong_value == 0x1234); + assert(sscanf("1234", "%jx", &uintmax_value) == 1); + assert(uintmax_value == 0x1234); + assert(sscanf("1234", "%zx", &size_value) == 1); + assert(size_value == 0x1234); + assert(sscanf("1234", "%tx", &ptrdiff_value) == 1); + assert(ptrdiff_value == 0x1234); + assert(sscanf(" 1234ABC", "%x", &int_value) == 1); + assert(int_value == 0x1234ABC); + assert(sscanf(" 1234ab", "%X", &int_value) == 1); + assert(int_value == 0x1234AB); + assert(sscanf(" 0x1234", "%x", &int_value) == 1); + assert(int_value == 0x1234); + assert(sscanf(" 0x1234A", "%x", &int_value) == 1); + assert(int_value == 0x1234A); + assert(sscanf(" 0X1234AB", "%x", &int_value) == 1); + assert(int_value == 0x1234AB); + assert(sscanf(" +0x1234", "%x", &int_value) == 1); + assert(int_value == 0x1234); + assert(sscanf(" -0x1234", "%x", &int_value) == 1); + assert(int_value == -0x1234); + + assert(sscanf("abc", "abc%n", &int_value) == 0); + assert(int_value == 3); + assert(sscanf("1234", "1234%hhn", &uchar_value) == 0); + assert(uchar_value == 4); + assert(sscanf("1234", "1234%hn", &ushort_value) == 0); + assert(ushort_value == 4); + assert(sscanf("1234", "1234%ln", &ulong_value) == 0); + assert(ulong_value == 4); + assert(sscanf("1234", "1234%lln", &ulonglong_value) == 0); + assert(ulonglong_value == 4); + assert(sscanf("1234", "1234%jn", &uintmax_value) == 0); + assert(uintmax_value == 4); + assert(sscanf("1234", "1234%zn", &size_value) == 0); + assert(size_value == 4); + assert(sscanf("1234", "1234%tn", &ptrdiff_value) == 0); + assert(ptrdiff_value == 4); + assert(sscanf("abcd", "ab%nc%c", &int_value, char_value) == 1); + assert(int_value == 2); + assert(char_value[0] == 'd'); + + float float_value; + double double_value; + long double long_double_value; + (void)float_value; + (void)double_value; + (void)long_double_value; + /*assert(sscanf("1.123", "%a", &float_value) == 1); + assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01); + assert(sscanf("1.123", "%la", &double_value) == 1); + assert(double_value >= 1.123 - 0.01 && double_value <= 1.123 + 0.01); + assert(sscanf("1.123", "%La", &long_double_value) == 1); + assert(long_double_value >= 1.123L - 0.01 && long_double_value <= 1.123L + 0.01); + assert(sscanf("1.1234", "%A", &float_value) == 1); + assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01); + assert(sscanf("1.123", "%e", &float_value) == 1); + assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01); + assert(sscanf("1.123", "%le", &double_value) == 1); + assert(double_value >= 1.123 - 0.01 && double_value <= 1.123 + 0.01); + assert(sscanf("1.123", "%Le", &long_double_value) == 1); + assert(long_double_value >= 1.123L - 0.01 && long_double_value <= 1.123L + 0.01); + assert(sscanf("1.1234", "%E", &float_value) == 1); + assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01); + assert(sscanf("1.123", "%f", &float_value) == 1); + assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01); + assert(sscanf("1.123", "%lf", &double_value) == 1); + assert(double_value >= 1.123 - 0.01 && double_value <= 1.123 + 0.01); + assert(sscanf("1.123", "%Lf", &long_double_value) == 1); + assert(long_double_value >= 1.123L - 0.01 && long_double_value <= 1.123L + 0.01); + assert(sscanf("1.1234", "%F", &float_value) == 1); + assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01); + assert(sscanf("1.123", "%g", &float_value) == 1); + assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01); + assert(sscanf("1.123", "%lg", &double_value) == 1); + assert(double_value >= 1.123 - 0.01 && double_value <= 1.123 + 0.01); + assert(sscanf("1.123", "%Lg", &long_double_value) == 1); + assert(long_double_value >= 1.123L - 0.01 && long_double_value <= 1.123L + 0.01); + assert(sscanf("1.1234", "%G", &float_value) == 1); + assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01); + assert(sscanf("+1.1234", "%f", &float_value) == 1); + assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01); + assert(sscanf("-1.1234", "%f", &float_value) == 1); + assert(float_value >= -1.1234f - 0.01 && float_value <= -1.1234f + 0.01); + assert(sscanf("1.1234e3", "%f", &float_value) == 1); + assert(float_value >= 1.1234E3f - 0.01 && float_value <= 1.1234E3f + 0.01); + assert(sscanf("1.1234E3", "%f", &float_value) == 1); + assert(float_value >= 1.1234E3f - 0.01 && float_value <= 1.1234E3f + 0.01); + assert(sscanf("0x1234", "%f", &float_value) == 1); + assert(float_value >= 0x1234P0f - 0.01 && float_value <= 0x1234P0f + 0.01); + assert(sscanf("0X1234", "%f", &float_value) == 1); + assert(float_value >= 0x1234P0f - 0.01 && float_value <= 0x1234P0f + 0.01); + assert(sscanf("0x1.1234", "%f", &float_value) == 1); + assert(float_value >= 0x1.1234P0 - 0.01 && float_value <= 0x1.1234P0 + 0.01); + assert(sscanf("0x1.abcdP3", "%f", &float_value) == 1); + assert(float_value >= 0x1.ABCDP3 - 0.01 && float_value <= 0x1.ABCDP3 + 0.01); + assert(sscanf("0x1.abcdP+3", "%f", &float_value) == 1); + assert(float_value >= 0x1.ABCDP3 - 0.01 && float_value <= 0x1.ABCDP3 + 0.01); + assert(sscanf("0x1.abcdP-3", "%f", &float_value) == 1); + assert(float_value >= 0x1.ABCDP-3 - 0.01 && float_value <= 0x1.ABCDP-3 + 0.01); + assert(sscanf("0x1.AbCdP-3", "%f", &float_value) == 1); + assert(float_value >= 0x1.ABCDP-3 - 0.01 && float_value <= 0x1.ABCDP-3 + 0.01); + assert(sscanf("inf", "%f", &float_value) == 1); + assert(isinf(float_value)); + assert(sscanf("InF", "%f", &float_value) == 1); + assert(isinf(float_value)); + assert(sscanf("+inf", "%f", &float_value) == 1); + assert(isinf(float_value)); + assert(sscanf("-inf", "%f", &float_value) == 1); + assert(isinf(float_value)); + assert(sscanf("INF", "%f", &float_value) == 1); + assert(isinf(float_value)); + assert(sscanf("infinity", "%f", &float_value) == 1); + assert(isinf(float_value)); + assert(sscanf("INFINITY", "%f", &float_value) == 1); + assert(isinf(float_value)); + assert(sscanf("nan", "%f", &float_value) == 1); + assert(isnan(float_value)); + assert(sscanf("NaN", "%f", &float_value) == 1); + assert(isnan(float_value)); + assert(sscanf("+nan", "%f", &float_value) == 1); + assert(isnan(float_value)); + assert(sscanf("-nan", "%f", &float_value) == 1); + assert(isnan(float_value)); + assert(sscanf("0xhello", "%f", &float_value) == 0); + assert(sscanf("0x1hello", "%f", &float_value) == 1); + assert(float_value >= 0x1P0f - 0.01 && float_value <= 0x1P0f + 0.01); + assert(sscanf("ab1.1234", "%f", &float_value) == 0); + assert(sscanf(" 1.123", "%f", &float_value) == 1); + assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01);*/ + + void* ptr; + assert(sscanf("hello", "%p", &ptr) == 0); +#if UINTPTR_MAX == UINT64_MAX + assert(sscanf("0xabcdef12abcdef12", "%p", &ptr) == 1); + assert(ptr == (void*)0xabcdef12abcdef12); +#else + assert(sscanf("0xabcdef12", "%p", &ptr) == 1); + assert(ptr == (void*)0xabcdef12); +#endif + + assert(sscanf("a", "%*c") == 0); + char_value[2] = 'q'; + assert(sscanf("abcd", "%2c", char_value) == 1); + assert(char_value[2] == 'q'); + char_value[2] = 0; + assert(strcmp(char_value, "ab") == 0); + + assert(sscanf("cdef", "%2s", char_value) == 1); + assert(strcmp(char_value, "cd") == 0); + assert(sscanf("c def", "%2s", char_value) == 1); + assert(strcmp(char_value, "c") == 0); + + assert(sscanf("aacd", "%2[ac]", char_value) == 1); + assert(strcmp(char_value, "aa") == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/strchr.c b/user/include/mlibc/tests/ansi/strchr.c new file mode 100644 index 0000000..a80a1f9 --- /dev/null +++ b/user/include/mlibc/tests/ansi/strchr.c @@ -0,0 +1,20 @@ +#include +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + // The character 's' is at position 4, 7, 11 and 18 + pch = strchr(str, 's'); + assert(pch - str + 1 == 4); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 7); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 11); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 18); + pch = strchr(pch + 1, 's'); + assert(pch == NULL); + return 0; +} diff --git a/user/include/mlibc/tests/ansi/strftime.c b/user/include/mlibc/tests/ansi/strftime.c new file mode 100644 index 0000000..feb0338 --- /dev/null +++ b/user/include/mlibc/tests/ansi/strftime.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +int main() { + // Date representation depends on locale, here only C is tested. + // Maybe consider testing more locales? + if (setlocale (LC_ALL, "C") == NULL) { + fputs("strftime testcase could not set locale, errors may be expected!", stderr); + } + + char timebuf[32]; + char result[32] = " 8"; + struct tm tm; + tm.tm_sec = 0; + tm.tm_min = 17; + tm.tm_hour = 17; + tm.tm_mday = 8; + tm.tm_mon = 2; + tm.tm_year = 121; + tm.tm_wday = 2; + tm.tm_yday = 39; + tm.tm_gmtoff = 3600; + strftime(timebuf, sizeof(timebuf), "%e", &tm); + assert(!strcmp(timebuf, result)); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%x", &tm); + assert(!strcmp(timebuf, "03/08/21")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%X", &tm); + assert(!strcmp(timebuf, "17:17:00")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%D", &tm); + assert(!strcmp(timebuf, "03/08/21")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%OB %Ob", &tm); + assert(!strcmp(timebuf, "March Mar")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%c", &tm); + memset(result, 0, sizeof(result)); + strftime(result, sizeof(result), "%a %b %e %H:%M:%S %Y", &tm); + assert(!strcmp(timebuf, result)); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%k %p %P%n", &tm); + assert(!strcmp(timebuf, "17 PM pm\n")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%a %A", &tm); + assert(!strcmp(timebuf, "Tue Tuesday")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%b %B %h", &tm); + assert(!strcmp(timebuf, "Mar March Mar")); + + memset(timebuf, 0, sizeof(timebuf)); + assert(!strftime(timebuf, sizeof(timebuf), "%a %A %a %A %b %B %h", &tm)); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%z", &tm); + assert(!strcmp(timebuf, "+0100")); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/strrchr.c b/user/include/mlibc/tests/ansi/strrchr.c new file mode 100644 index 0000000..2de9821 --- /dev/null +++ b/user/include/mlibc/tests/ansi/strrchr.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + pch = strrchr(str, 's'); + // The last occurence of 's' is at position 18 + assert(pch - str + 1 == 18); + return 0; +} diff --git a/user/include/mlibc/tests/ansi/strtof.c b/user/include/mlibc/tests/ansi/strtof.c new file mode 100644 index 0000000..a13af90 --- /dev/null +++ b/user/include/mlibc/tests/ansi/strtof.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#define FLT_RANGE 0.000001f +#define DBL_RANGE 0.000001 +#define LDBL_RANGE 0.000001 + +#define DO_TEST(str, value, off, func, range) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + __typeof(func(s, &pEnd)) result = func(s, &pEnd); \ + assert(result >= (value) - (range)); \ + assert(result <= (value) + (range)); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +#define DO_TEST_SUCCESS_FUNC(str, success_func, off, func) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + assert(success_func(func(s, &pEnd))); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +int main () { + DO_TEST("0", 0.0f, -1, strtof, FLT_RANGE); + DO_TEST("0.12", 0.12f, -1, strtof, FLT_RANGE); + DO_TEST("12", 12.0f, -1, strtof, FLT_RANGE); + DO_TEST("12.13", 12.13f, -1, strtof, FLT_RANGE); + DO_TEST("10.0e1", 100.0f, -1, strtof, FLT_RANGE); + DO_TEST("10.0e10", 100000000000.0f, -1, strtof, FLT_RANGE); + DO_TEST("100.0e-1", 10.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x0", 0.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x0.12", 0.0703125f, -1, strtof, FLT_RANGE); + DO_TEST("0x12", 18.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x12.13", 18.07421875f, -1, strtof, FLT_RANGE); + DO_TEST("0x10.0p1", 32.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x10.0p10", 16384.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x100.0p-1", 128.0f, -1, strtof, FLT_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtof); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtof); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtof); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtof); + + DO_TEST("0", 0.0, -1, strtod, DBL_RANGE); + DO_TEST("0.12", 0.12, -1, strtod, DBL_RANGE); + DO_TEST("12", 12.0, -1, strtod, DBL_RANGE); + DO_TEST("12.13", 12.13, -1, strtod, DBL_RANGE); + DO_TEST("10.0e1", 100.0, -1, strtod, DBL_RANGE); + DO_TEST("10.0e10", 100000000000.0, -1, strtod, DBL_RANGE); + DO_TEST("100.0e-1", 10.0, -1, strtod, DBL_RANGE); + DO_TEST("0x0", 0.0, -1, strtod, DBL_RANGE); + DO_TEST("0x0.12", 0.0703125, -1, strtod, DBL_RANGE); + DO_TEST("0x12", 18.0, -1, strtod, DBL_RANGE); + DO_TEST("0x12.13", 18.07421875, -1, strtod, DBL_RANGE); + DO_TEST("0x10.0p1", 32.0, -1, strtod, DBL_RANGE); + DO_TEST("0x10.0p10", 16384.0, -1, strtod, DBL_RANGE); + DO_TEST("0x100.0p-1", 128.0, -1, strtod, DBL_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtod); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtod); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtod); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtod); + + DO_TEST("0", 0.0, -1, strtold, LDBL_RANGE); + DO_TEST("0.12", 0.12, -1, strtold, LDBL_RANGE); + DO_TEST("12", 12.0, -1, strtold, LDBL_RANGE); + DO_TEST("12.13", 12.13, -1, strtold, LDBL_RANGE); + DO_TEST("10.0e1", 100.0, -1, strtold, LDBL_RANGE); + DO_TEST("10.0e10", 100000000000.0, -1, strtold, LDBL_RANGE); + DO_TEST("100.0e-1", 10.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x0", 0.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x0.12", 0.0703125, -1, strtold, LDBL_RANGE); + DO_TEST("0x12", 18.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x12.13", 18.07421875, -1, strtold, LDBL_RANGE); + DO_TEST("0x10.0p1", 32.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x10.0p10", 16384.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x100.0p-1", 128.0, -1, strtold, LDBL_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtold); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtold); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtold); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtold); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/strtol.c b/user/include/mlibc/tests/ansi/strtol.c new file mode 100644 index 0000000..6002486 --- /dev/null +++ b/user/include/mlibc/tests/ansi/strtol.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include +#include + +#define DO_TEST(str, value, off, func, base) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == 0); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +#define DO_ERR_TEST(str, value, err, func, base) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == err); \ + assert(pEnd == (err == ERANGE ? s + strlen(s) : s)); }) + +#define DO_TESTL(str, value, off, func, base) ({ \ + wchar_t s[] = (str); \ + wchar_t *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == 0); \ + assert(pEnd == (off == -1 ? s + wcslen(s) : s + off)); }) + +#define DO_ERR_TESTL(str, value, err, func, base) ({ \ + wchar_t s[] = (str); \ + wchar_t *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == err); \ + assert(pEnd == (err == ERANGE ? s + wcslen(s) : s)); }) + +int main () { + // A few generic checks. + DO_TEST("0", 0, -1, strtol, 0); + DO_TEST("0", 0, -1, strtol, 10); + DO_TEST("2001", 2001, -1, strtol, 10); + DO_TEST("+2001", 2001, -1, strtol, 10); + DO_TEST("60c0c0", 0x60c0c0, -1, strtol, 16); + DO_TEST("-1101110100110100100000", -3624224, -1, strtol, 2); + DO_TEST("0x6fffff", 0x6fffff, -1, strtol, 0); + DO_TEST("0666", 0666, -1, strtol, 0); +#ifndef USE_HOST_LIBC + DO_TEST("1100", 0b1100, -1, strtol, 2); + DO_TEST("0b1100", 0b1100, -1, strtol, 0); + DO_TEST("0B1100", 0b1100, -1, strtol, 0); + DO_TEST("0b1zzz", 1, 3, strtol, 0); +#endif + DO_TEST("0xzzz", 0, 1, strtol, 0); + DO_TEST("0yzzz", 0, 1, strtol, 0); + DO_TEST("00xzz", 0, 2, strtol, 0); + DO_ERR_TEST("", 0, 0, strtol, 10); + DO_ERR_TEST("asd", 0, 0, strtol, 10); + DO_ERR_TEST("999999999999999999999999999", LONG_MAX, ERANGE, strtol, 10); + DO_ERR_TEST("-999999999999999999999999999", LONG_MIN, ERANGE, strtol, 10); + + // strtol +#if defined(__i386__) || defined(__m68k__) + DO_TEST("-2147483648", LONG_MIN, -1, strtol, 10); + DO_TEST("2147483647", LONG_MAX, -1, strtol, 10); + DO_ERR_TEST("-2147483649", LONG_MIN, ERANGE, strtol, 10); + DO_ERR_TEST("2147483648", LONG_MAX, ERANGE, strtol, 10); +#else + DO_TEST("-9223372036854775808", LONG_MIN, -1, strtol, 10); + DO_TEST("9223372036854775807", LONG_MAX, -1, strtol, 10); + DO_ERR_TEST("9223372036854775808", LONG_MAX, ERANGE, strtol, 10); + DO_ERR_TEST("-9223372036854775809", LONG_MIN, ERANGE, strtol, 10); +#endif + + // wcstol +#if defined(__i386__) || defined(__m68k__) + DO_TESTL(L"-2147483648", LONG_MIN, -1, wcstol, 10); + DO_TESTL(L"2147483647", LONG_MAX, -1, wcstol, 10); + DO_ERR_TESTL(L"2147483648", LONG_MAX, ERANGE, wcstol, 10); + DO_ERR_TESTL(L"-2147483649", LONG_MIN, ERANGE, wcstol, 10); +#else + DO_TESTL(L"-9223372036854775808", LONG_MIN, -1, wcstol, 10); + DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstol, 10); + DO_ERR_TESTL(L"9223372036854775808", LONG_MAX, ERANGE, wcstol, 10); + DO_ERR_TESTL(L"-9223372036854775809", LONG_MIN, ERANGE, wcstol, 10); +#endif + + // strtoll + DO_TEST("-9223372036854775808", LLONG_MIN, -1, strtoll, 10); + DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoll, 10); + DO_ERR_TEST("9223372036854775808", LLONG_MAX, ERANGE, strtoll, 10); + DO_ERR_TEST("-9223372036854775809", LLONG_MIN, ERANGE, strtoll, 10); + // wcstoll + DO_TESTL(L"-9223372036854775808", LLONG_MIN, -1, wcstoll, 10); + DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoll, 10); + DO_ERR_TESTL(L"9223372036854775808", LLONG_MAX, ERANGE, wcstoll, 10); + DO_ERR_TESTL(L"-9223372036854775809", LLONG_MIN, ERANGE, wcstoll, 10); + + // strtoul +#if defined(__i386__) || defined(__m68k__) + DO_TEST("-1", -(1UL), -1, strtoul, 10); + DO_TEST("2147483647", LONG_MAX, -1, strtoul, 10); + DO_TEST("4294967295", ULONG_MAX, -1, strtoul, 10); + DO_TEST("-4294967295", 1UL, -1, strtoul, 10); + DO_ERR_TEST("4294967296", ULONG_MAX, ERANGE, strtoul, 10); +#else + DO_TEST("-1", -(1UL), -1, strtoul, 10); + DO_TEST("9223372036854775807", LONG_MAX, -1, strtoul, 10); + DO_TEST("18446744073709551615", ULONG_MAX, -1, strtoul, 10); + DO_TEST("-18446744073709551615", 1UL, -1, strtoul, 10); + DO_ERR_TEST("18446744073709551616", ULONG_MAX, ERANGE, strtoul, 10); +#endif + + // wcstoul +#if defined(__i386__) || defined(__m68k__) + DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10); + DO_TESTL(L"2147483647", LONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"4294967295", ULONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"-4294967295", 1UL, -1, wcstoul, 10); + DO_ERR_TESTL(L"4294967296", ULONG_MAX, ERANGE, wcstoul, 10); +#else + DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10); + DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"18446744073709551615", ULONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"-18446744073709551615", 1UL, -1, wcstoul, 10); + DO_ERR_TESTL(L"18446744073709551616", ULONG_MAX, ERANGE, wcstoul, 10); +#endif + + // strtoull + DO_TEST("-1", -(1ULL), -1, strtoull, 10); + DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoull, 10); + DO_TEST("18446744073709551615", ULLONG_MAX, -1, strtoull, 10); + DO_TEST("-18446744073709551615", 1ULL, -1, strtoull, 10); + DO_ERR_TEST("18446744073709551616", ULLONG_MAX, ERANGE, strtoull, 10); + // wcstoull + DO_TESTL(L"-1", -(1ULL), -1, wcstoull, 10); + DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoull, 10); + DO_TESTL(L"18446744073709551615", ULLONG_MAX, -1, wcstoull, 10); + DO_TESTL(L"-18446744073709551615", 1ULL, -1, wcstoull, 10); + DO_ERR_TESTL(L"18446744073709551616", ULLONG_MAX, ERANGE, wcstoull, 10); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/strverscmp.c b/user/include/mlibc/tests/ansi/strverscmp.c new file mode 100644 index 0000000..f54c81d --- /dev/null +++ b/user/include/mlibc/tests/ansi/strverscmp.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main() { + int res; + + res = strverscmp("jan1", "jan10"); + assert(res < 0); + + res = strverscmp("jan11", "jan10"); + assert(res > 0); + + res = strverscmp("jan1", "jan1"); + assert(res == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/strxfrm.c b/user/include/mlibc/tests/ansi/strxfrm.c new file mode 100644 index 0000000..c8a0f7e --- /dev/null +++ b/user/include/mlibc/tests/ansi/strxfrm.c @@ -0,0 +1,16 @@ +#include +#include +#include + +int main() { + setlocale(LC_ALL, "C"); + + const char *buf = "cbtteststring"; + char dest[14]; + size_t ret = strxfrm(dest, buf, strlen(buf) + 1); + assert(ret == 13); + int cmp = strncmp(dest, buf, 13); + assert(!cmp); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/timegm.c b/user/include/mlibc/tests/ansi/timegm.c new file mode 100644 index 0000000..f5af03e --- /dev/null +++ b/user/include/mlibc/tests/ansi/timegm.c @@ -0,0 +1,45 @@ +#include +#include +#include + +int main() { + struct tm soon = {}; + soon.tm_sec = 0; + soon.tm_min = 0; + soon.tm_hour = 0; + soon.tm_mday = 1; + soon.tm_mon = 0; + soon.tm_year = 70; + time_t result; + time_t expected_result = 0; + // This should be epoch. + result = timegm(&soon); + printf("epoch: %ld\n", result); + assert(result == expected_result); + + soon.tm_sec = 12; + soon.tm_min = 8; + soon.tm_hour = 16; + soon.tm_mday = 17; + soon.tm_mon = 4; + soon.tm_year = 122; + expected_result = 1652803692; + result = timegm(&soon); + // On my host, this returned 1652803692, verify this. + printf("epoch: %ld\n", result); + assert(result == expected_result); + + soon.tm_sec = 45; + soon.tm_min = 42; + soon.tm_hour = 17; + soon.tm_mday = 16; + soon.tm_mon = 8; + soon.tm_year = 69; + expected_result = -9181035; + result = timegm(&soon); + // On my host, this returned -9181035, verify this. + printf("epoch: %ld\n", result); + assert(result == expected_result); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/tz.c b/user/include/mlibc/tests/ansi/tz.c new file mode 100644 index 0000000..1b1766b --- /dev/null +++ b/user/include/mlibc/tests/ansi/tz.c @@ -0,0 +1,27 @@ +#include +#include +#include + +extern int daylight; +extern long timezone; +extern char *tzname[2]; + +int main() { + tzset(); + printf("%s %s %ld %d\n", tzname[0], tzname[1], timezone, daylight); + + time_t sometime_in_summer_in_the_north = 1752019200; + struct tm *local = localtime(&sometime_in_summer_in_the_north); + + // Print the current timezone offset from UTC in seconds, considering DST + if (local) { + long offset = local->tm_gmtoff; + int hours = offset / 3600; + int minutes = (offset % 3600) / 60; + printf("UTC offset: %0d:%02d\n", hours, abs(minutes)); + } else { + printf("localtime returned NULL\n"); + } + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/tz.py b/user/include/mlibc/tests/ansi/tz.py new file mode 100644 index 0000000..2cacf9a --- /dev/null +++ b/user/include/mlibc/tests/ansi/tz.py @@ -0,0 +1,57 @@ +import subprocess +import sys +import os +from pyexpect import expect + +exe_wrapper = os.environ.get("MESON_EXE_WRAPPER") +wrapper = exe_wrapper.split(" ") if exe_wrapper else [] + +def check_tz(tz, expected): + environ = os.environ.copy() + environ["TZ"] = tz + + output = subprocess.check_output( + wrapper + sys.argv[1:], + stderr=subprocess.STDOUT, + env=environ, + ) + + expect(expected).to_equal(output) + +if len(sys.argv) < 2: + print("Usage: python3 tz.py ", file=sys.stderr) + sys.exit(1) + +check_tz("UTC0", b"UTC UTC 0 0\nUTC offset: 0:00\n") +check_tz("GMT0", b"GMT GMT 0 0\nUTC offset: 0:00\n") +check_tz(":UTC0", b"UTC UTC 0 0\nUTC offset: 0:00\n") +check_tz("EST+5", b"EST EST 18000 0\nUTC offset: -5:00\n") +check_tz("EET-2", b"EET EET -7200 0\nUTC offset: 2:00\n") +check_tz("<+03>-03", b"+03 +03 -10800 0\nUTC offset: 3:00\n") +check_tz("NPT-05:45", b"NPT NPT -20700 0\nUTC offset: 5:45\n") +check_tz("NST+03:30NDT", b"NST NDT 12600 1\nUTC offset: -2:30\n") +check_tz("NZST-12NZDT-13,M9.5.0,M4.1.0/3", b"NZST NZDT -43200 1\nUTC offset: 12:00\n") +check_tz("+8+7", b"PST-8 PDT-7 28800 1\nUTC offset: -7:00\n") +check_tz("+8+7,M3.2.0,M11.1.0", b"PST-8 PDT-7 28800 1\nUTC offset: -7:00\n") + +# These depend on tzdata, which may or may not exist. +# Useful to check every now and then, but these also present subtle differences +# between the host libc and mlibc, so we can't expect these to always hold up. +# E.g. glibc will set `tzname` from the TZ environment variable even if it +# cannot find the tzinfo file, however mlibc will use the name of the timezone +# as read from the tzinfo file or the timezone that it defaults to (UTC). + +# Would be b"Universal 0 0\n" on glibc. +# check_tz("", b"UTC UTC 0 0\n") + +# Would be b"UTC 0 0\n" on glibc. +# check_tz("UTC", b"UTC UTC 0 0\n") +# check_tz(":UTC", b"UTC UTC 0 0\n") + +# Would be b"Universal 0 0\n" on glibc. +# check_tz("Universal", b"UTC UTC 0 0\n") +# check_tz(":Universal", b"UTC UTC 0 0\n") + +# Would be b"ATimeZoneThatShouldHopefullyNeverBeInTzdata 0 0\n" on glibc. +# check_tz("ATimeZoneThatShouldHopefullyNeverBeInTzdata", b"UTC UTC 0 0\n") +# check_tz(":ATimeZoneThatShouldHopefullyNeverBeInTzdata", b"UTC UTC 0 0\n") diff --git a/user/include/mlibc/tests/ansi/ungetc.c b/user/include/mlibc/tests/ansi/ungetc.c new file mode 100644 index 0000000..3701c53 --- /dev/null +++ b/user/include/mlibc/tests/ansi/ungetc.c @@ -0,0 +1,76 @@ +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "ungetc-host-libc.tmp" +#else +#define TEST_FILE "ungetc.tmp" +#endif + +void test(int buffering) { + FILE *f = fopen(TEST_FILE, "w"); + for(int c = '0'; c <= '9'; c++) { + fputc(c, f); + } + fclose(f); + + f = fopen(TEST_FILE, "r"); + if (!buffering) { + setbuf(f, NULL); + } + + assert(ungetc('x', f) == 'x'); + assert(fgetc(f) == 'x'); + + // Test pushing back the same character + for (int c = '0'; c <= '9'; c++) { + assert(fgetc(f) == c); + assert(ungetc(c, f) == c); + assert(fgetc(f) == c); + } + assert(fgetc(f) == EOF); + assert(ungetc(EOF, f) == EOF); + + // Even though the spec does not guarantee it, we should be able to + // ungetc more than one character. + assert(ungetc('x', f) == 'x'); + assert(ungetc('y', f) == 'y'); + assert(fgetc(f) == 'y'); + assert(fgetc(f) == 'x'); + + // Seeking should discard the effects of ungetc. + assert(ungetc('x', f) == 'x'); + rewind(f); + + // Test pushing back a different character + for (int c = '0'; c <= '9'; c++) { + assert(fgetc(f) == c); + assert(ungetc(c - '0' + 'a', f) == c - '0' + 'a'); + assert(fgetc(f) == c - '0' + 'a'); + } + +#ifndef USE_HOST_LIBC + // Too many ungetcs should fail. + int eof = 0; + for (int i = 0; i < 100; i++) { + if (ungetc('x', f) == EOF) { + eof = 1; + break; + } + } + assert(eof); +#endif + + fclose(f); + + // TODO: Test with other operations, like fread. +} + +int main() { + fprintf(stderr, "with buffering...\n"); + test(1); + fprintf(stderr, "without buffering...\n"); + test(0); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/utf8.c b/user/include/mlibc/tests/ansi/utf8.c new file mode 100644 index 0000000..0024983 --- /dev/null +++ b/user/include/mlibc/tests/ansi/utf8.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include +#include + +#if UINTPTR_MAX == UINT64_MAX +#define WCHAR_SPEC "" +#else +#define WCHAR_SPEC "l" +#endif + +#define EXPECT(func) ({ \ + if(res != expected_ret) { \ + printf(#func " decoded %d bytes (expected %d bytes), at %s:%d\n", \ + res, expected_ret, __FILE__, line); \ + fflush(stdout); \ + abort(); \ + } \ + if(wc != expected) { \ + printf(#func " output cp %" WCHAR_SPEC "x (expected cp %" WCHAR_SPEC "x), at %s:%d\n", wc, \ + expected, __FILE__, line); \ + fflush(stdout); \ + abort(); \ + } \ + }) + +void verify_decode(const char *input, wchar_t expected, int line) { + wchar_t wc; + int bytes = *input ? strlen(input) : 1; + int expected_ret = *input ? strlen(input) : 0; + + // Check mbrtowc(). + mbstate_t state; + memset(&state, 0, sizeof(state)); + assert(mbrtowc(NULL, NULL, -1, &state) == 0); + int res = mbrtowc(&wc, input, bytes, &state); + EXPECT("mbrtowc"); + res = mbrtowc(NULL, input, bytes, &state); + EXPECT("mbrtowc (pwc == NULL)"); + + // Check mbtowc(). + assert(mbtowc(NULL, NULL, -1) == 0); + res = mbtowc(&wc, input, bytes); + EXPECT("mbtowc"); + res = mbtowc(NULL, input, bytes); + EXPECT("mbtowc (pwc == NULL)"); +} + +int main() { + setlocale(LC_ALL, "C.UTF-8"); + +#define verify_decode(in, out) verify_decode(in, out, __LINE__) + verify_decode("\x24", 0x24); + verify_decode("\xC2\xA2", 0xA2); + verify_decode("\xE0\xA4\xB9", 0x939); + verify_decode("\xE2\x82\xAC", 0x20AC); + verify_decode("\xED\x95\x9C", 0xD55C); + verify_decode("\xF0\x90\x8D\x88", 0x10348); + verify_decode("", L'\0'); + + // Check wcrtomb. + char representation[MB_CUR_MAX]; + representation[0] = '\0'; + mbstate_t state; + memset(&state, 0, sizeof(state)); + assert(wcrtomb(representation, L'1', &state) == 1); + assert(wcrtomb(representation, L'ß', &state) == 2); + assert(!strncmp(representation, "\xC3\x9F", 2)); + assert(wcrtomb(representation, L'ࠑ', &state) == 3); + assert(!strncmp(representation, "\xE0\xA0\x91", 3)); + assert(wcrtomb(representation, L'𒂲', &state) == 4); + assert(!strncmp(representation, "\xF0\x92\x82\xB2", 4)); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/wcsdup.c b/user/include/mlibc/tests/ansi/wcsdup.c new file mode 100644 index 0000000..efecee7 --- /dev/null +++ b/user/include/mlibc/tests/ansi/wcsdup.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +int main() { + wchar_t *wide_string = L"test string\n"; + wchar_t *dup_string = wcsdup(wide_string); + assert(!memcmp(wide_string, dup_string, (wcslen(wide_string) + 1) * sizeof(wchar_t))); + free(dup_string); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/wcsncasecmp.c b/user/include/mlibc/tests/ansi/wcsncasecmp.c new file mode 100644 index 0000000..0bfdd4c --- /dev/null +++ b/user/include/mlibc/tests/ansi/wcsncasecmp.c @@ -0,0 +1,13 @@ +#include +#include + +int main() { + assert(!wcsncasecmp(L"foo", L"foo", 3)); + assert(!wcsncasecmp(L"foo", L"FOO", 3)); + assert(!wcsncasecmp(L"fooa", L"FOOB", 3)); + assert(wcsncasecmp(L"foo", L"bar", 3)); + assert(!wcsncasecmp(L"fooa", L"FOOA", 4)); + assert(!wcsncasecmp(L"123abc", L"123AbC", 6)); + + return 0; +} diff --git a/user/include/mlibc/tests/ansi/wcsrtombs.c b/user/include/mlibc/tests/ansi/wcsrtombs.c new file mode 100644 index 0000000..80df257 --- /dev/null +++ b/user/include/mlibc/tests/ansi/wcsrtombs.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +int main() { + const wchar_t str[] = L"wcsrtombs"; + const wchar_t *p = str; + int ret = wcsrtombs(NULL, &p, 343245234, NULL); + assert(ret == 9); + return 0; +} diff --git a/user/include/mlibc/tests/ansi/wmemcmp.c b/user/include/mlibc/tests/ansi/wmemcmp.c new file mode 100644 index 0000000..74de9bd --- /dev/null +++ b/user/include/mlibc/tests/ansi/wmemcmp.c @@ -0,0 +1,19 @@ +#include +#include +#include + +int main(void){ + wchar_t *ws1 = calloc(10, sizeof(wchar_t)); + wchar_t *ws2 = calloc(10, sizeof(wchar_t)); + + mbstowcs(ws1, "Test 1", 10); + mbstowcs(ws2, "Tester 2", 10); + + assert(wmemcmp(ws1, ws2, 10) < 0); + assert(wmemcmp(ws2, ws1, 10) > 0); + assert(wmemcmp(ws2, ws2, 10) == 0); + + free(ws1); + free(ws2); + return 0; +} diff --git a/user/include/mlibc/tests/bsd/getloadavg.c b/user/include/mlibc/tests/bsd/getloadavg.c new file mode 100644 index 0000000..a69ffa3 --- /dev/null +++ b/user/include/mlibc/tests/bsd/getloadavg.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int main(void) { + double samples[3]; + assert(getloadavg(samples, 3) != 0); + printf("%f %f %f\n", samples[0], samples[1], samples[2]); + return 0; +} diff --git a/user/include/mlibc/tests/bsd/ns_get_put.c b/user/include/mlibc/tests/bsd/ns_get_put.c new file mode 100644 index 0000000..d64bb2a --- /dev/null +++ b/user/include/mlibc/tests/bsd/ns_get_put.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +int main() { + uint8_t *buf = malloc(256); + uint16_t original16 = 4891; + uint32_t original32 = 4861984; + memset(buf, 0x0, sizeof(*buf)); + ns_put16(original16, buf); + uint16_t result16 = ns_get16(buf); + assert(result16 == original16); + memset(buf, 0x0, sizeof(*buf)); + ns_put32(original32, buf); + uint32_t result32 = ns_get32(buf); + assert(result32 == original32); + free(buf); + return 0; +} diff --git a/user/include/mlibc/tests/bsd/reallocarray.c b/user/include/mlibc/tests/bsd/reallocarray.c new file mode 100644 index 0000000..905d68d --- /dev/null +++ b/user/include/mlibc/tests/bsd/reallocarray.c @@ -0,0 +1,7 @@ +#include + +int main() { + void *ret = reallocarray(NULL, 69, 0xCB7); + free(ret); + return !ret; +} diff --git a/user/include/mlibc/tests/bsd/sbrk.c b/user/include/mlibc/tests/bsd/sbrk.c new file mode 100644 index 0000000..b54b734 --- /dev/null +++ b/user/include/mlibc/tests/bsd/sbrk.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int main() { + void *ret = sbrk(0); + assert(ret != (void *) -1); + assert(ret); + + return 0; +} diff --git a/user/include/mlibc/tests/bsd/strl.c b/user/include/mlibc/tests/bsd/strl.c new file mode 100644 index 0000000..a502850 --- /dev/null +++ b/user/include/mlibc/tests/bsd/strl.c @@ -0,0 +1,56 @@ +#include +#include + +int main() { + char buf[256]; + + /* Test copy to 0-sized buffer . */ + memset(buf, 0, sizeof(buf)); + assert(strlcpy(buf, "xyz", 0) == 3); + assert(strcmp(buf, "") == 0); + + /* Test normal copy. */ + memset(buf, 0, sizeof(buf)); + assert(strlcpy(buf, "xyz", sizeof(buf)) == 3); + assert(strcmp(buf, "xyz") == 0); + + /* Test truncated copy. */ + memset(buf, 0, sizeof(buf)); + assert(strlcpy(buf, "abcdefabcdef", 10) == 12); + assert(strcmp(buf, "abcdefabc") == 0); + + /* Test concat to 0-sized buffer. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abc", 0) == 3); + assert(strcmp(buf, "") == 0); + + /* Test concat to full buffer. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abcde", 6) == 5); + assert(strcmp(buf, "abcde") == 0); + assert(strlcat(buf, "xyz", 5) == 8); + assert(strcmp(buf, "abcde") == 0); + + /* Test normal concat. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abc", sizeof(buf)) == 3); + assert(strcmp(buf, "abc") == 0); + assert(strlcat(buf, "xyz", sizeof(buf)) == 6); + assert(strcmp(buf, "abcxyz") == 0); + + /* Test truncated concat. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abcabc", 10) == 6); + assert(strcmp(buf, "abcabc") == 0); + assert(strlcat(buf, "xyzxyz", 10) == 12); + assert(strcmp(buf, "abcabcxyz") == 0); + + /* Test truncated concat w/ truncated dst. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abcabc", 10) == 6); + assert(strcmp(buf, "abcabc") == 0); + assert(strlcat(buf, "xyz", 4) == 7); + assert(strcmp(buf, "abcabc") == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/error.c b/user/include/mlibc/tests/glibc/error.c new file mode 100644 index 0000000..41789ee --- /dev/null +++ b/user/include/mlibc/tests/glibc/error.c @@ -0,0 +1,8 @@ +#include +#include + +int main() { + error(0, EINVAL, "test: %s", "error"); + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/error.py b/user/include/mlibc/tests/glibc/error.py new file mode 100644 index 0000000..3833974 --- /dev/null +++ b/user/include/mlibc/tests/glibc/error.py @@ -0,0 +1,11 @@ +import subprocess +import sys +import os +from pyexpect import expect + +wrapper = os.getenv("MESON_EXE_WRAPPER") +wrapper = [x for x in (wrapper,) if x] + +output = subprocess.check_output(wrapper + [sys.argv[1]], stderr=subprocess.STDOUT) + +expect(bytes(sys.argv[1], 'utf-8') + b': test: error: Invalid argument (EINVAL)\n').to_equal(output) diff --git a/user/include/mlibc/tests/glibc/error_at_line.c b/user/include/mlibc/tests/glibc/error_at_line.c new file mode 100644 index 0000000..a8b6122 --- /dev/null +++ b/user/include/mlibc/tests/glibc/error_at_line.c @@ -0,0 +1,8 @@ +#include +#include + +int main() { + error_at_line(0, EINVAL, "error_at_line", 5, "test: %s", "error"); + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/error_at_line.py b/user/include/mlibc/tests/glibc/error_at_line.py new file mode 100644 index 0000000..7499e05 --- /dev/null +++ b/user/include/mlibc/tests/glibc/error_at_line.py @@ -0,0 +1,11 @@ +import subprocess +import sys +import os +from pyexpect import expect + +wrapper = os.getenv("MESON_EXE_WRAPPER") +wrapper = [x for x in (wrapper,) if x] + +output = subprocess.check_output(wrapper + [sys.argv[1]], stderr=subprocess.STDOUT) + +expect(bytes(sys.argv[1], 'utf-8') + b':error_at_line:5: test: error: Invalid argument (EINVAL)\n').to_equal(output) diff --git a/user/include/mlibc/tests/glibc/error_expect_fail.c b/user/include/mlibc/tests/glibc/error_expect_fail.c new file mode 100644 index 0000000..131d640 --- /dev/null +++ b/user/include/mlibc/tests/glibc/error_expect_fail.c @@ -0,0 +1,8 @@ +#include +#include + +int main() { + error(1, EINVAL, "test error #1"); + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/error_message_count.c b/user/include/mlibc/tests/glibc/error_message_count.c new file mode 100644 index 0000000..9b83bd6 --- /dev/null +++ b/user/include/mlibc/tests/glibc/error_message_count.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + assert(error_message_count == 0); + error(0, EINVAL, "test error #1"); + assert(error_message_count == 1); + error_at_line(0, EINVAL, __FILE__, __LINE__, "test error #2"); + assert(error_message_count == 2); + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/error_one_per_line.c b/user/include/mlibc/tests/glibc/error_one_per_line.c new file mode 100644 index 0000000..e3b9895 --- /dev/null +++ b/user/include/mlibc/tests/glibc/error_one_per_line.c @@ -0,0 +1,15 @@ +#include +#include +#include + +int main() { + assert(error_one_per_line == 0); + assert(error_message_count == 0); + error_one_per_line = 1; + error_at_line(0, EINVAL, __FILE__, 0, "test error #1"); + assert(error_message_count == 1); + error_at_line(0, EINVAL, __FILE__, 0, "test error #2"); + assert(error_message_count == 1); + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/error_print_progname.c b/user/include/mlibc/tests/glibc/error_print_progname.c new file mode 100644 index 0000000..b3181c7 --- /dev/null +++ b/user/include/mlibc/tests/glibc/error_print_progname.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +bool ran = false; + +void test_progname(void) { + ran = true; + fprintf(stderr, "progname test"); +} + +int main() { + assert(error_print_progname == NULL); + error_print_progname = &test_progname; + error(0, EINVAL, "test error #1"); + assert(ran == true); + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/ffsl-ffsll.c b/user/include/mlibc/tests/glibc/ffsl-ffsll.c new file mode 100644 index 0000000..ed70ad6 --- /dev/null +++ b/user/include/mlibc/tests/glibc/ffsl-ffsll.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +int main(void){ + // ffsl + assert(ffsl(0x8000) == 16); + assert(ffsl(0) == 0); +#if UINTPTR_MAX == UINT64_MAX + assert(ffsl(LLONG_MAX - 1) == 2); + assert(ffsl(LLONG_MAX) == 1); +#endif + assert(ffsl(LONG_MIN) == (long)(sizeof(long) * CHAR_BIT)); + assert(ffsl(LONG_MIN + 1) == 1); + + for (int i = 1; i < 0x1000; i++) { + assert(ffsl(i) - 1 == __builtin_ctz(i)); + } + + // ffsll + assert(ffsll(0x8000) == 16); + assert(ffsll(0) == 0); +#if UINTPTR_MAX == UINT64_MAX + assert(ffsll(LLONG_MAX - 1) == 2); + assert(ffsll(LLONG_MAX) == 1); +#endif + assert(ffsll(LLONG_MIN) == (long long)(sizeof(long long) * CHAR_BIT)); + assert(ffsll(LLONG_MIN + 1) == 1); + + for (int i = 1; i < 0x1000; i++) { + assert(ffsll(i) - 1 == __builtin_ctz(i)); + } + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/getgrouplist.c b/user/include/mlibc/tests/glibc/getgrouplist.c new file mode 100644 index 0000000..dbdf566 --- /dev/null +++ b/user/include/mlibc/tests/glibc/getgrouplist.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main() { + int ngroups = 100; + struct passwd *pw; + struct group *gr; + gid_t *groups; + bool gid_checked = false; + int e = 0; + + groups = malloc(sizeof(*groups) * ngroups); + if(groups == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + + /* Fetch passwd structure */ + pw = getpwuid(geteuid()); + if(pw == NULL) { + perror("getpwnam"); + exit(EXIT_FAILURE); + } + + /* Retrieve group list */ + e = getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); + assert(e > 0); + if(e == -1) { + fprintf(stderr, "getgrouplist() returned -1 (%s); ngroups = %d\n", strerror(errno), ngroups); + exit(EXIT_FAILURE); + } + + /* Display list of retrieved groups, along with group names */ + fprintf(stderr, "ngroups = %d\n", ngroups); + for(int j = 0; j < ngroups; j++) { + if(groups[j] == pw->pw_gid) + gid_checked = true; + printf("%d", groups[j]); + gr = getgrgid(groups[j]); + if(gr != NULL) + printf(" (%s)", gr->gr_name); + printf("\n"); + } + + assert(gid_checked); + + exit(EXIT_SUCCESS); +} diff --git a/user/include/mlibc/tests/glibc/getopt.c b/user/include/mlibc/tests/glibc/getopt.c new file mode 100644 index 0000000..2b3764e --- /dev/null +++ b/user/include/mlibc/tests/glibc/getopt.c @@ -0,0 +1,884 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) +#define dump(x) fprintf(stderr, "getopt c '%c' (%d), optind %d ('%s'), optarg '%s', optopt '%c' (%d)\n", \ + (x), (x), optind, (size_t)optind >= COUNT_OF(test_argv) ? "out of range" : test_argv[optind], optarg, optopt, optopt); + +#define dumpargv(argv) do { \ + fprintf(stderr, "args(%zu) {\n", COUNT_OF(argv)); \ + for (size_t i = 0; i < COUNT_OF(argv); i++) { \ + fprintf(stderr, "\targv[%zu] = '%s'\n", i, argv[i]); \ + } \ + fprintf(stderr, "}\n"); \ +} while (0) + +void test1() { + const char *shortopts = "b:cdef"; + + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + int test_argc = 7; + + char *test_argv[] = { + "dummy", + "--foo", + "abc", + "-b", + "abc", + "abc", + "abc" + }; + + optind = 0; + int c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c) + assert(c == 'f'); + + c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c) + assert(optarg && !strcmp(optarg, "abc")); + assert(c == 'b'); + + c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(c == -1); + assert(optarg == NULL); + + // we have 2 non-option arguments + assert((optind + 2) == test_argc); +} + +void test2() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-c", + }; + + fputs("Situation: we pass a non-existant short option in argv\n", stderr); + + optind = 0; + opterr = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:", longopts, NULL); + // Expected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we pass a non-existant short option in argv, while passing a leading colon in optstring\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:", longopts, NULL); + // Expected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we omit the required arg to a short option\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + // Expected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we omit the required arg to a short option, while passing a leading colon in optstring\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:c:", longopts, NULL); + // Expected result: return ':', optopt is set to the offender + assert(c == ':'); + assert(optopt == 'c'); +} + +void test3() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-cmanagarm", + }; + + fputs("Situation: we pass a concatenated argument to a short option\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + dump(c); + // Expected result: + assert(c == 'c'); + assert(!strcmp(optarg, "managarm")); +} + +void test4() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-acmanagarm", + }; + + fputs("Situation: we pass concatenated short options to getopt\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + assert(c == 'a'); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + // Expected result: + assert(c == 'c'); + assert(!strcmp(optarg, "managarm")); +} + +void test5() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "su", + "-", + "managarm", + 0 + }; + + int test_argc = 3; + + fputs("Situation: testing `su - managarm`\n", stderr); + + optind = 0; + int c = getopt_long(test_argc, test_argv, "ab:", longopts, NULL); + dump(c); + assert(c == -1); + + if (optind < test_argc && !strcmp(test_argv[optind], "-")) { + ++optind; + } + + assert(optind < test_argc); + assert(!strcmp(test_argv[optind++], "managarm")); + assert(optind == test_argc); +} + +void test6() { + char *test_argv[] = { + "telescope", + "gemini://electrode.codes", + "-S", + 0 + }; + + int test_argc = 3; + optind = 0; + + const struct option longopts[] = { + {"colors", no_argument, NULL, 'C'}, + {"colours", no_argument, NULL, 'C'}, + {"help", no_argument, NULL, 'h'}, + {"safe", no_argument, NULL, 'S'}, + {"version", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0}, + }; + + int c = getopt_long(test_argc, test_argv, "Cc:hnST:v", longopts, NULL); + dump(c); + dumpargv(test_argv); + assert(c == 'S'); + c = getopt_long(test_argc, test_argv, "Cc:hnST:v", longopts, NULL); + dump(c); + dumpargv(test_argv); + assert(optind == 2); + assert(!optarg); +} + +void test7() { + int c; + + static const struct option options[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + {} + }; + const char *command; + + char *test_argv[] = { + "udevadm", + "hwdb", + "--update", + 0 + }; + + int test_argc = 3; + setenv("POSIXLY_CORRECT", "1", 1); + optind = 0; + + while ((c = getopt_long(test_argc, test_argv, "+dhV", options, NULL)) >= 0) { + switch (c) { + case 'd': + break; + case 'h': + break; + case 'V': + break; + default: + break; + } + } + + dump(c); + command = test_argv[optind]; + assert(command); + assert(!strcmp(command, "hwdb")); + unsetenv("POSIXLY_CORRECT"); +} + +void test8() { + const char *shortopts = "b:cde"; + + int foo = false; + int bar = false; + + const struct option longopts[] = { + {"foo", required_argument, &foo, 'x'}, + {"bar", required_argument, &bar, 'y'}, + {NULL, no_argument, NULL, 0} + }; + + int test_argc = 6; + + char *test_argv[] = { + "dummy", + "-foo", + "abc", + "-bar=def", + "ghi", + "jkl" + }; + + #ifdef __GLIBC__ + optind = 0; + #else + optreset = 1; + #endif + optopt = 0; + int c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(foo && !c); + assert(optind == 3); + + c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(bar && !c); + assert(optind == 4); +} + +void test9() { + char *test_argv[] = { + "foo", + }; + struct option opts[] = { {0} }; + optind = 0; + int c = getopt_long(1, test_argv, "abc", opts, NULL); + dump(c); + assert(c == -1); +} + +void test10() { + char *test_argv[] = { + "foo", + "nonoption", + "-a", + "nonoption2", + "nonoption3", + "-b", + "-c", + }; + struct option opts[] = { {0} }; + optind = 2; + dump(0); + int c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL); + dump(c); + dumpargv(test_argv); + assert(c == 'a'); + c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL); + dump(c); + dumpargv(test_argv); + assert(c == 'b'); + c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL); + dump(c); + dumpargv(test_argv); + assert(c == 'c'); + c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL); + dump(c); + dumpargv(test_argv); + assert(c == -1); + + assert(!strcmp(test_argv[0], "foo")); + assert(!strcmp(test_argv[1], "nonoption")); + assert(!strcmp(test_argv[2], "-a")); + assert(!strcmp(test_argv[3], "-b")); + assert(!strcmp(test_argv[4], "-c")); + assert(!strcmp(test_argv[5], "nonoption2")); + assert(!strcmp(test_argv[6], "nonoption3")); +} + +void test11() { + const struct option longopts[] = { + {"op", optional_argument, NULL, 'o'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "--op", + "--op=arg", + "non-option", + "--op" + }; + + fputs("Situation: optional argument to long option\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == 'o'); + assert(optarg == NULL); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == 'o'); + assert(!strcmp(optarg, "arg")); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == 'o'); + assert(optarg == NULL); +} + +void test12() { + char *test_argv[] = { + "dummy", + "-a", + "-b", + "arg", + "-carg", + "arg", + }; + + fputs("Situation: optional argument to short option\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL); + assert(c == 'a'); + assert(optarg == NULL); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL); + assert(c == 'b'); + assert(!optarg); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL); + assert(c == 'c'); + assert(!strcmp(optarg, "arg")); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL); + assert(c == -1); + assert(optind == 4); + assert(!strcmp(test_argv[optind], "arg")); +} + +void test13() { + const struct option longopts[] = { + {"ambiguous-opt", no_argument, NULL, 0}, + {"ambiguous-option", no_argument, NULL, 1}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "--ambiguous-o" + }; + + fputs("Situation: ambiguous long option\n", stderr); + + optind = 0; + opterr = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == '?'); +} + +void test14() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-Wfoo=bar", + }; + + fputs("Situation: -W for long options\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL); + assert(c == 'f'); + assert(!strcmp(optarg, "bar")); +} + +void test15() { + char *test_argv[] = { + "dummy", + "-c", + "-a", + "--", + "-b" + }; + + fputs("Situation: -- to stop option processing\n", stderr); + + optind = 0; + int c = getopt(COUNT_OF(test_argv), test_argv, "+ab"); + assert(c == '?'); + assert(optind == 2); + + c = getopt(COUNT_OF(test_argv), test_argv, "+ab"); + assert(c == 'a'); + assert(optind == 3); + + c = getopt(COUNT_OF(test_argv), test_argv, "+ab"); + assert(c == -1); + assert(optind == 4); + assert(!strcmp(test_argv[optind], "-b")); +} + +void test16() { + const struct option longopts[] = { + {"add", required_argument, NULL, 'a'}, + {"append", no_argument, NULL, 'p'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "--ad=foo", + "--appe" + }; + + fputs("Situation: non-ambiguous long option prefix\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == 'a'); + assert(!strcmp(optarg, "foo")); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == 'p'); + assert(optarg == NULL); +} + +void test17() { + const struct option longopts[] = { + {"foo", no_argument, NULL, 'l'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-foo" + }; + + fputs("Situation: getopt_long_only with what could be short opts or a long opt\n", stderr); + + // Case 1: long option "foo" exists, so "-foo" should be treated as "--foo" + optind = 0; + int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "f:o", longopts, NULL); + assert(c == 'l'); + + // Case 2: long option "foo" does not exist. + const struct option longopts2[] = { + {"bar", no_argument, NULL, 'b'}, + {NULL, 0, NULL, 0} + }; + optind = 0; + c = getopt_long_only(COUNT_OF(test_argv), test_argv, "f:o", longopts2, NULL); + assert(c == 'f'); + assert(!strcmp(optarg, "oo")); +} + +void test18() { + const struct option longopts[] = { + {"op", optional_argument, NULL, 'o'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-Wop=val", + }; + + fputs("Situation: -W with a long option with an optional argument (with value)\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL); + assert(c == 'o'); + assert(!strcmp(optarg, "val")); + + char *test_argv2[] = { + "dummy", + "-Wop", + }; + + fputs("Situation: -W with a long option with an optional argument (no value)\n", stderr); + + optind = 0; + c = getopt_long(COUNT_OF(test_argv2), test_argv2, "W;", longopts, NULL); + assert(c == 'o'); + assert(optarg == NULL); +} + +void test19() { + char *test_argv[] = { + "dummy", + "-a", + "non-option", + "-b", + }; + + fputs("Situation: POSIXLY_CORRECT behavior with '+'\n", stderr); + + optind = 0; + int c = getopt(COUNT_OF(test_argv), test_argv, "+ab"); + assert(c == 'a'); + + c = getopt(COUNT_OF(test_argv), test_argv, "+ab"); + assert(c == -1); + assert(optind == 2); + assert(!strcmp(test_argv[optind], "non-option")); +} + +void test20() { + const struct option longopts[] = { + {"option", required_argument, NULL, 'o'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "--option", + "-x", + }; + + fputs("Situation: long option with argument that looks like an option\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "x", longopts, NULL); + assert(c == 'o'); + assert(!strcmp(optarg, "-x")); + assert(optind == 3); +} + +void test21() { + const struct option longopts[] = { + {"ambig-one", no_argument, NULL, '1'}, + {"ambig-two", no_argument, NULL, '2'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-ambig", + }; + + fputs("Situation: ambiguous long option with getopt_long_only\n", stderr); + + optind = 0; + opterr = 0; + int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == '?'); +} + +void test22() { + const struct option longopts[] = { + {"foo", no_argument, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-Wbar", + }; + + fputs("Situation: -W with non-existent long option\n", stderr); + + optind = 0; + opterr = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL); + assert(c == '?'); + assert(optind == 2); +} + +void test23() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-foo", + "val1", + "-foo=val2", + }; + + fputs("Situation: getopt_long_only with required argument\n", stderr); + + optind = 0; + int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == 'f'); + assert(!strcmp(optarg, "val1")); + assert(optind == 3); + + c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL); + assert(c == 'f'); + assert(!strcmp(optarg, "val2")); + assert(optind == 4); +} + +void test24() { + char *test_argv[] = { + "dummy", + "-W", + }; + + fputs("Situation: -W as a short option, not for passing long options\n", stderr); + + optind = 0; + int c = getopt(COUNT_OF(test_argv), test_argv, "W"); + assert(c == 'W'); + assert(optind == 2); +} + +void test25() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-Wfoo", + }; + + fputs("Situation: -W with missing argument for a long option, with ':' in optstring\n", stderr); + + optind = 0; + opterr = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, ":W;", longopts, NULL); + assert(c == ':'); + assert(optopt == 'f'); + assert(optind == 2); +} + +void test26() { + const struct option longopts[] = { + {"foo", no_argument, NULL, 0}, + {"ambig-one", no_argument, NULL, 1}, + {"ambig-two", no_argument, NULL, 2}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-W", + }; + + fputs("Situation: -W without an argument\n", stderr); + + optind = 0; + opterr = 1; + int c = getopt_long(COUNT_OF(test_argv), test_argv, ":W;", longopts, NULL); + assert(c == ':'); + assert(optopt == 'W'); + assert(optind == 2); +} + +void test27() { + char *test_argv[] = { + "dummy", + "-Wambig", + }; + + const struct option longopts[] = { + {"foo", no_argument, NULL, 0}, + {"ambig-one", no_argument, NULL, 1}, + {"ambig-two", no_argument, NULL, 2}, + {NULL, 0, NULL, 0} + }; + + fputs("Situation: -W with an ambiguous long option\n", stderr); + + optind = 0; + opterr = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL); + assert(c == '?'); + assert(optind == 2); +} + +void test28() { + char *test_argv[] = { + "dummy", + "-Wfoo=bar", + "-Wfoo=", + }; + + const struct option longopts[] = { + {"foo", no_argument, NULL, 0}, + {"ambig-one", no_argument, NULL, 1}, + {"ambig-two", no_argument, NULL, 2}, + {NULL, 0, NULL, 0} + }; + + fputs("Situation: -W with an argument to a long option that does not take one\n", stderr); + + optind = 0; + opterr = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL); + assert(c == '?'); + assert(optind == 2); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL); + assert(c == '?'); + assert(optind == 3); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL); + assert(c == -1); +} + +void test29() { + char *test_argv[] = { + "dummy", + "--a", + }; + + const struct option longopts[] = { + {"load-credentials", no_argument, NULL, 0x103}, + {NULL, 0, NULL, 0}, + }; + + optind = 0; + opterr = 1; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "el:sSRp:m:t:Vh", longopts, NULL); + dump(c); + assert(c == '?'); + assert(optind == 2); +} + +void test30() { + const struct option longopts[] = { + {"long-opt", required_argument, NULL, 'l'}, + {NULL, 0, NULL, 0} + }; + + char *test_argv[] = { + "getopt_test", + "non-arg1", + "--long-opt", + "val", + "non-arg2" + }; + + fputs("Situation: non-arguments before valid long arguments\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "+", longopts, NULL); + assert(c == -1); + assert(optind == 1); + assert(!strcmp(test_argv[0], "getopt_test")); + assert(!strcmp(test_argv[1], "non-arg1")); + assert(!strcmp(test_argv[2], "--long-opt")); + assert(!strcmp(test_argv[3], "val")); + assert(!strcmp(test_argv[4], "non-arg2")); + + optind = 2; + while ((c = getopt_long(COUNT_OF(test_argv), test_argv, "+", longopts, NULL)) != -1) { + switch (c) { + case 'l': + assert(!strcmp(optarg, "val")); + break; + default: + break; + } + } + + assert(c == -1); + assert(optind == 4); + + optind = 0; + while ((c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL)) != -1) { + switch (c) { + case 'l': + assert(!strcmp(optarg, "val")); + break; + default: + break; + } + } + + assert(optind == 3); + assert(!strcmp(test_argv[0], "getopt_test")); + assert(!strcmp(test_argv[1], "--long-opt")); + assert(!strcmp(test_argv[2], "val")); + assert(!strcmp(test_argv[3], "non-arg1")); + assert(!strcmp(test_argv[4], "non-arg2")); +} + +int main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test13(); + test14(); + test15(); + test16(); + test17(); + test18(); + test19(); + test20(); + test21(); + test22(); + test23(); + test24(); + test25(); + test26(); + test27(); + test28(); + test29(); + test30(); + + return 0; +} diff --git a/user/include/mlibc/tests/glibc/gnu-basename.c b/user/include/mlibc/tests/glibc/gnu-basename.c new file mode 100644 index 0000000..9566532 --- /dev/null +++ b/user/include/mlibc/tests/glibc/gnu-basename.c @@ -0,0 +1,13 @@ +#define _GNU_SOURCE +#include +#include + +#define test_string(x, expectval) assert(strcmp(basename(x), expectval) == 0) + +int main() { + test_string("/usr/lib", "lib"); + test_string("/usr/", ""); + test_string("/", ""); + test_string(".", "."); + test_string("..", ".."); +} diff --git a/user/include/mlibc/tests/glibc/linux-syscall.c b/user/include/mlibc/tests/glibc/linux-syscall.c new file mode 100644 index 0000000..2760df4 --- /dev/null +++ b/user/include/mlibc/tests/glibc/linux-syscall.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include +#include + +int main() { + char *data = "hello mlibc\n"; + long ret = syscall(SYS_write, 1, data, strlen(data)); + assert(ret == (long)strlen(data)); + + syscall(SYS_exit, 0); + abort(); +} diff --git a/user/include/mlibc/tests/glibc/rpmatch.c b/user/include/mlibc/tests/glibc/rpmatch.c new file mode 100644 index 0000000..6435663 --- /dev/null +++ b/user/include/mlibc/tests/glibc/rpmatch.c @@ -0,0 +1,17 @@ +#include +#include +#include + +int main() { + assert(rpmatch("y") == 1); + assert(rpmatch("Y") == 1); + assert(rpmatch("n") == 0); + assert(rpmatch("N") == 0); + assert(rpmatch("yno") == 1); + assert(rpmatch("no") == 0); + assert(rpmatch("NO") == 0); + assert(rpmatch("YES") == 1); + assert(rpmatch("mlibc") == -1); + + return 0; +} diff --git a/user/include/mlibc/tests/linux/cpuset.c b/user/include/mlibc/tests/linux/cpuset.c new file mode 100644 index 0000000..3f55732 --- /dev/null +++ b/user/include/mlibc/tests/linux/cpuset.c @@ -0,0 +1,27 @@ +#include +#include +#include + +#define SET_SIZE 15 + +int main() { + cpu_set_t *set = CPU_ALLOC(SET_SIZE); + size_t setsize = CPU_ALLOC_SIZE(SET_SIZE); + + CPU_ZERO_S(setsize, set); + + assert(!CPU_ISSET_S(11, setsize, set)); + + CPU_SET_S(11, setsize, set); + assert(CPU_ISSET_S(11, setsize, set)); + assert(CPU_COUNT_S(setsize, set) == 1); + + assert(!CPU_ISSET_S(CPU_SETSIZE - 1, setsize, set)); + + CPU_CLR_S(11, setsize, set); + assert(!CPU_ISSET_S(11, setsize, set)); + + CPU_FREE(set); + + return 0; +} diff --git a/user/include/mlibc/tests/linux/getifaddrs.c b/user/include/mlibc/tests/linux/getifaddrs.c new file mode 100644 index 0000000..f98c7e3 --- /dev/null +++ b/user/include/mlibc/tests/linux/getifaddrs.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + (void) argc; + (void) argv; + + struct ifaddrs *ifaddr = 0; + char host[NI_MAXHOST]; + bool loopback_found = false; + + if(getifaddrs(&ifaddr)) { + perror("getifaddrs"); + exit(EXIT_FAILURE); + } + + for(struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) { + if(ifa->ifa_addr == NULL) + continue; + + int family = ifa->ifa_addr->sa_family; + + if(family == AF_INET && !strcmp("lo", ifa->ifa_name)) { + loopback_found = true; + + printf("%-10s %s (%d)\n", ifa->ifa_name, + (family == AF_INET) ? "AF_INET" : (family == AF_INET6) ? "AF_INET6" : "???", + family + ); + + int s = getnameinfo(ifa->ifa_addr, + (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + assert(!s); + + printf("\t\taddress: <%s>\n", host); + if(ifa->ifa_netmask) + printf("\t\tnetmask: <%s>\n", inet_ntoa(((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr)); + + if(ifa->ifa_flags & IFF_BROADCAST) { + assert(ifa->ifa_broadaddr); + printf("\t\tbroadcast: <%s>\n", inet_ntoa(((struct sockaddr_in *) ifa->ifa_broadaddr)->sin_addr)); + } + + if(ifa->ifa_flags & IFF_POINTOPOINT) { + assert(ifa->ifa_dstaddr); + printf("\t\tdest addr: <%s>\n", inet_ntoa(((struct sockaddr_in *) ifa->ifa_dstaddr)->sin_addr)); + } + } + } + + freeifaddrs(ifaddr); + + exit(loopback_found ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/user/include/mlibc/tests/linux/malloc-usable-size.c b/user/include/mlibc/tests/linux/malloc-usable-size.c new file mode 100644 index 0000000..3bb0394 --- /dev/null +++ b/user/include/mlibc/tests/linux/malloc-usable-size.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +int main() { + void *p1 = malloc(1023); + fprintf(stderr, "size: %zu\n", malloc_usable_size(p1)); + assert(malloc_usable_size(p1) >= 1023); + free(p1); + + return 0; +} diff --git a/user/include/mlibc/tests/linux/pidfd.c b/user/include/mlibc/tests/linux/pidfd.c new file mode 100644 index 0000000..57e6755 --- /dev/null +++ b/user/include/mlibc/tests/linux/pidfd.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main() { + int child = fork(); + + if(!child) { + sleep(1); + exit(42); + } + + int pidfd = pidfd_open(child, 0); + assert(pidfd > 0); + + int ret = lseek(pidfd, 0, SEEK_SET); + assert(ret == -1); + assert(errno == ESPIPE); + + pid_t outpid = pidfd_getpid(pidfd); + assert(outpid == child); + + struct pollfd pollfd; + pollfd.fd = pidfd; + pollfd.events = POLLIN; + + int ready = poll(&pollfd, 1, 0); + assert(ready == 0); + + ready = poll(&pollfd, 1, 2000); + if(ready == -1) { + perror("poll"); + exit(EXIT_FAILURE); + } + assert(ready == 1); + assert(pollfd.revents == POLLIN); + + siginfo_t info = {}; + ret = waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG); + assert(ret == 0); + assert(info.si_code == CLD_EXITED); + assert(info.si_pid == child); + assert(info.si_status == 42); + + close(pidfd); + + child = fork(); + + if(!child) { + sleep(10); + } + + pidfd = pidfd_open(child, 0); + assert(pidfd > 0); + + ret = pidfd_send_signal(pidfd, SIGKILL, NULL, 0); + assert(ret == 0); + + memset(&info, 0, sizeof(info)); + ret = waitid(P_PIDFD, pidfd, &info, WEXITED); + assert(ret == 0); + assert(info.si_code == CLD_KILLED); + assert(info.si_pid == child); + assert(info.si_status == SIGKILL); + + return 0; +} diff --git a/user/include/mlibc/tests/linux/ppoll.c b/user/include/mlibc/tests/linux/ppoll.c new file mode 100644 index 0000000..cfddea0 --- /dev/null +++ b/user/include/mlibc/tests/linux/ppoll.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void sig_handler(int sig) { + (void)sig; +} + +int main() { + int fds[2]; + int ret = pipe(fds); + assert(ret == 0); + + struct pollfd poll_fds[1]; + poll_fds[0].fd = fds[0]; + poll_fds[0].events = POLLIN; + + struct timespec timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = 1000000; // 1 ms + + // Test that ppoll times out correctly. + ret = ppoll(poll_fds, 1, &timeout, NULL); + assert(ret == 0); + + // Test that ppoll returns 1 if there is an event. + char buf[1]; + ret = write(fds[1], "a", 1); + assert(ret == 1); + + ret = ppoll(poll_fds, 1, &timeout, NULL); + assert(ret == 1); + assert(poll_fds[0].revents & POLLIN); + + // Test that ppoll returns 0 if there are no events and timeout is 0. + ret = read(fds[0], buf, 1); + assert(ret == 1); + + timeout.tv_nsec = 0; + ret = ppoll(poll_fds, 1, &timeout, NULL); + assert(ret == 0); + + // Test that ppoll returns immediately if there is an event and timeout is 0. + ret = write(fds[1], "a", 1); + assert(ret == 1); + + ret = ppoll(poll_fds, 1, &timeout, NULL); + assert(ret == 1); + assert(poll_fds[0].revents & POLLIN); + + char recvbuf[2]; + ret = read(fds[0], &recvbuf, 2); + assert(ret == 1); + + // Test that ppoll is interrupted by a signal. + struct sigaction sa; + sa.sa_handler = sig_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + ret = sigaction(SIGUSR1, &sa, NULL); + assert(ret == 0); + + pid_t pid = fork(); + assert(pid >= 0); + + if (pid == 0) { + // Child process. + usleep(100000); // 100 ms + ret = kill(getppid(), SIGUSR1); + assert(ret == 0); + exit(0); + } else { + // Parent process. + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + ret = ppoll(poll_fds, 1, &timeout, NULL); + assert(ret == -1); + assert(errno == EINTR); + + int status; + ret = waitpid(pid, &status, 0); + assert(ret == pid); + assert(WIFEXITED(status) && WEXITSTATUS(status) == 0); + } + + close(fds[0]); + close(fds[1]); + + return 0; +} diff --git a/user/include/mlibc/tests/linux/process_vm_readv_writev.c b/user/include/mlibc/tests/linux/process_vm_readv_writev.c new file mode 100644 index 0000000..a31ba13 --- /dev/null +++ b/user/include/mlibc/tests/linux/process_vm_readv_writev.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +// Test variable to read and write +static int test = 42; + +int main() { + // Read the variable using process_vm_readv + int temp; + struct iovec local_iov = { + .iov_base = &temp, + .iov_len = sizeof(temp), + }; + struct iovec remote_iov = { + .iov_base = &test, + .iov_len = sizeof(test), + }; + ssize_t bytes_read = process_vm_readv(getpid(), &local_iov, 1, &remote_iov, 1, 0); + assert(bytes_read == sizeof(test)); + assert(temp == 42); + + // Write a new value to the variable using process_vm_writev + int new_value = 1337; + struct iovec new_local_iov = { + .iov_base = &new_value, + .iov_len = sizeof(new_value), + }; + ssize_t bytes_written = process_vm_writev(getpid(), &new_local_iov, 1, &remote_iov, 1, 0); + assert(bytes_written == sizeof(new_value)); + assert(test == 1337); + + return 0; +} diff --git a/user/include/mlibc/tests/linux/pthread_attr.c b/user/include/mlibc/tests/linux/pthread_attr.c new file mode 100644 index 0000000..4c1907c --- /dev/null +++ b/user/include/mlibc/tests/linux/pthread_attr.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +static void test_affinity() { + pthread_attr_t attr; + cpu_set_t set = {0}; + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setaffinity_np(&attr, 1, &set)); + + cpu_set_t other_set = {0}; + assert(!pthread_attr_getaffinity_np(&attr, 1, &set)); + + assert(!memcmp(&set, &other_set, sizeof(cpu_set_t))); + + pthread_attr_destroy(&attr); +} + +#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) +static void test_sigmask() { + pthread_attr_t attr; + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR1); +#ifndef USE_HOST_LIBC + sigaddset(&set, SIGCANCEL); +#endif + + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setsigmask_np(&attr, &set)); + + sigset_t other_set; + sigemptyset(&other_set); + + assert(!pthread_attr_getsigmask_np(&attr, &other_set)); + + assert(sigismember(&other_set, SIGUSR1)); +#ifndef USE_HOST_LIBC + // Test whether internal signals get filtered properly. + assert(!sigismember(&other_set, SIGCANCEL)); +#endif + + pthread_attr_destroy(&attr); +} + +static void *getattr_worker(void *arg) { + (void)arg; + return NULL; +} + +static void test_getattrnp() { + pthread_attr_t attr; + size_t stacksize = PTHREAD_STACK_MIN; + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setstacksize(&attr, stacksize)); + + pthread_t thread; + assert(!pthread_create(&thread, &attr, getattr_worker, NULL)); + assert(!pthread_getattr_np(thread, &attr)); + size_t other_stacksize; + assert(!pthread_attr_getstacksize(&attr, &other_stacksize)); + assert(other_stacksize == stacksize); + assert(!pthread_join(thread, NULL)); + + pthread_t own_thread = pthread_self(); + void *stack; + assert(!pthread_getattr_np(own_thread, &attr)); + assert(!pthread_attr_getstack(&attr, &stack, &other_stacksize)); + assert(stack); + assert(other_stacksize); + // Check that we can read from the highest byte returned. + // pthread_getattr_np() should return the lowest byte + // of the stack. + printf("highest byte: %hhu\n", *(char *)(stack + other_stacksize - 1)); + + pthread_attr_destroy(&attr); +} +#endif // !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) + +int main() { + test_affinity(); +#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) + test_sigmask(); + test_getattrnp(); +#endif + + return 0; +} diff --git a/user/include/mlibc/tests/linux/pthread_setname_np.c b/user/include/mlibc/tests/linux/pthread_setname_np.c new file mode 100644 index 0000000..95c95c9 --- /dev/null +++ b/user/include/mlibc/tests/linux/pthread_setname_np.c @@ -0,0 +1,33 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +int main() { + int ret = pthread_setname_np(pthread_self(), "mlibc-test-123"); + assert(!ret); + + char buf[16]; + ret = pthread_getname_np(pthread_self(), buf, 16); + assert(!ret); + assert(!strcmp("mlibc-test-123", buf)); + + ret = pthread_setname_np(pthread_self(), "mlibc-test-123-too-long"); + assert(ret == ERANGE); + + ret = pthread_getname_np(pthread_self(), buf, 1); + assert(ret == ERANGE); + + ret = pthread_getname_np(pthread_self(), buf, 15); + assert(ret == ERANGE); + + ret = pthread_getname_np(pthread_self(), buf, 16); + assert(!ret); + assert(!strcmp("mlibc-test-123", buf)); + + return 0; +} diff --git a/user/include/mlibc/tests/linux/timerfd.c b/user/include/mlibc/tests/linux/timerfd.c new file mode 100644 index 0000000..b27fd16 --- /dev/null +++ b/user/include/mlibc/tests/linux/timerfd.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + int t = timerfd_create(CLOCK_MONOTONIC, 0); + assert(t > 0); + + struct itimerspec its; + int ret = timerfd_gettime(t, &its); + assert(ret == 0); + assert(!its.it_value.tv_sec); + assert(!its.it_value.tv_nsec); + assert(!its.it_interval.tv_sec); + assert(!its.it_interval.tv_nsec); + + struct itimerspec new_its = { + .it_interval = {0, 0}, + .it_value = {0, 100000000}, + }; + ret = timerfd_settime(t, 0, &new_its, &its); + assert(ret == 0); + assert(!its.it_value.tv_sec); + assert(!its.it_value.tv_nsec); + assert(!its.it_interval.tv_sec); + assert(!its.it_interval.tv_nsec); + + ret = timerfd_gettime(t, &its); + assert(ret == 0); + assert(!its.it_value.tv_sec); + assert(its.it_value.tv_nsec); + assert(!its.it_interval.tv_sec); + assert(!its.it_interval.tv_nsec); + + struct timeval before; + gettimeofday(&before, NULL); + assert(ret == 0); + uint64_t ev = 0; + ret = read(t, &ev, sizeof(ev)); + struct timeval after; + gettimeofday(&after, NULL); + + assert(ret == sizeof(ev)); + assert(ev == 1); + + struct timeval diff = {}; + timersub(&after, &before, &diff); + assert(diff.tv_sec || diff.tv_usec); + + fcntl(t, F_SETFL, fcntl(t, F_GETFL, 0) | O_NONBLOCK); + + ret = timerfd_settime(t, 0, &new_its, &its); + assert(ret == 0); + + ret = read(t, &ev, sizeof(ev)); + assert(ret == -1); + assert(errno == EAGAIN); + + return 0; +} diff --git a/user/include/mlibc/tests/linux/utmp.c b/user/include/mlibc/tests/linux/utmp.c new file mode 100644 index 0000000..fe968dc --- /dev/null +++ b/user/include/mlibc/tests/linux/utmp.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main() { + char path[] = "/tmp/mlibc-utmp-test-XXXXXX"; + int fd = mkstemp(path); + assert(fd != -1); + close(fd); + + int ret = utmpname(path); + assert(!ret); + + // Test writing to the utmp file. + struct utmp entry1; + memset(&entry1, 0, sizeof(struct utmp)); + entry1.ut_type = USER_PROCESS; + entry1.ut_pid = 1234; + strcpy(entry1.ut_line, "pts/1"); + strcpy(entry1.ut_id, "id1"); + strcpy(entry1.ut_user, "user1"); + strcpy(entry1.ut_host, "host1"); + entry1.ut_tv.tv_sec = 1; + entry1.ut_tv.tv_usec = 1; + + setutent(); + struct utmp *res = pututline(&entry1); + assert(res); + endutent(); + + // Test reading from the utmp file. + setutent(); + struct utmp *read_entry = getutent(); + assert(read_entry); + assert(read_entry->ut_type == USER_PROCESS); + assert(read_entry->ut_pid == 1234); + assert(strcmp(read_entry->ut_line, "pts/1") == 0); + assert(strcmp(read_entry->ut_id, "id1") == 0); + assert(strcmp(read_entry->ut_user, "user1") == 0); + assert(strcmp(read_entry->ut_host, "host1") == 0); + assert(read_entry->ut_tv.tv_sec == 1); + assert(read_entry->ut_tv.tv_usec == 1); + + read_entry = getutent(); + assert(!read_entry); + assert(errno == ESRCH); + endutent(); + + // Test getutid + struct utmp id_entry; + memset(&id_entry, 0, sizeof(struct utmp)); + id_entry.ut_type = USER_PROCESS; + strcpy(id_entry.ut_id, "id1"); + + setutent(); + struct utmp *id_read_entry = getutid(&id_entry); + assert(id_read_entry); + assert(id_read_entry->ut_pid == 1234); + + read_entry = getutent(); + assert(!read_entry); + assert(errno == ESRCH); + endutent(); + + // Test getutline + struct utmp line_entry; + memset(&line_entry, 0, sizeof(struct utmp)); + line_entry.ut_type = USER_PROCESS; + strcpy(line_entry.ut_line, "pts/1"); + + setutent(); + struct utmp *line_read_entry = getutline(&line_entry); + assert(line_read_entry); + assert(line_read_entry->ut_pid == 1234); + endutent(); + + // Test getutent_r + struct utmp buf; + struct utmp *res_r; + setutent(); + int ret_r = getutent_r(&buf, &res_r); + assert(!ret_r); + assert(res_r == &buf); + assert(buf.ut_pid == 1234); + endutent(); + + // Test updwtmp. + char wtmp_path[] = "/tmp/mlibc-wtmp-test-XXXXXX"; + int wtmp_fd = mkstemp(wtmp_path); + assert(wtmp_fd != -1); + close(wtmp_fd); + + struct utmp entry2; + memset(&entry2, 0, sizeof(struct utmp)); + entry2.ut_type = USER_PROCESS; + entry2.ut_pid = 5678; + strcpy(entry2.ut_line, "pts/2"); + strcpy(entry2.ut_id, "id2"); + strcpy(entry2.ut_user, "user2"); + strcpy(entry2.ut_host, "host2"); + entry2.ut_tv.tv_sec = 2; + entry2.ut_tv.tv_usec = 2; + + updwtmp(wtmp_path, &entry2); + + // Verify the wtmp file. + FILE *f = fopen(wtmp_path, "r"); + assert(f); + struct utmp wtmp_entry; + ret = fread(&wtmp_entry, sizeof(struct utmp), 1, f); + assert(ret == 1); + fclose(f); + + assert(wtmp_entry.ut_type == USER_PROCESS); + assert(wtmp_entry.ut_pid == 5678); + assert(strcmp(wtmp_entry.ut_line, "pts/2") == 0); + assert(strcmp(wtmp_entry.ut_id, "id2") == 0); + assert(strcmp(wtmp_entry.ut_user, "user2") == 0); + assert(strcmp(wtmp_entry.ut_host, "host2") == 0); + assert(wtmp_entry.ut_tv.tv_sec == 2); + assert(wtmp_entry.ut_tv.tv_usec == 2); + + unlink(wtmp_path); + unlink(path); + + return EXIT_SUCCESS; +} diff --git a/user/include/mlibc/tests/linux/utmpx.c b/user/include/mlibc/tests/linux/utmpx.c new file mode 100644 index 0000000..5a0fb6b --- /dev/null +++ b/user/include/mlibc/tests/linux/utmpx.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + char path[] = "/tmp/mlibc-utmpx-test-XXXXXX"; + int fd = mkstemp(path); + assert(fd != -1); + close(fd); + + int ret = utmpxname(path); + assert(!ret); + + struct utmpx entry; + memset(&entry, 0, sizeof(struct utmpx)); + + // Test an empty file. + setutxent(); + struct utmpx *read_entry = getutxent(); + assert(!read_entry); + endutxent(); + + // Test writing a new entry. + entry.ut_type = USER_PROCESS; + entry.ut_pid = getpid(); + strncpy(entry.ut_line, "tty1", sizeof(entry.ut_line)); + strncpy(entry.ut_id, "t1", sizeof(entry.ut_id)); + strncpy(entry.ut_user, "root", sizeof(entry.ut_user)); + strncpy(entry.ut_host, "localhost", sizeof(entry.ut_host)); + entry.ut_tv.tv_sec = 1234567890; + entry.ut_tv.tv_usec = 0; + setutxent(); + assert(pututxline(&entry)); + endutxent(); + + // Test reading the entry back. + setutxent(); + read_entry = getutxent(); + assert(read_entry); + assert(read_entry->ut_type == USER_PROCESS); + assert(read_entry->ut_pid == getpid()); + assert(!strcmp(read_entry->ut_line, "tty1")); + assert(!strcmp(read_entry->ut_id, "t1")); + assert(!strcmp(read_entry->ut_user, "root")); + assert(!strcmp(read_entry->ut_host, "localhost")); + assert(read_entry->ut_tv.tv_sec == 1234567890); + read_entry = getutxent(); + assert(!read_entry); + endutxent(); + + // Test getutxid(). + struct utmpx id_entry; + memset(&id_entry, 0, sizeof(struct utmpx)); + id_entry.ut_type = USER_PROCESS; + strncpy(id_entry.ut_id, "t1", sizeof(id_entry.ut_id)); + setutxent(); + struct utmpx *id_read_entry = getutxid(&id_entry); + assert(id_read_entry); + assert(id_read_entry->ut_pid == getpid()); + endutxent(); + + // Test getutxline(). + struct utmpx line_entry; + memset(&line_entry, 0, sizeof(struct utmpx)); + line_entry.ut_type = USER_PROCESS; + strncpy(line_entry.ut_line, "tty1", sizeof(line_entry.ut_line)); + setutxent(); + struct utmpx *line_read_entry = getutxline(&line_entry); + assert(line_read_entry); + assert(line_read_entry->ut_pid == getpid()); + endutxent(); + + // Test updwtmpx. + char wtmpx_path[] = "/tmp/mlibc-wtmpx-test-XXXXXX"; + int wtmpx_fd = mkstemp(wtmpx_path); + assert(wtmpx_fd != -1); + close(wtmpx_fd); + + struct utmpx entry2; + memset(&entry2, 0, sizeof(struct utmpx)); + entry2.ut_type = USER_PROCESS; + entry2.ut_pid = 5678; + strcpy(entry2.ut_line, "pts/2"); + strcpy(entry2.ut_id, "id2"); + strcpy(entry2.ut_user, "user2"); + strcpy(entry2.ut_host, "host2"); + entry2.ut_tv.tv_sec = 2; + entry2.ut_tv.tv_usec = 2; + + updwtmpx(wtmpx_path, &entry2); + + // Verify the wtmpx file. + FILE *f = fopen(wtmpx_path, "r"); + assert(f); + struct utmpx wtmpx_entry; + ret = fread(&wtmpx_entry, sizeof(struct utmpx), 1, f); + assert(ret == 1); + fclose(f); + + assert(wtmpx_entry.ut_type == USER_PROCESS); + assert(wtmpx_entry.ut_pid == 5678); + assert(strcmp(wtmpx_entry.ut_line, "pts/2") == 0); + assert(strcmp(wtmpx_entry.ut_id, "id2") == 0); + assert(strcmp(wtmpx_entry.ut_user, "user2") == 0); + assert(strcmp(wtmpx_entry.ut_host, "host2") == 0); + assert(wtmpx_entry.ut_tv.tv_sec == 2); + assert(wtmpx_entry.ut_tv.tv_usec == 2); + + unlink(wtmpx_path); + unlink(path); + + return EXIT_SUCCESS; +} diff --git a/user/include/mlibc/tests/linux/xattr.c b/user/include/mlibc/tests/linux/xattr.c new file mode 100644 index 0000000..c565030 --- /dev/null +++ b/user/include/mlibc/tests/linux/xattr.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include + +#define assert_perror(x) \ + ({ \ + int res = (x); \ + if (res < 0) { \ + perror(#x); \ + return 1; \ + } \ + res; \ + }) + +#define soft_assert(x, m) \ + ({ \ + if (!(x)) { \ + fprintf(stderr, "cond \"%s\" failed: %s\n", #x, m); \ + return 1; \ + } \ + }) + +void remove_tmp(const char (*fname)[]) { + unlink(&(*fname)[0]); +} +#define _cleanup_file_ __attribute__((cleanup(remove_tmp))) + +int main(void) { + int ret; + char buf[32] = { 0 }; + _cleanup_file_ char filename[] = "xattr_test.XXXXXX"; + _cleanup_file_ char filename2[] = "xattr_test.XXXXXX.2"; + + int tmpfile = assert_perror(mkstemp(filename)); + memcpy(filename2, filename, sizeof(filename) - 1); + assert_perror(symlink(filename, filename2)); + + assert_perror(setxattr(filename, "user.T1", "ABC", 3, XATTR_CREATE)); + assert_perror(fsetxattr(tmpfile, "user.T2", "DEF", 3, XATTR_CREATE)); + + // for testing remove + assert_perror(fsetxattr(tmpfile, "user.T3", "DEF", 3, XATTR_CREATE)); + + if ((ret = getxattr(filename, "user.T1", buf, 3)) != 3) { + if (ret < 0) { + perror("getxattr"); + return 1; + } + + soft_assert(memcmp(buf, "ABC", 3) == 0, "xattr read wrong"); + } + + ret = lgetxattr(filename2, "user.T1", buf, 3); + soft_assert(ret < 0 && errno == ENODATA, "lgetxattr deref'd"); + + if ((ret = fgetxattr(tmpfile, "user.T3", buf, 3)) != 3) { + if (ret < 0) { + perror("fgetxattr"); + return 1; + } + + soft_assert(memcmp(buf, "DEF", 3) == 0, "xattr read wrong"); + } + + assert_perror(removexattr(filename, "user.T2")); + assert_perror(fremovexattr(tmpfile, "user.T3")); + + ret = assert_perror(listxattr(filename, buf, sizeof(buf) - 1)); + soft_assert(memmem(buf, ret, "user.T1", 7), "user.T1 not found"); + soft_assert(!memmem(buf, ret, "user.T2", 7), "user.T2 found"); + soft_assert(!memmem(buf, ret, "user.T3", 7), "user.T3 found"); + + ret = assert_perror(flistxattr(tmpfile, buf, sizeof(buf) - 1)); + soft_assert(memmem(buf, ret, "user.T1", 7), "user.T1 not found"); + soft_assert(!memmem(buf, ret, "user.T2", 7), "user.T2 found"); + soft_assert(!memmem(buf, ret, "user.T3", 7), "user.T3 found"); + + return 0; +} diff --git a/user/include/mlibc/tests/meson.build b/user/include/mlibc/tests/meson.build new file mode 100644 index 0000000..a270709 --- /dev/null +++ b/user/include/mlibc/tests/meson.build @@ -0,0 +1,342 @@ +timeout_sec = 10 + +all_test_cases = [ + 'ansi/alloc', + 'ansi/sscanf', + 'ansi/sprintf', + 'ansi/snprintf', + 'ansi/utf8', + 'ansi/strtol', + 'ansi/strtof', + 'ansi/abs', + 'ansi/longjmp', + 'ansi/mbrtoc32', + 'ansi/strverscmp', + 'ansi/strftime', + 'ansi/strchr', + 'ansi/strrchr', + 'ansi/wcsrtombs', + 'ansi/wmemcmp', + 'ansi/timegm', + 'ansi/tz', + 'ansi/ungetc', + 'ansi/wcsdup', + 'ansi/wcsncasecmp', + 'ansi/fopen', + 'ansi/memmem', + 'ansi/creal-cimag', + 'ansi/fenv', + 'ansi/qsort', + 'ansi/freopen', + 'ansi/strxfrm', + 'ansi/calloc', + 'ansi/fgetpos', + 'ansi/fputs', + 'ansi/ftell', + 'bsd/ns_get_put', + 'bsd/reallocarray', + 'bsd/strl', + 'bsd/sbrk', + 'bsd/getloadavg', + 'posix/inet_ntop', + 'posix/inet_pton', + 'posix/access', + 'posix/pthread_barrier', + 'posix/pthread_rwlock', + 'posix/pthread_cond', + 'posix/pthread_create', + 'posix/pthread_cancel', + 'posix/pthread_atfork', + 'posix/pthread_cleanup', + 'posix/pthread_kill', + 'posix/pthread_mutex', + 'posix/pthread_key', + 'posix/pthread_thread_local', + 'posix/pthread_attr', + 'posix/pthread_schedparam', + 'posix/pwd', + 'posix/fdopen', + 'posix/fopencookie', + 'posix/fmemopen', + 'posix/getaddrinfo', + 'posix/getdelim', + 'posix/getnameinfo', + 'posix/getparam', + 'posix/getservbyname', + 'posix/getservbyport', + 'posix/grp', + 'posix/dprintf', + 'posix/posix_memalign', + 'posix/posix_spawn', + 'posix/index', + 'posix/rindex', + 'posix/search', + 'posix/semaphore', + 'posix/open_memstream', + 'posix/popen', + 'posix/system', # This test should be in the ANSI tests, but it depends on sys/wait.h + 'posix/sigsuspend', + 'posix/sigaltstack', + 'posix/time', + 'posix/realpath', + 'posix/ffs', + 'posix/getcwd', + 'posix/memrchr', + 'posix/wordexp', + 'posix/rlimits', + 'posix/accept4', + 'posix/setpriority', + 'posix/nice', + 'posix/alarm', + 'posix/abort', # This test should be in the ANSI tests, but it depends on sigaction + 'posix/timer', + 'posix/vfork', + 'posix/wcwidth', + 'posix/pause', + 'posix/flockfile', + 'posix/basename', + 'posix/regex', + 'posix/sigtimedwait', + 'posix/if_indextoname', + 'posix/readv-writev', + 'posix/posix-timer', + 'posix/strdupa', + 'posix/mkstemp', + 'posix/waitid', + 'posix/usershell', + 'posix/shm', + 'posix/swab', + 'glibc/getopt', + 'glibc/ffsl-ffsll', + 'glibc/error_message_count', + 'glibc/error_one_per_line', + 'glibc/error_print_progname', + 'glibc/error_expect_fail', + 'glibc/error', + 'glibc/error_at_line', + 'glibc/getgrouplist', + 'glibc/rpmatch', + 'linux/xattr', + 'linux/pthread_setname_np', + 'linux/pthread_attr', + 'linux/cpuset', + 'linux/malloc-usable-size', + 'linux/getifaddrs', + 'linux/pidfd', + 'linux/timerfd', + 'linux/ppoll', + 'linux/utmp', + 'linux/utmpx', +] + +if host_machine.system() == 'linux' + all_test_cases += 'glibc/linux-syscall' +endif + +# We only add some tests if the target is the same as the build machine. +if build_machine.cpu_family() == target_machine.cpu_family() + # process_vm_readv_writev can only run natively beacuse qemu-user doesn't support these syscalls. + all_test_cases += 'linux/process_vm_readv_writev' +endif + +fail_test_cases = [ + 'posix/abort', + 'glibc/error_expect_fail', +] + +wrapped_test_cases = [ + 'ansi/tz', + 'glibc/error', + 'glibc/error_at_line', +] + +host_libc_excluded_test_cases = [ + 'bsd/strl', # These functions do not exist on Linux. + 'glibc/error', # These tests depend on mlibc error messages. + 'glibc/error_at_line', # These tests depend on mlibc error messages. + 'rtld/search-order', # See rtld/search-order/meson.build. +] +host_libc_noasan_test_cases = [ + 'posix/pthread_cancel', + 'posix/pthread_attr', # does some stack overflowing to check stack size + 'posix/posix_memalign', + 'posix/search', # requires tdelete (#351) + 'ansi/calloc', # does some overflowing + 'linux/pthread_attr', # encounters memory leaks +] + +extra_cflags_test_cases = { + 'ansi/calloc': ['-Wno-alloc-size-larger-than'], +} + +test_sources = [] +test_objects = [] +test_link_args = [] +test_c_args = ['-D_GNU_SOURCE', '-U__MLIBC_DEBUG', '-U__MLIBC_BUILDING_MLIBC', '-fhosted', '-fno-builtin'] +use_pie = false + +host_test_c_args = ['-fno-builtin'] + +c_compiler = meson.get_compiler('c') + +if c_compiler.get_id() == 'gcc' + test_c_args += [] + host_test_c_args += [] +elif c_compiler.get_id() == 'clang' + test_c_args += ['-Wno-unknown-warning-option'] + host_test_c_args += ['-Wno-unknown-warning-option'] +endif + +# Our ubsan implementation can't be used by the tests themselves, +# since it is internal to libc.so and ld.so. +test_override_options = ['b_sanitize=none'] + +if library_type == 'static' + c_compiler = meson.get_compiler('c') + searchdirs = run_command(c_compiler.cmd_array(), '-print-search-dirs', + check: true).stdout() + searchdirs_arr = searchdirs.split('\n') + searchline = 'libraries: =' + searchpaths = '' + + foreach line : searchdirs_arr + if line.startswith(searchline) + searchpaths = line.strip(searchline) + break + endif + endforeach + + if searchpaths == '' + error('could not find compiler-specific library directory') + endif + + searchpaths_arr = searchpaths.split(':') + crtpath = '' + fs = import('fs') + foreach path : searchpaths_arr + if fs.exists(path / 'crtbegin.o') + crtpath = path + break + endif + endforeach + + if crtpath == '' + error('could not find crtbegin.o/crtend.o') + endif + test_objects += [crtpath / 'crtbegin.o', crtpath / 'crtend.o'] + + libc_dep = declare_dependency( + include_directories: libc_include_dirs, + link_with: libc_static, + dependencies: [libc_deps, rtlib_deps] + ) + use_pie = false + test_c_args += '-no-pie' + test_link_args += ['-no-pie', '-static'] + test_sources += crt +else + libc_dep = declare_dependency( + include_directories: libc_include_dirs, + link_with: libc_shared, + dependencies: [libc_deps, rtlib_deps] + ) + test_link_args += ['-Wl,--dynamic-linker=' + meson.global_build_root() + '/ld.so'] + + if host_machine.system() in ['linux'] + use_pie = true + test_sources += crt_pie + else + use_pie = false + test_sources += crt + + # Meson doesn't set these for us (issue #4651). + test_c_args += '-no-pie' + test_link_args += '-no-pie' + endif + + # Add the rtld tests. + if posix_option + subdir('rtld') + endif +endif + +py = import('python').find_installation('python3') + +foreach test_name : all_test_cases + test_subdir = test_name.split('/')[0] + test_short_name = test_name.split('/')[1] + test_exec_name = test_name.replace('/', '-') + + if test_subdir == 'bsd' and not bsd_option + continue + elif test_subdir == 'glibc' and not glibc_option + continue + elif test_subdir == 'posix' and not posix_option + continue + elif test_subdir == 'linux' and not linux_option + continue + endif + + should_fail = fail_test_cases.contains(test_name) + exec = executable(test_exec_name, [test_name + '.c', test_sources], + dependencies: libc_dep, + objects: test_objects, + build_rpath: meson.global_build_root(), + override_options: test_override_options, + c_args: test_c_args, + link_args: test_link_args, + pie: use_pie, + ) + + if wrapped_test_cases.contains(test_name) + test(test_short_name, + py, + suite: test_subdir, + should_fail: should_fail, + args: [ + meson.global_source_root() + '/tests/' + test_name + '.py', + exec + ], + timeout: timeout_sec, + ) + else + test(test_short_name, exec, suite: test_subdir, should_fail: should_fail, timeout: timeout_sec) + endif + + if build_tests_host_libc and not host_libc_excluded_test_cases.contains(test_name) + if test_name in host_libc_noasan_test_cases + host_libc_sanitize_options = 'b_sanitize=undefined' + else + host_libc_sanitize_options = 'b_sanitize=address,undefined' + endif + + if test_name in extra_cflags_test_cases + extra_cflags = extra_cflags_test_cases[test_name] + else + extra_cflags = [] + endif + + exec = executable('host-libc-' + test_exec_name, test_name + '.c', + build_rpath: meson.global_build_root(), + override_options: host_libc_sanitize_options, + c_args: [host_test_c_args + '-D_GNU_SOURCE', '-DUSE_HOST_LIBC', '-pthread', extra_cflags], + link_args: ['-lresolv', '-ldl', '-pthread', '-lm', '-lrt'], + native: true, + ) + + if wrapped_test_cases.contains(test_name) + test(test_short_name, + py, + suite: ['host-libc', test_subdir], + should_fail: should_fail, + args: [ + meson.source_root() + '/tests/' + test_name + '.py', + exec + ], + timeout: timeout_sec, + ) + else + test(test_short_name, exec, suite: ['host-libc', test_subdir], should_fail: should_fail, timeout: timeout_sec) + endif + endif +endforeach diff --git a/user/include/mlibc/tests/posix/abort.c b/user/include/mlibc/tests/posix/abort.c new file mode 100644 index 0000000..5f7bb7d --- /dev/null +++ b/user/include/mlibc/tests/posix/abort.c @@ -0,0 +1,21 @@ +#include +#include +#include + +void handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; +} + +int main() { + struct sigaction sa; + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + + int ret = sigaction(SIGABRT, &sa, NULL); + assert(!ret); + + abort(); +} diff --git a/user/include/mlibc/tests/posix/accept4.c b/user/include/mlibc/tests/posix/accept4.c new file mode 100644 index 0000000..3bc6662 --- /dev/null +++ b/user/include/mlibc/tests/posix/accept4.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_PORT 31337 +#else +#define TEST_PORT 42069 +#endif + +static struct sockaddr_in connect_addr, accept_addr; +static int listen_fd; + +int permutations[] = { + 0, + SOCK_CLOEXEC, + SOCK_NONBLOCK, + SOCK_CLOEXEC | SOCK_NONBLOCK, +}; + +static bool run_test(int flags) +{ + int connect_fd; + int fd_flags, access; + socklen_t addrlen; + + connect_fd = socket(AF_INET, SOCK_STREAM, 0); + connect(connect_fd, (struct sockaddr *)&connect_addr, sizeof(connect_addr)); + addrlen = sizeof(accept_addr); + + int accept_fd = accept4(listen_fd, (struct sockaddr *)&accept_addr, &addrlen, flags); + + if(accept_fd == -1) { + fprintf(stderr, "accept4 failed: %s\n", strerror(errno)); + goto cleanup; + } + + fd_flags = fcntl(accept_fd, F_GETFD); + if(!(!!(fd_flags & FD_CLOEXEC) == !!(flags & SOCK_CLOEXEC))) { + fprintf(stderr, "CLOEXEC mismatch, got %d instead of %d\n", !!(fd_flags & FD_CLOEXEC), !!(flags & SOCK_CLOEXEC)); + goto cleanup; + } + + access = fcntl(accept_fd, F_GETFL); + if(!(!!(access & O_NONBLOCK) == !!(flags & SOCK_NONBLOCK))) { + fprintf(stderr, "NONBLOCK flag mismatch, %d vs %d\n", !!(access & O_NONBLOCK), !!(flags & SOCK_NONBLOCK)); + goto cleanup; + } + + close(accept_fd); + close(connect_fd); + + fprintf(stderr, "tested CLOEXEC %d, NONBLOCK %d\n", !!(flags & SOCK_CLOEXEC), !!(flags & SOCK_NONBLOCK)); + return true; + +cleanup: + close(accept_fd); + close(connect_fd); + return false; +} + +static int socket_setup(void) +{ + struct sockaddr_in addr; + int reuseaddr; + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(TEST_PORT); + + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + + if(socket_fd == -1) { + fprintf(stderr, "socket failed: %s\n", strerror(errno)); + exit(1); + } + + reuseaddr = 1; + int ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); + + if(ret == -1) { + fprintf(stderr, "setsockopt failed: %s\n", strerror(errno)); + exit(1); + } + + ret = bind(socket_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + + if(ret == -1) { + fprintf(stderr, "bind failed: %s\n", strerror(errno)); + exit(1); + } + + ret = listen(socket_fd, 5); + + if(ret == -1) { + fprintf(stderr, "listen failed: %s\n", strerror(errno)); + exit(1); + } + + return socket_fd; +} + +int main() { + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + connect_addr.sin_port = htons(TEST_PORT); + + for(size_t i = 0; i < 4; i++) { + listen_fd = socket_setup(); + if(!run_test(permutations[i])) { + exit(1); + } + close(listen_fd); + } + + return 0; +} diff --git a/user/include/mlibc/tests/posix/access.c b/user/include/mlibc/tests/posix/access.c new file mode 100644 index 0000000..ad7c859 --- /dev/null +++ b/user/include/mlibc/tests/posix/access.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "access-host-libc.tmp" +#else +#define TEST_FILE "access.tmp" +#endif + +int main() { + // Make sure that it wasn't created by a previous test run + unlink(TEST_FILE); + + assert(access(TEST_FILE, F_OK) == -1); + assert(access(TEST_FILE, W_OK) == -1); + assert(access(TEST_FILE, R_OK) == -1); + assert(access(TEST_FILE, X_OK) == -1); + + close(open(TEST_FILE, O_CREAT | O_RDWR, 0666)); + + assert(access(TEST_FILE, F_OK) == 0); + assert(access(TEST_FILE, W_OK) == 0); + assert(access(TEST_FILE, R_OK) == 0); + assert(access(TEST_FILE, X_OK) == -1); + + unlink(TEST_FILE); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/alarm.c b/user/include/mlibc/tests/posix/alarm.c new file mode 100644 index 0000000..7629846 --- /dev/null +++ b/user/include/mlibc/tests/posix/alarm.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include + +static volatile int alarms_fired = 0; + +static void sigalrm_handler(int signal) { + if(signal == SIGALRM) + alarms_fired++; +} + +int main() { + signal(SIGALRM, sigalrm_handler); + + alarms_fired = 0; + + unsigned int ret = alarm(10); + assert(!ret); + + sleep(1); + + ret = alarm(1); + assert(ret == 9); + + sleep(2); + + if(alarms_fired != 1) { + fprintf(stderr, "alarm handler fired %u times instead of 1\n", alarms_fired); + exit(1); + } + + return 0; +} diff --git a/user/include/mlibc/tests/posix/basename.c b/user/include/mlibc/tests/posix/basename.c new file mode 100644 index 0000000..c46c709 --- /dev/null +++ b/user/include/mlibc/tests/posix/basename.c @@ -0,0 +1,19 @@ +#include +#include +#include + +int main() { + /* intentionally a macro: basename modifies its argument */ +#define test_string(x, expectval) do { \ + char str[] = x; \ + assert(strcmp(basename(str), expectval) == 0); \ + } while (0) + + test_string("/usr/lib", "lib"); + test_string("/usr/", "usr"); + test_string("/", "/"); + test_string(".", "."); + test_string("..", ".."); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/dprintf.c b/user/include/mlibc/tests/posix/dprintf.c new file mode 100644 index 0000000..4746edb --- /dev/null +++ b/user/include/mlibc/tests/posix/dprintf.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "dprintf-host-libc.tmp" +#else +#define TEST_FILE "dprintf.tmp" +#endif + +int main() { + int fd = open(TEST_FILE, O_RDWR | O_CREAT, 0666); + assert(fd > -1); + + int ret = dprintf(fd, "aaa"); + assert(ret == 3); + + // Check if we can read back the same things. + // Also checks to see if the fd is still open, + // which is issue #199. + + off_t seek = lseek(fd, 0, SEEK_SET); + assert(seek == 0); + + char buf[3]; + ssize_t num_read = read(fd, buf, 3); + + assert(num_read == 3); + assert(buf[0] == 'a' + && buf[1] == 'a' + && buf[2] == 'a'); + + // All the tests pass, now we can unlink the file. + ret = unlink(TEST_FILE); + assert(ret == 0); + return 0; +} diff --git a/user/include/mlibc/tests/posix/fdopen.c b/user/include/mlibc/tests/posix/fdopen.c new file mode 100644 index 0000000..10dc173 --- /dev/null +++ b/user/include/mlibc/tests/posix/fdopen.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +#define TEST_FILE "fdopen.tmp" + +int main() { + int fd = open(TEST_FILE, O_CREAT | O_RDWR, 0666); + assert(fd >= 0); + + char *str = "mlibc fdopen test"; + assert(write(fd, str, strlen(str))); + + // Seek to the beginning, then reopen with fdopen in append mode. + lseek(fd, 0, SEEK_SET); + FILE *file = fdopen(fd, "a"); + assert(file); + + // Append and close. + str = " appended"; + fwrite(str, strlen(str), 1, file); + fflush(file); + fclose(file); + + // Open it again and check that the append succeeded. + fd = open(TEST_FILE, O_RDONLY); + assert(fd >= 0); + file = fdopen(fd, "r"); + assert(file); + str = "mlibc fdopen test appended"; + char buf[100] = {0}; + assert(fread(buf, 1, strlen(str), file)); + assert(!strcmp(buf, str)); + fclose(file); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/ffs.c b/user/include/mlibc/tests/posix/ffs.c new file mode 100644 index 0000000..3f7ba84 --- /dev/null +++ b/user/include/mlibc/tests/posix/ffs.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main(void){ + assert(ffs(0x8000) == 16); + assert(ffs(0) == 0); + assert(ffs(INT_MAX - 1) == 2); + assert(ffs(INT_MAX) == 1); + assert(ffs(INT_MIN) == (int)(sizeof(int) * CHAR_BIT)); + assert(ffs(INT_MIN + 1) == 1); + + for (int i = 1; i < 0x1000; i++) { + assert(ffs(i) - 1 == __builtin_ctz(i)); + } + + return 0; +} diff --git a/user/include/mlibc/tests/posix/flockfile.c b/user/include/mlibc/tests/posix/flockfile.c new file mode 100644 index 0000000..982311e --- /dev/null +++ b/user/include/mlibc/tests/posix/flockfile.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +static void *worker(void *arg) { + (void)arg; + flockfile(stdout); + fputs_unlocked("hello from worker", stdout); + funlockfile(stdout); + return NULL; +} + +int main() { + // Check that recursive locking works. + assert(!ftrylockfile(stdout)); + flockfile(stdout); + flockfile(stdout); + funlockfile(stdout); + funlockfile(stdout); + funlockfile(stdout); + + assert(!ftrylockfile(stdout)); + + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker, NULL); + assert(!ret); + + sleep(1); + funlockfile(stdout); + + assert(!pthread_join(thread, NULL)); + return 0; +} diff --git a/user/include/mlibc/tests/posix/fmemopen.c b/user/include/mlibc/tests/posix/fmemopen.c new file mode 100644 index 0000000..4d5046e --- /dev/null +++ b/user/include/mlibc/tests/posix/fmemopen.c @@ -0,0 +1,150 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#define BUFFER0_SIZE 0x1000 +#define BUFFER1 "Hello world" +#define BUFFER1_SIZE (sizeof(BUFFER1)) + +int main() { + // test seek with mode "r" + FILE *f = fmemopen(NULL, BUFFER0_SIZE, "r"); + assert(f); + + int ret = fseek(f, 0, SEEK_END); + assert(!ret); + long pos = ftell(f); + fprintf(stderr, "pos = %ld\n", pos); + // Despite the fact that this is correct behavior (see below), + // this sometimes fails on glibc; newlib seems to get this wrong, too. + // to quote what posix says about it: + // > The stream shall also maintain the size of the current buffer contents; + // > use of fseek() or fseeko() on the stream with SEEK_END shall seek relative to this size. + // > For modes r and r+ the size shall be set to the value given by the size argument. +#if !defined(__GLIBC__) + assert(pos == BUFFER0_SIZE); +#endif + + fclose(f); + + // test seek with mode "w" + f = fmemopen(NULL, BUFFER0_SIZE, "w"); + assert(f); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + pos = ftell(f); + assert(pos == 0); + + fclose(f); + + // test seek with mode "a" and a NULL buffer + f = fmemopen(NULL, BUFFER0_SIZE, "a"); + assert(f); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + pos = ftell(f); + assert(pos == 0); + + fclose(f); + + // test seek with mode "a" and a buffer containing a '\0' + f = fmemopen(BUFFER1, BUFFER1_SIZE + 2, "a"); + assert(f); + + pos = ftell(f); + assert(pos == (long) (BUFFER1_SIZE - 1)); + + ret = fseek(f, 0, SEEK_SET); + assert(!ret); + pos = ftell(f); + assert(!pos); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + pos = ftell(f); + assert(pos == (long) (BUFFER1_SIZE - 1)); + + fclose(f); + + // test seek with mode "a" and a buffer not containing a '\0' + f = fmemopen(BUFFER1, BUFFER1_SIZE - 2, "a"); + assert(f); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + pos = ftell(f); + assert(pos == (long) (BUFFER1_SIZE - 2)); + + fclose(f); + + f = fmemopen(BUFFER1, BUFFER1_SIZE, "r"); + assert(f); + + ret = fseek(f, 0, SEEK_SET); + assert(!ret); + + char buf[BUFFER1_SIZE]; + int read = fread(buf, 1, BUFFER1_SIZE - 2, f); + assert(read == BUFFER1_SIZE - 2); + assert(!strncmp(BUFFER1, buf, BUFFER1_SIZE - 2)); + + fseek(f, 0, SEEK_END); + + read = fread(buf, 1, 2, f); + assert(read == 0); + assert(feof(f)); + + fclose(f); + + // Open a buffer for read+write + char *buf1 = strdup(BUFFER1); + f = fmemopen(buf1, BUFFER1_SIZE, "w+"); + assert(f); + assert(strlen(BUFFER1) == BUFFER1_SIZE - 1); + + // seek to somewhere in the middle of the buffer + fseek(f, BUFFER1_SIZE - 5, SEEK_SET); + // write as much data to it as possible + read = fwrite(BUFFER1, 1, 9, f); + rewind(f); + + // seek the the same position in the middle of the buffer + ret = fseek(f, BUFFER1_SIZE - 5, SEEK_SET); + assert(!ret); + memset(buf, 0, BUFFER1_SIZE); + // read what we just wrote + read = fread(buf, 1, 5, f); + // check that the write got correctly truncated + fprintf(stderr, "buf '%s' (%zu)\n", buf, strlen(buf)); + assert(!strncmp(BUFFER1, buf, 4) && strlen(buf) == 4); + + fclose(f); + free(buf1); + + char *buf2 = strdup(BUFFER1); + f = fmemopen(buf2, 0, "r"); + assert(f || errno == EINVAL); + + if(f) { + memset(buf, 0, BUFFER1_SIZE); + read = fread(buf, 10, 1, f); + assert(!read); + rewind(f); + + read = fwrite(BUFFER1, 1, 12, f); + assert(read == 0); + + fclose(f); + } + free(buf2); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/fopencookie.c b/user/include/mlibc/tests/posix/fopencookie.c new file mode 100644 index 0000000..3de1bc0 --- /dev/null +++ b/user/include/mlibc/tests/posix/fopencookie.c @@ -0,0 +1,71 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include + +struct testcookie { + bool read; + bool write; + bool seek; + bool close; +}; + +ssize_t cookie_read(void *c, char *buf, size_t size) { + (void) buf; + struct testcookie *cookie = c; + cookie->read = true; + return size; +} + +ssize_t cookie_write(void *c, const char *buf, size_t size) { + (void) buf; + struct testcookie *cookie = c; + cookie->write = true; + return size; +} + +int cookie_seek(void *c, off64_t *offset, int whence) { + (void) offset; + (void) whence; + struct testcookie *cookie = c; + cookie->seek = true; + return 0; +} + +int cookie_close(void *c) { + struct testcookie *cookie = c; + cookie->close = true; + return 0; +} + +int main() { + struct testcookie cookie = { false, false, false, false }; + + cookie_io_functions_t funcs = { + .read = cookie_read, + .write = cookie_write, + .seek = cookie_seek, + .close = cookie_close, + }; + + FILE *stream = fopencookie(&cookie, "w+", funcs); + assert(stream); + + unsigned char buf[1]; + int ret = fread(buf, 1, 1, stream); + assert(ret == 1); + ret = fwrite(buf, 1, 1, stream); + assert(ret == 1); + ret = fseek(stream, 0, SEEK_SET); + assert(!ret); + + ret = fclose(stream); + assert(!ret); + + assert(cookie.read && cookie.write && cookie.seek && cookie.close); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/getaddrinfo.c b/user/include/mlibc/tests/posix/getaddrinfo.c new file mode 100644 index 0000000..cbb75f6 --- /dev/null +++ b/user/include/mlibc/tests/posix/getaddrinfo.c @@ -0,0 +1,235 @@ +#if !defined(USE_HOST_LIBC) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __MLIBC_LINUX_OPTION || defined(USE_HOST_LIBC) +#include + +static bool has_ipv4_addr(void) { + struct ifaddrs *addrs; + if (getifaddrs(&addrs)) { + return false; + } + + int found = 0; + for (struct ifaddrs *cur = addrs; cur; cur = cur->ifa_next) { + if (cur->ifa_addr && (cur->ifa_flags & IFF_UP) && cur->ifa_addr->sa_family == AF_INET && strncmp(cur->ifa_name, "lo", IF_NAMESIZE)) { + found = 1; + break; + } + } + + freeifaddrs(addrs); + return found; +} + +static bool has_ipv6_addr(void) { + struct ifaddrs *addrs; + if (getifaddrs(&addrs)) { + return false; + } + + int found = 0; + for (struct ifaddrs *cur = addrs; cur; cur = cur->ifa_next) { + if (cur->ifa_addr && (cur->ifa_flags & IFF_UP) && cur->ifa_addr->sa_family == AF_INET6 && strncmp(cur->ifa_name, "lo", IF_NAMESIZE)) { + found = 1; + break; + } + } + + freeifaddrs(addrs); + return found; +} +#endif // __MLIBC_LINUX_OPTION || defined(USE_HOST_LIBC) + +int main() { + struct addrinfo *res = NULL; + struct addrinfo hints = {0}; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + int ret = getaddrinfo(NULL, "443", &hints, &res); + assert(ret == 0); + + struct sockaddr_in *addr = (struct sockaddr_in*)(res[0].ai_addr); + assert(addr->sin_port == htons(443)); + assert(res[0].ai_socktype == SOCK_STREAM); + assert(res[0].ai_protocol == IPPROTO_TCP); + + freeaddrinfo(res); + res = NULL; + + /* check we can resolve any domain */ + ret = getaddrinfo("example.net", NULL, &hints, &res); + assert(ret == 0); + + freeaddrinfo(res); + res = NULL; + + hints.ai_flags = AI_NUMERICHOST; + ret = getaddrinfo("10.10.10.10", NULL, &hints, &res); + assert(ret == 0); + + addr = (struct sockaddr_in*)res[0].ai_addr; + assert((addr->sin_addr.s_addr & 0xFF) == 10); + assert(((addr->sin_addr.s_addr >> 8) & 0xFF) == 10); + assert(((addr->sin_addr.s_addr >> 16) & 0xFF) == 10); + assert(((addr->sin_addr.s_addr >> 24) & 0xFF) == 10); + + freeaddrinfo(res); + res = NULL; + + ret = getaddrinfo("example.net", NULL, &hints, &res); + assert(ret == EAI_NONAME); + + freeaddrinfo(res); + res = NULL; + + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + ret = getaddrinfo("::1", "1234", &hints, &res); + assert(ret == 0); + + assert(res[0].ai_family == AF_INET6); + struct sockaddr_in6 *addr6 = (struct sockaddr_in6*) res[0].ai_addr; + assert(addr6->sin6_port == htons(1234)); + assert(addr6->sin6_addr.s6_addr[15] == 1); + for (int i = 0; i < 15; i++) { + assert(addr6->sin6_addr.s6_addr[i] == 0); + } + + freeaddrinfo(res); + res = NULL; + + hints.ai_family = AF_INET6; + hints.ai_flags = 0; + ret = getaddrinfo("example.net", "443", &hints, &res); + assert(ret == 0); + + assert(res[0].ai_family == AF_INET6); + addr6 = (struct sockaddr_in6*)res[0].ai_addr; + assert(addr6->sin6_port == htons(443)); + + freeaddrinfo(res); + res = NULL; + +#if __MLIBC_LINUX_OPTION || defined(USE_HOST_LIBC) + // Test with AF_INET + hints.ai_family = AF_INET; + ret = getaddrinfo("localhost", NULL, &hints, &res); + if (has_ipv4_addr()) { + assert(ret == 0); + for(struct addrinfo *p = res; p != NULL; p = p->ai_next) { + assert(p->ai_family == AF_INET); + } + } else { + assert(ret != 0); + } + freeaddrinfo(res); + res = NULL; + + // Test with AF_INET6 + hints.ai_family = AF_INET6; + ret = getaddrinfo("localhost", NULL, &hints, &res); + assert(ret == 0); + for(struct addrinfo *p = res; p != NULL; p = p->ai_next) { + assert(p->ai_family == AF_INET6); + } + freeaddrinfo(res); + res = NULL; + + // Test AI_ADDRCONFIG + hints = (struct addrinfo){0}; + hints.ai_flags = AI_ADDRCONFIG; + hints.ai_family = AF_UNSPEC; + + ret = getaddrinfo("localhost", NULL, &hints, &res); + + if (ret == 0) { + int found_ipv4 = 0; + int found_ipv6 = 0; + for(struct addrinfo *p = res; p != NULL; p = p->ai_next) { + if (p->ai_family == AF_INET) + found_ipv4 = 1; + else if (p->ai_family == AF_INET6) + found_ipv6 = 1; + } + + if (has_ipv4_addr()) + assert(found_ipv4); + else + assert(!found_ipv4); + + if (has_ipv6_addr()) + assert(found_ipv6); + else + assert(!found_ipv6); + } else { + // If getaddrinfo fails, it should be because no addresses are configured. + assert(!has_ipv4_addr() && !has_ipv6_addr()); + } + + freeaddrinfo(res); + res = NULL; +#endif // __MLIBC_LINUX_OPTION || defined(USE_HOST_LIBC) + + // Test AI_NUMERICSERV. + hints = (struct addrinfo){0}; + hints.ai_flags = AI_NUMERICSERV; + hints.ai_family = AF_INET; + + ret = getaddrinfo(NULL, "8080", &hints, &res); + assert(ret == 0); + assert(res->ai_family == AF_INET); + struct sockaddr_in *addr_in = (struct sockaddr_in *)res->ai_addr; + assert(addr_in->sin_port == htons(8080)); + freeaddrinfo(res); + res = NULL; + + ret = getaddrinfo(NULL, "http", &hints, &res); + assert(ret == EAI_NONAME); + assert(res == NULL); + + hints.ai_family = AF_INET6; + + ret = getaddrinfo(NULL, "9090", &hints, &res); + assert(ret == 0); + assert(res->ai_family == AF_INET6); + struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res->ai_addr; + assert(addr_in6->sin6_port == htons(9090)); + freeaddrinfo(res); + res = NULL; + + ret = getaddrinfo(NULL, "https", &hints, &res); + assert(ret == EAI_NONAME); + assert(res == NULL); + + // Test for NXDOMAIN + hints = (struct addrinfo){0}; + ret = getaddrinfo("this-domain-should-not-exist.nxdomain", NULL, &hints, &res); + assert(ret == EAI_NONAME); + assert(res == NULL); + + // Test AI_CANONNAME. + hints = (struct addrinfo){0}; + hints.ai_flags = AI_CANONNAME; + ret = getaddrinfo("localhost.localdomain", NULL, &hints, &res); + assert(ret == 0); + assert(res->ai_canonname); + freeaddrinfo(res); + res = NULL; + + return 0; +} diff --git a/user/include/mlibc/tests/posix/getcwd.c b/user/include/mlibc/tests/posix/getcwd.c new file mode 100644 index 0000000..f3ba8da --- /dev/null +++ b/user/include/mlibc/tests/posix/getcwd.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +int main() { + char buf[PATH_MAX]; + char *ret = getcwd(buf, PATH_MAX); + + assert(ret); + assert((strlen(ret) == strlen(buf)) && strlen(ret)); + assert(!strcmp(ret, buf)); + + char *ret2 = getcwd(NULL, 0); + assert(ret2); + assert(strlen(ret2)); + assert(!strcmp(ret, ret2)); + free(ret2); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/getdelim.c b/user/include/mlibc/tests/posix/getdelim.c new file mode 100644 index 0000000..9836123 --- /dev/null +++ b/user/include/mlibc/tests/posix/getdelim.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "getdelim-host-libc.tmp" +#else +#define TEST_FILE "getdelim.tmp" +#endif + +int main(void) { + FILE *fp; + char *line = NULL; + size_t len = 0; + ssize_t read; + + // We have to open the file for writing and then reading separately, + // as mlibc doesn't allow us to do both at the same time (yet). + fp = fopen(TEST_FILE, "w"); + assert(fp); + fputs("foo\nbar\nbaz\nquux\n", fp); + fclose(fp); + + fp = fopen(TEST_FILE, "r"); + assert(fp); + while ((read = getline(&line, &len, fp)) != -1) { + printf("read line of length %zd, capacity %zu\n", read, len); + } + assert(!ferror(fp)); + free(line); + fclose(fp); + + size_t nchars = 10000; + fp = fopen(TEST_FILE, "w"); + assert(fp); + for (size_t i = 0; i < nchars; i++) + fputc('a', fp); + fputc('b', fp); + fclose(fp); + + line = NULL; + len = 0; + fp = fopen(TEST_FILE, "r"); + assert(fp); + while ((read = getdelim(&line, &len, 'b', fp)) != -1) { + printf("read line of length %zd, capacity %zu\n", read, len); + assert((size_t)read == nchars + 1); + } + + assert(len > nchars + 1); + assert(!ferror(fp)); + assert(feof(fp)); + + assert(getdelim(&line, &len, 'b', fp) == -1); + assert(feof(fp)); + + free(line); + fclose(fp); + + fp = fopen(TEST_FILE, "w"); + assert(fp); + assert(fwrite("1234ef\0f", 1, 8, fp) == 8); + fclose(fp); + + fp = fopen(TEST_FILE, "r"); + assert(fp); + + /* test with line = NULL and large len */ + line = NULL; + len = (size_t) ~0; + assert(getdelim(&line, &len, 'e', fp) == 5); + assert(!memcmp(line, "1234e", 6)); + assert(5 < len); + + /* test handling of internal nulls */ + assert(getdelim(&line, &len, 'e', fp) == 3); + assert(!memcmp(line, "f\0f", 4)); + assert(3 < len); + + /* test handling of EOF */ + assert(getdelim(&line, &len, 'e', fp) == -1); + + free(line); + fclose(fp); + + // Delete the file + unlink(TEST_FILE); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/getnameinfo.c b/user/include/mlibc/tests/posix/getnameinfo.c new file mode 100644 index 0000000..d22a0eb --- /dev/null +++ b/user/include/mlibc/tests/posix/getnameinfo.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +int main() { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + assert(inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr)); + + char host[64]; + assert(!getnameinfo((struct sockaddr*)&addr, sizeof(addr), host, + sizeof(host), NULL, 0, 0)); + + assert(inet_pton(AF_INET, "8.8.8.8", &addr.sin_addr)); + + assert(!getnameinfo((struct sockaddr*)&addr, sizeof(addr), host, + sizeof(host), NULL, 0, 0)); + assert(!strcmp(host, "dns.google")); + return 0; +} diff --git a/user/include/mlibc/tests/posix/getparam.c b/user/include/mlibc/tests/posix/getparam.c new file mode 100644 index 0000000..f725534 --- /dev/null +++ b/user/include/mlibc/tests/posix/getparam.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +int main() { + struct sched_param param = { + .sched_priority = 100, + }; + + int ret = sched_getparam(getpid(), ¶m); + assert(!ret); + + ret = sched_setparam(getpid(), ¶m); + assert(ret == 0); + + param.sched_priority = 0xD00DFEED; + + ret = sched_setparam(getpid(), ¶m); + assert(ret == -1 && errno == EINVAL); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/getservbyname.c b/user/include/mlibc/tests/posix/getservbyname.c new file mode 100644 index 0000000..8c51710 --- /dev/null +++ b/user/include/mlibc/tests/posix/getservbyname.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +int main() { + struct servent *ret = getservbyname("http", "tcp"); + assert(ret); + assert(!strcmp("http", ret->s_name)); + assert(ret->s_port == htons(80)); + assert(!strcmp("tcp", ret->s_proto)); + + ret = getservbyname("http", NULL); + assert(ret); + assert(!strcmp("http", ret->s_name)); + assert(ret->s_port == htons(80)); + assert(!strcmp("tcp", ret->s_proto)); + + ret = getservbyname("babel", "udp"); + assert(ret); + ret = getservbyname("babel", "tcp"); + assert(!ret); + + ret = getservbyname("", NULL); + assert(!ret); + return 0; +} diff --git a/user/include/mlibc/tests/posix/getservbyport.c b/user/include/mlibc/tests/posix/getservbyport.c new file mode 100644 index 0000000..f522d71 --- /dev/null +++ b/user/include/mlibc/tests/posix/getservbyport.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include + +int main() { + struct servent *ret = getservbyport(htons(80), "tcp"); + assert(ret); + assert(!strcmp("http", ret->s_name)); + assert(ret->s_port == htons(80)); + assert(!strcmp("tcp", ret->s_proto)); + + ret = getservbyport(htons(80), NULL); + assert(ret); + assert(!strcmp("http", ret->s_name)); + assert(ret->s_port == htons(80)); + assert(!strcmp("tcp", ret->s_proto)); + + ret = getservbyport(htons(6696), "udp"); + assert(ret); + ret = getservbyport(htons(6696), "tcp"); + assert(!ret); + + ret = getservbyport(htons(0), NULL); + assert(!ret); + return 0; +} diff --git a/user/include/mlibc/tests/posix/grp.c b/user/include/mlibc/tests/posix/grp.c new file mode 100644 index 0000000..bf4f147 --- /dev/null +++ b/user/include/mlibc/tests/posix/grp.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void check_root_group(struct group *grp) { + assert(grp); + + printf("group name: %s\n", grp->gr_name); + fflush(stdout); + + assert(grp->gr_gid == 0); + assert(!strcmp(grp->gr_name, "root")); + + // Depending on your system, the root group may or may not contain the root user. + if (grp->gr_mem[0] != NULL) { + bool found = false; + for (size_t i = 0; grp->gr_mem[i] != NULL; i++) { + printf("group member: %s\n", grp->gr_mem[i]); + fflush(stdout); + + if (!strcmp(grp->gr_mem[i], "root")) { + found = true; + break; + } + } + assert(found); + } +} + +int main() +{ + struct group grp, *result = NULL; + char *buf; + size_t bufsize; + int s; + bool password = false; + char *members[3]; + char filename[] = "grpXXXXXX"; + int tmpfd; + FILE *tmp; + char *expected = "managarm:passwordhash:12345:managarm,mlibc\n"; + size_t readsize; + + bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); + assert(bufsize > 0 && bufsize < 0x100000); + + buf = malloc(bufsize); + assert(buf); + + s = getgrnam_r("root", &grp, buf, bufsize, &result); + assert(!s); + check_root_group(result); + + s = getgrgid_r(0, &grp, buf, bufsize, &result); + assert(!s); + check_root_group(result); + + result = getgrnam("root"); + check_root_group(result); + + result = getgrgid(0); + check_root_group(result); + + result = getgrnam("this_group_doesnt_exist"); + assert(!result); +#ifndef USE_HOST_LIBC + // This is not guaranteed. + assert(errno == ESRCH); +#endif + + s = getgrnam_r("this_group_doesnt_exist", &grp, buf, bufsize, &result); + assert(!result); +#ifndef USE_HOST_LIBC + // This is not guaranteed. + assert(s == ESRCH); +#endif + + errno = 0; + setgrent(); + assert(errno == 0); + + result = getgrent(); + assert(result); + grp.gr_name = strdup(result->gr_name); + if(result->gr_passwd) { + password = true; + } + grp.gr_passwd = strdup(result->gr_passwd); + grp.gr_gid = result->gr_gid; + assert(grp.gr_name); + if(password) + assert(grp.gr_passwd); + + assert(grp.gr_name); + if(password) + assert(grp.gr_passwd); + + endgrent(); + + result = getgrent(); + assert(result); + assert(strcmp(result->gr_name, grp.gr_name) == 0); + if(password) + assert(strcmp(result->gr_passwd, grp.gr_passwd) == 0); + assert(result->gr_gid == grp.gr_gid); + + free(grp.gr_name); + if(password) + free(grp.gr_passwd); + + grp.gr_name = "managarm"; + grp.gr_passwd = "passwordhash"; + grp.gr_gid = 12345; + members[0] = "managarm"; + members[1] = "mli:bc"; + members[2] = NULL; + grp.gr_mem = members; + + // tmpfile() cannot be used because its unimplemented in mlibc. + tmpfd = mkstemp(filename); + assert(tmpfd); + tmp = fdopen(tmpfd, "w+"); + assert(tmp); + + assert(putgrent(NULL, tmp) < 0); + assert(putgrent(&grp, tmp) < 0); + + members[1] = "mlibc"; + + grp.gr_name = "mana:garm"; + assert(putgrent(&grp, tmp) < 0); + grp.gr_name = "managarm"; + + grp.gr_passwd = "passwordhash\n"; + assert(putgrent(&grp, tmp) < 0); + grp.gr_passwd = "passwordhash"; + + assert(putgrent(&grp, tmp) == 0); + rewind(tmp); + + readsize = fread(buf, 1, bufsize, tmp); + assert(readsize == strlen(expected)); + assert(strncmp(expected, buf, strlen(expected)) == 0); + + fclose(tmp); + unlink(filename); + + free(buf); + return 0; +} diff --git a/user/include/mlibc/tests/posix/if_indextoname.c b/user/include/mlibc/tests/posix/if_indextoname.c new file mode 100644 index 0000000..364ba6d --- /dev/null +++ b/user/include/mlibc/tests/posix/if_indextoname.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + char name[IF_NAMESIZE]; + + assert(name == if_indextoname(1, name)); + printf("test: name '%s'\n", name); + assert(1 == if_nametoindex(name)); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/index.c b/user/include/mlibc/tests/posix/index.c new file mode 100644 index 0000000..63be75d --- /dev/null +++ b/user/include/mlibc/tests/posix/index.c @@ -0,0 +1,20 @@ +#include +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + // The character 's' is at position 4, 7, 11 and 18 + pch = index(str, 's'); + assert(pch - str + 1 == 4); + pch = index(pch + 1, 's'); + assert(pch - str + 1 == 7); + pch = index(pch + 1, 's'); + assert(pch - str + 1 == 11); + pch = index(pch + 1, 's'); + assert(pch - str + 1 == 18); + pch = index(pch + 1, 's'); + assert(pch == NULL); + return 0; +} diff --git a/user/include/mlibc/tests/posix/inet_ntop.c b/user/include/mlibc/tests/posix/inet_ntop.c new file mode 100644 index 0000000..feca26c --- /dev/null +++ b/user/include/mlibc/tests/posix/inet_ntop.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +int main() { + struct in_addr addr; + addr.s_addr = (1 << 24) | + (1 << 16) | (1 << 8) | 1; + char buf[INET_ADDRSTRLEN]; + assert(inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN) != NULL); + assert(strncmp("1.1.1.1", buf, INET_ADDRSTRLEN) == 0); + + struct in6_addr addr2 = { .s6_addr = {0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1} }; + char buf2[INET6_ADDRSTRLEN]; + assert(inet_ntop(AF_INET6, &addr2, buf2, INET6_ADDRSTRLEN) != NULL); + assert(strncmp("2001:db8::1:0:0:1", buf2, INET6_ADDRSTRLEN) == 0); + + struct in6_addr addr3 = { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} }; + char buf3[INET6_ADDRSTRLEN]; + assert(inet_ntop(AF_INET6, &addr3, buf3, INET6_ADDRSTRLEN) != NULL); + assert(strncmp("::1", buf3, INET6_ADDRSTRLEN) == 0); + + struct in6_addr addr4 = { .s6_addr = {0x20, 0x1, 0xd, 0xb8, 00, 00, 00, 0x1, 00, 0x1, 00, 0x1, 00, 0x1, 00, 0x1} }; + char buf4[INET6_ADDRSTRLEN]; + assert(inet_ntop(AF_INET6, &addr4, buf4, INET6_ADDRSTRLEN) != NULL); + assert(strncmp("2001:db8:0:1:1:1:1:1", buf4, INET6_ADDRSTRLEN) == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/inet_pton.c b/user/include/mlibc/tests/posix/inet_pton.c new file mode 100644 index 0000000..7739865 --- /dev/null +++ b/user/include/mlibc/tests/posix/inet_pton.c @@ -0,0 +1,136 @@ +#include +#include +#include + +int main() { + struct in_addr addr; + assert(inet_pton(AF_INET, "1.1.1.1", &addr)); + assert((addr.s_addr & 0xFF) == 1); + assert(((addr.s_addr >> 8) & 0xFF) == 1); + assert(((addr.s_addr >> 16) & 0xFF) == 1); + assert(((addr.s_addr >> 24) & 0xFF) == 1); + + assert(!inet_pton(AF_INET, "256.999.1234.555", &addr)); + assert(!inet_pton(AF_INET, "a.b.c.d", &addr)); + + struct in6_addr test6; + { + struct in6_addr addr6 = { + .s6_addr = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }, + }; + int ret = inet_pton(AF_INET6, "::1", &test6); + assert(ret == 1); + assert(!memcmp(&addr6, &test6, sizeof(addr6))); + } + + memset(&test6, 0, sizeof(test6)); + + { + struct in6_addr addr6 = { + .s6_addr16 = { + htons(0x2606), htons(0x4700), htons(0x4700), htons(0x00), htons(0x00), htons(0x00), htons(0x00), htons(0x1111) + }, + }; + int ret = inet_pton(AF_INET6, "2606:4700:4700::1111", &test6); + assert(ret == 1); + assert(!memcmp(&addr6, &test6, sizeof(addr6))); + } + + memset(&test6, 0, sizeof(test6)); + + { + struct in6_addr addr6 = { + .s6_addr16 = { + htons(0x2606), htons(0x4700), htons(0x4700), htons(0x00), htons(0x00), htons(0x00), htons(0x00), htons(0x1111) + }, + }; + int ret = inet_pton(AF_INET6, "2606:4700:4700:0000:0000:0000:0000:1111", &test6); + assert(ret == 1); + assert(!memcmp(&addr6, &test6, sizeof(addr6))); + } + + memset(&test6, 0, sizeof(test6)); + + { + struct in6_addr addr6 = { + .s6_addr16 = { + 0, 0, 0, 0, 0, 0, 0, 0 + }, + }; + int ret = inet_pton(AF_INET6, "::", &test6); + assert(ret == 1); + assert(!memcmp(&addr6, &test6, sizeof(addr6))); + } + + memset(&test6, 0, sizeof(test6)); + + { + int ret = inet_pton(AF_INET6, "mlibc::", &test6); + assert(!ret); + } + + memset(&test6, 0, sizeof(test6)); + + { + struct in6_addr addr6 = { + .s6_addr = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0xFF, 0xFF, 204, 152, 189, 116, + }, + }; + int ret = inet_pton(AF_INET6, "::FFFF:204.152.189.116", &test6); + assert(ret == 1); + assert(!memcmp(&addr6, &test6, sizeof(addr6))); + } + + memset(&test6, 0, sizeof(test6)); + + { + int ret = inet_pton(AF_INET6, "::FFFF:204.152.189.", &test6); + assert(!ret); + } + + memset(&test6, 0, sizeof(test6)); + + { + int ret = inet_pton(AF_INET6, "::FFFF:204.152.189.420", &test6); + assert(!ret); + } + + memset(&test6, 0, sizeof(test6)); + + { + int ret = inet_pton(AF_INET6, "::FFFF:204.152.420.69", &test6); + assert(!ret); + } + + memset(&test6, 0, sizeof(test6)); + + { + int ret = inet_pton(AF_INET6, "1100::FFFF:204.152.189.116", &test6); + (void) ret; +#if !defined(USE_HOST_LIBC) + assert(!ret); +#endif + } + + memset(&test6, 0, sizeof(test6)); + + { + struct in6_addr addr6 = { + .s6_addr = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0xFF, 0xFF, 204, 152, 189, 116, + }, + }; + int ret = inet_pton(AF_INET6, "0000:0000:0000:0000:0000:FFFF:204.152.189.116", &test6); + assert(ret == 1); + assert(!memcmp(&addr6, &test6, sizeof(addr6))); + } + + return 0; +} + diff --git a/user/include/mlibc/tests/posix/memrchr.c b/user/include/mlibc/tests/posix/memrchr.c new file mode 100644 index 0000000..99e3e25 --- /dev/null +++ b/user/include/mlibc/tests/posix/memrchr.c @@ -0,0 +1,25 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include + +int main () { + char str[] = "The Last Supper by Leonardo da Vinci"; + char *str_temp; + + // Test strstr + str_temp = strstr(str, "Supper"); /* Find a substring in the string */ + assert(!strcmp(str_temp, "Supper by Leonardo da Vinci")); + + /* Following calls use memory APIs for the above tasks */ + // Test memchr + str_temp = (char *)memchr((void *)str, 'L', strlen(str)); + assert(!strcmp(str_temp, "Last Supper by Leonardo da Vinci")); + + // Test memrchr + str_temp = (char *)memrchr((void *)str, 'L', strlen(str)); + assert(!strcmp(str_temp, "Leonardo da Vinci")); + return 0; +} diff --git a/user/include/mlibc/tests/posix/mkstemp.c b/user/include/mlibc/tests/posix/mkstemp.c new file mode 100644 index 0000000..3003b14 --- /dev/null +++ b/user/include/mlibc/tests/posix/mkstemp.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include + +void validate_pattern(char *p) { + assert(memcmp(p, "XXXXXX", 6)); + assert(memchr(p, 0, 6) == NULL); + + for (int i = 0; i < 6; i++) { + assert(isalnum(p[i])); + } +} + +int main() { + int ret; + + // Make sure the patterns themselves cannot be chosen. This + // *could* happen on glibc, or if we widen the character set + // used for generating random names. Odds are 1 in 60 billion, + // but I'd rather not worry about this. + ret = open("prefixXXXXXX", O_RDWR | O_CREAT | O_EXCL, 0600); + assert(ret >= 0 || (ret == -1 && errno == EEXIST)); + ret = open("longprefixXXXXXXlongsuffix", O_RDWR | O_CREAT | O_EXCL, 0600); + assert(ret >= 0 || (ret == -1 && errno == EEXIST)); + + ret = mkstemp("short"); + assert(ret == -1); + assert(errno == EINVAL); + + ret = mkstemp("lessthan6XXX"); + assert(ret == -1); + assert(errno == EINVAL); + + ret = mkstemps("lessthan6XXXswithsuffix", 11); + assert(ret == -1); + assert(errno == EINVAL); + + char *p = strdup("prefixXXXXXX"); + ret = mkstemp(p); + // We can't really protect against EEXIST... + assert(ret >= 0 || (ret == -1 && errno == EEXIST)); + assert(!memcmp(p, "prefix", 6)); + assert(p[12] == 0); + validate_pattern(p + 6); + + if (ret >= 0) { + ret = close(ret); + assert(!ret); + } + free(p); + + p = strdup("longprefixXXXXXXlongsuffix"); + ret = mkstemps(p, 10); + // We can't really protect against EEXIST... + assert(ret >= 0 || (ret == -1 && errno == EEXIST)); + assert(!memcmp(p, "longprefix", 10)); + assert(!memcmp(p + 16, "longsuffix", 10)); + assert(p[26] == 0); + validate_pattern(p + 10); + + if (ret >= 0) { + ret = close(ret); + assert(!ret); + } + free(p); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/nice.c b/user/include/mlibc/tests/posix/nice.c new file mode 100644 index 0000000..45291de --- /dev/null +++ b/user/include/mlibc/tests/posix/nice.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main() { + errno = 0; + int original_priority = nice(0); + + assert(original_priority != -1 || !errno); + + errno = 0; + int ret = nice(1); + + if(ret == -1 && errno) { + fprintf(stderr, "%s", strerror(errno)); + exit(1); + } + + errno = 0; + int new_priority = nice(0); + + assert(new_priority != -1 || !errno); + assert(new_priority == original_priority + 1); + + errno = 0; + new_priority = nice(INT_MAX - new_priority); + + assert(new_priority != -1 || !errno); + assert(new_priority != INT_MAX); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/open_memstream.c b/user/include/mlibc/tests/posix/open_memstream.c new file mode 100644 index 0000000..0347003 --- /dev/null +++ b/user/include/mlibc/tests/posix/open_memstream.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#define WRITE_NO 1024 + +int main() { + size_t size; + char *buf; + + FILE *fp = open_memstream(&buf, &size); + assert(fp); + + char c = 'A'; + for (size_t i = 0; i < WRITE_NO; i++) + assert(fwrite(&c, sizeof(char), 1, fp) == 1); + + // Flush the file to update the pointers. + assert(!fflush(fp)); + + assert(size == WRITE_NO); + for (size_t i = 0; i < size; i++) + assert(buf[i] == c); + + // Check if the stream maintains a null-bye at the end. + assert(buf[size] == '\0'); + + // Stream should be expanded, size should be == 2*WRITE_NO. + assert(!fseek(fp, WRITE_NO, SEEK_END)); + assert(!fflush(fp)); + assert(size == 2*WRITE_NO); + assert(buf[size] == '\0'); + + // Check if it's filled with zero's. + for (size_t i = WRITE_NO; i < size; i++) + assert(buf[i] == '\0'); + + // Go back and overwrite the 0's with 'B'. + assert(!fseek(fp, -WRITE_NO, SEEK_CUR)); + c = 'B'; + for (size_t i = 0; i < WRITE_NO; i++) + assert(fwrite(&c, sizeof(char), 1, fp) == 1); + + // Check if that happened. + assert(size == 2*WRITE_NO); + for (size_t i = WRITE_NO; i < size; i++) + assert(buf[i] == c); + assert(buf[size] == '\0'); + + // Go to the front and write 'B'. + assert(!fseek(fp, 0, SEEK_SET)); + for (size_t i = 0; i < WRITE_NO; i++) + assert(fwrite(&c, sizeof(char), 1, fp) == 1); + + // Check if that happened. + assert(size == 2*WRITE_NO); + for (size_t i = 0; i < size; i++) + assert(buf[i] == c); + assert(buf[size] == '\0'); + + // Close the file, we have tested everything. + assert(!fclose(fp)); + free(buf); + return 0; +} diff --git a/user/include/mlibc/tests/posix/pause.c b/user/include/mlibc/tests/posix/pause.c new file mode 100644 index 0000000..054c5a4 --- /dev/null +++ b/user/include/mlibc/tests/posix/pause.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include +#include + +static void noop(int x) { + (void)x; +} + +int main() { + signal(SIGUSR1, &noop); + + int pid; + switch(pid = fork()) { + case -1: + perror("fork"); + abort(); + case 0: + pause(); + assert(errno == EINTR); + return 0; + default: + while (1) { + usleep(100); + kill(pid, SIGUSR1); + usleep(100); + int status; + + errno = 0; + if (waitpid(-1, &status, WNOHANG) <= 0) { + if (errno && errno != EAGAIN) { + perror("wait"); + kill(pid, SIGKILL); + } + continue; + } + + if (!WIFEXITED(status)) { + printf("wait returned %x\n", status); + abort(); + } + + return WEXITSTATUS(status); + } + } +} diff --git a/user/include/mlibc/tests/posix/popen.c b/user/include/mlibc/tests/posix/popen.c new file mode 100644 index 0000000..87bbde2 --- /dev/null +++ b/user/include/mlibc/tests/posix/popen.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "popen-host-libc.tmp" +#else +#define TEST_FILE "popen.tmp" +#endif + +#define TEST_STRING1 "the quick brown fox jumps over the lazy dog" +#define TEST_STRING1_LEN 43 +#define TEST_STRING2 "Lorem ipsum dolor sit amet, consectetur adipiscing elit" +#define TEST_STRING2_LEN 55 + +int main() { + // Test reading + FILE *f1 = popen("echo -n '" TEST_STRING1 "'", "r"); + assert(f1); + char buf1[TEST_STRING1_LEN]; + assert(fread(buf1, 1, TEST_STRING1_LEN, f1) == TEST_STRING1_LEN); + assert(memcmp(buf1, TEST_STRING1, TEST_STRING1_LEN) == 0); + pclose(f1); + + // Test writing + FILE *f2 = popen("cat - > " TEST_FILE, "w"); + assert(f2); + assert(fwrite(TEST_STRING2, 1, TEST_STRING2_LEN, f2) == TEST_STRING2_LEN); + pclose(f2); + + // Read test file back + FILE *test_file = fopen(TEST_FILE, "r"); + assert(test_file); + char buf2[TEST_STRING2_LEN]; + assert(fread(buf2, 1, TEST_STRING2_LEN, test_file) == TEST_STRING2_LEN); + assert(memcmp(buf2, TEST_STRING2, TEST_STRING2_LEN) == 0); + fclose(test_file); + assert(unlink(TEST_FILE) == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/posix-timer.c b/user/include/mlibc/tests/posix/posix-timer.c new file mode 100644 index 0000000..d6a9d15 --- /dev/null +++ b/user/include/mlibc/tests/posix/posix-timer.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) + +#include + +size_t COUNTER_EXPIRATIONS = 3; + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +size_t count = 0; + +void timer_handler(union sigval val) { + (void) val; + pthread_mutex_lock(&mutex); + count++; + fprintf(stderr, "new count %zu\n", count); + if(count >= COUNTER_EXPIRATIONS) { + pthread_cond_signal(&cond); + } + pthread_mutex_unlock(&mutex); +} + +static void test_thread_notify() { + timer_t timer; + struct sigevent sev = { + .sigev_value = { + .sival_ptr = &timer, + }, + .sigev_notify = SIGEV_THREAD, + }; + sev.sigev_notify_function = timer_handler; + sev.sigev_notify_attributes = NULL; + + int ret = timer_create(CLOCK_MONOTONIC, &sev, &timer); + assert(ret == 0); + + struct itimerspec its = { + .it_interval = { + .tv_sec = 1, + .tv_nsec = 0, + }, + .it_value = { + .tv_sec = 1, + .tv_nsec = 0, + }, + }; + ret = timer_settime(timer, 0, &its, NULL); + assert(ret == 0); + + pthread_mutex_lock(&mutex); + + while(count < COUNTER_EXPIRATIONS) + pthread_cond_wait(&cond, &mutex); + + pthread_mutex_unlock(&mutex); + + ret = timer_delete(timer); + assert(ret == 0); +} + +#endif + +int main() { + struct sigevent evp; + memset(&evp, 0, sizeof(evp)); + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + sigprocmask(SIG_BLOCK, &set, 0); + evp.sigev_notify = SIGEV_SIGNAL; + evp.sigev_signo = SIGUSR1; + + struct timeval start; + gettimeofday(&start, NULL); + + timer_t timer; + if (timer_create(CLOCK_MONOTONIC, &evp, &timer)) { + perror("timer_create"); + exit(1); + } + + struct itimerspec spec; + memset(&spec, 0, sizeof(spec)); + spec.it_value.tv_sec = 1; + spec.it_value.tv_nsec = 0; + + int sig; + timer_settime(timer, 0, &spec, NULL); + + struct itimerspec its = {}; + int ret = timer_gettime(timer, &its); + assert(ret == 0); + assert(its.it_value.tv_sec || its.it_value.tv_nsec); + + sigwait(&set, &sig); + + struct timeval end; + gettimeofday(&end, NULL); + + double diff = end.tv_sec - start.tv_sec; + diff += (end.tv_usec - start.tv_usec) / 1000000.0; + assert(diff >= 1.0); + +#if defined(__linux__) + test_thread_notify(); +#endif + + timer_delete(timer); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/posix_memalign.c b/user/include/mlibc/tests/posix/posix_memalign.c new file mode 100644 index 0000000..b03d62f --- /dev/null +++ b/user/include/mlibc/tests/posix/posix_memalign.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +int main() { + void *p = NULL; + + // align must be a power of two + assert(posix_memalign(&p, 3, 1) == EINVAL && p == NULL); + + // align must be a multiple of sizeof(void *) + assert(posix_memalign(&p, sizeof(void *) / 2, 8) == EINVAL && p == NULL); + + assert(posix_memalign(&p, sizeof(void *), sizeof(void *)) == 0 && p != NULL && (uintptr_t)p % sizeof(void *) == 0); + free(p); + assert(posix_memalign(&p, 256, 1) == 0 && p != NULL && (uintptr_t)p % 256 == 0); + free(p); + assert(posix_memalign(&p, 256, 256) == 0 && p != NULL && (uintptr_t)p % 256 == 0); + free(p); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/posix_spawn.c b/user/include/mlibc/tests/posix/posix_spawn.c new file mode 100644 index 0000000..cc5ccff --- /dev/null +++ b/user/include/mlibc/tests/posix/posix_spawn.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +#include +#include +#include + +extern char **environ; + +void run_cmd(char *cmd) +{ + pid_t pid; + char *argv[] = {"sh", "-c", cmd, NULL}; + int status; + printf("Run command: %s\n", cmd); + status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ); + if(status == 0) { + printf("Child pid: %i\n", pid); + if(waitpid(pid, &status, 0) != -1) { + printf("Child exited with status %i\n", status); + printf("Child exit status: %i\n", WEXITSTATUS(status)); + assert(WEXITSTATUS(status) == 0); + } else { + perror("waitpid"); + assert(0 == 1); + } + } else { + printf("posix_spawn: %s\n", strerror(status)); + assert(0 == 1); + } +} + +int main() { + run_cmd(":"); + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_atfork.c b/user/include/mlibc/tests/posix/pthread_atfork.c new file mode 100644 index 0000000..45be136 --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_atfork.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include + +_Atomic int prepare_order = 0; +_Atomic int parent_order = 0; +_Atomic int child_order = 0; + +static void prepare1() { prepare_order = 1; } +static void prepare2() { prepare_order = 2; } + +static void parent1() { parent_order = 1; } +static void parent2() { parent_order = 2; } + +static void child1() { child_order = 1; } +static void child2() { child_order = 2; } + +int main() { + assert(!pthread_atfork(prepare1, parent1, child1)); + assert(!pthread_atfork(prepare2, parent2, child2)); + + pid_t pid = fork(); + assert(pid >= 0); + + if (!pid) { + assert(child_order == 2); + exit(0); + } else { + assert(prepare_order == 1); + assert(parent_order == 2); + + while (1) { + int status = 0; + + int ret = waitpid(pid, &status, 0); + + if (ret == -1 && errno == EINTR) + continue; + + assert(ret > 0); + + if (WIFSIGNALED(status) && WTERMSIG(status) == SIGABRT) + return 1; + + return WEXITSTATUS(status); + } + } + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_attr.c b/user/include/mlibc/tests/posix/pthread_attr.c new file mode 100644 index 0000000..e523c0d --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_attr.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include +#include + +static void test_detachstate() { + pthread_attr_t attr; + assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); + int detachstate; + assert(!pthread_attr_getdetachstate(&attr, &detachstate)); + assert(detachstate == PTHREAD_CREATE_DETACHED); + assert(pthread_attr_setdetachstate(&attr, 2* (PTHREAD_CREATE_DETACHED + + PTHREAD_CREATE_JOINABLE)) == EINVAL); +} + +static void *stacksize_worker(void *arg) { + size_t default_stacksize = (*(size_t*)arg); + size_t alloc_size = default_stacksize + default_stacksize/2; + void *area = alloca(alloc_size); + // If the allocated stack was not enough this will crash. + // Trample both the start and end of the area so it works on both upwards- + // and downwards-growing stacks. + *(volatile char*)area = 1; + *(volatile char*)(area + alloc_size - 1) = 1; + return NULL; +} + +static void test_stacksize() { + pthread_attr_t attr; + assert(!pthread_attr_init(&attr)); + size_t stacksize; + assert(!pthread_attr_getstacksize(&attr, &stacksize)); + assert(!pthread_attr_setstacksize(&attr, stacksize * 2)); + pthread_t thread; + assert(!pthread_create(&thread, &attr, stacksize_worker, &stacksize)); + assert(!pthread_join(thread, NULL)); +} + +static void test_guardsize() { + pthread_attr_t attr; + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setguardsize(&attr, 0)); + size_t guardsize; + assert(!pthread_attr_getguardsize(&attr, &guardsize)); + assert(!guardsize); +} + +static void test_scope() { + pthread_attr_t attr; + assert(!pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)); + int scope; + assert(!pthread_attr_getscope(&attr, &scope)); + assert(scope == PTHREAD_SCOPE_SYSTEM); + assert(pthread_attr_setscope(&attr, 2* (PTHREAD_SCOPE_SYSTEM + + PTHREAD_SCOPE_PROCESS)) == EINVAL); +} + +static void test_inheritsched() { + pthread_attr_t attr; + assert(!pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED)); + int inheritsched; + assert(!pthread_attr_getinheritsched(&attr, &inheritsched)); + assert(inheritsched == PTHREAD_INHERIT_SCHED); + assert(pthread_attr_setinheritsched(&attr, 2* (PTHREAD_INHERIT_SCHED + + PTHREAD_EXPLICIT_SCHED)) == EINVAL); +} + +static void test_schedparam() { + pthread_attr_t attr; + struct sched_param init_param = {0}; + assert(!pthread_attr_setschedparam(&attr, &init_param)); + struct sched_param param = {1}; + assert(!pthread_attr_getschedparam(&attr, ¶m)); + assert(param.sched_priority == init_param.sched_priority); +} + +static void test_schedpolicy() { + pthread_attr_t attr; + assert(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO)); + int policy; + assert(!pthread_attr_getschedpolicy(&attr, &policy)); + assert(policy == SCHED_FIFO); + assert(pthread_attr_setinheritsched(&attr, 2* (SCHED_FIFO + SCHED_RR + + SCHED_OTHER)) == EINVAL); +} + +static void *stackaddr_worker(void *arg) { + void *addr = *(void**)arg; + + void *sp; +#if defined(__x86_64__) + asm volatile ("mov %%rsp, %0" : "=r"(sp)); +#elif defined(__i386__) + asm volatile ("mov %%esp, %0" : "=r"(sp)); +#elif defined(__aarch64__) + asm volatile ("mov %0, sp" : "=r"(sp)); +#elif defined (__riscv) + asm volatile ("mv %0, sp" : "=r"(sp)); +#elif defined(__m68k__) + asm volatile ("move.l %%sp, %0" : "=r"(sp)); +#elif defined (__loongarch64) + asm volatile ("move %0, $sp" : "=r"(sp)); +#else +# error Unknown architecture +#endif + + // Check if our stack pointer is in a sane range. + assert(sp > addr); + return NULL; +} +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +static void test_stackaddr() { + pthread_attr_t attr; + assert(!pthread_attr_init(&attr)); + size_t size; + assert(!pthread_attr_getstacksize(&attr, &size)); + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(!pthread_attr_setstack(&attr, addr, size)); + assert(!pthread_attr_setguardsize(&attr, 0)); + void *new_addr; + size_t new_size; + assert(!pthread_attr_getstack(&attr, &new_addr, &new_size)); + assert(new_addr == addr); + assert(new_size == size); + + pthread_t thread; + assert(!pthread_create(&thread, &attr, stackaddr_worker, &addr)); + assert(!pthread_join(thread, NULL)); +} +#pragma GCC diagnostic pop + +#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) +static void test_stack() { + pthread_attr_t attr; + void *stackaddr = (void*)1; + size_t stacksize = PTHREAD_STACK_MIN; + + assert(!pthread_attr_setstack(&attr, stackaddr, stacksize)); + void *new_addr; + size_t new_size; + assert(!pthread_attr_getstack(&attr, &new_addr, &new_size)); + assert(new_addr == stackaddr); + assert(new_size == stacksize); +} +#endif + +int main() { + test_detachstate(); + test_stacksize(); + test_guardsize(); + test_scope(); + test_inheritsched(); + test_schedparam(); + test_schedpolicy(); + test_stackaddr(); +#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) + test_stack(); +#endif + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_barrier.c b/user/include/mlibc/tests/posix/pthread_barrier.c new file mode 100644 index 0000000..31cc696 --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_barrier.c @@ -0,0 +1,58 @@ +#include +#include +#include + +pthread_barrier_t barrier; +_Atomic int hitBarrierCount, pastBarrierCount; + +static void *worker(void *arg) { + (void)arg; + hitBarrierCount++; + pthread_barrier_wait(&barrier); + pastBarrierCount++; + return NULL; +} + +int main() { + // pthread_barrierattr_t + pthread_barrierattr_t attr; + pthread_barrierattr_init(&attr); + + int pshared; + pthread_barrierattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + + pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_barrierattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_SHARED); + + pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + pthread_barrierattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + + // pthread_barrier_t + pthread_barrier_init(&barrier, &attr, 3); + pthread_barrierattr_destroy(&attr); + + pthread_t thread1; + int ret = pthread_create(&thread1, NULL, &worker, NULL); + assert(!ret); + + pthread_t thread2; + ret = pthread_create(&thread2, NULL, &worker, NULL); + assert(!ret); + + sleep(1); + + // Make sure the barrier actually stops threads from proceeding. + assert(pastBarrierCount == 0); + assert(hitBarrierCount <= 2); + + hitBarrierCount++; + pthread_barrier_wait(&barrier); + assert(hitBarrierCount == 3); + + pthread_barrier_destroy(&barrier); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_cancel.c b/user/include/mlibc/tests/posix/pthread_cancel.c new file mode 100644 index 0000000..ca4ca34 --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_cancel.c @@ -0,0 +1,150 @@ +#include +#include +#include + +_Atomic int worker_ready = 0; +_Atomic int main_ready = 0; + +static void *worker1(void *arg) { + (void)arg; + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + assert(!pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); + + worker_ready = 1; + + while (1) sleep(1); + + return NULL; +} + +static void *worker2(void *arg) { + (void) arg; + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + worker_ready = 1; + + while(!main_ready); + + // Cancellation point - we should cancel right now + sleep(1); + + assert(!"Expected to be cancelled!"); + __builtin_unreachable(); +} + +static void *worker3(void *arg) { + (void) arg; + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + worker_ready = 1; + + while(!main_ready); + + // Cancellation point - we should cancel right now + pthread_testcancel(); + + assert(!"Expected to be cancelled!"); + __builtin_unreachable(); +} + +static void *worker4(void *arg) { + (void) arg; + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + worker_ready = 1; + sleep(1); + + // We expect to be canceled during the sleep + + assert(!"Expected to be cancelled!"); + __builtin_unreachable(); +} + +static void *worker5(void *arg) { + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + worker_ready = 1; + + while(!main_ready); + + // Cancellation point - we should NOT cancel right now + pthread_testcancel(); + + int *arg_int = (int*)arg; + *arg_int = 1; + + return NULL; +} + +static void check_result(pthread_t thread) { + + void *ret_val = NULL; + int ret = pthread_join(thread, &ret_val); + assert(!ret); + assert(ret_val == PTHREAD_CANCELED); +} + +int main() { + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker1, NULL); + assert(!ret); + + while (!worker_ready); + ret = pthread_cancel(thread); + assert(!ret); + check_result(thread); + + main_ready = 0; + worker_ready = 0; + main_ready = 0; + ret = pthread_create(&thread, NULL, &worker2, NULL); + assert(!ret); + + while(!worker_ready); + ret = pthread_cancel(thread); + assert(!ret); + main_ready = 1; + check_result(thread); + + main_ready = 0; + worker_ready = 0; + main_ready = 0; + ret = pthread_create(&thread, NULL, &worker3, NULL); + assert(!ret); + + while(!worker_ready); + ret = pthread_cancel(thread); + assert(!ret); + main_ready = 1; + check_result(thread); + + worker_ready = 0; + main_ready = 0; + ret = pthread_create(&thread, NULL, &worker4, NULL); + assert(!ret); + + while(!worker_ready); + ret = pthread_cancel(thread); + assert(!ret); + main_ready = 1; + check_result(thread); + + // Test for bug where pthread_testcancel() was not checking if + // cancellation was triggered properly. + worker_ready = 0; + int pthread_arg = 0; + main_ready = 0; + ret = pthread_create(&thread, NULL, &worker5, &pthread_arg); + assert(!ret); + + while(!worker_ready); + main_ready = 1; + + void *ret_val = NULL; + ret = pthread_join(thread, &ret_val); + assert(!ret); + assert(!ret_val); + assert(pthread_arg == 1); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_cleanup.c b/user/include/mlibc/tests/posix/pthread_cleanup.c new file mode 100644 index 0000000..b6136aa --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_cleanup.c @@ -0,0 +1,42 @@ +#include +#include +#include + +_Atomic uintptr_t cleanup_val = 0; + +static void cleanup(void *arg) { + cleanup_val = (uintptr_t)arg; +} + +static void *worker(void *arg) { + (void)arg; + + pthread_cleanup_push(cleanup, (void *)1); + pthread_cleanup_push(cleanup, (void *)2); + pthread_cleanup_push(cleanup, (void *)3); + pthread_cleanup_push(cleanup, (void *)4); + + pthread_cleanup_pop(1); + assert(cleanup_val == 4); + + pthread_cleanup_pop(0); + assert(cleanup_val == 4); + + pthread_exit(NULL); + + pthread_cleanup_pop(0); + pthread_cleanup_pop(0); + + return NULL; +} + +int main() { + pthread_t thread; + assert(!pthread_create(&thread, NULL, &worker, NULL)); + assert(!pthread_join(thread, NULL)); + + assert(cleanup_val == 1); + + return 0; +} + diff --git a/user/include/mlibc/tests/posix/pthread_cond.c b/user/include/mlibc/tests/posix/pthread_cond.c new file mode 100644 index 0000000..a97fe16 --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_cond.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include + +_Atomic int waiting, should_exit; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; + +static void *worker(void *arg) { + (void)arg; + pthread_mutex_lock(&mtx); + ++waiting; + while (!should_exit) + pthread_cond_wait(&cond, &mtx); + pthread_mutex_unlock(&mtx); + return NULL; +} + +static void test_broadcast_wakes_all() { + pthread_t t1, t2; + pthread_create(&t1, NULL, &worker, NULL); + pthread_create(&t2, NULL, &worker, NULL); + + // Wait until the workers have actually entered the cond_wait + // before doing a broadcast. + while (waiting != 2 || pthread_mutex_trylock(&mtx) == EBUSY) + usleep(150000); // 150ms + + should_exit = 1; + assert(!pthread_cond_broadcast(&cond)); + pthread_mutex_unlock(&mtx); + + pthread_join(t1, NULL); + pthread_join(t2, NULL); +} + +static void test_timedwait_timedout() { + // Use CLOCK_MONOTONIC. + pthread_condattr_t attr; + pthread_condattr_init(&attr); + assert(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)); + + struct timespec before_now; + assert(!clock_gettime(CLOCK_MONOTONIC, &before_now)); + before_now.tv_nsec -= 10000; + + pthread_mutex_lock(&mtx); + int e = pthread_cond_timedwait(&cond, &mtx, &before_now); + assert(e == ETIMEDOUT); + pthread_mutex_unlock(&mtx); + + long nanos_per_second = 1000000000; + struct timespec after_now; + assert(!clock_gettime(CLOCK_MONOTONIC, &after_now)); + after_now.tv_nsec += nanos_per_second / 10; // 100ms + if (after_now.tv_nsec >= nanos_per_second) { + after_now.tv_nsec -= nanos_per_second; + after_now.tv_sec++; + } + + pthread_mutex_lock(&mtx); + e = pthread_cond_timedwait(&cond, &mtx, &after_now); + assert(e == ETIMEDOUT); + pthread_mutex_unlock(&mtx); + + after_now.tv_nsec += nanos_per_second; + pthread_mutex_lock(&mtx); + e = pthread_cond_timedwait(&cond, &mtx, &after_now); + assert(e == EINVAL); + pthread_mutex_unlock(&mtx); +} + +static void test_attr() { + pthread_condattr_t attr; + pthread_condattr_init(&attr); + + clockid_t clock; + assert(!pthread_condattr_getclock(&attr, &clock)); + assert(clock == CLOCK_REALTIME); + assert(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)); + assert(!pthread_condattr_getclock(&attr, &clock)); + assert(clock == CLOCK_MONOTONIC); + + int pshared; + assert(!pthread_condattr_getpshared(&attr, &pshared)); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + assert(!pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)); + assert(!pthread_condattr_getpshared(&attr, &pshared)); + assert(pshared == PTHREAD_PROCESS_SHARED); + + pthread_condattr_destroy(&attr); + pthread_condattr_init(&attr); + + // Make sure that we can create a pthread_cond_t with an attr. + pthread_cond_t cond; + pthread_cond_init(&cond, &attr); + pthread_cond_destroy(&cond); + pthread_condattr_destroy(&attr); +} + +int main() { + test_attr(); + test_broadcast_wakes_all(); + test_timedwait_timedout(); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_create.c b/user/include/mlibc/tests/posix/pthread_create.c new file mode 100644 index 0000000..b78674f --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_create.c @@ -0,0 +1,22 @@ +#include +#include +#include + +int variable = 0; + +static void *worker(void *arg) { + (void) arg; + variable = 1; + return NULL; +} + +int main() { + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker, NULL); + assert(!ret); + + ret = pthread_join(thread, NULL); + assert(!ret); + assert(variable == 1); + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_key.c b/user/include/mlibc/tests/posix/pthread_key.c new file mode 100644 index 0000000..40bd882 --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_key.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +_Atomic int dtors_entered = 0; +pthread_key_t key3; + +static void dtor1(void *arg) { + (void)arg; + dtors_entered++; + + // Set the key during destruction to trigger dtor2 (as it only runs if + // the key value is non-NULL). + assert(!pthread_setspecific(key3, &key3)); + assert(pthread_getspecific(key3) == &key3); +} + +static void dtor2(void *arg) { + (void)arg; + dtors_entered++; +} + +static void *worker1(void *arg) { + (void)arg; + + pthread_key_t key1, key2; + assert(!pthread_key_create(&key1, NULL)); + assert(!pthread_key_create(&key2, dtor1)); + assert(!pthread_key_create(&key3, dtor2)); + + assert(!pthread_setspecific(key1, &key1)); + assert(pthread_getspecific(key1) == &key1); + + assert(!pthread_setspecific(key2, &key2)); + assert(pthread_getspecific(key2) == &key2); + + pthread_exit(0); + return NULL; +} + +static void dtor3(void *arg) { + (void)arg; + + // Make sure that we can create and destroy keys inside the dtor. + pthread_key_t dtorKey; + assert(!pthread_key_create(&dtorKey, NULL)); + + assert(!pthread_setspecific(dtorKey, &dtorKey)); + assert(pthread_getspecific(dtorKey) == &dtorKey); + + assert(!pthread_key_delete(dtorKey)); +} + +static void *worker2(void *arg) { + (void)arg; + + pthread_key_t key; + assert(!pthread_key_create(&key, dtor3)); + + assert(!pthread_setspecific(key, &key)); + assert(pthread_getspecific(key) == &key); + + pthread_exit(0); + return NULL; +} + +int main() { + // NOTE that the EINVAL return from pthread_setspecific is mlibc-specific, + // POSIX specifies that accessing an invalid key is undefined behavior. + + assert(pthread_getspecific(PTHREAD_KEYS_MAX) == NULL); + assert(pthread_setspecific(PTHREAD_KEYS_MAX, NULL) == EINVAL); + + pthread_key_t key; + assert(!pthread_key_create(&key, NULL)); + assert(!pthread_setspecific(key, &key)); + assert(pthread_getspecific(key) == &key); + assert(!pthread_key_delete(key)); + + pthread_t thread; + assert(!pthread_create(&thread, NULL, &worker1, NULL)); + assert(!pthread_join(thread, NULL)); + + assert(pthread_getspecific(key) == NULL); + assert(!pthread_setspecific(key, &key)); + assert(pthread_getspecific(key) == &key); + + assert(dtors_entered == 2); + + assert(!pthread_create(&thread, NULL, &worker2, NULL)); + assert(!pthread_join(thread, NULL)); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_kill.c b/user/include/mlibc/tests/posix/pthread_kill.c new file mode 100644 index 0000000..b740b70 --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_kill.c @@ -0,0 +1,46 @@ +#include +#include +#include + +_Atomic int handler_ready = 0; +_Atomic int thread_signal_ran = 0; + +static void sig_handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; + + thread_signal_ran = 1; +} + +static void *worker(void *arg) { + (void)arg; + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = sig_handler; + sa.sa_flags = SA_SIGINFO; + assert(!sigaction(SIGUSR1, &sa, NULL)); + + handler_ready = 1; + + while (!thread_signal_ran) + ; + + return NULL; +} + +int main() { + pthread_t thread; + assert(!pthread_create(&thread, NULL, &worker, NULL)); + + while (!handler_ready) + ; + + assert(!pthread_kill(thread, SIGUSR1)); + assert(!pthread_join(thread, NULL)); + + assert(thread_signal_ran); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_mutex.c b/user/include/mlibc/tests/posix/pthread_mutex.c new file mode 100644 index 0000000..6ee202e --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_mutex.c @@ -0,0 +1,103 @@ +#include +#include +#include + +#define TEST_ATTR(attr, field, value) ({ \ + int x; \ + assert(!pthread_mutexattr_set ## field (&(attr), (value))); \ + assert(!pthread_mutexattr_get ## field (&(attr), &x)); \ + assert(x == (value)); \ + }) + +int variable; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static void *worker(void *arg) { + (void)arg; + pthread_mutex_lock(&mutex); + variable = 1; + pthread_mutex_unlock(&mutex); + return NULL; +} + +static void testAttr() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + + TEST_ATTR(attr, type, PTHREAD_MUTEX_DEFAULT); + TEST_ATTR(attr, type, PTHREAD_MUTEX_NORMAL); + TEST_ATTR(attr, type, PTHREAD_MUTEX_ERRORCHECK); + TEST_ATTR(attr, type, PTHREAD_MUTEX_RECURSIVE); + + TEST_ATTR(attr, robust, PTHREAD_MUTEX_STALLED); + TEST_ATTR(attr, robust, PTHREAD_MUTEX_ROBUST); + + TEST_ATTR(attr, protocol, PTHREAD_PRIO_NONE); + TEST_ATTR(attr, protocol, PTHREAD_PRIO_INHERIT); + TEST_ATTR(attr, protocol, PTHREAD_PRIO_PROTECT); + + TEST_ATTR(attr, pshared, PTHREAD_PROCESS_PRIVATE); + TEST_ATTR(attr, pshared, PTHREAD_PROCESS_SHARED); + + // TODO: sched_get_priority* is unimplemented. + // int prio = sched_get_priority_max(SCHED_FIFO); + // TEST_ATTR(attr, prioceiling, prio); + + pthread_mutexattr_destroy(&attr); +} + +static void testNormal() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutex_init(&mutex, &attr); + pthread_mutexattr_destroy(&attr); + + pthread_mutex_lock(&mutex); + variable = 0; + + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker, NULL); + assert(!ret); + + assert(pthread_mutex_trylock(&mutex) == EBUSY); + pthread_mutex_unlock(&mutex); + + ret = pthread_join(thread, NULL); + assert(!ret); + assert(variable == 1); + + pthread_mutex_destroy(&mutex); +} + +static void testRecursive() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mutex, &attr); + pthread_mutexattr_destroy(&attr); + + pthread_mutex_lock(&mutex); + variable = 0; + + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker, NULL); + assert(!ret); + + assert(pthread_mutex_trylock(&mutex) == 0); + pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); + + ret = pthread_join(thread, NULL); + assert(!ret); + assert(variable == 1); + + pthread_mutex_destroy(&mutex); +} + +int main() { + testAttr(); + testNormal(); + testRecursive(); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_rwlock.c b/user/include/mlibc/tests/posix/pthread_rwlock.c new file mode 100644 index 0000000..e26084b --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_rwlock.c @@ -0,0 +1,116 @@ +#include +#include +#include + +static void test_write_lock_unlock() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_wrlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_read_lock_unlock() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_rdlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_write_trylock_unlock() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_trywrlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_read_trylock_unlock() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_tryrdlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_write_prevents_read() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_wrlock(&rw); + assert(!res); + res = pthread_rwlock_tryrdlock(&rw); + assert(res == EBUSY); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_write_prevents_write() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_wrlock(&rw); + assert(!res); + res = pthread_rwlock_trywrlock(&rw); + assert(res == EBUSY); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_read_prevents_write() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_rdlock(&rw); + assert(!res); + res = pthread_rwlock_trywrlock(&rw); + assert(res == EBUSY); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_read_allows_read() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_rdlock(&rw); + assert(!res); + res = pthread_rwlock_tryrdlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_attr() { + pthread_rwlockattr_t attr; + pthread_rwlockattr_init(&attr); + + int pshared; + pthread_rwlockattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + + pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_rwlockattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_SHARED); + + pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + pthread_rwlockattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + + pthread_rwlockattr_destroy(&attr); +} + +int main() { + test_write_lock_unlock(); + test_read_lock_unlock(); + test_write_trylock_unlock(); + test_read_trylock_unlock(); + test_write_prevents_read(); + test_write_prevents_write(); + test_read_prevents_write(); + test_read_allows_read(); + test_attr(); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_schedparam.c b/user/include/mlibc/tests/posix/pthread_schedparam.c new file mode 100644 index 0000000..6a3a886 --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_schedparam.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +int main() { + struct sched_param param = { + .sched_priority = 100, + }; + + int policy = 0xDEADBEEF; + + int ret = pthread_getschedparam(pthread_self(), &policy, ¶m); + assert(policy == SCHED_OTHER); + assert(!ret); + + param.sched_priority = 10; + + ret = pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); + assert(!ret || ret == EPERM); + + if(ret == EPERM) { + exit(0); + } + + param.sched_priority = 0xDEADBEEF; + + ret = pthread_getschedparam(pthread_self(), &policy, ¶m); + assert(policy == SCHED_FIFO); + assert(param.sched_priority == 10); + assert(!ret); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pthread_thread_local.c b/user/include/mlibc/tests/posix/pthread_thread_local.c new file mode 100644 index 0000000..38651b1 --- /dev/null +++ b/user/include/mlibc/tests/posix/pthread_thread_local.c @@ -0,0 +1,55 @@ +#include +#include +#include + +_Thread_local unsigned int counter = 9999; +_Thread_local unsigned int uninitialized; + +void *check_counter(void *arg) +{ + (void)arg; + fprintf(stderr, "counter for worker thread: %d, at %p\n", counter, &counter); + fflush(stderr); + assert(counter == 9999); + + fprintf(stderr, "uninitialized data for worker thread: %d, at %p\n", uninitialized, &uninitialized); + fflush(stderr); + assert(uninitialized == 0); + + ++counter; + ++uninitialized; + fprintf(stderr, "counter for worker thread: %d\n", counter); + fflush(stderr); + assert(counter == 10000); + assert(uninitialized == 1); + return NULL; +} + +int main() +{ + fprintf(stderr, "counter for main thread: %d, at %p\n", counter, &counter); + fflush(stderr); + assert(counter == 9999); + + fprintf(stderr, "uninitialized data for main thread: %d, at %p\n", uninitialized, &uninitialized); + fflush(stderr); + assert(uninitialized == 0); + + ++counter; + ++uninitialized; + fprintf(stderr, "counter for main: %d\n", counter); + fflush(stderr); + assert(counter == 10000); + assert(uninitialized == 1); + + pthread_t thd; + pthread_create(&thd, NULL, check_counter, NULL); + pthread_join(thd, NULL); + + fprintf(stderr, "counter for main: %d\n", counter); + fflush(stderr); + assert(counter == 10000); + assert(uninitialized == 1); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/pwd.c b/user/include/mlibc/tests/posix/pwd.c new file mode 100644 index 0000000..9645646 --- /dev/null +++ b/user/include/mlibc/tests/posix/pwd.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + struct passwd pwd, *result = NULL; + char *buf; + size_t bufsize; + int s; + + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + assert(bufsize > 0 && bufsize < 0x100000); + + buf = malloc(bufsize); + assert(buf); + + s = getpwnam_r("root", &pwd, buf, bufsize, &result); + assert(!s); + assert(pwd.pw_uid == 0); + assert(!strcmp(pwd.pw_name, "root")); + assert(strlen(pwd.pw_passwd) <= 1000); + + s = getpwuid_r(0, &pwd, buf, bufsize, &result); + assert(!s); + assert(pwd.pw_uid == 0); + assert(!strcmp(pwd.pw_name, "root")); + assert(strlen(pwd.pw_passwd) <= 1000); + + result = getpwnam("root"); + assert(result); + assert(result->pw_uid == 0); + assert(!strcmp(result->pw_name, "root")); + assert(strlen(result->pw_passwd) <= 1000); + + result = getpwuid(0); + assert(result); + assert(result->pw_uid == 0); + assert(!strcmp(result->pw_name, "root")); + assert(strlen(result->pw_passwd) <= 1000); + + errno = 0; + setpwent(); + assert(errno == 0); + + errno = 0; + result = getpwent(); + assert(result); + + pwd = *result; + pwd.pw_name = strdup(result->pw_name); + pwd.pw_passwd = strdup(result->pw_passwd); + pwd.pw_gecos = strdup(result->pw_gecos); + pwd.pw_dir = strdup(result->pw_dir); + pwd.pw_shell = strdup(result->pw_shell); + assert(pwd.pw_name); + assert(pwd.pw_passwd); + assert(pwd.pw_gecos); + assert(pwd.pw_dir); + assert(pwd.pw_shell); + + errno = 0; + setpwent(); + assert(errno == 0); + + errno = 0; + result = getpwent(); + assert(result); + + assert(!strcmp(pwd.pw_name, result->pw_name)); + assert(!strcmp(pwd.pw_passwd, result->pw_passwd)); + assert(!strcmp(pwd.pw_gecos, result->pw_gecos)); + assert(!strcmp(pwd.pw_dir, result->pw_dir)); + assert(!strcmp(pwd.pw_shell, result->pw_shell)); + assert(pwd.pw_uid == result->pw_uid); + assert(pwd.pw_gid == result->pw_gid); + + free(pwd.pw_name); + free(pwd.pw_passwd); + free(pwd.pw_gecos); + free(pwd.pw_dir); + free(pwd.pw_shell); + + pwd.pw_name = "managarm"; + pwd.pw_passwd = "passwordhash"; + pwd.pw_uid = 1234; + pwd.pw_gid = 12345; + pwd.pw_gecos = "/etc/password test"; + pwd.pw_dir = "/home/managarm\n"; + pwd.pw_shell = "/usr/bin/bash"; + + // tmpfile() cannot be used because its unimplemented in mlibc. + char filename[] = "pwdXXXXXX"; + int tmpfd = mkstemp(filename); + assert(tmpfd); + FILE *tmp = fdopen(tmpfd, "w+"); + assert(tmp); + + assert(putpwent(NULL, tmp) < 0); + assert(putpwent(&pwd, tmp) < 0); + + pwd.pw_dir = "/home/managarm:"; + assert(putpwent(&pwd, tmp) < 0); + + pwd.pw_dir = "/home/:managarm\n"; + assert(putpwent(&pwd, tmp) < 0); + + pwd.pw_dir = "/home/managarm"; + assert(putpwent(&pwd, tmp) == 0); + rewind(tmp); + + char *expected = "managarm:passwordhash:1234:12345:/etc/password test:/home/managarm:/usr/bin/bash\n"; + size_t expectedlen = strlen(expected); + + size_t readsize = fread(buf, 1, bufsize, tmp); + assert(readsize == expectedlen); + assert(strncmp(expected, buf, expectedlen) == 0); + + fclose(tmp); + unlink(filename); + free(buf); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/readv-writev.c b/user/include/mlibc/tests/posix/readv-writev.c new file mode 100644 index 0000000..899de99 --- /dev/null +++ b/user/include/mlibc/tests/posix/readv-writev.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "readv-writev-host-libc.tmp" +#else +#define TEST_FILE "readv-writev.tmp" +#endif + +int main() { + // Make sure that it wasn't created by a previous test run + unlink(TEST_FILE); + + int fd = open(TEST_FILE, O_RDWR | O_CREAT, 0644); + assert(fd != -1); + + char str0[] = "hello "; + char str1[] = "world!"; + + struct iovec bufs[2] = { + { + .iov_base = &str0, + .iov_len = strlen(str0), + }, + { + .iov_base = &str1, + .iov_len = strlen(str1), + }, + }; + + ssize_t written = writev(fd, bufs, 2); + assert(written == 12); + + memset(&str0, 0, strlen(str0)); + memset(&str1, 0, strlen(str1)); + + assert(!lseek(fd, 0, SEEK_SET)); + + ssize_t read = readv(fd, bufs, 2); + assert(read == 12); + + assert(!strncmp(str0, "hello ", 7)); + assert(!strncmp(str1, "world!", 7)); + + assert(!close(fd)); + + unlink(TEST_FILE); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/realpath.c b/user/include/mlibc/tests/posix/realpath.c new file mode 100644 index 0000000..60eb812 --- /dev/null +++ b/user/include/mlibc/tests/posix/realpath.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_BASE "/tmp/mlibc-realpath-host-libc" +#else +#define TEST_BASE "/tmp/mlibc-realpath" +#endif + +void prepare() { + assert(!mkdir(TEST_BASE "/", S_IRWXU)); + assert(!mkdir(TEST_BASE "/dir1", S_IRWXU)); + assert(!mkdir(TEST_BASE "/dir2", S_IRWXU)); + assert(!symlink(TEST_BASE "/dir2/", TEST_BASE "/dir1/abs-link")); + assert(!symlink(TEST_BASE "/dir2///", TEST_BASE "/dir1/abs-link-trail")); + assert(!symlink(TEST_BASE "/dir2", TEST_BASE "/dir1/abs-link-no-trail")); + assert(!chdir(TEST_BASE "/dir1")); + assert(!symlink("../dir2/", TEST_BASE "/dir1/rel-link")); +} + +void cleanup(int do_assert) { + if (do_assert) { + assert(!unlink(TEST_BASE "/dir1/rel-link")); + assert(!unlink(TEST_BASE "/dir1/abs-link")); + assert(!unlink(TEST_BASE "/dir1/abs-link-trail")); + assert(!unlink(TEST_BASE "/dir1/abs-link-no-trail")); + assert(!rmdir(TEST_BASE "/dir2")); + assert(!rmdir(TEST_BASE "/dir1")); + assert(!rmdir(TEST_BASE "/")); + } else { + unlink(TEST_BASE "/dir1/rel-link"); + unlink(TEST_BASE "/dir1/abs-link"); + unlink(TEST_BASE "/dir1/abs-link-trail"); + unlink(TEST_BASE "/dir1/abs-link-no-trail"); + rmdir(TEST_BASE "/dir2"); + rmdir(TEST_BASE "/dir1"); + rmdir(TEST_BASE "/"); + } +} + +void signal_handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; + + cleanup(0); + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + + sigaction(SIGABRT, &sa, NULL); + abort(); +} + +#define TEST_PATH(rpath, expected) \ + path = realpath(rpath, NULL); \ + assert(path); \ + assert(!strcmp(path, expected)); \ + free(path); + + +int main() { + char *path; + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = signal_handler; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGABRT, &sa, NULL); + + prepare(); + + TEST_PATH(TEST_BASE "/dir1/", TEST_BASE "/dir1"); + TEST_PATH(TEST_BASE "/dir1/../dir2", TEST_BASE "/dir2"); + TEST_PATH(TEST_BASE "/dir1/abs-link/", TEST_BASE "/dir2"); + TEST_PATH(TEST_BASE "/dir1/rel-link/", TEST_BASE "/dir2"); + TEST_PATH(TEST_BASE "/dir1/abs-link/../", TEST_BASE ""); + TEST_PATH(TEST_BASE "/dir1/rel-link/../", TEST_BASE ""); + TEST_PATH(TEST_BASE "/dir1/abs-link/../dir1/abs-link/", TEST_BASE "/dir2"); + TEST_PATH(TEST_BASE "/dir1/rel-link/../dir1/rel-link/", TEST_BASE "/dir2"); + TEST_PATH(TEST_BASE "/dir1/abs-link/../dir1/rel-link/", TEST_BASE "/dir2"); + TEST_PATH(TEST_BASE "/dir1/rel-link/../dir1/abs-link/", TEST_BASE "/dir2"); + TEST_PATH(TEST_BASE "/dir1/abs-link-no-trail/", TEST_BASE "/dir2"); + TEST_PATH(TEST_BASE "/dir1/abs-link-trail/", TEST_BASE "/dir2"); + + TEST_PATH("/tmp", "/tmp"); + TEST_PATH("/", "/"); + TEST_PATH("//", "/"); + + cleanup(1); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/regex.c b/user/include/mlibc/tests/posix/regex.c new file mode 100644 index 0000000..6c2ca3f --- /dev/null +++ b/user/include/mlibc/tests/posix/regex.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +int main(void) { + char *testString = "mlibc is the best best best libc"; + char *pattern = "\\(be[a-z]t\\) \\1"; + + regex_t reg; + int rc = regcomp(®, pattern, 0); + assert(!rc); + + regmatch_t matches[2]; + rc = regexec(®, testString, 2, matches, 0); + assert(!rc); + + printf("Whole pattern: \"%.*s\" at %zd-%zd.\n", + (int)(matches[0].rm_eo - matches[0].rm_so), &testString[matches[0].rm_so], + (ssize_t)matches[0].rm_so, (ssize_t)(matches[0].rm_eo - 1)); + assert(matches[0].rm_so == 13 && matches[0].rm_eo == 22); + + printf("Substring: \"%.*s\" at %zd-%zd.\n", + (int)(matches[1].rm_eo - matches[1].rm_so), &testString[matches[1].rm_so], + (ssize_t)matches[1].rm_so, (ssize_t)matches[1].rm_eo - 1); + assert(matches[1].rm_so == 13 && matches[1].rm_eo == 17); + + regfree(®); + return 0; +} diff --git a/user/include/mlibc/tests/posix/rindex.c b/user/include/mlibc/tests/posix/rindex.c new file mode 100644 index 0000000..0eb2f54 --- /dev/null +++ b/user/include/mlibc/tests/posix/rindex.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + pch = rindex(str, 's'); + // The last occurence of 's' is at position 18 + assert(pch - str + 1 == 18); + return 0; +} diff --git a/user/include/mlibc/tests/posix/rlimits.c b/user/include/mlibc/tests/posix/rlimits.c new file mode 100644 index 0000000..3565521 --- /dev/null +++ b/user/include/mlibc/tests/posix/rlimits.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +int main() { + struct rlimit getlim, setlim; + + setlim.rlim_cur = 16; + setlim.rlim_max = 4096; + + int ret = setrlimit(RLIMIT_NOFILE, &setlim); + + if(ret == -1) { + fprintf(stderr, "%s\n", strerror(errno)); + assert(!ret); + } + + assert(!getrlimit(RLIMIT_NOFILE, &getlim)); + + assert(setlim.rlim_cur == getlim.rlim_cur); + assert(setlim.rlim_max == getlim.rlim_max); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/search.c b/user/include/mlibc/tests/posix/search.c new file mode 100644 index 0000000..c75cfc5 --- /dev/null +++ b/user/include/mlibc/tests/posix/search.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include + +static int compare(const void *pa, const void *pb) { + if (*(int*)pa < *(int*) pb) + return -1; + if (*(int*)pa > *(int*) pb) + return 1; + return 0; +} + +static void check_key(int key, void *root) { + int keyp = key; + void *ret = tfind((void*) &keyp, &root, compare); + assert(ret); + assert(**((int **) ret) == key); +} + +static int freed = 0; + +static void free_key(void *key) { + freed++; + free(key); +} + +int main() { + void *root = NULL; + for (int i = 0; i < 12; i++) { + int *ptr = malloc(sizeof(int)); + assert(ptr); + *ptr = i; + + void *ret = tsearch((void*) ptr, &root, compare); + assert(ret); + assert(**((int **) ret) == i); + } + + // Test a couple of keys + check_key(1, root); + check_key(5, root); + check_key(10, root); + + // Verify NULL on non-existent key + int key = -1; + void *ret = tfind((void*) &key, &root, compare); + assert(ret == NULL); + + tdestroy(root, free_key); + assert(freed == 12); + + assert(hcreate(3)); + + // Search for a non-existent entry + ENTRY entry = { + .key = (char *)"foo", + .data = (void *)0x12345678 + }; + ENTRY *result = hsearch(entry, FIND); + assert(!result); + assert(errno == ESRCH); + + // Add a couple keys + assert(hsearch(entry, ENTER)); + entry.key = (char *)"bar"; + entry.data = (void *)0x87654321; + assert(hsearch(entry, ENTER)); + entry.key = (char *)"baz"; + entry.data = (void *)0x12344321; + assert(hsearch(entry, ENTER)); + + // Make sure that we can't add more keys + entry.key = (char *)"not existing"; + assert(!hsearch(entry, ENTER)); + assert(errno == ENOMEM); + + // Check that the entries are in the hash table + entry.key = (char *)"baz"; + result = hsearch(entry, FIND); + assert(result); + assert(result->data == (void *)0x12344321); + entry.key = (char *)"foo"; + result = hsearch(entry, FIND); + assert(result); + assert(result->data == (void *)0x12345678); + entry.key = (char *)"bar"; + result = hsearch(entry, FIND); + assert(result); + assert(result->data == (void *)0x87654321); + + hdestroy(); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/semaphore.c b/user/include/mlibc/tests/posix/semaphore.c new file mode 100644 index 0000000..f8ecf7d --- /dev/null +++ b/user/include/mlibc/tests/posix/semaphore.c @@ -0,0 +1,28 @@ +#include +#include +#include + +int main() { + sem_t sem; + assert(sem_init(&sem, 0, 1) == 0); + assert(sem_destroy(&sem) == 0); + assert(sem_init(&sem, 0, -1) == -1); + assert(errno == EINVAL); + + assert(sem_init(&sem, 0, 3) == 0); + assert(sem_trywait(&sem) == 0); + assert(sem_trywait(&sem) == 0); + assert(sem_trywait(&sem) == 0); + assert(sem_trywait(&sem) == -1); + assert(errno == EAGAIN); + assert(sem_destroy(&sem) == 0); + + sem_init(&sem, 0, 1); + assert(sem_wait(&sem) == 0); + assert(sem_trywait(&sem) == -1); + assert(sem_post(&sem) == 0); + assert(sem_wait(&sem) == 0); + assert(sem_destroy(&sem) == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/setpriority.c b/user/include/mlibc/tests/posix/setpriority.c new file mode 100644 index 0000000..d674e57 --- /dev/null +++ b/user/include/mlibc/tests/posix/setpriority.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + errno = 0; + int original_priority = getpriority(PRIO_PROCESS, getpid()); + + assert(original_priority != -1 || !errno); + + int ret = setpriority(PRIO_PROCESS, getpid(), original_priority + 1); + + if(ret) { + fprintf(stderr, "%s", strerror(errno)); + exit(1); + } + + errno = 0; + int new_priority = getpriority(PRIO_PROCESS, getpid()); + + assert(new_priority != -1 || !errno); + assert(new_priority == original_priority + 1); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/shm.c b/user/include/mlibc/tests/posix/shm.c new file mode 100644 index 0000000..3d18740 --- /dev/null +++ b/user/include/mlibc/tests/posix/shm.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(void) { + size_t page_size = getpagesize(); + + srand(time(NULL)); + + int shmid = -1; + for (int i = 0; i < 10; i++) { + shmid = shmget((key_t)rand(), page_size, 0644 | IPC_CREAT | IPC_EXCL); + if (shmid != -1) { + break; + } + } + assert(shmid != -1); + + struct shmid_ds buf; + assert(shmctl(shmid, IPC_STAT, &buf) >= 0); + assert((size_t)buf.shm_segsz == page_size); + assert(buf.shm_cpid == getpid()); + + void *attach_addr = shmat(shmid, NULL, SHM_RDONLY); + assert(attach_addr != NULL); + + assert(shmctl(shmid, IPC_RMID, &buf) >= 0); + assert(shmdt(attach_addr) == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/sigaltstack.c b/user/include/mlibc/tests/posix/sigaltstack.c new file mode 100644 index 0000000..a3636a0 --- /dev/null +++ b/user/include/mlibc/tests/posix/sigaltstack.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include + +static jmp_buf env; +static char *sigStack; + +static void sig_handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; + + longjmp(env, 1); +} + +int main() { + if (setjmp(env)) { + free(sigStack); + return 0; + } + + sigStack = malloc(SIGSTKSZ); + + stack_t ss; + ss.ss_sp = sigStack; + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; + + assert(!sigaltstack(&ss, NULL)); + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sa.sa_sigaction = sig_handler; + + assert(!sigaction(SIGSEGV, &sa, NULL)); + + // This is used to trash the stack to ensure sigaltstack actually switched stacks. +#if defined(__x86_64__) + asm volatile ("mov $0, %rsp\n" + "\t" "push $0"); +#elif defined(__i386__) + asm volatile ("mov $0, %esp\n" + "\t" "push $0"); +#elif defined(__aarch64__) + asm volatile ("mov sp, %0\n" + "\t" "stp x0, x1, [sp, #-16]!" :: "r"((uint64_t)0)); +#elif defined(__riscv) && __riscv_xlen == 64 + asm volatile ("li sp, 0\n" + "\t" "sd zero, 0(sp)"); +#elif defined (__m68k__) + asm volatile ("move.l #0, %sp\n" + "\t" "move.l #0, -(%sp)"); +#elif defined(__loongarch64) + asm volatile ("addi.d $sp, $r0, 0\n" + "\t" "st.d $r0, $sp, 0"); +#else +# error Unknown architecture +#endif + + return 0; +} diff --git a/user/include/mlibc/tests/posix/sigsuspend.c b/user/include/mlibc/tests/posix/sigsuspend.c new file mode 100644 index 0000000..09b9a1e --- /dev/null +++ b/user/include/mlibc/tests/posix/sigsuspend.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include + +_Atomic int handler_ready = 0; +_Atomic int thread_signal_ran = 0; + +static void sig_handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; + + thread_signal_ran = 1; +} + +static void *worker(void *arg) { + (void)arg; + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = sig_handler; + sa.sa_flags = SA_SIGINFO; + assert(!sigaction(SIGUSR1, &sa, NULL)); + + handler_ready = 1; + + sigset_t set; + sigfillset(&set); + sigdelset(&set, SIGUSR1); + + assert(sigsuspend(&set)); + assert(thread_signal_ran); + assert(errno == EINTR); + + return NULL; +} + +int main() { + pthread_t thread; + assert(!pthread_create(&thread, NULL, &worker, NULL)); + + while (!handler_ready) + ; + + sleep(1); + + assert(!pthread_kill(thread, SIGUSR1)); + assert(!pthread_join(thread, NULL)); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/sigtimedwait.c b/user/include/mlibc/tests/posix/sigtimedwait.c new file mode 100644 index 0000000..697f63c --- /dev/null +++ b/user/include/mlibc/tests/posix/sigtimedwait.c @@ -0,0 +1,93 @@ +#include + +#include +#include +#include +#include +#include + +pid_t parent; +pid_t child; + +int fds[2]; + +void parent_fn() { + int res; + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR2); + sigprocmask(SIG_BLOCK, &set, NULL); + + res = write(fds[1], "!", 1); + assert(res == 1); + + siginfo_t info; + res = sigwaitinfo(&set, &info); + assert(res == SIGUSR2); + assert(info.si_signo == SIGUSR2); + + res = write(fds[1], "!", 1); + assert(res == 1); + + // XXX: This may not be long enough to get scheduled + struct timespec tout = {1, 0}; + res = sigtimedwait(&set, &info, &tout); + assert(res == SIGUSR2); + assert(info.si_signo == SIGUSR2); + + res = write(fds[1], "!", 1); + assert(res == 1); + + int sig; + res = sigwait(&set, &sig); + assert(res == 0); + assert(sig == SIGUSR2); + + res = write(fds[1], "!", 1); + assert(res == 1); + + res = sigtimedwait(&set, &info, &tout); + assert(res < 0); + assert(errno == EAGAIN); + + int wsts; + res = waitpid(child, &wsts, 0); + assert(res >= 0); +} + +void child_fn() { + int res; + char c; + + res = read(fds[0], &c, 1); + assert(res == 1); + kill(parent, SIGUSR2); + res = read(fds[0], &c, 1); + assert(res == 1); + kill(parent, SIGUSR2); + res = read(fds[0], &c, 1); + assert(res == 1); + kill(parent, SIGUSR2); + res = read(fds[0], &c, 1); + assert(res == 1); +} + +int main() { + int res; + + parent = getpid(); + assert(parent > 0); + + res = pipe(fds); + assert(res == 0); + + child = fork(); + assert(child >= 0); + if (child) + parent_fn(); + else + child_fn(); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/strdupa.c b/user/include/mlibc/tests/posix/strdupa.c new file mode 100644 index 0000000..465933a --- /dev/null +++ b/user/include/mlibc/tests/posix/strdupa.c @@ -0,0 +1,16 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include + +int main() { + char test[19] = "Hello mlibc World!"; + char *alloca_ed = strdupa(test); + assert(!strcmp(test, alloca_ed)); + + char *trimmed = strndupa(test, 5); + assert(!strcmp("Hello", trimmed)); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/string.c b/user/include/mlibc/tests/posix/string.c new file mode 100644 index 0000000..9c6e036 --- /dev/null +++ b/user/include/mlibc/tests/posix/string.c @@ -0,0 +1,29 @@ +#include +#include + +int main() { + char buf[4]; + + // stpncpy + assert(stpncpy(buf, "", 4) == buf); + assert(!strcmp(buf, "")); + + assert(stpncpy(buf, "123", 4) == buf + 3); + assert(!strcmp(buf, "123")); + + assert(stpncpy(buf, "12", 4) == buf + 2); + assert(buf[0] == '1' && buf[1] == '2' && buf[2] == '\0' && buf[3] == '\0'); + + assert(stpncpy(buf, "123456", 4) == buf + 4); + assert(buf[0] == '1' && buf[1] == '2' && buf[2] == '3' && buf[3] == '4'); + + // stpcpy + assert(stpcpy(buf, "") == buf); + assert(!strcmp(buf, "")); + + assert(stpcpy(buf, "12") == buf + 2); + assert(!strcmp(buf, "12")); + + assert(stpcpy(buf, "123") == buf + 3); + assert(!strcmp(buf, "123")); +} diff --git a/user/include/mlibc/tests/posix/swab.c b/user/include/mlibc/tests/posix/swab.c new file mode 100644 index 0000000..6c89781 --- /dev/null +++ b/user/include/mlibc/tests/posix/swab.c @@ -0,0 +1,66 @@ +#include +#include +#include + +void test_swab_even_bytes() { + uint8_t input[] = {0x01, 0x02, 0x03, 0x04}; + uint8_t output[4]; + + swab(input, output, sizeof(input)); + + assert(output[0] == 0x02); + assert(output[1] == 0x01); + assert(output[2] == 0x04); + assert(output[3] == 0x03); +} + +void test_swab_odd_bytes() { + uint8_t input[] = {0x01, 0x02, 0x03, 0x04, 0x05}; + uint8_t output[5] = {0, 0, 0, 0, 0}; + + swab(input, output, sizeof(input)); + + assert(output[0] == 0x02); + assert(output[1] == 0x01); + assert(output[2] == 0x04); + assert(output[3] == 0x03); + + // Last byte is UB, assume unchanged? + assert(output[4] == 0); +} + +void test_swab_negative_bytes() { + uint8_t input[] = {0x01, 0x02, 0x03, 0x04}; + uint8_t output[4] = {0, 0, 0, 0}; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" + swab(input, output, -1); // Should change nothing +#pragma GCC diagnostic pop + + assert(output[0] == 0); + assert(output[1] == 0); + assert(output[2] == 0); + assert(output[3] == 0); +} + +void test_swab_zero_bytes() { + uint8_t input[] = {0x01, 0x02, 0x03, 0x04}; + uint8_t output[4] = {0, 0, 0, 0}; + + swab(input, output, 0); // Should change nothing + + assert(output[0] == 0); + assert(output[1] == 0); + assert(output[2] == 0); + assert(output[3] == 0); +} + +int main() { + test_swab_even_bytes(); + test_swab_odd_bytes(); + test_swab_negative_bytes(); + test_swab_zero_bytes(); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/system.c b/user/include/mlibc/tests/posix/system.c new file mode 100644 index 0000000..df63a97 --- /dev/null +++ b/user/include/mlibc/tests/posix/system.c @@ -0,0 +1,20 @@ +#include +#include +#include + +int main() { + int res; + + res = system("true"); + assert(WIFEXITED(res)); + assert(WEXITSTATUS(res) == 0); + + res = system("false"); + assert(WIFEXITED(res)); + assert(WEXITSTATUS(res) == 1); + + res = system(NULL); + assert(res == 1); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/time.c b/user/include/mlibc/tests/posix/time.c new file mode 100644 index 0000000..ae3516d --- /dev/null +++ b/user/include/mlibc/tests/posix/time.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE 1024 + +int main() { + struct tm tm = {0}; + char buf[BUF_SIZE]; + + char *a = strptime("%", "%%", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(strftime(buf, BUF_SIZE, "%%", &tm) == 1); + assert(!strcmp(buf, "%")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("1991-11-21", "%F", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_mday == 21); + assert(tm.tm_mon == 10); + assert(tm.tm_wday == 4); + assert(tm.tm_yday == 324); + assert(strftime(buf, BUF_SIZE, "%F", &tm) == 10); + assert(!strcmp(buf, "1991-11-21")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("10/19/91", "%D", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_mday == 19); + assert(tm.tm_mon == 9); + assert(tm.tm_year == 91); + assert(tm.tm_wday == 6); + assert(tm.tm_yday == 291); + assert(strftime(buf, BUF_SIZE, "%D", &tm) == 8); + assert(!strcmp(buf, "10/19/91")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("15:23", "%R", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_min == 23); + assert(tm.tm_hour == 15); + assert(strftime(buf, BUF_SIZE, "%R", &tm) == 5); + assert(!strcmp(buf, "15:23")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("17:12:56", "%T", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_sec == 56); + assert(tm.tm_min == 12); + assert(tm.tm_hour == 17); + assert(strftime(buf, BUF_SIZE, "%T", &tm) == 8); + assert(!strcmp(buf, "17:12:56")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("10", "%m", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_yday == 272); + assert(strftime(buf, BUF_SIZE, "%m", &tm) == 2); + assert(!strcmp(buf, "10")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("14 83", "%C %y", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_year == -417); + assert(strftime(buf, BUF_SIZE, "%C %y", &tm) == 5); + assert(!strcmp(buf, "14 83")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("32 16", "%y %C", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_year == -268); + assert(tm.tm_wday == 3); + assert(strftime(buf, BUF_SIZE, "%y %C", &tm) == 5); + assert(!strcmp(buf, "32 16")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("12", "%C", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_year == -700); + assert(tm.tm_wday == 5); + assert(strftime(buf, BUF_SIZE, "%C", &tm) == 2); + assert(!strcmp(buf, "12")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("1683-9-23", "%F", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_mday == 23); + assert(tm.tm_mon == 8); + assert(tm.tm_year == -217); + assert(tm.tm_wday == 4); + assert(tm.tm_yday == 265); + assert(strftime(buf, BUF_SIZE, "%F", &tm) == 10); + assert(!strcmp(buf, "1683-09-23")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("14 53", "%H%t%S", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_sec == 53); + assert(tm.tm_hour == 14); + assert(strftime(buf, BUF_SIZE, "%H%t%S", &tm) == 5); + assert(!strcmp(buf, "14 53")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("24", "%H", &tm); + assert(a == NULL); + memset(&tm, 0, sizeof(tm)); + + a = strptime("0", "%I", &tm); + assert(a == NULL); + memset(&tm, 0, sizeof(tm)); + + setlocale(LC_TIME, "en_US.UTF-8"); + a = strptime("10 21 PM", "%I %M %p", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_hour == 22); + assert(tm.tm_min == 21); + assert(strftime(buf, BUF_SIZE, "%I %M %p", &tm) == 8); + assert(!strcmp(buf, "10 21 PM")); + memset(&tm, 0, sizeof(tm)); + + tm.tm_min = 23; + assert(strftime(buf, BUF_SIZE, "%I %M", &tm) == 5); + assert(!strcmp(buf, "12 23")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("January", "%h", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_mon == 0); + assert(strftime(buf, BUF_SIZE, "%h %b", &tm) == 7); + assert(!strcmp(buf, "Jan Jan")); + assert(strftime(buf, BUF_SIZE, "%B", &tm) == 7); + assert(!strcmp(buf, "January")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("2", "%j", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_yday == 1); + assert(strftime(buf, BUF_SIZE, "%j", &tm) == 3); + assert(!strcmp(buf, "002")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("Wednesday", "%A", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_wday == 3); + assert(strftime(buf, BUF_SIZE, "%A", &tm) == 9); + assert(!strcmp(buf, "Wednesday")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("11:51:13 PM", "%r", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_hour == 23); + assert(tm.tm_min == 51); + assert(tm.tm_sec == 13); + assert(strftime(buf, BUF_SIZE, "%r", &tm) == 11); + assert(!strcmp(buf, "11:51:13 PM")); + memset(&tm, 0, sizeof(tm)); + + tm.tm_hour = 0; + tm.tm_min = 51; + tm.tm_sec = 13; + assert(strftime(buf, BUF_SIZE, "%r", &tm) == 11); + assert(!strcmp(buf, "12:51:13 AM")); + memset(&tm, 0, sizeof(tm)); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(strftime(buf, BUF_SIZE, "%", &tm) == 1); + fprintf(stderr, "%s\n", buf); + assert(!strcmp(buf, "%")); + memset(&tm, 0, sizeof(tm)); +#pragma GCC diagnostic pop + + return 0; +} diff --git a/user/include/mlibc/tests/posix/timer.c b/user/include/mlibc/tests/posix/timer.c new file mode 100644 index 0000000..f39e928 --- /dev/null +++ b/user/include/mlibc/tests/posix/timer.c @@ -0,0 +1,25 @@ +#include +#include +#include + +int main() { + struct timeval a = {0, 0}; + struct timeval b = {0, 0}; + struct timeval res = {0, 0}; + a.tv_sec = 10; + assert(timerisset(&a) == 1); + timerclear(&a); + assert(timerisset(&a) == 0); + a.tv_sec = 40; + a.tv_usec = 500; + b.tv_sec = 10; + b.tv_usec = 20; + timeradd(&a, &b, &res); + assert(res.tv_sec == 50); + assert(res.tv_usec == 520); + timerclear(&res); + timersub(&a, &b, &res); + assert(res.tv_sec == 30); + assert(res.tv_usec == 480); + return 0; +} diff --git a/user/include/mlibc/tests/posix/usershell.c b/user/include/mlibc/tests/posix/usershell.c new file mode 100644 index 0000000..94c0b78 --- /dev/null +++ b/user/include/mlibc/tests/posix/usershell.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include + +static void testfor(const char *expected, char *shell, int *count) { + if (strcmp(shell, expected) == 0) + *count += 1; +} + +#define BUFFER_SIZE (1024 * 512) + +int main(void) { + setusershell(); + + FILE *f = fopen("/etc/shells", "r"); + if (f == NULL) { + /* /etc/shells file is unreadable, test for the existance of /bin/sh and /bin/csh */ + char *shell = getusershell(); + int csh = 0; + int sh = 0; + + testfor("/bin/sh", shell, &sh); + testfor("/bin/csh", shell, &csh); + + shell = getusershell(); + assert(shell); + + testfor("/bin/sh", shell, &sh); + testfor("/bin/csh", shell, &csh); + + assert(sh == 1 && csh == 1); + assert(getusershell() == NULL); + } else { + /* /etc/shells is there, read the whole file into a buffer and change all '\n's to '\0'. */ + char buffer[BUFFER_SIZE + 1]; + int nbytes = fread(buffer, 1, BUFFER_SIZE, f); + buffer[nbytes] = '\0'; + + for (int i = 0; i < nbytes; ++i) { + if (buffer[i] == '\n') + buffer[i] = '\0'; + } + + /* loop through each shell and make sure the result is right */ + char *shell = buffer; + while (shell < &buffer[nbytes]) { + char *usershell = getusershell(); + while (usershell && *usershell == '#') + usershell = getusershell(); + + while (*shell == '#') + shell += strlen(shell) + 1; + + assert(strcmp(shell, usershell) == 0); + shell += strlen(shell) + 1; + } + } + + endusershell(); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/vfork.c b/user/include/mlibc/tests/posix/vfork.c new file mode 100644 index 0000000..9ec0914 --- /dev/null +++ b/user/include/mlibc/tests/posix/vfork.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include + +void prevent_atforks(void){ + exit(1); +} + +int main() { + pid_t pid; + int status; + assert(!pthread_atfork(prevent_atforks, NULL, NULL)); + + switch (pid = vfork()) { + case -1: + perror("vfork"); + abort(); + case 0: + _exit(12); + default: break; + } + + assert(wait(&status) == pid); + assert(WIFEXITED(status) && WEXITSTATUS(status) == 12); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/waitid.c b/user/include/mlibc/tests/posix/waitid.c new file mode 100644 index 0000000..9d53c40 --- /dev/null +++ b/user/include/mlibc/tests/posix/waitid.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +siginfo_t si; + +int main() { + int pid = fork(); + + if(!pid) + exit(69); + + int ret = waitid(P_ALL, 0, &si, WEXITED); + assert(ret == 0); + assert(si.si_pid == pid); + assert(si.si_signo == SIGCHLD); + assert(si.si_code == CLD_EXITED); + + return 0; +} diff --git a/user/include/mlibc/tests/posix/wcwidth.c b/user/include/mlibc/tests/posix/wcwidth.c new file mode 100644 index 0000000..2e6fc8c --- /dev/null +++ b/user/include/mlibc/tests/posix/wcwidth.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include + +#if UINTPTR_MAX == UINT64_MAX +#define WCHAR_SPEC "" +#else +#define WCHAR_SPEC "l" +#endif + +/* + * The code in this test is taken from https://github.com/termux/wcwidth/, + * under the following license: + * + * Copyright (C) Fredrik Fornwall 2016. + * Distributed under the MIT License. + * + * Implementation of wcwidth(3) as a C port of: + * https://github.com/jquast/wcwidth + * + * Report issues at: + * https://github.com/termux/wcwidth + */ + +static int tests_run; +static int test_failures; + +void assertWidthIs(int expected_width, wchar_t c) { + tests_run++; + int actual_width = wcwidth(c); + if (actual_width != expected_width) { + fprintf(stderr, "ERROR: wcwidth(U+%04" WCHAR_SPEC "x, '%lc') returned %d, expected %d\n", c, (wint_t) c, actual_width, expected_width); + test_failures++; + } +} + +int main() { + setlocale(LC_CTYPE, "C.UTF-8"); + assertWidthIs(1, 'a'); + assertWidthIs(1, L'ö'); + + // Some wide: + assertWidthIs(2, L'A'); + assertWidthIs(2, L'B'); + assertWidthIs(2, L'C'); + assertWidthIs(2, L'中'); + assertWidthIs(2, L'文'); + assertWidthIs(2, 0x679C); + assertWidthIs(2, 0x679D); + assertWidthIs(2, 0x2070E); + assertWidthIs(2, 0x20731); + +#ifndef USE_HOST_LIBC + assertWidthIs(1, 0x11A3); +#endif + + assertWidthIs(2, 0x1F428); // Koala emoji. + assertWidthIs(2, 0x231a); // Watch emoji. + + if (test_failures > 0) printf("%d tests FAILED, ", test_failures); + printf("%d tests OK\n", tests_run - test_failures); + return (test_failures == 0) ? 0 : 1; +} diff --git a/user/include/mlibc/tests/posix/wordexp.c b/user/include/mlibc/tests/posix/wordexp.c new file mode 100644 index 0000000..063a374 --- /dev/null +++ b/user/include/mlibc/tests/posix/wordexp.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *wordexp_return_stringify(int val, int *should_free); + +struct we_test { + int expected_return; + const char *words; + int flags; + const char *wordv[16]; + size_t wordc; +} test_cases[] = { + /* (unbalanced) pairs */ + {WRDE_SYNTAX, "\\", 0, {NULL}, 0}, + {WRDE_SYNTAX, "\'", 0, {NULL}, 0}, + {0, "\'\'", 0, {""}, 1}, + {0, "\'\"\'", 0, {"\""}, 1}, + {WRDE_SYNTAX, "\"\'", 0, {NULL}, 0}, + + /* numbers & calculations */ + {0, "$((5+5))", 0, {"10"}, 1}, + {0, "$((-5+5))", 0, {"0"}, 1}, + {0, "$((010))", 0, {"8"}, 1}, + {0, "$((0x10))", 0, {"16"}, 1}, + + /* errant symbols */ + {WRDE_BADCHAR, "(string", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string)", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "{string", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string}", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string|", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string;", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string&", WRDE_NOCMD, {NULL}, 0}, + + /* command substitution with WRDE_NOCMD */ + {WRDE_CMDSUB, "$(pwd)", WRDE_NOCMD, {NULL}, 0}, + + /* env vars */ + {WRDE_BADVAL, "$DOES_NOT_EXIST", WRDE_UNDEF, {NULL}, 0}, + + /* normal arguments */ + {0, "arg1 arg2", 0, {"arg1", "arg2"}, 2}, + {-1, NULL, 0, {NULL}, 0}, +}; + +int main() { + wordexp_t we; + + wordexp("$(pwd)", &we, 0); + char *cwd = getcwd(NULL, 0); + assert(!strcmp(cwd, we.we_wordv[0])); + wordfree(&we); + free(cwd); + + char *home; + assert(asprintf(&home, "%s/.config", getenv("HOME")) != -1); + wordexp("$HOME ~ ~/.config", &we, WRDE_REUSE); + assert(!strcmp(getenv("HOME"), we.we_wordv[0])); + assert(!strcmp(getenv("HOME"), we.we_wordv[1])); + assert(!strcmp(home, we.we_wordv[2])); + free(home); + wordfree(&we); + + struct passwd *pw = getpwnam("root"); + assert(asprintf(&home, "%s/.config", pw->pw_dir) != -1); + wordexp("~root ~root/.config", &we, WRDE_REUSE); + assert(!strcmp(pw->pw_dir, we.we_wordv[0])); + assert(!strcmp(home, we.we_wordv[1])); + free(home); + wordfree(&we); + + size_t i = 0; + + for(struct we_test *test = &test_cases[i]; test->expected_return != -1; test = &test_cases[++i]) { + wordexp_t test_we; + + int should_free; + const char *expected = wordexp_return_stringify(test->expected_return, &should_free); + fprintf(stderr, "TESTCASE %zu: '%s' with flags %d expected to return %s\n", i, test->words, test->flags, expected); + int test_ret = wordexp(test->words, &test_we, test->flags); + + if(test_ret != test->expected_return) { + fprintf(stderr, "\twordexp() returned %s, but we expect %s\n", wordexp_return_stringify(test_ret, &should_free), wordexp_return_stringify(test->expected_return, &should_free)); + } + + assert(test_ret == test->expected_return); + + if(test_ret != 0) + continue; + + assert(test_we.we_wordc == test->wordc); + + for(size_t j = 0; j < 16 && j < test->wordc; j++) { + assert(test->wordv[j] && test_we.we_wordv[j]); + assert(!strcmp(test->wordv[j], test_we.we_wordv[j])); + } + + wordfree(&test_we); + if (should_free) + free((void *)expected); + } + + exit(EXIT_SUCCESS); +} + +struct wordexp_return_val { + int val; + const char *string; +} wordexp_return_vals[] = { + {0, "WRDE_SUCCESS"}, + {WRDE_BADCHAR, "WRDE_BADCHAR"}, + {WRDE_BADVAL, "WRDE_BADVAL"}, + {WRDE_CMDSUB, "WRDE_CMDSUB"}, + {WRDE_SYNTAX, "WRDE_SYNTAX"}, + {-1, NULL}, +}; + +static const char *wordexp_return_stringify(int val, int *should_free) { + for(size_t i = 0; wordexp_return_vals[i].val != -1 || wordexp_return_vals[i].string; i++) { + if(wordexp_return_vals[i].val == val) { + *should_free = 0; + return wordexp_return_vals[i].string; + } + } + + char *unknown; + assert(asprintf(&unknown, "unknown return value %d", val) != -1); + *should_free = 1; + + return unknown; +} diff --git a/user/include/mlibc/tests/rtld/destroy1/meson.build b/user/include/mlibc/tests/rtld/destroy1/meson.build new file mode 100644 index 0000000..0e7d79e --- /dev/null +++ b/user/include/mlibc/tests/rtld/destroy1/meson.build @@ -0,0 +1 @@ +# only the test executable is required diff --git a/user/include/mlibc/tests/rtld/destroy1/test.c b/user/include/mlibc/tests/rtld/destroy1/test.c new file mode 100644 index 0000000..62da031 --- /dev/null +++ b/user/include/mlibc/tests/rtld/destroy1/test.c @@ -0,0 +1,9 @@ +#include + +__attribute__((destructor)) void destroy() { + _exit(0); +} + +int main() { + return 1; +} diff --git a/user/include/mlibc/tests/rtld/destroy2/meson.build b/user/include/mlibc/tests/rtld/destroy2/meson.build new file mode 100644 index 0000000..0e7d79e --- /dev/null +++ b/user/include/mlibc/tests/rtld/destroy2/meson.build @@ -0,0 +1 @@ +# only the test executable is required diff --git a/user/include/mlibc/tests/rtld/destroy2/test.c b/user/include/mlibc/tests/rtld/destroy2/test.c new file mode 100644 index 0000000..53e5178 --- /dev/null +++ b/user/include/mlibc/tests/rtld/destroy2/test.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +// Make sure files are flushed on process exit. + +int main() { + int pipefd[2]; + if (pipe(pipefd) < 0) { + perror("pipe"); + return -1; + } + + pid_t child = fork(); + if (child < 0) { + perror("fork"); + return -1; + } + + // This should sit in libc's buffer and be flushed on exit. + const char *message = "hello world"; + + if (child == 0) { + // Child + dup2(pipefd[1], STDOUT_FILENO); + printf("%s", message); + return 0; + } + + // Parent + wait(NULL); + + char buffer[64]; + ssize_t len = read(pipefd[0], buffer, sizeof(buffer)); + assert(len > 0); + buffer[len] = 0; + + return strcmp(buffer, message) != 0; +} + diff --git a/user/include/mlibc/tests/rtld/dl_iterate_phdr/libbar.c b/user/include/mlibc/tests/rtld/dl_iterate_phdr/libbar.c new file mode 100644 index 0000000..41ccc56 --- /dev/null +++ b/user/include/mlibc/tests/rtld/dl_iterate_phdr/libbar.c @@ -0,0 +1,3 @@ +// Bar needs to have a relocation against foo in order to set DT_NEEDED. +int foo(void); +int bar() { return foo(); } diff --git a/user/include/mlibc/tests/rtld/dl_iterate_phdr/libfoo.c b/user/include/mlibc/tests/rtld/dl_iterate_phdr/libfoo.c new file mode 100644 index 0000000..9fe07f8 --- /dev/null +++ b/user/include/mlibc/tests/rtld/dl_iterate_phdr/libfoo.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/user/include/mlibc/tests/rtld/dl_iterate_phdr/meson.build b/user/include/mlibc/tests/rtld/dl_iterate_phdr/meson.build new file mode 100644 index 0000000..acb679e --- /dev/null +++ b/user/include/mlibc/tests/rtld/dl_iterate_phdr/meson.build @@ -0,0 +1,7 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +test_depends = [libfoo, libbar] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +test_native_depends = [libfoo_native, libbar_native] diff --git a/user/include/mlibc/tests/rtld/dl_iterate_phdr/test.c b/user/include/mlibc/tests/rtld/dl_iterate_phdr/test.c new file mode 100644 index 0000000..5d48a41 --- /dev/null +++ b/user/include/mlibc/tests/rtld/dl_iterate_phdr/test.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LDSO_PATTERN "ld-linux-" +#define LIBFOO "libnative-foo.so" +#define LIBBAR "libnative-bar.so" +#else +#define LDSO_PATTERN "ld.so" +#define LIBFOO "libfoo.so" +#define LIBBAR "libbar.so" +#endif + +struct result { + int found_ldso; + int found_self; + int found_foo; + int found_bar; +}; + +static int ends_with(const char *suffix, const char *s) { + size_t suffix_len = strlen(suffix); + size_t s_len = strlen(s); + if (s_len < suffix_len) + return 0; + else { + return !strcmp(suffix, s + s_len - suffix_len); + } +} + +static int contains(const char *pattern, const char *s) { + return !!strstr(s, pattern); +} + +static int callback(struct dl_phdr_info *info, size_t size, void *data) { + assert(size == sizeof(struct dl_phdr_info)); + struct result *found = (struct result *) data; + + printf("%s\n", info->dlpi_name); + fflush(stdout); + + if (ends_with("foo.so", info->dlpi_name)) + found->found_foo++; + if (ends_with("bar.so", info->dlpi_name)) + found->found_bar++; + if (contains(LDSO_PATTERN, info->dlpi_name)) + found->found_ldso++; + + if (!strcmp("", info->dlpi_name)) + found->found_self++; + + assert(info->dlpi_phdr); + return 0; +} + +int main() { + struct result found = { 0 }; + assert(!dl_iterate_phdr(callback, &found)); + assert(found.found_ldso == 1); + assert(found.found_self == 1); + assert(found.found_foo == 0); + assert(found.found_bar == 0); + printf("---\n"); + + memset(&found, 0, sizeof(found)); + void *bar = dlopen(LIBBAR, RTLD_LOCAL | RTLD_NOW); + assert(bar); + assert(!dl_iterate_phdr(callback, &found)); + assert(found.found_ldso == 1); + assert(found.found_self == 1); + assert(found.found_bar == 1); + assert(found.found_foo == 1); // Since bar depends on foo. + printf("---\n"); + + memset(&found, 0, sizeof(found)); + void *foo = dlopen(LIBFOO, RTLD_GLOBAL | RTLD_NOW); + assert(foo); + assert(!dl_iterate_phdr(callback, &found)); + assert(found.found_ldso == 1); + assert(found.found_self == 1); + assert(found.found_foo == 1); + assert(found.found_bar == 1); + printf("---\n"); + + dlclose(bar); + dlclose(foo); + return 0; +} diff --git a/user/include/mlibc/tests/rtld/dladdr_local/libfoo.c b/user/include/mlibc/tests/rtld/dladdr_local/libfoo.c new file mode 100644 index 0000000..2903a3d --- /dev/null +++ b/user/include/mlibc/tests/rtld/dladdr_local/libfoo.c @@ -0,0 +1 @@ +char foo_global[] = ""; diff --git a/user/include/mlibc/tests/rtld/dladdr_local/meson.build b/user/include/mlibc/tests/rtld/dladdr_local/meson.build new file mode 100644 index 0000000..4ae6bb3 --- /dev/null +++ b/user/include/mlibc/tests/rtld/dladdr_local/meson.build @@ -0,0 +1,5 @@ +libfoo = shared_library('foo', 'libfoo.c') +test_depends = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +test_native_depends = [libfoo_native] diff --git a/user/include/mlibc/tests/rtld/dladdr_local/test.c b/user/include/mlibc/tests/rtld/dladdr_local/test.c new file mode 100644 index 0000000..9952e09 --- /dev/null +++ b/user/include/mlibc/tests/rtld/dladdr_local/test.c @@ -0,0 +1,23 @@ +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +int main() { + void *foo_handle = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo_handle); + + char *foo_global = (char *)dlsym(foo_handle, "foo_global"); + assert(foo_global); + + Dl_info info; + assert(dladdr((const void *)foo_global, &info) != 0); + + assert(dlclose(foo_handle) == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/env.py b/user/include/mlibc/tests/rtld/env.py new file mode 100644 index 0000000..60ca206 --- /dev/null +++ b/user/include/mlibc/tests/rtld/env.py @@ -0,0 +1,27 @@ +import os +import sys + +def main(): + args = sys.argv[1:] + env = os.environ.copy() + + # parse environment variable assignments + i = 0 + while i < len(args) and '=' in args[i]: + var, val = args[i].split('=', 1) + env[var] = val + i += 1 + + if i < len(args): + exe_wrapper = os.environ.get('MESON_EXE_WRAPPER') + if exe_wrapper: + cmd = [exe_wrapper] + args[i:] + else: + cmd = args[i:] + os.execvpe(cmd[0], cmd, env) + else: + print("No command provided to execute.", file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/user/include/mlibc/tests/rtld/ifunc-dlopen/lib.c b/user/include/mlibc/tests/rtld/ifunc-dlopen/lib.c new file mode 100644 index 0000000..1909ca0 --- /dev/null +++ b/user/include/mlibc/tests/rtld/ifunc-dlopen/lib.c @@ -0,0 +1,11 @@ +#include + +static uint64_t foo_impl(void) { + return 69; +} + +static uint64_t (*foo_resolver(void))(void) { + return foo_impl; +} + +uint64_t foo(void) __attribute__((ifunc("foo_resolver"))); diff --git a/user/include/mlibc/tests/rtld/ifunc-dlopen/meson.build b/user/include/mlibc/tests/rtld/ifunc-dlopen/meson.build new file mode 100644 index 0000000..3f25f32 --- /dev/null +++ b/user/include/mlibc/tests/rtld/ifunc-dlopen/meson.build @@ -0,0 +1,5 @@ +libifunc_test = shared_library('ifunc-test-dlopen', 'lib.c', dependencies: libc_dep, install: true) +test_depends = [libifunc_test] + +libifunc_test_native = shared_library('native-ifunc-test-dlopen', 'lib.c', native: true) +test_native_depends = [libifunc_test_native] diff --git a/user/include/mlibc/tests/rtld/ifunc-dlopen/test.c b/user/include/mlibc/tests/rtld/ifunc-dlopen/test.c new file mode 100644 index 0000000..21d95b4 --- /dev/null +++ b/user/include/mlibc/tests/rtld/ifunc-dlopen/test.c @@ -0,0 +1,23 @@ +#include +#include + +int foo(void); + +#ifdef USE_HOST_LIBC +#define LIB "libnative-ifunc-test-dlopen.so" +#else +#define LIB "libifunc-test-dlopen.so" +#endif + +int main(void) { + void *handle = dlopen(LIB, RTLD_NOW | RTLD_LOCAL); + assert(handle); + + int (*func)() = (int (*)()) dlsym(handle, "foo"); + assert(func); + + int ret = func(); + assert(ret == 69); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/ifunc/lib.c b/user/include/mlibc/tests/rtld/ifunc/lib.c new file mode 100644 index 0000000..3a4341b --- /dev/null +++ b/user/include/mlibc/tests/rtld/ifunc/lib.c @@ -0,0 +1,35 @@ +#include + +static uint64_t foo_impl(void) { + return 420; +} + +#if defined(__riscv) && !defined(USE_HOST_LIBC) +#include +#elif defined(__riscv) +int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpusetsize, cpu_set_t *cpus, + unsigned int flags) __attribute__((access(read_write, 1, 2))); + +typedef int (*__riscv_hwprobe_t)(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpusetsize, cpu_set_t *cpus, unsigned int flags) __attribute__((access(read_write, 1, 2))); +#endif + +#if defined(__riscv) +#include + +static uint64_t (*foo_resolver(long long, __riscv_hwprobe_t hwprobe, void *))(void) { + if (!hwprobe) + return NULL; + struct riscv_hwprobe pairs[1] = { + { .key = 4, .value = 0 } + }; + hwprobe(pairs, 1, 0, 0, 0); + return foo_impl; +} +#else +static uint64_t (*foo_resolver(void))(void) { + return foo_impl; +} +#endif + +uint64_t foo(void) __attribute__((ifunc("foo_resolver"))); diff --git a/user/include/mlibc/tests/rtld/ifunc/meson.build b/user/include/mlibc/tests/rtld/ifunc/meson.build new file mode 100644 index 0000000..2416520 --- /dev/null +++ b/user/include/mlibc/tests/rtld/ifunc/meson.build @@ -0,0 +1,5 @@ +libifunc_test = shared_library('ifunc-test', 'lib.c', dependencies: libc_dep) +test_link_with = [libifunc_test] + +libifunc_test_native = shared_library('native-ifunc-test', 'lib.c', native: true) +test_native_link_with = [libifunc_test_native] diff --git a/user/include/mlibc/tests/rtld/ifunc/test.c b/user/include/mlibc/tests/rtld/ifunc/test.c new file mode 100644 index 0000000..345e100 --- /dev/null +++ b/user/include/mlibc/tests/rtld/ifunc/test.c @@ -0,0 +1,10 @@ +#include + +int foo(void); + +int main(void) { + int res = foo(); + assert(res == 420); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/ld_library_path/libfoo.c b/user/include/mlibc/tests/rtld/ld_library_path/libfoo.c new file mode 100644 index 0000000..85e6cd8 --- /dev/null +++ b/user/include/mlibc/tests/rtld/ld_library_path/libfoo.c @@ -0,0 +1 @@ +void foo() {} diff --git a/user/include/mlibc/tests/rtld/ld_library_path/meson.build b/user/include/mlibc/tests/rtld/ld_library_path/meson.build new file mode 100644 index 0000000..63ea8eb --- /dev/null +++ b/user/include/mlibc/tests/rtld/ld_library_path/meson.build @@ -0,0 +1,22 @@ +# Remove the RPATH and set the LD_LIBRARY_PATH environment variable +# instead when running tests to make sure the library can be found +# in a directory specified by the user at runtime + +test_rpath = '$ORIGIN/' + +test_ld_path = meson.global_build_root() / 'tests' / 'rtld' / test_name +test_env += ['LD_LIBRARY_PATH=' + test_ld_path] +test_native_env += ['LD_LIBRARY_PATH=' + test_ld_path] + +libfoo = shared_library('foo', 'libfoo.c', + dependencies: libc_dep, + link_args: test_additional_link_args, +) + +test_depends = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', + link_args: ['-ldl'] + test_additional_link_args, + native: true +) +test_native_depends = [libfoo_native] diff --git a/user/include/mlibc/tests/rtld/ld_library_path/test.c b/user/include/mlibc/tests/rtld/ld_library_path/test.c new file mode 100644 index 0000000..151eb36 --- /dev/null +++ b/user/include/mlibc/tests/rtld/ld_library_path/test.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +int main() { + void *foo = dlopen(LIBFOO, RTLD_NOW); + assert(foo); + dlclose(foo); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/meson.build b/user/include/mlibc/tests/rtld/meson.build new file mode 100644 index 0000000..d3649f5 --- /dev/null +++ b/user/include/mlibc/tests/rtld/meson.build @@ -0,0 +1,106 @@ +rtld_test_cases = [ + 'dl_iterate_phdr', + 'dladdr_local', + 'ld_library_path', + 'noload-promote', + 'rtld_next', + 'soname', + 'preinit', + 'destroy1', + 'destroy2', + 'scope1', + 'scope2', + 'scope3', + 'scope4', + 'scope5', + 'search-order', + 'tls_align', + 'relr', + 'symver', +] + +if host_machine.cpu_family() != 'm68k' + rtld_test_cases += [ + 'ifunc', + 'ifunc-dlopen', + ] +endif + +host_libc_rtld_nosan_test_cases = [ + 'preinit', +] + +py = import('python').find_installation('python3') + +foreach test_name : rtld_test_cases + test_rpath = meson.global_build_root() / 'tests' / 'rtld' / test_name / '' + test_rpath += ':$ORIGIN/' # Workaround old and buggy qemu-user on CI + + test_env = [] + test_link_with = [] + test_depends = [] + test_native_env = [] + test_native_link_with = [] + test_native_depends = [] + test_additional_link_args = [] + test_skipped = false + + # Build the needed DSOs for the test. This sets the variables above. + subdir(test_name) + + if test_skipped + exec = executable('rtld-' + test_name, ['skipped.c', test_sources], + dependencies: libc_dep, + override_options: test_override_options, + c_args: test_c_args, + link_args: test_link_args, + ) + test(test_name, exec, suite: 'rtld') + if build_tests_host_libc and not host_libc_excluded_test_cases.contains('rtld' / test_name) + test(test_name, exec, suite: ['host-libc', 'rtld']) + endif + continue + endif + + exec = executable('rtld-' + test_name, [test_name / 'test.c', test_sources], + link_with: test_link_with, + dependencies: libc_dep, + build_rpath: test_rpath, + override_options: test_override_options, + c_args: test_c_args, + link_args: test_link_args + test_additional_link_args, + ) + args = [ + meson.global_source_root() + '/tests/rtld/env.py', + test_env, + exec, + ] + # wrap the test so we can control the environment variables without meson interfering + test(test_name, py, args: args, suite: 'rtld', depends: test_depends) + + if build_tests_host_libc and not host_libc_excluded_test_cases.contains('rtld' / test_name) + if test_name in host_libc_rtld_nosan_test_cases + host_libc_rtld_sanitize_options = 'b_sanitize=none' + else + # Don't use ASan here, due to a bug that breaks dlopen() + DT_RUNPATH: + # https://bugzilla.redhat.com/show_bug.cgi?id=1449604 + host_libc_rtld_sanitize_options = 'b_sanitize=undefined' + endif + + exec = executable('host-libc-' + test_name, test_name / 'test.c', + link_with: test_native_link_with, + dependencies: rtlib_deps, + build_rpath: test_rpath, + override_options: host_libc_rtld_sanitize_options, + c_args: ['-D_GNU_SOURCE', '-DUSE_HOST_LIBC'], + link_args: ['-ldl'] + test_additional_link_args, + native: true, + ) + args = [ + meson.global_source_root() + '/tests/rtld/env.py', + test_native_env, + exec, + ] + test(test_name, py, args: args, suite: ['host-libc', 'rtld'], depends: test_native_depends) + endif +endforeach diff --git a/user/include/mlibc/tests/rtld/noload-promote/libfoo.c b/user/include/mlibc/tests/rtld/noload-promote/libfoo.c new file mode 100644 index 0000000..85e6cd8 --- /dev/null +++ b/user/include/mlibc/tests/rtld/noload-promote/libfoo.c @@ -0,0 +1 @@ +void foo() {} diff --git a/user/include/mlibc/tests/rtld/noload-promote/meson.build b/user/include/mlibc/tests/rtld/noload-promote/meson.build new file mode 100644 index 0000000..4ae6bb3 --- /dev/null +++ b/user/include/mlibc/tests/rtld/noload-promote/meson.build @@ -0,0 +1,5 @@ +libfoo = shared_library('foo', 'libfoo.c') +test_depends = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +test_native_depends = [libfoo_native] diff --git a/user/include/mlibc/tests/rtld/noload-promote/test.c b/user/include/mlibc/tests/rtld/noload-promote/test.c new file mode 100644 index 0000000..cc9820e --- /dev/null +++ b/user/include/mlibc/tests/rtld/noload-promote/test.c @@ -0,0 +1,24 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +int main() { + void *foo = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo); + + assert(dlsym(RTLD_DEFAULT, "foo") == NULL); + + // Opening a library with RTLD_NOLOAD | RTLD_GLOBAL should promote it to the global scope. + assert(dlopen(LIBFOO, RTLD_NOLOAD | RTLD_GLOBAL | RTLD_NOW) == foo); + assert(dlsym(RTLD_DEFAULT, "foo") != NULL); + + assert(dlopen("does-not-exist.so.1337", RTLD_NOLOAD | RTLD_GLOBAL | RTLD_NOW) == NULL); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/preinit/libfoo.c b/user/include/mlibc/tests/rtld/preinit/libfoo.c new file mode 100644 index 0000000..9c834ea --- /dev/null +++ b/user/include/mlibc/tests/rtld/preinit/libfoo.c @@ -0,0 +1,18 @@ +#include +#include + +int fooDone = 0; + +// DSOs do not support pre-initialization functions. + +__attribute__((constructor)) +void fooInit() { + dprintf(1, "initialization function called in foo\n"); + + assert(fooDone == 0); + fooDone++; +} + +int isFooDone() { + return fooDone; +} diff --git a/user/include/mlibc/tests/rtld/preinit/meson.build b/user/include/mlibc/tests/rtld/preinit/meson.build new file mode 100644 index 0000000..58ff830 --- /dev/null +++ b/user/include/mlibc/tests/rtld/preinit/meson.build @@ -0,0 +1,19 @@ +if host_machine.cpu_family() == 'riscv64' + # gp isn't initialized until after crt1.o runs, so to access + # globals in our pre-initializers we must disable it. + test_additional_link_args = ['-Wl,--no-relax'] +endif + +libfoo = shared_library('foo', ['libfoo.c'], + dependencies: libc_dep, + override_options: 'b_sanitize=none', + link_args: test_additional_link_args, +) +test_link_with = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', + link_args: ['-ldl'] + test_additional_link_args, + override_options: 'b_sanitize=none', + native: true +) +test_native_link_with = [libfoo_native] diff --git a/user/include/mlibc/tests/rtld/preinit/test.c b/user/include/mlibc/tests/rtld/preinit/test.c new file mode 100644 index 0000000..de2fc51 --- /dev/null +++ b/user/include/mlibc/tests/rtld/preinit/test.c @@ -0,0 +1,46 @@ +#include +#include + +int mainDone = 0; + +int isFooDone(); + +void preInit1() { + // Use dprintf because stdout might not be initialized yet. + dprintf(1, "pre-initialization function 1 called in main executable\n"); + + assert(isFooDone() == 0); + assert(mainDone == 0); + mainDone++; +} + +void preInit2() { + dprintf(1, "pre-initialization function 2 called in main executable\n"); + + assert(isFooDone() == 0); + assert(mainDone == 1); + mainDone++; +} + +__attribute__((constructor)) +void mainInit() { + dprintf(1, "initialization function called in main executable\n"); + + assert(isFooDone() == 1); + assert(mainDone == 2); + mainDone++; +} + +// Manually register the pre-initialization functions. +__attribute__((used, section(".preinit_array"))) +static void (*preinitFunctions[])(void) = { + &preInit1, + &preInit2, +}; + +int main() { + assert(isFooDone() == 1); + assert(mainDone == 3); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/relr/meson.build b/user/include/mlibc/tests/rtld/relr/meson.build new file mode 100644 index 0000000..44b3f65 --- /dev/null +++ b/user/include/mlibc/tests/rtld/relr/meson.build @@ -0,0 +1 @@ +test_additional_link_args += ['-Wl,-z,pack-relative-relocs'] diff --git a/user/include/mlibc/tests/rtld/relr/test.c b/user/include/mlibc/tests/rtld/relr/test.c new file mode 100644 index 0000000..b7a0536 --- /dev/null +++ b/user/include/mlibc/tests/rtld/relr/test.c @@ -0,0 +1,24 @@ +#include +#include + +const char* strings[] = { + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", +}; + +int main() { + for(size_t i = 0; i < sizeof(strings) / sizeof(*strings); ++i) { + assert(strings[i][0] == 0); + } + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/rtld_next/libbar.c b/user/include/mlibc/tests/rtld/rtld_next/libbar.c new file mode 100644 index 0000000..c0950c5 --- /dev/null +++ b/user/include/mlibc/tests/rtld/rtld_next/libbar.c @@ -0,0 +1,16 @@ +#include + +typedef char *charFn(void); + +__attribute__((weak)) +char *definedInBoth() { + return "bar"; +} + +charFn *barGetDefault() { + return (charFn *)dlsym(RTLD_DEFAULT, "definedInBoth"); +} + +charFn *barGetNext() { + return (charFn *)dlsym(RTLD_NEXT, "definedInBoth"); +} diff --git a/user/include/mlibc/tests/rtld/rtld_next/libfoo.c b/user/include/mlibc/tests/rtld/rtld_next/libfoo.c new file mode 100644 index 0000000..1d46b73 --- /dev/null +++ b/user/include/mlibc/tests/rtld/rtld_next/libfoo.c @@ -0,0 +1,17 @@ +#include + +typedef char *charFn(void); + +__attribute__((weak)) +char *definedInBoth() { + return "foo"; +} + +charFn *fooGetDefault() { + return (charFn *)dlsym(RTLD_DEFAULT, "definedInBoth"); +} + +charFn *fooGetNext() { + return (charFn *)dlsym(RTLD_NEXT, "definedInBoth"); +} + diff --git a/user/include/mlibc/tests/rtld/rtld_next/meson.build b/user/include/mlibc/tests/rtld/rtld_next/meson.build new file mode 100644 index 0000000..3815a00 --- /dev/null +++ b/user/include/mlibc/tests/rtld/rtld_next/meson.build @@ -0,0 +1,27 @@ +# Prevent tail calls, as it breaks libc's 'calling object' detection. +no_tail_calls = '-fno-optimize-sibling-calls' + +libfoo = shared_library('foo', 'libfoo.c', + dependencies: libc_dep, + c_args: no_tail_calls, +) +libbar = shared_library('bar', 'libbar.c', + dependencies: libc_dep, + c_args: no_tail_calls, +) +test_link_with = [libfoo, libbar] # foo is linked before bar + +libfoo_native = shared_library('native-foo', 'libfoo.c', + c_args: [no_tail_calls, '-D_GNU_SOURCE'], + link_args: '-ldl', + override_options: 'b_sanitize=none', + native: true +) +libbar_native = shared_library('native-bar', 'libbar.c', + c_args: [no_tail_calls, '-D_GNU_SOURCE'], + link_args: '-ldl', + override_options: 'b_sanitize=none', + native: true +) +test_native_link_with = [libfoo_native, libbar_native] + diff --git a/user/include/mlibc/tests/rtld/rtld_next/test.c b/user/include/mlibc/tests/rtld/rtld_next/test.c new file mode 100644 index 0000000..061f48e --- /dev/null +++ b/user/include/mlibc/tests/rtld/rtld_next/test.c @@ -0,0 +1,28 @@ +#include +#include + +typedef char *charFn(void); +charFn *fooGetDefault(void); +charFn *fooGetNext(void); +charFn *barGetDefault(void); +charFn *barGetNext(void); + +int main() { + charFn *ret; + + ret = fooGetDefault(); + assert(ret != NULL); + assert(!strcmp(ret(), "foo")); + + ret = fooGetNext(); + assert(ret != NULL); + assert(!strcmp(ret(), "bar")); + + ret = barGetDefault(); + assert(ret != NULL); + assert(!strcmp(ret(), "foo")); + + assert(barGetNext() == NULL); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/scope1/libbar.c b/user/include/mlibc/tests/rtld/scope1/libbar.c new file mode 100644 index 0000000..bcf336d --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope1/libbar.c @@ -0,0 +1,14 @@ +char *foo(void); +char *foo_global(void); + +char *bar(void) { + return "bar"; +} + +char *bar_calls_foo(void) { + return foo(); +} + +char *bar_calls_foo_global(void) { + return foo_global(); +} diff --git a/user/include/mlibc/tests/rtld/scope1/libfoo.c b/user/include/mlibc/tests/rtld/scope1/libfoo.c new file mode 100644 index 0000000..112342c --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope1/libfoo.c @@ -0,0 +1,9 @@ +char *foo(void) { + return "foo"; +} + +char global[] = "foo global"; + +char *foo_global(void) { + return global; +} diff --git a/user/include/mlibc/tests/rtld/scope1/meson.build b/user/include/mlibc/tests/rtld/scope1/meson.build new file mode 100644 index 0000000..acb679e --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope1/meson.build @@ -0,0 +1,7 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +test_depends = [libfoo, libbar] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +test_native_depends = [libfoo_native, libbar_native] diff --git a/user/include/mlibc/tests/rtld/scope1/test.c b/user/include/mlibc/tests/rtld/scope1/test.c new file mode 100644 index 0000000..316d90b --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope1/test.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#define LIBBAR "libnative-bar.so" +#else +#define LIBFOO "libfoo.so" +#define LIBBAR "libbar.so" +#endif + +typedef char *strfn(void); + +int main() { + // We haven't dlopen'd these libs yet, so symbol resolution should fail. + assert(dlsym(RTLD_DEFAULT, "foo") == NULL); + assert(dlsym(RTLD_DEFAULT, "bar") == NULL); + + assert(!dlopen(LIBFOO, RTLD_NOLOAD)); + assert(!dlopen(LIBBAR, RTLD_NOLOAD)); + + void *foo_handle = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo_handle); + assert(dlopen(LIBFOO, RTLD_NOLOAD | RTLD_NOW)); + + strfn *foo_sym = dlsym(foo_handle, "foo"); + assert(foo_sym); + assert(foo_sym()); + assert(!strcmp(foo_sym(), "foo")); + + strfn *foo_global_sym = dlsym(foo_handle, "foo_global"); + assert(foo_global_sym); + assert(foo_global_sym()); + assert(!strcmp(foo_global_sym(), "foo global")); + + assert(dlsym(foo_handle, "doesnotexist") == NULL); + + // Nested opening should work + assert(dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW) == foo_handle); + assert(dlopen(LIBFOO, RTLD_NOLOAD | RTLD_NOW)); + + // Since we've loaded the same library twice, the addresses should be the same + assert(dlsym(foo_handle, "foo") == foo_sym); + assert(dlsym(foo_handle, "foo_global") == foo_global_sym); + + // libfoo was opened with RTLD_LOCAL, so we shouldn't be able to lookup + // its symbols in the global namespace. + assert(dlsym(RTLD_DEFAULT, "foo") == NULL); + + { + void *bar_handle = dlopen(LIBBAR, RTLD_GLOBAL | RTLD_NOW); + assert(bar_handle); + assert(dlopen(LIBBAR, RTLD_NOLOAD | RTLD_NOW)); + + strfn *bar_sym = dlsym(bar_handle, "bar"); + assert(bar_sym); + assert(bar_sym()); + assert(!strcmp(bar_sym(), "bar")); + + strfn *bar_calls_foo_sym = dlsym(bar_handle, "bar_calls_foo"); + assert(bar_calls_foo_sym); + assert(bar_calls_foo_sym()); + assert(!strcmp(bar_calls_foo_sym(), "foo")); + + strfn *bar_calls_foo_global_sym = dlsym(bar_handle, "bar_calls_foo_global"); + assert(bar_calls_foo_global_sym); + assert(bar_calls_foo_global_sym()); + assert(!strcmp(bar_calls_foo_global_sym(), "foo global")); + + // libbar was opened with RTLD_GLOBAL, so we can find symbols by + // searching in the global scope. + strfn *new_bar_sym = dlsym(RTLD_DEFAULT, "bar"); + assert(new_bar_sym); + assert(new_bar_sym == bar_sym); + + // Note that we loaded libbar with RTLD_GLOBAL, which should pull + // in libfoo's symbols globally too. + strfn *new_foo_sym = dlsym(RTLD_DEFAULT, "foo"); + assert(new_foo_sym); + assert(new_foo_sym == foo_sym); + + assert(dlclose(bar_handle) == 0); + } + + assert(dlclose(foo_handle) == 0); + assert(dlclose(foo_handle) == 0); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/scope2/libbar.c b/user/include/mlibc/tests/rtld/scope2/libbar.c new file mode 100644 index 0000000..5ae0b85 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope2/libbar.c @@ -0,0 +1,5 @@ +char *foo_baz_conflict(void); + +char *bar_calls_foo_baz_conflict(void) { + return foo_baz_conflict(); +} diff --git a/user/include/mlibc/tests/rtld/scope2/libbaz.c b/user/include/mlibc/tests/rtld/scope2/libbaz.c new file mode 100644 index 0000000..fc73adc --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope2/libbaz.c @@ -0,0 +1,3 @@ +char *foo_baz_conflict() { + return "resolved to baz"; +} diff --git a/user/include/mlibc/tests/rtld/scope2/libfoo.c b/user/include/mlibc/tests/rtld/scope2/libfoo.c new file mode 100644 index 0000000..9f7b881 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope2/libfoo.c @@ -0,0 +1,3 @@ +char *foo_baz_conflict() { + return "resolved to foo"; +} diff --git a/user/include/mlibc/tests/rtld/scope2/meson.build b/user/include/mlibc/tests/rtld/scope2/meson.build new file mode 100644 index 0000000..938272c --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope2/meson.build @@ -0,0 +1,9 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +libbaz = shared_library('baz', 'libbaz.c') +test_depends = [libfoo, libbar, libbaz] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +libbaz_native = shared_library('native-baz', 'libbaz.c', native: true) +test_native_depends = [libfoo_native, libbar_native, libbaz_native] diff --git a/user/include/mlibc/tests/rtld/scope2/test.c b/user/include/mlibc/tests/rtld/scope2/test.c new file mode 100644 index 0000000..d4763ae --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope2/test.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBBAR "libnative-bar.so" +#define LIBBAZ "libnative-baz.so" +#else +#define LIBBAR "libbar.so" +#define LIBBAZ "libbaz.so" +#endif + +typedef char *strfn(void); + +int main() { + void *baz = dlopen(LIBBAZ, RTLD_LAZY | RTLD_GLOBAL); + assert(baz); + + // At this point, baz is loaded in the global scope. When we load bar locally, + // there is a relocation to `foo_baz_conflict` which is defined in both + // foo (which is a dependency of bar), and baz. In this case baz should win + // since we search the global scope first. + + void *bar = dlopen(LIBBAR, RTLD_LAZY | RTLD_LOCAL); + assert(bar); + + strfn *bfn = dlsym(bar, "bar_calls_foo_baz_conflict"); + assert(!strcmp(bfn(), "resolved to baz")); + + // TODO: Test RTLD_DEEPBIND and DT_SYMBOLIC once we implement it. + + dlclose(bar); + dlclose(baz); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/scope3/libbar.c b/user/include/mlibc/tests/rtld/scope3/libbar.c new file mode 100644 index 0000000..28b5b86 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope3/libbar.c @@ -0,0 +1,8 @@ +int g = 1; + +int call_foo(void); + +int call_bar(void) { + return call_foo(); +} + diff --git a/user/include/mlibc/tests/rtld/scope3/libbaz.c b/user/include/mlibc/tests/rtld/scope3/libbaz.c new file mode 100644 index 0000000..d4be90a --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope3/libbaz.c @@ -0,0 +1,7 @@ +int g = 2; + +int call_foo(void); + +int call_baz(void) { + return call_foo(); +} diff --git a/user/include/mlibc/tests/rtld/scope3/libfoo.c b/user/include/mlibc/tests/rtld/scope3/libfoo.c new file mode 100644 index 0000000..0ec8071 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope3/libfoo.c @@ -0,0 +1,5 @@ +int g = 0; + +int call_foo(void) { + return g; +} diff --git a/user/include/mlibc/tests/rtld/scope3/meson.build b/user/include/mlibc/tests/rtld/scope3/meson.build new file mode 100644 index 0000000..0c98583 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope3/meson.build @@ -0,0 +1,9 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +libbaz = shared_library('baz', 'libbaz.c', build_rpath: test_rpath, link_with: libfoo) +test_depends = [libfoo, libbar, libbaz] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +libbaz_native = shared_library('native-baz', 'libbaz.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +test_native_depends = [libfoo_native, libbar_native, libbaz_native] diff --git a/user/include/mlibc/tests/rtld/scope3/test.c b/user/include/mlibc/tests/rtld/scope3/test.c new file mode 100644 index 0000000..27196ad --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope3/test.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBBAR "libnative-bar.so" +#define LIBBAZ "libnative-baz.so" +#else +#define LIBBAR "libbar.so" +#define LIBBAZ "libbaz.so" +#endif + +int main() { + // In this test, we have bar -> foo and baz -> foo (where -> means 'depends on'). + // All three objects contain a definition of a symbol g. Bar calls into foo to retrieve + // what foo thinks g is, but since bar appears earlier in the scope than foo, bar's copy + // of g wins. + // + // Next, we load baz, which is identical to bar. When baz calls into foo to retrieve g, + // foo still sees bar's definition of g, so bar's copy of g wins. + // + // Swapping the load order of bar and baz should therefore change the value of g which + // foo sees. This behaviour is why dlmopen exists. If we ever implement that, we should + // write a similar test and assert that the calls return different results. + + void *libbar = dlopen(LIBBAR, RTLD_LAZY | RTLD_LOCAL); + int (*call_bar)(void) = dlsym(libbar, "call_bar"); + printf("call_bar: %d\n", call_bar()); + assert(call_bar() == 1); + + void *libbaz = dlopen(LIBBAZ, RTLD_LAZY | RTLD_LOCAL); + int (*call_baz)(void) = dlsym(libbaz, "call_baz"); + printf("call_baz: %d\n", call_baz()); + assert(call_baz() == 1); + + + dlclose(libbar); + dlclose(libbaz); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/scope4/libbar.c b/user/include/mlibc/tests/rtld/scope4/libbar.c new file mode 100644 index 0000000..514e456 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope4/libbar.c @@ -0,0 +1,3 @@ +// Bar needs to have a relocation against foo in order to set DT_NEEDED. +void foo(void); +void bar() { foo(); } diff --git a/user/include/mlibc/tests/rtld/scope4/libbaz.c b/user/include/mlibc/tests/rtld/scope4/libbaz.c new file mode 100644 index 0000000..256a0e3 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope4/libbaz.c @@ -0,0 +1 @@ +void baz() {} diff --git a/user/include/mlibc/tests/rtld/scope4/libfoo.c b/user/include/mlibc/tests/rtld/scope4/libfoo.c new file mode 100644 index 0000000..6710db7 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope4/libfoo.c @@ -0,0 +1,3 @@ +// Foo needs to have a relocation against baz in order to set DT_NEEDED. +void baz(void); +void foo() { baz(); } diff --git a/user/include/mlibc/tests/rtld/scope4/meson.build b/user/include/mlibc/tests/rtld/scope4/meson.build new file mode 100644 index 0000000..804a40c --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope4/meson.build @@ -0,0 +1,9 @@ +libbaz = shared_library('baz', 'libbaz.c') +libfoo = shared_library('foo', 'libfoo.c', build_rpath: test_rpath, link_with: libbaz) +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +test_depends = [libfoo, libbar, libbaz] + +libbaz_native = shared_library('native-baz', 'libbaz.c', native: true) +libfoo_native = shared_library('native-foo', 'libfoo.c', build_rpath: test_rpath, link_with: libbaz_native, native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +test_native_depends = [libfoo_native, libbar_native, libbaz_native] diff --git a/user/include/mlibc/tests/rtld/scope4/test.c b/user/include/mlibc/tests/rtld/scope4/test.c new file mode 100644 index 0000000..57af05d --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope4/test.c @@ -0,0 +1,38 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#define LIBBAR "libnative-bar.so" +#define LIBBAZ "libnative-baz.so" +#else +#define LIBFOO "libfoo.so" +#define LIBBAR "libbar.so" +#define LIBBAZ "libbaz.so" +#endif + +int main() { + // In this test, we have foo -> baz, bar -> foo (where '->' means 'depends on'). + // We first load foo with RTLD_LOCAL, and then load bar with RTLD_GLOBAL. + // This should bring foo and bar into the global scope. + + void *foo = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo); + assert(dlsym(foo, "foo")); + assert(dlsym(foo, "baz")); + assert(!dlsym(RTLD_DEFAULT, "foo")); + assert(!dlsym(RTLD_DEFAULT, "baz")); + + void *bar = dlopen(LIBBAR, RTLD_GLOBAL | RTLD_NOW); + assert(bar); + assert(dlsym(bar, "bar")); + assert(dlsym(RTLD_DEFAULT, "bar")); + assert(dlsym(RTLD_DEFAULT, "foo")); + assert(dlsym(RTLD_DEFAULT, "baz")); + + dlclose(foo); + dlclose(bar); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/scope5/libfoo.c b/user/include/mlibc/tests/rtld/scope5/libfoo.c new file mode 100644 index 0000000..85e6cd8 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope5/libfoo.c @@ -0,0 +1 @@ +void foo() {} diff --git a/user/include/mlibc/tests/rtld/scope5/meson.build b/user/include/mlibc/tests/rtld/scope5/meson.build new file mode 100644 index 0000000..22ade5b --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope5/meson.build @@ -0,0 +1,5 @@ +libfoo = shared_library('foo', 'libfoo.c') +test_link_with = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +test_native_link_with = [libfoo_native] diff --git a/user/include/mlibc/tests/rtld/scope5/test.c b/user/include/mlibc/tests/rtld/scope5/test.c new file mode 100644 index 0000000..d2afe09 --- /dev/null +++ b/user/include/mlibc/tests/rtld/scope5/test.c @@ -0,0 +1,29 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +// We need to have a relocation against foo for DT_NEEDED. +void foo(); +void bar() { foo(); } + +int main() { + // In this test, we have exec -> foo (where '->' means 'depends on'). + // This means that foo is in the global scope due to DT_NEEDED. + // We then dlopen it again with RTLD_LOCAL, which should just return + // the already-loaded object, but used to crash in the mlibc linker instead. + + void *foo = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo); + assert(dlsym(foo, "foo")); + assert(dlsym(RTLD_DEFAULT, "foo")); + + dlclose(foo); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/search-order/libbar.c b/user/include/mlibc/tests/rtld/search-order/libbar.c new file mode 100644 index 0000000..e5b3c60 --- /dev/null +++ b/user/include/mlibc/tests/rtld/search-order/libbar.c @@ -0,0 +1,19 @@ +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +int foo(void); + +int bar(void) { + return foo(); +} + +[[gnu::constructor]] void init(void) { + void *libfoo = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(libfoo); +} diff --git a/user/include/mlibc/tests/rtld/search-order/libfoo.c b/user/include/mlibc/tests/rtld/search-order/libfoo.c new file mode 100644 index 0000000..83fa5bb --- /dev/null +++ b/user/include/mlibc/tests/rtld/search-order/libfoo.c @@ -0,0 +1,3 @@ +int foo(void) { + return 0xCAFEBABE; +} diff --git a/user/include/mlibc/tests/rtld/search-order/meson.build b/user/include/mlibc/tests/rtld/search-order/meson.build new file mode 100644 index 0000000..559b98d --- /dev/null +++ b/user/include/mlibc/tests/rtld/search-order/meson.build @@ -0,0 +1,32 @@ +# meson does not have native custom_target, so when cross compiling it gets +# unhappy that we're trying to link a "host" library (which is actually built +# for the build machine) to a build executable. This means we can't patchelf +# native libraries if we want cross compilation to work. + +patchelf = find_program('patchelf', required: false) + +if patchelf.found() + # Overwrite LD_LIBRARY_PATH to make meson not fix our shenanigans + # Otherwise, meson's LD_LIBRARY_PATH makes this test useless because libfoo + # will be found through it instead of failing when libfoo is not found + test_env += ['LD_LIBRARY_PATH='] + test_native_env += ['LD_LIBRARY_PATH='] + + libfoo = shared_library('foo', 'libfoo.c', link_args: test_additional_link_args) + libbar_unpatched = shared_library('bar-unpatched', 'libbar.c', + link_args: test_additional_link_args, + override_options: 'b_sanitize=none', + dependencies: libc_dep, + link_with: libfoo) + libbar = custom_target('patch-libbar', + command: [patchelf, + '--remove-rpath', + '--set-soname', 'libbar.so', + libbar_unpatched, + '--output', '@OUTPUT0@'], + output: ['libbar.so'], + ) + test_link_with = [libbar, libfoo] +else + test_skipped = true +endif diff --git a/user/include/mlibc/tests/rtld/search-order/test.c b/user/include/mlibc/tests/rtld/search-order/test.c new file mode 100644 index 0000000..f4b392a --- /dev/null +++ b/user/include/mlibc/tests/rtld/search-order/test.c @@ -0,0 +1,21 @@ +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBBAR "libnative-bar.so" +#else +#define LIBBAR "libbar.so" +#endif + +int foo(); +int bar(); + +int main() { + void *libbar = dlopen(LIBBAR, RTLD_LOCAL | RTLD_NOW); + assert(libbar); + + assert(foo() == (int) 0xCAFEBABE); + assert(bar() == (int) 0xCAFEBABE); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/skipped.c b/user/include/mlibc/tests/rtld/skipped.c new file mode 100644 index 0000000..e7c74c5 --- /dev/null +++ b/user/include/mlibc/tests/rtld/skipped.c @@ -0,0 +1,3 @@ +int main() { + return 77; +} diff --git a/user/include/mlibc/tests/rtld/soname/libbar.c b/user/include/mlibc/tests/rtld/soname/libbar.c new file mode 100644 index 0000000..7f9f475 --- /dev/null +++ b/user/include/mlibc/tests/rtld/soname/libbar.c @@ -0,0 +1 @@ +char *name() { return "bar"; } diff --git a/user/include/mlibc/tests/rtld/soname/libfoo.c b/user/include/mlibc/tests/rtld/soname/libfoo.c new file mode 100644 index 0000000..0837e06 --- /dev/null +++ b/user/include/mlibc/tests/rtld/soname/libfoo.c @@ -0,0 +1 @@ +char *name(void) { return "foo"; } diff --git a/user/include/mlibc/tests/rtld/soname/meson.build b/user/include/mlibc/tests/rtld/soname/meson.build new file mode 100644 index 0000000..1eb97a8 --- /dev/null +++ b/user/include/mlibc/tests/rtld/soname/meson.build @@ -0,0 +1,17 @@ +# Create two libraries with the same SONAME. +bar_soname = '-Wl,-soname=libbar.so' + +libfoo = shared_library('foo', 'libfoo.c', link_args: '-Wl,-soname=libbar.so') +libbar = shared_library('bar', 'libbar.c', link_args: '-Wl,-soname=libbar.so') +test_depends = [libfoo, libbar] + +libfoo_native = shared_library('native-foo', 'libfoo.c', + link_args: ['-ldl', '-Wl,-soname=libnative-bar.so'], + native: true +) +libbar_native = shared_library('native-bar', 'libbar.c', + link_args: ['-ldl', '-Wl,-soname=libnative-bar.so'], + native: true +) +test_native_depends = [libfoo_native, libbar_native] + diff --git a/user/include/mlibc/tests/rtld/soname/test.c b/user/include/mlibc/tests/rtld/soname/test.c new file mode 100644 index 0000000..1aba357 --- /dev/null +++ b/user/include/mlibc/tests/rtld/soname/test.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#define LIBBAR "libnative-bar.so" +#else +#define LIBFOO "libfoo.so" +#define LIBBAR "libbar.so" +#endif + +int main() { + void *foo = dlopen(LIBFOO, RTLD_NOW); + void *bar = dlopen(LIBBAR, RTLD_NOW); + assert(foo); + assert(bar); + + // Since these libraries have the same SONAME, they should return the same thing. + assert(foo == bar); + + char *(*fooSym)(void) = dlsym(foo, "name"); + char *(*barSym)(void) = dlsym(bar, "name"); + assert(fooSym && barSym); + assert(fooSym() && barSym()); + printf("foo: name() = \"%s\"\n", fooSym()); + printf("bar: name() = \"%s\"\n", barSym()); + assert(!strcmp(fooSym(), barSym())); + + dlclose(foo); + dlclose(bar); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/symver/libfoo.c b/user/include/mlibc/tests/rtld/symver/libfoo.c new file mode 100644 index 0000000..3514170 --- /dev/null +++ b/user/include/mlibc/tests/rtld/symver/libfoo.c @@ -0,0 +1,15 @@ +int foo_v1(void) { + return 1; +} + +int foo_v2(void) { + return 2; +} + +int foo_v3(void) { + return 3; +} + +asm(".symver foo_v1, foo@FOO_1"); +asm(".symver foo_v2, foo@FOO_2"); +asm(".symver foo_v3, foo@@FOO_3"); // default version (due to @@ vs @) diff --git a/user/include/mlibc/tests/rtld/symver/libfoo.ver b/user/include/mlibc/tests/rtld/symver/libfoo.ver new file mode 100644 index 0000000..ee16bdc --- /dev/null +++ b/user/include/mlibc/tests/rtld/symver/libfoo.ver @@ -0,0 +1,14 @@ +FOO_1 { + global: foo; + local: *; +}; + +FOO_2 { + global: foo; + local: *; +}; + +FOO_3 { + global: foo; + local: *; +}; diff --git a/user/include/mlibc/tests/rtld/symver/meson.build b/user/include/mlibc/tests/rtld/symver/meson.build new file mode 100644 index 0000000..65dde2f --- /dev/null +++ b/user/include/mlibc/tests/rtld/symver/meson.build @@ -0,0 +1,11 @@ +version_script = meson.current_source_dir() / 'libfoo.ver' + +libfoo = shared_library('foo', 'libfoo.c', + link_args : ['-Wl,--version-script', version_script]) +test_depends = [libfoo] +test_link_with = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true, + link_args : ['-Wl,--version-script', version_script]) +test_native_depends = [libfoo_native] +test_native_link_with = [libfoo_native] diff --git a/user/include/mlibc/tests/rtld/symver/test.c b/user/include/mlibc/tests/rtld/symver/test.c new file mode 100644 index 0000000..3a53a9f --- /dev/null +++ b/user/include/mlibc/tests/rtld/symver/test.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +int foo(void); + +int main() { + int ver = foo(); + fprintf(stderr, "called foo version %d\n", ver); + assert(ver == 3); // version 3 is the default for libfoo.so + + void *libfoo_h = dlopen(LIBFOO, RTLD_GLOBAL | RTLD_NOW); + assert(libfoo_h); + + int (*foo1)(void) = dlvsym(libfoo_h, "foo", "FOO_1"); + assert(foo1); + + int (*foo2)(void) = dlvsym(libfoo_h, "foo", "FOO_2"); + assert(foo2); + + int (*foo3)(void) = dlvsym(libfoo_h, "foo", "FOO_3"); + assert(foo3); + + int (*foo_def)(void) = dlsym(libfoo_h, "foo"); + assert(foo_def); + + assert(foo1() == 1); + assert(foo2() == 2); + assert(foo3() == 3); + assert(foo3 == foo_def); + + return 0; +} diff --git a/user/include/mlibc/tests/rtld/tls_align/libbar.c b/user/include/mlibc/tests/rtld/tls_align/libbar.c new file mode 100644 index 0000000..3f8d6a7 --- /dev/null +++ b/user/include/mlibc/tests/rtld/tls_align/libbar.c @@ -0,0 +1 @@ +_Thread_local __attribute__((aligned(8))) char bar_thread_local[8] = "Hello!"; diff --git a/user/include/mlibc/tests/rtld/tls_align/libfoo.c b/user/include/mlibc/tests/rtld/tls_align/libfoo.c new file mode 100644 index 0000000..8d98177 --- /dev/null +++ b/user/include/mlibc/tests/rtld/tls_align/libfoo.c @@ -0,0 +1 @@ +_Thread_local __attribute__((aligned(16))) char foo_thread_local[8] = "Hello!"; diff --git a/user/include/mlibc/tests/rtld/tls_align/meson.build b/user/include/mlibc/tests/rtld/tls_align/meson.build new file mode 100644 index 0000000..61d0fd9 --- /dev/null +++ b/user/include/mlibc/tests/rtld/tls_align/meson.build @@ -0,0 +1,7 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c') +test_link_with = [libfoo, libbar] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', native: true) +test_native_link_with = [libfoo_native, libbar_native] diff --git a/user/include/mlibc/tests/rtld/tls_align/test.c b/user/include/mlibc/tests/rtld/tls_align/test.c new file mode 100644 index 0000000..9aaff3a --- /dev/null +++ b/user/include/mlibc/tests/rtld/tls_align/test.c @@ -0,0 +1,12 @@ +#include +#include + +extern _Thread_local char foo_thread_local[]; +extern _Thread_local char bar_thread_local[]; + +int main() { + assert(!((uintptr_t)foo_thread_local & (16 - 1))); + assert(!((uintptr_t)bar_thread_local & (8 - 1))); + + return 0; +} diff --git a/user/include/mlibc/x86_64-kirkos-gcc.txt b/user/include/mlibc/x86_64-kirkos-gcc.txt new file mode 100644 index 0000000..21067f7 --- /dev/null +++ b/user/include/mlibc/x86_64-kirkos-gcc.txt @@ -0,0 +1,14 @@ +[host_machine] +system = 'kirkos' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' +[binaries] +c = 'gcc' +cpp = 'g++' +ar = 'ar' +strip = 'strip' +ld = 'ld' +[built-in options] +c_args = ['-march=x86-64', '-mabi=sysv'] +cpp_args = ['-march=x86-64', '-mabi=sysv']