| author | |
| committer | |
| log | ed50bd1b655ff028bdd650edecdcdd6675f1dee0 |
| tree | 18bab13e2631f2ec55fdd5447baa7134c282e4a4 |
| parent | 0fbb9e09ea89ea24ec214b244e1de9574516c74c |
18 files changed, 676 insertions(+), 84 deletions(-)
CMakeLists.txt+18-16| ... | ... | @@ -200,27 +200,29 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST}) |
| 200 | 200 | install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}") |
| 201 | 201 | install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}") |
| 202 | 202 | install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}") |
| 203 | install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 204 | install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_libc.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 205 | install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_nolibc.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 206 | install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 207 | install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 208 | install(FILES "${CMAKE_SOURCE_DIR}/std/os.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 209 | install(FILES "${CMAKE_SOURCE_DIR}/std/str.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 210 | 203 | install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}") |
| 211 | install(FILES "${CMAKE_SOURCE_DIR}/std/linux.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 204 | install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 205 | install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 206 | install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 207 | install(FILES "${CMAKE_SOURCE_DIR}/std/endian.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 212 | 208 | install(FILES "${CMAKE_SOURCE_DIR}/std/errno.zig" DESTINATION "${ZIG_STD_DEST}") |
| 213 | install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 214 | install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 215 | install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 209 | install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 216 | 210 | install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}") |
| 217 | install(FILES "${CMAKE_SOURCE_DIR}/std/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 211 | install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 212 | install(FILES "${CMAKE_SOURCE_DIR}/std/linux.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 218 | 213 | install(FILES "${CMAKE_SOURCE_DIR}/std/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}") |
| 219 | install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 214 | install(FILES "${CMAKE_SOURCE_DIR}/std/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 220 | 215 | install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}") |
| 221 | install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 222 | install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 223 | install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 216 | install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 217 | install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 218 | install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 219 | install(FILES "${CMAKE_SOURCE_DIR}/std/os.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 220 | install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 221 | install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 222 | install(FILES "${CMAKE_SOURCE_DIR}/std/str.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 223 | install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 224 | install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_libc.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 225 | install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_nolibc.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 224 | 226 | |
| 225 | 227 | add_executable(run_tests ${TEST_SOURCES}) |
| 226 | 228 | target_link_libraries(run_tests) |
doc/style.md+1-1| ... | ... | @@ -62,7 +62,7 @@ const xml_document = |
| 62 | 62 | \\<?xml version="1.0" encoding="UTF-8"?> |
| 63 | 63 | \\<document> |
| 64 | 64 | \\</document> |
| 65 | ; | |
| 65 | ; | |
| 66 | 66 | struct XmlParser {} |
| 67 | 67 | |
| 68 | 68 | // The initials BE (Big Endian) are just another word in Zig identifier names. |
example/cat/main.zig+2-1| ... | ... | @@ -14,7 +14,8 @@ pub fn main(args: [][]u8) -> %void { |
| 14 | 14 | } else if (arg[0] == '-') { |
| 15 | 15 | return usage(exe); |
| 16 | 16 | } else { |
| 17 | var is = io.InStream.open(arg) %% |err| { | |
| 17 | var is: io.InStream = undefined; | |
| 18 | is.open(arg) %% |err| { | |
| 18 | 19 | %%io.stderr.printf("Unable to open file: "); |
| 19 | 20 | %%io.stderr.printf(@errName(err)); |
| 20 | 21 | %%io.stderr.printf("\n"); |
example/guess_number/main.zig+1-1| ... | ... | @@ -7,7 +7,7 @@ pub fn main(args: [][]u8) -> %void { |
| 7 | 7 | %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n"); |
| 8 | 8 | |
| 9 | 9 | var seed: [@sizeOf(usize)]u8 = undefined; |
| 10 | %%os.get_random_bytes(seed); | |
| 10 | %%os.getRandomBytes(seed); | |
| 11 | 11 | var rand: Rand = undefined; |
| 12 | 12 | rand.init(([]usize)(seed)[0]); |
| 13 | 13 |
src/all_types.hpp+2| ... | ... | @@ -1232,6 +1232,7 @@ struct CodeGen { |
| 1232 | 1232 | TypeTableEntry *entry_os_enum; |
| 1233 | 1233 | TypeTableEntry *entry_arch_enum; |
| 1234 | 1234 | TypeTableEntry *entry_environ_enum; |
| 1235 | TypeTableEntry *entry_oformat_enum; | |
| 1235 | 1236 | TypeTableEntry *entry_atomic_order_enum; |
| 1236 | 1237 | } builtin_types; |
| 1237 | 1238 | |
| ... | ... | @@ -1256,6 +1257,7 @@ struct CodeGen { |
| 1256 | 1257 | uint32_t target_os_index; |
| 1257 | 1258 | uint32_t target_arch_index; |
| 1258 | 1259 | uint32_t target_environ_index; |
| 1260 | uint32_t target_oformat_index; | |
| 1259 | 1261 | LLVMTargetMachineRef target_machine; |
| 1260 | 1262 | LLVMZigDIFile *dummy_di_file; |
| 1261 | 1263 | bool is_native_target; |
src/analyze.cpp+3| ... | ... | @@ -5296,6 +5296,9 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 5296 | 5296 | } else if (buf_eql_str(var_name, "environ")) { |
| 5297 | 5297 | const_val->data.x_enum.tag = g->target_environ_index; |
| 5298 | 5298 | return g->builtin_types.entry_environ_enum; |
| 5299 | } else if (buf_eql_str(var_name, "object_format")) { | |
| 5300 | const_val->data.x_enum.tag = g->target_oformat_index; | |
| 5301 | return g->builtin_types.entry_oformat_enum; | |
| 5299 | 5302 | } else { |
| 5300 | 5303 | add_node_error(g, *str_node, |
| 5301 | 5304 | buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name))); |
src/codegen.cpp+27| ... | ... | @@ -4576,6 +4576,33 @@ static void define_builtin_types(CodeGen *g) { |
| 4576 | 4576 | g->builtin_types.entry_environ_enum = entry; |
| 4577 | 4577 | } |
| 4578 | 4578 | |
| 4579 | { | |
| 4580 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); | |
| 4581 | entry->deep_const = true; | |
| 4582 | entry->zero_bits = true; // only allowed at compile time | |
| 4583 | buf_init_from_str(&entry->name, "@ObjectFormat"); | |
| 4584 | uint32_t field_count = target_oformat_count(); | |
| 4585 | entry->data.enumeration.field_count = field_count; | |
| 4586 | entry->data.enumeration.fields = allocate<TypeEnumField>(field_count); | |
| 4587 | for (uint32_t i = 0; i < field_count; i += 1) { | |
| 4588 | TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i]; | |
| 4589 | ZigLLVM_ObjectFormatType oformat = get_target_oformat(i); | |
| 4590 | type_enum_field->name = buf_create_from_str(get_target_oformat_name(oformat)); | |
| 4591 | type_enum_field->value = i; | |
| 4592 | type_enum_field->type_entry = g->builtin_types.entry_void; | |
| 4593 | ||
| 4594 | if (oformat == g->zig_target.oformat) { | |
| 4595 | g->target_oformat_index = i; | |
| 4596 | } | |
| 4597 | } | |
| 4598 | entry->data.enumeration.complete = true; | |
| 4599 | ||
| 4600 | TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); | |
| 4601 | entry->data.enumeration.tag_type = tag_type_entry; | |
| 4602 | ||
| 4603 | g->builtin_types.entry_oformat_enum = entry; | |
| 4604 | } | |
| 4605 | ||
| 4579 | 4606 | { |
| 4580 | 4607 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); |
| 4581 | 4608 | entry->deep_const = true; |
src/target.cpp+25| ... | ... | @@ -137,6 +137,31 @@ static const ZigLLVM_EnvironmentType environ_list[] = { |
| 137 | 137 | ZigLLVM_CoreCLR, |
| 138 | 138 | }; |
| 139 | 139 | |
| 140 | static const ZigLLVM_ObjectFormatType oformat_list[] = { | |
| 141 | ZigLLVM_UnknownObjectFormat, | |
| 142 | ZigLLVM_COFF, | |
| 143 | ZigLLVM_ELF, | |
| 144 | ZigLLVM_MachO, | |
| 145 | }; | |
| 146 | ||
| 147 | int target_oformat_count(void) { | |
| 148 | return array_length(oformat_list); | |
| 149 | } | |
| 150 | ||
| 151 | const ZigLLVM_ObjectFormatType get_target_oformat(int index) { | |
| 152 | return oformat_list[index]; | |
| 153 | } | |
| 154 | ||
| 155 | const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat) { | |
| 156 | switch (oformat) { | |
| 157 | case ZigLLVM_UnknownObjectFormat: return "unknown"; | |
| 158 | case ZigLLVM_COFF: return "coff"; | |
| 159 | case ZigLLVM_ELF: return "elf"; | |
| 160 | case ZigLLVM_MachO: return "macho"; | |
| 161 | } | |
| 162 | zig_unreachable(); | |
| 163 | } | |
| 164 | ||
| 140 | 165 | int target_arch_count(void) { |
| 141 | 166 | return array_length(arch_list); |
| 142 | 167 | } |
src/target.hpp+5| ... | ... | @@ -52,6 +52,11 @@ const char *get_target_os_name(ZigLLVM_OSType os_type); |
| 52 | 52 | int target_environ_count(void); |
| 53 | 53 | ZigLLVM_EnvironmentType get_target_environ(int index); |
| 54 | 54 | |
| 55 | ||
| 56 | int target_oformat_count(void); | |
| 57 | const ZigLLVM_ObjectFormatType get_target_oformat(int index); | |
| 58 | const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat); | |
| 59 | ||
| 55 | 60 | void get_native_target(ZigTarget *target); |
| 56 | 61 | void get_unknown_target(ZigTarget *target); |
| 57 | 62 |
std/debug.zig+110-8| ... | ... | @@ -1,21 +1,123 @@ |
| 1 | 1 | const Allocator = @import("mem.zig").Allocator; |
| 2 | 2 | const io = @import("io.zig"); |
| 3 | const os = @import("os.zig"); | |
| 4 | const elf = @import("elf.zig"); | |
| 5 | ||
| 6 | pub error MissingDebugInfo; | |
| 7 | pub error InvalidDebugInfo; | |
| 8 | pub error UnsupportedDebugInfo; | |
| 3 | 9 | |
| 4 | 10 | pub fn assert(b: bool) { |
| 5 | 11 | if (!b) unreachable{} |
| 6 | 12 | } |
| 7 | 13 | |
| 8 | pub fn printStackTrace() { | |
| 9 | var maybe_fp: ?&const u8 = @frameAddress(); | |
| 10 | while (true) { | |
| 11 | const fp = maybe_fp ?? break; | |
| 12 | const return_address = *(&const usize)(usize(fp) + @sizeOf(usize)); | |
| 13 | %%io.stderr.printInt(usize, return_address); | |
| 14 | %%io.stderr.printf("\n"); | |
| 15 | maybe_fp = *(&const ?&const u8)(fp); | |
| 14 | pub fn printStackTrace() -> %void { | |
| 15 | %return writeStackTrace(&io.stderr); | |
| 16 | %return io.stderr.flush(); | |
| 17 | } | |
| 18 | ||
| 19 | pub fn writeStackTrace(out_stream: &io.OutStream) -> %void { | |
| 20 | switch (@compileVar("object_format")) { | |
| 21 | elf => { | |
| 22 | var st: ElfStackTrace = undefined; | |
| 23 | %return io.openSelfExe(&st.self_exe_stream); | |
| 24 | defer %return st.self_exe_stream.close(); | |
| 25 | ||
| 26 | %return st.elf.openStream(&global_allocator, &st.self_exe_stream); | |
| 27 | defer %return st.elf.close(); | |
| 28 | ||
| 29 | st.aranges = %return st.elf.findSection(".debug_aranges"); | |
| 30 | ||
| 31 | var maybe_fp: ?&const u8 = @frameAddress(); | |
| 32 | while (true) { | |
| 33 | const fp = maybe_fp ?? break; | |
| 34 | const return_address = *(&const usize)(usize(fp) + @sizeOf(usize)); | |
| 35 | ||
| 36 | // read .debug_aranges to find out which compile unit the address is in | |
| 37 | const debug_info_offset = %return debugInfoOffset(&st, return_address); | |
| 38 | ||
| 39 | %return out_stream.printInt(usize, return_address); | |
| 40 | %return out_stream.printf(" -> "); | |
| 41 | %return out_stream.printInt(u64, debug_info_offset); | |
| 42 | %return out_stream.printf("\n"); | |
| 43 | maybe_fp = *(&const ?&const u8)(fp); | |
| 44 | } | |
| 45 | }, | |
| 46 | coff => { | |
| 47 | out_stream.write("(stack trace unavailable for COFF object format)\n"); | |
| 48 | }, | |
| 49 | macho => { | |
| 50 | out_stream.write("(stack trace unavailable for Mach-O object format)\n"); | |
| 51 | }, | |
| 52 | unknown => { | |
| 53 | out_stream.write("(stack trace unavailable for unknown object format)\n"); | |
| 54 | }, | |
| 16 | 55 | } |
| 17 | 56 | } |
| 18 | 57 | |
| 58 | struct ElfStackTrace { | |
| 59 | self_exe_stream: io.InStream, | |
| 60 | elf: elf.Elf, | |
| 61 | aranges: ?&elf.SectionHeader, | |
| 62 | } | |
| 63 | ||
| 64 | fn debugInfoOffset(st: &ElfStackTrace, target_address: usize) -> %u64 { | |
| 65 | // when there is no .debug_aranges section, offset into debug info is 0x0 | |
| 66 | const aranges = st.aranges ?? return 0; | |
| 67 | ||
| 68 | %return st.elf.seekToSection(aranges); | |
| 69 | ||
| 70 | const first_32_bits = %return st.self_exe_stream.readIntLe(u32); | |
| 71 | const is_64 = (first_32_bits == 0xffffffff); | |
| 72 | const unit_length = if (is_64) { | |
| 73 | %return st.self_exe_stream.readIntLe(u64) | |
| 74 | } else { | |
| 75 | if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; | |
| 76 | first_32_bits | |
| 77 | }; | |
| 78 | var unit_index: u64 = 0; | |
| 79 | ||
| 80 | while (unit_index < unit_length) { | |
| 81 | const version = %return st.self_exe_stream.readIntLe(u16); | |
| 82 | if (version != 2) return error.InvalidDebugInfo; | |
| 83 | unit_index += 2; | |
| 84 | ||
| 85 | const debug_info_offset = if (is_64) { | |
| 86 | unit_index += 4; | |
| 87 | %return st.self_exe_stream.readIntLe(u64) | |
| 88 | } else { | |
| 89 | unit_index += 2; | |
| 90 | %return st.self_exe_stream.readIntLe(u32) | |
| 91 | }; | |
| 92 | ||
| 93 | const address_size = %return st.self_exe_stream.readByte(); | |
| 94 | if (address_size > 8) return error.UnsupportedDebugInfo; | |
| 95 | unit_index += 1; | |
| 96 | ||
| 97 | const segment_size = %return st.self_exe_stream.readByte(); | |
| 98 | if (segment_size > 0) return error.UnsupportedDebugInfo; | |
| 99 | unit_index += 1; | |
| 100 | ||
| 101 | const align = segment_size + 2 * address_size; | |
| 102 | const padding = st.self_exe_stream.offset % align; | |
| 103 | %return st.self_exe_stream.seekForward(padding); | |
| 104 | unit_index += padding; | |
| 105 | ||
| 106 | while (true) { | |
| 107 | const address = %return st.self_exe_stream.readVarInt(false, u64, address_size); | |
| 108 | const length = %return st.self_exe_stream.readVarInt(false, u64, address_size); | |
| 109 | unit_index += align; | |
| 110 | if (address == 0 && length == 0) break; | |
| 111 | ||
| 112 | if (target_address >= address && target_address < address + length) { | |
| 113 | return debug_info_offset; | |
| 114 | } | |
| 115 | } | |
| 116 | } | |
| 117 | ||
| 118 | return error.MissingDebugInfo; | |
| 119 | } | |
| 120 | ||
| 19 | 121 | pub var global_allocator = Allocator { |
| 20 | 122 | .allocFn = globalAlloc, |
| 21 | 123 | .reallocFn = globalRealloc, |
std/elf.zig created+261| ... | ... | @@ -0,0 +1,261 @@ |
| 1 | const io = @import("io.zig"); | |
| 2 | const str = @import("str.zig"); | |
| 3 | const math = @import("math.zig"); | |
| 4 | const mem = @import("mem.zig"); | |
| 5 | const debug = @import("debug.zig"); | |
| 6 | ||
| 7 | pub error InvalidFormat; | |
| 8 | ||
| 9 | pub const SHT_NULL = 0; | |
| 10 | pub const SHT_PROGBITS = 1; | |
| 11 | pub const SHT_SYMTAB = 2; | |
| 12 | pub const SHT_STRTAB = 3; | |
| 13 | pub const SHT_RELA = 4; | |
| 14 | pub const SHT_HASH = 5; | |
| 15 | pub const SHT_DYNAMIC = 6; | |
| 16 | pub const SHT_NOTE = 7; | |
| 17 | pub const SHT_NOBITS = 8; | |
| 18 | pub const SHT_REL = 9; | |
| 19 | pub const SHT_SHLIB = 10; | |
| 20 | pub const SHT_DYNSYM = 11; | |
| 21 | pub const SHT_INIT_ARRAY = 14; | |
| 22 | pub const SHT_FINI_ARRAY = 15; | |
| 23 | pub const SHT_PREINIT_ARRAY = 16; | |
| 24 | pub const SHT_GROUP = 17; | |
| 25 | pub const SHT_SYMTAB_SHNDX = 18; | |
| 26 | pub const SHT_LOOS = 0x60000000; | |
| 27 | pub const SHT_HIOS = 0x6fffffff; | |
| 28 | pub const SHT_LOPROC = 0x70000000; | |
| 29 | pub const SHT_HIPROC = 0x7fffffff; | |
| 30 | pub const SHT_LOUSER = 0x80000000; | |
| 31 | pub const SHT_HIUSER = 0xffffffff; | |
| 32 | ||
| 33 | pub enum FileType { | |
| 34 | Relocatable, | |
| 35 | Executable, | |
| 36 | Shared, | |
| 37 | Core, | |
| 38 | } | |
| 39 | ||
| 40 | pub enum Arch { | |
| 41 | Sparc, | |
| 42 | x86, | |
| 43 | Mips, | |
| 44 | PowerPc, | |
| 45 | Arm, | |
| 46 | SuperH, | |
| 47 | IA_64, | |
| 48 | x86_64, | |
| 49 | AArch64, | |
| 50 | } | |
| 51 | ||
| 52 | pub struct SectionHeader { | |
| 53 | name: u32, | |
| 54 | sh_type: u32, | |
| 55 | flags: u64, | |
| 56 | addr: u64, | |
| 57 | offset: u64, | |
| 58 | size: u64, | |
| 59 | link: u32, | |
| 60 | info: u32, | |
| 61 | addr_align: u64, | |
| 62 | ent_size: u64, | |
| 63 | } | |
| 64 | ||
| 65 | pub struct Elf { | |
| 66 | in_stream: &io.InStream, | |
| 67 | auto_close_stream: bool, | |
| 68 | is_64: bool, | |
| 69 | is_big_endian: bool, | |
| 70 | file_type: FileType, | |
| 71 | arch: Arch, | |
| 72 | entry_addr: u64, | |
| 73 | program_header_offset: u64, | |
| 74 | section_header_offset: u64, | |
| 75 | string_section_index: u64, | |
| 76 | string_section: &SectionHeader, | |
| 77 | section_headers: []SectionHeader, | |
| 78 | allocator: &mem.Allocator, | |
| 79 | prealloc_stream: io.InStream, | |
| 80 | ||
| 81 | /// Call close when done. | |
| 82 | pub fn openFile(elf: &Elf, allocator: &mem.Allocator, path: []const u8) -> %void { | |
| 83 | %return elf.prealloc_stream.open(path); | |
| 84 | %return elf.openStream(allocator, &elf.prealloc_stream); | |
| 85 | elf.auto_close_stream = true; | |
| 86 | } | |
| 87 | ||
| 88 | /// Call close when done. | |
| 89 | pub fn openStream(elf: &Elf, allocator: &mem.Allocator, stream: &io.InStream) -> %void { | |
| 90 | elf.allocator = allocator; | |
| 91 | elf.in_stream = stream; | |
| 92 | elf.auto_close_stream = false; | |
| 93 | ||
| 94 | var magic: [4]u8 = undefined; | |
| 95 | %return elf.in_stream.readNoEof(magic); | |
| 96 | if (!str.eql(magic, "\x7fELF")) return error.InvalidFormat; | |
| 97 | ||
| 98 | elf.is_64 = switch (%return elf.in_stream.readByte()) { | |
| 99 | 1 => false, | |
| 100 | 2 => true, | |
| 101 | else => return error.InvalidFormat, | |
| 102 | }; | |
| 103 | ||
| 104 | elf.is_big_endian = switch (%return elf.in_stream.readByte()) { | |
| 105 | 1 => false, | |
| 106 | 2 => true, | |
| 107 | else => return error.InvalidFormat, | |
| 108 | }; | |
| 109 | ||
| 110 | const version_byte = %return elf.in_stream.readByte(); | |
| 111 | if (version_byte != 1) return error.InvalidFormat; | |
| 112 | ||
| 113 | // skip over padding | |
| 114 | %return elf.in_stream.seekForward(9); | |
| 115 | ||
| 116 | elf.file_type = switch (%return elf.in_stream.readInt(elf.is_big_endian, u16)) { | |
| 117 | 1 => FileType.Relocatable, | |
| 118 | 2 => FileType.Executable, | |
| 119 | 3 => FileType.Shared, | |
| 120 | 4 => FileType.Core, | |
| 121 | else => return error.InvalidFormat, | |
| 122 | }; | |
| 123 | ||
| 124 | elf.arch = switch (%return elf.in_stream.readInt(elf.is_big_endian, u16)) { | |
| 125 | 0x02 => Arch.Sparc, | |
| 126 | 0x03 => Arch.x86, | |
| 127 | 0x08 => Arch.Mips, | |
| 128 | 0x14 => Arch.PowerPc, | |
| 129 | 0x28 => Arch.Arm, | |
| 130 | 0x2A => Arch.SuperH, | |
| 131 | 0x32 => Arch.IA_64, | |
| 132 | 0x3E => Arch.x86_64, | |
| 133 | 0xb7 => Arch.AArch64, | |
| 134 | else => return error.InvalidFormat, | |
| 135 | }; | |
| 136 | ||
| 137 | const elf_version = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 138 | if (elf_version != 1) return error.InvalidFormat; | |
| 139 | ||
| 140 | if (elf.is_64) { | |
| 141 | elf.entry_addr = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 142 | elf.program_header_offset = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 143 | elf.section_header_offset = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 144 | } else { | |
| 145 | elf.entry_addr = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 146 | elf.program_header_offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 147 | elf.section_header_offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 148 | } | |
| 149 | ||
| 150 | // skip over flags | |
| 151 | %return elf.in_stream.seekForward(4); | |
| 152 | ||
| 153 | const header_size = %return elf.in_stream.readInt(elf.is_big_endian, u16); | |
| 154 | if ((elf.is_64 && header_size != 64) || | |
| 155 | (!elf.is_64 && header_size != 52)) | |
| 156 | { | |
| 157 | return error.InvalidFormat; | |
| 158 | } | |
| 159 | ||
| 160 | const ph_entry_size = %return elf.in_stream.readInt(elf.is_big_endian, u16); | |
| 161 | const ph_entry_count = %return elf.in_stream.readInt(elf.is_big_endian, u16); | |
| 162 | const sh_entry_size = %return elf.in_stream.readInt(elf.is_big_endian, u16); | |
| 163 | const sh_entry_count = %return elf.in_stream.readInt(elf.is_big_endian, u16); | |
| 164 | elf.string_section_index = u64(%return elf.in_stream.readInt(elf.is_big_endian, u16)); | |
| 165 | ||
| 166 | if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; | |
| 167 | ||
| 168 | const sh_byte_count = u64(sh_entry_size) * u64(sh_entry_count); | |
| 169 | const end_sh = %return math.addOverflow(u64, elf.section_header_offset, sh_byte_count); | |
| 170 | const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count); | |
| 171 | const end_ph = %return math.addOverflow(u64, elf.program_header_offset, ph_byte_count); | |
| 172 | ||
| 173 | const stream_end = %return elf.in_stream.endPos(); | |
| 174 | if (stream_end < end_sh || stream_end < end_ph) { | |
| 175 | return error.InvalidFormat; | |
| 176 | } | |
| 177 | ||
| 178 | %return elf.in_stream.seekTo(elf.section_header_offset); | |
| 179 | ||
| 180 | elf.section_headers = %return elf.allocator.alloc(SectionHeader, sh_entry_count); | |
| 181 | %defer elf.allocator.free(SectionHeader, elf.section_headers); | |
| 182 | ||
| 183 | if (elf.is_64) { | |
| 184 | if (sh_entry_size != 64) return error.InvalidFormat; | |
| 185 | ||
| 186 | for (elf.section_headers) |*section| { | |
| 187 | section.name = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 188 | section.sh_type = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 189 | section.flags = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 190 | section.addr = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 191 | section.offset = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 192 | section.size = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 193 | section.link = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 194 | section.info = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 195 | section.addr_align = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 196 | section.ent_size = %return elf.in_stream.readInt(elf.is_big_endian, u64); | |
| 197 | } | |
| 198 | } else { | |
| 199 | if (sh_entry_size != 40) return error.InvalidFormat; | |
| 200 | ||
| 201 | for (elf.section_headers) |*section| { | |
| 202 | // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ? | |
| 203 | section.name = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 204 | section.sh_type = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 205 | section.flags = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 206 | section.addr = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 207 | section.offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 208 | section.size = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 209 | section.link = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 210 | section.info = %return elf.in_stream.readInt(elf.is_big_endian, u32); | |
| 211 | section.addr_align = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 212 | section.ent_size = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32)); | |
| 213 | } | |
| 214 | } | |
| 215 | ||
| 216 | for (elf.section_headers) |*section| { | |
| 217 | if (section.sh_type != SHT_NOBITS) { | |
| 218 | const file_end_offset = %return math.addOverflow(u64, | |
| 219 | section.offset, section.size); | |
| 220 | if (stream_end < file_end_offset) return error.InvalidFormat; | |
| 221 | } | |
| 222 | } | |
| 223 | ||
| 224 | elf.string_section = &elf.section_headers[elf.string_section_index]; | |
| 225 | if (elf.string_section.sh_type != SHT_STRTAB) { | |
| 226 | // not a string table | |
| 227 | return error.InvalidFormat; | |
| 228 | } | |
| 229 | } | |
| 230 | ||
| 231 | pub fn close(elf: &Elf) -> %void { | |
| 232 | elf.allocator.free(SectionHeader, elf.section_headers); | |
| 233 | if (elf.auto_close_stream) %return elf.in_stream.close(); | |
| 234 | } | |
| 235 | ||
| 236 | pub fn findSection(elf: &Elf, name: []u8) -> %?&SectionHeader { | |
| 237 | for (elf.section_headers) |*section| { | |
| 238 | if (section.sh_type == SHT_NULL) continue; | |
| 239 | ||
| 240 | const name_offset = elf.string_section.offset + section.name; | |
| 241 | %return elf.in_stream.seekTo(name_offset); | |
| 242 | ||
| 243 | for (name) |expected_c| { | |
| 244 | const target_c = %return elf.in_stream.readByte(); | |
| 245 | if (target_c == 0 || expected_c != target_c) goto next_section; | |
| 246 | } | |
| 247 | ||
| 248 | const null_byte = %return elf.in_stream.readByte(); | |
| 249 | if (null_byte == 0) return (?&SectionHeader)(section); | |
| 250 | ||
| 251 | next_section: | |
| 252 | } | |
| 253 | ||
| 254 | const null_sh: ?&SectionHeader = null; | |
| 255 | return null_sh; | |
| 256 | } | |
| 257 | ||
| 258 | pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void { | |
| 259 | %return elf.in_stream.seekTo(section.offset); | |
| 260 | } | |
| 261 | } |
std/endian.zig created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | pub inline fn swapIfLe(inline T: type, x: T) -> T { | |
| 2 | swapIf(false, T, x) | |
| 3 | } | |
| 4 | ||
| 5 | pub inline fn swapIfBe(inline T: type, x: T) -> T { | |
| 6 | swapIf(true, T, x) | |
| 7 | } | |
| 8 | ||
| 9 | pub inline fn swapIf(is_be: bool, inline T: type, x: T) -> T { | |
| 10 | if (@compileVar("is_big_endian") == is_be) swap(T, x) else x | |
| 11 | } | |
| 12 | ||
| 13 | pub fn swap(inline T: type, x: T) -> T { | |
| 14 | const x_slice = ([]u8)((&const x)[0...1]); | |
| 15 | var result: T = undefined; | |
| 16 | const result_slice = ([]u8)((&result)[0...1]); | |
| 17 | for (result_slice) |*b, i| { | |
| 18 | *b = x_slice[@sizeOf(T) - i - 1]; | |
| 19 | } | |
| 20 | return result; | |
| 21 | } |
std/io.zig+118-24| ... | ... | @@ -1,6 +1,9 @@ |
| 1 | 1 | const linux = @import("linux.zig"); |
| 2 | 2 | const errno = @import("errno.zig"); |
| 3 | 3 | const math = @import("math.zig"); |
| 4 | const endian = @import("endian.zig"); | |
| 5 | const debug = @import("debug.zig"); | |
| 6 | const assert = debug.assert; | |
| 4 | 7 | |
| 5 | 8 | pub const stdin_fileno = 0; |
| 6 | 9 | pub const stdout_fileno = 1; |
| ... | ... | @@ -8,6 +11,7 @@ pub const stderr_fileno = 2; |
| 8 | 11 | |
| 9 | 12 | pub var stdin = InStream { |
| 10 | 13 | .fd = stdin_fileno, |
| 14 | .offset = 0, | |
| 11 | 15 | }; |
| 12 | 16 | |
| 13 | 17 | pub var stdout = OutStream { |
| ... | ... | @@ -33,6 +37,8 @@ pub error Unexpected; |
| 33 | 37 | |
| 34 | 38 | pub error DiskQuota; |
| 35 | 39 | pub error FileTooBig; |
| 40 | // TODO hide interrupts at this layer by retrying. Users can use the linux specific APIs if they | |
| 41 | // want to handle interrupts. | |
| 36 | 42 | pub error SigInterrupt; |
| 37 | 43 | pub error Io; |
| 38 | 44 | pub error NoSpaceLeft; |
| ... | ... | @@ -48,6 +54,8 @@ pub error NameTooLong; |
| 48 | 54 | pub error NoDevice; |
| 49 | 55 | pub error PathNotFound; |
| 50 | 56 | pub error NoMem; |
| 57 | pub error Unseekable; | |
| 58 | pub error Eof; | |
| 51 | 59 | |
| 52 | 60 | const buffer_size = 4 * 1024; |
| 53 | 61 | const max_u64_base10_digits = 20; |
| ... | ... | @@ -137,14 +145,18 @@ pub struct OutStream { |
| 137 | 145 | } |
| 138 | 146 | } |
| 139 | 147 | |
| 148 | // TODO created a BufferedInStream struct and move some of this code there | |
| 149 | // BufferedInStream API goes on top of minimal InStream API. | |
| 140 | 150 | pub struct InStream { |
| 141 | 151 | fd: i32, |
| 142 | ||
| 143 | pub fn open(path: []u8) -> %InStream { | |
| 144 | const fd = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0); | |
| 145 | const fd_err = linux.getErrno(fd); | |
| 146 | if (fd_err > 0) { | |
| 147 | return switch (fd_err) { | |
| 152 | offset: usize, | |
| 153 | ||
| 154 | /// Call close to clean up. | |
| 155 | pub fn open(is: &InStream, path: []const u8) -> %void { | |
| 156 | const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0); | |
| 157 | const err = linux.getErrno(result); | |
| 158 | if (err > 0) { | |
| 159 | return switch (err) { | |
| 148 | 160 | errno.EFAULT => unreachable{}, |
| 149 | 161 | errno.EINVAL => unreachable{}, |
| 150 | 162 | errno.EACCES => error.BadPerm, |
| ... | ... | @@ -164,24 +176,8 @@ pub struct InStream { |
| 164 | 176 | else => error.Unexpected, |
| 165 | 177 | } |
| 166 | 178 | } |
| 167 | ||
| 168 | return InStream { .fd = i32(fd), }; | |
| 169 | } | |
| 170 | ||
| 171 | pub fn read(is: &InStream, buf: []u8) -> %usize { | |
| 172 | const amt_read = linux.read(is.fd, &buf[0], buf.len); | |
| 173 | const read_err = linux.getErrno(amt_read); | |
| 174 | if (read_err > 0) { | |
| 175 | return switch (read_err) { | |
| 176 | errno.EINVAL => unreachable{}, | |
| 177 | errno.EFAULT => unreachable{}, | |
| 178 | errno.EBADF => error.BadFd, | |
| 179 | errno.EINTR => error.SigInterrupt, | |
| 180 | errno.EIO => error.Io, | |
| 181 | else => error.Unexpected, | |
| 182 | } | |
| 183 | } | |
| 184 | return amt_read; | |
| 179 | is.fd = i32(result); | |
| 180 | is.offset = 0; | |
| 185 | 181 | } |
| 186 | 182 | |
| 187 | 183 | pub fn close(is: &InStream) -> %void { |
| ... | ... | @@ -196,6 +192,95 @@ pub struct InStream { |
| 196 | 192 | } |
| 197 | 193 | } |
| 198 | 194 | } |
| 195 | ||
| 196 | /// Returns the number of bytes read. If the number read is smaller than buf.len, then | |
| 197 | /// the stream reached End Of File. | |
| 198 | pub fn read(is: &InStream, buf: []u8) -> %usize { | |
| 199 | switch (@compileVar("os")) { | |
| 200 | linux => { | |
| 201 | while (true) { | |
| 202 | const amt_read = linux.pread(is.fd, buf.ptr, buf.len, is.offset); | |
| 203 | const read_err = linux.getErrno(amt_read); | |
| 204 | if (read_err > 0) { | |
| 205 | switch (read_err) { | |
| 206 | errno.EINTR => continue, | |
| 207 | errno.EINVAL => unreachable{}, | |
| 208 | errno.EFAULT => unreachable{}, | |
| 209 | errno.EBADF => return error.BadFd, | |
| 210 | errno.EIO => return error.Io, | |
| 211 | else => return error.Unexpected, | |
| 212 | } | |
| 213 | } | |
| 214 | is.offset += amt_read; | |
| 215 | return amt_read; | |
| 216 | } | |
| 217 | }, | |
| 218 | else => @compileErr("unsupported OS"), | |
| 219 | } | |
| 220 | } | |
| 221 | ||
| 222 | pub fn readNoEof(is: &InStream, buf: []u8) -> %void { | |
| 223 | const amt_read = %return is.read(buf); | |
| 224 | if (amt_read < buf.len) return error.Eof; | |
| 225 | } | |
| 226 | ||
| 227 | pub fn readByte(is: &InStream) -> %u8 { | |
| 228 | var result: [1]u8 = undefined; | |
| 229 | %return is.readNoEof(result); | |
| 230 | return result[0]; | |
| 231 | } | |
| 232 | ||
| 233 | pub inline fn readIntLe(is: &InStream, inline T: type) -> %T { | |
| 234 | is.readInt(false, T) | |
| 235 | } | |
| 236 | ||
| 237 | pub inline fn readIntBe(is: &InStream, inline T: type) -> %T { | |
| 238 | is.readInt(true, T) | |
| 239 | } | |
| 240 | ||
| 241 | pub inline fn readInt(is: &InStream, is_be: bool, inline T: type) -> %T { | |
| 242 | var result: T = undefined; | |
| 243 | const result_slice = ([]u8)((&result)[0...1]); | |
| 244 | %return is.readNoEof(result_slice); | |
| 245 | return endian.swapIf(!is_be, T, result); | |
| 246 | } | |
| 247 | ||
| 248 | pub inline fn readVarInt(is: &InStream, is_be: bool, inline T: type, size: usize) -> %T { | |
| 249 | var result: T = zeroes; | |
| 250 | const result_slice = ([]u8)((&result)[0...1]); | |
| 251 | const padding = @sizeOf(T) - size; | |
| 252 | {var i: usize = 0; while (i < size; i += 1) { | |
| 253 | const index = if (is_be == @compileVar("is_big_endian")) { | |
| 254 | padding + i | |
| 255 | } else { | |
| 256 | result_slice.len - i - 1 - padding | |
| 257 | }; | |
| 258 | result_slice[index] = %return is.readByte(); | |
| 259 | }} | |
| 260 | return result; | |
| 261 | } | |
| 262 | ||
| 263 | pub fn seekForward(is: &InStream, amount: usize) -> %void { | |
| 264 | is.offset += amount; | |
| 265 | } | |
| 266 | ||
| 267 | pub fn seekTo(is: &InStream, pos: usize) -> %void { | |
| 268 | is.offset = pos; | |
| 269 | } | |
| 270 | ||
| 271 | pub fn endPos(is: &InStream) -> %usize { | |
| 272 | var stat: linux.stat = undefined; | |
| 273 | const err = linux.getErrno(linux.fstat(is.fd, &stat)); | |
| 274 | if (err > 0) { | |
| 275 | return switch (err) { | |
| 276 | errno.EBADF => error.BadFd, | |
| 277 | errno.ENOMEM => error.NoMem, | |
| 278 | else => error.Unexpected, | |
| 279 | } | |
| 280 | } | |
| 281 | ||
| 282 | return usize(stat.size); | |
| 283 | } | |
| 199 | 284 | } |
| 200 | 285 | |
| 201 | 286 | pub fn parseUnsigned(inline T: type, buf: []u8, radix: u8) -> %T { |
| ... | ... | @@ -267,3 +352,12 @@ fn parseU64DigitTooBig() { |
| 267 | 352 | }; |
| 268 | 353 | unreachable{}; |
| 269 | 354 | } |
| 355 | ||
| 356 | pub fn openSelfExe(stream: &InStream) -> %void { | |
| 357 | switch (@compileVar("os")) { | |
| 358 | linux => { | |
| 359 | %return stream.open("/proc/self/exe"); | |
| 360 | }, | |
| 361 | else => @compileErr("unsupported os"), | |
| 362 | } | |
| 363 | } |
std/linux.zig+40-7| ... | ... | @@ -76,6 +76,10 @@ pub const O_PATH = arch.O_PATH; |
| 76 | 76 | pub const O_TMPFILE = arch.O_TMPFILE; |
| 77 | 77 | pub const O_NDELAY = arch.O_NDELAY; |
| 78 | 78 | |
| 79 | pub const SEEK_SET = 0; | |
| 80 | pub const SEEK_CUR = 1; | |
| 81 | pub const SEEK_END = 2; | |
| 82 | ||
| 79 | 83 | const SIG_BLOCK = 0; |
| 80 | 84 | const SIG_UNBLOCK = 1; |
| 81 | 85 | const SIG_SETMASK = 2; |
| ... | ... | @@ -226,7 +230,9 @@ pub fn getErrno(r: usize) -> usize { |
| 226 | 230 | if (signed_r > -4096 && signed_r < 0) usize(-signed_r) else 0 |
| 227 | 231 | } |
| 228 | 232 | |
| 229 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize) -> usize { | |
| 233 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize) | |
| 234 | -> usize | |
| 235 | { | |
| 230 | 236 | arch.syscall6(arch.SYS_mmap, usize(address), length, prot, flags, usize(fd), offset) |
| 231 | 237 | } |
| 232 | 238 | |
| ... | ... | @@ -238,29 +244,49 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize { |
| 238 | 244 | arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count) |
| 239 | 245 | } |
| 240 | 246 | |
| 247 | pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize { | |
| 248 | arch.syscall4(arch.SYS_pread, usize(fd), usize(buf), count, offset) | |
| 249 | } | |
| 250 | ||
| 241 | 251 | pub fn write(fd: i32, buf: &const u8, count: usize) -> usize { |
| 242 | 252 | arch.syscall3(arch.SYS_write, usize(fd), usize(buf), count) |
| 243 | 253 | } |
| 244 | 254 | |
| 245 | pub fn open(path: []u8, flags: usize, perm: usize) -> usize { | |
| 255 | pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize { | |
| 256 | arch.syscall4(arch.SYS_pwrite, usize(fd), usize(buf), count, offset) | |
| 257 | } | |
| 258 | ||
| 259 | pub fn open_c(path: &const u8, flags: usize, perm: usize) -> usize { | |
| 260 | arch.syscall3(arch.SYS_open, usize(path), flags, perm) | |
| 261 | } | |
| 262 | ||
| 263 | pub fn open(path: []const u8, flags: usize, perm: usize) -> usize { | |
| 246 | 264 | var buf: [path.len + 1]u8 = undefined; |
| 247 | 265 | @memcpy(&buf[0], &path[0], path.len); |
| 248 | 266 | buf[path.len] = 0; |
| 249 | arch.syscall3(arch.SYS_open, usize(&buf[0]), flags, perm) | |
| 267 | return open_c(buf.ptr, flags, perm); | |
| 250 | 268 | } |
| 251 | 269 | |
| 252 | pub fn create(path: []u8, perm: usize) -> usize { | |
| 270 | pub fn create_c(path: &const u8, perm: usize) -> usize { | |
| 271 | arch.syscall2(arch.SYS_creat, usize(path), perm) | |
| 272 | } | |
| 273 | ||
| 274 | pub fn create(path: []const u8, perm: usize) -> usize { | |
| 253 | 275 | var buf: [path.len + 1]u8 = undefined; |
| 254 | 276 | @memcpy(&buf[0], &path[0], path.len); |
| 255 | 277 | buf[path.len] = 0; |
| 256 | arch.syscall2(arch.SYS_creat, usize(&buf[0]), perm) | |
| 278 | return create_c(buf.ptr, perm); | |
| 279 | } | |
| 280 | ||
| 281 | pub fn openat_c(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize { | |
| 282 | arch.syscall4(arch.SYS_openat, usize(dirfd), usize(path), flags, mode) | |
| 257 | 283 | } |
| 258 | 284 | |
| 259 | pub fn openat(dirfd: i32, path: []u8, flags: usize, mode: usize) -> usize { | |
| 285 | pub fn openat(dirfd: i32, path: []const u8, flags: usize, mode: usize) -> usize { | |
| 260 | 286 | var buf: [path.len + 1]u8 = undefined; |
| 261 | 287 | @memcpy(&buf[0], &path[0], path.len); |
| 262 | 288 | buf[path.len] = 0; |
| 263 | arch.syscall4(arch.SYS_openat, usize(dirfd), usize(&buf[0]), flags, mode) | |
| 289 | return openat_c(dirfd, buf.ptr, flags, mode); | |
| 264 | 290 | } |
| 265 | 291 | |
| 266 | 292 | pub fn close(fd: i32) -> usize { |
| ... | ... | @@ -457,3 +483,10 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: |
| 457 | 483 | // } |
| 458 | 484 | // return ifr.ifr_ifindex; |
| 459 | 485 | // } |
| 486 | ||
| 487 | pub const stat = arch.stat; | |
| 488 | pub const timespec = arch.timespec; | |
| 489 | ||
| 490 | pub fn fstat(fd: i32, stat_buf: &stat) -> usize { | |
| 491 | arch.syscall2(arch.SYS_fstat, usize(fd), usize(stat_buf)) | |
| 492 | } |
std/linux_x86_64.zig+27-2| ... | ... | @@ -19,8 +19,8 @@ pub const SYS_rt_sigaction = 13; |
| 19 | 19 | pub const SYS_rt_sigprocmask = 14; |
| 20 | 20 | pub const SYS_rt_sigreturn = 15; |
| 21 | 21 | pub const SYS_ioctl = 16; |
| 22 | pub const SYS_pread64 = 17; | |
| 23 | pub const SYS_pwrite64 = 18; | |
| 22 | pub const SYS_pread = 17; | |
| 23 | pub const SYS_pwrite = 18; | |
| 24 | 24 | pub const SYS_readv = 19; |
| 25 | 25 | pub const SYS_writev = 20; |
| 26 | 26 | pub const SYS_access = 21; |
| ... | ... | @@ -453,3 +453,28 @@ export struct msghdr { |
| 453 | 453 | __pad2: socklen_t, |
| 454 | 454 | msg_flags: i32, |
| 455 | 455 | } |
| 456 | ||
| 457 | export struct stat { | |
| 458 | dev: u64, | |
| 459 | ino: u64, | |
| 460 | nlink: usize, | |
| 461 | ||
| 462 | mode: u32, | |
| 463 | uid: u32, | |
| 464 | gid: u32, | |
| 465 | __pad0: u32, | |
| 466 | rdev: u64, | |
| 467 | size: i64, | |
| 468 | blksize: isize, | |
| 469 | blocks: i64, | |
| 470 | ||
| 471 | atim: timespec, | |
| 472 | mtim: timespec, | |
| 473 | ctim: timespec, | |
| 474 | __unused: [3]isize, | |
| 475 | } | |
| 476 | ||
| 477 | export struct timespec { | |
| 478 | tv_sec: isize, | |
| 479 | tv_nsec: isize, | |
| 480 | } |
std/net.zig+4-17| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const linux = @import("linux.zig"); |
| 2 | 2 | const errno = @import("errno.zig"); |
| 3 | 3 | const assert = @import("debug.zig").assert; |
| 4 | const endian = @import("endian.zig"); | |
| 4 | 5 | |
| 5 | 6 | pub error SigInterrupt; |
| 6 | 7 | pub error Unexpected; |
| ... | ... | @@ -99,14 +100,14 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection { |
| 99 | 100 | const connect_ret = if (addr.family == linux.AF_INET) { |
| 100 | 101 | var os_addr: linux.sockaddr_in = undefined; |
| 101 | 102 | os_addr.family = addr.family; |
| 102 | os_addr.port = swapIfLittleEndian(u16, port); | |
| 103 | os_addr.port = endian.swapIfLe(u16, port); | |
| 103 | 104 | @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4); |
| 104 | 105 | @memset(&os_addr.zero, 0, @sizeOf(@typeOf(os_addr.zero))); |
| 105 | 106 | linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in)) |
| 106 | 107 | } else if (addr.family == linux.AF_INET6) { |
| 107 | 108 | var os_addr: linux.sockaddr_in6 = undefined; |
| 108 | 109 | os_addr.family = addr.family; |
| 109 | os_addr.port = swapIfLittleEndian(u16, port); | |
| 110 | os_addr.port = endian.swapIfLe(u16, port); | |
| 110 | 111 | os_addr.flowinfo = 0; |
| 111 | 112 | os_addr.scope_id = addr.scope_id; |
| 112 | 113 | @memcpy(&os_addr.addr[0], &addr.addr[0], 16); |
| ... | ... | @@ -319,7 +320,7 @@ fn parseIp4(buf: []const u8) -> %u32 { |
| 319 | 320 | |
| 320 | 321 | #attribute("test") |
| 321 | 322 | fn testParseIp4() { |
| 322 | assert(%%parseIp4("127.0.0.1") == swapIfLittleEndian(u32, 0x7f000001)); | |
| 323 | assert(%%parseIp4("127.0.0.1") == endian.swapIfLe(u32, 0x7f000001)); | |
| 323 | 324 | switch (parseIp4("256.0.0.1")) { Overflow => {}, else => unreachable {}, } |
| 324 | 325 | switch (parseIp4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, } |
| 325 | 326 | switch (parseIp4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, } |
| ... | ... | @@ -351,17 +352,3 @@ fn testLookupSimpleIp() { |
| 351 | 352 | assert(addr.addr[3] == 1); |
| 352 | 353 | } |
| 353 | 354 | } |
| 354 | ||
| 355 | fn swapIfLittleEndian(inline T: type, x: T) -> T { | |
| 356 | if (@compileVar("is_big_endian")) x else endianSwap(T, x) | |
| 357 | } | |
| 358 | ||
| 359 | fn endianSwap(inline T: type, x: T) -> T { | |
| 360 | const x_slice = ([]u8)((&const x)[0...1]); | |
| 361 | var result: T = undefined; | |
| 362 | const result_slice = ([]u8)((&result)[0...1]); | |
| 363 | for (result_slice) |*b, i| { | |
| 364 | *b = x_slice[@sizeOf(T) - i - 1]; | |
| 365 | } | |
| 366 | return result; | |
| 367 | } |
std/os.zig+10-6| ... | ... | @@ -4,7 +4,7 @@ const errno = @import("errno.zig"); |
| 4 | 4 | pub error SigInterrupt; |
| 5 | 5 | pub error Unexpected; |
| 6 | 6 | |
| 7 | pub fn get_random_bytes(buf: []u8) -> %void { | |
| 7 | pub fn getRandomBytes(buf: []u8) -> %void { | |
| 8 | 8 | switch (@compileVar("os")) { |
| 9 | 9 | linux => { |
| 10 | 10 | const ret = linux.getrandom(buf.ptr, buf.len, 0); |
| ... | ... | @@ -18,14 +18,18 @@ pub fn get_random_bytes(buf: []u8) -> %void { |
| 18 | 18 | } |
| 19 | 19 | } |
| 20 | 20 | }, |
| 21 | else => @compile_err("unsupported os"), | |
| 21 | else => @compileErr("unsupported os"), | |
| 22 | 22 | } |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | #attribute("cold") |
| 26 | 26 | pub fn abort() -> unreachable { |
| 27 | linux.raise(linux.SIGABRT); | |
| 28 | linux.raise(linux.SIGKILL); | |
| 29 | while (true) {} | |
| 27 | switch (@compileVar("os")) { | |
| 28 | linux => { | |
| 29 | linux.raise(linux.SIGABRT); | |
| 30 | linux.raise(linux.SIGKILL); | |
| 31 | while (true) {} | |
| 32 | }, | |
| 33 | else => @compileErr("unsupported os"), | |
| 34 | } | |
| 30 | 35 | } |
| 31 |
std/rand.zig+1-1| ... | ... | @@ -87,7 +87,7 @@ pub struct Rand { |
| 87 | 87 | } else if (T == f64) { |
| 88 | 88 | 9007199254740992 |
| 89 | 89 | } else { |
| 90 | @compile_err("unknown floating point type" ++ @typeName(T)) | |
| 90 | @compileErr("unknown floating point type" ++ @typeName(T)) | |
| 91 | 91 | }; |
| 92 | 92 | return T(r.rangeUnsigned(int_type, 0, precision)) / T(precision); |
| 93 | 93 | } |