rfc: Adding a mode to -gline-tables-only to include parameter names, namespaces

Hi,

the motivation for -gline-tables-only was to make debug info much smaller,
but still include enough to get usable stack frames [1]. We recently tried
using it in Chromium and discovered that the stack frames aren't all that
usable: Function parameters disappear, as do function namespaces.

Are there any concerns about adding a mode to -gline-tables-only (or a
second flag -gline-tables-full, or similar) that includes function
parameter info and namespace info but still omits most debug info?

I’m not convinced that the resulting debug info will dramatically smaller
than the full debug info. The largest bit of the debug info is the type
information if we are going to emit function parameters that will probably
pull in the majority of the types in the program.

Reviving this a few years later: Just letting clang emit DW_AT_linkage_name
in -g1 would give us qualified stacks, and wouldn't require serializing any
debug info for types from what I understand. gcc does
emit DW_AT_linkage_name in -g1.

We're currently using fdebug-info-for-profiling + -g1 on Android which does
give us DW_AT_linkage_name but also a bunch of other stuff, and we had to
know about the flag. If -g1 just emitted DW_AT_linkage_name by default,
that'd be pretty useful while also being pretty cheap size-wise.

Opinions?

Would be great to have a prototype & numbers to back up/quantify the “pretty cheap size-wise” (& good to look at object size as well as final executable size). & Alexey’s no longer working on this stuff - so probably add kcc or eugenis maybe? That was the original motivation for -gmlt (symbolized stacks in asan) so they’re probably more sensitive to the size costs.

  • Dave

Would be great to have a prototype & numbers to back up/quantify the “pretty cheap size-wise” (& good to look at object size as well as final executable size). & Alexey’s no longer working on this stuff - so probably add kcc or eugenis maybe? That was the original motivation for -gmlt (symbolized stacks in asan) so they’re probably more sensitive to the size costs.

IIRC mostly it’s a lot of strings in the output. That said, I agree that it would be very useful and we should probably contemplate it as just “part of the expense of C++ and stack traces” here. Be good to get numbers first so we know what we’re getting ourselves into though.

-eric

I’m happy to collect data if someone can tell me how to get the compiler to always emit DW_AT_linkage_name. My non-working attempt was this:

Index: lib/CodeGen/CGDebugInfo.cpp

There’s a bunch of custom logic in lib/CodeGen/AsmPrinter/DwarfDebug.cpp to gate the emission of linkage names, including a hidden option called -dwarf-linkage-names that you may need to enable.

– adrian

Thanks. I changed that flag to default to on (in addition to my clang-side
change) but that didn't seem to make a difference:

Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp

I think you’d need at least two changes - one in the frontend to add linkage names and then the backend to use them.

Clang change:

diff --git lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CGDebugInfo.cpp
index c9aa04815f…f392a24e09 100644
— lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -2867,7 +2867,7 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
!CGM.getCodeGenOpts().EmitGcovNotes &&
!CGM.getCodeGenOpts().DebugInfoForProfiling &&
DebugKind <= codegenoptions::DebugLineTablesOnly))

  • LinkageName = StringRef();
  • ; // LinkageName = StringRef();

if (DebugKind >= codegenoptions::LimitedDebugInfo) {
if (const NamespaceDecl *NSDecl =

LLVM change:

diff --git lib/CodeGen/AsmPrinter/DwarfUnit.cpp lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 784a1d512c1…c9e4e2ecdac 100644
— lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -1194,7 +1194,9 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie,
return;

// Constructors and operators for anonymous aggregates do not have names.

  • if (!SP->getName().empty())
  • if (SkipSPAttributes && !SP->getLinkageName().empty())
  • addLinkageName(SPDie, SP->getLinkageName());
  • else if (!SP->getName().empty())
    addString(SPDie, dwarf::DW_AT_name, SP->getName());

if (!SkipSPSourceLocation)

Obviously this is just a hack to test - and I might’ve missed other necessary changes, but at least a simple test case seems to do what I’d want:

0x0000000b: DW_TAG_compile_unit [1] *

0x0000002a: DW_TAG_subprogram [2]
DW_AT_linkage_name [DW_FORM_strp] ( .debug_str[0x0000006d] = “_Z2f2v”)

0x0000002f: DW_TAG_subprogram [3] *

DW_AT_linkage_name [DW_FORM_strp] ( .debug_str[0x00000074] = “_Z2f3v”)

0x00000040: DW_TAG_inlined_subroutine [4]
DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x002a => {0x0000002a} “_Z2f2v”)

(built from:

void f1();
attribute((always_inline)) void f2() {
f1();
}
void f3() {
f2();
}
)

Might break non-gmlt (though not in any way that’s readily apparent to me), might break backwards compatible (taking existing frontend gmlt-like IR and building it with this /should/ do the right thing, falling back to the DW_AT_name in the absence of DW_AT_linkage_name, but untested, etc), etc.