Dwarf: fix and test string format

This commit is contained in:
Jacob Young 2024-08-26 23:37:03 -04:00
parent 93cb44c805
commit 8c3f6c72c0
8 changed files with 193 additions and 64 deletions

View File

@ -64,7 +64,7 @@ stage3-debug/bin/zig build \
stage3-debug/bin/zig build test docs \
--maxrss 21000000000 \
-Dlldb=$HOME/deps/lldb-zig/Debug-62538077d/bin/lldb \
-Dlldb=$HOME/deps/lldb-zig/Debug-70b8227f1/bin/lldb \
-fqemu \
-fwasmtime \
-Dstatic-llvm \

View File

@ -64,7 +64,7 @@ stage3-release/bin/zig build \
stage3-release/bin/zig build test docs \
--maxrss 21000000000 \
-Dlldb=$HOME/deps/lldb-zig/Release-62538077d/bin/lldb \
-Dlldb=$HOME/deps/lldb-zig/Release-70b8227f1/bin/lldb \
-fqemu \
-fwasmtime \
-Dstatic-llvm \

View File

@ -192,11 +192,12 @@ pub fn toBigIntAdvanced(
zcu: *Zcu,
tid: strat.Tid(),
) Zcu.CompileError!BigIntConst {
const ip = &zcu.intern_pool;
return switch (val.toIntern()) {
.bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),
.bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),
.null_value => BigIntMutable.init(&space.limbs, 0).toConst(),
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
else => switch (ip.indexToKey(val.toIntern())) {
.int => |int| switch (int.storage) {
.u64, .i64, .big_int => int.storage.toBigInt(space),
.lazy_align, .lazy_size => |ty| {
@ -214,6 +215,7 @@ pub fn toBigIntAdvanced(
&space.limbs,
(try val.getUnsignedIntInner(strat, zcu, tid)).?,
).toConst(),
.err => |err| BigIntMutable.init(&space.limbs, ip.getErrorValueIfExists(err.name).?).toConst(),
else => unreachable,
},
};
@ -326,15 +328,11 @@ pub fn toBool(val: Value) bool {
};
}
fn ptrHasIntAddr(val: Value, zcu: *Zcu) bool {
return zcu.intern_pool.getBackingAddrTag(val.toIntern()).? == .int;
}
/// Write a Value's contents to `buffer`.
///
/// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past
/// the end of the value in memory.
pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) error{
pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
ReinterpretDeclRef,
IllDefinedMemoryLayout,
Unimplemented,
@ -343,19 +341,25 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
const zcu = pt.zcu;
const target = zcu.getTarget();
const endian = target.cpu.arch.endian();
const ip = &zcu.intern_pool;
const ty = val.typeOf(zcu);
if (val.isUndef(zcu)) {
const size: usize = @intCast(ty.abiSize(zcu));
@memset(buffer[0..size], 0xaa);
return;
}
const ip = &zcu.intern_pool;
switch (ty.zigTypeTag(zcu)) {
.Void => {},
.Bool => {
buffer[0] = @intFromBool(val.toBool());
},
.Int, .Enum => {
const int_info = ty.intInfo(zcu);
.Int, .Enum, .ErrorSet, .Pointer => |tag| {
const int_ty = if (tag == .Pointer) int_ty: {
if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout;
if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
break :int_ty Type.usize;
} else ty;
const int_info = int_ty.intInfo(zcu);
const bits = int_info.bits;
const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);
@ -379,7 +383,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
var buf_off: usize = 0;
while (elem_i < len) : (elem_i += 1) {
const elem_val = try val.elemValue(pt, elem_i);
try elem_val.writeToMemory(elem_ty, pt, buffer[buf_off..]);
try elem_val.writeToMemory(pt, buffer[buf_off..]);
buf_off += elem_size;
}
},
@ -403,8 +407,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
.elems => |elems| elems[field_index],
.repeated_elem => |elem| elem,
});
const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
try writeToMemory(field_val, field_ty, pt, buffer[off..]);
try writeToMemory(field_val, pt, buffer[off..]);
},
.@"packed" => {
const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8;
@ -412,22 +415,6 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
},
}
},
.ErrorSet => {
const bits = zcu.errorSetBits();
const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);
const name = switch (ip.indexToKey(val.toIntern())) {
.err => |err| err.name,
.error_union => |error_union| error_union.val.err_name,
else => unreachable,
};
var bigint_buffer: BigIntSpace = undefined;
const bigint = BigIntMutable.init(
&bigint_buffer.limbs,
ip.getErrorValueIfExists(name).?,
).toConst();
bigint.writeTwosComplement(buffer[0..byte_count], endian);
},
.Union => switch (ty.containerLayout(zcu)) {
.auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already
.@"extern" => {
@ -437,11 +424,11 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
const field_val = try val.fieldValue(pt, field_index);
const byte_count: usize = @intCast(field_type.abiSize(zcu));
return writeToMemory(field_val, field_type, pt, buffer[0..byte_count]);
return writeToMemory(field_val, pt, buffer[0..byte_count]);
} else {
const backing_ty = try ty.unionBackingType(pt);
const byte_count: usize = @intCast(backing_ty.abiSize(zcu));
return writeToMemory(val.unionValue(zcu), backing_ty, pt, buffer[0..byte_count]);
return writeToMemory(val.unionValue(zcu), pt, buffer[0..byte_count]);
}
},
.@"packed" => {
@ -450,19 +437,13 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);
},
},
.Pointer => {
if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout;
if (!val.ptrHasIntAddr(zcu)) return error.ReinterpretDeclRef;
return val.writeToMemory(Type.usize, pt, buffer);
},
.Optional => {
if (!ty.isPtrLikeOptional(zcu)) return error.IllDefinedMemoryLayout;
const child = ty.optionalChild(zcu);
const opt_val = val.optionalValue(zcu);
if (opt_val) |some| {
return some.writeToMemory(child, pt, buffer);
return some.writeToMemory(pt, buffer);
} else {
return writeToMemory(try pt.intValue(Type.usize, 0), Type.usize, pt, buffer);
return writeToMemory(try pt.intValue(Type.usize, 0), pt, buffer);
}
},
else => return error.Unimplemented,
@ -582,7 +563,7 @@ pub fn writeToPackedMemory(
},
.Pointer => {
assert(!ty.isSlice(zcu)); // No well defined layout.
if (!val.ptrHasIntAddr(zcu)) return error.ReinterpretDeclRef;
if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
return val.writeToPackedMemory(Type.usize, pt, buffer, bit_offset);
},
.Optional => {
@ -3658,14 +3639,15 @@ pub fn mulAddScalar(
/// If the value is represented in-memory as a series of bytes that all
/// have the same value, return that byte value, otherwise null.
pub fn hasRepeatedByteRepr(val: Value, ty: Type, pt: Zcu.PerThread) !?u8 {
pub fn hasRepeatedByteRepr(val: Value, pt: Zcu.PerThread) !?u8 {
const zcu = pt.zcu;
const ty = val.typeOf(zcu);
const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null;
assert(abi_size >= 1);
const byte_buffer = try zcu.gpa.alloc(u8, abi_size);
defer zcu.gpa.free(byte_buffer);
writeToMemory(val, ty, pt, byte_buffer) catch |err| switch (err) {
writeToMemory(val, pt, byte_buffer) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ReinterpretDeclRef => return null,
// TODO: The writeToMemory function was originally created for the purpose

View File

@ -3357,7 +3357,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.vector_type => {
assert(determineSimdStoreStrategy(ty, zcu, func.target.*) == .direct);
var buf: [16]u8 = undefined;
val.writeToMemory(ty, pt, &buf) catch unreachable;
val.writeToMemory(pt, &buf) catch unreachable;
return func.storeSimdImmd(buf);
},
.struct_type => {

View File

@ -9412,7 +9412,7 @@ pub const FuncGen = struct {
// repeating byte pattern, for example, `@as(u64, 0)` has a
// repeating byte pattern of 0 bytes. In such case, the memset
// intrinsic can be used.
if (try elem_val.hasRepeatedByteRepr(elem_ty, pt)) |byte_val| {
if (try elem_val.hasRepeatedByteRepr(pt)) |byte_val| {
const fill_byte = try o.builder.intValue(.i8, byte_val);
const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
if (intrinsic_len0_traps) {

View File

@ -589,7 +589,8 @@ pub const File = struct {
fs.File.WriteFileError ||
fs.File.OpenError ||
std.process.Child.SpawnError ||
fs.Dir.CopyFileError;
fs.Dir.CopyFileError ||
FlushDebugInfoError;
/// Commit pending changes and write headers. Takes into account final output mode
/// and `use_lld`, not only `effectiveOutputMode`.

View File

@ -17,13 +17,21 @@ debug_loclists: DebugLocLists,
debug_rnglists: DebugRngLists,
debug_str: StringSection,
pub const UpdateError =
pub const UpdateError = error{
ReinterpretDeclRef,
IllDefinedMemoryLayout,
Unimplemented,
OutOfMemory,
EndOfStream,
Overflow,
Underflow,
UnexpectedEndOfFile,
} ||
std.fs.File.OpenError ||
std.fs.File.SetEndPosError ||
std.fs.File.CopyRangeError ||
std.fs.File.PReadError ||
std.fs.File.PWriteError ||
error{ EndOfStream, Overflow, Underflow, UnexpectedEndOfFile };
std.fs.File.PWriteError;
pub const FlushError =
UpdateError ||
@ -1401,7 +1409,7 @@ pub const WipNav = struct {
else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness,
};
if (loaded_enum.values.len > 0) {
var big_int_space: InternPool.Key.Int.Storage.BigIntSpace = undefined;
var big_int_space: Value.BigIntSpace = undefined;
const big_int = ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage.toBigInt(&big_int_space);
const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness));
if (bits <= 64) {
@ -1429,9 +1437,12 @@ pub const WipNav = struct {
}
} else {
try wip_nav.abbrevCode(abbrev_code.block);
const bytes = Type.fromInterned(loaded_enum.tag_ty).abiSize(wip_nav.pt.zcu);
const bytes = Type.fromInterned(loaded_enum.tag_ty).abiSize(zcu);
try uleb128(diw, bytes);
big_int.writeTwosComplement(try wip_nav.debug_info.addManyAsSlice(wip_nav.dwarf.gpa, @intCast(bytes)), wip_nav.dwarf.endian);
big_int.writeTwosComplement(
try wip_nav.debug_info.addManyAsSlice(wip_nav.dwarf.gpa, @intCast(bytes)),
wip_nav.dwarf.endian,
);
}
} else switch (signedness) {
.signed => {
@ -2566,8 +2577,17 @@ fn updateType(
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
.One, .Many, .C => {
const ptr_child_type = Type.fromInterned(ptr_type.child);
try wip_nav.abbrevCode(.ptr_type);
try wip_nav.abbrevCode(if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type);
try wip_nav.strp(name);
if (ptr_type.sentinel != .none) {
const bytes = ptr_child_type.abiSize(zcu);
try uleb128(diw, bytes);
const mem = try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, @intCast(bytes));
Value.fromInterned(ptr_type.sentinel).writeToMemory(pt, mem) catch |err| switch (err) {
error.IllDefinedMemoryLayout => @memset(mem, 0),
else => |e| return e,
};
}
try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse
ptr_child_type.abiAlignment(zcu).toByteUnits().?);
try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
@ -2609,16 +2629,34 @@ fn updateType(
try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
},
inline .array_type, .vector_type => |array_type, ty_tag| {
try wip_nav.abbrevCode(.array_type);
.array_type => |array_type| {
const array_child_type = Type.fromInterned(array_type.child);
try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
try wip_nav.strp(name);
try wip_nav.refType(Type.fromInterned(array_type.child));
try diw.writeByte(@intFromBool(ty_tag == .vector_type));
if (array_type.sentinel != .none) {
const bytes = array_child_type.abiSize(zcu);
try uleb128(diw, bytes);
const mem = try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, @intCast(bytes));
Value.fromInterned(array_type.sentinel).writeToMemory(pt, mem) catch |err| switch (err) {
error.IllDefinedMemoryLayout => @memset(mem, 0),
else => |e| return e,
};
}
try wip_nav.refType(array_child_type);
try wip_nav.abbrevCode(.array_index);
try wip_nav.refType(Type.usize);
try uleb128(diw, array_type.len);
try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
.vector_type => |vector_type| {
try wip_nav.abbrevCode(.vector_type);
try wip_nav.strp(name);
try wip_nav.refType(Type.fromInterned(vector_type.child));
try wip_nav.abbrevCode(.array_index);
try wip_nav.refType(Type.usize);
try uleb128(diw, vector_type.len);
try uleb128(diw, @intFromEnum(AbbrevCode.null));
},
.opt_type => |opt_child_type_index| {
const opt_child_type = Type.fromInterned(opt_child_type_index);
try wip_nav.abbrevCode(.union_type);
@ -2660,7 +2698,7 @@ fn updateType(
.error_set => {
try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = pt.zcu.errorSetBits(),
.bits = zcu.errorSetBits(),
} })));
try uleb128(diw, 0);
},
@ -2729,7 +2767,7 @@ fn updateType(
try wip_nav.strp("is_error");
try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = pt.zcu.errorSetBits(),
.bits = zcu.errorSetBits(),
} })));
try uleb128(diw, error_union_error_set_offset);
@ -2892,7 +2930,7 @@ fn updateType(
try wip_nav.strp(name);
try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = pt.zcu.errorSetBits(),
.bits = zcu.errorSetBits(),
} })));
for (0..error_set_type.names.len) |field_index| {
const field_name = error_set_type.names.get(ip)[field_index];
@ -3204,7 +3242,8 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A
}
pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
const ip = &pt.zcu.intern_pool;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
if (dwarf.types.get(.anyerror_type)) |entry| {
var wip_nav: WipNav = .{
.dwarf = dwarf,
@ -3228,7 +3267,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
try wip_nav.strp("anyerror");
try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = pt.zcu.errorSetBits(),
.bits = zcu.errorSetBits(),
} })));
for (global_error_set_names, 1..) |name, value| {
try wip_nav.abbrevCode(.unsigned_enum_field);
@ -3455,7 +3494,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable;
for (mod_info.files.keys()) |file_index| {
const file = pt.zcu.fileByIndex(file_index);
const file = zcu.fileByIndex(file_index);
unit.cross_section_relocs.appendAssumeCapacity(.{
.source_off = @intCast(header.items.len),
.target_sec = .debug_line_str,
@ -3602,9 +3641,12 @@ const AbbrevCode = enum {
numeric_type,
inferred_error_set_type,
ptr_type,
ptr_sentinel_type,
is_const,
is_volatile,
array_type,
array_sentinel_type,
vector_type,
array_index,
nullary_func_type,
func_type,
@ -3913,6 +3955,16 @@ const AbbrevCode = enum {
.{ .type, .ref_addr },
},
},
.ptr_sentinel_type = .{
.tag = .pointer_type,
.attrs = &.{
.{ .name, .strp },
.{ .ZIG_sentinel, .block },
.{ .alignment, .udata },
.{ .address_class, .data1 },
.{ .type, .ref_addr },
},
},
.is_const = .{
.tag = .const_type,
.attrs = &.{
@ -3931,7 +3983,24 @@ const AbbrevCode = enum {
.attrs = &.{
.{ .name, .strp },
.{ .type, .ref_addr },
.{ .GNU_vector, .flag },
},
},
.array_sentinel_type = .{
.tag = .array_type,
.children = true,
.attrs = &.{
.{ .name, .strp },
.{ .ZIG_sentinel, .block },
.{ .type, .ref_addr },
},
},
.vector_type = .{
.tag = .array_type,
.children = true,
.attrs = &.{
.{ .name, .strp },
.{ .type, .ref_addr },
.{ .GNU_vector, .flag_present },
},
},
.array_index = .{
@ -4132,6 +4201,7 @@ const Dwarf = @This();
const InternPool = @import("../InternPool.zig");
const Module = @import("../Package.zig").Module;
const Type = @import("../Type.zig");
const Value = @import("../Value.zig");
const Zcu = @import("../Zcu.zig");
const Zir = std.zig.Zir;
const assert = std.debug.assert;

View File

@ -305,6 +305,82 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\1 breakpoints deleted; 0 breakpoint locations disabled.
},
);
db.addLldbTest(
"strings",
target,
&.{
.{
.path = "strings.zig",
.source =
\\const Strings = struct {
\\ c_ptr: [*c]const u8 = "c_ptr\x07\x08\t",
\\ many_ptr: [*:0]const u8 = "many_ptr\n\x0b\x0c",
\\ ptr_array: *const [12:0]u8 = "ptr_array\x00\r\x1b",
\\ slice: [:0]const u8 = "slice\"\'\\\x00",
\\};
\\fn testStrings(strings: Strings) void {
\\ _ = strings;
\\}
\\pub fn main() void {
\\ testStrings(.{});
\\}
\\
,
},
},
\\breakpoint set --file strings.zig --source-pattern-regexp '_ = strings;'
\\process launch
\\frame variable --show-types strings.slice
\\frame variable --show-types --format character strings.slice
\\frame variable --show-types --format c-string strings
\\breakpoint delete --force 1
,
&.{
\\(lldb) frame variable --show-types strings.slice
\\([:0]const u8) strings.slice = len=9 {
\\ (u8) [0] = 115
\\ (u8) [1] = 108
\\ (u8) [2] = 105
\\ (u8) [3] = 99
\\ (u8) [4] = 101
\\ (u8) [5] = 34
\\ (u8) [6] = 39
\\ (u8) [7] = 92
\\ (u8) [8] = 0
\\}
\\(lldb) frame variable --show-types --format character strings.slice
\\([:0]const u8) strings.slice = len=9 {
\\ (u8) [0] = 's'
\\ (u8) [1] = 'l'
\\ (u8) [2] = 'i'
\\ (u8) [3] = 'c'
\\ (u8) [4] = 'e'
\\ (u8) [5] = '\"'
\\ (u8) [6] = '\''
\\ (u8) [7] = '\\'
\\ (u8) [8] = '\x00'
\\}
\\(lldb) frame variable --show-types --format c-string strings
\\(root.strings.Strings) strings = {
\\ ([*c]const u8) c_ptr = "c_ptr\x07\x08\t"
\\ ([*:0]const u8) many_ptr = "many_ptr\n\x0b\x0c"
\\ (*const [12:0]u8) ptr_array = "ptr_array\x00\r\x1b"
\\ ([:0]const u8) slice = "slice\"\'\\\x00" len=9 {
\\ (u8) [0] = "s"
\\ (u8) [1] = "l"
\\ (u8) [2] = "i"
\\ (u8) [3] = "c"
\\ (u8) [4] = "e"
\\ (u8) [5] = "\""
\\ (u8) [6] = "\'"
\\ (u8) [7] = "\\"
\\ (u8) [8] = "\x00"
\\ }
\\}
\\(lldb) breakpoint delete --force 1
\\1 breakpoints deleted; 0 breakpoint locations disabled.
},
);
db.addLldbTest(
"enums",
target,