aboutsummaryrefslogtreecommitdiff
path: root/std/debug.zig
diff options
context:
space:
mode:
authorhryx <codroid@gmail.com>2019-05-12 02:00:49 -0700
committerhryx <codroid@gmail.com>2019-05-12 02:00:49 -0700
commit3787f3428625e830fd852a8f5a40c7d8a2d429f6 (patch)
tree23fb493b9d2f07c7abe57955874682959936319a /std/debug.zig
parent16aee1f58a80295f7599a8290d764a5c7040c373 (diff)
parentedcc7c72d1a684a8a16ca23ad26689f2cce4e803 (diff)
downloadzig-3787f3428625e830fd852a8f5a40c7d8a2d429f6.tar.gz
zig-3787f3428625e830fd852a8f5a40c7d8a2d429f6.zip
Merge branch 'master' into rebased
Diffstat (limited to 'std/debug.zig')
-rw-r--r--std/debug.zig630
1 files changed, 344 insertions, 286 deletions
diff --git a/std/debug.zig b/std/debug.zig
index c85a982059..d017f96144 100644
--- a/std/debug.zig
+++ b/std/debug.zig
@@ -13,6 +13,8 @@ const ArrayList = std.ArrayList;
const builtin = @import("builtin");
const maxInt = std.math.maxInt;
+const leb = @import("debug/leb128.zig");
+
pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator;
pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;
@@ -214,14 +216,14 @@ pub fn writeStackTrace(
tty_color: bool,
) !void {
var frame_index: usize = 0;
- var frames_left: usize = stack_trace.index;
+ var frames_left: usize = std.math.min(stack_trace.index, stack_trace.instruction_addresses.len);
while (frames_left != 0) : ({
frames_left -= 1;
frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
}) {
const return_address = stack_trace.instruction_addresses[frame_index];
- try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
+ try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_color);
}
}
@@ -263,7 +265,7 @@ pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color
}
var it = StackIterator.init(start_addr);
while (it.next()) |return_address| {
- try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
+ try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_color);
}
}
@@ -376,7 +378,6 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
// There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
// from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
// breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
-
const subsection_end_index = sect_offset + subsect_hdr.Length;
while (line_index < subsection_end_index) {
@@ -690,9 +691,9 @@ pub fn printSourceAtAddressDwarf(
return;
};
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
- if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
+ if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address)) |line_info| {
defer line_info.deinit();
- const symbol_name = "???";
+ const symbol_name = getSymbolNameDwarf(debug_info, address) orelse "???";
try printLineInfo(
out_stream,
line_info,
@@ -969,6 +970,8 @@ fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Sec
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);
+ di.func_list = ArrayList(Func).init(allocator);
+ try scanAllFunctions(di);
try scanAllCompileUnits(di);
}
@@ -992,6 +995,7 @@ pub fn openElfDebugInfo(
.debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
.abbrev_table_list = undefined,
.compile_unit_list = undefined,
+ .func_list = undefined,
};
try openDwarfDebugInfo(&di, allocator);
return di;
@@ -1162,6 +1166,7 @@ pub const DwarfInfo = struct {
debug_ranges: ?Section,
abbrev_table_list: ArrayList(AbbrevTableHeader),
compile_unit_list: ArrayList(CompileUnit),
+ func_list: ArrayList(Func),
pub const Section = struct {
offset: usize,
@@ -1178,7 +1183,7 @@ pub const DwarfInfo = struct {
};
pub const DebugInfo = switch (builtin.os) {
- builtin.Os.macosx => struct {
+ builtin.Os.macosx, builtin.Os.ios => struct {
symbols: []const MachoSymbol,
strings: []const u8,
ofiles: OFileTable,
@@ -1213,7 +1218,6 @@ const CompileUnit = struct {
version: u16,
is_64: bool,
die: *Die,
- index: usize,
pc_range: ?PcRange,
};
@@ -1244,21 +1248,19 @@ const FormValue = union(enum) {
ExprLoc: []u8,
Flag: bool,
SecOffset: u64,
- Ref: []u8,
+ Ref: u64,
RefAddr: u64,
- RefSig8: u64,
String: []u8,
StrPtr: u64,
};
const Constant = struct {
- payload: []u8,
+ payload: u64,
signed: bool,
fn asUnsignedLe(self: *const Constant) !u64 {
- if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
if (self.signed) return error.InvalidDebugInfo;
- return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
+ return self.payload;
}
};
@@ -1304,6 +1306,14 @@ const Die = struct {
};
}
+ fn getAttrRef(self: *const Die, id: u64) !u64 {
+ const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
+ return switch (form_value.*) {
+ FormValue.Ref => |value| value,
+ else => error.InvalidDebugInfo,
+ };
+ }
+
fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
return switch (form_value.*) {
@@ -1443,11 +1453,18 @@ fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !
return parseFormValueBlockLen(allocator, in_stream, block_len);
}
-fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
+fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
return FormValue{
.Const = Constant{
.signed = signed,
- .payload = try readAllocBytes(allocator, in_stream, size),
+ .payload = switch (size) {
+ 1 => try in_stream.readIntLittle(u8),
+ 2 => try in_stream.readIntLittle(u16),
+ 4 => try in_stream.readIntLittle(u32),
+ 8 => try in_stream.readIntLittle(u64),
+ -1 => if (signed) @bitCast(u64, try leb.readILEB128(i64, in_stream)) else try leb.readULEB128(u64, in_stream),
+ else => @compileError("Invalid size"),
+ },
},
};
}
@@ -1460,14 +1477,17 @@ fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
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 {
- const buf = try readAllocBytes(allocator, in_stream, size);
- return FormValue{ .Ref = buf };
-}
-
-fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
- const block_len = try in_stream.readIntLittle(T);
- return parseFormValueRefLen(allocator, in_stream, block_len);
+fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {
+ return FormValue{
+ .Ref = switch (size) {
+ 1 => try in_stream.readIntLittle(u8),
+ 2 => try in_stream.readIntLittle(u16),
+ 4 => try in_stream.readIntLittle(u32),
+ 8 => try in_stream.readIntLittle(u64),
+ -1 => try leb.readULEB128(u64, in_stream),
+ else => unreachable,
+ },
+ };
}
fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
@@ -1477,7 +1497,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
DW.FORM_block => x: {
- const block_len = try readULeb128(in_stream);
+ const block_len = try leb.readULEB128(usize, in_stream);
return parseFormValueBlockLen(allocator, in_stream, block_len);
},
DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
@@ -1485,12 +1505,11 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
DW.FORM_udata, DW.FORM_sdata => {
- const block_len = try readULeb128(in_stream);
const signed = form_id == DW.FORM_sdata;
- return parseFormValueConstant(allocator, in_stream, signed, block_len);
+ return parseFormValueConstant(allocator, in_stream, signed, -1);
},
DW.FORM_exprloc => {
- const size = try readULeb128(in_stream);
+ const size = try leb.readULEB128(usize, in_stream);
const buf = try readAllocBytes(allocator, in_stream, size);
return FormValue{ .ExprLoc = buf };
},
@@ -1498,22 +1517,19 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
DW.FORM_flag_present => FormValue{ .Flag = true },
DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
- DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
- DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
- DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
- DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
- DW.FORM_ref_udata => {
- const ref_len = try readULeb128(in_stream);
- return parseFormValueRefLen(allocator, in_stream, ref_len);
- },
+ DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, 1),
+ DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, 2),
+ DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, 4),
+ DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, 8),
+ DW.FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
- DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
+ DW.FORM_ref_sig8 => FormValue{ .Ref = 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) },
DW.FORM_indirect => {
- const child_form_id = try readULeb128(in_stream);
+ const child_form_id = try leb.readULEB128(u64, in_stream);
return parseFormValue(allocator, in_stream, child_form_id, is_64);
},
else => error.InvalidDebugInfo,
@@ -1523,19 +1539,19 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
var result = AbbrevTable.init(di.allocator());
while (true) {
- const abbrev_code = try readULeb128(di.dwarf_in_stream);
+ const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
if (abbrev_code == 0) return result;
try result.append(AbbrevTableEntry{
.abbrev_code = abbrev_code,
- .tag_id = try readULeb128(di.dwarf_in_stream),
+ .tag_id = try leb.readULEB128(u64, 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(di.dwarf_in_stream);
- const form_id = try readULeb128(di.dwarf_in_stream);
+ const attr_id = try leb.readULEB128(u64, di.dwarf_in_stream);
+ const form_id = try leb.readULEB128(u64, di.dwarf_in_stream);
if (attr_id == 0 and form_id == 0) break;
try attrs.append(AbbrevAttr{
.attr_id = attr_id,
@@ -1568,8 +1584,28 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
return null;
}
+fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
+ const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
+ if (abbrev_code == 0) return null;
+ 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(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(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
+ };
+ }
+ return result;
+}
+
fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
- const abbrev_code = try readULeb128(di.dwarf_in_stream);
+ const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
var result = Die{
@@ -1682,9 +1718,9 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
while (true) {
const file_name = readStringMem(&ptr);
if (file_name.len == 0) break;
- const dir_index = try readULeb128Mem(&ptr);
- const mtime = try readULeb128Mem(&ptr);
- const len_bytes = try readULeb128Mem(&ptr);
+ const dir_index = try leb.readULEB128Mem(usize, &ptr);
+ const mtime = try leb.readULEB128Mem(usize, &ptr);
+ const len_bytes = try leb.readULEB128Mem(usize, &ptr);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
@@ -1698,7 +1734,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
const opcode = readByteMem(&ptr);
if (opcode == DW.LNS_extended_op) {
- const op_size = try readULeb128Mem(&ptr);
+ const op_size = try leb.readULEB128Mem(u64, &ptr);
if (op_size < 1) return error.InvalidDebugInfo;
var sub_op = readByteMem(&ptr);
switch (sub_op) {
@@ -1713,9 +1749,9 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
},
DW.LNE_define_file => {
const file_name = readStringMem(&ptr);
- const dir_index = try readULeb128Mem(&ptr);
- const mtime = try readULeb128Mem(&ptr);
- const len_bytes = try readULeb128Mem(&ptr);
+ const dir_index = try leb.readULEB128Mem(usize, &ptr);
+ const mtime = try leb.readULEB128Mem(usize, &ptr);
+ const len_bytes = try leb.readULEB128Mem(usize, &ptr);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
@@ -1743,19 +1779,19 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
prog.basic_block = false;
},
DW.LNS_advance_pc => {
- const arg = try readULeb128Mem(&ptr);
+ const arg = try leb.readULEB128Mem(u64, &ptr);
prog.address += arg * minimum_instruction_length;
},
DW.LNS_advance_line => {
- const arg = try readILeb128Mem(&ptr);
+ const arg = try leb.readILEB128Mem(i64, &ptr);
prog.line += arg;
},
DW.LNS_set_file => {
- const arg = try readULeb128Mem(&ptr);
+ const arg = try leb.readULEB128Mem(u64, &ptr);
prog.file = arg;
},
DW.LNS_set_column => {
- const arg = try readULeb128Mem(&ptr);
+ const arg = try leb.readULEB128Mem(u64, &ptr);
prog.column = arg;
},
DW.LNS_negate_stmt => {
@@ -1787,182 +1823,292 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
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 line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list);
- const debug_line_end = di.debug_line.offset + di.debug_line.size;
- var this_offset = di.debug_line.offset;
- var this_index: usize = 0;
+ assert(line_info_offset < di.debug_line.size);
- while (this_offset < debug_line_end) : (this_index += 1) {
- try di.dwarf_seekable_stream.seekTo(this_offset);
+ try di.dwarf_seekable_stream.seekTo(di.debug_line.offset + line_info_offset);
- var is_64: bool = undefined;
- 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));
+ var is_64: bool = undefined;
+ 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));
- if (compile_unit.index != this_index) {
- this_offset += next_offset;
- continue;
- }
+ 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 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(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();
+ if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
+
+ if (version >= 4) {
+ // maximum_operations_per_instruction
+ _ = try di.dwarf_in_stream.readByte();
+ }
+
+ const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
+ const line_base = try di.dwarf_in_stream.readByteSigned();
+
+ const line_range = try di.dwarf_in_stream.readByte();
+ if (line_range == 0) return error.InvalidDebugInfo;
- 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 opcode_base = try di.dwarf_in_stream.readByte();
- const minimum_instruction_length = try di.dwarf_in_stream.readByte();
- if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
+ const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
- if (version >= 4) {
- // maximum_operations_per_instruction
- _ = try di.dwarf_in_stream.readByte();
+ {
+ var i: usize = 0;
+ while (i < opcode_base - 1) : (i += 1) {
+ standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
}
+ }
- const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
- const line_base = try di.dwarf_in_stream.readByteSigned();
+ var include_directories = ArrayList([]u8).init(di.allocator());
+ try include_directories.append(compile_unit_cwd);
+ while (true) {
+ const dir = try di.readString();
+ if (dir.len == 0) break;
+ try include_directories.append(dir);
+ }
+
+ var file_entries = ArrayList(FileEntry).init(di.allocator());
+ var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
- const line_range = try di.dwarf_in_stream.readByte();
- if (line_range == 0) return error.InvalidDebugInfo;
+ while (true) {
+ const file_name = try di.readString();
+ if (file_name.len == 0) break;
+ const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
+ const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
+ const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
+ try file_entries.append(FileEntry{
+ .file_name = file_name,
+ .dir_index = dir_index,
+ .mtime = mtime,
+ .len_bytes = len_bytes,
+ });
+ }
- const opcode_base = try di.dwarf_in_stream.readByte();
+ try di.dwarf_seekable_stream.seekTo(prog_start_offset);
- const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
+ while (true) {
+ const opcode = try di.dwarf_in_stream.readByte();
- {
- var i: usize = 0;
- while (i < opcode_base - 1) : (i += 1) {
- standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
+ if (opcode == DW.LNS_extended_op) {
+ const op_size = try leb.readULEB128(u64, di.dwarf_in_stream);
+ if (op_size < 1) return error.InvalidDebugInfo;
+ var sub_op = try di.dwarf_in_stream.readByte();
+ switch (sub_op) {
+ DW.LNE_end_sequence => {
+ prog.end_sequence = true;
+ if (try prog.checkLineMatch()) |info| return info;
+ return error.MissingDebugInfo;
+ },
+ DW.LNE_set_address => {
+ const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
+ prog.address = addr;
+ },
+ DW.LNE_define_file => {
+ const file_name = try di.readString();
+ const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
+ const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
+ const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
+ try file_entries.append(FileEntry{
+ .file_name = file_name,
+ .dir_index = dir_index,
+ .mtime = mtime,
+ .len_bytes = len_bytes,
+ });
+ },
+ else => {
+ const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
+ try di.dwarf_seekable_stream.seekForward(fwd_amt);
+ },
+ }
+ } else if (opcode >= opcode_base) {
+ // special opcodes
+ const adjusted_opcode = opcode - opcode_base;
+ const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
+ const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
+ prog.line += inc_line;
+ prog.address += inc_addr;
+ if (try prog.checkLineMatch()) |info| return info;
+ prog.basic_block = false;
+ } else {
+ switch (opcode) {
+ DW.LNS_copy => {
+ if (try prog.checkLineMatch()) |info| return info;
+ prog.basic_block = false;
+ },
+ DW.LNS_advance_pc => {
+ const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
+ prog.address += arg * minimum_instruction_length;
+ },
+ DW.LNS_advance_line => {
+ const arg = try leb.readILEB128(i64, di.dwarf_in_stream);
+ prog.line += arg;
+ },
+ DW.LNS_set_file => {
+ const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
+ prog.file = arg;
+ },
+ DW.LNS_set_column => {
+ const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
+ prog.column = arg;
+ },
+ DW.LNS_negate_stmt => {
+ prog.is_stmt = !prog.is_stmt;
+ },
+ DW.LNS_set_basic_block => {
+ prog.basic_block = true;
+ },
+ DW.LNS_const_add_pc => {
+ const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
+ prog.address += inc_addr;
+ },
+ DW.LNS_fixed_advance_pc => {
+ const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
+ 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 di.dwarf_seekable_stream.seekForward(len_bytes);
+ },
}
}
+ }
- var include_directories = ArrayList([]u8).init(di.allocator());
- try include_directories.append(compile_unit_cwd);
- while (true) {
- const dir = try di.readString();
- if (dir.len == 0) break;
- try include_directories.append(dir);
- }
+ return error.MissingDebugInfo;
+}
- var file_entries = ArrayList(FileEntry).init(di.allocator());
- var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
+const Func = struct {
+ pc_range: ?PcRange,
+ name: ?[]u8,
+};
- while (true) {
- const file_name = try di.readString();
- if (file_name.len == 0) break;
- 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,
- .mtime = mtime,
- .len_bytes = len_bytes,
- });
+fn getSymbolNameDwarf(di: *DwarfInfo, address: u64) ?[]const u8 {
+ for (di.func_list.toSliceConst()) |*func| {
+ if (func.pc_range) |range| {
+ if (address >= range.start and address < range.end) {
+ return func.name;
+ }
}
+ }
+
+ return null;
+}
- try di.dwarf_seekable_stream.seekTo(prog_start_offset);
+fn scanAllFunctions(di: *DwarfInfo) !void {
+ const debug_info_end = di.debug_info.offset + di.debug_info.size;
+ var this_unit_offset = di.debug_info.offset;
- while (true) {
- const opcode = try di.dwarf_in_stream.readByte();
-
- if (opcode == DW.LNS_extended_op) {
- const op_size = try readULeb128(di.dwarf_in_stream);
- if (op_size < 1) return error.InvalidDebugInfo;
- var sub_op = try di.dwarf_in_stream.readByte();
- switch (sub_op) {
- DW.LNE_end_sequence => {
- prog.end_sequence = true;
- if (try prog.checkLineMatch()) |info| return info;
- return error.MissingDebugInfo;
- },
- DW.LNE_set_address => {
- const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
- prog.address = addr;
- },
- DW.LNE_define_file => {
- const file_name = try di.readString();
- 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,
- .mtime = mtime,
- .len_bytes = len_bytes,
- });
- },
- else => {
- const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
- try di.dwarf_seekable_stream.seekForward(fwd_amt);
- },
- }
- } else if (opcode >= opcode_base) {
- // special opcodes
- const adjusted_opcode = opcode - opcode_base;
- const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
- const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
- prog.line += inc_line;
- prog.address += inc_addr;
- if (try prog.checkLineMatch()) |info| return info;
- prog.basic_block = false;
- } else {
- switch (opcode) {
- DW.LNS_copy => {
- if (try prog.checkLineMatch()) |info| return info;
- prog.basic_block = false;
- },
- DW.LNS_advance_pc => {
- const arg = try readULeb128(di.dwarf_in_stream);
- prog.address += arg * minimum_instruction_length;
- },
- DW.LNS_advance_line => {
- const arg = try readILeb128(di.dwarf_in_stream);
- prog.line += arg;
- },
- DW.LNS_set_file => {
- const arg = try readULeb128(di.dwarf_in_stream);
- prog.file = arg;
- },
- DW.LNS_set_column => {
- const arg = try readULeb128(di.dwarf_in_stream);
- prog.column = arg;
- },
- DW.LNS_negate_stmt => {
- prog.is_stmt = !prog.is_stmt;
- },
- DW.LNS_set_basic_block => {
- prog.basic_block = true;
- },
- DW.LNS_const_add_pc => {
- const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
- prog.address += inc_addr;
- },
- DW.LNS_fixed_advance_pc => {
- const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
- 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 di.dwarf_seekable_stream.seekForward(len_bytes);
- },
- }
+ while (this_unit_offset < debug_info_end) {
+ try di.dwarf_seekable_stream.seekTo(this_unit_offset);
+
+ var is_64: bool = undefined;
+ 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 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(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;
+
+ const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
+ const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
+
+ try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
+
+ const next_unit_pos = this_unit_offset + next_offset;
+
+ while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) {
+ const die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse continue;
+ const after_die_offset = try di.dwarf_seekable_stream.getPos();
+
+ switch (die_obj.tag_id) {
+ DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
+ const fn_name = x: {
+ var depth: i32 = 3;
+ var this_die_obj = die_obj;
+ // Prenvent endless loops
+ while (depth > 0) : (depth -= 1) {
+ if (this_die_obj.getAttr(DW.AT_name)) |_| {
+ const name = try this_die_obj.getAttrString(di, DW.AT_name);
+ break :x name;
+ } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| {
+ // Follow the DIE it points to and repeat
+ const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
+ if (ref_offset > next_offset) return error.InvalidDebugInfo;
+ try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
+ this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
+ } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
+ // Follow the DIE it points to and repeat
+ const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification);
+ if (ref_offset > next_offset) return error.InvalidDebugInfo;
+ try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
+ this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
+ } else {
+ break :x null;
+ }
+ }
+
+ break :x null;
+ };
+
+ const pc_range = x: {
+ if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
+ if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
+ const pc_end = switch (high_pc_value.*) {
+ FormValue.Address => |value| value,
+ FormValue.Const => |value| b: {
+ const offset = try value.asUnsignedLe();
+ break :b (low_pc + offset);
+ },
+ else => return error.InvalidDebugInfo,
+ };
+ break :x PcRange{
+ .start = low_pc,
+ .end = pc_end,
+ };
+ } else {
+ break :x null;
+ }
+ } else |err| {
+ if (err != error.MissingDebugInfo) return err;
+ break :x null;
+ }
+ };
+
+ try di.func_list.append(Func{
+ .name = fn_name,
+ .pc_range = pc_range,
+ });
+ },
+ else => {
+ continue;
+ },
}
+
+ try di.dwarf_seekable_stream.seekTo(after_die_offset);
}
- this_offset += next_offset;
+ this_unit_offset += next_offset;
}
-
- return error.MissingDebugInfo;
}
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;
while (this_unit_offset < debug_info_end) {
try di.dwarf_seekable_stream.seekTo(this_unit_offset);
@@ -2019,11 +2165,9 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void {
.is_64 = is_64,
.pc_range = pc_range,
.die = compile_unit_die,
- .index = cu_index,
});
this_unit_offset += next_offset;
- cu_index += 1;
}
}
@@ -2098,52 +2242,6 @@ fn readStringMem(ptr: *[*]const u8) []const u8 {
return result;
}
-fn readULeb128Mem(ptr: *[*]const u8) !u64 {
- var result: u64 = 0;
- var shift: usize = 0;
- var i: usize = 0;
-
- while (true) {
- const byte = ptr.*[i];
- i += 1;
-
- var operand: u64 = undefined;
-
- if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
-
- result |= operand;
-
- if ((byte & 0b10000000) == 0) {
- ptr.* += i;
- return result;
- }
-
- shift += 7;
- }
-}
-fn readILeb128Mem(ptr: *[*]const u8) !i64 {
- var result: i64 = 0;
- var shift: usize = 0;
- var i: usize = 0;
-
- while (true) {
- const byte = ptr.*[i];
- i += 1;
-
- var operand: i64 = undefined;
- if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
-
- result |= operand;
- shift += 7;
-
- if ((byte & 0b10000000) == 0) {
- if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
- ptr.* += i;
- return result;
- }
- }
-}
-
fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
const first_32_bits = try in_stream.readIntLittle(u32);
is_64.* = (first_32_bits == 0xffffffff);
@@ -2155,46 +2253,6 @@ fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool)
}
}
-fn readULeb128(in_stream: var) !u64 {
- var result: u64 = 0;
- var shift: usize = 0;
-
- while (true) {
- const byte = try in_stream.readByte();
-
- var operand: u64 = undefined;
-
- if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
-
- result |= operand;
-
- if ((byte & 0b10000000) == 0) return result;
-
- shift += 7;
- }
-}
-
-fn readILeb128(in_stream: var) !i64 {
- var result: i64 = 0;
- var shift: usize = 0;
-
- while (true) {
- const byte = try in_stream.readByte();
-
- var operand: i64 = undefined;
-
- if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
-
- result |= operand;
- shift += 7;
-
- if ((byte & 0b10000000) == 0) {
- if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
- return result;
- }
- }
-}
-
/// This should only be used in temporary test programs.
pub const global_allocator = &global_fixed_allocator.allocator;
var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]);