From d026202a26e56e7e2ea20ca49509fdcf8b937020 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Thu, 6 Apr 2023 10:16:20 +0200 Subject: [PATCH 1/2] Expose an option for producing 64-bit DWARF format This commit enables producing 64-bit DWARF format for Zig executables that are produced through the LLVM backend. This is achieved by exposing both command-line flags and CompileStep flags. The production of the 64-bit format only affects binaries that use the DWARF format and it is disabled on MacOS due to it being problematic. This commit, despite generating the interface for the Zig user to be able to tell the compile which format is wanted, is just implemented for the LLVM backend, so clang and the self-hosted backends will need this to be implemented in a future commit. This is an effort to work around #7962, since the emission of the 64-bit format automatically produces 64-bit relocations. Further investigation will be needed to make DWARF 32-bit format to emit bigger relocations when needed and not make the linker angry. --- lib/std/Build/CompileStep.zig | 9 +++++++++ lib/std/dwarf.zig | 5 +++++ src/Compilation.zig | 2 ++ src/codegen/llvm.zig | 9 ++++++++- src/codegen/llvm/bindings.zig | 2 +- src/link.zig | 2 ++ src/main.zig | 6 ++++++ src/zig_llvm.cpp | 6 +++++- src/zig_llvm.h | 2 +- 9 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/std/Build/CompileStep.zig b/lib/std/Build/CompileStep.zig index 9340ec8d99..2c51d58852 100644 --- a/lib/std/Build/CompileStep.zig +++ b/lib/std/Build/CompileStep.zig @@ -69,6 +69,7 @@ disable_stack_probing: bool, disable_sanitize_c: bool, sanitize_thread: bool, rdynamic: bool, +dwarf_format: ?std.dwarf.Format = null, import_memory: bool = false, /// For WebAssembly targets, this will allow for undefined symbols to /// be imported from the host environment. @@ -1449,6 +1450,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try addFlag(&zig_args, "strip", self.strip); try addFlag(&zig_args, "unwind-tables", self.unwind_tables); + if (!self.producesPdbFile()) { + if (self.dwarf_format) |dwarf_format| { + try zig_args.append(switch (dwarf_format) { + .dwarf32 => "-gdwarf32", + .dwarf64 => "-gdwarf64", + }); + } + } switch (self.compress_debug_sections) { .none => {}, diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 99dff14c36..505a5cb886 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -147,6 +147,11 @@ pub const CC = enum(u8) { GNU_borland_fastcall_i386 = 0x41, }; +pub const Format = enum { + dwarf32, + dwarf64, +}; + const PcRange = struct { start: u64, end: u64, diff --git a/src/Compilation.zig b/src/Compilation.zig index 48a0412b23..848b1594fa 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -620,6 +620,7 @@ pub const InitOptions = struct { test_name_prefix: ?[]const u8 = null, test_runner_path: ?[]const u8 = null, subsystem: ?std.Target.SubSystem = null, + dwarf_format: ?std.dwarf.Format = null, /// WASI-only. Type of WASI execution model ("command" or "reactor"). wasi_exec_model: ?std.builtin.WasiExecModel = null, /// (Zig compiler development) Enable dumping linker's state as JSON. @@ -1517,6 +1518,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, .subsystem = options.subsystem, .is_test = options.is_test, + .dwarf_format = options.dwarf_format, .wasi_exec_model = wasi_exec_model, .hash_style = options.hash_style, .enable_link_snapshots = options.enable_link_snapshots, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 47b47cc807..23d9af39e0 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -433,7 +433,14 @@ pub const Object = struct { if (!options.strip) { switch (options.target.ofmt) { .coff => llvm_module.addModuleCodeViewFlag(), - else => llvm_module.addModuleDebugInfoFlag(), + else => { + const dwarf_format = options.dwarf_format orelse .dwarf32; + const produce_dwarf64 = switch (dwarf_format) { + .dwarf32 => false, + .dwarf64 => true, + }; + llvm_module.addModuleDebugInfoFlag(produce_dwarf64); + }, } const di_builder = llvm_module.createDIBuilder(true); opt_di_builder = di_builder; diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 63cac80db8..55f0ba8963 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -409,7 +409,7 @@ pub const Module = opaque { extern fn LLVMSetTarget(M: *Module, Triple: [*:0]const u8) void; pub const addModuleDebugInfoFlag = ZigLLVMAddModuleDebugInfoFlag; - extern fn ZigLLVMAddModuleDebugInfoFlag(module: *Module) void; + extern fn ZigLLVMAddModuleDebugInfoFlag(module: *Module, dwarf64: bool) void; pub const addModuleCodeViewFlag = ZigLLVMAddModuleCodeViewFlag; extern fn ZigLLVMAddModuleCodeViewFlag(module: *Module) void; diff --git a/src/link.zig b/src/link.zig index c8999cee47..a0a1bdad94 100644 --- a/src/link.zig +++ b/src/link.zig @@ -200,6 +200,8 @@ pub const Options = struct { compatibility_version: ?std.builtin.Version, libc_installation: ?*const LibCInstallation, + dwarf_format: ?std.dwarf.Format = null, + /// WASI-only. Type of WASI execution model ("command" or "reactor"). wasi_exec_model: std.builtin.WasiExecModel = undefined, diff --git a/src/main.zig b/src/main.zig index 2bc4961cba..81a83d580d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -844,6 +844,7 @@ fn buildOutputType( var reference_trace: ?u32 = null; var error_tracing: ?bool = null; var pdb_out_path: ?[]const u8 = null; + var dwarf_format: ?std.dwarf.Format = null; // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. // This array is populated by zig cc frontend and then has to be converted to zig-style @@ -1355,6 +1356,10 @@ fn buildOutputType( strip = true; } else if (mem.eql(u8, arg, "-fno-strip")) { strip = false; + } else if (mem.eql(u8, arg, "-gdwarf32")) { + dwarf_format = .dwarf32; + } else if (mem.eql(u8, arg, "-gdwarf64")) { + dwarf_format = .dwarf64; } else if (mem.eql(u8, arg, "-fformatted-panics")) { formatted_panics = true; } else if (mem.eql(u8, arg, "-fno-formatted-panics")) { @@ -3145,6 +3150,7 @@ fn buildOutputType( .test_runner_path = test_runner_path, .disable_lld_caching = !output_to_cache, .subsystem = subsystem, + .dwarf_format = dwarf_format, .wasi_exec_model = wasi_exec_model, .debug_compile_errors = debug_compile_errors, .enable_link_snapshots = enable_link_snapshots, diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index a884420422..af53bd1d27 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -1163,9 +1163,13 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, free(native_triple); } -void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module) { +void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module, bool produce_dwarf64) { unwrap(module)->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION); unwrap(module)->addModuleFlag(Module::Warning, "Dwarf Version", 4); + + if (produce_dwarf64) { + unwrap(module)->addModuleFlag(Module::Warning, "DWARF64", 1); + } } void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) { diff --git a/src/zig_llvm.h b/src/zig_llvm.h index e466be9e8c..8f24d045a2 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -238,7 +238,7 @@ ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void); ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder); -ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); +ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module, bool produce_dwarf64); ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module); ZIG_EXTERN_C void ZigLLVMSetModulePICLevel(LLVMModuleRef module); ZIG_EXTERN_C void ZigLLVMSetModulePIELevel(LLVMModuleRef module); From ceff2782029672714ac2e04a7b3e25af23eb9a9b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Apr 2023 15:09:33 -0700 Subject: [PATCH 2/2] fixes to the previous commit * CompileStep: Avoid calling producesPdbFile() to determine whether the option should be respected. If the user asks for it, put it on the command line and let the Zig CLI deal with it appropriately. * Make the namespace of `std.dwarf.Format.dwarf32` no longer have a redundant "dwarf" in it. * Add `zig cc` integration for `-gdwarf32` and `-gdwarf64`. * Toss in a bonus bug fix for `-gdwarf-2`, `-gdwarf-3`, etc. * Avoid using default init values for struct fields unnecessarily. * Add missing cache hash addition for the new option. --- lib/std/Build/CompileStep.zig | 13 ++++--- lib/std/dwarf.zig | 5 +-- src/Compilation.zig | 9 ++++- src/clang_options_data.zig | 63 ++++++++++++++++++++++++++++++---- src/codegen/llvm.zig | 9 +---- src/link.zig | 2 +- src/main.zig | 14 ++++++-- tools/update_clang_options.zig | 18 +++++++--- 8 files changed, 98 insertions(+), 35 deletions(-) diff --git a/lib/std/Build/CompileStep.zig b/lib/std/Build/CompileStep.zig index 2c51d58852..b71298ce6a 100644 --- a/lib/std/Build/CompileStep.zig +++ b/lib/std/Build/CompileStep.zig @@ -1450,13 +1450,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try addFlag(&zig_args, "strip", self.strip); try addFlag(&zig_args, "unwind-tables", self.unwind_tables); - if (!self.producesPdbFile()) { - if (self.dwarf_format) |dwarf_format| { - try zig_args.append(switch (dwarf_format) { - .dwarf32 => "-gdwarf32", - .dwarf64 => "-gdwarf64", - }); - } + + if (self.dwarf_format) |dwarf_format| { + try zig_args.append(switch (dwarf_format) { + .@"32" => "-gdwarf32", + .@"64" => "-gdwarf64", + }); } switch (self.compress_debug_sections) { diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 505a5cb886..d7b4e29947 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -147,10 +147,7 @@ pub const CC = enum(u8) { GNU_borland_fastcall_i386 = 0x41, }; -pub const Format = enum { - dwarf32, - dwarf64, -}; +pub const Format = enum { @"32", @"64" }; const PcRange = struct { start: u64, diff --git a/src/Compilation.zig b/src/Compilation.zig index 848b1594fa..a07ac417e3 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1112,6 +1112,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { cache.hash.add(link_libunwind); cache.hash.add(options.output_mode); cache.hash.add(options.machine_code_model); + cache.hash.addOptional(options.dwarf_format); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib); cache.hash.addBytes(options.root_name); @@ -4490,7 +4491,13 @@ pub fn addCCArgs( // generation, it only changes the type of information generated. try argv.appendSlice(&.{ "-g", "-gcodeview" }); }, - .elf, .macho => try argv.append("-gdwarf-4"), + .elf, .macho => { + try argv.append("-gdwarf-4"); + if (comp.bin_file.options.dwarf_format) |f| switch (f) { + .@"32" => try argv.append("-gdwarf32"), + .@"64" => try argv.append("-gdwarf64"), + }; + }, else => try argv.append("-g"), } } diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index fc23d86964..c342cf7777 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -3870,13 +3870,62 @@ flagpd1("gcodeview-command-line"), flagpd1("gcodeview-ghash"), flagpd1("gcolumn-info"), flagpd1("gdbx"), -flagpd1("gdwarf"), -flagpd1("gdwarf32"), -flagpd1("gdwarf64"), -flagpd1("gdwarf-2"), -flagpd1("gdwarf-3"), -flagpd1("gdwarf-4"), -flagpd1("gdwarf-5"), +.{ + .name = "gdwarf", + .syntax = .flag, + .zig_equivalent = .debug, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "gdwarf32", + .syntax = .flag, + .zig_equivalent = .gdwarf32, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "gdwarf64", + .syntax = .flag, + .zig_equivalent = .gdwarf64, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "gdwarf-2", + .syntax = .flag, + .zig_equivalent = .debug, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "gdwarf-3", + .syntax = .flag, + .zig_equivalent = .debug, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "gdwarf-4", + .syntax = .flag, + .zig_equivalent = .debug, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "gdwarf-5", + .syntax = .flag, + .zig_equivalent = .debug, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("gdwarf-aranges"), flagpd1("gembed-source"), sepd1("gen-cdb-fragment-path"), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 23d9af39e0..a081448155 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -433,14 +433,7 @@ pub const Object = struct { if (!options.strip) { switch (options.target.ofmt) { .coff => llvm_module.addModuleCodeViewFlag(), - else => { - const dwarf_format = options.dwarf_format orelse .dwarf32; - const produce_dwarf64 = switch (dwarf_format) { - .dwarf32 => false, - .dwarf64 => true, - }; - llvm_module.addModuleDebugInfoFlag(produce_dwarf64); - }, + else => llvm_module.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"), } const di_builder = llvm_module.createDIBuilder(true); opt_di_builder = di_builder; diff --git a/src/link.zig b/src/link.zig index a0a1bdad94..672a53999f 100644 --- a/src/link.zig +++ b/src/link.zig @@ -200,7 +200,7 @@ pub const Options = struct { compatibility_version: ?std.builtin.Version, libc_installation: ?*const LibCInstallation, - dwarf_format: ?std.dwarf.Format = null, + dwarf_format: ?std.dwarf.Format, /// WASI-only. Type of WASI execution model ("command" or "reactor"). wasi_exec_model: std.builtin.WasiExecModel = undefined, diff --git a/src/main.zig b/src/main.zig index 81a83d580d..6a83791ca3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1357,9 +1357,9 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-strip")) { strip = false; } else if (mem.eql(u8, arg, "-gdwarf32")) { - dwarf_format = .dwarf32; + dwarf_format = .@"32"; } else if (mem.eql(u8, arg, "-gdwarf64")) { - dwarf_format = .dwarf64; + dwarf_format = .@"64"; } else if (mem.eql(u8, arg, "-fformatted-panics")) { formatted_panics = true; } else if (mem.eql(u8, arg, "-fno-formatted-panics")) { @@ -1767,6 +1767,14 @@ fn buildOutputType( try clang_argv.appendSlice(it.other_args); } }, + .gdwarf32 => { + strip = false; + dwarf_format = .@"32"; + }, + .gdwarf64 => { + strip = false; + dwarf_format = .@"64"; + }, .sanitize => { if (mem.eql(u8, it.only_arg, "undefined")) { want_sanitize_c = true; @@ -5108,6 +5116,8 @@ pub const ClangArgIterator = struct { asm_only, optimize, debug, + gdwarf32, + gdwarf64, sanitize, linker_script, dry_run, diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index cf7d72595b..7639d08ce3 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -241,23 +241,31 @@ const known_options = [_]KnownOpt{ .ident = "debug", }, .{ - .name = "g-dwarf", + .name = "gdwarf32", + .ident = "gdwarf32", + }, + .{ + .name = "gdwarf64", + .ident = "gdwarf64", + }, + .{ + .name = "gdwarf", .ident = "debug", }, .{ - .name = "g-dwarf-2", + .name = "gdwarf-2", .ident = "debug", }, .{ - .name = "g-dwarf-3", + .name = "gdwarf-3", .ident = "debug", }, .{ - .name = "g-dwarf-4", + .name = "gdwarf-4", .ident = "debug", }, .{ - .name = "g-dwarf-5", + .name = "gdwarf-5", .ident = "debug", }, .{