Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -40,8 +40,8 @@ // For --discard-{all,locals,none}. enum class DiscardPolicy { Default, All, Locals, None }; -// For --strip-{all,debug}. -enum class StripPolicy { None, All, Debug }; +// For --strip-{all,debug-non-line,debug}. +enum class StripPolicy { None, All, DebugNonLine, Debug }; // For --unresolved-symbols. enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll }; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -498,12 +498,16 @@ if (Args.hasArg(OPT_relocatable)) return StripPolicy::None; - auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug); + auto *Arg = + Args.getLastArg(OPT_strip_all, OPT_strip_debug, OPT_strip_debug_non_line); if (!Arg) return StripPolicy::None; - if (Arg->getOption().getID() == OPT_strip_all) + auto ID = Arg->getOption().getID(); + if (ID == OPT_strip_all) return StripPolicy::All; - return StripPolicy::Debug; + else if (ID == OPT_strip_debug) + return StripPolicy::Debug; + return StripPolicy::DebugNonLine; } static uint64_t parseSectionAddress(StringRef S, const opt::Arg &Arg) { @@ -1298,12 +1302,26 @@ for (InputSectionBase *S : F->getSections()) InputSections.push_back(cast(S)); - // We do not want to emit debug sections if --strip-all - // or -strip-debug are given. - if (Config->Strip != StripPolicy::None) + // We do not want to emit any debug sections if --strip-all or + // --strip-debug are given. If --strip-debug-non-line is specified, + // emit only the sections used for line info. + if (Config->Strip == StripPolicy::All || + Config->Strip == StripPolicy::Debug) { llvm::erase_if(InputSections, [](InputSectionBase *S) { return S->Name.startswith(".debug") || S->Name.startswith(".zdebug"); }); + } else if (Config->Strip == StripPolicy::DebugNonLine) { + llvm::erase_if(InputSections, [](InputSectionBase *S) { + return StringSwitch(S->Name) + .EndsWith("debug_abbrev", false) + .EndsWith("debug_info", false) + .EndsWith("debug_line", false) + .EndsWith("debug_str", false) + .StartsWith(".debug", true) + .StartsWith(".zdebug", true) + .Default(false); + }); + } Config->EFlags = Target->calcEFlags(); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -290,6 +290,9 @@ def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; +def strip_debug_non_line: F<"strip-debug-non-line">, + HelpText<"Emit only debug line number information">; + defm symbol_ordering_file: Eq<"symbol-ordering-file">, HelpText<"Layout sections to place symbols in the order specified by symbol ordering file">; Index: docs/ld.lld.1 =================================================================== --- docs/ld.lld.1 +++ docs/ld.lld.1 @@ -324,6 +324,8 @@ in an archive. .It Fl -strip-all Strip all symbols. +.It Fl -strip-debug-non-line +Emit only debug line number information. .It Fl -strip-debug Strip debugging information. .It Fl -symbol-ordering-file Ns = Ns Ar file Index: test/ELF/strip-debug-non-line.s =================================================================== --- /dev/null +++ test/ELF/strip-debug-non-line.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 +# RUN: llvm-mc -g -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 --strip-debug-non-line +# RUN: llvm-readobj -sections -symbols %t2 | FileCheck %s + +# CHECK: Name: .{{z?}}debug_info +# CHECK: Name: .{{z?}}debug_abbrev +# CHECK-NOT: Name: .{{z?}}debug_aranges +# CHECK: Name: .{{z?}}debug_line + +# exits with return code 42 on linux +.globl _start +_start: + mov $60, %rax + mov $42, %rdi + syscall