stack traces: support DW_AT_ranges

This makes some cases print stack traces where it previously failed.
This commit is contained in:
Andrew Kelley 2017-12-12 11:33:14 -05:00
parent 23058d8b43
commit caa6433b56

View File

@ -113,6 +113,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
.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),
};
@ -127,6 +128,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
st.debug_ranges = (%return st.elf.findSection(".debug_ranges"));
%return scanAllCompileUnits(st);
var ignored_count: usize = 0;
@ -144,7 +146,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
// at compile time. I'll call it issue #313
const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
const compile_unit = findCompileUnit(st, return_address) ?? {
const compile_unit = findCompileUnit(st, return_address) %% {
%return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
return_address);
continue;
@ -233,6 +235,7 @@ const ElfStackTrace = struct {
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),
@ -333,6 +336,15 @@ const Die = struct {
};
}
fn getAttrSecOffset(self: &const Die, id: u64) -> %u64 {
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
return switch (*form_value) {
FormValue.Const => |value| value.asUnsignedLe(),
FormValue.SecOffset => |value| value,
else => error.InvalidDebugInfo,
};
}
fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 {
const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
return switch (*form_value) {
@ -900,14 +912,40 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
}
}
fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> ?&const CompileUnit {
fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUnit {
var in_file_stream = io.FileInStream.init(&st.self_exe_file);
const in_stream = &in_file_stream.stream;
for (st.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| {
%return st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
while (true) {
const begin_addr = %return in_stream.readIntLe(usize);
const end_addr = %return in_stream.readIntLe(usize);
if (begin_addr == 0 and end_addr == 0) {
break;
}
if (begin_addr == @maxValue(usize)) {
base_address = begin_addr;
continue;
}
if (target_address >= begin_addr and target_address < end_addr) {
return compile_unit;
}
}
}
} else |err| {
if (err != error.MissingDebugInfo)
return err;
continue;
}
}
return null;
return error.MissingDebugInfo;
}
fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {