From 72dca05f5c60cbb492825f61b5308ff925ce9275 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 10 Apr 2020 10:08:48 +0200 Subject: [PATCH] debug: Fix parsing of DWARF info for BE machines Tested with ppc32 --- lib/std/dwarf.zig | 109 +++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 59 deletions(-) diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 3381321330..42139876bb 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -236,11 +236,11 @@ const LineNumberProgram = struct { } }; -fn readInitialLength(in_stream: var, is_64: *bool) !u64 { - const first_32_bits = try in_stream.readIntLittle(u32); +fn readUnitLength(in_stream: var, endian: builtin.Endian, is_64: *bool) !u64 { + const first_32_bits = try in_stream.readInt(u32, endian); is_64.* = (first_32_bits == 0xffffffff); if (is_64.*) { - return in_stream.readIntLittle(u64); + return in_stream.readInt(u64, endian); } else { if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; // TODO this cast should not be needed @@ -256,28 +256,36 @@ fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 return buf; } +// TODO the noasyncs here are workarounds +fn readAddress(in_stream: var, endian: builtin.Endian, is_64: bool) !u64 { + return noasync if (is_64) + try in_stream.readInt(u64, endian) + else + @as(u64, try in_stream.readInt(u32, endian)); +} + fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { const buf = try readAllocBytes(allocator, in_stream, size); return FormValue{ .Block = buf }; } // TODO the noasyncs here are workarounds -fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { - const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size); +fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, endian: builtin.Endian, size: usize) !FormValue { + const block_len = try noasync in_stream.readVarInt(usize, endian, size); return parseFormValueBlockLen(allocator, in_stream, block_len); } -fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue { +fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, endian: builtin.Endian, comptime size: i32) !FormValue { // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here. // `noasync` should be removed from all the function calls once it is fixed. return FormValue{ .Const = Constant{ .signed = signed, .payload = switch (size) { - 1 => try noasync in_stream.readIntLittle(u8), - 2 => try noasync in_stream.readIntLittle(u16), - 4 => try noasync in_stream.readIntLittle(u32), - 8 => try noasync in_stream.readIntLittle(u64), + 1 => try noasync in_stream.readInt(u8, endian), + 2 => try noasync in_stream.readInt(u16, endian), + 4 => try noasync in_stream.readInt(u32, endian), + 8 => try noasync in_stream.readInt(u64, endian), -1 => blk: { if (signed) { const x = try noasync leb.readILEB128(i64, in_stream); @@ -294,30 +302,13 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo } // TODO the noasyncs here are workarounds -fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { - return if (is_64) try noasync in_stream.readIntLittle(u64) else @as(u64, try noasync in_stream.readIntLittle(u32)); -} - -// TODO the noasyncs here are workarounds -fn parseFormValueTargetAddrSize(in_stream: var) !u64 { - if (@sizeOf(usize) == 4) { - // TODO this cast should not be needed - return @as(u64, try noasync in_stream.readIntLittle(u32)); - } else if (@sizeOf(usize) == 8) { - return noasync in_stream.readIntLittle(u64); - } else { - unreachable; - } -} - -// TODO the noasyncs here are workarounds -fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue { +fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, endian: builtin.Endian, size: i32) !FormValue { return FormValue{ .Ref = switch (size) { - 1 => try noasync in_stream.readIntLittle(u8), - 2 => try noasync in_stream.readIntLittle(u16), - 4 => try noasync in_stream.readIntLittle(u32), - 8 => try noasync in_stream.readIntLittle(u64), + 1 => try noasync in_stream.readInt(u8, endian), + 2 => try noasync in_stream.readInt(u16, endian), + 4 => try noasync in_stream.readInt(u32, endian), + 8 => try noasync in_stream.readInt(u64, endian), -1 => try noasync leb.readULEB128(u64, in_stream), else => unreachable, }, @@ -325,23 +316,23 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !Form } // TODO the noasyncs here are workarounds -fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue { +fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endian: builtin.Endian, is_64: bool) anyerror!FormValue { return switch (form_id) { - FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) }, - FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), - FORM_block2 => parseFormValueBlock(allocator, in_stream, 2), - FORM_block4 => parseFormValueBlock(allocator, in_stream, 4), + FORM_addr => FormValue{ .Address = try readAddress(in_stream, endian, @sizeOf(usize) == 8) }, + FORM_block1 => parseFormValueBlock(allocator, in_stream, endian, 1), + FORM_block2 => parseFormValueBlock(allocator, in_stream, endian, 2), + FORM_block4 => parseFormValueBlock(allocator, in_stream, endian, 4), FORM_block => x: { const block_len = try noasync leb.readULEB128(usize, in_stream); return parseFormValueBlockLen(allocator, in_stream, block_len); }, - FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1), - FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2), - FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4), - FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8), + FORM_data1 => parseFormValueConstant(allocator, in_stream, false, endian, 1), + FORM_data2 => parseFormValueConstant(allocator, in_stream, false, endian, 2), + FORM_data4 => parseFormValueConstant(allocator, in_stream, false, endian, 4), + FORM_data8 => parseFormValueConstant(allocator, in_stream, false, endian, 8), FORM_udata, FORM_sdata => { const signed = form_id == FORM_sdata; - return parseFormValueConstant(allocator, in_stream, signed, -1); + return parseFormValueConstant(allocator, in_stream, signed, endian, -1); }, FORM_exprloc => { const size = try noasync leb.readULEB128(usize, in_stream); @@ -350,25 +341,25 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 }, FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 }, FORM_flag_present => FormValue{ .Flag = true }, - FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, + FORM_sec_offset => FormValue{ .SecOffset = try readAddress(in_stream, endian, is_64) }, - FORM_ref1 => parseFormValueRef(allocator, in_stream, 1), - FORM_ref2 => parseFormValueRef(allocator, in_stream, 2), - FORM_ref4 => parseFormValueRef(allocator, in_stream, 4), - FORM_ref8 => parseFormValueRef(allocator, in_stream, 8), - FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1), + FORM_ref1 => parseFormValueRef(allocator, in_stream, endian, 1), + FORM_ref2 => parseFormValueRef(allocator, in_stream, endian, 2), + FORM_ref4 => parseFormValueRef(allocator, in_stream, endian, 4), + FORM_ref8 => parseFormValueRef(allocator, in_stream, endian, 8), + FORM_ref_udata => parseFormValueRef(allocator, in_stream, endian, -1), - FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, - FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) }, + FORM_ref_addr => FormValue{ .RefAddr = try readAddress(in_stream, endian, is_64) }, + FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readInt(u64, endian) }, FORM_string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) }, - FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, + FORM_strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) }, FORM_indirect => { const child_form_id = try noasync leb.readULEB128(u64, in_stream); - const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64)); + const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64)); var frame = try allocator.create(F); defer allocator.destroy(frame); - return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, is_64); + return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, endian, is_64); }, else => error.InvalidDebugInfo, }; @@ -423,7 +414,7 @@ pub const DwarfInfo = struct { }; var is_64: bool = undefined; - const unit_length = try readInitialLength(in, &is_64); + const unit_length = try readUnitLength(in, di.endian, &is_64); if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); @@ -530,7 +521,7 @@ pub const DwarfInfo = struct { }; var is_64: bool = undefined; - const unit_length = try readInitialLength(in, &is_64); + const unit_length = try readUnitLength(in, di.endian, &is_64); if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); @@ -610,8 +601,8 @@ pub const DwarfInfo = struct { try seekable.seekTo(ranges_offset); while (true) { - const begin_addr = try in.readIntLittle(usize); - const end_addr = try in.readIntLittle(usize); + const begin_addr = try in.readInt(usize, di.endian); + const end_addr = try in.readInt(usize, di.endian); if (begin_addr == 0 and end_addr == 0) { break; } @@ -693,7 +684,7 @@ pub const DwarfInfo = struct { for (table_entry.attrs.span()) |attr, i| { result.attrs.items[i] = Die.Attr{ .id = attr.attr_id, - .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, is_64), + .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, di.endian, is_64), }; } return result; @@ -710,7 +701,7 @@ pub const DwarfInfo = struct { try seekable.seekTo(line_info_offset); var is_64: bool = undefined; - const unit_length = try readInitialLength(in, &is_64); + const unit_length = try readUnitLength(in, di.endian, &is_64); if (unit_length == 0) { return error.MissingDebugInfo; }