mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
progress toward stack trace printing
This commit is contained in:
parent
0fbb9e09ea
commit
ed50bd1b65
@ -200,27 +200,29 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/endian.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/errno.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/linux.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/os.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/str.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_libc.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_nolibc.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/os.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/str.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/linux.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/errno.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
|
||||
add_executable(run_tests ${TEST_SOURCES})
|
||||
target_link_libraries(run_tests)
|
||||
|
@ -62,7 +62,7 @@ const xml_document =
|
||||
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||
\\<document>
|
||||
\\</document>
|
||||
;
|
||||
;
|
||||
struct XmlParser {}
|
||||
|
||||
// The initials BE (Big Endian) are just another word in Zig identifier names.
|
||||
|
@ -14,7 +14,8 @@ pub fn main(args: [][]u8) -> %void {
|
||||
} else if (arg[0] == '-') {
|
||||
return usage(exe);
|
||||
} else {
|
||||
var is = io.InStream.open(arg) %% |err| {
|
||||
var is: io.InStream = undefined;
|
||||
is.open(arg) %% |err| {
|
||||
%%io.stderr.printf("Unable to open file: ");
|
||||
%%io.stderr.printf(@errName(err));
|
||||
%%io.stderr.printf("\n");
|
||||
|
@ -7,7 +7,7 @@ pub fn main(args: [][]u8) -> %void {
|
||||
%%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");
|
||||
|
||||
var seed: [@sizeOf(usize)]u8 = undefined;
|
||||
%%os.get_random_bytes(seed);
|
||||
%%os.getRandomBytes(seed);
|
||||
var rand: Rand = undefined;
|
||||
rand.init(([]usize)(seed)[0]);
|
||||
|
||||
|
@ -1232,6 +1232,7 @@ struct CodeGen {
|
||||
TypeTableEntry *entry_os_enum;
|
||||
TypeTableEntry *entry_arch_enum;
|
||||
TypeTableEntry *entry_environ_enum;
|
||||
TypeTableEntry *entry_oformat_enum;
|
||||
TypeTableEntry *entry_atomic_order_enum;
|
||||
} builtin_types;
|
||||
|
||||
@ -1256,6 +1257,7 @@ struct CodeGen {
|
||||
uint32_t target_os_index;
|
||||
uint32_t target_arch_index;
|
||||
uint32_t target_environ_index;
|
||||
uint32_t target_oformat_index;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
LLVMZigDIFile *dummy_di_file;
|
||||
bool is_native_target;
|
||||
|
@ -5296,6 +5296,9 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
||||
} else if (buf_eql_str(var_name, "environ")) {
|
||||
const_val->data.x_enum.tag = g->target_environ_index;
|
||||
return g->builtin_types.entry_environ_enum;
|
||||
} else if (buf_eql_str(var_name, "object_format")) {
|
||||
const_val->data.x_enum.tag = g->target_oformat_index;
|
||||
return g->builtin_types.entry_oformat_enum;
|
||||
} else {
|
||||
add_node_error(g, *str_node,
|
||||
buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
|
||||
|
@ -4576,6 +4576,33 @@ static void define_builtin_types(CodeGen *g) {
|
||||
g->builtin_types.entry_environ_enum = entry;
|
||||
}
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->deep_const = true;
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@ObjectFormat");
|
||||
uint32_t field_count = target_oformat_count();
|
||||
entry->data.enumeration.field_count = field_count;
|
||||
entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
for (uint32_t i = 0; i < field_count; i += 1) {
|
||||
TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
|
||||
ZigLLVM_ObjectFormatType oformat = get_target_oformat(i);
|
||||
type_enum_field->name = buf_create_from_str(get_target_oformat_name(oformat));
|
||||
type_enum_field->value = i;
|
||||
type_enum_field->type_entry = g->builtin_types.entry_void;
|
||||
|
||||
if (oformat == g->zig_target.oformat) {
|
||||
g->target_oformat_index = i;
|
||||
}
|
||||
}
|
||||
entry->data.enumeration.complete = true;
|
||||
|
||||
TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
|
||||
entry->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
g->builtin_types.entry_oformat_enum = entry;
|
||||
}
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->deep_const = true;
|
||||
|
@ -137,6 +137,31 @@ static const ZigLLVM_EnvironmentType environ_list[] = {
|
||||
ZigLLVM_CoreCLR,
|
||||
};
|
||||
|
||||
static const ZigLLVM_ObjectFormatType oformat_list[] = {
|
||||
ZigLLVM_UnknownObjectFormat,
|
||||
ZigLLVM_COFF,
|
||||
ZigLLVM_ELF,
|
||||
ZigLLVM_MachO,
|
||||
};
|
||||
|
||||
int target_oformat_count(void) {
|
||||
return array_length(oformat_list);
|
||||
}
|
||||
|
||||
const ZigLLVM_ObjectFormatType get_target_oformat(int index) {
|
||||
return oformat_list[index];
|
||||
}
|
||||
|
||||
const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat) {
|
||||
switch (oformat) {
|
||||
case ZigLLVM_UnknownObjectFormat: return "unknown";
|
||||
case ZigLLVM_COFF: return "coff";
|
||||
case ZigLLVM_ELF: return "elf";
|
||||
case ZigLLVM_MachO: return "macho";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
int target_arch_count(void) {
|
||||
return array_length(arch_list);
|
||||
}
|
||||
|
@ -52,6 +52,11 @@ const char *get_target_os_name(ZigLLVM_OSType os_type);
|
||||
int target_environ_count(void);
|
||||
ZigLLVM_EnvironmentType get_target_environ(int index);
|
||||
|
||||
|
||||
int target_oformat_count(void);
|
||||
const ZigLLVM_ObjectFormatType get_target_oformat(int index);
|
||||
const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat);
|
||||
|
||||
void get_native_target(ZigTarget *target);
|
||||
void get_unknown_target(ZigTarget *target);
|
||||
|
||||
|
118
std/debug.zig
118
std/debug.zig
@ -1,21 +1,123 @@
|
||||
const Allocator = @import("mem.zig").Allocator;
|
||||
const io = @import("io.zig");
|
||||
const os = @import("os.zig");
|
||||
const elf = @import("elf.zig");
|
||||
|
||||
pub error MissingDebugInfo;
|
||||
pub error InvalidDebugInfo;
|
||||
pub error UnsupportedDebugInfo;
|
||||
|
||||
pub fn assert(b: bool) {
|
||||
if (!b) unreachable{}
|
||||
}
|
||||
|
||||
pub fn printStackTrace() {
|
||||
var maybe_fp: ?&const u8 = @frameAddress();
|
||||
while (true) {
|
||||
const fp = maybe_fp ?? break;
|
||||
const return_address = *(&const usize)(usize(fp) + @sizeOf(usize));
|
||||
%%io.stderr.printInt(usize, return_address);
|
||||
%%io.stderr.printf("\n");
|
||||
maybe_fp = *(&const ?&const u8)(fp);
|
||||
pub fn printStackTrace() -> %void {
|
||||
%return writeStackTrace(&io.stderr);
|
||||
%return io.stderr.flush();
|
||||
}
|
||||
|
||||
pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
|
||||
switch (@compileVar("object_format")) {
|
||||
elf => {
|
||||
var st: ElfStackTrace = undefined;
|
||||
%return io.openSelfExe(&st.self_exe_stream);
|
||||
defer %return st.self_exe_stream.close();
|
||||
|
||||
%return st.elf.openStream(&global_allocator, &st.self_exe_stream);
|
||||
defer %return st.elf.close();
|
||||
|
||||
st.aranges = %return st.elf.findSection(".debug_aranges");
|
||||
|
||||
var maybe_fp: ?&const u8 = @frameAddress();
|
||||
while (true) {
|
||||
const fp = maybe_fp ?? break;
|
||||
const return_address = *(&const usize)(usize(fp) + @sizeOf(usize));
|
||||
|
||||
// read .debug_aranges to find out which compile unit the address is in
|
||||
const debug_info_offset = %return debugInfoOffset(&st, return_address);
|
||||
|
||||
%return out_stream.printInt(usize, return_address);
|
||||
%return out_stream.printf(" -> ");
|
||||
%return out_stream.printInt(u64, debug_info_offset);
|
||||
%return out_stream.printf("\n");
|
||||
maybe_fp = *(&const ?&const u8)(fp);
|
||||
}
|
||||
},
|
||||
coff => {
|
||||
out_stream.write("(stack trace unavailable for COFF object format)\n");
|
||||
},
|
||||
macho => {
|
||||
out_stream.write("(stack trace unavailable for Mach-O object format)\n");
|
||||
},
|
||||
unknown => {
|
||||
out_stream.write("(stack trace unavailable for unknown object format)\n");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct ElfStackTrace {
|
||||
self_exe_stream: io.InStream,
|
||||
elf: elf.Elf,
|
||||
aranges: ?&elf.SectionHeader,
|
||||
}
|
||||
|
||||
fn debugInfoOffset(st: &ElfStackTrace, target_address: usize) -> %u64 {
|
||||
// when there is no .debug_aranges section, offset into debug info is 0x0
|
||||
const aranges = st.aranges ?? return 0;
|
||||
|
||||
%return st.elf.seekToSection(aranges);
|
||||
|
||||
const first_32_bits = %return st.self_exe_stream.readIntLe(u32);
|
||||
const is_64 = (first_32_bits == 0xffffffff);
|
||||
const unit_length = if (is_64) {
|
||||
%return st.self_exe_stream.readIntLe(u64)
|
||||
} else {
|
||||
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
|
||||
first_32_bits
|
||||
};
|
||||
var unit_index: u64 = 0;
|
||||
|
||||
while (unit_index < unit_length) {
|
||||
const version = %return st.self_exe_stream.readIntLe(u16);
|
||||
if (version != 2) return error.InvalidDebugInfo;
|
||||
unit_index += 2;
|
||||
|
||||
const debug_info_offset = if (is_64) {
|
||||
unit_index += 4;
|
||||
%return st.self_exe_stream.readIntLe(u64)
|
||||
} else {
|
||||
unit_index += 2;
|
||||
%return st.self_exe_stream.readIntLe(u32)
|
||||
};
|
||||
|
||||
const address_size = %return st.self_exe_stream.readByte();
|
||||
if (address_size > 8) return error.UnsupportedDebugInfo;
|
||||
unit_index += 1;
|
||||
|
||||
const segment_size = %return st.self_exe_stream.readByte();
|
||||
if (segment_size > 0) return error.UnsupportedDebugInfo;
|
||||
unit_index += 1;
|
||||
|
||||
const align = segment_size + 2 * address_size;
|
||||
const padding = st.self_exe_stream.offset % align;
|
||||
%return st.self_exe_stream.seekForward(padding);
|
||||
unit_index += padding;
|
||||
|
||||
while (true) {
|
||||
const address = %return st.self_exe_stream.readVarInt(false, u64, address_size);
|
||||
const length = %return st.self_exe_stream.readVarInt(false, u64, address_size);
|
||||
unit_index += align;
|
||||
if (address == 0 && length == 0) break;
|
||||
|
||||
if (target_address >= address && target_address < address + length) {
|
||||
return debug_info_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error.MissingDebugInfo;
|
||||
}
|
||||
|
||||
pub var global_allocator = Allocator {
|
||||
.allocFn = globalAlloc,
|
||||
.reallocFn = globalRealloc,
|
||||
|
261
std/elf.zig
Normal file
261
std/elf.zig
Normal file
@ -0,0 +1,261 @@
|
||||
const io = @import("io.zig");
|
||||
const str = @import("str.zig");
|
||||
const math = @import("math.zig");
|
||||
const mem = @import("mem.zig");
|
||||
const debug = @import("debug.zig");
|
||||
|
||||
pub error InvalidFormat;
|
||||
|
||||
pub const SHT_NULL = 0;
|
||||
pub const SHT_PROGBITS = 1;
|
||||
pub const SHT_SYMTAB = 2;
|
||||
pub const SHT_STRTAB = 3;
|
||||
pub const SHT_RELA = 4;
|
||||
pub const SHT_HASH = 5;
|
||||
pub const SHT_DYNAMIC = 6;
|
||||
pub const SHT_NOTE = 7;
|
||||
pub const SHT_NOBITS = 8;
|
||||
pub const SHT_REL = 9;
|
||||
pub const SHT_SHLIB = 10;
|
||||
pub const SHT_DYNSYM = 11;
|
||||
pub const SHT_INIT_ARRAY = 14;
|
||||
pub const SHT_FINI_ARRAY = 15;
|
||||
pub const SHT_PREINIT_ARRAY = 16;
|
||||
pub const SHT_GROUP = 17;
|
||||
pub const SHT_SYMTAB_SHNDX = 18;
|
||||
pub const SHT_LOOS = 0x60000000;
|
||||
pub const SHT_HIOS = 0x6fffffff;
|
||||
pub const SHT_LOPROC = 0x70000000;
|
||||
pub const SHT_HIPROC = 0x7fffffff;
|
||||
pub const SHT_LOUSER = 0x80000000;
|
||||
pub const SHT_HIUSER = 0xffffffff;
|
||||
|
||||
pub enum FileType {
|
||||
Relocatable,
|
||||
Executable,
|
||||
Shared,
|
||||
Core,
|
||||
}
|
||||
|
||||
pub enum Arch {
|
||||
Sparc,
|
||||
x86,
|
||||
Mips,
|
||||
PowerPc,
|
||||
Arm,
|
||||
SuperH,
|
||||
IA_64,
|
||||
x86_64,
|
||||
AArch64,
|
||||
}
|
||||
|
||||
pub struct SectionHeader {
|
||||
name: u32,
|
||||
sh_type: u32,
|
||||
flags: u64,
|
||||
addr: u64,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
link: u32,
|
||||
info: u32,
|
||||
addr_align: u64,
|
||||
ent_size: u64,
|
||||
}
|
||||
|
||||
pub struct Elf {
|
||||
in_stream: &io.InStream,
|
||||
auto_close_stream: bool,
|
||||
is_64: bool,
|
||||
is_big_endian: bool,
|
||||
file_type: FileType,
|
||||
arch: Arch,
|
||||
entry_addr: u64,
|
||||
program_header_offset: u64,
|
||||
section_header_offset: u64,
|
||||
string_section_index: u64,
|
||||
string_section: &SectionHeader,
|
||||
section_headers: []SectionHeader,
|
||||
allocator: &mem.Allocator,
|
||||
prealloc_stream: io.InStream,
|
||||
|
||||
/// Call close when done.
|
||||
pub fn openFile(elf: &Elf, allocator: &mem.Allocator, path: []const u8) -> %void {
|
||||
%return elf.prealloc_stream.open(path);
|
||||
%return elf.openStream(allocator, &elf.prealloc_stream);
|
||||
elf.auto_close_stream = true;
|
||||
}
|
||||
|
||||
/// Call close when done.
|
||||
pub fn openStream(elf: &Elf, allocator: &mem.Allocator, stream: &io.InStream) -> %void {
|
||||
elf.allocator = allocator;
|
||||
elf.in_stream = stream;
|
||||
elf.auto_close_stream = false;
|
||||
|
||||
var magic: [4]u8 = undefined;
|
||||
%return elf.in_stream.readNoEof(magic);
|
||||
if (!str.eql(magic, "\x7fELF")) return error.InvalidFormat;
|
||||
|
||||
elf.is_64 = switch (%return elf.in_stream.readByte()) {
|
||||
1 => false,
|
||||
2 => true,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
elf.is_big_endian = switch (%return elf.in_stream.readByte()) {
|
||||
1 => false,
|
||||
2 => true,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
const version_byte = %return elf.in_stream.readByte();
|
||||
if (version_byte != 1) return error.InvalidFormat;
|
||||
|
||||
// skip over padding
|
||||
%return elf.in_stream.seekForward(9);
|
||||
|
||||
elf.file_type = switch (%return elf.in_stream.readInt(elf.is_big_endian, u16)) {
|
||||
1 => FileType.Relocatable,
|
||||
2 => FileType.Executable,
|
||||
3 => FileType.Shared,
|
||||
4 => FileType.Core,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
elf.arch = switch (%return elf.in_stream.readInt(elf.is_big_endian, u16)) {
|
||||
0x02 => Arch.Sparc,
|
||||
0x03 => Arch.x86,
|
||||
0x08 => Arch.Mips,
|
||||
0x14 => Arch.PowerPc,
|
||||
0x28 => Arch.Arm,
|
||||
0x2A => Arch.SuperH,
|
||||
0x32 => Arch.IA_64,
|
||||
0x3E => Arch.x86_64,
|
||||
0xb7 => Arch.AArch64,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
const elf_version = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
if (elf_version != 1) return error.InvalidFormat;
|
||||
|
||||
if (elf.is_64) {
|
||||
elf.entry_addr = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
elf.program_header_offset = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
elf.section_header_offset = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
} else {
|
||||
elf.entry_addr = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
elf.program_header_offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
elf.section_header_offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
}
|
||||
|
||||
// skip over flags
|
||||
%return elf.in_stream.seekForward(4);
|
||||
|
||||
const header_size = %return elf.in_stream.readInt(elf.is_big_endian, u16);
|
||||
if ((elf.is_64 && header_size != 64) ||
|
||||
(!elf.is_64 && header_size != 52))
|
||||
{
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
const ph_entry_size = %return elf.in_stream.readInt(elf.is_big_endian, u16);
|
||||
const ph_entry_count = %return elf.in_stream.readInt(elf.is_big_endian, u16);
|
||||
const sh_entry_size = %return elf.in_stream.readInt(elf.is_big_endian, u16);
|
||||
const sh_entry_count = %return elf.in_stream.readInt(elf.is_big_endian, u16);
|
||||
elf.string_section_index = u64(%return elf.in_stream.readInt(elf.is_big_endian, u16));
|
||||
|
||||
if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
|
||||
|
||||
const sh_byte_count = u64(sh_entry_size) * u64(sh_entry_count);
|
||||
const end_sh = %return math.addOverflow(u64, elf.section_header_offset, sh_byte_count);
|
||||
const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
|
||||
const end_ph = %return math.addOverflow(u64, elf.program_header_offset, ph_byte_count);
|
||||
|
||||
const stream_end = %return elf.in_stream.endPos();
|
||||
if (stream_end < end_sh || stream_end < end_ph) {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
%return elf.in_stream.seekTo(elf.section_header_offset);
|
||||
|
||||
elf.section_headers = %return elf.allocator.alloc(SectionHeader, sh_entry_count);
|
||||
%defer elf.allocator.free(SectionHeader, elf.section_headers);
|
||||
|
||||
if (elf.is_64) {
|
||||
if (sh_entry_size != 64) return error.InvalidFormat;
|
||||
|
||||
for (elf.section_headers) |*section| {
|
||||
section.name = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.sh_type = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.flags = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.addr = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.offset = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.size = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.link = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.info = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.addr_align = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
section.ent_size = %return elf.in_stream.readInt(elf.is_big_endian, u64);
|
||||
}
|
||||
} else {
|
||||
if (sh_entry_size != 40) return error.InvalidFormat;
|
||||
|
||||
for (elf.section_headers) |*section| {
|
||||
// TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ?
|
||||
section.name = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.sh_type = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.flags = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.addr = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.size = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.link = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.info = %return elf.in_stream.readInt(elf.is_big_endian, u32);
|
||||
section.addr_align = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
section.ent_size = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));
|
||||
}
|
||||
}
|
||||
|
||||
for (elf.section_headers) |*section| {
|
||||
if (section.sh_type != SHT_NOBITS) {
|
||||
const file_end_offset = %return math.addOverflow(u64,
|
||||
section.offset, section.size);
|
||||
if (stream_end < file_end_offset) return error.InvalidFormat;
|
||||
}
|
||||
}
|
||||
|
||||
elf.string_section = &elf.section_headers[elf.string_section_index];
|
||||
if (elf.string_section.sh_type != SHT_STRTAB) {
|
||||
// not a string table
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(elf: &Elf) -> %void {
|
||||
elf.allocator.free(SectionHeader, elf.section_headers);
|
||||
if (elf.auto_close_stream) %return elf.in_stream.close();
|
||||
}
|
||||
|
||||
pub fn findSection(elf: &Elf, name: []u8) -> %?&SectionHeader {
|
||||
for (elf.section_headers) |*section| {
|
||||
if (section.sh_type == SHT_NULL) continue;
|
||||
|
||||
const name_offset = elf.string_section.offset + section.name;
|
||||
%return elf.in_stream.seekTo(name_offset);
|
||||
|
||||
for (name) |expected_c| {
|
||||
const target_c = %return elf.in_stream.readByte();
|
||||
if (target_c == 0 || expected_c != target_c) goto next_section;
|
||||
}
|
||||
|
||||
const null_byte = %return elf.in_stream.readByte();
|
||||
if (null_byte == 0) return (?&SectionHeader)(section);
|
||||
|
||||
next_section:
|
||||
}
|
||||
|
||||
const null_sh: ?&SectionHeader = null;
|
||||
return null_sh;
|
||||
}
|
||||
|
||||
pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void {
|
||||
%return elf.in_stream.seekTo(section.offset);
|
||||
}
|
||||
}
|
21
std/endian.zig
Normal file
21
std/endian.zig
Normal file
@ -0,0 +1,21 @@
|
||||
pub inline fn swapIfLe(inline T: type, x: T) -> T {
|
||||
swapIf(false, T, x)
|
||||
}
|
||||
|
||||
pub inline fn swapIfBe(inline T: type, x: T) -> T {
|
||||
swapIf(true, T, x)
|
||||
}
|
||||
|
||||
pub inline fn swapIf(is_be: bool, inline T: type, x: T) -> T {
|
||||
if (@compileVar("is_big_endian") == is_be) swap(T, x) else x
|
||||
}
|
||||
|
||||
pub fn swap(inline T: type, x: T) -> T {
|
||||
const x_slice = ([]u8)((&const x)[0...1]);
|
||||
var result: T = undefined;
|
||||
const result_slice = ([]u8)((&result)[0...1]);
|
||||
for (result_slice) |*b, i| {
|
||||
*b = x_slice[@sizeOf(T) - i - 1];
|
||||
}
|
||||
return result;
|
||||
}
|
140
std/io.zig
140
std/io.zig
@ -1,6 +1,9 @@
|
||||
const linux = @import("linux.zig");
|
||||
const errno = @import("errno.zig");
|
||||
const math = @import("math.zig");
|
||||
const endian = @import("endian.zig");
|
||||
const debug = @import("debug.zig");
|
||||
const assert = debug.assert;
|
||||
|
||||
pub const stdin_fileno = 0;
|
||||
pub const stdout_fileno = 1;
|
||||
@ -8,6 +11,7 @@ pub const stderr_fileno = 2;
|
||||
|
||||
pub var stdin = InStream {
|
||||
.fd = stdin_fileno,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
pub var stdout = OutStream {
|
||||
@ -33,6 +37,8 @@ pub error Unexpected;
|
||||
|
||||
pub error DiskQuota;
|
||||
pub error FileTooBig;
|
||||
// TODO hide interrupts at this layer by retrying. Users can use the linux specific APIs if they
|
||||
// want to handle interrupts.
|
||||
pub error SigInterrupt;
|
||||
pub error Io;
|
||||
pub error NoSpaceLeft;
|
||||
@ -48,6 +54,8 @@ pub error NameTooLong;
|
||||
pub error NoDevice;
|
||||
pub error PathNotFound;
|
||||
pub error NoMem;
|
||||
pub error Unseekable;
|
||||
pub error Eof;
|
||||
|
||||
const buffer_size = 4 * 1024;
|
||||
const max_u64_base10_digits = 20;
|
||||
@ -137,14 +145,18 @@ pub struct OutStream {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO created a BufferedInStream struct and move some of this code there
|
||||
// BufferedInStream API goes on top of minimal InStream API.
|
||||
pub struct InStream {
|
||||
fd: i32,
|
||||
offset: usize,
|
||||
|
||||
pub fn open(path: []u8) -> %InStream {
|
||||
const fd = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
|
||||
const fd_err = linux.getErrno(fd);
|
||||
if (fd_err > 0) {
|
||||
return switch (fd_err) {
|
||||
/// Call close to clean up.
|
||||
pub fn open(is: &InStream, path: []const u8) -> %void {
|
||||
const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
|
||||
const err = linux.getErrno(result);
|
||||
if (err > 0) {
|
||||
return switch (err) {
|
||||
errno.EFAULT => unreachable{},
|
||||
errno.EINVAL => unreachable{},
|
||||
errno.EACCES => error.BadPerm,
|
||||
@ -164,24 +176,8 @@ pub struct InStream {
|
||||
else => error.Unexpected,
|
||||
}
|
||||
}
|
||||
|
||||
return InStream { .fd = i32(fd), };
|
||||
}
|
||||
|
||||
pub fn read(is: &InStream, buf: []u8) -> %usize {
|
||||
const amt_read = linux.read(is.fd, &buf[0], buf.len);
|
||||
const read_err = linux.getErrno(amt_read);
|
||||
if (read_err > 0) {
|
||||
return switch (read_err) {
|
||||
errno.EINVAL => unreachable{},
|
||||
errno.EFAULT => unreachable{},
|
||||
errno.EBADF => error.BadFd,
|
||||
errno.EINTR => error.SigInterrupt,
|
||||
errno.EIO => error.Io,
|
||||
else => error.Unexpected,
|
||||
}
|
||||
}
|
||||
return amt_read;
|
||||
is.fd = i32(result);
|
||||
is.offset = 0;
|
||||
}
|
||||
|
||||
pub fn close(is: &InStream) -> %void {
|
||||
@ -196,6 +192,95 @@ pub struct InStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of bytes read. If the number read is smaller than buf.len, then
|
||||
/// the stream reached End Of File.
|
||||
pub fn read(is: &InStream, buf: []u8) -> %usize {
|
||||
switch (@compileVar("os")) {
|
||||
linux => {
|
||||
while (true) {
|
||||
const amt_read = linux.pread(is.fd, buf.ptr, buf.len, is.offset);
|
||||
const read_err = linux.getErrno(amt_read);
|
||||
if (read_err > 0) {
|
||||
switch (read_err) {
|
||||
errno.EINTR => continue,
|
||||
errno.EINVAL => unreachable{},
|
||||
errno.EFAULT => unreachable{},
|
||||
errno.EBADF => return error.BadFd,
|
||||
errno.EIO => return error.Io,
|
||||
else => return error.Unexpected,
|
||||
}
|
||||
}
|
||||
is.offset += amt_read;
|
||||
return amt_read;
|
||||
}
|
||||
},
|
||||
else => @compileErr("unsupported OS"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readNoEof(is: &InStream, buf: []u8) -> %void {
|
||||
const amt_read = %return is.read(buf);
|
||||
if (amt_read < buf.len) return error.Eof;
|
||||
}
|
||||
|
||||
pub fn readByte(is: &InStream) -> %u8 {
|
||||
var result: [1]u8 = undefined;
|
||||
%return is.readNoEof(result);
|
||||
return result[0];
|
||||
}
|
||||
|
||||
pub inline fn readIntLe(is: &InStream, inline T: type) -> %T {
|
||||
is.readInt(false, T)
|
||||
}
|
||||
|
||||
pub inline fn readIntBe(is: &InStream, inline T: type) -> %T {
|
||||
is.readInt(true, T)
|
||||
}
|
||||
|
||||
pub inline fn readInt(is: &InStream, is_be: bool, inline T: type) -> %T {
|
||||
var result: T = undefined;
|
||||
const result_slice = ([]u8)((&result)[0...1]);
|
||||
%return is.readNoEof(result_slice);
|
||||
return endian.swapIf(!is_be, T, result);
|
||||
}
|
||||
|
||||
pub inline fn readVarInt(is: &InStream, is_be: bool, inline T: type, size: usize) -> %T {
|
||||
var result: T = zeroes;
|
||||
const result_slice = ([]u8)((&result)[0...1]);
|
||||
const padding = @sizeOf(T) - size;
|
||||
{var i: usize = 0; while (i < size; i += 1) {
|
||||
const index = if (is_be == @compileVar("is_big_endian")) {
|
||||
padding + i
|
||||
} else {
|
||||
result_slice.len - i - 1 - padding
|
||||
};
|
||||
result_slice[index] = %return is.readByte();
|
||||
}}
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn seekForward(is: &InStream, amount: usize) -> %void {
|
||||
is.offset += amount;
|
||||
}
|
||||
|
||||
pub fn seekTo(is: &InStream, pos: usize) -> %void {
|
||||
is.offset = pos;
|
||||
}
|
||||
|
||||
pub fn endPos(is: &InStream) -> %usize {
|
||||
var stat: linux.stat = undefined;
|
||||
const err = linux.getErrno(linux.fstat(is.fd, &stat));
|
||||
if (err > 0) {
|
||||
return switch (err) {
|
||||
errno.EBADF => error.BadFd,
|
||||
errno.ENOMEM => error.NoMem,
|
||||
else => error.Unexpected,
|
||||
}
|
||||
}
|
||||
|
||||
return usize(stat.size);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parseUnsigned(inline T: type, buf: []u8, radix: u8) -> %T {
|
||||
@ -267,3 +352,12 @@ fn parseU64DigitTooBig() {
|
||||
};
|
||||
unreachable{};
|
||||
}
|
||||
|
||||
pub fn openSelfExe(stream: &InStream) -> %void {
|
||||
switch (@compileVar("os")) {
|
||||
linux => {
|
||||
%return stream.open("/proc/self/exe");
|
||||
},
|
||||
else => @compileErr("unsupported os"),
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,10 @@ pub const O_PATH = arch.O_PATH;
|
||||
pub const O_TMPFILE = arch.O_TMPFILE;
|
||||
pub const O_NDELAY = arch.O_NDELAY;
|
||||
|
||||
pub const SEEK_SET = 0;
|
||||
pub const SEEK_CUR = 1;
|
||||
pub const SEEK_END = 2;
|
||||
|
||||
const SIG_BLOCK = 0;
|
||||
const SIG_UNBLOCK = 1;
|
||||
const SIG_SETMASK = 2;
|
||||
@ -226,7 +230,9 @@ pub fn getErrno(r: usize) -> usize {
|
||||
if (signed_r > -4096 && signed_r < 0) usize(-signed_r) else 0
|
||||
}
|
||||
|
||||
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize) -> usize {
|
||||
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)
|
||||
-> usize
|
||||
{
|
||||
arch.syscall6(arch.SYS_mmap, usize(address), length, prot, flags, usize(fd), offset)
|
||||
}
|
||||
|
||||
@ -238,29 +244,49 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
|
||||
arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)
|
||||
}
|
||||
|
||||
pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {
|
||||
arch.syscall4(arch.SYS_pread, usize(fd), usize(buf), count, offset)
|
||||
}
|
||||
|
||||
pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
|
||||
arch.syscall3(arch.SYS_write, usize(fd), usize(buf), count)
|
||||
}
|
||||
|
||||
pub fn open(path: []u8, flags: usize, perm: usize) -> usize {
|
||||
var buf: [path.len + 1]u8 = undefined;
|
||||
@memcpy(&buf[0], &path[0], path.len);
|
||||
buf[path.len] = 0;
|
||||
arch.syscall3(arch.SYS_open, usize(&buf[0]), flags, perm)
|
||||
pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize {
|
||||
arch.syscall4(arch.SYS_pwrite, usize(fd), usize(buf), count, offset)
|
||||
}
|
||||
|
||||
pub fn create(path: []u8, perm: usize) -> usize {
|
||||
var buf: [path.len + 1]u8 = undefined;
|
||||
@memcpy(&buf[0], &path[0], path.len);
|
||||
buf[path.len] = 0;
|
||||
arch.syscall2(arch.SYS_creat, usize(&buf[0]), perm)
|
||||
pub fn open_c(path: &const u8, flags: usize, perm: usize) -> usize {
|
||||
arch.syscall3(arch.SYS_open, usize(path), flags, perm)
|
||||
}
|
||||
|
||||
pub fn openat(dirfd: i32, path: []u8, flags: usize, mode: usize) -> usize {
|
||||
pub fn open(path: []const u8, flags: usize, perm: usize) -> usize {
|
||||
var buf: [path.len + 1]u8 = undefined;
|
||||
@memcpy(&buf[0], &path[0], path.len);
|
||||
buf[path.len] = 0;
|
||||
arch.syscall4(arch.SYS_openat, usize(dirfd), usize(&buf[0]), flags, mode)
|
||||
return open_c(buf.ptr, flags, perm);
|
||||
}
|
||||
|
||||
pub fn create_c(path: &const u8, perm: usize) -> usize {
|
||||
arch.syscall2(arch.SYS_creat, usize(path), perm)
|
||||
}
|
||||
|
||||
pub fn create(path: []const u8, perm: usize) -> usize {
|
||||
var buf: [path.len + 1]u8 = undefined;
|
||||
@memcpy(&buf[0], &path[0], path.len);
|
||||
buf[path.len] = 0;
|
||||
return create_c(buf.ptr, perm);
|
||||
}
|
||||
|
||||
pub fn openat_c(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize {
|
||||
arch.syscall4(arch.SYS_openat, usize(dirfd), usize(path), flags, mode)
|
||||
}
|
||||
|
||||
pub fn openat(dirfd: i32, path: []const u8, flags: usize, mode: usize) -> usize {
|
||||
var buf: [path.len + 1]u8 = undefined;
|
||||
@memcpy(&buf[0], &path[0], path.len);
|
||||
buf[path.len] = 0;
|
||||
return openat_c(dirfd, buf.ptr, flags, mode);
|
||||
}
|
||||
|
||||
pub fn close(fd: i32) -> usize {
|
||||
@ -457,3 +483,10 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:
|
||||
// }
|
||||
// return ifr.ifr_ifindex;
|
||||
// }
|
||||
|
||||
pub const stat = arch.stat;
|
||||
pub const timespec = arch.timespec;
|
||||
|
||||
pub fn fstat(fd: i32, stat_buf: &stat) -> usize {
|
||||
arch.syscall2(arch.SYS_fstat, usize(fd), usize(stat_buf))
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ pub const SYS_rt_sigaction = 13;
|
||||
pub const SYS_rt_sigprocmask = 14;
|
||||
pub const SYS_rt_sigreturn = 15;
|
||||
pub const SYS_ioctl = 16;
|
||||
pub const SYS_pread64 = 17;
|
||||
pub const SYS_pwrite64 = 18;
|
||||
pub const SYS_pread = 17;
|
||||
pub const SYS_pwrite = 18;
|
||||
pub const SYS_readv = 19;
|
||||
pub const SYS_writev = 20;
|
||||
pub const SYS_access = 21;
|
||||
@ -453,3 +453,28 @@ export struct msghdr {
|
||||
__pad2: socklen_t,
|
||||
msg_flags: i32,
|
||||
}
|
||||
|
||||
export struct stat {
|
||||
dev: u64,
|
||||
ino: u64,
|
||||
nlink: usize,
|
||||
|
||||
mode: u32,
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
__pad0: u32,
|
||||
rdev: u64,
|
||||
size: i64,
|
||||
blksize: isize,
|
||||
blocks: i64,
|
||||
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
__unused: [3]isize,
|
||||
}
|
||||
|
||||
export struct timespec {
|
||||
tv_sec: isize,
|
||||
tv_nsec: isize,
|
||||
}
|
||||
|
21
std/net.zig
21
std/net.zig
@ -1,6 +1,7 @@
|
||||
const linux = @import("linux.zig");
|
||||
const errno = @import("errno.zig");
|
||||
const assert = @import("debug.zig").assert;
|
||||
const endian = @import("endian.zig");
|
||||
|
||||
pub error SigInterrupt;
|
||||
pub error Unexpected;
|
||||
@ -99,14 +100,14 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
|
||||
const connect_ret = if (addr.family == linux.AF_INET) {
|
||||
var os_addr: linux.sockaddr_in = undefined;
|
||||
os_addr.family = addr.family;
|
||||
os_addr.port = swapIfLittleEndian(u16, port);
|
||||
os_addr.port = endian.swapIfLe(u16, port);
|
||||
@memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
|
||||
@memset(&os_addr.zero, 0, @sizeOf(@typeOf(os_addr.zero)));
|
||||
linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in))
|
||||
} else if (addr.family == linux.AF_INET6) {
|
||||
var os_addr: linux.sockaddr_in6 = undefined;
|
||||
os_addr.family = addr.family;
|
||||
os_addr.port = swapIfLittleEndian(u16, port);
|
||||
os_addr.port = endian.swapIfLe(u16, port);
|
||||
os_addr.flowinfo = 0;
|
||||
os_addr.scope_id = addr.scope_id;
|
||||
@memcpy(&os_addr.addr[0], &addr.addr[0], 16);
|
||||
@ -319,7 +320,7 @@ fn parseIp4(buf: []const u8) -> %u32 {
|
||||
|
||||
#attribute("test")
|
||||
fn testParseIp4() {
|
||||
assert(%%parseIp4("127.0.0.1") == swapIfLittleEndian(u32, 0x7f000001));
|
||||
assert(%%parseIp4("127.0.0.1") == endian.swapIfLe(u32, 0x7f000001));
|
||||
switch (parseIp4("256.0.0.1")) { Overflow => {}, else => unreachable {}, }
|
||||
switch (parseIp4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, }
|
||||
switch (parseIp4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, }
|
||||
@ -351,17 +352,3 @@ fn testLookupSimpleIp() {
|
||||
assert(addr.addr[3] == 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn swapIfLittleEndian(inline T: type, x: T) -> T {
|
||||
if (@compileVar("is_big_endian")) x else endianSwap(T, x)
|
||||
}
|
||||
|
||||
fn endianSwap(inline T: type, x: T) -> T {
|
||||
const x_slice = ([]u8)((&const x)[0...1]);
|
||||
var result: T = undefined;
|
||||
const result_slice = ([]u8)((&result)[0...1]);
|
||||
for (result_slice) |*b, i| {
|
||||
*b = x_slice[@sizeOf(T) - i - 1];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
16
std/os.zig
16
std/os.zig
@ -4,7 +4,7 @@ const errno = @import("errno.zig");
|
||||
pub error SigInterrupt;
|
||||
pub error Unexpected;
|
||||
|
||||
pub fn get_random_bytes(buf: []u8) -> %void {
|
||||
pub fn getRandomBytes(buf: []u8) -> %void {
|
||||
switch (@compileVar("os")) {
|
||||
linux => {
|
||||
const ret = linux.getrandom(buf.ptr, buf.len, 0);
|
||||
@ -18,14 +18,18 @@ pub fn get_random_bytes(buf: []u8) -> %void {
|
||||
}
|
||||
}
|
||||
},
|
||||
else => @compile_err("unsupported os"),
|
||||
else => @compileErr("unsupported os"),
|
||||
}
|
||||
}
|
||||
|
||||
#attribute("cold")
|
||||
pub fn abort() -> unreachable {
|
||||
linux.raise(linux.SIGABRT);
|
||||
linux.raise(linux.SIGKILL);
|
||||
while (true) {}
|
||||
switch (@compileVar("os")) {
|
||||
linux => {
|
||||
linux.raise(linux.SIGABRT);
|
||||
linux.raise(linux.SIGKILL);
|
||||
while (true) {}
|
||||
},
|
||||
else => @compileErr("unsupported os"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ pub struct Rand {
|
||||
} else if (T == f64) {
|
||||
9007199254740992
|
||||
} else {
|
||||
@compile_err("unknown floating point type" ++ @typeName(T))
|
||||
@compileErr("unknown floating point type" ++ @typeName(T))
|
||||
};
|
||||
return T(r.rangeUnsigned(int_type, 0, precision)) / T(precision);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user