aboutsummaryrefslogtreecommitdiff
path: root/std/debug.zig
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-09-20 16:10:34 -0400
committerAndrew Kelley <superjoe30@gmail.com>2016-09-20 16:10:34 -0400
commitb97bfc3ecba9655cdd989add13a7582272659268 (patch)
treeaf3c8902db85adfd71995b7e3d49c3f51a17aafa /std/debug.zig
parent158225a2038e304cf5e8effa2f9e9624636b0d59 (diff)
downloadzig-b97bfc3ecba9655cdd989add13a7582272659268.tar.gz
zig-b97bfc3ecba9655cdd989add13a7582272659268.zip
fix error when switch prong has implicit cast
closes #194
Diffstat (limited to 'std/debug.zig')
-rw-r--r--std/debug.zig219
1 files changed, 210 insertions, 9 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) {