forked from OSchip/llvm-project
dsymutil: Follow references to clang modules and recursively clone the
debug info. This does not yet resolve external type references. llvm-svn: 248331
This commit is contained in:
parent
0a9466c11e
commit
e5162dba49
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
if not 'X86' in config.root.targets:
|
if not 'X86' in config.root.targets:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
|
||||||
config.suffixes = ['.test', '.cpp', '.s']
|
config.suffixes = ['.test', '.cpp', '.m', '.s']
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* Compile with:
|
||||||
|
cat >modules.modulemap <<EOF
|
||||||
|
module Foo {
|
||||||
|
header "Foo.h"
|
||||||
|
export *
|
||||||
|
}
|
||||||
|
module Bar {
|
||||||
|
header "Bar.h"
|
||||||
|
export *
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
clang -D BAR_H -E -o Bar.h
|
||||||
|
clang -D FOO_H -E -o Foo.h
|
||||||
|
clang -cc1 -emit-obj -fmodules -fmodule-map-file=modules.modulemap \
|
||||||
|
-fmodule-format=obj -g -dwarf-ext-refs -fmodules-cache-path=. \
|
||||||
|
-fdisable-module-hash modules.m -o 1.o
|
||||||
|
*/
|
||||||
|
|
||||||
|
// RUN: llvm-dsymutil -f -oso-prepend-path=%p/../Inputs/modules \
|
||||||
|
// RUN: -y %p/dummy-debug-map.map -o - \
|
||||||
|
// RUN: | llvm-dwarfdump --debug-dump=info - | FileCheck %s
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
#ifdef BAR_H
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// CHECK: DW_TAG_compile_unit
|
||||||
|
// CHECK: DW_TAG_module
|
||||||
|
// CHECK-NEXT: DW_AT_name {{.*}}"Bar"
|
||||||
|
// CHECK: DW_TAG_member
|
||||||
|
// CHECK: DW_AT_name {{.*}}"value"
|
||||||
|
|
||||||
|
struct Bar {
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
#ifdef FOO_H
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// CHECK: 55{{.*}}DW_TAG_compile_unit
|
||||||
|
// CHECK: DW_TAG_module
|
||||||
|
// CHECK-NEXT: DW_AT_name {{.*}}"Foo"
|
||||||
|
// CHECK: DW_TAG_typedef
|
||||||
|
@import Bar;
|
||||||
|
typedef struct Bar Bar;
|
||||||
|
struct S {};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
#else
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
// CHECK: DW_TAG_compile_unit
|
||||||
|
// CHECK: DW_TAG_subprogram
|
||||||
|
// CHECK: DW_AT_name {{.*}}"main"
|
||||||
|
@import Foo;
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
Bar bar;
|
||||||
|
bar.value = 42;
|
||||||
|
return bar.value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -13,7 +13,7 @@
|
||||||
#include "MachOUtils.h"
|
#include "MachOUtils.h"
|
||||||
#include "NonRelocatableStringpool.h"
|
#include "NonRelocatableStringpool.h"
|
||||||
#include "llvm/ADT/IntervalMap.h"
|
#include "llvm/ADT/IntervalMap.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringSet.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/CodeGen/AsmPrinter.h"
|
#include "llvm/CodeGen/AsmPrinter.h"
|
||||||
#include "llvm/CodeGen/DIE.h"
|
#include "llvm/CodeGen/DIE.h"
|
||||||
|
@ -248,6 +248,14 @@ public:
|
||||||
return LocationAttributes;
|
return LocationAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setHasInterestingContent() { HasInterestingContent = true; }
|
||||||
|
bool hasInterestingContent() { return HasInterestingContent; }
|
||||||
|
|
||||||
|
/// Mark every DIE in this unit as kept. This function also
|
||||||
|
/// marks variables as InDebugMap so that they appear in the
|
||||||
|
/// reconstructed accelerator tables.
|
||||||
|
void markEverythingAsKept();
|
||||||
|
|
||||||
/// \brief Compute the end offset for this unit. Must be
|
/// \brief Compute the end offset for this unit. Must be
|
||||||
/// called after the CU's DIEs have been cloned.
|
/// called after the CU's DIEs have been cloned.
|
||||||
/// \returns the next unit offset (which is also the current
|
/// \returns the next unit offset (which is also the current
|
||||||
|
@ -368,8 +376,15 @@ private:
|
||||||
|
|
||||||
/// Is this unit subject to the ODR rule?
|
/// Is this unit subject to the ODR rule?
|
||||||
bool HasODR;
|
bool HasODR;
|
||||||
|
/// Did a DIE actually contain a valid reloc?
|
||||||
|
bool HasInterestingContent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void CompileUnit::markEverythingAsKept() {
|
||||||
|
for (auto &I : Info)
|
||||||
|
I.Keep = true;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t CompileUnit::computeNextUnitOffset() {
|
uint64_t CompileUnit::computeNextUnitOffset() {
|
||||||
NextUnitOffset = StartOffset + 11 /* Header size */;
|
NextUnitOffset = StartOffset + 11 /* Header size */;
|
||||||
// The root DIE might be null, meaning that the Unit had nothing to
|
// The root DIE might be null, meaning that the Unit had nothing to
|
||||||
|
@ -1177,6 +1192,22 @@ private:
|
||||||
const DebugMapObject &DMO, CompileUnit &CU,
|
const DebugMapObject &DMO, CompileUnit &CU,
|
||||||
unsigned Flags);
|
unsigned Flags);
|
||||||
|
|
||||||
|
/// If this compile unit is really a skeleton CU that points to a
|
||||||
|
/// clang module, register it in ClangModules and return true.
|
||||||
|
///
|
||||||
|
/// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
|
||||||
|
/// pointing to the module, and a DW_AT_gnu_dwo_id with the module
|
||||||
|
/// hash.
|
||||||
|
bool registerModuleReference(const DWARFDebugInfoEntryMinimal &CUDie,
|
||||||
|
const DWARFUnit &Unit, DebugMap &ModuleMap,
|
||||||
|
unsigned Indent = 0);
|
||||||
|
|
||||||
|
/// Recursively add the debug info in this clang module .pcm
|
||||||
|
/// file (and all the modules imported by it in a bottom-up fashion)
|
||||||
|
/// to Units.
|
||||||
|
void loadClangModule(StringRef Filename, StringRef ModulePath,
|
||||||
|
DebugMap &ModuleMap, unsigned Indent = 0);
|
||||||
|
|
||||||
/// \brief Flags passed to DwarfLinker::lookForDIEsToKeep
|
/// \brief Flags passed to DwarfLinker::lookForDIEsToKeep
|
||||||
enum TravesalFlags {
|
enum TravesalFlags {
|
||||||
TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
|
TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
|
||||||
|
@ -1383,12 +1414,12 @@ private:
|
||||||
const DebugMap &Map);
|
const DebugMap &Map);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
private:
|
|
||||||
std::string OutputFilename;
|
std::string OutputFilename;
|
||||||
LinkOptions Options;
|
LinkOptions Options;
|
||||||
BinaryHolder BinHolder;
|
BinaryHolder BinHolder;
|
||||||
std::unique_ptr<DwarfStreamer> Streamer;
|
std::unique_ptr<DwarfStreamer> Streamer;
|
||||||
uint64_t OutputDebugInfoSize;
|
uint64_t OutputDebugInfoSize;
|
||||||
|
unsigned UnitID; ///< A unique ID that identifies each compile unit.
|
||||||
|
|
||||||
/// The units of the current debug map object.
|
/// The units of the current debug map object.
|
||||||
std::vector<CompileUnit> Units;
|
std::vector<CompileUnit> Units;
|
||||||
|
@ -1416,6 +1447,9 @@ private:
|
||||||
/// Offset of the last CIE that has been emitted in the output
|
/// Offset of the last CIE that has been emitted in the output
|
||||||
/// debug_frame section.
|
/// debug_frame section.
|
||||||
uint32_t LastCIEOffset;
|
uint32_t LastCIEOffset;
|
||||||
|
|
||||||
|
/// FIXME: We may need to use something more resilient than the PCM filename.
|
||||||
|
StringSet<> ClangModules;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
|
/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
|
||||||
|
@ -2588,7 +2622,13 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
|
||||||
|
|
||||||
// Extract and clone every attribute.
|
// Extract and clone every attribute.
|
||||||
DataExtractor Data = U.getDebugInfoExtractor();
|
DataExtractor Data = U.getDebugInfoExtractor();
|
||||||
uint32_t NextOffset = U.getDIEAtIndex(Idx + 1)->getOffset();
|
// Point to the next DIE (generally there is always at least a NULL
|
||||||
|
// entry after the current one). If this is a lone
|
||||||
|
// DW_TAG_compile_unit without any children, point to the next unit.
|
||||||
|
uint32_t NextOffset =
|
||||||
|
(Idx + 1 < U.getNumDIEs())
|
||||||
|
? U.getDIEAtIndex(Idx + 1)->getOffset()
|
||||||
|
: U.getNextUnitOffset();
|
||||||
AttributesInfo AttrInfo;
|
AttributesInfo AttrInfo;
|
||||||
|
|
||||||
// We could copy the data only if we need to aply a relocation to
|
// We could copy the data only if we need to aply a relocation to
|
||||||
|
@ -3051,6 +3091,38 @@ void DwarfLinker::DIECloner::copyAbbrev(
|
||||||
Linker.AssignAbbrev(Copy);
|
Linker.AssignAbbrev(Copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DwarfLinker::registerModuleReference(
|
||||||
|
const DWARFDebugInfoEntryMinimal &CUDie, const DWARFUnit &Unit,
|
||||||
|
DebugMap &ModuleMap, unsigned Indent) {
|
||||||
|
std::string PCMfile =
|
||||||
|
CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_GNU_dwo_name, "");
|
||||||
|
if (PCMfile.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Clang module DWARF skeleton CUs abuse this for the path to the module.
|
||||||
|
std::string PCMpath =
|
||||||
|
CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_comp_dir, "");
|
||||||
|
|
||||||
|
if (Options.Verbose) {
|
||||||
|
outs().indent(Indent);
|
||||||
|
outs() << "Found clang module reference " << PCMfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ClangModules.count(PCMfile)) {
|
||||||
|
if (Options.Verbose)
|
||||||
|
outs() << " [cached].\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Options.Verbose)
|
||||||
|
outs() << " ...\n";
|
||||||
|
|
||||||
|
// Cyclic dependencies are disallowed by Clang, but we still
|
||||||
|
// shouldn't run into an infinite loop, so mark it as processed now.
|
||||||
|
ClangModules.insert(PCMfile);
|
||||||
|
loadClangModule(PCMfile, PCMpath, ModuleMap, Indent + 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<const object::ObjectFile &>
|
ErrorOr<const object::ObjectFile &>
|
||||||
DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
|
DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
|
||||||
const DebugMap &Map) {
|
const DebugMap &Map) {
|
||||||
|
@ -3066,6 +3138,58 @@ DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
|
||||||
return ErrOrObj;
|
return ErrOrObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
|
||||||
|
DebugMap &ModuleMap, unsigned Indent) {
|
||||||
|
SmallString<80> Path(Options.PrependPath);
|
||||||
|
if (sys::path::is_relative(Filename))
|
||||||
|
sys::path::append(Path, ModulePath, Filename);
|
||||||
|
else
|
||||||
|
sys::path::append(Path, Filename);
|
||||||
|
BinaryHolder ObjHolder(Options.Verbose);
|
||||||
|
auto &Obj =
|
||||||
|
ModuleMap.addDebugMapObject(Path, sys::TimeValue::PosixZeroTime());
|
||||||
|
auto ErrOrObj = loadObject(ObjHolder, Obj, ModuleMap);
|
||||||
|
if (!ErrOrObj) {
|
||||||
|
ClangModules.erase(ClangModules.find(Filename));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: At this point dsymutil should verify the DW_AT_gnu_dwo_id
|
||||||
|
// against the module hash of the clang module.
|
||||||
|
|
||||||
|
CompileUnit *Unit = nullptr;
|
||||||
|
|
||||||
|
// Setup access to the debug info.
|
||||||
|
DWARFContextInMemory DwarfContext(*ErrOrObj);
|
||||||
|
RelocationManager RelocMgr(*this);
|
||||||
|
for (const auto &CU : DwarfContext.compile_units()) {
|
||||||
|
auto *CUDie = CU->getUnitDIE(false);
|
||||||
|
// Recursively get all modules imported by this one.
|
||||||
|
if (!registerModuleReference(*CUDie, *CU, ModuleMap, Indent)) {
|
||||||
|
// Add this module.
|
||||||
|
if (Unit) {
|
||||||
|
errs() << Filename << ": Clang modules are expected to have exactly"
|
||||||
|
<< " 1 compile unit.\n";
|
||||||
|
exitDsymutil(1);
|
||||||
|
}
|
||||||
|
Unit = new CompileUnit(*CU, UnitID++, !Options.NoODR);
|
||||||
|
Unit->setHasInterestingContent();
|
||||||
|
gatherDIEParents(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool,
|
||||||
|
ODRContexts);
|
||||||
|
// Keep everything.
|
||||||
|
Unit->markEverythingAsKept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Options.Verbose) {
|
||||||
|
outs().indent(Indent);
|
||||||
|
outs() << "cloning .debug_info from " << Filename << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
DIECloner(*this, RelocMgr, DIEAlloc, MutableArrayRef<CompileUnit>(*Unit),
|
||||||
|
Options)
|
||||||
|
.cloneAllCompileUnits(DwarfContext);
|
||||||
|
}
|
||||||
|
|
||||||
void DwarfLinker::DIECloner::cloneAllCompileUnits(
|
void DwarfLinker::DIECloner::cloneAllCompileUnits(
|
||||||
DWARFContextInMemory &DwarfContext) {
|
DWARFContextInMemory &DwarfContext) {
|
||||||
if (!Linker.Streamer)
|
if (!Linker.Streamer)
|
||||||
|
@ -3113,7 +3237,9 @@ bool DwarfLinker::link(const DebugMap &Map) {
|
||||||
// Size of the DIEs (and headers) generated for the linked output.
|
// Size of the DIEs (and headers) generated for the linked output.
|
||||||
OutputDebugInfoSize = 0;
|
OutputDebugInfoSize = 0;
|
||||||
// A unique ID that identifies each compile unit.
|
// A unique ID that identifies each compile unit.
|
||||||
unsigned UnitID = 0;
|
UnitID = 0;
|
||||||
|
DebugMap ModuleMap(Map.getTriple(), Map.getBinaryPath());
|
||||||
|
|
||||||
for (const auto &Obj : Map.objects()) {
|
for (const auto &Obj : Map.objects()) {
|
||||||
CurrentDebugObject = Obj.get();
|
CurrentDebugObject = Obj.get();
|
||||||
|
|
||||||
|
@ -3143,9 +3269,11 @@ bool DwarfLinker::link(const DebugMap &Map) {
|
||||||
outs() << "Input compilation unit:";
|
outs() << "Input compilation unit:";
|
||||||
CUDie->dump(outs(), CU.get(), 0);
|
CUDie->dump(outs(), CU.get(), 0);
|
||||||
}
|
}
|
||||||
Units.emplace_back(*CU, UnitID++, !Options.NoODR);
|
if (!registerModuleReference(*CUDie, *CU, ModuleMap)) {
|
||||||
gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(),
|
Units.emplace_back(*CU, UnitID++, !Options.NoODR);
|
||||||
StringPool, ODRContexts);
|
gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(),
|
||||||
|
StringPool, ODRContexts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then mark all the DIEs that need to be present in the linked
|
// Then mark all the DIEs that need to be present in the linked
|
||||||
|
|
Loading…
Reference in New Issue