[dsymutil] Add flag to force a static variable to keep its enclosing function

Add a flag to change dsymutil's behavior and force a static variable to
keep its enclosing function. The test shows a situation where that could
be useful. I'm not convinced this behavior makes sense as a default,
which is why it's behind a flag.

rdar://74918374

Differential revision: https://reviews.llvm.org/D101337
This commit is contained in:
Jonas Devlieghere 2021-04-26 18:20:49 -07:00
parent 8a4ee3b39c
commit 625bd94c6d
11 changed files with 72 additions and 7 deletions

View File

@ -50,6 +50,11 @@ OPTIONS
Print this help output. Print this help output.
.. option:: --keep-function-for-static
Make a static variable keep the enclosing function even if it would have been
omitted otherwise.
.. option:: --minimize, -z .. option:: --minimize, -z
When used when creating a dSYM file, this option will suppress the emission of When used when creating a dSYM file, this option will suppress the emission of

View File

@ -281,6 +281,11 @@ public:
/// update existing DWARF info(for the linked binary). /// update existing DWARF info(for the linked binary).
void setUpdate(bool Update) { Options.Update = Update; } void setUpdate(bool Update) { Options.Update = Update; }
/// Set whether to keep the enclosing function for a static variable.
void setKeepFunctionForStatic(bool KeepFunctionForStatic) {
Options.KeepFunctionForStatic = KeepFunctionForStatic;
}
/// Use specified number of threads for parallel files linking. /// Use specified number of threads for parallel files linking.
void setNumThreads(unsigned NumThreads) { Options.Threads = NumThreads; } void setNumThreads(unsigned NumThreads) { Options.Threads = NumThreads; }
@ -782,6 +787,10 @@ private:
/// Update /// Update
bool Update = false; bool Update = false;
/// Whether we want a static variable to force us to keep its enclosing
/// function.
bool KeepFunctionForStatic = false;
/// Number of threads. /// Number of threads.
unsigned Threads = 1; unsigned Threads = 1;

View File

