stage2: add naive impl of pointer type in ELF

Augment relocation tracking mechanism to de-duplicate potential
creation of base as well as composite types while unrolling
composite types in the linker - there is still potential for
further space optimisation by moving all type information into
a separate section `.debug_types` and providing references to
entries within that section whenever required (e.g., `ref4` form).
Currently, we duplicate type definitions on a per-decl basis.

Anyhow, with this patch, an example function signature of the following
type:

```zig
fn byPtrPtr(ptr_ptr_x: **u32, ptr_x: *u32) void {
    ptr_ptr_x.* = ptr_x;
}
```

will generate the following `.debug_info` for formal parameters:

```
 <1><1aa>: Abbrev Number: 3 (DW_TAG_subprogram)
    <1ab>   DW_AT_low_pc      : 0x8000197
    <1b3>   DW_AT_high_pc     : 0x2c
    <1b7>   DW_AT_name        : byPtrPtr
 <2><1c0>: Abbrev Number: 7 (DW_TAG_formal_parameter)
    <1c1>   DW_AT_location    : 1 byte block: 55        (DW_OP_reg5 (rdi))
    <1c3>   DW_AT_type        : <0x1df>
    <1c7>   DW_AT_name        : ptr_ptr_x
 <2><1d1>: Abbrev Number: 7 (DW_TAG_formal_parameter)
    <1d2>   DW_AT_location    : 1 byte block: 54        (DW_OP_reg4 (rsi))
    <1d4>   DW_AT_type        : <0x1e4>
    <1d8>   DW_AT_name        : ptr_x
 <2><1de>: Abbrev Number: 0
 <1><1df>: Abbrev Number: 5 (DW_TAG_pointer_type)
    <1e0>   DW_AT_type        : <0x1e4>
 <1><1e4>: Abbrev Number: 5 (DW_TAG_pointer_type)
    <1e5>   DW_AT_type        : <0x1e9>
 <1><1e9>: Abbrev Number: 4 (DW_TAG_base_type)
    <1ea>   DW_AT_encoding    : 7       (unsigned)
    <1eb>   DW_AT_byte_size   : 4
    <1ec>   DW_AT_name        : u32
```
This commit is contained in:
Jakub Konka 2022-01-24 10:33:42 +01:00
parent 05c5bb9edd
commit 53c668d3a9
4 changed files with 66 additions and 21 deletions

View File

