diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-09-20 16:10:34 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-09-20 16:10:34 -0400 |
| commit | b97bfc3ecba9655cdd989add13a7582272659268 (patch) | |
| tree | af3c8902db85adfd71995b7e3d49c3f51a17aafa /std | |
| parent | 158225a2038e304cf5e8effa2f9e9624636b0d59 (diff) | |
| download | zig-b97bfc3ecba9655cdd989add13a7582272659268.tar.gz zig-b97bfc3ecba9655cdd989add13a7582272659268.zip | |
fix error when switch prong has implicit cast
closes #194
Diffstat (limited to 'std')
| -rw-r--r-- | std/debug.zig | 219 | ||||
| -rw-r--r-- | std/dwarf.zig | 2 | ||||
| -rw-r--r-- | std/mem.zig | 1 |
3 files changed, 211 insertions, 11 deletions
diff --git a/std/debug.zig b/std/debug.zig index 8b3d4c9b05..d8d2ea4b48 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -3,6 +3,7 @@ const io = @import("io.zig"); const os = @import("os.zig"); const elf = @import("elf.zig"); const DW = @import("dwarf.zig"); +const List = @import("list.zig").List; pub error MissingDebugInfo; pub error InvalidDebugInfo; @@ -29,6 +30,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void { st.aranges = %return st.elf.findSection(".debug_aranges"); st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo; + st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo; var maybe_fp: ?&const u8 = @frameAddress(); while (true) { @@ -62,6 +64,140 @@ struct ElfStackTrace { elf: elf.Elf, aranges: ?&elf.SectionHeader, debug_info: &elf.SectionHeader, + debug_abbrev: &elf.SectionHeader, +} + +enum FormValue { + Address: u64, + Block: []u8, + Const: Constant, + ExprLoc: []u8, + Flag: bool, + SecOffset: u64, + Ref: []u8, + RefAddr: u64, + RefSig8: u64, + String: []u8, + StrPtr: u64, +} + +struct Constant { + payload: []u8, + signed: bool, +} + + +fn readAllocBytes(in_stream: &io.InStream, size: usize) -> %[]u8 { + const buf = %return global_allocator.alloc(u8, size); + %defer global_allocator.free(u8, buf); + %return in_stream.read(buf); + return buf; +} + +fn parseFormValueBlockLen(in_stream: &io.InStream, size: usize) -> %FormValue { + const buf = %return readAllocBytes(in_stream, size); + return FormValue.Block { buf }; +} + +fn parseFormValueBlock(in_stream: &io.InStream, inline T: type) -> %FormValue { + const block_len = %return in_stream.readIntLe(T); + return parseFormValueBlockLen(in_stream, block_len); +} + +fn parseFormValueConstantLen(in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue { + const buf = %return readAllocBytes(in_stream, size); + return FormValue.Const { Constant { + .signed = signed, + .payload = buf, + }}; +} + +fn parseFormValueConstant(in_stream: &io.InStream, signed: bool, inline T: type) -> %FormValue { + const block_len = %return in_stream.readIntLe(T); + return parseFormValueConstantLen(in_stream, signed, block_len); +} + +fn parseFormValueAddrSize(in_stream: &io.InStream, is_64: bool) -> %u64 { + return if (is_64) { + %return in_stream.readIntLe(u64) + } else { + u64(%return in_stream.readIntLe(u32)) + }; +} + +fn parseFormValueRefLen(in_stream: &io.InStream, size: usize) -> %FormValue { + const buf = %return readAllocBytes(in_stream, size); + return FormValue.Ref { buf }; +} + +fn parseFormValueRef(in_stream: &io.InStream, inline T: type) -> %FormValue { + const block_len = %return in_stream.readIntLe(T); + return parseFormValueRefLen(in_stream, block_len); +} + +fn parseFormValue(in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue { + return switch (form_id) { + DW.FORM_addr => FormValue.Address { + %return parseFormValueAddrSize(in_stream, is_64) + }, + DW.FORM_block1 => parseFormValueBlock(in_stream, u8), + DW.FORM_block2 => parseFormValueBlock(in_stream, u16), + DW.FORM_block4 => parseFormValueBlock(in_stream, u32), + DW.FORM_block => { + const block_len = %return readULeb128(in_stream); + parseFormValueBlockLen(in_stream, block_len) + }, + DW.FORM_data1 => parseFormValueConstant(in_stream, false, u8), + DW.FORM_data2 => parseFormValueConstant(in_stream, false, u16), + DW.FORM_data4 => parseFormValueConstant(in_stream, false, u32), + DW.FORM_data8 => parseFormValueConstant(in_stream, false, u64), + DW.FORM_udata, DW.FORM_sdata => { + const block_len = %return readULeb128(in_stream); + const signed = form_id == DW.FORM_sdata; + parseFormValueConstantLen(in_stream, signed, block_len) + }, + DW.FORM_exprloc => { + const size = %return readULeb128(in_stream); + const buf = %return readAllocBytes(in_stream, size); + return FormValue.ExprLoc { buf }; + }, + DW.FORM_flag => FormValue.Flag { (%return in_stream.readByte()) != 0 }, + DW.FORM_flag_present => FormValue.Flag { true }, + DW.FORM_sec_offset => FormValue.SecOffset { + %return parseFormValueAddrSize(in_stream, is_64) + }, + + DW.FORM_ref1 => parseFormValueRef(in_stream, u8), + DW.FORM_ref2 => parseFormValueRef(in_stream, u16), + DW.FORM_ref4 => parseFormValueRef(in_stream, u32), + DW.FORM_ref8 => parseFormValueRef(in_stream, u64), + DW.FORM_ref_udata => { + const ref_len = %return readULeb128(in_stream); + parseFormValueRefLen(in_stream, ref_len) + }, + + DW.FORM_ref_addr => FormValue.RefAddr { %return parseFormValueAddrSize(in_stream, is_64) }, + DW.FORM_ref_sig8 => FormValue.RefSig8 { %return in_stream.readIntLe(u64) }, + + DW.FORM_string => { + var buf: List(u8) = undefined; + buf.init(&global_allocator); + while (true) { + const byte = %return in_stream.readByte(); + if (byte == 0) + break; + %return buf.append(byte); + } + + FormValue.String { buf.items } + }, + DW.FORM_strp => FormValue.StrPtr { %return parseFormValueAddrSize(in_stream, is_64) }, + DW.FORM_indirect => { + const child_form_id = %return readULeb128(in_stream); + parseFormValue(in_stream, child_form_id, is_64) + }, + else => return error.InvalidDebugInfo, + } } fn findCompileUnitOffset(st: &ElfStackTrace, target_address: usize) -> %u64 { @@ -72,8 +208,78 @@ fn findCompileUnitOffset(st: &ElfStackTrace, target_address: usize) -> %u64 { %return st.elf.seekToSection(st.debug_info); while (true) { - const tag_id = %return st.self_exe_stream.readByte(); - // TODO iterate until we find the relevant compile unit + var is_64: bool = undefined; + const unit_length = %return readInitialLength(&st.self_exe_stream, &is_64); + + const version = %return st.self_exe_stream.readInt(st.elf.is_big_endian, u16); + if (version != 4) return error.InvalidDebugInfo; + + const debug_abbrev_offset = if (is_64) { + %return st.self_exe_stream.readInt(st.elf.is_big_endian, u64) + } else { + %return st.self_exe_stream.readInt(st.elf.is_big_endian, u32) + }; + + const address_size = %return st.self_exe_stream.readByte(); + if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; + + const abbrev_tag_id = %return st.self_exe_stream.readByte(); + + + } +} + +fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 { + const first_32_bits = %return in_stream.readIntLe(u32); + *is_64 = (first_32_bits == 0xffffffff); + return if (*is_64) { + %return in_stream.readIntLe(u64) + } else { + if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; + u64(first_32_bits) + }; +} + +fn readULeb128(in_stream: &io.InStream) -> %u64 { + var result: u64 = 0; + var shift: u64 = 0; + + while (true) { + const byte = %return in_stream.readByte(); + var operand: u64 = undefined; + + if (@shlWithOverflow(u64, byte & 0b01111111, shift, &operand)) + return error.InvalidDebugInfo; + + result |= operand; + + if ((byte & 0b10000000) == 0) + return result; + + shift += 7; + } +} + +fn readILeb128(in_stream: &io.InStream) -> %i64 { + var result: i64 = 0; + var shift: i64 = 0; + + while (true) { + const byte = %return in_stream.readByte(); + var operand: i64 = undefined; + + if (@shlWithOverflow(i64, byte & 0b01111111, shift, &operand)) + return error.InvalidDebugInfo; + + result |= operand; + shift += 7; + + if ((byte & 0b10000000) == 0) { + if (shift < @sizeOf(i64) * 8 && (byte & 0b01000000) != 0) + result |= -(i64(1) << shift); + + return result; + } } } @@ -84,13 +290,8 @@ fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 { %return st.elf.seekToSection(aranges); const first_32_bits = %return st.self_exe_stream.readIntLe(u32); - const is_64 = (first_32_bits == 0xffffffff); - const unit_length = if (is_64) { - %return st.self_exe_stream.readIntLe(u64) - } else { - if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; - first_32_bits - }; + var is_64: bool = undefined; + const unit_length = %return readInitialLength(&st.self_exe_stream, &is_64); var unit_index: u64 = 0; while (unit_index < unit_length) { diff --git a/std/dwarf.zig b/std/dwarf.zig index 9354211692..319bcef982 100644 --- a/std/dwarf.zig +++ b/std/dwarf.zig @@ -127,8 +127,6 @@ pub const FORM_ref4 = 0x13; pub const FORM_ref8 = 0x14; pub const FORM_ref_udata = 0x15; pub const FORM_indirect = 0x16; - -// DWARF 4. pub const FORM_sec_offset = 0x17; pub const FORM_exprloc = 0x18; pub const FORM_flag_present = 0x19; diff --git a/std/mem.zig b/std/mem.zig index 882588834c..0103c71f8e 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -35,6 +35,7 @@ pub struct Allocator { ([]T)(%return self.reallocFn(self, ([]u8)(old_mem), byte_count)) } + // TODO mem: []var and get rid of 2nd param fn free(self: &Allocator, inline T: type, mem: []T) { self.freeFn(self, ([]u8)(mem)); } |
