authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-17 20:11:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-17 20:11:04-07:00
loged50bd1b655ff028bdd650edecdcdd6675f1dee0
tree18bab13e2631f2ec55fdd5447baa7134c282e4a4
parent0fbb9e09ea89ea24ec214b244e1de9574516c74c

progress toward stack trace printing


18 files changed, 676 insertions(+), 84 deletions(-)

CMakeLists.txt+18-16
...@@ -200,27 +200,29 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})...@@ -200,27 +200,29 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
200install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}")200install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}")
201install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}")201install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}")
202install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}")202install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}")
203install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}")
204install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_libc.zig" DESTINATION "${ZIG_STD_DEST}")
205install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_nolibc.zig" DESTINATION "${ZIG_STD_DEST}")
206install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")
207install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}")
208install(FILES "${CMAKE_SOURCE_DIR}/std/os.zig" DESTINATION "${ZIG_STD_DEST}")
209install(FILES "${CMAKE_SOURCE_DIR}/std/str.zig" DESTINATION "${ZIG_STD_DEST}")
210install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")203install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
211install(FILES "${CMAKE_SOURCE_DIR}/std/linux.zig" DESTINATION "${ZIG_STD_DEST}")204install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}")
205install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}")
206install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}")
207install(FILES "${CMAKE_SOURCE_DIR}/std/endian.zig" DESTINATION "${ZIG_STD_DEST}")
212install(FILES "${CMAKE_SOURCE_DIR}/std/errno.zig" DESTINATION "${ZIG_STD_DEST}")208install(FILES "${CMAKE_SOURCE_DIR}/std/errno.zig" DESTINATION "${ZIG_STD_DEST}")
213install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")209install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")
214install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
215install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
216install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")210install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")
217install(FILES "${CMAKE_SOURCE_DIR}/std/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}")211install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")
212install(FILES "${CMAKE_SOURCE_DIR}/std/linux.zig" DESTINATION "${ZIG_STD_DEST}")
218install(FILES "${CMAKE_SOURCE_DIR}/std/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}")213install(FILES "${CMAKE_SOURCE_DIR}/std/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}")
219install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")214install(FILES "${CMAKE_SOURCE_DIR}/std/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}")
220install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}")215install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}")
221install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")216install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
222install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}")217install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")
223install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}")218install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}")
219install(FILES "${CMAKE_SOURCE_DIR}/std/os.zig" DESTINATION "${ZIG_STD_DEST}")
220install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
221install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
222install(FILES "${CMAKE_SOURCE_DIR}/std/str.zig" DESTINATION "${ZIG_STD_DEST}")
223install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}")
224install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_libc.zig" DESTINATION "${ZIG_STD_DEST}")
225install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_nolibc.zig" DESTINATION "${ZIG_STD_DEST}")
224226
225add_executable(run_tests ${TEST_SOURCES})227add_executable(run_tests ${TEST_SOURCES})
226target_link_libraries(run_tests)228target_link_libraries(run_tests)
doc/style.md+1-1
...@@ -62,7 +62,7 @@ const xml_document =...@@ -62,7 +62,7 @@ const xml_document =
62 \\<?xml version="1.0" encoding="UTF-8"?>62 \\<?xml version="1.0" encoding="UTF-8"?>
63 \\<document>63 \\<document>
64 \\</document>64 \\</document>
65 ;65;
66struct XmlParser {}66struct XmlParser {}
6767
68// The initials BE (Big Endian) are just another word in Zig identifier names.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,7 +14,8 @@ pub fn main(args: [][]u8) -> %void {
14 } else if (arg[0] == '-') {14 } else if (arg[0] == '-') {
15 return usage(exe);15 return usage(exe);
16 } else {16 } else {
17 var is = io.InStream.open(arg) %% |err| {17 var is: io.InStream = undefined;
18 is.open(arg) %% |err| {
18 %%io.stderr.printf("Unable to open file: ");19 %%io.stderr.printf("Unable to open file: ");
19 %%io.stderr.printf(@errName(err));20 %%io.stderr.printf(@errName(err));
20 %%io.stderr.printf("\n");21 %%io.stderr.printf("\n");
example/guess_number/main.zig+1-1
...@@ -7,7 +7,7 @@ pub fn main(args: [][]u8) -> %void {...@@ -7,7 +7,7 @@ pub fn main(args: [][]u8) -> %void {
7 %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");7 %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");
88
9 var seed: [@sizeOf(usize)]u8 = undefined;9 var seed: [@sizeOf(usize)]u8 = undefined;
10 %%os.get_random_bytes(seed);10 %%os.getRandomBytes(seed);
11 var rand: Rand = undefined;11 var rand: Rand = undefined;
12 rand.init(([]usize)(seed)[0]);12 rand.init(([]usize)(seed)[0]);
1313
src/all_types.hpp+2
...@@ -1232,6 +1232,7 @@ struct CodeGen {...@@ -1232,6 +1232,7 @@ struct CodeGen {
1232 TypeTableEntry *entry_os_enum;1232 TypeTableEntry *entry_os_enum;
1233 TypeTableEntry *entry_arch_enum;1233 TypeTableEntry *entry_arch_enum;
1234 TypeTableEntry *entry_environ_enum;1234 TypeTableEntry *entry_environ_enum;
1235 TypeTableEntry *entry_oformat_enum;
1235 TypeTableEntry *entry_atomic_order_enum;1236 TypeTableEntry *entry_atomic_order_enum;
1236 } builtin_types;1237 } builtin_types;
12371238
...@@ -1256,6 +1257,7 @@ struct CodeGen {...@@ -1256,6 +1257,7 @@ struct CodeGen {
1256 uint32_t target_os_index;1257 uint32_t target_os_index;
1257 uint32_t target_arch_index;1258 uint32_t target_arch_index;
1258 uint32_t target_environ_index;1259 uint32_t target_environ_index;
1260 uint32_t target_oformat_index;
1259 LLVMTargetMachineRef target_machine;1261 LLVMTargetMachineRef target_machine;
1260 LLVMZigDIFile *dummy_di_file;1262 LLVMZigDIFile *dummy_di_file;
1261 bool is_native_target;1263 bool is_native_target;
src/analyze.cpp+3
...@@ -5296,6 +5296,9 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -5296,6 +5296,9 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
5296 } else if (buf_eql_str(var_name, "environ")) {5296 } else if (buf_eql_str(var_name, "environ")) {
5297 const_val->data.x_enum.tag = g->target_environ_index;5297 const_val->data.x_enum.tag = g->target_environ_index;
5298 return g->builtin_types.entry_environ_enum;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 } else {5302 } else {
5300 add_node_error(g, *str_node,5303 add_node_error(g, *str_node,
5301 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));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,6 +4576,33 @@ static void define_builtin_types(CodeGen *g) {
4576 g->builtin_types.entry_environ_enum = entry;4576 g->builtin_types.entry_environ_enum = entry;
4577 }4577 }
45784578
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 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);4607 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
4581 entry->deep_const = true;4608 entry->deep_const = true;
src/target.cpp+25
...@@ -137,6 +137,31 @@ static const ZigLLVM_EnvironmentType environ_list[] = {...@@ -137,6 +137,31 @@ static const ZigLLVM_EnvironmentType environ_list[] = {
137 ZigLLVM_CoreCLR,137 ZigLLVM_CoreCLR,
138};138};
139139
140static const ZigLLVM_ObjectFormatType oformat_list[] = {
141 ZigLLVM_UnknownObjectFormat,
142 ZigLLVM_COFF,
143 ZigLLVM_ELF,
144 ZigLLVM_MachO,
145};
146
147int target_oformat_count(void) {
148 return array_length(oformat_list);
149}
150
151const ZigLLVM_ObjectFormatType get_target_oformat(int index) {
152 return oformat_list[index];
153}
154
155const 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
140int target_arch_count(void) {165int target_arch_count(void) {
141 return array_length(arch_list);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,6 +52,11 @@ const char *get_target_os_name(ZigLLVM_OSType os_type);
52int target_environ_count(void);52int target_environ_count(void);
53ZigLLVM_EnvironmentType get_target_environ(int index);53ZigLLVM_EnvironmentType get_target_environ(int index);
5454
55
56int target_oformat_count(void);
57const ZigLLVM_ObjectFormatType get_target_oformat(int index);
58const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat);
59
55void get_native_target(ZigTarget *target);60void get_native_target(ZigTarget *target);
56void get_unknown_target(ZigTarget *target);61void get_unknown_target(ZigTarget *target);
5762
std/debug.zig+110-8
...@@ -1,21 +1,123 @@...@@ -1,21 +1,123 @@
1const Allocator = @import("mem.zig").Allocator;1const Allocator = @import("mem.zig").Allocator;
2const io = @import("io.zig");2const io = @import("io.zig");
3const os = @import("os.zig");
4const elf = @import("elf.zig");
5
6pub error MissingDebugInfo;
7pub error InvalidDebugInfo;
8pub error UnsupportedDebugInfo;
39
4pub fn assert(b: bool) {10pub fn assert(b: bool) {
5 if (!b) unreachable{}11 if (!b) unreachable{}
6}12}
713
8pub fn printStackTrace() {14pub fn printStackTrace() -> %void {
9 var maybe_fp: ?&const u8 = @frameAddress();15 %return writeStackTrace(&io.stderr);
10 while (true) {16 %return io.stderr.flush();
11 const fp = maybe_fp ?? break;17}
12 const return_address = *(&const usize)(usize(fp) + @sizeOf(usize));18
13 %%io.stderr.printInt(usize, return_address);19pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
14 %%io.stderr.printf("\n");20 switch (@compileVar("object_format")) {
15 maybe_fp = *(&const ?&const u8)(fp);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}
1857
58struct ElfStackTrace {
59 self_exe_stream: io.InStream,
60 elf: elf.Elf,
61 aranges: ?&elf.SectionHeader,
62}
63
64fn 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
19pub var global_allocator = Allocator {121pub var global_allocator = Allocator {
20 .allocFn = globalAlloc,122 .allocFn = globalAlloc,
21 .reallocFn = globalRealloc,123 .reallocFn = globalRealloc,
std/elf.zig created+261
...@@ -0,0 +1,261 @@
1const io = @import("io.zig");
2const str = @import("str.zig");
3const math = @import("math.zig");
4const mem = @import("mem.zig");
5const debug = @import("debug.zig");
6
7pub error InvalidFormat;
8
9pub const SHT_NULL = 0;
10pub const SHT_PROGBITS = 1;
11pub const SHT_SYMTAB = 2;
12pub const SHT_STRTAB = 3;
13pub const SHT_RELA = 4;
14pub const SHT_HASH = 5;
15pub const SHT_DYNAMIC = 6;
16pub const SHT_NOTE = 7;
17pub const SHT_NOBITS = 8;
18pub const SHT_REL = 9;
19pub const SHT_SHLIB = 10;
20pub const SHT_DYNSYM = 11;
21pub const SHT_INIT_ARRAY = 14;
22pub const SHT_FINI_ARRAY = 15;
23pub const SHT_PREINIT_ARRAY = 16;
24pub const SHT_GROUP = 17;
25pub const SHT_SYMTAB_SHNDX = 18;
26pub const SHT_LOOS = 0x60000000;
27pub const SHT_HIOS = 0x6fffffff;
28pub const SHT_LOPROC = 0x70000000;
29pub const SHT_HIPROC = 0x7fffffff;
30pub const SHT_LOUSER = 0x80000000;
31pub const SHT_HIUSER = 0xffffffff;
32
33pub enum FileType {
34 Relocatable,
35 Executable,
36 Shared,
37 Core,
38}
39
40pub enum Arch {
41 Sparc,
42 x86,
43 Mips,
44 PowerPc,
45 Arm,
46 SuperH,
47 IA_64,
48 x86_64,
49 AArch64,
50}
51
52pub 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
65pub 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 @@
1pub inline fn swapIfLe(inline T: type, x: T) -> T {
2 swapIf(false, T, x)
3}
4
5pub inline fn swapIfBe(inline T: type, x: T) -> T {
6 swapIf(true, T, x)
7}
8
9pub 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
13pub 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,6 +1,9 @@
1const linux = @import("linux.zig");1const linux = @import("linux.zig");
2const errno = @import("errno.zig");2const errno = @import("errno.zig");
3const math = @import("math.zig");3const math = @import("math.zig");
4const endian = @import("endian.zig");
5const debug = @import("debug.zig");
6const assert = debug.assert;
47
5pub const stdin_fileno = 0;8pub const stdin_fileno = 0;
6pub const stdout_fileno = 1;9pub const stdout_fileno = 1;
...@@ -8,6 +11,7 @@ pub const stderr_fileno = 2;...@@ -8,6 +11,7 @@ pub const stderr_fileno = 2;
811
9pub var stdin = InStream {12pub var stdin = InStream {
10 .fd = stdin_fileno,13 .fd = stdin_fileno,
14 .offset = 0,
11};15};
1216
13pub var stdout = OutStream {17pub var stdout = OutStream {
...@@ -33,6 +37,8 @@ pub error Unexpected;...@@ -33,6 +37,8 @@ pub error Unexpected;
3337
34pub error DiskQuota;38pub error DiskQuota;
35pub error FileTooBig;39pub 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.
36pub error SigInterrupt;42pub error SigInterrupt;
37pub error Io;43pub error Io;
38pub error NoSpaceLeft;44pub error NoSpaceLeft;
...@@ -48,6 +54,8 @@ pub error NameTooLong;...@@ -48,6 +54,8 @@ pub error NameTooLong;
48pub error NoDevice;54pub error NoDevice;
49pub error PathNotFound;55pub error PathNotFound;
50pub error NoMem;56pub error NoMem;
57pub error Unseekable;
58pub error Eof;
5159
52const buffer_size = 4 * 1024;60const buffer_size = 4 * 1024;
53const max_u64_base10_digits = 20;61const max_u64_base10_digits = 20;
...@@ -137,14 +145,18 @@ pub struct OutStream {...@@ -137,14 +145,18 @@ pub struct OutStream {
137 }145 }
138}146}
139147
148// TODO created a BufferedInStream struct and move some of this code there
149// BufferedInStream API goes on top of minimal InStream API.
140pub struct InStream {150pub struct InStream {
141 fd: i32,151 fd: i32,
142152 offset: usize,
143 pub fn open(path: []u8) -> %InStream {153
144 const fd = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);154 /// Call close to clean up.
145 const fd_err = linux.getErrno(fd);155 pub fn open(is: &InStream, path: []const u8) -> %void {
146 if (fd_err > 0) {156 const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
147 return switch (fd_err) {157 const err = linux.getErrno(result);
158 if (err > 0) {
159 return switch (err) {
148 errno.EFAULT => unreachable{},160 errno.EFAULT => unreachable{},
149 errno.EINVAL => unreachable{},161 errno.EINVAL => unreachable{},
150 errno.EACCES => error.BadPerm,162 errno.EACCES => error.BadPerm,
...@@ -164,24 +176,8 @@ pub struct InStream {...@@ -164,24 +176,8 @@ pub struct InStream {
164 else => error.Unexpected,176 else => error.Unexpected,
165 }177 }
166 }178 }
167179 is.fd = i32(result);
168 return InStream { .fd = i32(fd), };180 is.offset = 0;
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;
185 }181 }
186182
187 pub fn close(is: &InStream) -> %void {183 pub fn close(is: &InStream) -> %void {
...@@ -196,6 +192,95 @@ pub struct InStream {...@@ -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}
200285
201pub fn parseUnsigned(inline T: type, buf: []u8, radix: u8) -> %T {286pub fn parseUnsigned(inline T: type, buf: []u8, radix: u8) -> %T {
...@@ -267,3 +352,12 @@ fn parseU64DigitTooBig() {...@@ -267,3 +352,12 @@ fn parseU64DigitTooBig() {
267 };352 };
268 unreachable{};353 unreachable{};
269}354}
355
356pub 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,6 +76,10 @@ pub const O_PATH = arch.O_PATH;
76pub const O_TMPFILE = arch.O_TMPFILE;76pub const O_TMPFILE = arch.O_TMPFILE;
77pub const O_NDELAY = arch.O_NDELAY;77pub const O_NDELAY = arch.O_NDELAY;
7878
79pub const SEEK_SET = 0;
80pub const SEEK_CUR = 1;
81pub const SEEK_END = 2;
82
79const SIG_BLOCK = 0;83const SIG_BLOCK = 0;
80const SIG_UNBLOCK = 1;84const SIG_UNBLOCK = 1;
81const SIG_SETMASK = 2;85const SIG_SETMASK = 2;
...@@ -226,7 +230,9 @@ pub fn getErrno(r: usize) -> usize {...@@ -226,7 +230,9 @@ pub fn getErrno(r: usize) -> usize {
226 if (signed_r > -4096 && signed_r < 0) usize(-signed_r) else 0230 if (signed_r > -4096 && signed_r < 0) usize(-signed_r) else 0
227}231}
228232
229pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize) -> usize {233pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)
234 -> usize
235{
230 arch.syscall6(arch.SYS_mmap, usize(address), length, prot, flags, usize(fd), offset)236 arch.syscall6(arch.SYS_mmap, usize(address), length, prot, flags, usize(fd), offset)
231}237}
232238
...@@ -238,29 +244,49 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize {...@@ -238,29 +244,49 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
238 arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)244 arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)
239}245}
240246
247pub 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
241pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {251pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
242 arch.syscall3(arch.SYS_write, usize(fd), usize(buf), count)252 arch.syscall3(arch.SYS_write, usize(fd), usize(buf), count)
243}253}
244254
245pub fn open(path: []u8, flags: usize, perm: usize) -> usize {255pub 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
259pub fn open_c(path: &const u8, flags: usize, perm: usize) -> usize {
260 arch.syscall3(arch.SYS_open, usize(path), flags, perm)
261}
262
263pub fn open(path: []const u8, flags: usize, perm: usize) -> usize {
246 var buf: [path.len + 1]u8 = undefined;264 var buf: [path.len + 1]u8 = undefined;
247 @memcpy(&buf[0], &path[0], path.len);265 @memcpy(&buf[0], &path[0], path.len);
248 buf[path.len] = 0;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}
251269
252pub fn create(path: []u8, perm: usize) -> usize {270pub fn create_c(path: &const u8, perm: usize) -> usize {
271 arch.syscall2(arch.SYS_creat, usize(path), perm)
272}
273
274pub fn create(path: []const u8, perm: usize) -> usize {
253 var buf: [path.len + 1]u8 = undefined;275 var buf: [path.len + 1]u8 = undefined;
254 @memcpy(&buf[0], &path[0], path.len);276 @memcpy(&buf[0], &path[0], path.len);
255 buf[path.len] = 0;277 buf[path.len] = 0;
256 arch.syscall2(arch.SYS_creat, usize(&buf[0]), perm)278 return create_c(buf.ptr, perm);
279}
280
281pub 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}
258284
259pub fn openat(dirfd: i32, path: []u8, flags: usize, mode: usize) -> usize {285pub fn openat(dirfd: i32, path: []const u8, flags: usize, mode: usize) -> usize {
260 var buf: [path.len + 1]u8 = undefined;286 var buf: [path.len + 1]u8 = undefined;
261 @memcpy(&buf[0], &path[0], path.len);287 @memcpy(&buf[0], &path[0], path.len);
262 buf[path.len] = 0;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}
265291
266pub fn close(fd: i32) -> usize {292pub fn close(fd: i32) -> usize {
...@@ -457,3 +483,10 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:...@@ -457,3 +483,10 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:
457// }483// }
458// return ifr.ifr_ifindex;484// return ifr.ifr_ifindex;
459// }485// }
486
487pub const stat = arch.stat;
488pub const timespec = arch.timespec;
489
490pub 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,8 +19,8 @@ pub const SYS_rt_sigaction = 13;
19pub const SYS_rt_sigprocmask = 14;19pub const SYS_rt_sigprocmask = 14;
20pub const SYS_rt_sigreturn = 15;20pub const SYS_rt_sigreturn = 15;
21pub const SYS_ioctl = 16;21pub const SYS_ioctl = 16;
22pub const SYS_pread64 = 17;22pub const SYS_pread = 17;
23pub const SYS_pwrite64 = 18;23pub const SYS_pwrite = 18;
24pub const SYS_readv = 19;24pub const SYS_readv = 19;
25pub const SYS_writev = 20;25pub const SYS_writev = 20;
26pub const SYS_access = 21;26pub const SYS_access = 21;
...@@ -453,3 +453,28 @@ export struct msghdr {...@@ -453,3 +453,28 @@ export struct msghdr {
453 __pad2: socklen_t,453 __pad2: socklen_t,
454 msg_flags: i32,454 msg_flags: i32,
455}455}
456
457export 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
477export struct timespec {
478 tv_sec: isize,
479 tv_nsec: isize,
480}
std/net.zig+4-17
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const linux = @import("linux.zig");1const linux = @import("linux.zig");
2const errno = @import("errno.zig");2const errno = @import("errno.zig");
3const assert = @import("debug.zig").assert;3const assert = @import("debug.zig").assert;
4const endian = @import("endian.zig");
45
5pub error SigInterrupt;6pub error SigInterrupt;
6pub error Unexpected;7pub error Unexpected;
...@@ -99,14 +100,14 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection {...@@ -99,14 +100,14 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
99 const connect_ret = if (addr.family == linux.AF_INET) {100 const connect_ret = if (addr.family == linux.AF_INET) {
100 var os_addr: linux.sockaddr_in = undefined;101 var os_addr: linux.sockaddr_in = undefined;
101 os_addr.family = addr.family;102 os_addr.family = addr.family;
102 os_addr.port = swapIfLittleEndian(u16, port);103 os_addr.port = endian.swapIfLe(u16, port);
103 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);104 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
104 @memset(&os_addr.zero, 0, @sizeOf(@typeOf(os_addr.zero)));105 @memset(&os_addr.zero, 0, @sizeOf(@typeOf(os_addr.zero)));
105 linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in))106 linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in))
106 } else if (addr.family == linux.AF_INET6) {107 } else if (addr.family == linux.AF_INET6) {
107 var os_addr: linux.sockaddr_in6 = undefined;108 var os_addr: linux.sockaddr_in6 = undefined;
108 os_addr.family = addr.family;109 os_addr.family = addr.family;
109 os_addr.port = swapIfLittleEndian(u16, port);110 os_addr.port = endian.swapIfLe(u16, port);
110 os_addr.flowinfo = 0;111 os_addr.flowinfo = 0;
111 os_addr.scope_id = addr.scope_id;112 os_addr.scope_id = addr.scope_id;
112 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);113 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
...@@ -319,7 +320,7 @@ fn parseIp4(buf: []const u8) -> %u32 {...@@ -319,7 +320,7 @@ fn parseIp4(buf: []const u8) -> %u32 {
319320
320#attribute("test")321#attribute("test")
321fn testParseIp4() {322fn testParseIp4() {
322 assert(%%parseIp4("127.0.0.1") == swapIfLittleEndian(u32, 0x7f000001));323 assert(%%parseIp4("127.0.0.1") == endian.swapIfLe(u32, 0x7f000001));
323 switch (parseIp4("256.0.0.1")) { Overflow => {}, else => unreachable {}, }324 switch (parseIp4("256.0.0.1")) { Overflow => {}, else => unreachable {}, }
324 switch (parseIp4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, }325 switch (parseIp4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, }
325 switch (parseIp4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, }326 switch (parseIp4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, }
...@@ -351,17 +352,3 @@ fn testLookupSimpleIp() {...@@ -351,17 +352,3 @@ fn testLookupSimpleIp() {
351 assert(addr.addr[3] == 1);352 assert(addr.addr[3] == 1);
352 }353 }
353}354}
354
355fn swapIfLittleEndian(inline T: type, x: T) -> T {
356 if (@compileVar("is_big_endian")) x else endianSwap(T, x)
357}
358
359fn 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,7 +4,7 @@ const errno = @import("errno.zig");
4pub error SigInterrupt;4pub error SigInterrupt;
5pub error Unexpected;5pub error Unexpected;
66
7pub fn get_random_bytes(buf: []u8) -> %void {7pub fn getRandomBytes(buf: []u8) -> %void {
8 switch (@compileVar("os")) {8 switch (@compileVar("os")) {
9 linux => {9 linux => {
10 const ret = linux.getrandom(buf.ptr, buf.len, 0);10 const ret = linux.getrandom(buf.ptr, buf.len, 0);
...@@ -18,14 +18,18 @@ pub fn get_random_bytes(buf: []u8) -> %void {...@@ -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}
2424
25#attribute("cold")25#attribute("cold")
26pub fn abort() -> unreachable {26pub fn abort() -> unreachable {
27 linux.raise(linux.SIGABRT);27 switch (@compileVar("os")) {
28 linux.raise(linux.SIGKILL);28 linux => {
29 while (true) {}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,7 +87,7 @@ pub struct Rand {
87 } else if (T == f64) {87 } else if (T == f64) {
88 900719925474099288 9007199254740992
89 } else {89 } else {
90 @compile_err("unknown floating point type" ++ @typeName(T))90 @compileErr("unknown floating point type" ++ @typeName(T))
91 };91 };
92 return T(r.rangeUnsigned(int_type, 0, precision)) / T(precision);92 return T(r.rangeUnsigned(int_type, 0, precision)) / T(precision);
93 }93 }