debug: Fix parsing of DWARF info for BE machines
Tested with ppc32
This commit is contained in:
parent
1b1cbd9358
commit
72dca05f5c
@ -236,11 +236,11 @@ const LineNumberProgram = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn readInitialLength(in_stream: var, is_64: *bool) !u64 {
|
fn readUnitLength(in_stream: var, endian: builtin.Endian, is_64: *bool) !u64 {
|
||||||
const first_32_bits = try in_stream.readIntLittle(u32);
|
const first_32_bits = try in_stream.readInt(u32, endian);
|
||||||
is_64.* = (first_32_bits == 0xffffffff);
|
is_64.* = (first_32_bits == 0xffffffff);
|
||||||
if (is_64.*) {
|
if (is_64.*) {
|
||||||
return in_stream.readIntLittle(u64);
|
return in_stream.readInt(u64, endian);
|
||||||
} else {
|
} else {
|
||||||
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
|
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
|
||||||
// TODO this cast should not be needed
|
// TODO this cast should not be needed
|
||||||
@ -256,28 +256,36 @@ fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8
|
|||||||
return buf;
|
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 {
|
fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
|
||||||
const buf = try readAllocBytes(allocator, in_stream, size);
|
const buf = try readAllocBytes(allocator, in_stream, size);
|
||||||
return FormValue{ .Block = buf };
|
return FormValue{ .Block = buf };
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO the noasyncs here are workarounds
|
// TODO the noasyncs here are workarounds
|
||||||
fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
|
fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, endian: builtin.Endian, size: usize) !FormValue {
|
||||||
const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size);
|
const block_len = try noasync in_stream.readVarInt(usize, endian, size);
|
||||||
return parseFormValueBlockLen(allocator, in_stream, block_len);
|
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.
|
// 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.
|
// `noasync` should be removed from all the function calls once it is fixed.
|
||||||
return FormValue{
|
return FormValue{
|
||||||
.Const = Constant{
|
.Const = Constant{
|
||||||
.signed = signed,
|
.signed = signed,
|
||||||
.payload = switch (size) {
|
.payload = switch (size) {
|
||||||
1 => try noasync in_stream.readIntLittle(u8),
|
1 => try noasync in_stream.readInt(u8, endian),
|
||||||
2 => try noasync in_stream.readIntLittle(u16),
|
2 => try noasync in_stream.readInt(u16, endian),
|
||||||
4 => try noasync in_stream.readIntLittle(u32),
|
4 => try noasync in_stream.readInt(u32, endian),
|
||||||
8 => try noasync in_stream.readIntLittle(u64),
|
8 => try noasync in_stream.readInt(u64, endian),
|
||||||
-1 => blk: {
|
-1 => blk: {
|
||||||
if (signed) {
|
if (signed) {
|
||||||
const x = try noasync leb.readILEB128(i64, in_stream);
|
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
|
// TODO the noasyncs here are workarounds
|
||||||
fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
|
fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, endian: builtin.Endian, size: i32) !FormValue {
|
||||||
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 {
|
|
||||||
return FormValue{
|
return FormValue{
|
||||||
.Ref = switch (size) {
|
.Ref = switch (size) {
|
||||||
1 => try noasync in_stream.readIntLittle(u8),
|
1 => try noasync in_stream.readInt(u8, endian),
|
||||||
2 => try noasync in_stream.readIntLittle(u16),
|
2 => try noasync in_stream.readInt(u16, endian),
|
||||||
4 => try noasync in_stream.readIntLittle(u32),
|
4 => try noasync in_stream.readInt(u32, endian),
|
||||||
8 => try noasync in_stream.readIntLittle(u64),
|
8 => try noasync in_stream.readInt(u64, endian),
|
||||||
-1 => try noasync leb.readULEB128(u64, in_stream),
|
-1 => try noasync leb.readULEB128(u64, in_stream),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
@ -325,23 +316,23 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !Form
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO the noasyncs here are workarounds
|
// 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) {
|
return switch (form_id) {
|
||||||
FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
|
FORM_addr => FormValue{ .Address = try readAddress(in_stream, endian, @sizeOf(usize) == 8) },
|
||||||
FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
|
FORM_block1 => parseFormValueBlock(allocator, in_stream, endian, 1),
|
||||||
FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
|
FORM_block2 => parseFormValueBlock(allocator, in_stream, endian, 2),
|
||||||
FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
|
FORM_block4 => parseFormValueBlock(allocator, in_stream, endian, 4),
|
||||||
FORM_block => x: {
|
FORM_block => x: {
|
||||||
const block_len = try noasync leb.readULEB128(usize, in_stream);
|
const block_len = try noasync leb.readULEB128(usize, in_stream);
|
||||||
return parseFormValueBlockLen(allocator, in_stream, block_len);
|
return parseFormValueBlockLen(allocator, in_stream, block_len);
|
||||||
},
|
},
|
||||||
FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
|
FORM_data1 => parseFormValueConstant(allocator, in_stream, false, endian, 1),
|
||||||
FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
|
FORM_data2 => parseFormValueConstant(allocator, in_stream, false, endian, 2),
|
||||||
FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
|
FORM_data4 => parseFormValueConstant(allocator, in_stream, false, endian, 4),
|
||||||
FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
|
FORM_data8 => parseFormValueConstant(allocator, in_stream, false, endian, 8),
|
||||||
FORM_udata, FORM_sdata => {
|
FORM_udata, FORM_sdata => {
|
||||||
const signed = form_id == 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 => {
|
FORM_exprloc => {
|
||||||
const size = try noasync leb.readULEB128(usize, in_stream);
|
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 => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 },
|
||||||
FORM_flag_present => FormValue{ .Flag = true },
|
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_ref1 => parseFormValueRef(allocator, in_stream, endian, 1),
|
||||||
FORM_ref2 => parseFormValueRef(allocator, in_stream, 2),
|
FORM_ref2 => parseFormValueRef(allocator, in_stream, endian, 2),
|
||||||
FORM_ref4 => parseFormValueRef(allocator, in_stream, 4),
|
FORM_ref4 => parseFormValueRef(allocator, in_stream, endian, 4),
|
||||||
FORM_ref8 => parseFormValueRef(allocator, in_stream, 8),
|
FORM_ref8 => parseFormValueRef(allocator, in_stream, endian, 8),
|
||||||
FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
|
FORM_ref_udata => parseFormValueRef(allocator, in_stream, endian, -1),
|
||||||
|
|
||||||
FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
FORM_ref_addr => FormValue{ .RefAddr = try readAddress(in_stream, endian, is_64) },
|
||||||
FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) },
|
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_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 => {
|
FORM_indirect => {
|
||||||
const child_form_id = try noasync leb.readULEB128(u64, in_stream);
|
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);
|
var frame = try allocator.create(F);
|
||||||
defer allocator.destroy(frame);
|
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,
|
else => error.InvalidDebugInfo,
|
||||||
};
|
};
|
||||||
@ -423,7 +414,7 @@ pub const DwarfInfo = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var is_64: bool = undefined;
|
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;
|
if (unit_length == 0) return;
|
||||||
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
|
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;
|
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;
|
if (unit_length == 0) return;
|
||||||
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
|
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);
|
try seekable.seekTo(ranges_offset);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const begin_addr = try in.readIntLittle(usize);
|
const begin_addr = try in.readInt(usize, di.endian);
|
||||||
const end_addr = try in.readIntLittle(usize);
|
const end_addr = try in.readInt(usize, di.endian);
|
||||||
if (begin_addr == 0 and end_addr == 0) {
|
if (begin_addr == 0 and end_addr == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -693,7 +684,7 @@ pub const DwarfInfo = struct {
|
|||||||
for (table_entry.attrs.span()) |attr, i| {
|
for (table_entry.attrs.span()) |attr, i| {
|
||||||
result.attrs.items[i] = Die.Attr{
|
result.attrs.items[i] = Die.Attr{
|
||||||
.id = attr.attr_id,
|
.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;
|
return result;
|
||||||
@ -710,7 +701,7 @@ pub const DwarfInfo = struct {
|
|||||||
try seekable.seekTo(line_info_offset);
|
try seekable.seekTo(line_info_offset);
|
||||||
|
|
||||||
var is_64: bool = undefined;
|
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) {
|
if (unit_length == 0) {
|
||||||
return error.MissingDebugInfo;
|
return error.MissingDebugInfo;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user