| author | |
| committer | |
| log | 8fea84f77ebc6805fe4558ae73064955dbfdcb64 |
| tree | 1d5e16eb93373eaff9a7c802991b1d00ce828fff |
| parent | 17ab40f755a038bd9c06c7817354f9ce2eb4353f |
2 files changed, 61 insertions(+), 74 deletions(-)
src/arch/wasm/CodeGen.zig+18-59| ... | @@ -1291,23 +1291,6 @@ fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, target: | ... | @@ -1291,23 +1291,6 @@ fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, target: |
| 1291 | } | 1291 | } |
| 1292 | } | 1292 | } |
| 1293 | 1293 | ||
| 1294 | /// For a given `Type`, add debug information to .debug_info at the current position. | ||
| 1295 | /// The actual bytes will be written to the position after relocation. | ||
| 1296 | fn addDbgInfoTypeReloc(func: *CodeGen, ty: Type) !void { | ||
| 1297 | switch (func.debug_output) { | ||
| 1298 | .dwarf => |dwarf| { | ||
| 1299 | assert(ty.hasRuntimeBitsIgnoreComptime()); | ||
| 1300 | const dbg_info = &dwarf.dbg_info; | ||
| 1301 | const index = dbg_info.items.len; | ||
| 1302 | try dbg_info.resize(index + 4); | ||
| 1303 | const atom = &func.decl.link.wasm.dbg_info_atom; | ||
| 1304 | try dwarf.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); | ||
| 1305 | }, | ||
| 1306 | .plan9 => unreachable, | ||
| 1307 | .none => {}, | ||
| 1308 | } | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | /// Lowers a Zig type and its value based on a given calling convention to ensure | 1294 | /// Lowers a Zig type and its value based on a given calling convention to ensure |
| 1312 | /// it matches the ABI. | 1295 | /// it matches the ABI. |
| 1313 | fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void { | 1296 | fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void { |
| ... | @@ -2358,24 +2341,10 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2358,24 +2341,10 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2358 | .dwarf => |dwarf| { | 2341 | .dwarf => |dwarf| { |
| 2359 | // TODO: Get the original arg index rather than wasm arg index | 2342 | // TODO: Get the original arg index rather than wasm arg index |
| 2360 | const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, arg_index); | 2343 | const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, arg_index); |
| 2361 | const leb_size = link.File.Wasm.getULEB128Size(arg.local.value); | 2344 | const atom = func.getDbgInfoAtom(); |
| 2362 | const dbg_info = &dwarf.dbg_info; | 2345 | try dwarf.genArgDbgInfo(name, arg_ty, atom, .{ |
| 2363 | try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1); | 2346 | .wasm_local = arg.local.value, |
| 2364 | // wasm locations are encoded as follow: | ||
| 2365 | // DW_OP_WASM_location wasm-op | ||
| 2366 | // where wasm-op is defined as | ||
| 2367 | // wasm-op := wasm-local | wasm-global | wasm-operand_stack | ||
| 2368 | // where each argument is encoded as | ||
| 2369 | // <opcode> i:uleb128 | ||
| 2370 | dbg_info.appendSliceAssumeCapacity(&.{ | ||
| 2371 | @enumToInt(link.File.Dwarf.AbbrevKind.parameter), | ||
| 2372 | std.dwarf.OP.WASM_location, | ||
| 2373 | std.dwarf.OP.WASM_local, | ||
| 2374 | }); | 2347 | }); |
| 2375 | leb.writeULEB128(dbg_info.writer(), arg.local.value) catch unreachable; | ||
| 2376 | try func.addDbgInfoTypeReloc(arg_ty); | ||
| 2377 | dbg_info.appendSliceAssumeCapacity(name); | ||
| 2378 | dbg_info.appendAssumeCapacity(0); | ||
| 2379 | }, | 2348 | }, |
| 2380 | else => {}, | 2349 | else => {}, |
| 2381 | } | 2350 | } |
| ... | @@ -2383,6 +2352,12 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2383,6 +2352,12 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2383 | func.finishAir(inst, arg, &.{}); | 2352 | func.finishAir(inst, arg, &.{}); |
| 2384 | } | 2353 | } |
| 2385 | 2354 | ||
| 2355 | fn getDbgInfoAtom(func: CodeGen) *link.File.Dwarf.Atom { | ||
| 2356 | const mod = func.bin_file.base.options.module.?; | ||
| 2357 | const fn_owner_decl = mod.declPtr(func.mod_fn.owner_decl); | ||
| 2358 | return &fn_owner_decl.link.wasm.dbg_info_atom; | ||
| 2359 | } | ||
| 2360 | |||
| 2386 | fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | 2361 | fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2387 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 2362 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 2388 | if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); | 2363 | if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| ... | @@ -5345,38 +5320,22 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { | ... | @@ -5345,38 +5320,22 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { |
| 5345 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 5320 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 5346 | const ty = func.air.typeOf(pl_op.operand); | 5321 | const ty = func.air.typeOf(pl_op.operand); |
| 5347 | const operand = try func.resolveInst(pl_op.operand); | 5322 | const operand = try func.resolveInst(pl_op.operand); |
| 5348 | const op_ty = if (is_ptr) ty.childType() else ty; | ||
| 5349 | 5323 | ||
| 5350 | log.debug("airDbgVar: %{d}: {}, {}", .{ inst, op_ty.fmtDebug(), operand }); | 5324 | log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand }); |
| 5351 | 5325 | ||
| 5352 | const name = func.air.nullTerminatedString(pl_op.payload); | 5326 | const name = func.air.nullTerminatedString(pl_op.payload); |
| 5353 | log.debug(" var name = ({s})", .{name}); | 5327 | log.debug(" var name = ({s})", .{name}); |
| 5354 | 5328 | ||
| 5355 | const dbg_info = &func.debug_output.dwarf.dbg_info; | 5329 | const atom = func.getDbgInfoAtom(); |
| 5356 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); | 5330 | const loc: link.File.Dwarf.DeclState.VarArgDbgInfoLoc = switch (operand) { |
| 5357 | switch (operand) { | 5331 | .local => |local| .{ .wasm_local = local.value }, |
| 5358 | .local => |local| { | 5332 | else => blk: { |
| 5359 | const leb_size = link.File.Wasm.getULEB128Size(local.value); | 5333 | log.debug("TODO generate debug info for {}", .{operand}); |
| 5360 | try dbg_info.ensureUnusedCapacity(2 + leb_size); | 5334 | break :blk .nop; |
| 5361 | // wasm locals are encoded as follow: | ||
| 5362 | // DW_OP_WASM_location wasm-op | ||
| 5363 | // where wasm-op is defined as | ||
| 5364 | // wasm-op := wasm-local | wasm-global | wasm-operand_stack | ||
| 5365 | // where wasm-local is encoded as | ||
| 5366 | // wasm-local := 0x00 i:uleb128 | ||
| 5367 | dbg_info.appendSliceAssumeCapacity(&.{ | ||
| 5368 | std.dwarf.OP.WASM_location, | ||
| 5369 | std.dwarf.OP.WASM_local, | ||
| 5370 | }); | ||
| 5371 | leb.writeULEB128(dbg_info.writer(), local.value) catch unreachable; | ||
| 5372 | }, | 5335 | }, |
| 5373 | else => {}, // TODO | 5336 | }; |
| 5374 | } | 5337 | try func.debug_output.dwarf.genVarDbgInfo(name, ty, atom, is_ptr, loc); |
| 5375 | 5338 | ||
| 5376 | try dbg_info.ensureUnusedCapacity(5 + name.len + 1); | ||
| 5377 | try func.addDbgInfoTypeReloc(op_ty); | ||
| 5378 | dbg_info.appendSliceAssumeCapacity(name); | ||
| 5379 | dbg_info.appendAssumeCapacity(0); | ||
| 5380 | func.finishAir(inst, .none, &.{}); | 5339 | func.finishAir(inst, .none, &.{}); |
| 5381 | } | 5340 | } |
| 5382 | 5341 |
src/link/Dwarf.zig+43-15| ... | @@ -102,7 +102,7 @@ pub const DeclState = struct { | ... | @@ -102,7 +102,7 @@ pub const DeclState = struct { |
| 102 | self.exprloc_relocs.deinit(self.gpa); | 102 | self.exprloc_relocs.deinit(self.gpa); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void { | 105 | fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void { |
| 106 | log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr }); | 106 | log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr }); |
| 107 | try self.exprloc_relocs.append(self.gpa, .{ | 107 | try self.exprloc_relocs.append(self.gpa, .{ |
| 108 | .type = if (is_ptr) .got_load else .direct_load, | 108 | .type = if (is_ptr) .got_load else .direct_load, |
| ... | @@ -113,7 +113,7 @@ pub const DeclState = struct { | ... | @@ -113,7 +113,7 @@ pub const DeclState = struct { |
| 113 | 113 | ||
| 114 | /// Adds local type relocation of the form: @offset => @this + addend | 114 | /// Adds local type relocation of the form: @offset => @this + addend |
| 115 | /// @this signifies the offset within the .debug_abbrev section of the containing atom. | 115 | /// @this signifies the offset within the .debug_abbrev section of the containing atom. |
| 116 | pub fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void { | 116 | fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void { |
| 117 | log.debug("{x}: @this + {x}", .{ offset, addend }); | 117 | log.debug("{x}: @this + {x}", .{ offset, addend }); |
| 118 | try self.abbrev_relocs.append(self.gpa, .{ | 118 | try self.abbrev_relocs.append(self.gpa, .{ |
| 119 | .target = null, | 119 | .target = null, |
| ... | @@ -126,7 +126,7 @@ pub const DeclState = struct { | ... | @@ -126,7 +126,7 @@ pub const DeclState = struct { |
| 126 | /// Adds global type relocation of the form: @offset => @symbol + 0 | 126 | /// Adds global type relocation of the form: @offset => @symbol + 0 |
| 127 | /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section | 127 | /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section |
| 128 | /// which we use as our target of the relocation. | 128 | /// which we use as our target of the relocation. |
| 129 | pub fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void { | 129 | fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void { |
| 130 | const resolv = self.abbrev_resolver.getContext(ty, .{ | 130 | const resolv = self.abbrev_resolver.getContext(ty, .{ |
| 131 | .mod = self.mod, | 131 | .mod = self.mod, |
| 132 | }) orelse blk: { | 132 | }) orelse blk: { |
| ... | @@ -570,6 +570,7 @@ pub const DeclState = struct { | ... | @@ -570,6 +570,7 @@ pub const DeclState = struct { |
| 570 | loc: union(enum) { | 570 | loc: union(enum) { |
| 571 | register: u8, | 571 | register: u8, |
| 572 | stack: struct { fp_register: u8, offset: i32 }, | 572 | stack: struct { fp_register: u8, offset: i32 }, |
| 573 | wasm_local: u32, | ||
| 573 | }, | 574 | }, |
| 574 | ) error{OutOfMemory}!void { | 575 | ) error{OutOfMemory}!void { |
| 575 | const dbg_info = &self.dbg_info; | 576 | const dbg_info = &self.dbg_info; |
| ... | @@ -583,12 +584,6 @@ pub const DeclState = struct { | ... | @@ -583,12 +584,6 @@ pub const DeclState = struct { |
| 583 | 1, // ULEB128 dwarf expression length | 584 | 1, // ULEB128 dwarf expression length |
| 584 | reg, | 585 | reg, |
| 585 | }); | 586 | }); |
| 586 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | ||
| 587 | const index = dbg_info.items.len; | ||
| 588 | try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 | ||
| 589 | try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4 | ||
| 590 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | ||
| 591 | |||
| 592 | }, | 587 | }, |
| 593 | .stack => |info| { | 588 | .stack => |info| { |
| 594 | try dbg_info.ensureUnusedCapacity(8); | 589 | try dbg_info.ensureUnusedCapacity(8); |
| ... | @@ -600,14 +595,30 @@ pub const DeclState = struct { | ... | @@ -600,14 +595,30 @@ pub const DeclState = struct { |
| 600 | }); | 595 | }); |
| 601 | leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable; | 596 | leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable; |
| 602 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | 597 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); |
| 603 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | 598 | }, |
| 604 | const index = dbg_info.items.len; | 599 | .wasm_local => |value| { |
| 605 | try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 | 600 | const leb_size = link.File.Wasm.getULEB128Size(value); |
| 606 | try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); | 601 | try dbg_info.ensureUnusedCapacity(3 + leb_size); |
| 607 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | 602 | // wasm locations are encoded as follow: |
| 608 | 603 | // DW_OP_WASM_location wasm-op | |
| 604 | // where wasm-op is defined as | ||
| 605 | // wasm-op := wasm-local | wasm-global | wasm-operand_stack | ||
| 606 | // where each argument is encoded as | ||
| 607 | // <opcode> i:uleb128 | ||
| 608 | dbg_info.appendSliceAssumeCapacity(&.{ | ||
| 609 | @enumToInt(AbbrevKind.parameter), | ||
| 610 | DW.OP.WASM_location, | ||
| 611 | DW.OP.WASM_local, | ||
| 612 | }); | ||
| 613 | leb128.writeULEB128(dbg_info.writer(), value) catch unreachable; | ||
| 609 | }, | 614 | }, |
| 610 | } | 615 | } |
| 616 | |||
| 617 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | ||
| 618 | const index = dbg_info.items.len; | ||
| 619 | try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 | ||
| 620 | try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4 | ||
| 621 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | ||
| 611 | } | 622 | } |
| 612 | 623 | ||
| 613 | pub const VarArgDbgInfoLoc = union(enum) { | 624 | pub const VarArgDbgInfoLoc = union(enum) { |
| ... | @@ -616,6 +627,7 @@ pub const DeclState = struct { | ... | @@ -616,6 +627,7 @@ pub const DeclState = struct { |
| 616 | fp_register: u8, | 627 | fp_register: u8, |
| 617 | offset: i32, | 628 | offset: i32, |
| 618 | }, | 629 | }, |
| 630 | wasm_local: u32, | ||
| 619 | memory: u64, | 631 | memory: u64, |
| 620 | linker_load: LinkerLoad, | 632 | linker_load: LinkerLoad, |
| 621 | immediate: u64, | 633 | immediate: u64, |
| ... | @@ -659,6 +671,22 @@ pub const DeclState = struct { | ... | @@ -659,6 +671,22 @@ pub const DeclState = struct { |
| 659 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | 671 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); |
| 660 | }, | 672 | }, |
| 661 | 673 | ||
| 674 | .wasm_local => |value| { | ||
| 675 | const leb_size = link.File.Wasm.getULEB128Size(value); | ||
| 676 | try dbg_info.ensureUnusedCapacity(2 + leb_size); | ||
| 677 | // wasm locals are encoded as follow: | ||
| 678 | // DW_OP_WASM_location wasm-op | ||
| 679 | // where wasm-op is defined as | ||
| 680 | // wasm-op := wasm-local | wasm-global | wasm-operand_stack | ||
| 681 | // where wasm-local is encoded as | ||
| 682 | // wasm-local := 0x00 i:uleb128 | ||
| 683 | dbg_info.appendSliceAssumeCapacity(&.{ | ||
| 684 | DW.OP.WASM_location, | ||
| 685 | DW.OP.WASM_local, | ||
| 686 | }); | ||
| 687 | leb128.writeULEB128(dbg_info.writer(), value) catch unreachable; | ||
| 688 | }, | ||
| 689 | |||
| 662 | .memory, | 690 | .memory, |
| 663 | .linker_load, | 691 | .linker_load, |
| 664 | => { | 692 | => { |