| author | |
| committer | |
| log | 16dc86a49e1e92d036d196be40a4fc073314bcf7 |
| tree | 8842f844da54874ff384398382bf3b2374a071a4 |
| parent | 665eba93c1733f83614c443c19cd9a5f1be910df |
| parent | bfd36cbf97bfa012e5c399c16578b8756782e1d8 |
| signature |
dwarf: dedup generation of dwarf info for func args and vars in Dwarf module8 files changed, 393 insertions(+), 603 deletions(-)
src/arch/aarch64/CodeGen.zig+45-179| ... | ... | @@ -146,11 +146,8 @@ const MCValue = union(enum) { |
| 146 | 146 | /// If the type is a pointer, it means the pointer address is at |
| 147 | 147 | /// this memory location. |
| 148 | 148 | memory: u64, |
| 149 | /// The value is in memory but requires a linker relocation fixup: | |
| 150 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) | |
| 151 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) | |
| 152 | /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) | |
| 153 | linker_load: struct { type: enum { got, direct, import }, sym_index: u32 }, | |
| 149 | /// The value is in memory but requires a linker relocation fixup. | |
| 150 | linker_load: codegen.LinkerLoad, | |
| 154 | 151 | /// The value is one of the stack variables. |
| 155 | 152 | /// |
| 156 | 153 | /// If the type is a pointer, it means the pointer address is in |
| ... | ... | @@ -184,52 +181,34 @@ const DbgInfoReloc = struct { |
| 184 | 181 | else => unreachable, |
| 185 | 182 | } |
| 186 | 183 | } |
| 187 | ||
| 188 | 184 | fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void { |
| 189 | const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1]; | |
| 190 | ||
| 191 | 185 | switch (function.debug_output) { |
| 192 | 186 | .dwarf => |dw| { |
| 193 | const dbg_info = &dw.dbg_info; | |
| 194 | switch (reloc.mcv) { | |
| 195 | .register => |reg| { | |
| 196 | try dbg_info.ensureUnusedCapacity(3); | |
| 197 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 198 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 199 | 1, // ULEB128 dwarf expression length | |
| 200 | reg.dwarfLocOp(), | |
| 201 | }); | |
| 202 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 203 | try function.addDbgInfoTypeReloc(reloc.ty); // DW.AT.type, DW.FORM.ref4 | |
| 204 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 205 | }, | |
| 206 | ||
| 187 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) { | |
| 188 | .register => |reg| .{ .register = reg.dwarfLocOp() }, | |
| 207 | 189 | .stack_offset, |
| 208 | 190 | .stack_argument_offset, |
| 209 | => |offset| { | |
| 191 | => |offset| blk: { | |
| 210 | 192 | const adjusted_offset = switch (reloc.mcv) { |
| 211 | 193 | .stack_offset => -@intCast(i32, offset), |
| 212 | 194 | .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset), |
| 213 | 195 | else => unreachable, |
| 214 | 196 | }; |
| 215 | ||
| 216 | try dbg_info.ensureUnusedCapacity(8); | |
| 217 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 218 | const fixup = dbg_info.items.len; | |
| 219 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 220 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 221 | Register.x29.dwarfLocOpDeref(), // frame pointer | |
| 222 | }); | |
| 223 | leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable; | |
| 224 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 225 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 226 | try function.addDbgInfoTypeReloc(reloc.ty); // DW.AT.type, DW.FORM.ref4 | |
| 227 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 228 | ||
| 197 | break :blk .{ .stack = .{ | |
| 198 | .fp_register = Register.x29.dwarfLocOpDeref(), | |
| 199 | .offset = adjusted_offset, | |
| 200 | } }; | |
| 229 | 201 | }, |
| 230 | ||
| 231 | 202 | else => unreachable, // not a possible argument |
| 232 | } | |
| 203 | ||
| 204 | }; | |
| 205 | try dw.genArgDbgInfo( | |
| 206 | reloc.name, | |
| 207 | reloc.ty, | |
| 208 | function.bin_file.tag, | |
| 209 | function.mod_fn.owner_decl, | |
| 210 | loc, | |
| 211 | ); | |
| 233 | 212 | }, |
| 234 | 213 | .plan9 => {}, |
| 235 | 214 | .none => {}, |
| ... | ... | @@ -237,32 +216,20 @@ const DbgInfoReloc = struct { |
| 237 | 216 | } |
| 238 | 217 | |
| 239 | 218 | fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void { |
| 240 | const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1]; | |
| 241 | const ty = switch (reloc.tag) { | |
| 242 | .dbg_var_ptr => reloc.ty.childType(), | |
| 243 | .dbg_var_val => reloc.ty, | |
| 219 | const is_ptr = switch (reloc.tag) { | |
| 220 | .dbg_var_ptr => true, | |
| 221 | .dbg_var_val => false, | |
| 244 | 222 | else => unreachable, |
| 245 | 223 | }; |
| 246 | 224 | |
| 247 | 225 | switch (function.debug_output) { |
| 248 | 226 | .dwarf => |dw| { |
| 249 | const dbg_info = &dw.dbg_info; | |
| 250 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); | |
| 251 | const endian = function.target.cpu.arch.endian(); | |
| 252 | ||
| 253 | switch (reloc.mcv) { | |
| 254 | .register => |reg| { | |
| 255 | try dbg_info.ensureUnusedCapacity(2); | |
| 256 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 257 | 1, // ULEB128 dwarf expression length | |
| 258 | reg.dwarfLocOp(), | |
| 259 | }); | |
| 260 | }, | |
| 261 | ||
| 227 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) { | |
| 228 | .register => |reg| .{ .register = reg.dwarfLocOp() }, | |
| 262 | 229 | .ptr_stack_offset, |
| 263 | 230 | .stack_offset, |
| 264 | 231 | .stack_argument_offset, |
| 265 | => |offset| { | |
| 232 | => |offset| blk: { | |
| 266 | 233 | const adjusted_offset = switch (reloc.mcv) { |
| 267 | 234 | .ptr_stack_offset, |
| 268 | 235 | .stack_offset, |
| ... | ... | @@ -270,110 +237,31 @@ const DbgInfoReloc = struct { |
| 270 | 237 | .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset), |
| 271 | 238 | else => unreachable, |
| 272 | 239 | }; |
| 273 | ||
| 274 | try dbg_info.ensureUnusedCapacity(7); | |
| 275 | const fixup = dbg_info.items.len; | |
| 276 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 277 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 278 | Register.x29.dwarfLocOpDeref(), // frame pointer | |
| 279 | }); | |
| 280 | leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable; | |
| 281 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 282 | }, | |
| 283 | ||
| 284 | .memory, | |
| 285 | .linker_load, | |
| 286 | => { | |
| 287 | const ptr_width = @intCast(u8, @divExact(function.target.cpu.arch.ptrBitWidth(), 8)); | |
| 288 | const is_ptr = switch (reloc.tag) { | |
| 289 | .dbg_var_ptr => true, | |
| 290 | .dbg_var_val => false, | |
| 291 | else => unreachable, | |
| 292 | }; | |
| 293 | try dbg_info.ensureUnusedCapacity(2 + ptr_width); | |
| 294 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 295 | 1 + ptr_width + @boolToInt(is_ptr), | |
| 296 | DW.OP.addr, // literal address | |
| 297 | }); | |
| 298 | const offset = @intCast(u32, dbg_info.items.len); | |
| 299 | const addr = switch (reloc.mcv) { | |
| 300 | .memory => |addr| addr, | |
| 301 | else => 0, | |
| 302 | }; | |
| 303 | switch (ptr_width) { | |
| 304 | 0...4 => { | |
| 305 | try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian); | |
| 240 | break :blk .{ | |
| 241 | .stack = .{ | |
| 242 | .fp_register = Register.x29.dwarfLocOpDeref(), | |
| 243 | .offset = adjusted_offset, | |
| 306 | 244 | }, |
| 307 | 5...8 => { | |
| 308 | try dbg_info.writer().writeInt(u64, addr, endian); | |
| 309 | }, | |
| 310 | else => unreachable, | |
| 311 | } | |
| 312 | if (is_ptr) { | |
| 313 | // We need deref the address as we point to the value via GOT entry. | |
| 314 | try dbg_info.append(DW.OP.deref); | |
| 315 | } | |
| 316 | switch (reloc.mcv) { | |
| 317 | .linker_load => |load_struct| try dw.addExprlocReloc( | |
| 318 | load_struct.sym_index, | |
| 319 | offset, | |
| 320 | is_ptr, | |
| 321 | ), | |
| 322 | else => {}, | |
| 323 | } | |
| 324 | }, | |
| 325 | ||
| 326 | .immediate => |x| { | |
| 327 | try dbg_info.ensureUnusedCapacity(2); | |
| 328 | const fixup = dbg_info.items.len; | |
| 329 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 330 | 1, | |
| 331 | if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu, | |
| 332 | }); | |
| 333 | if (ty.isSignedInt()) { | |
| 334 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); | |
| 335 | } else { | |
| 336 | try leb128.writeULEB128(dbg_info.writer(), x); | |
| 337 | } | |
| 338 | try dbg_info.append(DW.OP.stack_value); | |
| 339 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 340 | }, | |
| 341 | ||
| 342 | .undef => { | |
| 343 | // DW.AT.location, DW.FORM.exprloc | |
| 344 | // uleb128(exprloc_len) | |
| 345 | // DW.OP.implicit_value uleb128(len_of_bytes) bytes | |
| 346 | const abi_size = @intCast(u32, ty.abiSize(function.target.*)); | |
| 347 | var implicit_value_len = std.ArrayList(u8).init(function.gpa); | |
| 348 | defer implicit_value_len.deinit(); | |
| 349 | try leb128.writeULEB128(implicit_value_len.writer(), abi_size); | |
| 350 | const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size; | |
| 351 | try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len); | |
| 352 | try dbg_info.ensureUnusedCapacity(total_exprloc_len); | |
| 353 | dbg_info.appendAssumeCapacity(DW.OP.implicit_value); | |
| 354 | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); | |
| 355 | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); | |
| 356 | }, | |
| 357 | ||
| 358 | .none => { | |
| 359 | try dbg_info.ensureUnusedCapacity(3); | |
| 360 | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 361 | 2, DW.OP.lit0, DW.OP.stack_value, | |
| 362 | }); | |
| 245 | }; | |
| 363 | 246 | }, |
| 364 | ||
| 365 | else => { | |
| 366 | try dbg_info.ensureUnusedCapacity(2); | |
| 367 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 368 | 1, DW.OP.nop, | |
| 369 | }); | |
| 247 | .memory => |address| .{ .memory = address }, | |
| 248 | .linker_load => |linker_load| .{ .linker_load = linker_load }, | |
| 249 | .immediate => |x| .{ .immediate = x }, | |
| 250 | .undef => .undef, | |
| 251 | .none => .none, | |
| 252 | else => blk: { | |
| 370 | 253 | log.debug("TODO generate debug info for {}", .{reloc.mcv}); |
| 254 | break :blk .nop; | |
| 371 | 255 | }, |
| 372 | } | |
| 373 | ||
| 374 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 375 | try function.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 376 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 256 | }; | |
| 257 | try dw.genVarDbgInfo( | |
| 258 | reloc.name, | |
| 259 | reloc.ty, | |
| 260 | function.bin_file.tag, | |
| 261 | function.mod_fn.owner_decl, | |
| 262 | is_ptr, | |
| 263 | loc, | |
| 264 | ); | |
| 377 | 265 | }, |
| 378 | 266 | .plan9 => {}, |
| 379 | 267 | .none => {}, |
| ... | ... | @@ -1079,28 +967,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 1079 | 967 | try table.ensureUnusedCapacity(self.gpa, additional_count); |
| 1080 | 968 | } |
| 1081 | 969 | |
| 1082 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | |
| 1083 | /// after codegen for this symbol is done. | |
| 1084 | fn addDbgInfoTypeReloc(self: Self, ty: Type) !void { | |
| 1085 | switch (self.debug_output) { | |
| 1086 | .dwarf => |dw| { | |
| 1087 | const dbg_info = &dw.dbg_info; | |
| 1088 | const index = dbg_info.items.len; | |
| 1089 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 1090 | const mod = self.bin_file.options.module.?; | |
| 1091 | const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl); | |
| 1092 | const atom = switch (self.bin_file.tag) { | |
| 1093 | .elf => &fn_owner_decl.link.elf.dbg_info_atom, | |
| 1094 | .macho => &fn_owner_decl.link.macho.dbg_info_atom, | |
| 1095 | else => unreachable, | |
| 1096 | }; | |
| 1097 | try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); | |
| 1098 | }, | |
| 1099 | .plan9 => {}, | |
| 1100 | .none => {}, | |
| 1101 | } | |
| 1102 | } | |
| 1103 | ||
| 1104 | 970 | fn allocMem( |
| 1105 | 971 | self: *Self, |
| 1106 | 972 | abi_size: u32, |
src/arch/arm/CodeGen.zig+18-69| ... | ... | @@ -4029,86 +4029,35 @@ fn genInlineMemsetCode( |
| 4029 | 4029 | // end: |
| 4030 | 4030 | } |
| 4031 | 4031 | |
| 4032 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | |
| 4033 | /// after codegen for this symbol is done. | |
| 4034 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { | |
| 4035 | switch (self.debug_output) { | |
| 4036 | .dwarf => |dw| { | |
| 4037 | assert(ty.hasRuntimeBits()); | |
| 4038 | const dbg_info = &dw.dbg_info; | |
| 4039 | const index = dbg_info.items.len; | |
| 4040 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 4041 | const mod = self.bin_file.options.module.?; | |
| 4042 | const atom = switch (self.bin_file.tag) { | |
| 4043 | .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom, | |
| 4044 | .macho => unreachable, | |
| 4045 | else => unreachable, | |
| 4046 | }; | |
| 4047 | try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); | |
| 4048 | }, | |
| 4049 | .plan9 => {}, | |
| 4050 | .none => {}, | |
| 4051 | } | |
| 4052 | } | |
| 4053 | ||
| 4054 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void { | |
| 4032 | fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void { | |
| 4055 | 4033 | const mcv = self.args[arg_index]; |
| 4056 | 4034 | const ty = self.air.instructions.items(.data)[inst].ty; |
| 4057 | 4035 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); |
| 4058 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 4059 | 4036 | |
| 4060 | switch (mcv) { | |
| 4061 | .register => |reg| { | |
| 4062 | switch (self.debug_output) { | |
| 4063 | .dwarf => |dw| { | |
| 4064 | const dbg_info = &dw.dbg_info; | |
| 4065 | try dbg_info.ensureUnusedCapacity(3); | |
| 4066 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 4067 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 4068 | 1, // ULEB128 dwarf expression length | |
| 4069 | reg.dwarfLocOp(), | |
| 4070 | }); | |
| 4071 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 4072 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 4073 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 4074 | }, | |
| 4075 | .plan9 => {}, | |
| 4076 | .none => {}, | |
| 4077 | } | |
| 4078 | }, | |
| 4079 | .stack_offset, | |
| 4080 | .stack_argument_offset, | |
| 4081 | => { | |
| 4082 | switch (self.debug_output) { | |
| 4083 | .dwarf => |dw| { | |
| 4037 | switch (self.debug_output) { | |
| 4038 | .dwarf => |dw| { | |
| 4039 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { | |
| 4040 | .register => |reg| .{ .register = reg.dwarfLocOp() }, | |
| 4041 | .stack_offset, | |
| 4042 | .stack_argument_offset, | |
| 4043 | => blk: { | |
| 4084 | 4044 | const adjusted_stack_offset = switch (mcv) { |
| 4085 | 4045 | .stack_offset => |offset| -@intCast(i32, offset), |
| 4086 | 4046 | .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset), |
| 4087 | 4047 | else => unreachable, |
| 4088 | 4048 | }; |
| 4089 | ||
| 4090 | const dbg_info = &dw.dbg_info; | |
| 4091 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 4092 | ||
| 4093 | // Get length of the LEB128 stack offset | |
| 4094 | var counting_writer = std.io.countingWriter(std.io.null_writer); | |
| 4095 | leb128.writeILEB128(counting_writer.writer(), adjusted_stack_offset) catch unreachable; | |
| 4096 | ||
| 4097 | // DW.AT.location, DW.FORM.exprloc | |
| 4098 | // ULEB128 dwarf expression length | |
| 4099 | try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1); | |
| 4100 | try dbg_info.append(DW.OP.breg11); | |
| 4101 | try leb128.writeILEB128(dbg_info.writer(), adjusted_stack_offset); | |
| 4102 | ||
| 4103 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 4104 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 4105 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 4049 | break :blk .{ .stack = .{ | |
| 4050 | .fp_register = DW.OP.breg11, | |
| 4051 | .offset = adjusted_stack_offset, | |
| 4052 | } }; | |
| 4106 | 4053 | }, |
| 4107 | .plan9 => {}, | |
| 4108 | .none => {}, | |
| 4109 | } | |
| 4054 | else => unreachable, // not a possible argument | |
| 4055 | ||
| 4056 | }; | |
| 4057 | try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc); | |
| 4110 | 4058 | }, |
| 4111 | else => unreachable, // not a possible argument | |
| 4059 | .plan9 => {}, | |
| 4060 | .none => {}, | |
| 4112 | 4061 | } |
| 4113 | 4062 | } |
| 4114 | 4063 |
src/arch/riscv64/CodeGen.zig+14-51| ... | ... | @@ -772,28 +772,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 772 | 772 | try table.ensureUnusedCapacity(self.gpa, additional_count); |
| 773 | 773 | } |
| 774 | 774 | |
| 775 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | |
| 776 | /// after codegen for this symbol is done. | |
| 777 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { | |
| 778 | switch (self.debug_output) { | |
| 779 | .dwarf => |dw| { | |
| 780 | assert(ty.hasRuntimeBits()); | |
| 781 | const dbg_info = &dw.dbg_info; | |
| 782 | const index = dbg_info.items.len; | |
| 783 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 784 | const mod = self.bin_file.options.module.?; | |
| 785 | const atom = switch (self.bin_file.tag) { | |
| 786 | .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom, | |
| 787 | .macho => unreachable, | |
| 788 | else => unreachable, | |
| 789 | }; | |
| 790 | try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); | |
| 791 | }, | |
| 792 | .plan9 => {}, | |
| 793 | .none => {}, | |
| 794 | } | |
| 795 | } | |
| 796 | ||
| 797 | 775 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { |
| 798 | 776 | if (abi_align > self.stack_align) |
| 799 | 777 | self.stack_align = abi_align; |
| ... | ... | @@ -1624,39 +1602,24 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1624 | 1602 | return self.fail("TODO implement codegen airFieldParentPtr", .{}); |
| 1625 | 1603 | } |
| 1626 | 1604 | |
| 1627 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void { | |
| 1605 | fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void { | |
| 1628 | 1606 | const ty = self.air.instructions.items(.data)[inst].ty; |
| 1629 | 1607 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); |
| 1630 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 1631 | 1608 | |
| 1632 | switch (mcv) { | |
| 1633 | .register => |reg| { | |
| 1634 | switch (self.debug_output) { | |
| 1635 | .dwarf => |dw| { | |
| 1636 | const dbg_info = &dw.dbg_info; | |
| 1637 | try dbg_info.ensureUnusedCapacity(3); | |
| 1638 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 1639 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 1640 | 1, // ULEB128 dwarf expression length | |
| 1641 | reg.dwarfLocOp(), | |
| 1642 | }); | |
| 1643 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 1644 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 1645 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 1646 | }, | |
| 1647 | .plan9 => {}, | |
| 1648 | .none => {}, | |
| 1649 | } | |
| 1650 | }, | |
| 1651 | .stack_offset => |offset| { | |
| 1652 | _ = offset; | |
| 1653 | switch (self.debug_output) { | |
| 1654 | .dwarf => {}, | |
| 1655 | .plan9 => {}, | |
| 1656 | .none => {}, | |
| 1657 | } | |
| 1609 | switch (self.debug_output) { | |
| 1610 | .dwarf => |dw| switch (mcv) { | |
| 1611 | .register => |reg| try dw.genArgDbgInfo( | |
| 1612 | name, | |
| 1613 | ty, | |
| 1614 | self.bin_file.tag, | |
| 1615 | self.mod_fn.owner_decl, | |
| 1616 | .{ .register = reg.dwarfLocOp() }, | |
| 1617 | ), | |
| 1618 | .stack_offset => {}, | |
| 1619 | else => {}, | |
| 1658 | 1620 | }, |
| 1659 | else => {}, | |
| 1621 | .plan9 => {}, | |
| 1622 | .none => {}, | |
| 1660 | 1623 | } |
| 1661 | 1624 | } |
| 1662 | 1625 |
src/arch/sparc64/CodeGen.zig+11-46| ... | ... | @@ -2460,26 +2460,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2460 | 2460 | |
| 2461 | 2461 | // Common helper functions |
| 2462 | 2462 | |
| 2463 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | |
| 2464 | /// after codegen for this symbol is done. | |
| 2465 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { | |
| 2466 | switch (self.debug_output) { | |
| 2467 | .dwarf => |dw| { | |
| 2468 | assert(ty.hasRuntimeBits()); | |
| 2469 | const dbg_info = &dw.dbg_info; | |
| 2470 | const index = dbg_info.items.len; | |
| 2471 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 2472 | const mod = self.bin_file.options.module.?; | |
| 2473 | const atom = switch (self.bin_file.tag) { | |
| 2474 | .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom, | |
| 2475 | else => unreachable, | |
| 2476 | }; | |
| 2477 | try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); | |
| 2478 | }, | |
| 2479 | else => {}, | |
| 2480 | } | |
| 2481 | } | |
| 2482 | ||
| 2483 | 2463 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 2484 | 2464 | const gpa = self.gpa; |
| 2485 | 2465 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -3272,35 +3252,20 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 3272 | 3252 | self.finishAirBookkeeping(); |
| 3273 | 3253 | } |
| 3274 | 3254 | |
| 3275 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void { | |
| 3255 | fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void { | |
| 3276 | 3256 | const ty = self.air.instructions.items(.data)[inst].ty; |
| 3277 | 3257 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); |
| 3278 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 3279 | 3258 | |
| 3280 | switch (mcv) { | |
| 3281 | .register => |reg| { | |
| 3282 | switch (self.debug_output) { | |
| 3283 | .dwarf => |dw| { | |
| 3284 | const dbg_info = &dw.dbg_info; | |
| 3285 | try dbg_info.ensureUnusedCapacity(3); | |
| 3286 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 3287 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 3288 | 1, // ULEB128 dwarf expression length | |
| 3289 | reg.dwarfLocOp(), | |
| 3290 | }); | |
| 3291 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 3292 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 3293 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 3294 | }, | |
| 3295 | else => {}, | |
| 3296 | } | |
| 3297 | }, | |
| 3298 | .stack_offset => |offset| { | |
| 3299 | _ = offset; | |
| 3300 | switch (self.debug_output) { | |
| 3301 | .dwarf => {}, | |
| 3302 | else => {}, | |
| 3303 | } | |
| 3259 | switch (self.debug_output) { | |
| 3260 | .dwarf => |dw| switch (mcv) { | |
| 3261 | .register => |reg| try dw.genArgDbgInfo( | |
| 3262 | name, | |
| 3263 | ty, | |
| 3264 | self.bin_file.tag, | |
| 3265 | self.mod_fn.owner_decl, | |
| 3266 | .{ .register = reg.dwarfLocOp() }, | |
| 3267 | ), | |
| 3268 | else => {}, | |
| 3304 | 3269 | }, |
| 3305 | 3270 | else => {}, |
| 3306 | 3271 | } |
src/arch/wasm/CodeGen.zig+10-59| ... | ... | @@ -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 | 1294 | /// Lowers a Zig type and its value based on a given calling convention to ensure |
| 1312 | 1295 | /// it matches the ABI. |
| 1313 | 1296 | fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void { |
| ... | ... | @@ -2358,24 +2341,9 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2358 | 2341 | .dwarf => |dwarf| { |
| 2359 | 2342 | // TODO: Get the original arg index rather than wasm arg index |
| 2360 | 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); | |
| 2362 | const dbg_info = &dwarf.dbg_info; | |
| 2363 | try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1); | |
| 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, | |
| 2344 | try dwarf.genArgDbgInfo(name, arg_ty, .wasm, func.mod_fn.owner_decl, .{ | |
| 2345 | .wasm_local = arg.local.value, | |
| 2374 | 2346 | }); |
| 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 | 2347 | }, |
| 2380 | 2348 | else => {}, |
| 2381 | 2349 | } |
| ... | ... | @@ -5345,38 +5313,21 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { |
| 5345 | 5313 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 5346 | 5314 | const ty = func.air.typeOf(pl_op.operand); |
| 5347 | 5315 | const operand = try func.resolveInst(pl_op.operand); |
| 5348 | const op_ty = if (is_ptr) ty.childType() else ty; | |
| 5349 | 5316 | |
| 5350 | log.debug("airDbgVar: %{d}: {}, {}", .{ inst, op_ty.fmtDebug(), operand }); | |
| 5317 | log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand }); | |
| 5351 | 5318 | |
| 5352 | 5319 | const name = func.air.nullTerminatedString(pl_op.payload); |
| 5353 | 5320 | log.debug(" var name = ({s})", .{name}); |
| 5354 | 5321 | |
| 5355 | const dbg_info = &func.debug_output.dwarf.dbg_info; | |
| 5356 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); | |
| 5357 | switch (operand) { | |
| 5358 | .local => |local| { | |
| 5359 | const leb_size = link.File.Wasm.getULEB128Size(local.value); | |
| 5360 | try dbg_info.ensureUnusedCapacity(2 + leb_size); | |
| 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; | |
| 5322 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (operand) { | |
| 5323 | .local => |local| .{ .wasm_local = local.value }, | |
| 5324 | else => blk: { | |
| 5325 | log.debug("TODO generate debug info for {}", .{operand}); | |
| 5326 | break :blk .nop; | |
| 5372 | 5327 | }, |
| 5373 | else => {}, // TODO | |
| 5374 | } | |
| 5328 | }; | |
| 5329 | try func.debug_output.dwarf.genVarDbgInfo(name, ty, .wasm, func.mod_fn.owner_decl, is_ptr, loc); | |
| 5375 | 5330 | |
| 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 | 5331 | func.finishAir(inst, .none, &.{}); |
| 5381 | 5332 | } |
| 5382 | 5333 |
src/arch/x86_64/CodeGen.zig+51-196| ... | ... | @@ -128,11 +128,8 @@ pub const MCValue = union(enum) { |
| 128 | 128 | /// The value is in memory at a hard-coded address. |
| 129 | 129 | /// If the type is a pointer, it means the pointer address is at this memory location. |
| 130 | 130 | memory: u64, |
| 131 | /// The value is in memory but requires a linker relocation fixup: | |
| 132 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) | |
| 133 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) | |
| 134 | /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) | |
| 135 | linker_load: struct { type: enum { got, direct, import }, sym_index: u32 }, | |
| 131 | /// The value is in memory but requires a linker relocation fixup. | |
| 132 | linker_load: codegen.LinkerLoad, | |
| 136 | 133 | /// The value is one of the stack variables. |
| 137 | 134 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. |
| 138 | 135 | stack_offset: i32, |
| ... | ... | @@ -3818,41 +3815,60 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3818 | 3815 | } |
| 3819 | 3816 | |
| 3820 | 3817 | fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 3821 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 3822 | 3818 | switch (self.debug_output) { |
| 3823 | 3819 | .dwarf => |dw| { |
| 3824 | const dbg_info = &dw.dbg_info; | |
| 3825 | switch (mcv) { | |
| 3826 | .register => |reg| { | |
| 3827 | try dbg_info.ensureUnusedCapacity(3); | |
| 3828 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 3829 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 3830 | 1, // ULEB128 dwarf expression length | |
| 3831 | reg.dwarfLocOp(), | |
| 3832 | }); | |
| 3833 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 3834 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 3835 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 3820 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { | |
| 3821 | .register => |reg| .{ .register = reg.dwarfLocOp() }, | |
| 3822 | .stack_offset => |off| .{ | |
| 3823 | .stack = .{ | |
| 3824 | // TODO handle -fomit-frame-pointer | |
| 3825 | .fp_register = Register.rbp.dwarfLocOpDeref(), | |
| 3826 | .offset = -off, | |
| 3827 | }, | |
| 3836 | 3828 | }, |
| 3829 | else => unreachable, // not a valid function parameter | |
| 3830 | }; | |
| 3831 | try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc); | |
| 3832 | }, | |
| 3833 | .plan9 => {}, | |
| 3834 | .none => {}, | |
| 3835 | } | |
| 3836 | } | |
| 3837 | 3837 | |
| 3838 | .stack_offset => |off| { | |
| 3839 | try dbg_info.ensureUnusedCapacity(8); | |
| 3840 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 3841 | const fixup = dbg_info.items.len; | |
| 3842 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 3843 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 3844 | Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer | |
| 3845 | }); | |
| 3846 | leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; | |
| 3847 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 3848 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 3849 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 3850 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 3838 | fn genVarDbgInfo( | |
| 3839 | self: Self, | |
| 3840 | tag: Air.Inst.Tag, | |
| 3841 | ty: Type, | |
| 3842 | mcv: MCValue, | |
| 3843 | name: [:0]const u8, | |
| 3844 | ) !void { | |
| 3845 | const is_ptr = switch (tag) { | |
| 3846 | .dbg_var_ptr => true, | |
| 3847 | .dbg_var_val => false, | |
| 3848 | else => unreachable, | |
| 3849 | }; | |
| 3851 | 3850 | |
| 3851 | switch (self.debug_output) { | |
| 3852 | .dwarf => |dw| { | |
| 3853 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { | |
| 3854 | .register => |reg| .{ .register = reg.dwarfLocOp() }, | |
| 3855 | .ptr_stack_offset, | |
| 3856 | .stack_offset, | |
| 3857 | => |off| .{ .stack = .{ | |
| 3858 | .fp_register = Register.rbp.dwarfLocOpDeref(), | |
| 3859 | .offset = -off, | |
| 3860 | } }, | |
| 3861 | .memory => |address| .{ .memory = address }, | |
| 3862 | .linker_load => |linker_load| .{ .linker_load = linker_load }, | |
| 3863 | .immediate => |x| .{ .immediate = x }, | |
| 3864 | .undef => .undef, | |
| 3865 | .none => .none, | |
| 3866 | else => blk: { | |
| 3867 | log.debug("TODO generate debug info for {}", .{mcv}); | |
| 3868 | break :blk .nop; | |
| 3852 | 3869 | }, |
| 3853 | ||
| 3854 | else => unreachable, // not a valid function parameter | |
| 3855 | } | |
| 3870 | }; | |
| 3871 | try dw.genVarDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, is_ptr, loc); | |
| 3856 | 3872 | }, |
| 3857 | 3873 | .plan9 => {}, |
| 3858 | 3874 | .none => {}, |
| ... | ... | @@ -4418,172 +4434,11 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4418 | 4434 | const name = self.air.nullTerminatedString(pl_op.payload); |
| 4419 | 4435 | |
| 4420 | 4436 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4421 | switch (tag) { | |
| 4422 | .dbg_var_ptr => try self.genVarDbgInfo(tag, ty.childType(), mcv, name), | |
| 4423 | .dbg_var_val => try self.genVarDbgInfo(tag, ty, mcv, name), | |
| 4424 | else => unreachable, | |
| 4425 | } | |
| 4437 | try self.genVarDbgInfo(tag, ty, mcv, name); | |
| 4426 | 4438 | |
| 4427 | 4439 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); |
| 4428 | 4440 | } |
| 4429 | 4441 | |
| 4430 | fn genVarDbgInfo( | |
| 4431 | self: Self, | |
| 4432 | tag: Air.Inst.Tag, | |
| 4433 | ty: Type, | |
| 4434 | mcv: MCValue, | |
| 4435 | name: [:0]const u8, | |
| 4436 | ) !void { | |
| 4437 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 4438 | switch (self.debug_output) { | |
| 4439 | .dwarf => |dw| { | |
| 4440 | const dbg_info = &dw.dbg_info; | |
| 4441 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); | |
| 4442 | const endian = self.target.cpu.arch.endian(); | |
| 4443 | ||
| 4444 | switch (mcv) { | |
| 4445 | .register => |reg| { | |
| 4446 | try dbg_info.ensureUnusedCapacity(2); | |
| 4447 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 4448 | 1, // ULEB128 dwarf expression length | |
| 4449 | reg.dwarfLocOp(), | |
| 4450 | }); | |
| 4451 | }, | |
| 4452 | ||
| 4453 | .ptr_stack_offset, | |
| 4454 | .stack_offset, | |
| 4455 | => |off| { | |
| 4456 | try dbg_info.ensureUnusedCapacity(7); | |
| 4457 | const fixup = dbg_info.items.len; | |
| 4458 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 4459 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 4460 | Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer | |
| 4461 | }); | |
| 4462 | leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; | |
| 4463 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 4464 | }, | |
| 4465 | ||
| 4466 | .memory, | |
| 4467 | .linker_load, | |
| 4468 | => { | |
| 4469 | const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)); | |
| 4470 | const is_ptr = switch (tag) { | |
| 4471 | .dbg_var_ptr => true, | |
| 4472 | .dbg_var_val => false, | |
| 4473 | else => unreachable, | |
| 4474 | }; | |
| 4475 | try dbg_info.ensureUnusedCapacity(2 + ptr_width); | |
| 4476 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 4477 | 1 + ptr_width + @boolToInt(is_ptr), | |
| 4478 | DW.OP.addr, // literal address | |
| 4479 | }); | |
| 4480 | const offset = @intCast(u32, dbg_info.items.len); | |
| 4481 | const addr = switch (mcv) { | |
| 4482 | .memory => |addr| addr, | |
| 4483 | else => 0, | |
| 4484 | }; | |
| 4485 | switch (ptr_width) { | |
| 4486 | 0...4 => { | |
| 4487 | try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian); | |
| 4488 | }, | |
| 4489 | 5...8 => { | |
| 4490 | try dbg_info.writer().writeInt(u64, addr, endian); | |
| 4491 | }, | |
| 4492 | else => unreachable, | |
| 4493 | } | |
| 4494 | if (is_ptr) { | |
| 4495 | // We need deref the address as we point to the value via GOT entry. | |
| 4496 | try dbg_info.append(DW.OP.deref); | |
| 4497 | } | |
| 4498 | switch (mcv) { | |
| 4499 | .linker_load => |load_struct| try dw.addExprlocReloc( | |
| 4500 | load_struct.sym_index, | |
| 4501 | offset, | |
| 4502 | is_ptr, | |
| 4503 | ), | |
| 4504 | else => {}, | |
| 4505 | } | |
| 4506 | }, | |
| 4507 | ||
| 4508 | .immediate => |x| { | |
| 4509 | try dbg_info.ensureUnusedCapacity(2); | |
| 4510 | const fixup = dbg_info.items.len; | |
| 4511 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 4512 | 1, | |
| 4513 | if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu, | |
| 4514 | }); | |
| 4515 | if (ty.isSignedInt()) { | |
| 4516 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); | |
| 4517 | } else { | |
| 4518 | try leb128.writeULEB128(dbg_info.writer(), x); | |
| 4519 | } | |
| 4520 | try dbg_info.append(DW.OP.stack_value); | |
| 4521 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 4522 | }, | |
| 4523 | ||
| 4524 | .undef => { | |
| 4525 | // DW.AT.location, DW.FORM.exprloc | |
| 4526 | // uleb128(exprloc_len) | |
| 4527 | // DW.OP.implicit_value uleb128(len_of_bytes) bytes | |
| 4528 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | |
| 4529 | var implicit_value_len = std.ArrayList(u8).init(self.gpa); | |
| 4530 | defer implicit_value_len.deinit(); | |
| 4531 | try leb128.writeULEB128(implicit_value_len.writer(), abi_size); | |
| 4532 | const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size; | |
| 4533 | try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len); | |
| 4534 | try dbg_info.ensureUnusedCapacity(total_exprloc_len); | |
| 4535 | dbg_info.appendAssumeCapacity(DW.OP.implicit_value); | |
| 4536 | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); | |
| 4537 | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); | |
| 4538 | }, | |
| 4539 | ||
| 4540 | .none => { | |
| 4541 | try dbg_info.ensureUnusedCapacity(3); | |
| 4542 | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 4543 | 2, DW.OP.lit0, DW.OP.stack_value, | |
| 4544 | }); | |
| 4545 | }, | |
| 4546 | ||
| 4547 | else => { | |
| 4548 | try dbg_info.ensureUnusedCapacity(2); | |
| 4549 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 4550 | 1, DW.OP.nop, | |
| 4551 | }); | |
| 4552 | log.debug("TODO generate debug info for {}", .{mcv}); | |
| 4553 | }, | |
| 4554 | } | |
| 4555 | ||
| 4556 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 4557 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 4558 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 4559 | }, | |
| 4560 | .plan9 => {}, | |
| 4561 | .none => {}, | |
| 4562 | } | |
| 4563 | } | |
| 4564 | ||
| 4565 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | |
| 4566 | /// after codegen for this symbol is done. | |
| 4567 | fn addDbgInfoTypeReloc(self: Self, ty: Type) !void { | |
| 4568 | switch (self.debug_output) { | |
| 4569 | .dwarf => |dw| { | |
| 4570 | const dbg_info = &dw.dbg_info; | |
| 4571 | const index = dbg_info.items.len; | |
| 4572 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 4573 | const mod = self.bin_file.options.module.?; | |
| 4574 | const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl); | |
| 4575 | const atom = switch (self.bin_file.tag) { | |
| 4576 | .elf => &fn_owner_decl.link.elf.dbg_info_atom, | |
| 4577 | .macho => &fn_owner_decl.link.macho.dbg_info_atom, | |
| 4578 | else => unreachable, | |
| 4579 | }; | |
| 4580 | try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); | |
| 4581 | }, | |
| 4582 | .plan9 => {}, | |
| 4583 | .none => {}, | |
| 4584 | } | |
| 4585 | } | |
| 4586 | ||
| 4587 | 4442 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { |
| 4588 | 4443 | const abi_size = ty.abiSize(self.target.*); |
| 4589 | 4444 | switch (mcv) { |
src/codegen.zig+13| ... | ... | @@ -68,6 +68,19 @@ pub const DebugInfoOutput = union(enum) { |
| 68 | 68 | none, |
| 69 | 69 | }; |
| 70 | 70 | |
| 71 | /// Helper struct to denote that the value is in memory but requires a linker relocation fixup: | |
| 72 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) | |
| 73 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) | |
| 74 | /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) | |
| 75 | pub const LinkerLoad = struct { | |
| 76 | type: enum { | |
| 77 | got, | |
| 78 | direct, | |
| 79 | import, | |
| 80 | }, | |
| 81 | sym_index: u32, | |
| 82 | }; | |
| 83 | ||
| 71 | 84 | pub fn generateFunction( |
| 72 | 85 | bin_file: *link.File, |
| 73 | 86 | src_loc: Module.SrcLoc, |
src/link/Dwarf.zig+231-3| ... | ... | @@ -16,6 +16,7 @@ const DW = std.dwarf; |
| 16 | 16 | const File = link.File; |
| 17 | 17 | const LinkBlock = File.LinkBlock; |
| 18 | 18 | const LinkFn = File.LinkFn; |
| 19 | const LinkerLoad = @import("../codegen.zig").LinkerLoad; | |
| 19 | 20 | const Module = @import("../Module.zig"); |
| 20 | 21 | const Value = @import("../value.zig").Value; |
| 21 | 22 | const Type = @import("../type.zig").Type; |
| ... | ... | @@ -101,7 +102,7 @@ pub const DeclState = struct { |
| 101 | 102 | self.exprloc_relocs.deinit(self.gpa); |
| 102 | 103 | } |
| 103 | 104 | |
| 104 | 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 { | |
| 105 | 106 | log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr }); |
| 106 | 107 | try self.exprloc_relocs.append(self.gpa, .{ |
| 107 | 108 | .type = if (is_ptr) .got_load else .direct_load, |
| ... | ... | @@ -112,7 +113,7 @@ pub const DeclState = struct { |
| 112 | 113 | |
| 113 | 114 | /// Adds local type relocation of the form: @offset => @this + addend |
| 114 | 115 | /// @this signifies the offset within the .debug_abbrev section of the containing atom. |
| 115 | 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 { | |
| 116 | 117 | log.debug("{x}: @this + {x}", .{ offset, addend }); |
| 117 | 118 | try self.abbrev_relocs.append(self.gpa, .{ |
| 118 | 119 | .target = null, |
| ... | ... | @@ -125,7 +126,7 @@ pub const DeclState = struct { |
| 125 | 126 | /// Adds global type relocation of the form: @offset => @symbol + 0 |
| 126 | 127 | /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section |
| 127 | 128 | /// which we use as our target of the relocation. |
| 128 | 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 { | |
| 129 | 130 | const resolv = self.abbrev_resolver.getContext(ty, .{ |
| 130 | 131 | .mod = self.mod, |
| 131 | 132 | }) orelse blk: { |
| ... | ... | @@ -560,6 +561,233 @@ pub const DeclState = struct { |
| 560 | 561 | }, |
| 561 | 562 | } |
| 562 | 563 | } |
| 564 | ||
| 565 | pub const DbgInfoLoc = union(enum) { | |
| 566 | register: u8, | |
| 567 | stack: struct { | |
| 568 | fp_register: u8, | |
| 569 | offset: i32, | |
| 570 | }, | |
| 571 | wasm_local: u32, | |
| 572 | memory: u64, | |
| 573 | linker_load: LinkerLoad, | |
| 574 | immediate: u64, | |
| 575 | undef, | |
| 576 | none, | |
| 577 | nop, | |
| 578 | }; | |
| 579 | ||
| 580 | pub fn genArgDbgInfo( | |
| 581 | self: *DeclState, | |
| 582 | name: [:0]const u8, | |
| 583 | ty: Type, | |
| 584 | tag: File.Tag, | |
| 585 | owner_decl: Module.Decl.Index, | |
| 586 | loc: DbgInfoLoc, | |
| 587 | ) error{OutOfMemory}!void { | |
| 588 | const dbg_info = &self.dbg_info; | |
| 589 | const atom = self.getDbgInfoAtom(tag, owner_decl); | |
| 590 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 591 | ||
| 592 | switch (loc) { | |
| 593 | .register => |reg| { | |
| 594 | try dbg_info.ensureUnusedCapacity(3); | |
| 595 | dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter)); | |
| 596 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 597 | 1, // ULEB128 dwarf expression length | |
| 598 | reg, | |
| 599 | }); | |
| 600 | }, | |
| 601 | .stack => |info| { | |
| 602 | try dbg_info.ensureUnusedCapacity(8); | |
| 603 | dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter)); | |
| 604 | const fixup = dbg_info.items.len; | |
| 605 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 606 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 607 | info.fp_register, // frame pointer | |
| 608 | }); | |
| 609 | leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable; | |
| 610 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 611 | }, | |
| 612 | .wasm_local => |value| { | |
| 613 | const leb_size = link.File.Wasm.getULEB128Size(value); | |
| 614 | try dbg_info.ensureUnusedCapacity(3 + leb_size); | |
| 615 | // wasm locations are encoded as follow: | |
| 616 | // DW_OP_WASM_location wasm-op | |
| 617 | // where wasm-op is defined as | |
| 618 | // wasm-op := wasm-local | wasm-global | wasm-operand_stack | |
| 619 | // where each argument is encoded as | |
| 620 | // <opcode> i:uleb128 | |
| 621 | dbg_info.appendSliceAssumeCapacity(&.{ | |
| 622 | @enumToInt(AbbrevKind.parameter), | |
| 623 | DW.OP.WASM_location, | |
| 624 | DW.OP.WASM_local, | |
| 625 | }); | |
| 626 | leb128.writeULEB128(dbg_info.writer(), value) catch unreachable; | |
| 627 | }, | |
| 628 | else => unreachable, | |
| 629 | } | |
| 630 | ||
| 631 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 632 | const index = dbg_info.items.len; | |
| 633 | try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 | |
| 634 | try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4 | |
| 635 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 636 | } | |
| 637 | ||
| 638 | pub fn genVarDbgInfo( | |
| 639 | self: *DeclState, | |
| 640 | name: [:0]const u8, | |
| 641 | ty: Type, | |
| 642 | tag: File.Tag, | |
| 643 | owner_decl: Module.Decl.Index, | |
| 644 | is_ptr: bool, | |
| 645 | loc: DbgInfoLoc, | |
| 646 | ) error{OutOfMemory}!void { | |
| 647 | const dbg_info = &self.dbg_info; | |
| 648 | const atom = self.getDbgInfoAtom(tag, owner_decl); | |
| 649 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 650 | try dbg_info.append(@enumToInt(AbbrevKind.variable)); | |
| 651 | const target = self.mod.getTarget(); | |
| 652 | const endian = target.cpu.arch.endian(); | |
| 653 | const child_ty = if (is_ptr) ty.childType() else ty; | |
| 654 | ||
| 655 | switch (loc) { | |
| 656 | .register => |reg| { | |
| 657 | try dbg_info.ensureUnusedCapacity(2); | |
| 658 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 659 | 1, // ULEB128 dwarf expression length | |
| 660 | reg, | |
| 661 | }); | |
| 662 | }, | |
| 663 | ||
| 664 | .stack => |info| { | |
| 665 | try dbg_info.ensureUnusedCapacity(7); | |
| 666 | const fixup = dbg_info.items.len; | |
| 667 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 668 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 669 | info.fp_register, | |
| 670 | }); | |
| 671 | leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable; | |
| 672 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 673 | }, | |
| 674 | ||
| 675 | .wasm_local => |value| { | |
| 676 | const leb_size = link.File.Wasm.getULEB128Size(value); | |
| 677 | try dbg_info.ensureUnusedCapacity(2 + leb_size); | |
| 678 | // wasm locals are encoded as follow: | |
| 679 | // DW_OP_WASM_location wasm-op | |
| 680 | // where wasm-op is defined as | |
| 681 | // wasm-op := wasm-local | wasm-global | wasm-operand_stack | |
| 682 | // where wasm-local is encoded as | |
| 683 | // wasm-local := 0x00 i:uleb128 | |
| 684 | dbg_info.appendSliceAssumeCapacity(&.{ | |
| 685 | DW.OP.WASM_location, | |
| 686 | DW.OP.WASM_local, | |
| 687 | }); | |
| 688 | leb128.writeULEB128(dbg_info.writer(), value) catch unreachable; | |
| 689 | }, | |
| 690 | ||
| 691 | .memory, | |
| 692 | .linker_load, | |
| 693 | => { | |
| 694 | const ptr_width = @intCast(u8, @divExact(target.cpu.arch.ptrBitWidth(), 8)); | |
| 695 | try dbg_info.ensureUnusedCapacity(2 + ptr_width); | |
| 696 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 697 | 1 + ptr_width + @boolToInt(is_ptr), | |
| 698 | DW.OP.addr, // literal address | |
| 699 | }); | |
| 700 | const offset = @intCast(u32, dbg_info.items.len); | |
| 701 | const addr = switch (loc) { | |
| 702 | .memory => |x| x, | |
| 703 | else => 0, | |
| 704 | }; | |
| 705 | switch (ptr_width) { | |
| 706 | 0...4 => { | |
| 707 | try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian); | |
| 708 | }, | |
| 709 | 5...8 => { | |
| 710 | try dbg_info.writer().writeInt(u64, addr, endian); | |
| 711 | }, | |
| 712 | else => unreachable, | |
| 713 | } | |
| 714 | if (is_ptr) { | |
| 715 | // We need deref the address as we point to the value via GOT entry. | |
| 716 | try dbg_info.append(DW.OP.deref); | |
| 717 | } | |
| 718 | switch (loc) { | |
| 719 | .linker_load => |load_struct| try self.addExprlocReloc( | |
| 720 | load_struct.sym_index, | |
| 721 | offset, | |
| 722 | is_ptr, | |
| 723 | ), | |
| 724 | else => {}, | |
| 725 | } | |
| 726 | }, | |
| 727 | ||
| 728 | .immediate => |x| { | |
| 729 | try dbg_info.ensureUnusedCapacity(2); | |
| 730 | const fixup = dbg_info.items.len; | |
| 731 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 732 | 1, | |
| 733 | if (child_ty.isSignedInt()) DW.OP.consts else DW.OP.constu, | |
| 734 | }); | |
| 735 | if (child_ty.isSignedInt()) { | |
| 736 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); | |
| 737 | } else { | |
| 738 | try leb128.writeULEB128(dbg_info.writer(), x); | |
| 739 | } | |
| 740 | try dbg_info.append(DW.OP.stack_value); | |
| 741 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 742 | }, | |
| 743 | ||
| 744 | .undef => { | |
| 745 | // DW.AT.location, DW.FORM.exprloc | |
| 746 | // uleb128(exprloc_len) | |
| 747 | // DW.OP.implicit_value uleb128(len_of_bytes) bytes | |
| 748 | const abi_size = @intCast(u32, child_ty.abiSize(target)); | |
| 749 | var implicit_value_len = std.ArrayList(u8).init(self.gpa); | |
| 750 | defer implicit_value_len.deinit(); | |
| 751 | try leb128.writeULEB128(implicit_value_len.writer(), abi_size); | |
| 752 | const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size; | |
| 753 | try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len); | |
| 754 | try dbg_info.ensureUnusedCapacity(total_exprloc_len); | |
| 755 | dbg_info.appendAssumeCapacity(DW.OP.implicit_value); | |
| 756 | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); | |
| 757 | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); | |
| 758 | }, | |
| 759 | ||
| 760 | .none => { | |
| 761 | try dbg_info.ensureUnusedCapacity(3); | |
| 762 | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 763 | 2, DW.OP.lit0, DW.OP.stack_value, | |
| 764 | }); | |
| 765 | }, | |
| 766 | ||
| 767 | .nop => { | |
| 768 | try dbg_info.ensureUnusedCapacity(2); | |
| 769 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 770 | 1, DW.OP.nop, | |
| 771 | }); | |
| 772 | }, | |
| 773 | } | |
| 774 | ||
| 775 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 776 | const index = dbg_info.items.len; | |
| 777 | try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 | |
| 778 | try self.addTypeRelocGlobal(atom, child_ty, @intCast(u32, index)); | |
| 779 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 780 | } | |
| 781 | ||
| 782 | fn getDbgInfoAtom(self: *DeclState, tag: File.Tag, decl_index: Module.Decl.Index) *Atom { | |
| 783 | const decl = self.mod.declPtr(decl_index); | |
| 784 | return switch (tag) { | |
| 785 | .elf => &decl.link.elf.dbg_info_atom, | |
| 786 | .macho => &decl.link.macho.dbg_info_atom, | |
| 787 | .wasm => &decl.link.wasm.dbg_info_atom, | |
| 788 | else => unreachable, | |
| 789 | }; | |
| 790 | } | |
| 563 | 791 | }; |
| 564 | 792 | |
| 565 | 793 | pub const AbbrevEntry = struct { |