| 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,11 +146,8 @@ const MCValue = union(enum) { |
| 146 | /// If the type is a pointer, it means the pointer address is at | 146 | /// If the type is a pointer, it means the pointer address is at |
| 147 | /// this memory location. | 147 | /// this memory location. |
| 148 | memory: u64, | 148 | memory: u64, |
| 149 | /// The value is in memory but requires a linker relocation fixup: | 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) | 150 | linker_load: codegen.LinkerLoad, |
| 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 }, | ||
| 154 | /// The value is one of the stack variables. | 151 | /// The value is one of the stack variables. |
| 155 | /// | 152 | /// |
| 156 | /// If the type is a pointer, it means the pointer address is in | 153 | /// If the type is a pointer, it means the pointer address is in |
| ... | @@ -184,52 +181,34 @@ const DbgInfoReloc = struct { | ... | @@ -184,52 +181,34 @@ const DbgInfoReloc = struct { |
| 184 | else => unreachable, | 181 | else => unreachable, |
| 185 | } | 182 | } |
| 186 | } | 183 | } |
| 187 | |||
| 188 | fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void { | 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 | switch (function.debug_output) { | 185 | switch (function.debug_output) { |
| 192 | .dwarf => |dw| { | 186 | .dwarf => |dw| { |
| 193 | const dbg_info = &dw.dbg_info; | 187 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) { |
| 194 | switch (reloc.mcv) { | 188 | .register => |reg| .{ .register = reg.dwarfLocOp() }, |
| 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 | |||
| 207 | .stack_offset, | 189 | .stack_offset, |
| 208 | .stack_argument_offset, | 190 | .stack_argument_offset, |
| 209 | => |offset| { | 191 | => |offset| blk: { |
| 210 | const adjusted_offset = switch (reloc.mcv) { | 192 | const adjusted_offset = switch (reloc.mcv) { |
| 211 | .stack_offset => -@intCast(i32, offset), | 193 | .stack_offset => -@intCast(i32, offset), |
| 212 | .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset), | 194 | .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset), |
| 213 | else => unreachable, | 195 | else => unreachable, |
| 214 | }; | 196 | }; |
| 215 | 197 | break :blk .{ .stack = .{ | |
| 216 | try dbg_info.ensureUnusedCapacity(8); | 198 | .fp_register = Register.x29.dwarfLocOpDeref(), |
| 217 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | 199 | .offset = adjusted_offset, |
| 218 | const fixup = dbg_info.items.len; | 200 | } }; |
| 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 | |||
| 229 | }, | 201 | }, |
| 230 | |||
| 231 | else => unreachable, // not a possible argument | 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 | .plan9 => {}, | 213 | .plan9 => {}, |
| 235 | .none => {}, | 214 | .none => {}, |
| ... | @@ -237,32 +216,20 @@ const DbgInfoReloc = struct { | ... | @@ -237,32 +216,20 @@ const DbgInfoReloc = struct { |
| 237 | } | 216 | } |
| 238 | 217 | ||
| 239 | fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void { | 218 | fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void { |
| 240 | const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1]; | 219 | const is_ptr = switch (reloc.tag) { |
| 241 | const ty = switch (reloc.tag) { | 220 | .dbg_var_ptr => true, |
| 242 | .dbg_var_ptr => reloc.ty.childType(), | 221 | .dbg_var_val => false, |
| 243 | .dbg_var_val => reloc.ty, | ||
| 244 | else => unreachable, | 222 | else => unreachable, |
| 245 | }; | 223 | }; |
| 246 | 224 | ||
| 247 | switch (function.debug_output) { | 225 | switch (function.debug_output) { |
| 248 | .dwarf => |dw| { | 226 | .dwarf => |dw| { |
| 249 | const dbg_info = &dw.dbg_info; | 227 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) { |
| 250 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); | 228 | .register => |reg| .{ .register = reg.dwarfLocOp() }, |
| 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 | |||
| 262 | .ptr_stack_offset, | 229 | .ptr_stack_offset, |
| 263 | .stack_offset, | 230 | .stack_offset, |
| 264 | .stack_argument_offset, | 231 | .stack_argument_offset, |
| 265 | => |offset| { | 232 | => |offset| blk: { |
| 266 | const adjusted_offset = switch (reloc.mcv) { | 233 | const adjusted_offset = switch (reloc.mcv) { |
| 267 | .ptr_stack_offset, | 234 | .ptr_stack_offset, |
| 268 | .stack_offset, | 235 | .stack_offset, |
| ... | @@ -270,110 +237,31 @@ const DbgInfoReloc = struct { | ... | @@ -270,110 +237,31 @@ const DbgInfoReloc = struct { |
| 270 | .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset), | 237 | .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset), |
| 271 | else => unreachable, | 238 | else => unreachable, |
| 272 | }; | 239 | }; |
| 273 | 240 | break :blk .{ | |
| 274 | try dbg_info.ensureUnusedCapacity(7); | 241 | .stack = .{ |
| 275 | const fixup = dbg_info.items.len; | 242 | .fp_register = Register.x29.dwarfLocOpDeref(), |
| 276 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 243 | .offset = adjusted_offset, |
| 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); | ||
| 306 | }, | 244 | }, |
| 307 | 5...8 => { | 245 | }; |
| 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 | }); | ||
| 363 | }, | 246 | }, |
| 364 | 247 | .memory => |address| .{ .memory = address }, | |
| 365 | else => { | 248 | .linker_load => |linker_load| .{ .linker_load = linker_load }, |
| 366 | try dbg_info.ensureUnusedCapacity(2); | 249 | .immediate => |x| .{ .immediate = x }, |
| 367 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 250 | .undef => .undef, |
| 368 | 1, DW.OP.nop, | 251 | .none => .none, |
| 369 | }); | 252 | else => blk: { |
| 370 | log.debug("TODO generate debug info for {}", .{reloc.mcv}); | 253 | log.debug("TODO generate debug info for {}", .{reloc.mcv}); |
| 254 | break :blk .nop; | ||
| 371 | }, | 255 | }, |
| 372 | } | 256 | }; |
| 373 | 257 | try dw.genVarDbgInfo( | |
| 374 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | 258 | reloc.name, |
| 375 | try function.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | 259 | reloc.ty, |
| 376 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | 260 | function.bin_file.tag, |
| 261 | function.mod_fn.owner_decl, | ||
| 262 | is_ptr, | ||
| 263 | loc, | ||
| 264 | ); | ||
| 377 | }, | 265 | }, |
| 378 | .plan9 => {}, | 266 | .plan9 => {}, |
| 379 | .none => {}, | 267 | .none => {}, |
| ... | @@ -1079,28 +967,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -1079,28 +967,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 1079 | try table.ensureUnusedCapacity(self.gpa, additional_count); | 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 | fn allocMem( | 970 | fn allocMem( |
| 1105 | self: *Self, | 971 | self: *Self, |
| 1106 | abi_size: u32, | 972 | abi_size: u32, |
src/arch/arm/CodeGen.zig+18-69| ... | @@ -4029,86 +4029,35 @@ fn genInlineMemsetCode( | ... | @@ -4029,86 +4029,35 @@ fn genInlineMemsetCode( |
| 4029 | // end: | 4029 | // end: |
| 4030 | } | 4030 | } |
| 4031 | 4031 | ||
| 4032 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | 4032 | fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void { |
| 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 { | ||
| 4055 | const mcv = self.args[arg_index]; | 4033 | const mcv = self.args[arg_index]; |
| 4056 | const ty = self.air.instructions.items(.data)[inst].ty; | 4034 | const ty = self.air.instructions.items(.data)[inst].ty; |
| 4057 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); | 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) { | 4037 | switch (self.debug_output) { |
| 4061 | .register => |reg| { | 4038 | .dwarf => |dw| { |
| 4062 | switch (self.debug_output) { | 4039 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { |
| 4063 | .dwarf => |dw| { | 4040 | .register => |reg| .{ .register = reg.dwarfLocOp() }, |
| 4064 | const dbg_info = &dw.dbg_info; | 4041 | .stack_offset, |
| 4065 | try dbg_info.ensureUnusedCapacity(3); | 4042 | .stack_argument_offset, |
| 4066 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | 4043 | => blk: { |
| 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| { | ||
| 4084 | const adjusted_stack_offset = switch (mcv) { | 4044 | const adjusted_stack_offset = switch (mcv) { |
| 4085 | .stack_offset => |offset| -@intCast(i32, offset), | 4045 | .stack_offset => |offset| -@intCast(i32, offset), |
| 4086 | .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset), | 4046 | .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset), |
| 4087 | else => unreachable, | 4047 | else => unreachable, |
| 4088 | }; | 4048 | }; |
| 4089 | 4049 | break :blk .{ .stack = .{ | |
| 4090 | const dbg_info = &dw.dbg_info; | 4050 | .fp_register = DW.OP.breg11, |
| 4091 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | 4051 | .offset = adjusted_stack_offset, |
| 4092 | 4052 | } }; | |
| 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 | ||
| 4106 | }, | 4053 | }, |
| 4107 | .plan9 => {}, | 4054 | else => unreachable, // not a possible argument |
| 4108 | .none => {}, | 4055 | |
| 4109 | } | 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,28 +772,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 772 | try table.ensureUnusedCapacity(self.gpa, additional_count); | 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 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { | 775 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { |
| 798 | if (abi_align > self.stack_align) | 776 | if (abi_align > self.stack_align) |
| 799 | self.stack_align = abi_align; | 777 | self.stack_align = abi_align; |
| ... | @@ -1624,39 +1602,24 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1624,39 +1602,24 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1624 | return self.fail("TODO implement codegen airFieldParentPtr", .{}); | 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 | const ty = self.air.instructions.items(.data)[inst].ty; | 1606 | const ty = self.air.instructions.items(.data)[inst].ty; |
| 1629 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); | 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) { | 1609 | switch (self.debug_output) { |
| 1633 | .register => |reg| { | 1610 | .dwarf => |dw| switch (mcv) { |
| 1634 | switch (self.debug_output) { | 1611 | .register => |reg| try dw.genArgDbgInfo( |
| 1635 | .dwarf => |dw| { | 1612 | name, |
| 1636 | const dbg_info = &dw.dbg_info; | 1613 | ty, |
| 1637 | try dbg_info.ensureUnusedCapacity(3); | 1614 | self.bin_file.tag, |
| 1638 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | 1615 | self.mod_fn.owner_decl, |
| 1639 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 1616 | .{ .register = reg.dwarfLocOp() }, |
| 1640 | 1, // ULEB128 dwarf expression length | 1617 | ), |
| 1641 | reg.dwarfLocOp(), | 1618 | .stack_offset => {}, |
| 1642 | }); | 1619 | else => {}, |
| 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 | } | ||
| 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,26 +2460,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2460 | 2460 | ||
| 2461 | // Common helper functions | 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 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | 2463 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 2484 | const gpa = self.gpa; | 2464 | const gpa = self.gpa; |
| 2485 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); | 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,35 +3252,20 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 3272 | self.finishAirBookkeeping(); | 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 | const ty = self.air.instructions.items(.data)[inst].ty; | 3256 | const ty = self.air.instructions.items(.data)[inst].ty; |
| 3277 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); | 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) { | 3259 | switch (self.debug_output) { |
| 3281 | .register => |reg| { | 3260 | .dwarf => |dw| switch (mcv) { |
| 3282 | switch (self.debug_output) { | 3261 | .register => |reg| try dw.genArgDbgInfo( |
| 3283 | .dwarf => |dw| { | 3262 | name, |
| 3284 | const dbg_info = &dw.dbg_info; | 3263 | ty, |
| 3285 | try dbg_info.ensureUnusedCapacity(3); | 3264 | self.bin_file.tag, |
| 3286 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | 3265 | self.mod_fn.owner_decl, |
| 3287 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 3266 | .{ .register = reg.dwarfLocOp() }, |
| 3288 | 1, // ULEB128 dwarf expression length | 3267 | ), |
| 3289 | reg.dwarfLocOp(), | 3268 | else => {}, |
| 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 | } | ||
| 3304 | }, | 3269 | }, |
| 3305 | else => {}, | 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,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,9 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2358,24 +2341,9 @@ 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 | try dwarf.genArgDbgInfo(name, arg_ty, .wasm, func.mod_fn.owner_decl, .{ |
| 2362 | const dbg_info = &dwarf.dbg_info; | 2345 | .wasm_local = arg.local.value, |
| 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, | ||
| 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 | else => {}, | 2348 | else => {}, |
| 2381 | } | 2349 | } |
| ... | @@ -5345,38 +5313,21 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { | ... | @@ -5345,38 +5313,21 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { |
| 5345 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 5313 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 5346 | const ty = func.air.typeOf(pl_op.operand); | 5314 | const ty = func.air.typeOf(pl_op.operand); |
| 5347 | const operand = try func.resolveInst(pl_op.operand); | 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 | const name = func.air.nullTerminatedString(pl_op.payload); | 5319 | const name = func.air.nullTerminatedString(pl_op.payload); |
| 5353 | log.debug(" var name = ({s})", .{name}); | 5320 | log.debug(" var name = ({s})", .{name}); |
| 5354 | 5321 | ||
| 5355 | const dbg_info = &func.debug_output.dwarf.dbg_info; | 5322 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (operand) { |
| 5356 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); | 5323 | .local => |local| .{ .wasm_local = local.value }, |
| 5357 | switch (operand) { | 5324 | else => blk: { |
| 5358 | .local => |local| { | 5325 | log.debug("TODO generate debug info for {}", .{operand}); |
| 5359 | const leb_size = link.File.Wasm.getULEB128Size(local.value); | 5326 | break :blk .nop; |
| 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; | ||
| 5372 | }, | 5327 | }, |
| 5373 | else => {}, // TODO | 5328 | }; |
| 5374 | } | 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 | func.finishAir(inst, .none, &.{}); | 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,11 +128,8 @@ pub const MCValue = union(enum) { |
| 128 | /// The value is in memory at a hard-coded address. | 128 | /// The value is in memory at a hard-coded address. |
| 129 | /// If the type is a pointer, it means the pointer address is at this memory location. | 129 | /// If the type is a pointer, it means the pointer address is at this memory location. |
| 130 | memory: u64, | 130 | memory: u64, |
| 131 | /// The value is in memory but requires a linker relocation fixup: | 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) | 132 | linker_load: codegen.LinkerLoad, |
| 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 }, | ||
| 136 | /// The value is one of the stack variables. | 133 | /// The value is one of the stack variables. |
| 137 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. | 134 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. |
| 138 | stack_offset: i32, | 135 | stack_offset: i32, |
| ... | @@ -3818,41 +3815,60 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3818,41 +3815,60 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3818 | } | 3815 | } |
| 3819 | 3816 | ||
| 3820 | fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { | 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 | switch (self.debug_output) { | 3818 | switch (self.debug_output) { |
| 3823 | .dwarf => |dw| { | 3819 | .dwarf => |dw| { |
| 3824 | const dbg_info = &dw.dbg_info; | 3820 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { |
| 3825 | switch (mcv) { | 3821 | .register => |reg| .{ .register = reg.dwarfLocOp() }, |
| 3826 | .register => |reg| { | 3822 | .stack_offset => |off| .{ |
| 3827 | try dbg_info.ensureUnusedCapacity(3); | 3823 | .stack = .{ |
| 3828 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | 3824 | // TODO handle -fomit-frame-pointer |
| 3829 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 3825 | .fp_register = Register.rbp.dwarfLocOpDeref(), |
| 3830 | 1, // ULEB128 dwarf expression length | 3826 | .offset = -off, |
| 3831 | reg.dwarfLocOp(), | 3827 | }, |
| 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 | ||
| 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| { | 3838 | fn genVarDbgInfo( |
| 3839 | try dbg_info.ensureUnusedCapacity(8); | 3839 | self: Self, |
| 3840 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | 3840 | tag: Air.Inst.Tag, |
| 3841 | const fixup = dbg_info.items.len; | 3841 | ty: Type, |
| 3842 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 3842 | mcv: MCValue, |
| 3843 | 1, // we will backpatch it after we encode the displacement in LEB128 | 3843 | name: [:0]const u8, |
| 3844 | Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer | 3844 | ) !void { |
| 3845 | }); | 3845 | const is_ptr = switch (tag) { |
| 3846 | leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; | 3846 | .dbg_var_ptr => true, |
| 3847 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | 3847 | .dbg_var_val => false, |
| 3848 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | 3848 | else => unreachable, |
| 3849 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | 3849 | }; |
| 3850 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | ||
| 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 | 3870 | }; | |
| 3854 | else => unreachable, // not a valid function parameter | 3871 | try dw.genVarDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, is_ptr, loc); |
| 3855 | } | ||
| 3856 | }, | 3872 | }, |
| 3857 | .plan9 => {}, | 3873 | .plan9 => {}, |
| 3858 | .none => {}, | 3874 | .none => {}, |
| ... | @@ -4418,172 +4434,11 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4418,172 +4434,11 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4418 | const name = self.air.nullTerminatedString(pl_op.payload); | 4434 | const name = self.air.nullTerminatedString(pl_op.payload); |
| 4419 | 4435 | ||
| 4420 | const tag = self.air.instructions.items(.tag)[inst]; | 4436 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4421 | switch (tag) { | 4437 | try self.genVarDbgInfo(tag, ty, mcv, name); |
| 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 | } | ||
| 4426 | 4438 | ||
| 4427 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); | 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 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { | 4442 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { |
| 4588 | const abi_size = ty.abiSize(self.target.*); | 4443 | const abi_size = ty.abiSize(self.target.*); |
| 4589 | switch (mcv) { | 4444 | switch (mcv) { |
src/codegen.zig+13| ... | @@ -68,6 +68,19 @@ pub const DebugInfoOutput = union(enum) { | ... | @@ -68,6 +68,19 @@ pub const DebugInfoOutput = union(enum) { |
| 68 | none, | 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 | pub fn generateFunction( | 84 | pub fn generateFunction( |
| 72 | bin_file: *link.File, | 85 | bin_file: *link.File, |
| 73 | src_loc: Module.SrcLoc, | 86 | src_loc: Module.SrcLoc, |
src/link/Dwarf.zig+231-3| ... | @@ -16,6 +16,7 @@ const DW = std.dwarf; | ... | @@ -16,6 +16,7 @@ const DW = std.dwarf; |
| 16 | const File = link.File; | 16 | const File = link.File; |
| 17 | const LinkBlock = File.LinkBlock; | 17 | const LinkBlock = File.LinkBlock; |
| 18 | const LinkFn = File.LinkFn; | 18 | const LinkFn = File.LinkFn; |
| 19 | const LinkerLoad = @import("../codegen.zig").LinkerLoad; | ||
| 19 | const Module = @import("../Module.zig"); | 20 | const Module = @import("../Module.zig"); |
| 20 | const Value = @import("../value.zig").Value; | 21 | const Value = @import("../value.zig").Value; |
| 21 | const Type = @import("../type.zig").Type; | 22 | const Type = @import("../type.zig").Type; |
| ... | @@ -101,7 +102,7 @@ pub const DeclState = struct { | ... | @@ -101,7 +102,7 @@ pub const DeclState = struct { |
| 101 | self.exprloc_relocs.deinit(self.gpa); | 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 | 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 }); |
| 106 | try self.exprloc_relocs.append(self.gpa, .{ | 107 | try self.exprloc_relocs.append(self.gpa, .{ |
| 107 | .type = if (is_ptr) .got_load else .direct_load, | 108 | .type = if (is_ptr) .got_load else .direct_load, |
| ... | @@ -112,7 +113,7 @@ pub const DeclState = struct { | ... | @@ -112,7 +113,7 @@ pub const DeclState = struct { |
| 112 | 113 | ||
| 113 | /// Adds local type relocation of the form: @offset => @this + addend | 114 | /// Adds local type relocation of the form: @offset => @this + addend |
| 114 | /// @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. |
| 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 | log.debug("{x}: @this + {x}", .{ offset, addend }); | 117 | log.debug("{x}: @this + {x}", .{ offset, addend }); |
| 117 | try self.abbrev_relocs.append(self.gpa, .{ | 118 | try self.abbrev_relocs.append(self.gpa, .{ |
| 118 | .target = null, | 119 | .target = null, |
| ... | @@ -125,7 +126,7 @@ pub const DeclState = struct { | ... | @@ -125,7 +126,7 @@ pub const DeclState = struct { |
| 125 | /// Adds global type relocation of the form: @offset => @symbol + 0 | 126 | /// Adds global type relocation of the form: @offset => @symbol + 0 |
| 126 | /// @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 |
| 127 | /// which we use as our target of the relocation. | 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 | const resolv = self.abbrev_resolver.getContext(ty, .{ | 130 | const resolv = self.abbrev_resolver.getContext(ty, .{ |
| 130 | .mod = self.mod, | 131 | .mod = self.mod, |
| 131 | }) orelse blk: { | 132 | }) orelse blk: { |
| ... | @@ -560,6 +561,233 @@ pub const DeclState = struct { | ... | @@ -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 | pub const AbbrevEntry = struct { | 793 | pub const AbbrevEntry = struct { |