@ -434,13 +434,15 @@ unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr,
return Flags | TF_Keep; return Flags | TF_Keep;
} }
// See if there is a relocation to a valid debug map entry inside // See if there is a relocation to a valid debug map entry inside this
// this variable's location. The order is important here. We want to // variable's location. The order is important here. We want to always check
// always check if the variable has a valid relocation, so that the // if the variable has a valid relocation, so that the DIEInfo is filled.
// DIEInfo is filled. However, we don't want a static variable in a // However, we don't want a static variable in a function to force us to keep
// function to force us to keep the enclosing function. // the enclosing function, unless requested explicitly.
if (!RelocMgr.hasLiveMemoryLocation(DIE, MyInfo) || const bool HasLiveMemoryLocation =
(Flags & TF_InFunctionScope)) RelocMgr.hasLiveMemoryLocation(DIE, MyInfo);
if (!HasLiveMemoryLocation || ((Flags & TF_InFunctionScope) &&
!LLVM_UNLIKELY(Options.KeepFunctionForStatic)))
return Flags; return Flags;
if (Options.Verbose) { if (Options.Verbose) {

View File

@ -0,0 +1,36 @@
$ cat main.cpp
#include <stdio.h>
static void Foo(void)
{
typedef struct {
int x1;
int x2;
} FOO_VAR_TYPE;
static FOO_VAR_TYPE MyDummyVar __attribute__((aligned(4), used, section("TAD_VIRTUAL, TAD_DUMMY_DATA"), nocommon));
printf("Foo called");
}
int main()
{
Foo();
return 1;
}
$ clang++ -O2 -g main.cpp -c -o main.o
$ clang++ main.o -o main.out
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.omit.dSYM
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.keep.dSYM -keep-function-for-static
RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
KEEP: DW_AT_name ("MyDummyVar")
KEEP: DW_AT_name ("FOO_VAR_TYPE")
KEEP: DW_AT_name ("x1")
KEEP: DW_AT_name ("x2")
OMIT-NOT: DW_AT_name ("MyDummyVar")
OMIT-NOT: DW_AT_name ("FOO_VAR_TYPE")
OMIT-NOT: DW_AT_name ("x1")
OMIT-NOT: DW_AT_name ("x2")

View File

@ -11,6 +11,7 @@ CHECK: -dump-debug-map
CHECK: -flat CHECK: -flat
CHECK: -gen-reproducer CHECK: -gen-reproducer
CHECK: -help CHECK: -help
CHECK: -keep-function-for-static
CHECK: -no-odr CHECK: -no-odr
CHECK: -no-output CHECK: -no-output
CHECK: -no-swiftmodule-timestamp CHECK: -no-swiftmodule-timestamp

View File

@ -325,6 +325,7 @@ bool DwarfLinkerForBinary::link(const DebugMap &Map) {
GeneralLinker.setNumThreads(Options.Threads); GeneralLinker.setNumThreads(Options.Threads);
GeneralLinker.setAccelTableKind(Options.TheAccelTableKind); GeneralLinker.setAccelTableKind(Options.TheAccelTableKind);
GeneralLinker.setPrependPath(Options.PrependPath); GeneralLinker.setPrependPath(Options.PrependPath);
GeneralLinker.setKeepFunctionForStatic(Options.KeepFunctionForStatic);
if (Options.Translator) if (Options.Translator)
GeneralLinker.setStringsTranslator(TranslationLambda); GeneralLinker.setStringsTranslator(TranslationLambda);
GeneralLinker.setWarningHandler( GeneralLinker.setWarningHandler(

View File

@ -42,6 +42,10 @@ struct LinkOptions {
/// Do not check swiftmodule timestamp /// Do not check swiftmodule timestamp
bool NoTimestamp = false; bool NoTimestamp = false;
/// Whether we want a static variable to force us to keep its enclosing
/// function.
bool KeepFunctionForStatic = false;
/// Number of threads. /// Number of threads.
unsigned Threads = 1; unsigned Threads = 1;

View File

@ -24,6 +24,10 @@ def verbose: F<"verbose">,
HelpText<"Enable verbose mode.">, HelpText<"Enable verbose mode.">,
Group<grp_general>; Group<grp_general>;
def keep_func_for_static: F<"keep-function-for-static">,
HelpText<"Make a static variable keep the enclosing function even if it would have been omitted otherwise.">,
Group<grp_general>;
def statistics: F<"statistics">, def statistics: F<"statistics">,
HelpText<"Print statistics about the contribution of each object file to " HelpText<"Print statistics about the contribution of each object file to "
"the linked debug info. This prints a table after linking with the " "the linked debug info. This prints a table after linking with the "

View File

@ -91,6 +91,7 @@ struct DsymutilOptions {
bool InputIsYAMLDebugMap = false; bool InputIsYAMLDebugMap = false;
bool PaperTrailWarnings = false; bool PaperTrailWarnings = false;
bool Verify = false; bool Verify = false;
bool ForceKeepFunctionForStatic = false;
std::string SymbolMap; std::string SymbolMap;
std::string OutputFile; std::string OutputFile;
std::string Toolchain; std::string Toolchain;
@ -230,6 +231,8 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
Options.LinkOpts.Update = Args.hasArg(OPT_update); Options.LinkOpts.Update = Args.hasArg(OPT_update);
Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose); Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose);
Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics); Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics);
Options.LinkOpts.KeepFunctionForStatic =
Args.hasArg(OPT_keep_func_for_static);
if (opt::Arg *ReproducerPath = Args.getLastArg(OPT_use_reproducer)) { if (opt::Arg *ReproducerPath = Args.getLastArg(OPT_use_reproducer)) {
Options.ReproMode = ReproducerMode::Use; Options.ReproMode = ReproducerMode::Use;