authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-07 15:43:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-08 14:58:53-07:00
logc6160fa3a5c2f55871c2ab2377531c8a4e34a76a
treecbee981048b3a1e0a1c51b3b9292017967f7df07
parent95fc41b2b433ccfa751c8877ec7edac3b9bffbd6

LLVM: add compile unit to debug info

This commit also adds a bunch of bindings for debug info.

4 files changed, 362 insertions(+), 8 deletions(-)

src/Compilation.zig+1-1
...@@ -898,7 +898,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -898,7 +898,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
898 // We put the `Compilation` itself in the arena. Freeing the arena will free the module.898 // We put the `Compilation` itself in the arena. Freeing the arena will free the module.
899 // It's initialized later after we prepare the initialization options.899 // It's initialized later after we prepare the initialization options.
900 const comp = try arena.create(Compilation);900 const comp = try arena.create(Compilation);
901 const root_name = try arena.dupe(u8, options.root_name);901 const root_name = try arena.dupeZ(u8, options.root_name);
902902
903 const ofmt = options.object_format orelse options.target.getObjectFormat();903 const ofmt = options.object_format orelse options.target.getObjectFormat();
904904
src/codegen/llvm.zig+61-5
...@@ -5,12 +5,14 @@ const Allocator = std.mem.Allocator;...@@ -5,12 +5,14 @@ const Allocator = std.mem.Allocator;
5const log = std.log.scoped(.codegen);5const log = std.log.scoped(.codegen);
6const math = std.math;6const math = std.math;
7const native_endian = builtin.cpu.arch.endian();7const native_endian = builtin.cpu.arch.endian();
8const DW = std.dwarf;
89
9const llvm = @import("llvm/bindings.zig");10const llvm = @import("llvm/bindings.zig");
10const link = @import("../link.zig");11const link = @import("../link.zig");
11const Compilation = @import("../Compilation.zig");12const Compilation = @import("../Compilation.zig");
12const build_options = @import("build_options");13const build_options = @import("build_options");
13const Module = @import("../Module.zig");14const Module = @import("../Module.zig");
15const Package = @import("../Package.zig");
14const TypedValue = @import("../TypedValue.zig");16const TypedValue = @import("../TypedValue.zig");
15const Air = @import("../Air.zig");17const Air = @import("../Air.zig");
16const Liveness = @import("../Liveness.zig");18const Liveness = @import("../Liveness.zig");
...@@ -159,6 +161,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {...@@ -159,6 +161,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
159161
160pub const Object = struct {162pub const Object = struct {
161 llvm_module: *const llvm.Module,163 llvm_module: *const llvm.Module,
164 dibuilder: ?*llvm.DIBuilder,
162 context: *const llvm.Context,165 context: *const llvm.Context,
163 target_machine: *const llvm.TargetMachine,166 target_machine: *const llvm.TargetMachine,
164 target_data: *const llvm.TargetData,167 target_data: *const llvm.TargetData,
...@@ -180,8 +183,9 @@ pub const Object = struct {...@@ -180,8 +183,9 @@ pub const Object = struct {
180 /// The backing memory for `type_map`. Periodically garbage collected after flush().183 /// The backing memory for `type_map`. Periodically garbage collected after flush().
181 /// The code for doing the periodical GC is not yet implemented.184 /// The code for doing the periodical GC is not yet implemented.
182 type_map_arena: std.heap.ArenaAllocator,185 type_map_arena: std.heap.ArenaAllocator,
183 /// The LLVM global table which holds the names corresponding to Zig errors. Note that the values186 /// The LLVM global table which holds the names corresponding to Zig errors.
184 /// are not added until flushModule, when all errors in the compilation are known.187 /// Note that the values are not added until flushModule, when all errors in
188 /// the compilation are known.
185 error_name_table: ?*const llvm.Value,189 error_name_table: ?*const llvm.Value,
186190
187 pub const TypeMap = std.HashMapUnmanaged(191 pub const TypeMap = std.HashMapUnmanaged(
...@@ -204,9 +208,7 @@ pub const Object = struct {...@@ -204,9 +208,7 @@ pub const Object = struct {
204208
205 initializeLLVMTarget(options.target.cpu.arch);209 initializeLLVMTarget(options.target.cpu.arch);
206210
207 const root_nameZ = try gpa.dupeZ(u8, options.root_name);211 const llvm_module = llvm.Module.createWithName(options.root_name.ptr, context);
208 defer gpa.free(root_nameZ);
209 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);
210 errdefer llvm_module.dispose();212 errdefer llvm_module.dispose();
211213
212 const llvm_target_triple = try targetTriple(gpa, options.target);214 const llvm_target_triple = try targetTriple(gpa, options.target);
...@@ -221,6 +223,58 @@ pub const Object = struct {...@@ -221,6 +223,58 @@ pub const Object = struct {
221 return error.InvalidLlvmTriple;223 return error.InvalidLlvmTriple;
222 }224 }
223225
226 llvm_module.setTarget(llvm_target_triple.ptr);
227 var opt_dbuilder: ?*llvm.DIBuilder = null;
228 errdefer if (opt_dbuilder) |dibuilder| dibuilder.dispose();
229
230 if (!options.strip) {
231 switch (options.object_format) {
232 .coff => llvm_module.addModuleCodeViewFlag(),
233 else => llvm_module.addModuleDebugInfoFlag(),
234 }
235 const dibuilder = llvm_module.createDIBuilder(true);
236 opt_dbuilder = dibuilder;
237
238 // Don't use the version string here; LLVM misparses it when it
239 // includes the git revision.
240 const producer = try std.fmt.allocPrintZ(gpa, "zig {d}.{d}.{d}", .{
241 build_options.semver.major,
242 build_options.semver.minor,
243 build_options.semver.patch,
244 });
245 defer gpa.free(producer);
246
247 // For macOS stack traces, we want to avoid having to parse the compilation unit debug
248 // info. As long as each debug info file has a path independent of the compilation unit
249 // directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug
250 // info. If we provide an absolute path to LLVM here for the compilation unit debug
251 // info, LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we
252 // pass "." for the compilation unit directory. This forces each debug file to have a
253 // directory rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug
254 // files will no longer reference DW_AT_comp_dir, for the purpose of being able to
255 // support the common practice of stripping all but the line number sections from an
256 // executable.
257 const compile_unit_dir = d: {
258 if (options.target.isDarwin()) break :d ".";
259 const mod = options.module orelse break :d ".";
260 break :d mod.root_pkg.root_src_directory.path orelse ".";
261 };
262 const compile_unit_dir_z = try gpa.dupeZ(u8, compile_unit_dir);
263 defer gpa.free(compile_unit_dir_z);
264
265 _ = dibuilder.createCompileUnit(
266 DW.LANG.C99,
267 dibuilder.createFile(options.root_name, compile_unit_dir_z),
268 producer,
269 options.optimize_mode != .Debug,
270 "", // flags
271 0, // runtime version
272 "", // split name
273 0, // dwo id
274 true, // emit debug info
275 );
276 }
277
224 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)278 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)
225 .None279 .None
226 else280 else
...@@ -266,6 +320,7 @@ pub const Object = struct {...@@ -266,6 +320,7 @@ pub const Object = struct {
266320
267 return Object{321 return Object{
268 .llvm_module = llvm_module,322 .llvm_module = llvm_module,
323 .dibuilder = opt_dbuilder,
269 .context = context,324 .context = context,
270 .target_machine = target_machine,325 .target_machine = target_machine,
271 .target_data = target_data,326 .target_data = target_data,
...@@ -277,6 +332,7 @@ pub const Object = struct {...@@ -277,6 +332,7 @@ pub const Object = struct {
277 }332 }
278333
279 pub fn deinit(self: *Object, gpa: Allocator) void {334 pub fn deinit(self: *Object, gpa: Allocator) void {
335 if (self.dibuilder) |dib| dib.dispose();
280 self.target_data.dispose();336 self.target_data.dispose();
281 self.target_machine.dispose();337 self.target_machine.dispose();
282 self.llvm_module.dispose();338 self.llvm_module.dispose();
src/codegen/llvm/bindings.zig+299-1
...@@ -184,6 +184,9 @@ pub const Value = opaque {...@@ -184,6 +184,9 @@ pub const Value = opaque {
184 pub const setFunctionCallConv = LLVMSetFunctionCallConv;184 pub const setFunctionCallConv = LLVMSetFunctionCallConv;
185 extern fn LLVMSetFunctionCallConv(Fn: *const Value, CC: CallConv) void;185 extern fn LLVMSetFunctionCallConv(Fn: *const Value, CC: CallConv) void;
186186
187 pub const fnSetSubprogram = ZigLLVMFnSetSubprogram;
188 extern fn ZigLLVMFnSetSubprogram(f: *const Value, subprogram: *DISubprogram) void;
189
187 pub const setValueName = LLVMSetValueName;190 pub const setValueName = LLVMSetValueName;
188 extern fn LLVMSetValueName(Val: *const Value, Name: [*:0]const u8) void;191 extern fn LLVMSetValueName(Val: *const Value, Name: [*:0]const u8) void;
189192
...@@ -354,6 +357,18 @@ pub const Module = opaque {...@@ -354,6 +357,18 @@ pub const Module = opaque {
354 Name: [*:0]const u8,357 Name: [*:0]const u8,
355 NameLen: usize,358 NameLen: usize,
356 ) ?*const Value;359 ) ?*const Value;
360
361 pub const setTarget = LLVMSetTarget;
362 extern fn LLVMSetTarget(M: *const Module, Triple: [*:0]const u8) void;
363
364 pub const addModuleDebugInfoFlag = ZigLLVMAddModuleDebugInfoFlag;
365 extern fn ZigLLVMAddModuleDebugInfoFlag(module: *const Module) void;
366
367 pub const addModuleCodeViewFlag = ZigLLVMAddModuleCodeViewFlag;
368 extern fn ZigLLVMAddModuleCodeViewFlag(module: *const Module) void;
369
370 pub const createDIBuilder = ZigLLVMCreateDIBuilder;
371 extern fn ZigLLVMCreateDIBuilder(module: *const Module, allow_unresolved: bool) *DIBuilder;
357};372};
358373
359pub const lookupIntrinsicID = LLVMLookupIntrinsicID;374pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
...@@ -1203,7 +1218,7 @@ pub const WriteImportLibrary = ZigLLVMWriteImportLibrary;...@@ -1203,7 +1218,7 @@ pub const WriteImportLibrary = ZigLLVMWriteImportLibrary;
1203extern fn ZigLLVMWriteImportLibrary(1218extern fn ZigLLVMWriteImportLibrary(
1204 def_path: [*:0]const u8,1219 def_path: [*:0]const u8,
1205 arch: ArchType,1220 arch: ArchType,
1206 output_lib_path: [*c]const u8,1221 output_lib_path: [*:0]const u8,
1207 kill_at: bool,1222 kill_at: bool,
1208) bool;1223) bool;
12091224
...@@ -1400,3 +1415,286 @@ pub const address_space = struct {...@@ -1400,3 +1415,286 @@ pub const address_space = struct {
1400 pub const constant_buffer_15: c_uint = 23;1415 pub const constant_buffer_15: c_uint = 23;
1401 };1416 };
1402};1417};
1418
1419pub const DIEnumerator = opaque {};
1420pub const DILocalVariable = opaque {};
1421pub const DIGlobalVariable = opaque {};
1422pub const DILocation = opaque {};
1423
1424pub const DIType = opaque {
1425 pub const toScope = ZigLLVMTypeToScope;
1426 extern fn ZigLLVMTypeToScope(ty: *DIType) *DIScope;
1427};
1428pub const DIFile = opaque {
1429 pub const toScope = ZigLLVMFileToScope;
1430 extern fn ZigLLVMFileToScope(difile: *DIFile) *DIScope;
1431};
1432pub const DILexicalBlock = opaque {
1433 pub const toScope = ZigLLVMLexicalBlockToScope;
1434 extern fn ZigLLVMLexicalBlockToScope(lexical_block: *DILexicalBlock) *DIScope;
1435};
1436pub const DICompileUnit = opaque {
1437 pub const toScope = ZigLLVMCompileUnitToScope;
1438 extern fn ZigLLVMCompileUnitToScope(compile_unit: *DICompileUnit) *DIScope;
1439};
1440pub const DISubprogram = opaque {
1441 pub const toScope = ZigLLVMSubprogramToScope;
1442 extern fn ZigLLVMSubprogramToScope(subprogram: *DISubprogram) *DIScope;
1443};
1444
1445pub const getDebugLoc = ZigLLVMGetDebugLoc;
1446extern fn ZigLLVMGetDebugLoc(line: c_uint, col: c_uint, scope: *DIScope) *DILocation;
1447
1448pub const DIBuilder = opaque {
1449 pub const dispose = ZigLLVMDisposeDIBuilder;
1450 extern fn ZigLLVMDisposeDIBuilder(dib: *DIBuilder) void;
1451
1452 pub const finalize = ZigLLVMDIBuilderFinalize;
1453 extern fn ZigLLVMDIBuilderFinalize(dib: *DIBuilder) void;
1454
1455 pub const createPointerType = ZigLLVMCreateDebugPointerType;
1456 extern fn ZigLLVMCreateDebugPointerType(
1457 dib: *DIBuilder,
1458 pointee_type: *DIType,
1459 size_in_bits: u64,
1460 align_in_bits: u64,
1461 name: [*:0]const u8,
1462 ) *DIType;
1463
1464 pub const createBasicType = ZigLLVMCreateDebugBasicType;
1465 extern fn ZigLLVMCreateDebugBasicType(
1466 dib: *DIBuilder,
1467 name: [*:0]const u8,
1468 size_in_bits: u64,
1469 encoding: c_uint,
1470 ) *DIType;
1471
1472 pub const createArrayType = ZigLLVMCreateDebugArrayType;
1473 extern fn ZigLLVMCreateDebugArrayType(
1474 dib: *DIBuilder,
1475 size_in_bits: u64,
1476 align_in_bits: u64,
1477 elem_type: *DIType,
1478 elem_count: c_int,
1479 ) *DIType;
1480
1481 pub const createEnumerator = ZigLLVMCreateDebugEnumerator;
1482 extern fn ZigLLVMCreateDebugEnumerator(
1483 dib: *DIBuilder,
1484 name: [*:0]const u8,
1485 val: i64,
1486 ) *DIEnumerator;
1487
1488 pub const createEnumerationType = ZigLLVMCreateDebugEnumerationType;
1489 extern fn ZigLLVMCreateDebugEnumerationType(
1490 dib: *DIBuilder,
1491 scope: *DIScope,
1492 name: [*:0]const u8,
1493 file: *DIFile,
1494 line_number: c_uint,
1495 size_in_bits: u64,
1496 align_in_bits: u64,
1497 enumerator_array: [*]const *DIEnumerator,
1498 enumerator_array_len: c_int,
1499 underlying_type: *DIType,
1500 unique_id: [*:0]const u8,
1501 ) *DIType;
1502
1503 pub const createStructType = ZigLLVMCreateDebugStructType;
1504 extern fn ZigLLVMCreateDebugStructType(
1505 dib: *DIBuilder,
1506 scope: *DIScope,
1507 name: [*:0]const u8,
1508 file: *DIFile,
1509 line_number: c_uint,
1510 size_in_bits: u64,
1511 align_in_bits: u64,
1512 flags: c_uint,
1513 derived_from: *DIType,
1514 types_array: [*]const *DIType,
1515 types_array_len: c_int,
1516 run_time_lang: c_uint,
1517 vtable_holder: *DIType,
1518 unique_id: [*:0]const u8,
1519 ) *DIType;
1520
1521 pub const createUnionType = ZigLLVMCreateDebugUnionType;
1522 extern fn ZigLLVMCreateDebugUnionType(
1523 dib: *DIBuilder,
1524 scope: *DIScope,
1525 name: [*:0]const u8,
1526 file: *DIFile,
1527 line_number: c_uint,
1528 size_in_bits: u64,
1529 align_in_bits: u64,
1530 flags: c_uint,
1531 types_array: [*]const *DIType,
1532 types_array_len: c_int,
1533 run_time_lang: c_uint,
1534 unique_id: [*:0]const u8,
1535 ) *DIType;
1536
1537 pub const createMemberType = ZigLLVMCreateDebugMemberType;
1538 extern fn ZigLLVMCreateDebugMemberType(
1539 dib: *DIBuilder,
1540 scope: *DIScope,
1541 name: [*:0]const u8,
1542 file: *DIFile,
1543 line: c_uint,
1544 size_in_bits: u64,
1545 align_in_bits: u64,
1546 offset_in_bits: u64,
1547 flags: c_uint,
1548 ty: *DIType,
1549 ) *DIType;
1550
1551 pub const createReplaceableCompositeType = ZigLLVMCreateReplaceableCompositeType;
1552 extern fn ZigLLVMCreateReplaceableCompositeType(
1553 dib: *DIBuilder,
1554 tag: c_uint,
1555 name: [*:0]const u8,
1556 scope: *DIScope,
1557 file: *DIFile,
1558 line: c_uint,
1559 ) *DIType;
1560
1561 pub const createForwardDeclType = ZigLLVMCreateDebugForwardDeclType;
1562 extern fn ZigLLVMCreateDebugForwardDeclType(
1563 dib: *DIBuilder,
1564 tag: c_uint,
1565 name: [*:0]const u8,
1566 scope: *DIScope,
1567 file: *DIFile,
1568 line: c_uint,
1569 ) *DIType;
1570
1571 pub const replaceTemporary = ZigLLVMReplaceTemporary;
1572 extern fn ZigLLVMReplaceTemporary(dib: *DIBuilder, ty: *DIType, replacement: *DIType) void;
1573
1574 pub const replaceDebugArrays = ZigLLVMReplaceDebugArrays;
1575 extern fn ZigLLVMReplaceDebugArrays(
1576 dib: *DIBuilder,
1577 ty: *DIType,
1578 types_array: [*]const *DIType,
1579 types_array_len: c_int,
1580 ) void;
1581
1582 pub const createSubroutineType = ZigLLVMCreateSubroutineType;
1583 extern fn ZigLLVMCreateSubroutineType(
1584 dib: *DIBuilder,
1585 types_array: [*]const *DIType,
1586 types_array_len: c_int,
1587 flags: c_uint,
1588 ) *DIType;
1589
1590 pub const createAutoVariable = ZigLLVMCreateAutoVariable;
1591 extern fn ZigLLVMCreateAutoVariable(
1592 dib: *DIBuilder,
1593 scope: *DIScope,
1594 name: [*:0]const u8,
1595 file: *DIFile,
1596 line_no: c_uint,
1597 ty: *DIType,
1598 always_preserve: bool,
1599 flags: c_uint,
1600 ) *DILocalVariable;
1601
1602 pub const createGlobalVariable = ZigLLVMCreateGlobalVariable;
1603 extern fn ZigLLVMCreateGlobalVariable(
1604 dib: *DIBuilder,
1605 scope: *DIScope,
1606 name: [*:0]const u8,
1607 linkage_name: [*:0]const u8,
1608 file: *DIFile,
1609 line_no: c_uint,
1610 di_type: *DIType,
1611 is_local_to_unit: bool,
1612 ) *DIGlobalVariable;
1613
1614 pub const createParameterVariable = ZigLLVMCreateParameterVariable;
1615 extern fn ZigLLVMCreateParameterVariable(
1616 dib: *DIBuilder,
1617 scope: *DIScope,
1618 name: [*:0]const u8,
1619 file: *DIFile,
1620 line_no: c_uint,
1621 ty: *DIType,
1622 always_preserve: bool,
1623 flags: c_uint,
1624 arg_no: c_uint,
1625 ) *DILocalVariable;
1626
1627 pub const createLexicalBlock = ZigLLVMCreateLexicalBlock;
1628 extern fn ZigLLVMCreateLexicalBlock(
1629 dib: *DIBuilder,
1630 scope: *DIScope,
1631 file: *DIFile,
1632 line: c_uint,
1633 col: c_uint,
1634 ) *DILexicalBlock;
1635
1636 pub const createCompileUnit = ZigLLVMCreateCompileUnit;
1637 extern fn ZigLLVMCreateCompileUnit(
1638 dib: *DIBuilder,
1639 lang: c_uint,
1640 difile: *DIFile,
1641 producer: [*:0]const u8,
1642 is_optimized: bool,
1643 flags: [*:0]const u8,
1644 runtime_version: c_uint,
1645 split_name: [*:0]const u8,
1646 dwo_id: u64,
1647 emit_debug_info: bool,
1648 ) *DICompileUnit;
1649
1650 pub const createFile = ZigLLVMCreateFile;
1651 extern fn ZigLLVMCreateFile(
1652 dib: *DIBuilder,
1653 filename: [*:0]const u8,
1654 directory: [*:0]const u8,
1655 ) *DIFile;
1656
1657 pub const createFunction = ZigLLVMCreateFunction;
1658 extern fn ZigLLVMCreateFunction(
1659 dib: *DIBuilder,
1660 scope: *DIScope,
1661 name: [*:0]const u8,
1662 linkage_name: [*:0]const u8,
1663 file: *DIFile,
1664 lineno: c_uint,
1665 fn_di_type: *DIType,
1666 is_local_to_unit: bool,
1667 is_definition: bool,
1668 scope_line: c_uint,
1669 flags: c_uint,
1670 is_optimized: bool,
1671 decl_subprogram: *DISubprogram,
1672 ) *DISubprogram;
1673
1674 pub const createVectorType = ZigLLVMDIBuilderCreateVectorType;
1675 extern fn ZigLLVMDIBuilderCreateVectorType(
1676 dib: *DIBuilder,
1677 SizeInBits: u64,
1678 AlignInBits: u32,
1679 Ty: *DIType,
1680 elem_count: u32,
1681 ) *DIType;
1682
1683 pub const insertDeclareAtEnd = ZigLLVMInsertDeclareAtEnd;
1684 extern fn ZigLLVMInsertDeclareAtEnd(
1685 dib: *DIBuilder,
1686 storage: *const Value,
1687 var_info: *DILocalVariable,
1688 debug_loc: *DILocation,
1689 basic_block_ref: *const BasicBlock,
1690 ) *const Value;
1691
1692 pub const insertDeclare = ZigLLVMInsertDeclare;
1693 extern fn ZigLLVMInsertDeclare(
1694 dib: *DIBuilder,
1695 storage: *const Value,
1696 var_info: *DILocalVariable,
1697 debug_loc: *DILocation,
1698 insert_before_instr: *const Value,
1699 ) *const Value;
1700};
src/link.zig+1-1
...@@ -72,7 +72,7 @@ pub const Options = struct {...@@ -72,7 +72,7 @@ pub const Options = struct {
72 object_format: std.Target.ObjectFormat,72 object_format: std.Target.ObjectFormat,
73 optimize_mode: std.builtin.Mode,73 optimize_mode: std.builtin.Mode,
74 machine_code_model: std.builtin.CodeModel,74 machine_code_model: std.builtin.CodeModel,
75 root_name: []const u8,75 root_name: [:0]const u8,
76 /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.76 /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
77 module: ?*Module,77 module: ?*Module,
78 dynamic_linker: ?[]const u8,78 dynamic_linker: ?[]const u8,