mirror of
https://github.com/ziglang/zig.git
synced 2025-12-30 01:53:16 +00:00
Unify the two DWARF interpreters
* Let's consolidate the special-cased DWARF interpreter for OSX with the general purpose one * Drop the assumption that all the debug data is contained in a single contiguous slice of memory. This is a good news for freestanding targets and paves the way for supporting compressed debug sections.
This commit is contained in:
parent
518dbd30cb
commit
d5c2a20d8e
@ -7,7 +7,10 @@ usingnamespace @import("../os/bits.zig");
|
||||
|
||||
extern "c" fn __error() *c_int;
|
||||
pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int;
|
||||
pub extern "c" fn _dyld_image_count() u32;
|
||||
pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header;
|
||||
pub extern "c" fn _dyld_get_image_vmaddr_slide(image_index: u32) usize;
|
||||
pub extern "c" fn _dyld_get_image_name(image_index: u32) [*:0]const u8;
|
||||
|
||||
pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize;
|
||||
|
||||
|
||||
@ -963,59 +963,61 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
|
||||
|
||||
pub fn openElfDebugInfo(
|
||||
allocator: *mem.Allocator,
|
||||
elf_seekable_stream: *DwarfSeekableStream,
|
||||
elf_in_stream: *DwarfInStream,
|
||||
data: []u8,
|
||||
) !DwarfInfo {
|
||||
var efile = try elf.Elf.openStream(allocator, elf_seekable_stream, elf_in_stream);
|
||||
errdefer efile.close();
|
||||
var seekable_stream = io.SliceSeekableInStream.init(data);
|
||||
var efile = try elf.Elf.openStream(
|
||||
allocator,
|
||||
@ptrCast(*DwarfSeekableStream, &seekable_stream.seekable_stream),
|
||||
@ptrCast(*DwarfInStream, &seekable_stream.stream),
|
||||
);
|
||||
defer efile.close();
|
||||
|
||||
const debug_info = (try efile.findSection(".debug_info")) orelse
|
||||
return error.MissingDebugInfo;
|
||||
const debug_abbrev = (try efile.findSection(".debug_abbrev")) orelse
|
||||
return error.MissingDebugInfo;
|
||||
const debug_str = (try efile.findSection(".debug_str")) orelse
|
||||
return error.MissingDebugInfo;
|
||||
const debug_line = (try efile.findSection(".debug_line")) orelse
|
||||
return error.MissingDebugInfo;
|
||||
const opt_debug_ranges = try efile.findSection(".debug_ranges");
|
||||
|
||||
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,
|
||||
.func_list = undefined,
|
||||
.debug_info = (data[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)]),
|
||||
.debug_abbrev = (data[@intCast(usize, debug_abbrev.offset)..@intCast(usize, debug_abbrev.offset + debug_abbrev.size)]),
|
||||
.debug_str = (data[@intCast(usize, debug_str.offset)..@intCast(usize, debug_str.offset + debug_str.size)]),
|
||||
.debug_line = (data[@intCast(usize, debug_line.offset)..@intCast(usize, debug_line.offset + debug_line.size)]),
|
||||
.debug_ranges = if (opt_debug_ranges) |debug_ranges|
|
||||
data[@intCast(usize, debug_ranges.offset)..@intCast(usize, debug_ranges.offset + debug_ranges.size)]
|
||||
else
|
||||
null,
|
||||
};
|
||||
|
||||
efile.close();
|
||||
|
||||
try openDwarfDebugInfo(&di, allocator);
|
||||
return di;
|
||||
}
|
||||
|
||||
fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {
|
||||
const S = struct {
|
||||
var self_exe_file: File = undefined;
|
||||
var self_exe_mmap_seekable: io.SliceSeekableInStream = undefined;
|
||||
};
|
||||
var exe_file = try fs.openSelfExe();
|
||||
errdefer exe_file.close();
|
||||
|
||||
S.self_exe_file = try fs.openSelfExe();
|
||||
errdefer S.self_exe_file.close();
|
||||
|
||||
const self_exe_len = math.cast(usize, try S.self_exe_file.getEndPos()) catch return error.DebugInfoTooLarge;
|
||||
const self_exe_mmap_len = mem.alignForward(self_exe_len, mem.page_size);
|
||||
const self_exe_mmap = try os.mmap(
|
||||
const exe_len = math.cast(usize, try exe_file.getEndPos()) catch
|
||||
return error.DebugInfoTooLarge;
|
||||
const exe_mmap = try os.mmap(
|
||||
null,
|
||||
self_exe_mmap_len,
|
||||
exe_len,
|
||||
os.PROT_READ,
|
||||
os.MAP_SHARED,
|
||||
S.self_exe_file.handle,
|
||||
exe_file.handle,
|
||||
0,
|
||||
);
|
||||
errdefer os.munmap(self_exe_mmap);
|
||||
errdefer os.munmap(exe_mmap);
|
||||
|
||||
S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(self_exe_mmap);
|
||||
|
||||
return openElfDebugInfo(
|
||||
allocator,
|
||||
// TODO https://github.com/ziglang/zig/issues/764
|
||||
@ptrCast(*DwarfSeekableStream, &S.self_exe_mmap_seekable.seekable_stream),
|
||||
// TODO https://github.com/ziglang/zig/issues/764
|
||||
@ptrCast(*DwarfInStream, &S.self_exe_mmap_seekable.stream),
|
||||
);
|
||||
return openElfDebugInfo(allocator, exe_mmap);
|
||||
}
|
||||
|
||||
fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
|
||||
@ -1142,41 +1144,26 @@ const MachoSymbol = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const MachOFile = struct {
|
||||
bytes: []align(@alignOf(macho.mach_header_64)) const u8,
|
||||
sect_debug_info: ?*const macho.section_64,
|
||||
sect_debug_line: ?*const macho.section_64,
|
||||
};
|
||||
|
||||
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,
|
||||
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),
|
||||
func_list: ArrayList(Func),
|
||||
|
||||
pub const Section = struct {
|
||||
offset: u64,
|
||||
size: u64,
|
||||
};
|
||||
// No memory is owned by the DwarfInfo
|
||||
debug_info: []u8,
|
||||
debug_abbrev: []u8,
|
||||
debug_str: []u8,
|
||||
debug_line: []u8,
|
||||
debug_ranges: ?[]u8,
|
||||
// Filled later by the initializer
|
||||
abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,
|
||||
compile_unit_list: ArrayList(CompileUnit) = undefined,
|
||||
func_list: ArrayList(Func) = undefined,
|
||||
|
||||
pub fn allocator(self: DwarfInfo) *mem.Allocator {
|
||||
return self.abbrev_table_list.allocator;
|
||||
}
|
||||
|
||||
pub fn readString(self: *DwarfInfo) ![]u8 {
|
||||
return readStringRaw(self.allocator(), self.dwarf_in_stream);
|
||||
}
|
||||
|
||||
/// This function works in freestanding mode.
|
||||
/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
|
||||
pub fn printSourceAtAddress(
|
||||
@ -1222,35 +1209,38 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
|
||||
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;
|
||||
var s = io.SliceSeekableInStream.init(di.debug_info);
|
||||
var this_unit_offset: u64 = 0;
|
||||
|
||||
while (this_unit_offset < debug_info_end) {
|
||||
try di.dwarf_seekable_stream.seekTo(this_unit_offset);
|
||||
while (true) {
|
||||
s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
|
||||
error.EndOfStream => return,
|
||||
else => return err,
|
||||
};
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = try readInitialLength(@TypeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
|
||||
const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
|
||||
if (unit_length == 0) return;
|
||||
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
|
||||
|
||||
const version = try di.dwarf_in_stream.readInt(u16, di.endian);
|
||||
const version = try s.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 debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
|
||||
|
||||
const address_size = try di.dwarf_in_stream.readByte();
|
||||
const address_size = try s.stream.readByte();
|
||||
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
||||
|
||||
const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
|
||||
const compile_unit_pos = try s.seekable_stream.getPos();
|
||||
const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
|
||||
|
||||
try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
|
||||
try s.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 di.parseDie(abbrev_table, is_64)) orelse continue;
|
||||
const after_die_offset = try di.dwarf_seekable_stream.getPos();
|
||||
while ((try s.seekable_stream.getPos()) < next_unit_pos) {
|
||||
const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue;
|
||||
const after_die_offset = try s.seekable_stream.getPos();
|
||||
|
||||
switch (die_obj.tag_id) {
|
||||
DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
|
||||
@ -1266,14 +1256,14 @@ pub const DwarfInfo = struct {
|
||||
// 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 di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
|
||||
try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
|
||||
this_die_obj = (try di.parseDie(&s.stream, 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 di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
|
||||
try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
|
||||
this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
|
||||
} else {
|
||||
break :x null;
|
||||
}
|
||||
@ -1311,12 +1301,10 @@ pub const DwarfInfo = struct {
|
||||
.pc_range = pc_range,
|
||||
});
|
||||
},
|
||||
else => {
|
||||
continue;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
try di.dwarf_seekable_stream.seekTo(after_die_offset);
|
||||
try s.seekable_stream.seekTo(after_die_offset);
|
||||
}
|
||||
|
||||
this_unit_offset += next_offset;
|
||||
@ -1324,32 +1312,35 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
|
||||
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 s = io.SliceSeekableInStream.init(di.debug_info);
|
||||
var this_unit_offset: u64 = 0;
|
||||
|
||||
while (this_unit_offset < debug_info_end) {
|
||||
try di.dwarf_seekable_stream.seekTo(this_unit_offset);
|
||||
while (true) {
|
||||
s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
|
||||
error.EndOfStream => return,
|
||||
else => return err,
|
||||
};
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = try readInitialLength(@TypeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
|
||||
const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
|
||||
if (unit_length == 0) return;
|
||||
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
|
||||
|
||||
const version = try di.dwarf_in_stream.readInt(u16, di.endian);
|
||||
const version = try s.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 debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
|
||||
|
||||
const address_size = try di.dwarf_in_stream.readByte();
|
||||
const address_size = try s.stream.readByte();
|
||||
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
||||
|
||||
const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
|
||||
const compile_unit_pos = try s.seekable_stream.getPos();
|
||||
const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
|
||||
|
||||
try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
|
||||
try s.seekable_stream.seekTo(compile_unit_pos);
|
||||
|
||||
const compile_unit_die = try di.allocator().create(Die);
|
||||
compile_unit_die.* = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
|
||||
compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
|
||||
|
||||
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
|
||||
|
||||
@ -1395,15 +1386,18 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
if (di.debug_ranges) |debug_ranges| {
|
||||
if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
|
||||
var s = io.SliceSeekableInStream.init(debug_ranges);
|
||||
|
||||
// All the addresses in the list are relative to the value
|
||||
// specified by DW_AT_low_pc or to some other value encoded
|
||||
// in the list itself
|
||||
var base_address = try compile_unit.die.getAttrAddr(DW.AT_low_pc);
|
||||
|
||||
try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
|
||||
try s.seekable_stream.seekTo(ranges_offset);
|
||||
|
||||
while (true) {
|
||||
const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
|
||||
const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
|
||||
const begin_addr = try s.stream.readIntLittle(usize);
|
||||
const end_addr = try s.stream.readIntLittle(usize);
|
||||
if (begin_addr == 0 and end_addr == 0) {
|
||||
break;
|
||||
}
|
||||
@ -1435,30 +1429,33 @@ pub const DwarfInfo = struct {
|
||||
return &header.table;
|
||||
}
|
||||
}
|
||||
try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
|
||||
try di.abbrev_table_list.append(AbbrevTableHeader{
|
||||
.offset = abbrev_offset,
|
||||
.table = try di.parseAbbrevTable(),
|
||||
.table = try di.parseAbbrevTable(abbrev_offset),
|
||||
});
|
||||
return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
|
||||
}
|
||||
|
||||
fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
|
||||
fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
|
||||
var s = io.SliceSeekableInStream.init(di.debug_abbrev);
|
||||
|
||||
try s.seekable_stream.seekTo(offset);
|
||||
var result = AbbrevTable.init(di.allocator());
|
||||
errdefer result.deinit();
|
||||
while (true) {
|
||||
const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
|
||||
const abbrev_code = try leb.readULEB128(u64, &s.stream);
|
||||
if (abbrev_code == 0) return result;
|
||||
try result.append(AbbrevTableEntry{
|
||||
.abbrev_code = abbrev_code,
|
||||
.tag_id = try leb.readULEB128(u64, di.dwarf_in_stream),
|
||||
.has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
|
||||
.tag_id = try leb.readULEB128(u64, &s.stream),
|
||||
.has_children = (try s.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 leb.readULEB128(u64, di.dwarf_in_stream);
|
||||
const form_id = try leb.readULEB128(u64, di.dwarf_in_stream);
|
||||
const attr_id = try leb.readULEB128(u64, &s.stream);
|
||||
const form_id = try leb.readULEB128(u64, &s.stream);
|
||||
if (attr_id == 0 and form_id == 0) break;
|
||||
try attrs.append(AbbrevAttr{
|
||||
.attr_id = attr_id,
|
||||
@ -1468,8 +1465,8 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
|
||||
const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
|
||||
fn parseDie(di: *DwarfInfo, in_stream: var, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
|
||||
const abbrev_code = try leb.readULEB128(u64, in_stream);
|
||||
if (abbrev_code == 0) return null;
|
||||
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
|
||||
|
||||
@ -1482,64 +1479,63 @@ pub const DwarfInfo = struct {
|
||||
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),
|
||||
.value = try parseFormValue(di.allocator(), in_stream, attr.form_id, is_64),
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
|
||||
var s = io.SliceSeekableInStream.init(di.debug_line);
|
||||
|
||||
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);
|
||||
|
||||
assert(line_info_offset < di.debug_line.size);
|
||||
|
||||
const this_unit_offset = di.debug_line.offset + line_info_offset;
|
||||
try di.dwarf_seekable_stream.seekTo(this_unit_offset);
|
||||
try s.seekable_stream.seekTo(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);
|
||||
const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
|
||||
if (unit_length == 0) {
|
||||
return error.MissingDebugInfo;
|
||||
}
|
||||
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
|
||||
|
||||
const version = try di.dwarf_in_stream.readInt(u16, di.endian);
|
||||
const version = try s.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 prologue_length = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
|
||||
const prog_start_offset = (try s.seekable_stream.getPos()) + prologue_length;
|
||||
|
||||
const minimum_instruction_length = try di.dwarf_in_stream.readByte();
|
||||
const minimum_instruction_length = try s.stream.readByte();
|
||||
if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
|
||||
|
||||
if (version >= 4) {
|
||||
// maximum_operations_per_instruction
|
||||
_ = try di.dwarf_in_stream.readByte();
|
||||
_ = try s.stream.readByte();
|
||||
}
|
||||
|
||||
const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
|
||||
const line_base = try di.dwarf_in_stream.readByteSigned();
|
||||
const default_is_stmt = (try s.stream.readByte()) != 0;
|
||||
const line_base = try s.stream.readByteSigned();
|
||||
|
||||
const line_range = try di.dwarf_in_stream.readByte();
|
||||
const line_range = try s.stream.readByte();
|
||||
if (line_range == 0) return error.InvalidDebugInfo;
|
||||
|
||||
const opcode_base = try di.dwarf_in_stream.readByte();
|
||||
const opcode_base = try s.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 di.dwarf_in_stream.readByte();
|
||||
standard_opcode_lengths[i] = try s.stream.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
var include_directories = ArrayList([]u8).init(di.allocator());
|
||||
try include_directories.append(compile_unit_cwd);
|
||||
while (true) {
|
||||
const dir = try di.readString();
|
||||
const dir = try readStringRaw(di.allocator(), &s.stream);
|
||||
if (dir.len == 0) break;
|
||||
try include_directories.append(dir);
|
||||
}
|
||||
@ -1548,11 +1544,11 @@ pub const DwarfInfo = struct {
|
||||
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
|
||||
|
||||
while (true) {
|
||||
const file_name = try di.readString();
|
||||
const file_name = try readStringRaw(di.allocator(), &s.stream);
|
||||
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);
|
||||
const dir_index = try leb.readULEB128(usize, &s.stream);
|
||||
const mtime = try leb.readULEB128(usize, &s.stream);
|
||||
const len_bytes = try leb.readULEB128(usize, &s.stream);
|
||||
try file_entries.append(FileEntry{
|
||||
.file_name = file_name,
|
||||
.dir_index = dir_index,
|
||||
@ -1561,17 +1557,17 @@ pub const DwarfInfo = struct {
|
||||
});
|
||||
}
|
||||
|
||||
try di.dwarf_seekable_stream.seekTo(prog_start_offset);
|
||||
try s.seekable_stream.seekTo(prog_start_offset);
|
||||
|
||||
const next_unit_pos = this_unit_offset + next_offset;
|
||||
const next_unit_pos = line_info_offset + next_offset;
|
||||
|
||||
while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) {
|
||||
const opcode = try di.dwarf_in_stream.readByte();
|
||||
while ((try s.seekable_stream.getPos()) < next_unit_pos) {
|
||||
const opcode = try s.stream.readByte();
|
||||
|
||||
if (opcode == DW.LNS_extended_op) {
|
||||
const op_size = try leb.readULEB128(u64, di.dwarf_in_stream);
|
||||
const op_size = try leb.readULEB128(u64, &s.stream);
|
||||
if (op_size < 1) return error.InvalidDebugInfo;
|
||||
var sub_op = try di.dwarf_in_stream.readByte();
|
||||
var sub_op = try s.stream.readByte();
|
||||
switch (sub_op) {
|
||||
DW.LNE_end_sequence => {
|
||||
prog.end_sequence = true;
|
||||
@ -1579,14 +1575,14 @@ pub const DwarfInfo = struct {
|
||||
prog.reset();
|
||||
},
|
||||
DW.LNE_set_address => {
|
||||
const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
|
||||
const addr = try s.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);
|
||||
const file_name = try readStringRaw(di.allocator(), &s.stream);
|
||||
const dir_index = try leb.readULEB128(usize, &s.stream);
|
||||
const mtime = try leb.readULEB128(usize, &s.stream);
|
||||
const len_bytes = try leb.readULEB128(usize, &s.stream);
|
||||
try file_entries.append(FileEntry{
|
||||
.file_name = file_name,
|
||||
.dir_index = dir_index,
|
||||
@ -1596,7 +1592,7 @@ pub const DwarfInfo = struct {
|
||||
},
|
||||
else => {
|
||||
const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
|
||||
try di.dwarf_seekable_stream.seekBy(fwd_amt);
|
||||
try s.seekable_stream.seekBy(fwd_amt);
|
||||
},
|
||||
}
|
||||
} else if (opcode >= opcode_base) {
|
||||
@ -1615,19 +1611,19 @@ pub const DwarfInfo = struct {
|
||||
prog.basic_block = false;
|
||||
},
|
||||
DW.LNS_advance_pc => {
|
||||
const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
|
||||
const arg = try leb.readULEB128(usize, &s.stream);
|
||||
prog.address += arg * minimum_instruction_length;
|
||||
},
|
||||
DW.LNS_advance_line => {
|
||||
const arg = try leb.readILEB128(i64, di.dwarf_in_stream);
|
||||
const arg = try leb.readILEB128(i64, &s.stream);
|
||||
prog.line += arg;
|
||||
},
|
||||
DW.LNS_set_file => {
|
||||
const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
|
||||
const arg = try leb.readULEB128(usize, &s.stream);
|
||||
prog.file = arg;
|
||||
},
|
||||
DW.LNS_set_column => {
|
||||
const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
|
||||
const arg = try leb.readULEB128(u64, &s.stream);
|
||||
prog.column = arg;
|
||||
},
|
||||
DW.LNS_negate_stmt => {
|
||||
@ -1641,14 +1637,14 @@ pub const DwarfInfo = struct {
|
||||
prog.address += inc_addr;
|
||||
},
|
||||
DW.LNS_fixed_advance_pc => {
|
||||
const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
|
||||
const arg = try s.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.seekBy(len_bytes);
|
||||
try s.seekable_stream.seekBy(len_bytes);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1658,9 +1654,17 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
|
||||
fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
|
||||
const pos = di.debug_str.offset + offset;
|
||||
try di.dwarf_seekable_stream.seekTo(pos);
|
||||
return di.readString();
|
||||
if (offset > di.debug_str.len)
|
||||
return error.InvalidDebugInfo;
|
||||
const casted_offset = math.cast(usize, offset) catch
|
||||
return error.InvalidDebugInfo;
|
||||
|
||||
// Valid strings always have a terminating zero byte
|
||||
if (mem.indexOfScalarPos(u8, di.debug_str, casted_offset, 0)) |last| {
|
||||
return di.debug_str[casted_offset..last];
|
||||
}
|
||||
|
||||
return error.InvalidDebugInfo;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1672,7 +1676,7 @@ pub const DebugInfo = switch (builtin.os) {
|
||||
|
||||
const OFileTable = std.HashMap(
|
||||
*macho.nlist_64,
|
||||
MachOFile,
|
||||
DwarfInfo,
|
||||
std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
|
||||
std.hash_map.getTrivialEqlFn(*macho.nlist_64),
|
||||
);
|
||||
@ -2066,24 +2070,32 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
|
||||
return null;
|
||||
}
|
||||
|
||||
fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {
|
||||
fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {
|
||||
const ofile = symbol.ofile orelse return error.MissingDebugInfo;
|
||||
const gop = try di.ofiles.getOrPut(ofile);
|
||||
const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: {
|
||||
const dwarf_info = if (gop.found_existing) &gop.kv.value else blk: {
|
||||
errdefer _ = di.ofiles.remove(ofile);
|
||||
const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));
|
||||
|
||||
gop.kv.value = MachOFile{
|
||||
.bytes = try std.fs.cwd().readFileAllocAligned(
|
||||
di.ofiles.allocator,
|
||||
ofile_path,
|
||||
maxInt(usize),
|
||||
@alignOf(macho.mach_header_64),
|
||||
),
|
||||
.sect_debug_info = null,
|
||||
.sect_debug_line = null,
|
||||
};
|
||||
const hdr = @ptrCast(*const macho.mach_header_64, gop.kv.value.bytes.ptr);
|
||||
var exe_file = try std.fs.openFileAbsoluteC(ofile_path, .{});
|
||||
errdefer exe_file.close();
|
||||
|
||||
const exe_len = math.cast(usize, try exe_file.getEndPos()) catch
|
||||
return error.DebugInfoTooLarge;
|
||||
const exe_mmap = try os.mmap(
|
||||
null,
|
||||
exe_len,
|
||||
os.PROT_READ,
|
||||
os.MAP_SHARED,
|
||||
exe_file.handle,
|
||||
0,
|
||||
);
|
||||
errdefer os.munmap(exe_mmap);
|
||||
|
||||
const hdr = @ptrCast(
|
||||
*const macho.mach_header_64,
|
||||
@alignCast(@alignOf(macho.mach_header_64), exe_mmap.ptr),
|
||||
);
|
||||
if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo;
|
||||
|
||||
const hdr_base = @ptrCast([*]const u8, hdr);
|
||||
@ -2092,181 +2104,75 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
|
||||
const segcmd = while (ncmd != 0) : (ncmd -= 1) {
|
||||
const lc = @ptrCast(*const std.macho.load_command, ptr);
|
||||
switch (lc.cmd) {
|
||||
std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr)),
|
||||
std.macho.LC_SEGMENT_64 => {
|
||||
break @ptrCast(
|
||||
*const std.macho.segment_command_64,
|
||||
@alignCast(@alignOf(std.macho.segment_command_64), ptr),
|
||||
);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
|
||||
} else {
|
||||
return error.MissingDebugInfo;
|
||||
};
|
||||
|
||||
var opt_debug_line: ?*const macho.section_64 = null;
|
||||
var opt_debug_info: ?*const macho.section_64 = null;
|
||||
var opt_debug_abbrev: ?*const macho.section_64 = null;
|
||||
var opt_debug_str: ?*const macho.section_64 = null;
|
||||
var opt_debug_ranges: ?*const macho.section_64 = null;
|
||||
|
||||
const sections = @ptrCast([*]const macho.section_64, @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects];
|
||||
for (sections) |*sect| {
|
||||
if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and
|
||||
(sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG)
|
||||
{
|
||||
const sect_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, §.sectname));
|
||||
if (mem.eql(u8, sect_name, "__debug_line")) {
|
||||
gop.kv.value.sect_debug_line = sect;
|
||||
} else if (mem.eql(u8, sect_name, "__debug_info")) {
|
||||
gop.kv.value.sect_debug_info = sect;
|
||||
}
|
||||
// The section name may not exceed 16 chars and a trailing null may
|
||||
// not be present
|
||||
const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|
|
||||
sect.sectname[0..last]
|
||||
else
|
||||
sect.sectname[0..];
|
||||
|
||||
if (mem.eql(u8, name, "__debug_line")) {
|
||||
opt_debug_line = sect;
|
||||
} else if (mem.eql(u8, name, "__debug_info")) {
|
||||
opt_debug_info = sect;
|
||||
} else if (mem.eql(u8, name, "__debug_abbrev")) {
|
||||
opt_debug_abbrev = sect;
|
||||
} else if (mem.eql(u8, name, "__debug_str")) {
|
||||
opt_debug_str = sect;
|
||||
} else if (mem.eql(u8, name, "__debug_ranges")) {
|
||||
opt_debug_ranges = sect;
|
||||
}
|
||||
}
|
||||
|
||||
var debug_line = opt_debug_line orelse
|
||||
return error.MissingDebugInfo;
|
||||
var debug_info = opt_debug_info orelse
|
||||
return error.MissingDebugInfo;
|
||||
var debug_str = opt_debug_str orelse
|
||||
return error.MissingDebugInfo;
|
||||
var debug_abbrev = opt_debug_abbrev orelse
|
||||
return error.MissingDebugInfo;
|
||||
|
||||
gop.kv.value = DwarfInfo{
|
||||
.endian = .Little,
|
||||
.debug_info = exe_mmap[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)],
|
||||
.debug_abbrev = exe_mmap[@intCast(usize, debug_abbrev.offset)..@intCast(usize, debug_abbrev.offset + debug_abbrev.size)],
|
||||
.debug_str = exe_mmap[@intCast(usize, debug_str.offset)..@intCast(usize, debug_str.offset + debug_str.size)],
|
||||
.debug_line = exe_mmap[@intCast(usize, debug_line.offset)..@intCast(usize, debug_line.offset + debug_line.size)],
|
||||
.debug_ranges = if (opt_debug_ranges) |debug_ranges|
|
||||
exe_mmap[@intCast(usize, debug_ranges.offset)..@intCast(usize, debug_ranges.offset + debug_ranges.size)]
|
||||
else
|
||||
null,
|
||||
};
|
||||
try openDwarfDebugInfo(&gop.kv.value, di.allocator());
|
||||
|
||||
break :blk &gop.kv.value;
|
||||
};
|
||||
|
||||
const sect_debug_line = mach_o_file.sect_debug_line orelse return error.MissingDebugInfo;
|
||||
var ptr = mach_o_file.bytes.ptr + sect_debug_line.offset;
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = try readInitialLengthMem(&ptr, &is_64);
|
||||
if (unit_length == 0) return error.MissingDebugInfo;
|
||||
|
||||
const version = readIntMem(&ptr, u16, builtin.Endian.Little);
|
||||
// TODO support 3 and 5
|
||||
if (version != 2 and version != 4) return error.InvalidDebugInfo;
|
||||
|
||||
const prologue_length = if (is_64)
|
||||
readIntMem(&ptr, u64, builtin.Endian.Little)
|
||||
else
|
||||
readIntMem(&ptr, u32, builtin.Endian.Little);
|
||||
const prog_start = ptr + prologue_length;
|
||||
|
||||
const minimum_instruction_length = readByteMem(&ptr);
|
||||
if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
|
||||
|
||||
if (version >= 4) {
|
||||
// maximum_operations_per_instruction
|
||||
ptr += 1;
|
||||
}
|
||||
|
||||
const default_is_stmt = readByteMem(&ptr) != 0;
|
||||
const line_base = readByteSignedMem(&ptr);
|
||||
|
||||
const line_range = readByteMem(&ptr);
|
||||
if (line_range == 0) return error.InvalidDebugInfo;
|
||||
|
||||
const opcode_base = readByteMem(&ptr);
|
||||
|
||||
const standard_opcode_lengths = ptr[0 .. opcode_base - 1];
|
||||
ptr += opcode_base - 1;
|
||||
|
||||
var include_directories = ArrayList([]const u8).init(di.allocator());
|
||||
try include_directories.append("");
|
||||
while (true) {
|
||||
const dir = readStringMem(&ptr);
|
||||
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);
|
||||
|
||||
while (true) {
|
||||
const file_name = readStringMem(&ptr);
|
||||
if (file_name.len == 0) break;
|
||||
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,
|
||||
.mtime = mtime,
|
||||
.len_bytes = len_bytes,
|
||||
});
|
||||
}
|
||||
|
||||
ptr = prog_start;
|
||||
while (true) {
|
||||
const opcode = readByteMem(&ptr);
|
||||
|
||||
if (opcode == DW.LNS_extended_op) {
|
||||
const op_size = try leb.readULEB128Mem(u64, &ptr);
|
||||
if (op_size < 1) return error.InvalidDebugInfo;
|
||||
var sub_op = readByteMem(&ptr);
|
||||
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 = readIntMem(&ptr, usize, builtin.Endian.Little);
|
||||
prog.address = symbol.reloc + addr;
|
||||
},
|
||||
DW.LNE_define_file => {
|
||||
const file_name = readStringMem(&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,
|
||||
.mtime = mtime,
|
||||
.len_bytes = len_bytes,
|
||||
});
|
||||
},
|
||||
else => {
|
||||
ptr += op_size - 1;
|
||||
},
|
||||
}
|
||||
} 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 = @as(i32, line_base) + @as(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.readULEB128Mem(usize, &ptr);
|
||||
prog.address += arg * minimum_instruction_length;
|
||||
},
|
||||
DW.LNS_advance_line => {
|
||||
const arg = try leb.readILEB128Mem(i64, &ptr);
|
||||
prog.line += arg;
|
||||
},
|
||||
DW.LNS_set_file => {
|
||||
const arg = try leb.readULEB128Mem(usize, &ptr);
|
||||
prog.file = arg;
|
||||
},
|
||||
DW.LNS_set_column => {
|
||||
const arg = try leb.readULEB128Mem(u64, &ptr);
|
||||
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 = readIntMem(&ptr, u16, builtin.Endian.Little);
|
||||
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];
|
||||
ptr += len_bytes;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error.MissingDebugInfo;
|
||||
const o_file_address = address - symbol.reloc;
|
||||
const compile_unit = try dwarf_info.findCompileUnit(o_file_address);
|
||||
return dwarf_info.getLineNumberInfo(compile_unit.*, o_file_address);
|
||||
}
|
||||
|
||||
const Func = struct {
|
||||
@ -2274,47 +2180,6 @@ const Func = struct {
|
||||
name: ?[]u8,
|
||||
};
|
||||
|
||||
fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
|
||||
// TODO https://github.com/ziglang/zig/issues/863
|
||||
const size = (T.bit_count + 7) / 8;
|
||||
const result = mem.readIntSlice(T, ptr.*[0..size], endian);
|
||||
ptr.* += size;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn readByteMem(ptr: *[*]const u8) u8 {
|
||||
const result = ptr.*[0];
|
||||
ptr.* += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn readByteSignedMem(ptr: *[*]const u8) i8 {
|
||||
return @bitCast(i8, readByteMem(ptr));
|
||||
}
|
||||
|
||||
fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
|
||||
// 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.readIntSliceLittle(u64, ptr.*[0..8]);
|
||||
ptr.* += 8;
|
||||
return result;
|
||||
} else {
|
||||
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
|
||||
ptr.* += 4;
|
||||
// TODO this cast should not be needed
|
||||
return @as(u64, first_32_bits);
|
||||
}
|
||||
}
|
||||
|
||||
fn readStringMem(ptr: *[*]const u8) [:0]const u8 {
|
||||
const result = mem.toSliceConst(u8, @ptrCast([*:0]const u8, ptr.*));
|
||||
ptr.* += result.len + 1;
|
||||
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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user