From 7a3f0a55d9a481f260935f26426ee4508d44cb18 Mon Sep 17 00:00:00 2001
From: Greg V
Date: Wed, 17 Oct 2018 18:01:00 +0300
Subject: Add freebsd to more things
---
std/debug/index.zig | 2 ++
1 file changed, 2 insertions(+)
(limited to 'std/debug')
diff --git a/std/debug/index.zig b/std/debug/index.zig
index e6d8fe3fc6..cabeba14f7 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -1078,6 +1078,8 @@ pub const DebugInfo = switch (builtin.os) {
self.elf.close();
}
},
+ builtin.Os.freebsd => struct.{
+ },
else => @compileError("Unsupported OS"),
};
--
cgit v1.2.3
From 4dafdc00d5c0d73511d64c5edf7481c8fe254a61 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 19 Nov 2018 17:28:18 -0500
Subject: zig fmt
---
std/c/freebsd.zig | 7 ++-----
std/debug/index.zig | 3 +--
std/mem.zig | 8 ++++----
std/os/freebsd/index.zig | 21 +++++++--------------
std/os/freebsd/x86_64.zig | 6 +++---
std/special/bootstrap.zig | 2 +-
6 files changed, 18 insertions(+), 29 deletions(-)
(limited to 'std/debug')
diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig
index 6eb34929b5..421e964827 100644
--- a/std/c/freebsd.zig
+++ b/std/c/freebsd.zig
@@ -1,4 +1,3 @@
-
const timespec = @import("../os/freebsd/index.zig").timespec;
extern "c" fn __error() *c_int;
@@ -18,7 +17,7 @@ pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usi
pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
-pub const Kevent = extern struct.{
+pub const Kevent = extern struct {
ident: usize,
filter: i16,
flags: u16,
@@ -28,9 +27,7 @@ pub const Kevent = extern struct.{
// TODO ext
};
-
-pub const pthread_attr_t = extern struct.{
+pub const pthread_attr_t = extern struct {
__size: [56]u8,
__align: c_long,
};
-
diff --git a/std/debug/index.zig b/std/debug/index.zig
index a3509b3117..722f95ccb0 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -1101,8 +1101,7 @@ pub const DebugInfo = switch (builtin.os) {
self.elf.close();
}
},
- builtin.Os.freebsd => struct.{
- },
+ builtin.Os.freebsd => struct {},
else => @compileError("Unsupported OS"),
};
diff --git a/std/mem.zig b/std/mem.zig
index 6b37dfe401..6b115a56f6 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -475,8 +475,8 @@ test "readIntBE/LE" {
assert(readIntBE(u8, []u8{0x32}) == 0x32);
assert(readIntLE(u8, []u8{0x12}) == 0x12);
- assert(readIntBE(u16, []u8{0x12, 0x34}) == 0x1234);
- assert(readIntLE(u16, []u8{0x12, 0x34}) == 0x3412);
+ assert(readIntBE(u16, []u8{ 0x12, 0x34 }) == 0x1234);
+ assert(readIntLE(u16, []u8{ 0x12, 0x34 }) == 0x3412);
assert(readIntBE(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024);
assert(readIntLE(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec);
@@ -484,8 +484,8 @@ test "readIntBE/LE" {
assert(readIntBE(i8, []u8{0xff}) == -1);
assert(readIntLE(i8, []u8{0xfe}) == -2);
- assert(readIntBE(i16, []u8{0xff, 0xfd}) == -3);
- assert(readIntLE(i16, []u8{0xfc, 0xff}) == -4);
+ assert(readIntBE(i16, []u8{ 0xff, 0xfd }) == -3);
+ assert(readIntLE(i16, []u8{ 0xfc, 0xff }) == -4);
}
/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes
diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig
index 1793379fb5..75389fc403 100644
--- a/std/os/freebsd/index.zig
+++ b/std/os/freebsd/index.zig
@@ -377,7 +377,6 @@ pub const NOTE_FFCOPY = 0xc0000000;
pub const NOTE_FFCTRLMASK = 0xc0000000;
pub const NOTE_FFLAGSMASK = 0x00ffffff;
-
/// low water mark
pub const NOTE_LOWAT = 0x00000001;
@@ -445,8 +444,6 @@ pub const NOTE_NSECONDS = 0x00000008;
/// timeout is absolute
pub const NOTE_ABSTIME = 0x00000010;
-
-
pub const TCGETS = 0x5401;
pub const TCSETS = 0x5402;
pub const TCSETSW = 0x5403;
@@ -528,7 +525,7 @@ pub fn WIFSIGNALED(s: i32) bool {
return (unsigned(s) & 0xffff) -% 1 < 0xff;
}
-pub const winsize = extern struct.{
+pub const winsize = extern struct {
ws_row: u16,
ws_col: u16,
ws_xpixel: u16,
@@ -703,11 +700,11 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti
const NSIG = 65;
const sigset_t = [128 / @sizeOf(usize)]usize;
-const all_mask = []usize.{@maxValue(usize)};
-const app_mask = []usize.{0xfffffffc7fffffff};
+const all_mask = []usize{@maxValue(usize)};
+const app_mask = []usize{0xfffffffc7fffffff};
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = struct.{
+pub const Sigaction = struct {
// TODO: Adjust to use freebsd struct layout
handler: extern fn (i32) void,
mask: sigset_t,
@@ -717,7 +714,7 @@ pub const Sigaction = struct.{
pub const SIG_ERR = @intToPtr(extern fn (i32) void, @maxValue(usize));
pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
-pub const empty_sigset = []usize.{0} ** sigset_t.len;
+pub const empty_sigset = []usize{0} ** sigset_t.len;
pub fn raise(sig: i32) usize {
// TODO implement, see linux equivalent for what we want to try and do
@@ -753,12 +750,12 @@ pub fn fstat(fd: i32, stat_buf: *Stat) usize {
return arch.syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf));
}
-pub const iovec = extern struct.{
+pub const iovec = extern struct {
iov_base: [*]u8,
iov_len: usize,
};
-pub const iovec_const = extern struct.{
+pub const iovec_const = extern struct {
iov_base: [*]const u8,
iov_len: usize,
};
@@ -790,13 +787,9 @@ pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
}
-
-
/// Takes the return value from a syscall and formats it back in the way
/// that the kernel represents it to libc. Errno was a mistake, let's make
/// it go away forever.
fn errnoWrap(value: isize) usize {
return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
}
-
-
diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig
index 28ae2d5471..20a6710596 100644
--- a/std/os/freebsd/x86_64.zig
+++ b/std/os/freebsd/x86_64.zig
@@ -97,7 +97,7 @@ pub nakedcc fn restore_rt() void {
);
}
-pub const msghdr = extern struct.{
+pub const msghdr = extern struct {
msg_name: &u8,
msg_namelen: socklen_t,
msg_iov: &iovec,
@@ -110,7 +110,7 @@ pub const msghdr = extern struct.{
};
/// Renamed to Stat to not conflict with the stat function.
-pub const Stat = extern struct.{
+pub const Stat = extern struct {
dev: u64,
ino: u64,
nlink: usize,
@@ -130,7 +130,7 @@ pub const Stat = extern struct.{
__unused: [3]isize,
};
-pub const timespec = extern struct.{
+pub const timespec = extern struct {
tv_sec: isize,
tv_nsec: isize,
};
diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig
index 070a26bf71..a15be317ab 100644
--- a/std/special/bootstrap.zig
+++ b/std/special/bootstrap.zig
@@ -23,7 +23,7 @@ nakedcc fn _start() noreturn {
builtin.Arch.x86_64 => switch (builtin.os) {
builtin.Os.freebsd => {
argc_ptr = asm ("lea (%%rdi), %[argc]"
- : [argc] "=r" (-> [*]usize)
+ : [argc] "=r" (-> [*]usize)
);
},
else => {
--
cgit v1.2.3
From 1fb15be05f1037aad53d2db32d13123363365d10 Mon Sep 17 00:00:00 2001
From: Sahnvour
Date: Wed, 28 Nov 2018 00:24:06 +0100
Subject: stack traces: fix for windows
---
std/debug/index.zig | 5 +++--
std/pdb.zig | 1 +
2 files changed, 4 insertions(+), 2 deletions(-)
(limited to 'std/debug')
diff --git a/std/debug/index.zig b/std/debug/index.zig
index b077bdb3b0..134f0a479f 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -282,8 +282,9 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
var coff_section: *coff.Section = undefined;
const mod_index = for (di.sect_contribs) |sect_contrib| {
- if (sect_contrib.Section >= di.coff.sections.len) continue;
- coff_section = &di.coff.sections.toSlice()[sect_contrib.Section];
+ if (sect_contrib.Section > di.coff.sections.len) continue;
+ // Remember that SectionContribEntry.Section is 1-based.
+ coff_section = &di.coff.sections.toSlice()[sect_contrib.Section-1];
const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
const vaddr_end = vaddr_start + sect_contrib.Size;
diff --git a/std/pdb.zig b/std/pdb.zig
index 17275ab2a5..2c5df3e597 100644
--- a/std/pdb.zig
+++ b/std/pdb.zig
@@ -34,6 +34,7 @@ pub const DbiStreamHeader = packed struct {
};
pub const SectionContribEntry = packed struct {
+ /// COFF Section index, 1-based
Section: u16,
Padding1: [2]u8,
Offset: u32,
--
cgit v1.2.3
From a40d160a5ca7fe50680578541c40038e280272ce Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 2 Dec 2018 18:35:41 -0500
Subject: introduce std.io.SeekableStream
Relevant #764
dwarf debug info is modified to use this instead of std.os.File
directly to make it easier for bare metal projects to take advantage
of debug info parsing
---
CMakeLists.txt | 1 +
std/debug/index.zig | 218 +++++++++++++++++++++++----------------------
std/elf.zig | 45 +++++-----
std/io.zig | 2 +
std/io/seekable_stream.zig | 32 +++++++
std/os/file.zig | 64 +++++++++++--
6 files changed, 228 insertions(+), 134 deletions(-)
create mode 100644 std/io/seekable_stream.zig
(limited to 'std/debug')
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9492d5dfac..0817c09f2a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -491,6 +491,7 @@ set(ZIG_STD_FILES
"heap.zig"
"index.zig"
"io.zig"
+ "io/seekable_stream.zig"
"json.zig"
"lazy_init.zig"
"linked_list.zig"
diff --git a/std/debug/index.zig b/std/debug/index.zig
index c317432654..3522da0881 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -284,7 +284,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
const mod_index = for (di.sect_contribs) |sect_contrib| {
if (sect_contrib.Section > di.coff.sections.len) continue;
// Remember that SectionContribEntry.Section is 1-based.
- coff_section = &di.coff.sections.toSlice()[sect_contrib.Section-1];
+ coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
const vaddr_end = vaddr_start + sect_contrib.Size;
@@ -872,9 +872,14 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
return list.toOwnedSlice();
}
-fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
+pub fn openDwarfDebugInfo(
+ allocator: *mem.Allocator,
+ dwarf_seekable_stream: *DwarfSeekableStream,
+ dwarf_in_stream: *DwarfInStream,
+) !DebugInfo {
var di = DebugInfo{
- .self_exe_file = undefined,
+ .dwarf_seekable_stream = dwarf_seekable_stream,
+ .dwarf_in_stream = dwarf_in_stream,
.elf = undefined,
.debug_info = undefined,
.debug_abbrev = undefined,
@@ -884,10 +889,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
.compile_unit_list = ArrayList(CompileUnit).init(allocator),
};
- di.self_exe_file = try os.openSelfExe();
- errdefer di.self_exe_file.close();
-
- try di.elf.openFile(allocator, di.self_exe_file);
+ try di.elf.openStream(allocator, dwarf_seekable_stream, dwarf_in_stream);
errdefer di.elf.close();
di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
@@ -899,6 +901,27 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
return di;
}
+fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
+ const S = struct {
+ var self_exe_file: os.File = undefined;
+ var self_exe_seekable_stream: os.File.SeekableStream = undefined;
+ var self_exe_in_stream: os.File.InStream = undefined;
+ };
+ S.self_exe_file = try os.openSelfExe();
+ errdefer S.self_exe_file.close();
+
+ S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
+ S.self_exe_in_stream = S.self_exe_file.inStream();
+
+ return openDwarfDebugInfo(
+ allocator,
+ // TODO https://github.com/ziglang/zig/issues/764
+ @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
+ // TODO https://github.com/ziglang/zig/issues/764
+ @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream),
+ );
+}
+
pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr {
var file_stream = elf.in_file.inStream();
const in = &file_stream.stream;
@@ -1053,6 +1076,9 @@ const MachOFile = struct {
sect_debug_line: ?*const macho.section_64,
};
+pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
+pub const DwarfInStream = io.InStream(anyerror);
+
pub const DebugInfo = switch (builtin.os) {
builtin.Os.macosx => struct {
symbols: []const MachoSymbol,
@@ -1077,7 +1103,8 @@ pub const DebugInfo = switch (builtin.os) {
modules: []Module,
},
builtin.Os.linux => struct {
- self_exe_file: os.File,
+ dwarf_seekable_stream: *DwarfSeekableStream,
+ dwarf_in_stream: *DwarfInStream,
elf: elf.Elf,
debug_info: *elf.SectionHeader,
debug_abbrev: *elf.SectionHeader,
@@ -1092,13 +1119,10 @@ pub const DebugInfo = switch (builtin.os) {
}
pub fn readString(self: *DebugInfo) ![]u8 {
- var in_file_stream = self.self_exe_file.inStream();
- const in_stream = &in_file_stream.stream;
- return readStringRaw(self.allocator(), in_stream);
+ return readStringRaw(self.allocator(), self.dwarf_in_stream);
}
pub fn close(self: *DebugInfo) void {
- self.self_exe_file.close();
self.elf.close();
}
},
@@ -1206,11 +1230,11 @@ const Die = struct {
};
}
- fn getAttrString(self: *const Die, st: *DebugInfo, id: u64) ![]u8 {
+ fn getAttrString(self: *const Die, di: *DebugInfo, id: u64) ![]u8 {
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
return switch (form_value.*) {
FormValue.String => |value| value,
- FormValue.StrPtr => |offset| getString(st, offset),
+ FormValue.StrPtr => |offset| getString(di, offset),
else => error.InvalidDebugInfo,
};
}
@@ -1321,10 +1345,10 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
return buf.toSlice();
}
-fn getString(st: *DebugInfo, offset: u64) ![]u8 {
- const pos = st.debug_str.offset + offset;
- try st.self_exe_file.seekTo(pos);
- return st.readString();
+fn getString(di: *DebugInfo, offset: u64) ![]u8 {
+ const pos = di.debug_str.offset + offset;
+ try di.dwarf_seekable_stream.seekTo(pos);
+ return di.readString();
}
fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
@@ -1371,14 +1395,7 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type
return parseFormValueRefLen(allocator, in_stream, block_len);
}
-const ParseFormValueError = error{
- EndOfStream,
- InvalidDebugInfo,
- EndOfFile,
- OutOfMemory,
-} || std.os.File.ReadError;
-
-fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
+fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
return switch (form_id) {
DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
@@ -1428,25 +1445,22 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
};
}
-fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
- const in_file = st.self_exe_file;
- var in_file_stream = in_file.inStream();
- const in_stream = &in_file_stream.stream;
- var result = AbbrevTable.init(st.allocator());
+fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable {
+ var result = AbbrevTable.init(di.allocator());
while (true) {
- const abbrev_code = try readULeb128(in_stream);
+ const abbrev_code = try readULeb128(di.dwarf_in_stream);
if (abbrev_code == 0) return result;
try result.append(AbbrevTableEntry{
.abbrev_code = abbrev_code,
- .tag_id = try readULeb128(in_stream),
- .has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
- .attrs = ArrayList(AbbrevAttr).init(st.allocator()),
+ .tag_id = try readULeb128(di.dwarf_in_stream),
+ .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
+ .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
});
const attrs = &result.items[result.len - 1].attrs;
while (true) {
- const attr_id = try readULeb128(in_stream);
- const form_id = try readULeb128(in_stream);
+ const attr_id = try readULeb128(di.dwarf_in_stream);
+ const form_id = try readULeb128(di.dwarf_in_stream);
if (attr_id == 0 and form_id == 0) break;
try attrs.append(AbbrevAttr{
.attr_id = attr_id,
@@ -1458,18 +1472,18 @@ fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
/// seeks in the stream and parses it.
-fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable {
- for (st.abbrev_table_list.toSlice()) |*header| {
+fn getAbbrevTable(di: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable {
+ for (di.abbrev_table_list.toSlice()) |*header| {
if (header.offset == abbrev_offset) {
return &header.table;
}
}
- try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
- try st.abbrev_table_list.append(AbbrevTableHeader{
+ try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
+ try di.abbrev_table_list.append(AbbrevTableHeader{
.offset = abbrev_offset,
- .table = try parseAbbrevTable(st),
+ .table = try parseAbbrevTable(di),
});
- return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
+ return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
}
fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
@@ -1479,23 +1493,20 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
return null;
}
-fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
- const in_file = st.self_exe_file;
- var in_file_stream = in_file.inStream();
- const in_stream = &in_file_stream.stream;
- const abbrev_code = try readULeb128(in_stream);
+fn parseDie(di: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
+ const abbrev_code = try readULeb128(di.dwarf_in_stream);
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
var result = Die{
.tag_id = table_entry.tag_id,
.has_children = table_entry.has_children,
- .attrs = ArrayList(Die.Attr).init(st.allocator()),
+ .attrs = ArrayList(Die.Attr).init(di.allocator()),
};
try result.attrs.resize(table_entry.attrs.len);
for (table_entry.attrs.toSliceConst()) |attr, i| {
result.attrs.items[i] = Die.Attr{
.id = attr.attr_id,
- .value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
+ .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
};
}
return result;
@@ -1702,19 +1713,15 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
- const in_file = di.self_exe_file;
const debug_line_end = di.debug_line.offset + di.debug_line.size;
var this_offset = di.debug_line.offset;
var this_index: usize = 0;
- var in_file_stream = in_file.inStream();
- const in_stream = &in_file_stream.stream;
-
while (this_offset < debug_line_end) : (this_index += 1) {
- try in_file.seekTo(this_offset);
+ try di.dwarf_seekable_stream.seekTo(this_offset);
var is_64: bool = undefined;
- const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
+ const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
if (unit_length == 0) return error.MissingDebugInfo;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
@@ -1723,35 +1730,35 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
continue;
}
- const version = try in_stream.readInt(di.elf.endian, u16);
+ const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
// TODO support 3 and 5
if (version != 2 and version != 4) return error.InvalidDebugInfo;
- const prologue_length = if (is_64) try in_stream.readInt(di.elf.endian, u64) else try in_stream.readInt(di.elf.endian, u32);
- const prog_start_offset = (try in_file.getPos()) + prologue_length;
+ const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32);
+ const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
- const minimum_instruction_length = try in_stream.readByte();
+ const minimum_instruction_length = try di.dwarf_in_stream.readByte();
if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
if (version >= 4) {
// maximum_operations_per_instruction
- _ = try in_stream.readByte();
+ _ = try di.dwarf_in_stream.readByte();
}
- const default_is_stmt = (try in_stream.readByte()) != 0;
- const line_base = try in_stream.readByteSigned();
+ const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
+ const line_base = try di.dwarf_in_stream.readByteSigned();
- const line_range = try in_stream.readByte();
+ const line_range = try di.dwarf_in_stream.readByte();
if (line_range == 0) return error.InvalidDebugInfo;
- const opcode_base = try in_stream.readByte();
+ const opcode_base = try di.dwarf_in_stream.readByte();
const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
{
var i: usize = 0;
while (i < opcode_base - 1) : (i += 1) {
- standard_opcode_lengths[i] = try in_stream.readByte();
+ standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
}
}
@@ -1769,9 +1776,9 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
while (true) {
const file_name = try di.readString();
if (file_name.len == 0) break;
- const dir_index = try readULeb128(in_stream);
- const mtime = try readULeb128(in_stream);
- const len_bytes = try readULeb128(in_stream);
+ const dir_index = try readULeb128(di.dwarf_in_stream);
+ const mtime = try readULeb128(di.dwarf_in_stream);
+ const len_bytes = try readULeb128(di.dwarf_in_stream);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
@@ -1780,15 +1787,15 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
});
}
- try in_file.seekTo(prog_start_offset);
+ try di.dwarf_seekable_stream.seekTo(prog_start_offset);
while (true) {
- const opcode = try in_stream.readByte();
+ const opcode = try di.dwarf_in_stream.readByte();
if (opcode == DW.LNS_extended_op) {
- const op_size = try readULeb128(in_stream);
+ const op_size = try readULeb128(di.dwarf_in_stream);
if (op_size < 1) return error.InvalidDebugInfo;
- var sub_op = try in_stream.readByte();
+ var sub_op = try di.dwarf_in_stream.readByte();
switch (sub_op) {
DW.LNE_end_sequence => {
prog.end_sequence = true;
@@ -1796,14 +1803,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
return error.MissingDebugInfo;
},
DW.LNE_set_address => {
- const addr = try in_stream.readInt(di.elf.endian, usize);
+ const addr = try di.dwarf_in_stream.readInt(di.elf.endian, usize);
prog.address = addr;
},
DW.LNE_define_file => {
const file_name = try di.readString();
- const dir_index = try readULeb128(in_stream);
- const mtime = try readULeb128(in_stream);
- const len_bytes = try readULeb128(in_stream);
+ const dir_index = try readULeb128(di.dwarf_in_stream);
+ const mtime = try readULeb128(di.dwarf_in_stream);
+ const len_bytes = try readULeb128(di.dwarf_in_stream);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
@@ -1813,7 +1820,7 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
},
else => {
const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
- try in_file.seekForward(fwd_amt);
+ try di.dwarf_seekable_stream.seekForward(fwd_amt);
},
}
} else if (opcode >= opcode_base) {
@@ -1832,19 +1839,19 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
prog.basic_block = false;
},
DW.LNS_advance_pc => {
- const arg = try readULeb128(in_stream);
+ const arg = try readULeb128(di.dwarf_in_stream);
prog.address += arg * minimum_instruction_length;
},
DW.LNS_advance_line => {
- const arg = try readILeb128(in_stream);
+ const arg = try readILeb128(di.dwarf_in_stream);
prog.line += arg;
},
DW.LNS_set_file => {
- const arg = try readULeb128(in_stream);
+ const arg = try readULeb128(di.dwarf_in_stream);
prog.file = arg;
},
DW.LNS_set_column => {
- const arg = try readULeb128(in_stream);
+ const arg = try readULeb128(di.dwarf_in_stream);
prog.column = arg;
},
DW.LNS_negate_stmt => {
@@ -1858,14 +1865,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
prog.address += inc_addr;
},
DW.LNS_fixed_advance_pc => {
- const arg = try in_stream.readInt(di.elf.endian, u16);
+ const arg = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
prog.address += arg;
},
DW.LNS_set_prologue_end => {},
else => {
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
const len_bytes = standard_opcode_lengths[opcode - 1];
- try in_file.seekForward(len_bytes);
+ try di.dwarf_seekable_stream.seekForward(len_bytes);
},
}
}
@@ -1877,36 +1884,33 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
return error.MissingDebugInfo;
}
-fn scanAllCompileUnits(st: *DebugInfo) !void {
- const debug_info_end = st.debug_info.offset + st.debug_info.size;
- var this_unit_offset = st.debug_info.offset;
+fn scanAllCompileUnits(di: *DebugInfo) !void {
+ const debug_info_end = di.debug_info.offset + di.debug_info.size;
+ var this_unit_offset = di.debug_info.offset;
var cu_index: usize = 0;
- var in_file_stream = st.self_exe_file.inStream();
- const in_stream = &in_file_stream.stream;
-
while (this_unit_offset < debug_info_end) {
- try st.self_exe_file.seekTo(this_unit_offset);
+ try di.dwarf_seekable_stream.seekTo(this_unit_offset);
var is_64: bool = undefined;
- const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
+ const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
if (unit_length == 0) return;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
- const version = try in_stream.readInt(st.elf.endian, u16);
+ const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
- const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
+ const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32);
- const address_size = try in_stream.readByte();
+ const address_size = try di.dwarf_in_stream.readByte();
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
- const compile_unit_pos = try st.self_exe_file.getPos();
- const abbrev_table = try getAbbrevTable(st, debug_abbrev_offset);
+ const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
+ const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
- try st.self_exe_file.seekTo(compile_unit_pos);
+ try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
- const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64));
+ const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64));
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
@@ -1934,7 +1938,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
}
};
- try st.compile_unit_list.append(CompileUnit{
+ try di.compile_unit_list.append(CompileUnit{
.version = version,
.is_64 = is_64,
.pc_range = pc_range,
@@ -1947,20 +1951,18 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
}
}
-fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {
- var in_file_stream = st.self_exe_file.inStream();
- const in_stream = &in_file_stream.stream;
- for (st.compile_unit_list.toSlice()) |*compile_unit| {
+fn findCompileUnit(di: *DebugInfo, target_address: u64) !*const CompileUnit {
+ for (di.compile_unit_list.toSlice()) |*compile_unit| {
if (compile_unit.pc_range) |range| {
if (target_address >= range.start and target_address < range.end) return compile_unit;
}
if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
var base_address: usize = 0;
- if (st.debug_ranges) |debug_ranges| {
- try st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
+ if (di.debug_ranges) |debug_ranges| {
+ try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
while (true) {
- const begin_addr = try in_stream.readIntLe(usize);
- const end_addr = try in_stream.readIntLe(usize);
+ const begin_addr = try di.dwarf_in_stream.readIntLe(usize);
+ const end_addr = try di.dwarf_in_stream.readIntLe(usize);
if (begin_addr == 0 and end_addr == 0) {
break;
}
diff --git a/std/elf.zig b/std/elf.zig
index e95222744d..cf7c29b1e5 100644
--- a/std/elf.zig
+++ b/std/elf.zig
@@ -353,7 +353,8 @@ pub const SectionHeader = struct {
};
pub const Elf = struct {
- in_file: os.File,
+ seekable_stream: *io.SeekableStream(anyerror, anyerror),
+ in_stream: *io.InStream(anyerror),
auto_close_stream: bool,
is_64: bool,
endian: builtin.Endian,
@@ -370,19 +371,24 @@ pub const Elf = struct {
/// Call close when done.
pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
- try elf.prealloc_file.open(path);
- try elf.openFile(allocator, *elf.prealloc_file);
- elf.auto_close_stream = true;
+ @compileError("TODO implement");
}
/// Call close when done.
pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {
- elf.allocator = allocator;
- elf.in_file = file;
- elf.auto_close_stream = false;
+ @compileError("TODO implement");
+ }
- var file_stream = elf.in_file.inStream();
- const in = &file_stream.stream;
+ pub fn openStream(
+ elf: *Elf,
+ allocator: *mem.Allocator,
+ seekable_stream: *io.SeekableStream(anyerror, anyerror),
+ in: *io.InStream(anyerror),
+ ) !void {
+ elf.auto_close_stream = false;
+ elf.allocator = allocator;
+ elf.seekable_stream = seekable_stream;
+ elf.in_stream = in;
var magic: [4]u8 = undefined;
try in.readNoEof(magic[0..]);
@@ -404,7 +410,7 @@ pub const Elf = struct {
if (version_byte != 1) return error.InvalidFormat;
// skip over padding
- try elf.in_file.seekForward(9);
+ try seekable_stream.seekForward(9);
elf.file_type = switch (try in.readInt(elf.endian, u16)) {
1 => FileType.Relocatable,
@@ -441,7 +447,7 @@ pub const Elf = struct {
}
// skip over flags
- try elf.in_file.seekForward(4);
+ try seekable_stream.seekForward(4);
const header_size = try in.readInt(elf.endian, u16);
if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
@@ -461,12 +467,12 @@ pub const Elf = struct {
const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count);
- const stream_end = try elf.in_file.getEndPos();
+ const stream_end = try seekable_stream.getEndPos();
if (stream_end < end_sh or stream_end < end_ph) {
return error.InvalidFormat;
}
- try elf.in_file.seekTo(elf.section_header_offset);
+ try seekable_stream.seekTo(elf.section_header_offset);
elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count);
errdefer elf.allocator.free(elf.section_headers);
@@ -521,26 +527,23 @@ pub const Elf = struct {
pub fn close(elf: *Elf) void {
elf.allocator.free(elf.section_headers);
- if (elf.auto_close_stream) elf.in_file.close();
+ if (elf.auto_close_stream) elf.prealloc_file.close();
}
pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
- var file_stream = elf.in_file.inStream();
- const in = &file_stream.stream;
-
section_loop: for (elf.section_headers) |*elf_section| {
if (elf_section.sh_type == SHT_NULL) continue;
const name_offset = elf.string_section.offset + elf_section.name;
- try elf.in_file.seekTo(name_offset);
+ try elf.seekable_stream.seekTo(name_offset);
for (name) |expected_c| {
- const target_c = try in.readByte();
+ const target_c = try elf.in_stream.readByte();
if (target_c == 0 or expected_c != target_c) continue :section_loop;
}
{
- const null_byte = try in.readByte();
+ const null_byte = try elf.in_stream.readByte();
if (null_byte == 0) return elf_section;
}
}
@@ -549,7 +552,7 @@ pub const Elf = struct {
}
pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void {
- try elf.in_file.seekTo(elf_section.offset);
+ try elf.seekable_stream.seekTo(elf_section.offset);
}
};
diff --git a/std/io.zig b/std/io.zig
index f4122a2f8b..bdca2b03e8 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -32,6 +32,8 @@ pub fn getStdIn() GetStdIoErrs!File {
return File.openHandle(handle);
}
+pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
+
pub fn InStream(comptime ReadError: type) type {
return struct {
const Self = @This();
diff --git a/std/io/seekable_stream.zig b/std/io/seekable_stream.zig
new file mode 100644
index 0000000000..a766f4fb89
--- /dev/null
+++ b/std/io/seekable_stream.zig
@@ -0,0 +1,32 @@
+const std = @import("../index.zig");
+const InStream = std.io.InStream;
+
+pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {
+ return struct {
+ const Self = @This();
+ pub const SeekError = SeekErrorType;
+ pub const GetSeekPosError = GetSeekPosErrorType;
+
+ seekToFn: fn (self: *Self, pos: usize) SeekError!void,
+ seekForwardFn: fn (self: *Self, pos: isize) SeekError!void,
+
+ getPosFn: fn (self: *Self) GetSeekPosError!usize,
+ getEndPosFn: fn (self: *Self) GetSeekPosError!usize,
+
+ pub fn seekTo(self: *Self, pos: usize) SeekError!void {
+ return self.seekToFn(self, pos);
+ }
+
+ pub fn seekForward(self: *Self, amt: isize) SeekError!void {
+ return self.seekForwardFn(self, amt);
+ }
+
+ pub fn getEndPos(self: *Self) GetSeekPosError!usize {
+ return self.getEndPosFn(self);
+ }
+
+ pub fn getPos(self: *Self) GetSeekPosError!usize {
+ return self.getPosFn(self);
+ }
+ };
+}
diff --git a/std/os/file.zig b/std/os/file.zig
index 82bd24fec0..2ae547c694 100644
--- a/std/os/file.zig
+++ b/std/os/file.zig
@@ -228,7 +228,14 @@ pub const File = struct {
return os.isTty(self.handle);
}
- pub fn seekForward(self: File, amount: isize) !void {
+ pub const SeekError = error{
+ /// TODO make this error impossible to get
+ Overflow,
+ Unseekable,
+ Unexpected,
+ };
+
+ pub fn seekForward(self: File, amount: isize) SeekError!void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
@@ -259,7 +266,7 @@ pub const File = struct {
}
}
- pub fn seekTo(self: File, pos: usize) !void {
+ pub fn seekTo(self: File, pos: usize) SeekError!void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const ipos = try math.cast(isize, pos);
@@ -293,7 +300,14 @@ pub const File = struct {
}
}
- pub fn getPos(self: File) !usize {
+ pub const GetSeekPosError = error{
+ Overflow,
+ SystemResources,
+ Unseekable,
+ Unexpected,
+ };
+
+ pub fn getPos(self: File) GetSeekPosError!usize {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
@@ -323,13 +337,13 @@ pub const File = struct {
}
assert(pos >= 0);
- return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange;
+ return math.cast(usize, pos);
},
else => @compileError("unsupported OS"),
}
}
- pub fn getEndPos(self: File) !usize {
+ pub fn getEndPos(self: File) GetSeekPosError!usize {
if (is_posix) {
const stat = try os.posixFStat(self.handle);
return @intCast(usize, stat.size);
@@ -431,6 +445,18 @@ pub const File = struct {
};
}
+ pub fn seekableStream(file: File) SeekableStream {
+ return SeekableStream{
+ .file = file,
+ .stream = SeekableStream.Stream{
+ .seekToFn = SeekableStream.seekToFn,
+ .seekForwardFn = SeekableStream.seekForwardFn,
+ .getPosFn = SeekableStream.getPosFn,
+ .getEndPosFn = SeekableStream.getEndPosFn,
+ },
+ };
+ }
+
/// Implementation of io.InStream trait for File
pub const InStream = struct {
file: File,
@@ -458,4 +484,32 @@ pub const File = struct {
return self.file.write(bytes);
}
};
+
+ /// Implementation of io.SeekableStream trait for File
+ pub const SeekableStream = struct {
+ file: File,
+ stream: Stream,
+
+ pub const Stream = io.SeekableStream(SeekError, GetSeekPosError);
+
+ pub fn seekToFn(seekable_stream: *Stream, pos: usize) SeekError!void {
+ const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
+ return self.file.seekTo(pos);
+ }
+
+ pub fn seekForwardFn(seekable_stream: *Stream, amt: isize) SeekError!void {
+ const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
+ return self.file.seekForward(amt);
+ }
+
+ pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!usize {
+ const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
+ return self.file.getEndPos();
+ }
+
+ pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!usize {
+ const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
+ return self.file.getPos();
+ }
+ };
};
--
cgit v1.2.3
From 4292ed9571ede4d616e92e9cba3986a07d135955 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 2 Dec 2018 18:54:04 -0500
Subject: std.debug.StackIterator
---
std/debug/index.zig | 69 +++++++++++++++++++++++++----------------------------
1 file changed, 33 insertions(+), 36 deletions(-)
(limited to 'std/debug')
diff --git a/std/debug/index.zig b/std/debug/index.zig
index 3522da0881..268087664f 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -198,49 +198,46 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var,
}
}
-pub inline fn getReturnAddress(frame_count: usize) usize {
- var fp = @ptrToInt(@frameAddress());
- var i: usize = 0;
- while (fp != 0 and i < frame_count) {
- fp = @intToPtr(*const usize, fp).*;
- i += 1;
+pub const StackIterator = struct {
+ first_addr: ?usize,
+ debug_info: *DebugInfo,
+ fp: usize,
+
+ pub fn init(debug_info: *DebugInfo, first_addr: ?usize) StackIterator {
+ return StackIterator{
+ .debug_info = debug_info,
+ .first_addr = first_addr,
+ .fp = @ptrToInt(@frameAddress()),
+ };
}
- return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
-}
+
+ fn next(self: *StackIterator) ?usize {
+ if (self.fp == 0) return null;
+ self.fp = @intToPtr(*const usize, self.fp).*;
+ if (self.fp == 0) return null;
+
+ if (self.first_addr) |addr| {
+ while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) {
+ const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
+ if (addr == return_address) {
+ self.first_addr = null;
+ return return_address;
+ }
+ }
+ }
+
+ const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
+ return return_address;
+ }
+};
pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
switch (builtin.os) {
builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
else => {},
}
- const AddressState = union(enum) {
- NotLookingForStartAddress,
- LookingForStartAddress: usize,
- };
- // TODO: I want to express like this:
- //var addr_state = if (start_addr) |addr| AddressState { .LookingForStartAddress = addr }
- // else AddressState.NotLookingForStartAddress;
- var addr_state: AddressState = undefined;
- if (start_addr) |addr| {
- addr_state = AddressState{ .LookingForStartAddress = addr };
- } else {
- addr_state = AddressState.NotLookingForStartAddress;
- }
-
- var fp = @ptrToInt(@frameAddress());
- while (fp != 0) : (fp = @intToPtr(*const usize, fp).*) {
- const return_address = @intToPtr(*const usize, fp + @sizeOf(usize)).*;
-
- switch (addr_state) {
- AddressState.NotLookingForStartAddress => {},
- AddressState.LookingForStartAddress => |addr| {
- if (return_address == addr) {
- addr_state = AddressState.NotLookingForStartAddress;
- } else {
- continue;
- }
- },
- }
+ var it = StackIterator.init(debug_info, start_addr);
+ while (it.next()) |return_address| {
try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
}
}
--
cgit v1.2.3
From a436d2ab8c61f46d97a5c31ac083ef8fa54ed706 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 2 Dec 2018 19:34:11 -0500
Subject: std.debug.printSourceAtAddressDwarf
which works in freestanding mode
---
std/debug/index.zig | 54 ++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 43 insertions(+), 11 deletions(-)
(limited to 'std/debug')
diff --git a/std/debug/index.zig b/std/debug/index.zig
index 268087664f..b74c412df1 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -411,7 +411,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
if (opt_line_info) |line_info| {
try out_stream.print("\n");
- if (printLineFromFile(out_stream, line_info)) {
+ if (printLineFromFileAnyOs(out_stream, line_info)) {
if (line_info.column == 0) {
try out_stream.write("\n");
} else {
@@ -595,7 +595,16 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
} else "???";
if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
defer line_info.deinit();
- try printLineInfo(di, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color);
+ try printLineInfo(
+ di,
+ out_stream,
+ line_info,
+ address,
+ symbol_name,
+ compile_unit_name,
+ tty_color,
+ printLineFromFileAnyOs,
+ );
} else |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => {
if (tty_color) {
@@ -608,7 +617,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
}
}
-pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
+/// This function works in freestanding mode.
+/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
+pub fn printSourceAtAddressDwarf(
+ debug_info: *DebugInfo,
+ out_stream: var,
+ address: usize,
+ tty_color: bool,
+ comptime printLineFromFile: var,
+) !void {
const compile_unit = findCompileUnit(debug_info, address) catch {
if (tty_color) {
try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
@@ -618,10 +635,19 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres
return;
};
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
- if (getLineNumberInfoLinux(debug_info, compile_unit, address - 1)) |line_info| {
+ if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
defer line_info.deinit();
const symbol_name = "???";
- try printLineInfo(debug_info, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color);
+ try printLineInfo(
+ debug_info,
+ out_stream,
+ line_info,
+ address,
+ symbol_name,
+ compile_unit_name,
+ tty_color,
+ printLineFromFile,
+ );
} else |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => {
if (tty_color) {
@@ -634,6 +660,10 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres
}
}
+pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
+ return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
+}
+
fn printLineInfo(
debug_info: *DebugInfo,
out_stream: var,
@@ -642,6 +672,7 @@ fn printLineInfo(
symbol_name: []const u8,
compile_unit_name: []const u8,
tty_color: bool,
+ comptime printLineFromFile: var,
) !void {
if (tty_color) {
try out_stream.print(
@@ -1020,7 +1051,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
};
}
-fn printLineFromFile(out_stream: var, line_info: LineInfo) !void {
+fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
var f = try os.File.openRead(line_info.file_name);
defer f.close();
// TODO fstat and make sure that the file has the correct size
@@ -1247,11 +1278,12 @@ const FileEntry = struct {
const LineInfo = struct {
line: usize,
column: usize,
- file_name: []u8,
- allocator: *mem.Allocator,
+ file_name: []const u8,
+ allocator: ?*mem.Allocator,
- fn deinit(self: *const LineInfo) void {
- self.allocator.free(self.file_name);
+ fn deinit(self: LineInfo) void {
+ const allocator = self.allocator orelse return;
+ allocator.free(self.file_name);
}
};
@@ -1707,7 +1739,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
return error.MissingDebugInfo;
}
-fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
+fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
const debug_line_end = di.debug_line.offset + di.debug_line.size;
--
cgit v1.2.3
From 5c3b8cb3659172b539423972d996a66221c0e4a0 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 2 Dec 2018 20:08:06 -0500
Subject: expose std.debug.DwarfInfo and delete unused function
---
std/debug/index.zig | 74 +++++++++++++++++++----------------------------------
1 file changed, 26 insertions(+), 48 deletions(-)
(limited to 'std/debug')
diff --git a/std/debug/index.zig b/std/debug/index.zig
index b74c412df1..ebf0f21a7f 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -950,30 +950,6 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
);
}
-pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr {
- var file_stream = elf.in_file.inStream();
- const in = &file_stream.stream;
-
- section_loop: for (elf.section_headers) |*elf_section| {
- if (elf_section.sh_type == SHT_NULL) continue;
-
- const name_offset = elf.string_section.offset + elf_section.name;
- try elf.in_file.seekTo(name_offset);
-
- for (name) |expected_c| {
- const target_c = try in.readByte();
- if (target_c == 0 or expected_c != target_c) continue :section_loop;
- }
-
- {
- const null_byte = try in.readByte();
- if (null_byte == 0) return elf_section;
- }
- }
-
- return null;
-}
-
fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
const hdr = &std.c._mh_execute_header;
assert(hdr.magic == std.macho.MH_MAGIC_64);
@@ -1107,6 +1083,31 @@ const MachOFile = struct {
pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
pub const DwarfInStream = io.InStream(anyerror);
+pub const DwarfInfo = struct {
+ dwarf_seekable_stream: *DwarfSeekableStream,
+ dwarf_in_stream: *DwarfInStream,
+ elf: elf.Elf,
+ debug_info: *elf.SectionHeader,
+ debug_abbrev: *elf.SectionHeader,
+ debug_str: *elf.SectionHeader,
+ debug_line: *elf.SectionHeader,
+ debug_ranges: ?*elf.SectionHeader,
+ abbrev_table_list: ArrayList(AbbrevTableHeader),
+ compile_unit_list: ArrayList(CompileUnit),
+
+ pub fn allocator(self: DebugInfo) *mem.Allocator {
+ return self.abbrev_table_list.allocator;
+ }
+
+ pub fn readString(self: *DebugInfo) ![]u8 {
+ return readStringRaw(self.allocator(), self.dwarf_in_stream);
+ }
+
+ pub fn close(self: *DebugInfo) void {
+ self.elf.close();
+ }
+};
+
pub const DebugInfo = switch (builtin.os) {
builtin.Os.macosx => struct {
symbols: []const MachoSymbol,
@@ -1130,30 +1131,7 @@ pub const DebugInfo = switch (builtin.os) {
sect_contribs: []pdb.SectionContribEntry,
modules: []Module,
},
- builtin.Os.linux => struct {
- dwarf_seekable_stream: *DwarfSeekableStream,
- dwarf_in_stream: *DwarfInStream,
- elf: elf.Elf,
- debug_info: *elf.SectionHeader,
- debug_abbrev: *elf.SectionHeader,
- debug_str: *elf.SectionHeader,
- debug_line: *elf.SectionHeader,
- debug_ranges: ?*elf.SectionHeader,
- abbrev_table_list: ArrayList(AbbrevTableHeader),
- compile_unit_list: ArrayList(CompileUnit),
-
- pub fn allocator(self: DebugInfo) *mem.Allocator {
- return self.abbrev_table_list.allocator;
- }
-
- pub fn readString(self: *DebugInfo) ![]u8 {
- return readStringRaw(self.allocator(), self.dwarf_in_stream);
- }
-
- pub fn close(self: *DebugInfo) void {
- self.elf.close();
- }
- },
+ builtin.Os.linux => DwarfInfo,
builtin.Os.freebsd => struct {},
else => @compileError("Unsupported OS"),
};
--
cgit v1.2.3
From 3a1612a0f5a41f5cfc9598dc4512b43ee17d030a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 2 Dec 2018 23:46:45 -0500
Subject: std.debug: fix some issues with freestanding debug info
---
std/debug/index.zig | 132 ++++++++++++++++++++++++++++------------------------
1 file changed, 71 insertions(+), 61 deletions(-)
(limited to 'std/debug')
diff --git a/std/debug/index.zig b/std/debug/index.zig
index ebf0f21a7f..4a96e9d259 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -200,12 +200,10 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var,
pub const StackIterator = struct {
first_addr: ?usize,
- debug_info: *DebugInfo,
fp: usize,
- pub fn init(debug_info: *DebugInfo, first_addr: ?usize) StackIterator {
+ pub fn init(first_addr: ?usize) StackIterator {
return StackIterator{
- .debug_info = debug_info,
.first_addr = first_addr,
.fp = @ptrToInt(@frameAddress()),
};
@@ -236,7 +234,7 @@ pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color
builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
else => {},
}
- var it = StackIterator.init(debug_info, start_addr);
+ var it = StackIterator.init(start_addr);
while (it.next()) |return_address| {
try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
}
@@ -596,7 +594,6 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
defer line_info.deinit();
try printLineInfo(
- di,
out_stream,
line_info,
address,
@@ -620,7 +617,7 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
/// This function works in freestanding mode.
/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
pub fn printSourceAtAddressDwarf(
- debug_info: *DebugInfo,
+ debug_info: *DwarfInfo,
out_stream: var,
address: usize,
tty_color: bool,
@@ -639,7 +636,6 @@ pub fn printSourceAtAddressDwarf(
defer line_info.deinit();
const symbol_name = "???";
try printLineInfo(
- debug_info,
out_stream,
line_info,
address,
@@ -665,7 +661,6 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres
}
fn printLineInfo(
- debug_info: *DebugInfo,
out_stream: var,
line_info: LineInfo,
address: usize,
@@ -900,36 +895,50 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
return list.toOwnedSlice();
}
-pub fn openDwarfDebugInfo(
+fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {
+ const elf_header = (try elf_file.findSection(name)) orelse return null;
+ return DwarfInfo.Section{
+ .offset = elf_header.offset,
+ .size = elf_header.size,
+ };
+}
+
+/// Initialize DWARF info. The caller has the responsibility to initialize most
+/// the DwarfInfo fields before calling. These fields can be left undefined:
+/// * abbrev_table_list
+/// * compile_unit_list
+pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
+ di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
+ di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
+ try scanAllCompileUnits(di);
+}
+
+pub fn openElfDebugInfo(
allocator: *mem.Allocator,
- dwarf_seekable_stream: *DwarfSeekableStream,
- dwarf_in_stream: *DwarfInStream,
-) !DebugInfo {
- var di = DebugInfo{
- .dwarf_seekable_stream = dwarf_seekable_stream,
- .dwarf_in_stream = dwarf_in_stream,
- .elf = undefined,
- .debug_info = undefined,
- .debug_abbrev = undefined,
- .debug_str = undefined,
- .debug_line = undefined,
- .debug_ranges = null,
- .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
- .compile_unit_list = ArrayList(CompileUnit).init(allocator),
+ elf_seekable_stream: *DwarfSeekableStream,
+ elf_in_stream: *DwarfInStream,
+) !DwarfInfo {
+ var efile: elf.Elf = undefined;
+ try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
+ errdefer efile.close();
+
+ var di = DwarfInfo{
+ .dwarf_seekable_stream = elf_seekable_stream,
+ .dwarf_in_stream = elf_in_stream,
+ .endian = efile.endian,
+ .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo,
+ .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo,
+ .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo,
+ .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo,
+ .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
+ .abbrev_table_list = undefined,
+ .compile_unit_list = undefined,
};
- try di.elf.openStream(allocator, dwarf_seekable_stream, dwarf_in_stream);
- errdefer di.elf.close();
-
- di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
- di.debug_abbrev = (try di.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo;
- di.debug_str = (try di.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo;
- di.debug_line = (try di.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo;
- di.debug_ranges = (try di.elf.findSection(".debug_ranges"));
- try scanAllCompileUnits(&di);
+ try openDwarfDebugInfo(&di, allocator);
return di;
}
-fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
+fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {
const S = struct {
var self_exe_file: os.File = undefined;
var self_exe_seekable_stream: os.File.SeekableStream = undefined;
@@ -941,7 +950,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
S.self_exe_in_stream = S.self_exe_file.inStream();
- return openDwarfDebugInfo(
+ return openElfDebugInfo(
allocator,
// TODO https://github.com/ziglang/zig/issues/764
@ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
@@ -1086,26 +1095,27 @@ pub const DwarfInStream = io.InStream(anyerror);
pub const DwarfInfo = struct {
dwarf_seekable_stream: *DwarfSeekableStream,
dwarf_in_stream: *DwarfInStream,
- elf: elf.Elf,
- debug_info: *elf.SectionHeader,
- debug_abbrev: *elf.SectionHeader,
- debug_str: *elf.SectionHeader,
- debug_line: *elf.SectionHeader,
- debug_ranges: ?*elf.SectionHeader,
+ endian: builtin.Endian,
+ debug_info: Section,
+ debug_abbrev: Section,
+ debug_str: Section,
+ debug_line: Section,
+ debug_ranges: ?Section,
abbrev_table_list: ArrayList(AbbrevTableHeader),
compile_unit_list: ArrayList(CompileUnit),
- pub fn allocator(self: DebugInfo) *mem.Allocator {
+ pub const Section = struct {
+ offset: usize,
+ size: usize,
+ };
+
+ pub fn allocator(self: DwarfInfo) *mem.Allocator {
return self.abbrev_table_list.allocator;
}
- pub fn readString(self: *DebugInfo) ![]u8 {
+ pub fn readString(self: *DwarfInfo) ![]u8 {
return readStringRaw(self.allocator(), self.dwarf_in_stream);
}
-
- pub fn close(self: *DebugInfo) void {
- self.elf.close();
- }
};
pub const DebugInfo = switch (builtin.os) {
@@ -1236,7 +1246,7 @@ const Die = struct {
};
}
- fn getAttrString(self: *const Die, di: *DebugInfo, id: u64) ![]u8 {
+ fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
return switch (form_value.*) {
FormValue.String => |value| value,
@@ -1253,7 +1263,7 @@ const FileEntry = struct {
len_bytes: usize,
};
-const LineInfo = struct {
+pub const LineInfo = struct {
line: usize,
column: usize,
file_name: []const u8,
@@ -1352,7 +1362,7 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
return buf.toSlice();
}
-fn getString(di: *DebugInfo, offset: u64) ![]u8 {
+fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
const pos = di.debug_str.offset + offset;
try di.dwarf_seekable_stream.seekTo(pos);
return di.readString();
@@ -1452,7 +1462,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
};
}
-fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable {
+fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
var result = AbbrevTable.init(di.allocator());
while (true) {
const abbrev_code = try readULeb128(di.dwarf_in_stream);
@@ -1479,7 +1489,7 @@ fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable {
/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
/// seeks in the stream and parses it.
-fn getAbbrevTable(di: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable {
+fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
for (di.abbrev_table_list.toSlice()) |*header| {
if (header.offset == abbrev_offset) {
return &header.table;
@@ -1500,7 +1510,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
return null;
}
-fn parseDie(di: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
+fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
const abbrev_code = try readULeb128(di.dwarf_in_stream);
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
@@ -1717,7 +1727,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
return error.MissingDebugInfo;
}
-fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
+fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
const debug_line_end = di.debug_line.offset + di.debug_line.size;
@@ -1737,11 +1747,11 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr
continue;
}
- const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
+ const version = try di.dwarf_in_stream.readInt(di.endian, u16);
// TODO support 3 and 5
if (version != 2 and version != 4) return error.InvalidDebugInfo;
- const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32);
+ const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32);
const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
const minimum_instruction_length = try di.dwarf_in_stream.readByte();
@@ -1810,7 +1820,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr
return error.MissingDebugInfo;
},
DW.LNE_set_address => {
- const addr = try di.dwarf_in_stream.readInt(di.elf.endian, usize);
+ const addr = try di.dwarf_in_stream.readInt(di.endian, usize);
prog.address = addr;
},
DW.LNE_define_file => {
@@ -1872,7 +1882,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr
prog.address += inc_addr;
},
DW.LNS_fixed_advance_pc => {
- const arg = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
+ const arg = try di.dwarf_in_stream.readInt(di.endian, u16);
prog.address += arg;
},
DW.LNS_set_prologue_end => {},
@@ -1891,7 +1901,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr
return error.MissingDebugInfo;
}
-fn scanAllCompileUnits(di: *DebugInfo) !void {
+fn scanAllCompileUnits(di: *DwarfInfo) !void {
const debug_info_end = di.debug_info.offset + di.debug_info.size;
var this_unit_offset = di.debug_info.offset;
var cu_index: usize = 0;
@@ -1904,10 +1914,10 @@ fn scanAllCompileUnits(di: *DebugInfo) !void {
if (unit_length == 0) return;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
- const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
+ const version = try di.dwarf_in_stream.readInt(di.endian, u16);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
- const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32);
+ const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32);
const address_size = try di.dwarf_in_stream.readByte();
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
@@ -1958,7 +1968,7 @@ fn scanAllCompileUnits(di: *DebugInfo) !void {
}
}
-fn findCompileUnit(di: *DebugInfo, target_address: u64) !*const CompileUnit {
+fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
for (di.compile_unit_list.toSlice()) |*compile_unit| {
if (compile_unit.pc_range) |range| {
if (target_address >= range.start and target_address < range.end) return compile_unit;
--
cgit v1.2.3
From b883bc873df7f1a8fa3a13800402e1ec8da74328 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 12 Dec 2018 20:19:46 -0500
Subject: breaking API changes to all readInt/writeInt functions & more
* add `@bswap` builtin function. See #767
* comptime evaluation facilities are improved to be able to
handle a `@ptrCast` with a backing array.
* `@truncate` allows "truncating" a u0 value to any integer
type, and the result is always comptime known to be `0`.
* when specifying pointer alignment in a type expression,
the alignment value of pointers which do not have addresses
at runtime is ignored, and always has the default/ABI alignment
* threw in a fix to freebsd/x86_64.zig to update syntax from
language changes
* some improvements are pending #863
closes #638
closes #1733
std lib API changes
* io.InStream().readIntNe renamed to readIntNative
* io.InStream().readIntLe renamed to readIntLittle
* io.InStream().readIntBe renamed to readIntBig
* introduced io.InStream().readIntForeign
* io.InStream().readInt has parameter order changed
* io.InStream().readVarInt has parameter order changed
* io.InStream().writeIntNe renamed to writeIntNative
* introduced io.InStream().writeIntForeign
* io.InStream().writeIntLe renamed to writeIntLittle
* io.InStream().writeIntBe renamed to writeIntBig
* io.InStream().writeInt has parameter order changed
* mem.readInt has different parameters and semantics
* introduced mem.readIntNative
* introduced mem.readIntForeign
* mem.readIntBE renamed to mem.readIntBig and different API
* mem.readIntLE renamed to mem.readIntLittle and different API
* introduced mem.readIntSliceNative
* introduced mem.readIntSliceForeign
* introduced mem.readIntSliceLittle
* introduced mem.readIntSliceBig
* introduced mem.readIntSlice
* mem.writeInt has different parameters and semantics
* introduced mem.writeIntNative
* introduced mem.writeIntForeign
* mem.writeIntBE renamed to mem.readIntBig and different semantics
* mem.writeIntLE renamed to mem.readIntLittle and different semantics
* introduced mem.writeIntSliceForeign
* introduced mem.writeIntSliceNative
* introduced mem.writeIntSliceBig
* introduced mem.writeIntSliceLittle
* introduced mem.writeIntSlice
* removed mem.endianSwapIfLe
* removed mem.endianSwapIfBe
* removed mem.endianSwapIf
* added mem.littleToNative
* added mem.bigToNative
* added mem.toNative
* added mem.nativeTo
* added mem.nativeToLittle
* added mem.nativeToBig
---
doc/langref.html.in | 9 +
example/guess_number/main.zig | 2 +-
src-self-hosted/compilation.zig | 2 +-
src/all_types.hpp | 13 ++
src/analyze.cpp | 7 +-
src/codegen.cpp | 31 +++
src/ir.cpp | 156 ++++++++++++++-
src/ir_print.cpp | 15 ++
std/coff.zig | 44 ++---
std/crypto/blake2.zig | 11 +-
std/crypto/chacha20.zig | 53 ++---
std/crypto/md5.zig | 3 +-
std/crypto/poly1305.zig | 27 +--
std/crypto/sha1.zig | 3 +-
std/crypto/sha2.zig | 6 +-
std/crypto/sha3.zig | 5 +-
std/crypto/x25519.zig | 41 ++--
std/debug/index.zig | 60 +++---
std/elf.zig | 70 +++----
std/event/io.zig | 14 +-
std/hash/siphash.zig | 14 +-
std/heap.zig | 2 +-
std/io.zig | 60 +++---
std/mem.zig | 427 +++++++++++++++++++++++++---------------
std/net.zig | 12 +-
std/os/child_process.zig | 4 +-
std/os/freebsd/x86_64.zig | 6 +-
std/pdb.zig | 6 +-
std/rand/index.zig | 8 +-
std/unicode.zig | 30 +--
test/behavior.zig | 2 +
test/cases/bswap.zig | 32 +++
test/cases/truncate.zig | 8 +
test/compile_errors.zig | 12 ++
34 files changed, 797 insertions(+), 398 deletions(-)
create mode 100644 test/cases/bswap.zig
create mode 100644 test/cases/truncate.zig
(limited to 'std/debug')
diff --git a/doc/langref.html.in b/doc/langref.html.in
index a1903331a4..f820a05b69 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -5312,6 +5312,15 @@ comptime {
{#header_close#}
+ {#header_open|@bswap#}
+ {#syntax#}@swap(comptime T: type, value: T) T{#endsyntax#}
+ {#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.
+
+ Swaps the byte order of the integer. This converts a big endian integer to a little endian integer,
+ and converts a little endian integer to a big endian integer.
+
+ {#header_close#}
+
{#header_open|@bytesToSlice#}
{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}
diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig
index 66264666bc..b4eb1c292a 100644
--- a/example/guess_number/main.zig
+++ b/example/guess_number/main.zig
@@ -15,7 +15,7 @@ pub fn main() !void {
std.debug.warn("unable to seed random number generator: {}", err);
return err;
};
- const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
+ const seed = std.mem.readIntNative(u64, &seed_bytes);
var prng = std.rand.DefaultPrng.init(seed);
const answer = prng.random.range(u8, 0, 100) + 1;
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
index a8c3e13e33..0594cbd749 100644
--- a/src-self-hosted/compilation.zig
+++ b/src-self-hosted/compilation.zig
@@ -55,7 +55,7 @@ pub const ZigCompiler = struct {
var seed_bytes: [@sizeOf(u64)]u8 = undefined;
try std.os.getRandomBytes(seed_bytes[0..]);
- const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
+ const seed = mem.readIntNative(u64, &seed_bytes);
return ZigCompiler{
.loop = loop,
diff --git a/src/all_types.hpp b/src/all_types.hpp
index f7ada09a57..83b7e8495f 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1415,6 +1415,7 @@ enum BuiltinFnId {
BuiltinFnIdErrorReturnTrace,
BuiltinFnIdAtomicRmw,
BuiltinFnIdAtomicLoad,
+ BuiltinFnIdBswap,
};
struct BuiltinFnEntry {
@@ -1487,6 +1488,7 @@ enum ZigLLVMFnId {
ZigLLVMFnIdFloor,
ZigLLVMFnIdCeil,
ZigLLVMFnIdSqrt,
+ ZigLLVMFnIdBswap,
};
enum AddSubMul {
@@ -1516,6 +1518,9 @@ struct ZigLLVMFnKey {
uint32_t bit_count;
bool is_signed;
} overflow_arithmetic;
+ struct {
+ uint32_t bit_count;
+ } bswap;
} data;
};
@@ -2158,6 +2163,7 @@ enum IrInstructionId {
IrInstructionIdMergeErrRetTraces,
IrInstructionIdMarkErrRetTracePtr,
IrInstructionIdSqrt,
+ IrInstructionIdBswap,
IrInstructionIdErrSetCast,
IrInstructionIdToBytes,
IrInstructionIdFromBytes,
@@ -3251,6 +3257,13 @@ struct IrInstructionCheckRuntimeScope {
IrInstruction *is_comptime;
};
+struct IrInstructionBswap {
+ IrInstruction base;
+
+ IrInstruction *type;
+ IrInstruction *op;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 2f4b173c5f..46686ce772 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -401,7 +401,8 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
}
ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
- bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes)
+ bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
+ uint32_t bit_offset_in_host, uint32_t host_int_bytes)
{
assert(!type_is_invalid(child_type));
assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
@@ -6110,6 +6111,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089;
case ZigLLVMFnIdSqrt:
return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385;
+ case ZigLLVMFnIdBswap:
+ return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335;
case ZigLLVMFnIdOverflowArithmetic:
return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +
((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +
@@ -6128,6 +6131,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
return a.data.clz.bit_count == b.data.clz.bit_count;
case ZigLLVMFnIdPopCount:
return a.data.pop_count.bit_count == b.data.pop_count.bit_count;
+ case ZigLLVMFnIdBswap:
+ return a.data.bswap.bit_count == b.data.bswap.bit_count;
case ZigLLVMFnIdFloor:
case ZigLLVMFnIdCeil:
case ZigLLVMFnIdSqrt:
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 1033ed8120..08dd11800a 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3814,6 +3814,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI
n_args = 1;
key.id = ZigLLVMFnIdPopCount;
key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count;
+ } else if (fn_id == BuiltinFnIdBswap) {
+ fn_name = "bswap";
+ n_args = 1;
+ key.id = ZigLLVMFnIdBswap;
+ key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count;
} else {
zig_unreachable();
}
@@ -5098,6 +5103,29 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr
return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
}
+static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {
+ LLVMValueRef op = ir_llvm_value(g, instruction->op);
+ ZigType *int_type = instruction->base.value.type;
+ assert(int_type->id == ZigTypeIdInt);
+ if (int_type->data.integral.bit_count % 16 == 0) {
+ LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap);
+ return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
+ }
+ // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate
+ ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed,
+ int_type->data.integral.bit_count + 8);
+ // aabbcc
+ LLVMValueRef extended = LLVMBuildZExt(g->builder, op, extended_type->type_ref, "");
+ // 00aabbcc
+ LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap);
+ LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, "");
+ // ccbbaa00
+ LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped,
+ LLVMConstInt(extended_type->type_ref, 8, false), "");
+ // 00ccbbaa
+ return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, "");
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -5335,6 +5363,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
case IrInstructionIdSqrt:
return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
+ case IrInstructionIdBswap:
+ return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction);
}
zig_unreachable();
}
@@ -6757,6 +6787,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
+ create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2);
}
static const char *bool_to_str(bool b) {
diff --git a/src/ir.cpp b/src/ir.cpp
index 68a0b7f6f6..dc87f040bc 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -856,6 +856,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {
return IrInstructionIdSqrt;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) {
+ return IrInstructionIdBswap;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) {
return IrInstructionIdCheckRuntimeScope;
}
@@ -2705,6 +2709,17 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc
return &instruction->base;
}
+static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) {
+ IrInstructionBswap *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->type = type;
+ instruction->op = op;
+
+ if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block);
+ ir_ref_instruction(op, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) {
IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node);
instruction->scope_is_comptime = scope_is_comptime;
@@ -4689,6 +4704,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value);
return ir_lval_wrap(irb, scope, result, lval);
}
+ case BuiltinFnIdBswap:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+ IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value);
+ return ir_lval_wrap(irb, scope, result, lval);
+ }
}
zig_unreachable();
}
@@ -13674,18 +13704,55 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
return ErrorNone;
}
- if (dst_size > src_size) {
- ir_add_error_node(ira, source_node,
- buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes",
- dst_size, buf_ptr(&pointee->type->name), src_size));
- return ErrorSemanticAnalyzeFail;
+ if (dst_size <= src_size) {
+ Buf buf = BUF_INIT;
+ buf_resize(&buf, src_size);
+ buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee);
+ buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val);
+ return ErrorNone;
}
- Buf buf = BUF_INIT;
- buf_resize(&buf, src_size);
- buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee);
- buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val);
- return ErrorNone;
+ switch (ptr_val->data.x_ptr.special) {
+ case ConstPtrSpecialInvalid:
+ zig_unreachable();
+ case ConstPtrSpecialRef: {
+ ir_add_error_node(ira, source_node,
+ buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes",
+ dst_size, buf_ptr(&pointee->type->name), src_size));
+ return ErrorSemanticAnalyzeFail;
+ }
+ case ConstPtrSpecialBaseArray: {
+ ConstExprValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
+ assert(array_val->type->id == ZigTypeIdArray);
+ if (array_val->data.x_array.special != ConstArraySpecialNone)
+ zig_panic("TODO");
+ size_t elem_size = src_size;
+ src_size = elem_size *
+ (array_val->type->data.array.len - ptr_val->data.x_ptr.data.base_array.elem_index);
+ if (dst_size > src_size) {
+ ir_add_error_node(ira, source_node,
+ buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes",
+ dst_size, buf_ptr(&array_val->type->name), ptr_val->data.x_ptr.data.base_array.elem_index,
+ src_size));
+ return ErrorSemanticAnalyzeFail;
+ }
+ size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1);
+ Buf buf = BUF_INIT;
+ buf_resize(&buf, elem_count * elem_size);
+ for (size_t i = 0; i < elem_count; i += 1) {
+ ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[i];
+ buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val);
+ }
+ buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val);
+ return ErrorNone;
+ }
+ case ConstPtrSpecialBaseStruct:
+ case ConstPtrSpecialDiscard:
+ case ConstPtrSpecialHardCodedAddr:
+ case ConstPtrSpecialFunction:
+ zig_panic("TODO");
+ }
+ zig_unreachable();
}
static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
@@ -18054,6 +18121,12 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct
return ira->codegen->invalid_instruction;
}
+ if (src_type->data.integral.bit_count == 0) {
+ IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
+ bigint_init_unsigned(&result->value.data.x_bigint, 0);
+ return result;
+ }
+
if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {
const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";
ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name)));
@@ -20299,6 +20372,9 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
return ira->codegen->invalid_instruction;
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown)))
return ira->codegen->invalid_instruction;
+ if (!type_has_bits(child_type)) {
+ align_bytes = 0;
+ }
} else {
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
@@ -20898,6 +20974,63 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS
return result;
}
+static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) {
+ ZigType *int_type = ir_resolve_type(ira, instruction->type->child);
+ if (type_is_invalid(int_type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *op = instruction->op->child;
+ if (type_is_invalid(op->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (int_type->id != ZigTypeIdInt) {
+ ir_add_error(ira, instruction->type,
+ buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (int_type->data.integral.bit_count % 8 != 0) {
+ ir_add_error(ira, instruction->type,
+ buf_sprintf("@bswap integer type '%s' has %" PRIu32 " bits which is not evenly divisible by 8",
+ buf_ptr(&int_type->name), int_type->data.integral.bit_count));
+ return ira->codegen->invalid_instruction;
+ }
+
+ IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type);
+ if (type_is_invalid(casted_op->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (int_type->data.integral.bit_count == 0) {
+ IrInstruction *result = ir_const(ira, &instruction->base, int_type);
+ bigint_init_unsigned(&result->value.data.x_bigint, 0);
+ return result;
+ }
+
+ if (int_type->data.integral.bit_count == 8) {
+ return casted_op;
+ }
+
+ if (instr_is_comptime(casted_op)) {
+ ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *result = ir_const(ira, &instruction->base, int_type);
+ size_t buf_size = int_type->data.integral.bit_count / 8;
+ uint8_t *buf = allocate_nonzero(buf_size);
+ bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true);
+ bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false,
+ int_type->data.integral.is_signed);
+ return result;
+ }
+
+ IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, nullptr, casted_op);
+ result->value.type = int_type;
+ return result;
+}
+
+
static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
Error err;
IrInstruction *target = instruction->target->child;
@@ -21233,6 +21366,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
case IrInstructionIdSqrt:
return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction);
+ case IrInstructionIdBswap:
+ return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction);
case IrInstructionIdIntToErr:
return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction);
case IrInstructionIdErrToInt:
@@ -21454,6 +21589,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCoroPromise:
case IrInstructionIdPromiseResultType:
case IrInstructionIdSqrt:
+ case IrInstructionIdBswap:
case IrInstructionIdAtomicLoad:
case IrInstructionIdIntCast:
case IrInstructionIdFloatCast:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 13c06e4e2d..e09b0073eb 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1323,6 +1323,18 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) {
+ fprintf(irp->f, "@bswap(");
+ if (instruction->type != nullptr) {
+ ir_print_other_instruction(irp, instruction->type);
+ } else {
+ fprintf(irp->f, "null");
+ }
+ fprintf(irp->f, ",");
+ ir_print_other_instruction(irp, instruction->op);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1736,6 +1748,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSqrt:
ir_print_sqrt(irp, (IrInstructionSqrt *)instruction);
break;
+ case IrInstructionIdBswap:
+ ir_print_bswap(irp, (IrInstructionBswap *)instruction);
+ break;
case IrInstructionIdAtomicLoad:
ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
break;
diff --git a/std/coff.zig b/std/coff.zig
index 6a1aa34b46..53bd2a4b7a 100644
--- a/std/coff.zig
+++ b/std/coff.zig
@@ -51,7 +51,7 @@ pub const Coff = struct {
// Seek to PE File Header (coff header)
try self.in_file.seekTo(pe_pointer_offset);
- const pe_magic_offset = try in.readIntLe(u32);
+ const pe_magic_offset = try in.readIntLittle(u32);
try self.in_file.seekTo(pe_magic_offset);
var pe_header_magic: [4]u8 = undefined;
@@ -60,13 +60,13 @@ pub const Coff = struct {
return error.InvalidPEHeader;
self.coff_header = CoffHeader{
- .machine = try in.readIntLe(u16),
- .number_of_sections = try in.readIntLe(u16),
- .timedate_stamp = try in.readIntLe(u32),
- .pointer_to_symbol_table = try in.readIntLe(u32),
- .number_of_symbols = try in.readIntLe(u32),
- .size_of_optional_header = try in.readIntLe(u16),
- .characteristics = try in.readIntLe(u16),
+ .machine = try in.readIntLittle(u16),
+ .number_of_sections = try in.readIntLittle(u16),
+ .timedate_stamp = try in.readIntLittle(u32),
+ .pointer_to_symbol_table = try in.readIntLittle(u32),
+ .number_of_symbols = try in.readIntLittle(u32),
+ .size_of_optional_header = try in.readIntLittle(u16),
+ .characteristics = try in.readIntLittle(u16),
};
switch (self.coff_header.machine) {
@@ -79,7 +79,7 @@ pub const Coff = struct {
fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void {
const in = &file_stream.stream;
- self.pe_header.magic = try in.readIntLe(u16);
+ self.pe_header.magic = try in.readIntLittle(u16);
// For now we're only interested in finding the reference to the .pdb,
// so we'll skip most of this header, which size is different in 32
// 64 bits by the way.
@@ -93,14 +93,14 @@ pub const Coff = struct {
try self.in_file.seekForward(skip_size);
- const number_of_rva_and_sizes = try in.readIntLe(u32);
+ const number_of_rva_and_sizes = try in.readIntLittle(u32);
if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
return error.InvalidPEHeader;
for (self.pe_header.data_directory) |*data_dir| {
data_dir.* = OptionalHeader.DataDirectory{
- .virtual_address = try in.readIntLe(u32),
- .size = try in.readIntLe(u32),
+ .virtual_address = try in.readIntLittle(u32),
+ .size = try in.readIntLittle(u32),
};
}
}
@@ -124,7 +124,7 @@ pub const Coff = struct {
if (!mem.eql(u8, cv_signature, "RSDS"))
return error.InvalidPEMagic;
try in.readNoEof(self.guid[0..]);
- self.age = try in.readIntLe(u32);
+ self.age = try in.readIntLittle(u32);
// Finally read the null-terminated string.
var byte = try in.readByte();
@@ -157,15 +157,15 @@ pub const Coff = struct {
try self.sections.append(Section{
.header = SectionHeader{
.name = name,
- .misc = SectionHeader.Misc{ .physical_address = try in.readIntLe(u32) },
- .virtual_address = try in.readIntLe(u32),
- .size_of_raw_data = try in.readIntLe(u32),
- .pointer_to_raw_data = try in.readIntLe(u32),
- .pointer_to_relocations = try in.readIntLe(u32),
- .pointer_to_line_numbers = try in.readIntLe(u32),
- .number_of_relocations = try in.readIntLe(u16),
- .number_of_line_numbers = try in.readIntLe(u16),
- .characteristics = try in.readIntLe(u32),
+ .misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) },
+ .virtual_address = try in.readIntLittle(u32),
+ .size_of_raw_data = try in.readIntLittle(u32),
+ .pointer_to_raw_data = try in.readIntLittle(u32),
+ .pointer_to_relocations = try in.readIntLittle(u32),
+ .pointer_to_line_numbers = try in.readIntLittle(u32),
+ .number_of_relocations = try in.readIntLittle(u16),
+ .number_of_line_numbers = try in.readIntLittle(u16),
+ .characteristics = try in.readIntLittle(u32),
},
});
}
diff --git a/std/crypto/blake2.zig b/std/crypto/blake2.zig
index dc68d806d2..e3de65916a 100644
--- a/std/crypto/blake2.zig
+++ b/std/crypto/blake2.zig
@@ -123,7 +123,8 @@ fn Blake2s(comptime out_len: usize) type {
const rr = d.h[0 .. out_len / 32];
for (rr) |s, j| {
- mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little);
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
}
}
@@ -134,7 +135,8 @@ fn Blake2s(comptime out_len: usize) type {
var v: [16]u32 = undefined;
for (m) |*r, i| {
- r.* = mem.readIntLE(u32, b[4 * i .. 4 * i + 4]);
+ // TODO https://github.com/ziglang/zig/issues/863
+ r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]);
}
var k: usize = 0;
@@ -356,7 +358,8 @@ fn Blake2b(comptime out_len: usize) type {
const rr = d.h[0 .. out_len / 64];
for (rr) |s, j| {
- mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Little);
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s);
}
}
@@ -367,7 +370,7 @@ fn Blake2b(comptime out_len: usize) type {
var v: [16]u64 = undefined;
for (m) |*r, i| {
- r.* = mem.readIntLE(u64, b[8 * i .. 8 * i + 8]);
+ r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]);
}
var k: usize = 0;
diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig
index 059bc82088..5ec1e79756 100644
--- a/std/crypto/chacha20.zig
+++ b/std/crypto/chacha20.zig
@@ -59,7 +59,8 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {
}
for (x) |_, i| {
- mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little);
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]);
}
}
@@ -70,10 +71,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo
const c = "expand 32-byte k";
const constant_le = []u32{
- mem.readIntLE(u32, c[0..4]),
- mem.readIntLE(u32, c[4..8]),
- mem.readIntLE(u32, c[8..12]),
- mem.readIntLE(u32, c[12..16]),
+ mem.readIntSliceLittle(u32, c[0..4]),
+ mem.readIntSliceLittle(u32, c[4..8]),
+ mem.readIntSliceLittle(u32, c[8..12]),
+ mem.readIntSliceLittle(u32, c[12..16]),
};
mem.copy(u32, ctx[0..], constant_le[0..4]);
@@ -117,19 +118,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce:
var k: [8]u32 = undefined;
var c: [4]u32 = undefined;
- k[0] = mem.readIntLE(u32, key[0..4]);
- k[1] = mem.readIntLE(u32, key[4..8]);
- k[2] = mem.readIntLE(u32, key[8..12]);
- k[3] = mem.readIntLE(u32, key[12..16]);
- k[4] = mem.readIntLE(u32, key[16..20]);
- k[5] = mem.readIntLE(u32, key[20..24]);
- k[6] = mem.readIntLE(u32, key[24..28]);
- k[7] = mem.readIntLE(u32, key[28..32]);
+ k[0] = mem.readIntSliceLittle(u32, key[0..4]);
+ k[1] = mem.readIntSliceLittle(u32, key[4..8]);
+ k[2] = mem.readIntSliceLittle(u32, key[8..12]);
+ k[3] = mem.readIntSliceLittle(u32, key[12..16]);
+ k[4] = mem.readIntSliceLittle(u32, key[16..20]);
+ k[5] = mem.readIntSliceLittle(u32, key[20..24]);
+ k[6] = mem.readIntSliceLittle(u32, key[24..28]);
+ k[7] = mem.readIntSliceLittle(u32, key[28..32]);
c[0] = counter;
- c[1] = mem.readIntLE(u32, nonce[0..4]);
- c[2] = mem.readIntLE(u32, nonce[4..8]);
- c[3] = mem.readIntLE(u32, nonce[8..12]);
+ c[1] = mem.readIntSliceLittle(u32, nonce[0..4]);
+ c[2] = mem.readIntSliceLittle(u32, nonce[4..8]);
+ c[3] = mem.readIntSliceLittle(u32, nonce[8..12]);
chaCha20_internal(out, in, k, c);
}
@@ -144,19 +145,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]
var k: [8]u32 = undefined;
var c: [4]u32 = undefined;
- k[0] = mem.readIntLE(u32, key[0..4]);
- k[1] = mem.readIntLE(u32, key[4..8]);
- k[2] = mem.readIntLE(u32, key[8..12]);
- k[3] = mem.readIntLE(u32, key[12..16]);
- k[4] = mem.readIntLE(u32, key[16..20]);
- k[5] = mem.readIntLE(u32, key[20..24]);
- k[6] = mem.readIntLE(u32, key[24..28]);
- k[7] = mem.readIntLE(u32, key[28..32]);
+ k[0] = mem.readIntSliceLittle(u32, key[0..4]);
+ k[1] = mem.readIntSliceLittle(u32, key[4..8]);
+ k[2] = mem.readIntSliceLittle(u32, key[8..12]);
+ k[3] = mem.readIntSliceLittle(u32, key[12..16]);
+ k[4] = mem.readIntSliceLittle(u32, key[16..20]);
+ k[5] = mem.readIntSliceLittle(u32, key[20..24]);
+ k[6] = mem.readIntSliceLittle(u32, key[24..28]);
+ k[7] = mem.readIntSliceLittle(u32, key[28..32]);
c[0] = @truncate(u32, counter);
c[1] = @truncate(u32, counter >> 32);
- c[2] = mem.readIntLE(u32, nonce[0..4]);
- c[3] = mem.readIntLE(u32, nonce[4..8]);
+ c[2] = mem.readIntSliceLittle(u32, nonce[0..4]);
+ c[3] = mem.readIntSliceLittle(u32, nonce[4..8]);
const block_size = (1 << 6);
const big_block = (block_size << 32);
diff --git a/std/crypto/md5.zig b/std/crypto/md5.zig
index 8663fa751f..994a7fa25c 100644
--- a/std/crypto/md5.zig
+++ b/std/crypto/md5.zig
@@ -112,7 +112,8 @@ pub const Md5 = struct {
d.round(d.buf[0..]);
for (d.s) |s, j| {
- mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little);
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
}
}
diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig
index a5d9fcdf57..0d7a4d672d 100644
--- a/std/crypto/poly1305.zig
+++ b/std/crypto/poly1305.zig
@@ -6,8 +6,8 @@ const std = @import("../index.zig");
const builtin = @import("builtin");
const Endian = builtin.Endian;
-const readInt = std.mem.readInt;
-const writeInt = std.mem.writeInt;
+const readIntSliceLittle = std.mem.readIntSliceLittle;
+const writeIntSliceLittle = std.mem.writeIntSliceLittle;
pub const Poly1305 = struct {
const Self = @This();
@@ -59,19 +59,19 @@ pub const Poly1305 = struct {
{
var i: usize = 0;
while (i < 1) : (i += 1) {
- ctx.r[0] = readInt(key[0..4], u32, Endian.Little) & 0x0fffffff;
+ ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff;
}
}
{
var i: usize = 1;
while (i < 4) : (i += 1) {
- ctx.r[i] = readInt(key[i * 4 .. i * 4 + 4], u32, Endian.Little) & 0x0ffffffc;
+ ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc;
}
}
{
var i: usize = 0;
while (i < 4) : (i += 1) {
- ctx.pad[i] = readInt(key[i * 4 + 16 .. i * 4 + 16 + 4], u32, Endian.Little);
+ ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]);
}
}
@@ -168,10 +168,10 @@ pub const Poly1305 = struct {
const nb_blocks = nmsg.len >> 4;
var i: usize = 0;
while (i < nb_blocks) : (i += 1) {
- ctx.c[0] = readInt(nmsg[0..4], u32, Endian.Little);
- ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little);
- ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little);
- ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little);
+ ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]);
+ ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]);
+ ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]);
+ ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]);
polyBlock(ctx);
nmsg = nmsg[16..];
}
@@ -210,10 +210,11 @@ pub const Poly1305 = struct {
const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000
- writeInt(out[0..], @truncate(u32, uu0), Endian.Little);
- writeInt(out[4..], @truncate(u32, uu1), Endian.Little);
- writeInt(out[8..], @truncate(u32, uu2), Endian.Little);
- writeInt(out[12..], @truncate(u32, uu3), Endian.Little);
+ // TODO https://github.com/ziglang/zig/issues/863
+ writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0));
+ writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1));
+ writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2));
+ writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3));
ctx.secureZero();
}
diff --git a/std/crypto/sha1.zig b/std/crypto/sha1.zig
index 1cb0b17434..d5aab8f33f 100644
--- a/std/crypto/sha1.zig
+++ b/std/crypto/sha1.zig
@@ -109,7 +109,8 @@ pub const Sha1 = struct {
d.round(d.buf[0..]);
for (d.s) |s, j| {
- mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big);
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
}
}
diff --git a/std/crypto/sha2.zig b/std/crypto/sha2.zig
index 7e9749364b..0476a3a25e 100644
--- a/std/crypto/sha2.zig
+++ b/std/crypto/sha2.zig
@@ -167,7 +167,8 @@ fn Sha2_32(comptime params: Sha2Params32) type {
const rr = d.s[0 .. params.out_len / 32];
for (rr) |s, j| {
- mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big);
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
}
}
@@ -508,7 +509,8 @@ fn Sha2_64(comptime params: Sha2Params64) type {
const rr = d.s[0 .. params.out_len / 64];
for (rr) |s, j| {
- mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Big);
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s);
}
}
diff --git a/std/crypto/sha3.zig b/std/crypto/sha3.zig
index 881370e686..e686e1337c 100644
--- a/std/crypto/sha3.zig
+++ b/std/crypto/sha3.zig
@@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
var c = []const u64{0} ** 5;
for (s) |*r, i| {
- r.* = mem.readIntLE(u64, d[8 * i .. 8 * i + 8]);
+ r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]);
}
comptime var x: usize = 0;
@@ -167,7 +167,8 @@ fn keccak_f(comptime F: usize, d: []u8) void {
}
for (s) |r, i| {
- mem.writeInt(d[8 * i .. 8 * i + 8], r, builtin.Endian.Little);
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r);
}
}
diff --git a/std/crypto/x25519.zig b/std/crypto/x25519.zig
index 281813b457..daccb56808 100644
--- a/std/crypto/x25519.zig
+++ b/std/crypto/x25519.zig
@@ -7,8 +7,8 @@ const builtin = @import("builtin");
const fmt = std.fmt;
const Endian = builtin.Endian;
-const readInt = std.mem.readInt;
-const writeInt = std.mem.writeInt;
+const readIntSliceLittle = std.mem.readIntSliceLittle;
+const writeIntSliceLittle = std.mem.writeIntSliceLittle;
// Based on Supercop's ref10 implementation.
pub const X25519 = struct {
@@ -255,16 +255,16 @@ const Fe = struct {
var t: [10]i64 = undefined;
- t[0] = readInt(s[0..4], u32, Endian.Little);
- t[1] = readInt(s[4..7], u32, Endian.Little) << 6;
- t[2] = readInt(s[7..10], u32, Endian.Little) << 5;
- t[3] = readInt(s[10..13], u32, Endian.Little) << 3;
- t[4] = readInt(s[13..16], u32, Endian.Little) << 2;
- t[5] = readInt(s[16..20], u32, Endian.Little);
- t[6] = readInt(s[20..23], u32, Endian.Little) << 7;
- t[7] = readInt(s[23..26], u32, Endian.Little) << 5;
- t[8] = readInt(s[26..29], u32, Endian.Little) << 4;
- t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2;
+ t[0] = readIntSliceLittle(u32, s[0..4]);
+ t[1] = u32(readIntSliceLittle(u24, s[4..7])) << 6;
+ t[2] = u32(readIntSliceLittle(u24, s[7..10])) << 5;
+ t[3] = u32(readIntSliceLittle(u24, s[10..13])) << 3;
+ t[4] = u32(readIntSliceLittle(u24, s[13..16])) << 2;
+ t[5] = readIntSliceLittle(u32, s[16..20]);
+ t[6] = u32(readIntSliceLittle(u24, s[20..23])) << 7;
+ t[7] = u32(readIntSliceLittle(u24, s[23..26])) << 5;
+ t[8] = u32(readIntSliceLittle(u24, s[26..29])) << 4;
+ t[9] = (u32(readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2;
carry1(h, t[0..]);
}
@@ -544,14 +544,15 @@ const Fe = struct {
ut[i] = @bitCast(u32, @intCast(i32, t[i]));
}
- writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little);
- writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little);
- writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little);
- writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little);
- writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little);
- writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little);
- writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little);
- writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little);
+ // TODO https://github.com/ziglang/zig/issues/863
+ writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));
+ writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));
+ writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));
+ writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));
+ writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));
+ writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));
+ writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));
+ writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6));
std.mem.secureZero(i64, t[0..]);
}
diff --git a/std/debug/index.zig b/std/debug/index.zig
index 4a96e9d259..3967e5a8be 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -523,7 +523,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void {
const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
- const signature = try modi.stream.readIntLe(u32);
+ const signature = try modi.stream.readIntLittle(u32);
if (signature != 4)
return error.InvalidDebugInfo;
@@ -757,9 +757,9 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
try di.pdb.openFile(di.coff, path);
var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
- const version = try pdb_stream.stream.readIntLe(u32);
- const signature = try pdb_stream.stream.readIntLe(u32);
- const age = try pdb_stream.stream.readIntLe(u32);
+ const version = try pdb_stream.stream.readIntLittle(u32);
+ const signature = try pdb_stream.stream.readIntLittle(u32);
+ const age = try pdb_stream.stream.readIntLittle(u32);
var guid: [16]u8 = undefined;
try pdb_stream.stream.readNoEof(guid[0..]);
if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
@@ -767,7 +767,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
// We validated the executable and pdb match.
const string_table_index = str_tab_index: {
- const name_bytes_len = try pdb_stream.stream.readIntLe(u32);
+ const name_bytes_len = try pdb_stream.stream.readIntLittle(u32);
const name_bytes = try allocator.alloc(u8, name_bytes_len);
try pdb_stream.stream.readNoEof(name_bytes);
@@ -797,8 +797,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
};
const bucket_list = try allocator.alloc(Bucket, present.len);
for (present) |_| {
- const name_offset = try pdb_stream.stream.readIntLe(u32);
- const name_index = try pdb_stream.stream.readIntLe(u32);
+ const name_offset = try pdb_stream.stream.readIntLittle(u32);
+ const name_index = try pdb_stream.stream.readIntLittle(u32);
const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
if (mem.eql(u8, name, "/names")) {
break :str_tab_index name_index;
@@ -859,7 +859,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
var sect_cont_offset: usize = 0;
if (section_contrib_size != 0) {
- const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32));
+ const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32));
if (ver != pdb.SectionContrSubstreamVersion.Ver60)
return error.InvalidDebugInfo;
sect_cont_offset += @sizeOf(u32);
@@ -879,11 +879,11 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
}
fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
- const num_words = try stream.readIntLe(u32);
+ const num_words = try stream.readIntLittle(u32);
var word_i: usize = 0;
var list = ArrayList(usize).init(allocator);
while (word_i != num_words) : (word_i += 1) {
- const word = try stream.readIntLe(u32);
+ const word = try stream.readIntLittle(u32);
var bit_i: u5 = 0;
while (true) : (bit_i += 1) {
if (word & (u32(1) << bit_i) != 0) {
@@ -1200,7 +1200,7 @@ const Constant = struct {
fn asUnsignedLe(self: *const Constant) !u64 {
if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
if (self.signed) return error.InvalidDebugInfo;
- return mem.readInt(self.payload, u64, builtin.Endian.Little);
+ return mem.readIntSliceLittle(u64, self.payload);
}
};
@@ -1381,7 +1381,7 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize
}
fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
- const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size);
+ const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size);
return parseFormValueBlockLen(allocator, in_stream, block_len);
}
@@ -1395,11 +1395,11 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo
}
fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
- return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32));
+ return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32));
}
fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
- return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable;
+ return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;
}
fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
@@ -1408,7 +1408,7 @@ fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize)
}
fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
- const block_len = try in_stream.readIntLe(T);
+ const block_len = try in_stream.readIntLittle(T);
return parseFormValueRefLen(allocator, in_stream, block_len);
}
@@ -1450,7 +1450,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
},
DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
- DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) },
+ DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
@@ -1747,11 +1747,11 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
continue;
}
- const version = try di.dwarf_in_stream.readInt(di.endian, u16);
+ const version = try di.dwarf_in_stream.readInt(u16, di.endian);
// TODO support 3 and 5
if (version != 2 and version != 4) return error.InvalidDebugInfo;
- const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32);
+ const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
const minimum_instruction_length = try di.dwarf_in_stream.readByte();
@@ -1820,7 +1820,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
return error.MissingDebugInfo;
},
DW.LNE_set_address => {
- const addr = try di.dwarf_in_stream.readInt(di.endian, usize);
+ const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
prog.address = addr;
},
DW.LNE_define_file => {
@@ -1882,7 +1882,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
prog.address += inc_addr;
},
DW.LNS_fixed_advance_pc => {
- const arg = try di.dwarf_in_stream.readInt(di.endian, u16);
+ const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
prog.address += arg;
},
DW.LNS_set_prologue_end => {},
@@ -1914,10 +1914,10 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void {
if (unit_length == 0) return;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
- const version = try di.dwarf_in_stream.readInt(di.endian, u16);
+ const version = try di.dwarf_in_stream.readInt(u16, di.endian);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
- const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32);
+ const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
const address_size = try di.dwarf_in_stream.readByte();
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
@@ -1978,8 +1978,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
if (di.debug_ranges) |debug_ranges| {
try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
while (true) {
- const begin_addr = try di.dwarf_in_stream.readIntLe(usize);
- const end_addr = try di.dwarf_in_stream.readIntLe(usize);
+ const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
+ const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
if (begin_addr == 0 and end_addr == 0) {
break;
}
@@ -2001,7 +2001,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
}
fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
- const result = mem.readInt(ptr.*[0..@sizeOf(T)], T, endian);
+ // TODO https://github.com/ziglang/zig/issues/863
+ const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);
ptr.* += @sizeOf(T);
return result;
}
@@ -2017,11 +2018,12 @@ fn readByteSignedMem(ptr: *[*]const u8) i8 {
}
fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
- const first_32_bits = mem.readIntLE(u32, ptr.*[0..4]);
+ // TODO this code can be improved with https://github.com/ziglang/zig/issues/863
+ const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]);
is_64.* = (first_32_bits == 0xffffffff);
if (is_64.*) {
ptr.* += 4;
- const result = mem.readIntLE(u64, ptr.*[0..8]);
+ const result = mem.readIntSliceLittle(u64, ptr.*[0..8]);
ptr.* += 8;
return result;
} else {
@@ -2084,10 +2086,10 @@ fn readILeb128Mem(ptr: *[*]const u8) !i64 {
}
fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
- const first_32_bits = try in_stream.readIntLe(u32);
+ const first_32_bits = try in_stream.readIntLittle(u32);
is_64.* = (first_32_bits == 0xffffffff);
if (is_64.*) {
- return in_stream.readIntLe(u64);
+ return in_stream.readIntLittle(u64);
} else {
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
return u64(first_32_bits);
diff --git a/std/elf.zig b/std/elf.zig
index cf7c29b1e5..6a564c3283 100644
--- a/std/elf.zig
+++ b/std/elf.zig
@@ -412,7 +412,7 @@ pub const Elf = struct {
// skip over padding
try seekable_stream.seekForward(9);
- elf.file_type = switch (try in.readInt(elf.endian, u16)) {
+ elf.file_type = switch (try in.readInt(u16, elf.endian)) {
1 => FileType.Relocatable,
2 => FileType.Executable,
3 => FileType.Shared,
@@ -420,7 +420,7 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
- elf.arch = switch (try in.readInt(elf.endian, u16)) {
+ elf.arch = switch (try in.readInt(u16, elf.endian)) {
0x02 => Arch.Sparc,
0x03 => Arch.x86,
0x08 => Arch.Mips,
@@ -433,32 +433,32 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
- const elf_version = try in.readInt(elf.endian, u32);
+ const elf_version = try in.readInt(u32, elf.endian);
if (elf_version != 1) return error.InvalidFormat;
if (elf.is_64) {
- elf.entry_addr = try in.readInt(elf.endian, u64);
- elf.program_header_offset = try in.readInt(elf.endian, u64);
- elf.section_header_offset = try in.readInt(elf.endian, u64);
+ elf.entry_addr = try in.readInt(u64, elf.endian);
+ elf.program_header_offset = try in.readInt(u64, elf.endian);
+ elf.section_header_offset = try in.readInt(u64, elf.endian);
} else {
- elf.entry_addr = u64(try in.readInt(elf.endian, u32));
- elf.program_header_offset = u64(try in.readInt(elf.endian, u32));
- elf.section_header_offset = u64(try in.readInt(elf.endian, u32));
+ elf.entry_addr = u64(try in.readInt(u32, elf.endian));
+ elf.program_header_offset = u64(try in.readInt(u32, elf.endian));
+ elf.section_header_offset = u64(try in.readInt(u32, elf.endian));
}
// skip over flags
try seekable_stream.seekForward(4);
- const header_size = try in.readInt(elf.endian, u16);
+ const header_size = try in.readInt(u16, elf.endian);
if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
return error.InvalidFormat;
}
- const ph_entry_size = try in.readInt(elf.endian, u16);
- const ph_entry_count = try in.readInt(elf.endian, u16);
- const sh_entry_size = try in.readInt(elf.endian, u16);
- const sh_entry_count = try in.readInt(elf.endian, u16);
- elf.string_section_index = u64(try in.readInt(elf.endian, u16));
+ const ph_entry_size = try in.readInt(u16, elf.endian);
+ const ph_entry_count = try in.readInt(u16, elf.endian);
+ const sh_entry_size = try in.readInt(u16, elf.endian);
+ const sh_entry_count = try in.readInt(u16, elf.endian);
+ elf.string_section_index = u64(try in.readInt(u16, elf.endian));
if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
@@ -481,32 +481,32 @@ pub const Elf = struct {
if (sh_entry_size != 64) return error.InvalidFormat;
for (elf.section_headers) |*elf_section| {
- elf_section.name = try in.readInt(elf.endian, u32);
- elf_section.sh_type = try in.readInt(elf.endian, u32);
- elf_section.flags = try in.readInt(elf.endian, u64);
- elf_section.addr = try in.readInt(elf.endian, u64);
- elf_section.offset = try in.readInt(elf.endian, u64);
- elf_section.size = try in.readInt(elf.endian, u64);
- elf_section.link = try in.readInt(elf.endian, u32);
- elf_section.info = try in.readInt(elf.endian, u32);
- elf_section.addr_align = try in.readInt(elf.endian, u64);
- elf_section.ent_size = try in.readInt(elf.endian, u64);
+ elf_section.name = try in.readInt(u32, elf.endian);
+ elf_section.sh_type = try in.readInt(u32, elf.endian);
+ elf_section.flags = try in.readInt(u64, elf.endian);
+ elf_section.addr = try in.readInt(u64, elf.endian);
+ elf_section.offset = try in.readInt(u64, elf.endian);
+ elf_section.size = try in.readInt(u64, elf.endian);
+ elf_section.link = try in.readInt(u32, elf.endian);
+ elf_section.info = try in.readInt(u32, elf.endian);
+ elf_section.addr_align = try in.readInt(u64, elf.endian);
+ elf_section.ent_size = try in.readInt(u64, elf.endian);
}
} else {
if (sh_entry_size != 40) return error.InvalidFormat;
for (elf.section_headers) |*elf_section| {
// TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ?
- elf_section.name = try in.readInt(elf.endian, u32);
- elf_section.sh_type = try in.readInt(elf.endian, u32);
- elf_section.flags = u64(try in.readInt(elf.endian, u32));
- elf_section.addr = u64(try in.readInt(elf.endian, u32));
- elf_section.offset = u64(try in.readInt(elf.endian, u32));
- elf_section.size = u64(try in.readInt(elf.endian, u32));
- elf_section.link = try in.readInt(elf.endian, u32);
- elf_section.info = try in.readInt(elf.endian, u32);
- elf_section.addr_align = u64(try in.readInt(elf.endian, u32));
- elf_section.ent_size = u64(try in.readInt(elf.endian, u32));
+ elf_section.name = try in.readInt(u32, elf.endian);
+ elf_section.sh_type = try in.readInt(u32, elf.endian);
+ elf_section.flags = u64(try in.readInt(u32, elf.endian));
+ elf_section.addr = u64(try in.readInt(u32, elf.endian));
+ elf_section.offset = u64(try in.readInt(u32, elf.endian));
+ elf_section.size = u64(try in.readInt(u32, elf.endian));
+ elf_section.link = try in.readInt(u32, elf.endian);
+ elf_section.info = try in.readInt(u32, elf.endian);
+ elf_section.addr_align = u64(try in.readInt(u32, elf.endian));
+ elf_section.ent_size = u64(try in.readInt(u32, elf.endian));
}
}
diff --git a/std/event/io.zig b/std/event/io.zig
index bb377a3b68..b11550f7aa 100644
--- a/std/event/io.zig
+++ b/std/event/io.zig
@@ -39,18 +39,22 @@ pub fn InStream(comptime ReadError: type) type {
if (amt_read < buf.len) return error.EndOfStream;
}
- pub async fn readIntLe(self: *Self, comptime T: type) !T {
- return await (async self.readInt(builtin.Endian.Little, T) catch unreachable);
+ pub async fn readIntLittle(self: *Self, comptime T: type) !T {
+ var bytes: [@sizeOf(T)]u8 = undefined;
+ try await (async self.readNoEof(bytes[0..]) catch unreachable);
+ return mem.readIntLittle(T, &bytes);
}
pub async fn readIntBe(self: *Self, comptime T: type) !T {
- return await (async self.readInt(builtin.Endian.Big, T) catch unreachable);
+ var bytes: [@sizeOf(T)]u8 = undefined;
+ try await (async self.readNoEof(bytes[0..]) catch unreachable);
+ return mem.readIntBig(T, &bytes);
}
- pub async fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T {
+ pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try await (async self.readNoEof(bytes[0..]) catch unreachable);
- return mem.readInt(bytes, T, endian);
+ return mem.readInt(T, &bytes, endian);
}
pub async fn readStruct(self: *Self, comptime T: type) !T {
diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig
index 0fe958c38b..ee26950272 100644
--- a/std/hash/siphash.zig
+++ b/std/hash/siphash.zig
@@ -42,8 +42,8 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
pub fn init(key: []const u8) Self {
debug.assert(key.len >= 16);
- const k0 = mem.readInt(key[0..8], u64, Endian.Little);
- const k1 = mem.readInt(key[8..16], u64, Endian.Little);
+ const k0 = mem.readIntSliceLittle(u64, key[0..8]);
+ const k1 = mem.readIntSliceLittle(u64, key[8..16]);
var d = Self{
.v0 = k0 ^ 0x736f6d6570736575,
@@ -121,7 +121,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
fn round(d: *Self, b: []const u8) void {
debug.assert(b.len == 8);
- const m = mem.readInt(b[0..], u64, Endian.Little);
+ const m = mem.readIntSliceLittle(u64, b[0..]);
d.v3 ^= m;
comptime var i: usize = 0;
@@ -162,7 +162,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
test "siphash64-2-4 sanity" {
- const vectors = [][]const u8{
+ const vectors = [][8]u8{
"\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
"\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
"\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
@@ -235,13 +235,13 @@ test "siphash64-2-4 sanity" {
for (vectors) |vector, i| {
buffer[i] = @intCast(u8, i);
- const expected = mem.readInt(vector, u64, Endian.Little);
+ const expected = mem.readIntLittle(u64, &vector);
debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
}
}
test "siphash128-2-4 sanity" {
- const vectors = [][]const u8{
+ const vectors = [][16]u8{
"\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
"\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
"\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",
@@ -314,7 +314,7 @@ test "siphash128-2-4 sanity" {
for (vectors) |vector, i| {
buffer[i] = @intCast(u8, i);
- const expected = mem.readInt(vector, u128, Endian.Little);
+ const expected = mem.readIntLittle(u128, &vector);
debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
}
}
diff --git a/std/heap.zig b/std/heap.zig
index 5c31d412cf..46b247fa7e 100644
--- a/std/heap.zig
+++ b/std/heap.zig
@@ -66,7 +66,7 @@ pub const DirectAllocator = struct {
}
}
- fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
+ fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) {
diff --git a/std/io.zig b/std/io.zig
index bdca2b03e8..4442191717 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -152,35 +152,42 @@ pub fn InStream(comptime ReadError: type) type {
}
/// Reads a native-endian integer
- pub fn readIntNe(self: *Self, comptime T: type) !T {
- return self.readInt(builtin.endian, T);
+ pub fn readIntNative(self: *Self, comptime T: type) !T {
+ var bytes: [@sizeOf(T)]u8 = undefined;
+ try self.readNoEof(bytes[0..]);
+ return mem.readIntSliceNative(T, bytes);
}
- pub fn readIntLe(self: *Self, comptime T: type) !T {
+ /// Reads a foreign-endian integer
+ pub fn readIntForeign(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
- return mem.readIntLE(T, bytes);
+ return mem.readIntSliceForeign(T, bytes);
}
- pub fn readIntBe(self: *Self, comptime T: type) !T {
+ pub fn readIntLittle(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
- return mem.readIntBE(T, bytes);
+ return mem.readIntSliceLittle(T, bytes);
}
- pub fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T {
+ pub fn readIntBig(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
- return mem.readInt(bytes, T, endian);
+ return mem.readIntSliceBig(T, bytes);
}
- pub fn readVarInt(self: *Self, endian: builtin.Endian, comptime T: type, size: usize) !T {
+ pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
+ var bytes: [@sizeOf(T)]u8 = undefined;
+ try self.readNoEof(bytes[0..]);
+ return mem.readIntSlice(T, bytes, endian);
+ }
+
+ pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T {
assert(size <= @sizeOf(T));
- assert(size <= 8);
- var input_buf: [8]u8 = undefined;
- const input_slice = input_buf[0..size];
- try self.readNoEof(input_slice);
- return mem.readInt(input_slice, T, endian);
+ var bytes: [@sizeOf(T)]u8 = undefined;
+ try self.readNoEof(bytes[0..]);
+ return mem.readIntSlice(T, bytes, endian);
}
pub fn skipBytes(self: *Self, num_bytes: usize) !void {
@@ -229,25 +236,34 @@ pub fn OutStream(comptime WriteError: type) type {
}
/// Write a native-endian integer.
- pub fn writeIntNe(self: *Self, comptime T: type, value: T) Error!void {
- return self.writeInt(builtin.endian, T, value);
+ pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
+ var bytes: [@sizeOf(T)]u8 = undefined;
+ mem.writeIntNative(T, &bytes, value);
+ return self.writeFn(self, bytes);
+ }
+
+ /// Write a foreign-endian integer.
+ pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
+ var bytes: [@sizeOf(T)]u8 = undefined;
+ mem.writeIntForeign(T, &bytes, value);
+ return self.writeFn(self, bytes);
}
- pub fn writeIntLe(self: *Self, comptime T: type, value: T) Error!void {
+ pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
var bytes: [@sizeOf(T)]u8 = undefined;
- mem.writeIntLE(T, &bytes, value);
+ mem.writeIntLittle(T, &bytes, value);
return self.writeFn(self, bytes);
}
- pub fn writeIntBe(self: *Self, comptime T: type, value: T) Error!void {
+ pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
var bytes: [@sizeOf(T)]u8 = undefined;
- mem.writeIntBE(T, &bytes, value);
+ mem.writeIntBig(T, &bytes, value);
return self.writeFn(self, bytes);
}
- pub fn writeInt(self: *Self, endian: builtin.Endian, comptime T: type, value: T) Error!void {
+ pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
var bytes: [@sizeOf(T)]u8 = undefined;
- mem.writeInt(bytes[0..], value, endian);
+ mem.writeInt(T, &bytes, value, endian);
return self.writeFn(self, bytes);
}
};
diff --git a/std/mem.zig b/std/mem.zig
index 9914a08e65..97dc46a80f 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -407,186 +407,250 @@ test "mem.indexOf" {
assert(lastIndexOfScalar(u8, "boo", 'o').? == 2);
}
-/// Reads an integer from memory with size equal to bytes.len.
-/// T specifies the return type, which must be large enough to store
-/// the result.
-/// See also ::readIntBE or ::readIntLE.
-pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) T {
- if (T.bit_count == 8) {
- return bytes[0];
- }
- var result: T = 0;
- switch (endian) {
- builtin.Endian.Big => {
- for (bytes) |b| {
- result = (result << 8) | b;
- }
- },
- builtin.Endian.Little => {
- const ShiftType = math.Log2Int(T);
- for (bytes) |b, index| {
- result = result | (T(b) << @intCast(ShiftType, index * 8));
- }
- },
- }
- return result;
-}
+/// Reads an integer from memory with bit count specified by T.
+/// The bit count of T must be evenly divisible by 8.
+/// This function cannot fail and cannot cause undefined behavior.
+/// Assumes the endianness of memory is native. This means the function can
+/// simply pointer cast memory.
+pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
+ comptime assert(T.bit_count % 8 == 0);
+ return @ptrCast(*align(1) const T, bytes).*;
+}
+
+/// Reads an integer from memory with bit count specified by T.
+/// The bit count of T must be evenly divisible by 8.
+/// This function cannot fail and cannot cause undefined behavior.
+/// Assumes the endianness of memory is foreign, so it must byte-swap.
+pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
+ comptime assert(T.bit_count % 8 == 0);
+ return @bswap(T, @ptrCast(*align(1) const T, bytes).*);
+}
+
+pub const readIntLittle = switch (builtin.endian) {
+ builtin.Endian.Little => readIntNative,
+ builtin.Endian.Big => readIntForeign,
+};
-/// Reads a big-endian int of type T from bytes.
-/// bytes.len must be exactly @sizeOf(T).
-pub fn readIntBE(comptime T: type, bytes: []const u8) T {
- if (T.is_signed) {
- return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes));
- }
- assert(bytes.len == @sizeOf(T));
- if (T == u8) return bytes[0];
- var result: T = 0;
- {
- comptime var i = 0;
- inline while (i < @sizeOf(T)) : (i += 1) {
- result = (result << 8) | T(bytes[i]);
- }
+pub const readIntBig = switch (builtin.endian) {
+ builtin.Endian.Little => readIntForeign,
+ builtin.Endian.Big => readIntNative,
+};
+
+/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
+/// and ignores extra bytes.
+/// Note that @sizeOf(u24) is 3.
+/// The bit count of T must be evenly divisible by 8.
+/// Assumes the endianness of memory is native. This means the function can
+/// simply pointer cast memory.
+pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
+ assert(@sizeOf(u24) == 3);
+ assert(bytes.len >= @sizeOf(T));
+ // TODO https://github.com/ziglang/zig/issues/863
+ return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr));
+}
+
+/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
+/// and ignores extra bytes.
+/// Note that @sizeOf(u24) is 3.
+/// The bit count of T must be evenly divisible by 8.
+/// Assumes the endianness of memory is foreign, so it must byte-swap.
+pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {
+ assert(@sizeOf(u24) == 3);
+ assert(bytes.len >= @sizeOf(T));
+ // TODO https://github.com/ziglang/zig/issues/863
+ return readIntForeign(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr));
+}
+
+pub const readIntSliceLittle = switch (builtin.endian) {
+ builtin.Endian.Little => readIntSliceNative,
+ builtin.Endian.Big => readIntSliceForeign,
+};
+
+pub const readIntSliceBig = switch (builtin.endian) {
+ builtin.Endian.Little => readIntSliceForeign,
+ builtin.Endian.Big => readIntSliceNative,
+};
+
+/// Reads an integer from memory with bit count specified by T.
+/// The bit count of T must be evenly divisible by 8.
+/// This function cannot fail and cannot cause undefined behavior.
+pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T {
+ if (endian == builtin.endian) {
+ return readIntNative(T, bytes);
+ } else {
+ return readIntForeign(T, bytes);
}
- return result;
}
-/// Reads a little-endian int of type T from bytes.
-/// bytes.len must be exactly @sizeOf(T).
-pub fn readIntLE(comptime T: type, bytes: []const u8) T {
- if (T.is_signed) {
- return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes));
- }
- assert(bytes.len == @sizeOf(T));
- if (T == u8) return bytes[0];
- var result: T = 0;
- {
- comptime var i = 0;
- inline while (i < @sizeOf(T)) : (i += 1) {
- result |= T(bytes[i]) << i * 8;
- }
- }
- return result;
+/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
+/// and ignores extra bytes.
+/// Note that @sizeOf(u24) is 3.
+/// The bit count of T must be evenly divisible by 8.
+pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
+ assert(@sizeOf(u24) == 3);
+ assert(bytes.len >= @sizeOf(T));
+ // TODO https://github.com/ziglang/zig/issues/863
+ return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian);
}
-test "readIntBE/LE" {
- assert(readIntBE(u0, []u8{}) == 0x0);
- assert(readIntLE(u0, []u8{}) == 0x0);
+test "readIntBig and readIntLittle" {
+ assert(readIntSliceBig(u0, []u8{}) == 0x0);
+ assert(readIntSliceLittle(u0, []u8{}) == 0x0);
- assert(readIntBE(u8, []u8{0x32}) == 0x32);
- assert(readIntLE(u8, []u8{0x12}) == 0x12);
+ assert(readIntSliceBig(u8, []u8{0x32}) == 0x32);
+ assert(readIntSliceLittle(u8, []u8{0x12}) == 0x12);
- assert(readIntBE(u16, []u8{ 0x12, 0x34 }) == 0x1234);
- assert(readIntLE(u16, []u8{ 0x12, 0x34 }) == 0x3412);
+ assert(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234);
+ assert(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412);
- assert(readIntBE(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024);
- assert(readIntLE(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec);
+ assert(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024);
+ assert(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec);
- assert(readIntBE(i8, []u8{0xff}) == -1);
- assert(readIntLE(i8, []u8{0xfe}) == -2);
+ assert(readIntSliceBig(i8, []u8{0xff}) == -1);
+ assert(readIntSliceLittle(i8, []u8{0xfe}) == -2);
- assert(readIntBE(i16, []u8{ 0xff, 0xfd }) == -3);
- assert(readIntLE(i16, []u8{ 0xfc, 0xff }) == -4);
+ assert(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3);
+ assert(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4);
}
-/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes
-/// to fill the entire buffer provided.
-/// value must be an integer.
-pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
- const uint = @IntType(false, @typeOf(value).bit_count);
- var bits = @truncate(uint, value);
- switch (endian) {
- builtin.Endian.Big => {
- var index: usize = buf.len;
- while (index != 0) {
- index -= 1;
+/// Writes an integer to memory, storing it in twos-complement.
+/// This function always succeeds, has defined behavior for all inputs, and
+/// accepts any integer bit width.
+/// This function stores in native endian, which means it is implemented as a simple
+/// memory store.
+pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
+ @ptrCast(*align(1) T, buf).* = value;
+}
- buf[index] = @truncate(u8, bits);
- bits >>= 8;
- }
- },
- builtin.Endian.Little => {
- for (buf) |*b| {
- b.* = @truncate(u8, bits);
- bits >>= 8;
- }
- },
+/// Writes an integer to memory, storing it in twos-complement.
+/// This function always succeeds, has defined behavior for all inputs, but
+/// the integer bit width must be divisible by 8.
+/// This function stores in foreign endian, which means it does a @bswap first.
+pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
+ @ptrCast(*align(1) T, buf).* = @bswap(T, value);
+}
+
+pub const writeIntLittle = switch (builtin.endian) {
+ builtin.Endian.Little => writeIntNative,
+ builtin.Endian.Big => writeIntForeign,
+};
+
+pub const writeIntBig = switch (builtin.endian) {
+ builtin.Endian.Little => writeIntForeign,
+ builtin.Endian.Big => writeIntNative,
+};
+
+/// Writes an integer to memory, storing it in twos-complement.
+/// This function always succeeds, has defined behavior for all inputs, but
+/// the integer bit width must be divisible by 8.
+pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void {
+ comptime assert(T.bit_count % 8 == 0);
+ if (endian == builtin.endian) {
+ return writeIntNative(T, buffer, value);
+ } else {
+ return writeIntForeign(T, buffer, value);
}
- assert(bits == 0);
}
-pub fn writeIntBE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
- assert(T.bit_count % 8 == 0);
+/// Writes a twos-complement little-endian integer to memory.
+/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
+/// The bit count of T must be divisible by 8.
+/// Any extra bytes in buffer after writing the integer are set to zero. To
+/// avoid the branch to check for extra buffer bytes, use writeIntLittle
+/// instead.
+pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
+ comptime assert(@sizeOf(u24) == 3);
+ comptime assert(T.bit_count % 8 == 0);
+ assert(buffer.len >= @sizeOf(T));
+
+ // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough
const uint = @IntType(false, T.bit_count);
- if (uint == u0) {
- return;
- }
- var bits = @bitCast(uint, value);
- if (uint == u8) {
- buf[0] = bits;
- return;
+ var bits = @truncate(uint, value);
+ for (buffer) |*b| {
+ b.* = @truncate(u8, bits);
+ bits >>= 8;
}
- var index: usize = buf.len;
+}
+
+/// Writes a twos-complement big-endian integer to memory.
+/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
+/// The bit count of T must be divisible by 8.
+/// Any extra bytes in buffer before writing the integer are set to zero. To
+/// avoid the branch to check for extra buffer bytes, use writeIntBig instead.
+pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
+ comptime assert(@sizeOf(u24) == 3);
+ comptime assert(T.bit_count % 8 == 0);
+ assert(buffer.len >= @sizeOf(T));
+
+ // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough
+ const uint = @IntType(false, T.bit_count);
+ var bits = @truncate(uint, value);
+ var index: usize = buffer.len;
while (index != 0) {
index -= 1;
-
- buf[index] = @truncate(u8, bits);
+ buffer[index] = @truncate(u8, bits);
bits >>= 8;
}
- assert(bits == 0);
}
-pub fn writeIntLE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
- assert(T.bit_count % 8 == 0);
- const uint = @IntType(false, T.bit_count);
- if (uint == u0) {
- return;
- }
- var bits = @bitCast(uint, value);
- if (uint == u8) {
- buf[0] = bits;
- return;
- }
- for (buf) |*b| {
- b.* = @truncate(u8, bits);
- bits >>= 8;
+pub const writeIntSliceNative = switch (builtin.endian) {
+ builtin.Endian.Little => writeIntSliceLittle,
+ builtin.Endian.Big => writeIntSliceBig,
+};
+
+pub const writeIntSliceForeign = switch (builtin.endian) {
+ builtin.Endian.Little => writeIntSliceBig,
+ builtin.Endian.Big => writeIntSliceLittle,
+};
+
+/// Writes a twos-complement integer to memory, with the specified endianness.
+/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
+/// The bit count of T must be evenly divisible by 8.
+/// Any extra bytes in buffer not part of the integer are set to zero, with
+/// respect to endianness. To avoid the branch to check for extra buffer bytes,
+/// use writeInt instead.
+pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void {
+ comptime assert(T.bit_count % 8 == 0);
+ switch (endian) {
+ builtin.Endian.Little => return writeIntSliceLittle(T, buffer, value),
+ builtin.Endian.Big => return writeIntSliceBig(T, buffer, value),
}
- assert(bits == 0);
}
-test "writeIntBE/LE" {
+test "writeIntBig and writeIntLittle" {
var buf0: [0]u8 = undefined;
var buf1: [1]u8 = undefined;
var buf2: [2]u8 = undefined;
var buf9: [9]u8 = undefined;
- writeIntBE(u0, &buf0, 0x0);
+ writeIntBig(u0, &buf0, 0x0);
assert(eql_slice_u8(buf0[0..], []u8{}));
- writeIntLE(u0, &buf0, 0x0);
+ writeIntLittle(u0, &buf0, 0x0);
assert(eql_slice_u8(buf0[0..], []u8{}));
- writeIntBE(u8, &buf1, 0x12);
+ writeIntBig(u8, &buf1, 0x12);
assert(eql_slice_u8(buf1[0..], []u8{0x12}));
- writeIntLE(u8, &buf1, 0x34);
+ writeIntLittle(u8, &buf1, 0x34);
assert(eql_slice_u8(buf1[0..], []u8{0x34}));
- writeIntBE(u16, &buf2, 0x1234);
+ writeIntBig(u16, &buf2, 0x1234);
assert(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 }));
- writeIntLE(u16, &buf2, 0x5678);
+ writeIntLittle(u16, &buf2, 0x5678);
assert(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 }));
- writeIntBE(u72, &buf9, 0x123456789abcdef024);
+ writeIntBig(u72, &buf9, 0x123456789abcdef024);
assert(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }));
- writeIntLE(u72, &buf9, 0xfedcba9876543210ec);
+ writeIntLittle(u72, &buf9, 0xfedcba9876543210ec);
assert(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }));
- writeIntBE(i8, &buf1, -1);
+ writeIntBig(i8, &buf1, -1);
assert(eql_slice_u8(buf1[0..], []u8{0xff}));
- writeIntLE(i8, &buf1, -2);
+ writeIntLittle(i8, &buf1, -2);
assert(eql_slice_u8(buf1[0..], []u8{0xfe}));
- writeIntBE(i16, &buf2, -3);
+ writeIntBig(i16, &buf2, -3);
assert(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd }));
- writeIntLE(i16, &buf2, -4);
+ writeIntLittle(i16, &buf2, -4);
assert(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff }));
}
@@ -735,12 +799,12 @@ fn testReadIntImpl() void {
0x56,
0x78,
};
- assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
- assert(readIntBE(u32, bytes) == 0x12345678);
- assert(readIntBE(i32, bytes) == 0x12345678);
- assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
- assert(readIntLE(u32, bytes) == 0x78563412);
- assert(readIntLE(i32, bytes) == 0x78563412);
+ assert(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678);
+ assert(readIntBig(u32, &bytes) == 0x12345678);
+ assert(readIntBig(i32, &bytes) == 0x12345678);
+ assert(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412);
+ assert(readIntLittle(u32, &bytes) == 0x78563412);
+ assert(readIntLittle(i32, &bytes) == 0x78563412);
}
{
const buf = []u8{
@@ -749,7 +813,7 @@ fn testReadIntImpl() void {
0x12,
0x34,
};
- const answer = readInt(buf, u64, builtin.Endian.Big);
+ const answer = readInt(u32, &buf, builtin.Endian.Big);
assert(answer == 0x00001234);
}
{
@@ -759,7 +823,7 @@ fn testReadIntImpl() void {
0x00,
0x00,
};
- const answer = readInt(buf, u64, builtin.Endian.Little);
+ const answer = readInt(u32, &buf, builtin.Endian.Little);
assert(answer == 0x00003412);
}
{
@@ -767,21 +831,33 @@ fn testReadIntImpl() void {
0xff,
0xfe,
};
- assert(readIntBE(u16, bytes) == 0xfffe);
- assert(readIntBE(i16, bytes) == -0x0002);
- assert(readIntLE(u16, bytes) == 0xfeff);
- assert(readIntLE(i16, bytes) == -0x0101);
+ assert(readIntBig(u16, &bytes) == 0xfffe);
+ assert(readIntBig(i16, &bytes) == -0x0002);
+ assert(readIntLittle(u16, &bytes) == 0xfeff);
+ assert(readIntLittle(i16, &bytes) == -0x0101);
}
}
-test "testWriteInt" {
+test "std.mem.writeIntSlice" {
testWriteIntImpl();
comptime testWriteIntImpl();
}
fn testWriteIntImpl() void {
var bytes: [8]u8 = undefined;
- writeInt(bytes[0..], u64(0x12345678CAFEBABE), builtin.Endian.Big);
+ writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big);
+ assert(eql(u8, bytes, []u8{
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ }));
+
+ writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little);
+ assert(eql(u8, bytes, []u8{
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ }));
+
+ writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big);
assert(eql(u8, bytes, []u8{
0x12,
0x34,
@@ -793,7 +869,7 @@ fn testWriteIntImpl() void {
0xBE,
}));
- writeInt(bytes[0..], u64(0xBEBAFECA78563412), builtin.Endian.Little);
+ writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little);
assert(eql(u8, bytes, []u8{
0x12,
0x34,
@@ -805,7 +881,7 @@ fn testWriteIntImpl() void {
0xBE,
}));
- writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
+ writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big);
assert(eql(u8, bytes, []u8{
0x00,
0x00,
@@ -817,7 +893,7 @@ fn testWriteIntImpl() void {
0x78,
}));
- writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
+ writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little);
assert(eql(u8, bytes, []u8{
0x12,
0x34,
@@ -829,7 +905,7 @@ fn testWriteIntImpl() void {
0x00,
}));
- writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
+ writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big);
assert(eql(u8, bytes, []u8{
0x00,
0x00,
@@ -841,7 +917,7 @@ fn testWriteIntImpl() void {
0x34,
}));
- writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
+ writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little);
assert(eql(u8, bytes, []u8{
0x34,
0x12,
@@ -939,29 +1015,52 @@ test "std.mem.rotate" {
}));
}
-// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by
-// endian-casting the pointer and then dereferencing
+/// Converts a little-endian integer to host endianness.
+pub fn littleToNative(comptime T: type, x: T) T {
+ return switch (builtin.endian) {
+ builtin.Endian.Little => x,
+ builtin.Endian.Big => @bswap(T, x),
+ };
+}
-pub fn endianSwapIfLe(comptime T: type, x: T) T {
- return endianSwapIf(builtin.Endian.Little, T, x);
+/// Converts a big-endian integer to host endianness.
+pub fn bigToNative(comptime T: type, x: T) T {
+ return switch (builtin.endian) {
+ builtin.Endian.Little => @bswap(T, x),
+ builtin.Endian.Big => x,
+ };
}
-pub fn endianSwapIfBe(comptime T: type, x: T) T {
- return endianSwapIf(builtin.Endian.Big, T, x);
+/// Converts an integer from specified endianness to host endianness.
+pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T {
+ return switch (endianness_of_x) {
+ builtin.Endian.Little => littleToNative(T, x),
+ builtin.Endian.Big => bigToNative(T, x),
+ };
}
-pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T {
- return if (builtin.endian == endian) endianSwap(T, x) else x;
+/// Converts an integer which has host endianness to the desired endianness.
+pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T {
+ return switch (desired_endianness) {
+ builtin.Endian.Little => nativeToLittle(T, x),
+ builtin.Endian.Big => nativeToBig(T, x),
+ };
}
-pub fn endianSwap(comptime T: type, x: T) T {
- var buf: [@sizeOf(T)]u8 = undefined;
- mem.writeInt(buf[0..], x, builtin.Endian.Little);
- return mem.readInt(buf, T, builtin.Endian.Big);
+/// Converts an integer which has host endianness to little endian.
+pub fn nativeToLittle(comptime T: type, x: T) T {
+ return switch (builtin.endian) {
+ builtin.Endian.Little => x,
+ builtin.Endian.Big => @bswap(T, x),
+ };
}
-test "std.mem.endianSwap" {
- assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE);
+/// Converts an integer which has host endianness to big endian.
+pub fn nativeToBig(comptime T: type, x: T) T {
+ return switch (builtin.endian) {
+ builtin.Endian.Little => @bswap(T, x),
+ builtin.Endian.Big => x,
+ };
}
fn AsBytesReturnType(comptime P: type) type {
diff --git a/std/net.zig b/std/net.zig
index 006a9d4ac5..968c1f019f 100644
--- a/std/net.zig
+++ b/std/net.zig
@@ -23,7 +23,7 @@ pub const Address = struct {
.os_addr = posix.sockaddr{
.in = posix.sockaddr_in{
.family = posix.AF_INET,
- .port = std.mem.endianSwapIfLe(u16, _port),
+ .port = mem.nativeToBig(u16, _port),
.addr = ip4,
.zero = []u8{0} ** 8,
},
@@ -37,7 +37,7 @@ pub const Address = struct {
.os_addr = posix.sockaddr{
.in6 = posix.sockaddr_in6{
.family = posix.AF_INET6,
- .port = std.mem.endianSwapIfLe(u16, _port),
+ .port = mem.nativeToBig(u16, _port),
.flowinfo = 0,
.addr = ip6.addr,
.scope_id = ip6.scope_id,
@@ -47,7 +47,7 @@ pub const Address = struct {
}
pub fn port(self: Address) u16 {
- return std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
+ return mem.bigToNative(u16, self.os_addr.in.port);
}
pub fn initPosix(addr: posix.sockaddr) Address {
@@ -57,12 +57,12 @@ pub const Address = struct {
pub fn format(self: *const Address, out_stream: var) !void {
switch (self.os_addr.in.family) {
posix.AF_INET => {
- const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
+ const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port);
const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]);
try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
},
posix.AF_INET6 => {
- const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port);
+ const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port);
try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
},
else => try out_stream.write("(unrecognized address family)"),
@@ -193,7 +193,7 @@ pub fn parseIp6(buf: []const u8) !Ip6Addr {
}
test "std.net.parseIp4" {
- assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001));
+ assert((try parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001));
testParseIp4Fail("256.0.0.1", error.Overflow);
testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
diff --git a/std/os/child_process.zig b/std/os/child_process.zig
index c8865bfacd..0aa896ff1b 100644
--- a/std/os/child_process.zig
+++ b/std/os/child_process.zig
@@ -807,10 +807,10 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);
fn writeIntFd(fd: i32, value: ErrInt) !void {
const stream = &os.File.openHandle(fd).outStream().stream;
- stream.writeIntNe(ErrInt, value) catch return error.SystemResources;
+ stream.writeIntNative(ErrInt, value) catch return error.SystemResources;
}
fn readIntFd(fd: i32) !ErrInt {
const stream = &os.File.openHandle(fd).inStream().stream;
- return stream.readIntNe(ErrInt) catch return error.SystemResources;
+ return stream.readIntNative(ErrInt) catch return error.SystemResources;
}
diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig
index 20a6710596..509075386f 100644
--- a/std/os/freebsd/x86_64.zig
+++ b/std/os/freebsd/x86_64.zig
@@ -98,12 +98,12 @@ pub nakedcc fn restore_rt() void {
}
pub const msghdr = extern struct {
- msg_name: &u8,
+ msg_name: *u8,
msg_namelen: socklen_t,
- msg_iov: &iovec,
+ msg_iov: *iovec,
msg_iovlen: i32,
__pad1: i32,
- msg_control: &u8,
+ msg_control: *u8,
msg_controllen: socklen_t,
__pad2: socklen_t,
msg_flags: i32,
diff --git a/std/pdb.zig b/std/pdb.zig
index 2c5df3e597..0cfc6a6cda 100644
--- a/std/pdb.zig
+++ b/std/pdb.zig
@@ -508,11 +508,11 @@ const Msf = struct {
allocator,
);
- const stream_count = try self.directory.stream.readIntLe(u32);
+ const stream_count = try self.directory.stream.readIntLittle(u32);
const stream_sizes = try allocator.alloc(u32, stream_count);
for (stream_sizes) |*s| {
- const size = try self.directory.stream.readIntLe(u32);
+ const size = try self.directory.stream.readIntLittle(u32);
s.* = blockCountFromSize(size, superblock.BlockSize);
}
@@ -603,7 +603,7 @@ const MsfStream = struct {
var i: u32 = 0;
while (i < block_count) : (i += 1) {
- stream.blocks[i] = try in.readIntLe(u32);
+ stream.blocks[i] = try in.readIntLittle(u32);
}
return stream;
diff --git a/std/rand/index.zig b/std/rand/index.zig
index 97101bc3b7..c335063e64 100644
--- a/std/rand/index.zig
+++ b/std/rand/index.zig
@@ -5,7 +5,7 @@
// ```
// var buf: [8]u8 = undefined;
// try std.os.getRandomBytes(buf[0..]);
-// const seed = mem.readIntLE(u64, buf[0..8]);
+// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
//
// var r = DefaultPrng.init(seed);
//
@@ -52,7 +52,7 @@ pub const Random = struct {
// use LE instead of native endian for better portability maybe?
// TODO: endian portability is pointless if the underlying prng isn't endian portable.
// TODO: document the endian portability of this library.
- const byte_aligned_result = mem.readIntLE(ByteAlignedT, rand_bytes);
+ const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes);
const unsigned_result = @truncate(UnsignedT, byte_aligned_result);
return @bitCast(T, unsigned_result);
}
@@ -69,6 +69,7 @@ pub const Random = struct {
return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than));
}
}
+
/// Returns an evenly distributed random unsigned integer `0 <= i < less_than`.
/// This function assumes that the underlying ::fillFn produces evenly distributed values.
/// Within this assumption, the runtime of this function is exponentially distributed.
@@ -123,6 +124,7 @@ pub const Random = struct {
}
return r.uintLessThanBiased(T, at_most + 1);
}
+
/// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
/// See ::uintLessThan, which this function uses in most cases,
/// for commentary on the runtime of this function.
@@ -151,6 +153,7 @@ pub const Random = struct {
return at_least + r.uintLessThanBiased(T, less_than - at_least);
}
}
+
/// Returns an evenly distributed random integer `at_least <= i < less_than`.
/// See ::uintLessThan, which this function uses in most cases,
/// for commentary on the runtime of this function.
@@ -185,6 +188,7 @@ pub const Random = struct {
return at_least + r.uintAtMostBiased(T, at_most - at_least);
}
}
+
/// Returns an evenly distributed random integer `at_least <= i <= at_most`.
/// See ::uintLessThan, which this function uses in most cases,
/// for commentary on the runtime of this function.
diff --git a/std/unicode.zig b/std/unicode.zig
index fcb748401f..2e542bcb19 100644
--- a/std/unicode.zig
+++ b/std/unicode.zig
@@ -249,12 +249,12 @@ pub const Utf16LeIterator = struct {
pub fn nextCodepoint(it: *Utf16LeIterator) !?u32 {
assert(it.i <= it.bytes.len);
if (it.i == it.bytes.len) return null;
- const c0: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]);
+ const c0: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]);
if (c0 & ~u32(0x03ff) == 0xd800) {
// surrogate pair
it.i += 2;
if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf;
- const c1: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]);
+ const c1: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]);
if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
it.i += 2;
return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
@@ -510,46 +510,46 @@ test "utf16leToUtf8" {
const utf16le_as_bytes = @sliceToBytes(utf16le[0..]);
{
- mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little);
- mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A');
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a');
const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le);
assert(mem.eql(u8, utf8, "Aa"));
}
{
- mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little);
- mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff);
const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le);
assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf"));
}
{
// the values just outside the surrogate half range
- mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little);
- mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000);
const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le);
assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80"));
}
{
// smallest surrogate pair
- mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little);
- mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00);
const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le);
assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80"));
}
{
// largest surrogate pair
- mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
- mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff);
const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le);
assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf"));
}
{
- mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
- mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00);
const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le);
assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80"));
}
@@ -583,7 +583,7 @@ pub fn utf8ToUtf16Le(utf16le: []u16, utf8: []const u8) !usize {
while (it.nextCodepoint()) |codepoint| {
if (end_index == utf16le_as_bytes.len) return (end_index / 2) + 1;
// TODO surrogate pairs
- mem.writeInt(utf16le_as_bytes[end_index..], @intCast(u16, codepoint), builtin.Endian.Little);
+ mem.writeIntSliceLittle(u16, utf16le_as_bytes[end_index..], @intCast(u16, codepoint));
end_index += 2;
}
return end_index / 2;
diff --git a/test/behavior.zig b/test/behavior.zig
index 1d031343d6..499c20ee20 100644
--- a/test/behavior.zig
+++ b/test/behavior.zig
@@ -8,6 +8,7 @@ comptime {
_ = @import("cases/atomics.zig");
_ = @import("cases/bitcast.zig");
_ = @import("cases/bool.zig");
+ _ = @import("cases/bswap.zig");
_ = @import("cases/bugs/1076.zig");
_ = @import("cases/bugs/1111.zig");
_ = @import("cases/bugs/1277.zig");
@@ -64,6 +65,7 @@ comptime {
_ = @import("cases/switch_prong_implicit_cast.zig");
_ = @import("cases/syntax.zig");
_ = @import("cases/this.zig");
+ _ = @import("cases/truncate.zig");
_ = @import("cases/try.zig");
_ = @import("cases/type_info.zig");
_ = @import("cases/undefined.zig");
diff --git a/test/cases/bswap.zig b/test/cases/bswap.zig
new file mode 100644
index 0000000000..57993077e1
--- /dev/null
+++ b/test/cases/bswap.zig
@@ -0,0 +1,32 @@
+const std = @import("std");
+const assert = std.debug.assert;
+
+test "@bswap" {
+ comptime testByteSwap();
+ testByteSwap();
+}
+
+fn testByteSwap() void {
+ assert(@bswap(u0, 0) == 0);
+ assert(@bswap(u8, 0x12) == 0x12);
+ assert(@bswap(u16, 0x1234) == 0x3412);
+ assert(@bswap(u24, 0x123456) == 0x563412);
+ assert(@bswap(u32, 0x12345678) == 0x78563412);
+ assert(@bswap(u40, 0x123456789a) == 0x9a78563412);
+ assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412);
+ assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412);
+ assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412);
+ assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412);
+
+ assert(@bswap(i0, 0) == 0);
+ assert(@bswap(i8, -50) == -50);
+ assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412)));
+ assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412)));
+ assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412)));
+ assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412)));
+ assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412)));
+ assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412)));
+ assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412)));
+ assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==
+ @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));
+}
diff --git a/test/cases/truncate.zig b/test/cases/truncate.zig
new file mode 100644
index 0000000000..02b5085ccd
--- /dev/null
+++ b/test/cases/truncate.zig
@@ -0,0 +1,8 @@
+const std = @import("std");
+const assert = std.debug.assert;
+
+test "truncate u0 to larger integer allowed and has comptime known result" {
+ var x: u0 = 0;
+ const y = @truncate(u8, x);
+ comptime assert(y == 0);
+}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index be839f0550..ee3741ee6b 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1,6 +1,18 @@
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompileErrorContext) void {
+ cases.add(
+ "reading past end of pointer casted array",
+ \\comptime {
+ \\ const array = "aoeu";
+ \\ const slice = array[2..];
+ \\ const int_ptr = @ptrCast(*const u24, slice.ptr);
+ \\ const deref = int_ptr.*;
+ \\}
+ ,
+ ".tmp_source.zig:5:26: error: attempt to read 3 bytes from [4]u8 at index 2 which is 2 bytes",
+ );
+
cases.add(
"error note for function parameter incompatibility",
\\fn do_the_thing(func: fn (arg: i32) void) void {}
--
cgit v1.2.3
From e98ba5fc4044cd84ab88b10cb8c88d765884462f Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 13 Dec 2018 06:38:14 -0500
Subject: add mem.readVarInt, fix InStream.readVarInt, fix stack traces
fixes a regression from b883bc8
---
std/debug/index.zig | 2 +-
std/io.zig | 11 ++++++-----
std/mem.zig | 21 +++++++++++++++++++++
3 files changed, 28 insertions(+), 6 deletions(-)
(limited to 'std/debug')
diff --git a/std/debug/index.zig b/std/debug/index.zig
index 3967e5a8be..73c6ea7b56 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -1200,7 +1200,7 @@ const Constant = struct {
fn asUnsignedLe(self: *const Constant) !u64 {
if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
if (self.signed) return error.InvalidDebugInfo;
- return mem.readIntSliceLittle(u64, self.payload);
+ return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
}
};
diff --git a/std/io.zig b/std/io.zig
index 8d33dfc5ea..c40ededc00 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -183,11 +183,12 @@ pub fn InStream(comptime ReadError: type) type {
return mem.readIntSlice(T, bytes, endian);
}
- pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T {
- assert(size <= @sizeOf(T));
- var bytes: [@sizeOf(T)]u8 = undefined;
- try self.readNoEof(bytes[0..size]);
- return mem.readIntSlice(T, bytes, endian);
+ pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
+ assert(size <= @sizeOf(ReturnType));
+ var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
+ const bytes = bytes_buf[0..size];
+ try self.readNoEof(bytes);
+ return mem.readVarInt(ReturnType, bytes, endian);
}
pub fn skipBytes(self: *Self, num_bytes: usize) !void {
diff --git a/std/mem.zig b/std/mem.zig
index 97dc46a80f..393033f22a 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -407,6 +407,27 @@ test "mem.indexOf" {
assert(lastIndexOfScalar(u8, "boo", 'o').? == 2);
}
+/// Reads an integer from memory with size equal to bytes.len.
+/// T specifies the return type, which must be large enough to store
+/// the result.
+pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType {
+ var result: ReturnType = 0;
+ switch (endian) {
+ builtin.Endian.Big => {
+ for (bytes) |b| {
+ result = (result << 8) | b;
+ }
+ },
+ builtin.Endian.Little => {
+ const ShiftType = math.Log2Int(ReturnType);
+ for (bytes) |b, index| {
+ result = result | (ReturnType(b) << @intCast(ShiftType, index * 8));
+ }
+ },
+ }
+ return result;
+}
+
/// Reads an integer from memory with bit count specified by T.
/// The bit count of T must be evenly divisible by 8.
/// This function cannot fail and cannot cause undefined behavior.
--
cgit v1.2.3