@ -235,7 +235,12 @@ pub const File = struct {
};
/// For DWARF .debug_info.
pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.HashContext64, std.hash_map.default_max_load_percentage);
pub const DbgInfoTypeRelocsTable = std.ArrayHashMapUnmanaged(
Type,
DbgInfoTypeReloc,
Type.HashContext32,
true,
);
/// For DWARF .debug_info.
pub const DbgInfoTypeReloc = struct {

View File

@ -783,8 +783,9 @@ pub const abbrev_compile_unit = 1;
pub const abbrev_subprogram = 2;
pub const abbrev_subprogram_retvoid = 3;
pub const abbrev_base_type = 4;
pub const abbrev_pad1 = 5;
pub const abbrev_parameter = 6;
pub const abbrev_ptr_type = 5;
pub const abbrev_pad1 = 6;
pub const abbrev_parameter = 7;
pub fn flush(self: *Elf, comp: *Compilation) !void {
if (self.base.options.emit == null) {
@ -871,9 +872,21 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
DW.AT.byte_size,
DW.FORM.data1,
DW.AT.name,
DW.FORM.string, 0, 0, // table sentinel
abbrev_pad1, DW.TAG.unspecified_type, DW.CHILDREN.no, // header
0, 0, // table sentinel
DW.FORM.string,
0,
0, // table sentinel
abbrev_ptr_type,
DW.TAG.pointer_type,
DW.CHILDREN.no, // header
DW.AT.type,
DW.FORM.ref4,
0,
0, // table sentinel
abbrev_pad1,
DW.TAG.unspecified_type,
DW.CHILDREN.no, // header
0,
0, // table sentinel
abbrev_parameter,
DW.TAG.formal_parameter, DW.CHILDREN.no, // header
DW.AT.location, DW.FORM.exprloc,
@ -2309,8 +2322,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
}
fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {
var it = table.valueIterator();
while (it.next()) |value| {
for (table.values()) |*value| {
value.relocs.deinit(gpa);
}
table.deinit(gpa);
@ -2387,10 +2399,12 @@ fn finishUpdateDecl(
// the buffer, so we have to do it before computing the offset, and we can't perform the actual
// relocations yet.
{
var it = dbg_info_type_relocs.iterator();
while (it.next()) |entry| {
entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer);
var it: usize = 0;
while (it < dbg_info_type_relocs.count()) : (it += 1) {
const ty = dbg_info_type_relocs.keys()[it];
const value_ptr = dbg_info_type_relocs.getPtr(ty).?;
value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
try self.addDbgInfoType(ty, dbg_info_buffer, dbg_info_type_relocs);
}
}
@ -2401,8 +2415,7 @@ fn finishUpdateDecl(
{
// Now that we have the offset assigned we can finally perform type relocations.
var it = dbg_info_type_relocs.valueIterator();
while (it.next()) |value| {
for (dbg_info_type_relocs.values()) |value| {
for (value.relocs.items) |off| {
mem.writeInt(
u32,
@ -2706,7 +2719,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
}
/// Asserts the type has codegen bits.
fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
fn addDbgInfoType(
self: *Elf,
ty: Type,
dbg_info_buffer: *std.ArrayList(u8),
dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
) error{OutOfMemory}!void {
var reloc: ?struct { ty: Type, reloc: u32 } = null;
switch (ty.zigTypeTag()) {
.Void => unreachable,
.NoReturn => unreachable,
@ -2747,11 +2767,34 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo
try dbg_info_buffer.append(abbrev_pad1);
}
},
.Pointer => blk: {
if (ty.isSlice()) {
log.debug("TODO implement .debug_info for type '{}'", .{ty});
try dbg_info_buffer.append(abbrev_pad1);
break :blk;
}
try dbg_info_buffer.ensureUnusedCapacity(5);
dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type);
const index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); // DW.AT.type, DW.FORM.ref4
reloc = .{ .ty = ty.childType(), .reloc = @intCast(u32, index) };
},
else => {
log.debug("TODO implement .debug_info for type '{}'", .{ty});
try dbg_info_buffer.append(abbrev_pad1);
},
}
if (reloc) |rel| {
const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, rel.ty);
if (!gop.found_existing) {
gop.value_ptr.* = .{
.off = undefined,
.relocs = .{},
};
}
try gop.value_ptr.relocs.append(self.base.allocator, rel.reloc);
}
}
fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void {

View File

@ -3578,8 +3578,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
if (debug_buffers) |dbg| {
dbg.dbg_line_buffer.deinit();
dbg.dbg_info_buffer.deinit();
var it = dbg.dbg_info_type_relocs.valueIterator();
while (it.next()) |value| {
for (dbg.dbg_info_type_relocs.values()) |*value| {
value.relocs.deinit(self.base.allocator);
}
dbg.dbg_info_type_relocs.deinit(self.base.allocator);
@ -3659,8 +3658,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
if (debug_buffers) |dbg| {
dbg.dbg_line_buffer.deinit();
dbg.dbg_info_buffer.deinit();
var it = dbg.dbg_info_type_relocs.valueIterator();
while (it.next()) |value| {
for (dbg.dbg_info_type_relocs.values()) |*value| {
value.relocs.deinit(self.base.allocator);
}
dbg.dbg_info_type_relocs.deinit(self.base.allocator);

View File

@ -1112,8 +1112,7 @@ pub fn commitDeclDebugInfo(
{
// Now that we have the offset assigned we can finally perform type relocations.
var it = dbg_info_type_relocs.valueIterator();
while (it.next()) |value| {
for (dbg_info_type_relocs.values()) |value| {
for (value.relocs.items) |off| {
mem.writeIntLittle(
u32,