2014-12-13 01:31:24 +08:00
|
|
|
//===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker -----------===//
|
|
|
|
//
|
2018-06-28 00:13:40 +08:00
|
|
|
// The LLVM Compiler Infrastructure
|
2014-12-13 01:31:24 +08:00
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2017-11-02 05:16:06 +08:00
|
|
|
|
2018-06-28 00:13:40 +08:00
|
|
|
#include "DwarfLinker.h"
|
2015-01-29 02:27:01 +08:00
|
|
|
#include "BinaryHolder.h"
|
|
|
|
#include "DebugMap.h"
|
2018-06-28 00:13:40 +08:00
|
|
|
#include "DeclContext.h"
|
|
|
|
#include "DwarfStreamer.h"
|
2015-09-03 00:49:13 +08:00
|
|
|
#include "MachOUtils.h"
|
2015-08-26 13:09:52 +08:00
|
|
|
#include "NonRelocatableStringpool.h"
|
2017-06-07 11:48:56 +08:00
|
|
|
#include "dsymutil.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2018-03-13 22:27:15 +08:00
|
|
|
#include "llvm/ADT/BitVector.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/DenseMapInfo.h"
|
|
|
|
#include "llvm/ADT/DenseSet.h"
|
|
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
|
|
#include "llvm/ADT/Hashing.h"
|
2015-03-13 02:45:10 +08:00
|
|
|
#include "llvm/ADT/IntervalMap.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/ADT/None.h"
|
|
|
|
#include "llvm/ADT/Optional.h"
|
|
|
|
#include "llvm/ADT/PointerIntPair.h"
|
2015-03-12 02:46:01 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2017-06-07 11:48:56 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/ADT/Triple.h"
|
|
|
|
#include "llvm/ADT/Twine.h"
|
2017-06-07 11:48:56 +08:00
|
|
|
#include "llvm/BinaryFormat/Dwarf.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
2018-01-29 22:52:50 +08:00
|
|
|
#include "llvm/CodeGen/AccelTable.h"
|
2015-02-28 08:29:11 +08:00
|
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
2015-03-05 06:07:44 +08:00
|
|
|
#include "llvm/CodeGen/DIE.h"
|
2015-07-22 06:41:43 +08:00
|
|
|
#include "llvm/Config/config.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/DebugInfo/DIContext.h"
|
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
2015-01-31 02:07:45 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
|
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
2018-10-31 09:12:58 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
2015-02-14 07:18:29 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
|
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
2015-02-28 08:29:11 +08:00
|
|
|
#include "llvm/MC/MCAsmBackend.h"
|
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
|
|
#include "llvm/MC/MCCodeEmitter.h"
|
2017-06-07 11:48:56 +08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2015-03-16 04:45:43 +08:00
|
|
|
#include "llvm/MC/MCDwarf.h"
|
2015-02-28 08:29:11 +08:00
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
|
|
#include "llvm/MC/MCObjectFileInfo.h"
|
2018-05-19 02:26:45 +08:00
|
|
|
#include "llvm/MC/MCObjectWriter.h"
|
2015-02-28 08:29:11 +08:00
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/MC/MCSection.h"
|
2015-02-28 08:29:11 +08:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
2015-05-16 06:19:42 +08:00
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/MC/MCTargetOptions.h"
|
2015-02-14 07:18:22 +08:00
|
|
|
#include "llvm/Object/MachO.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/Object/ObjectFile.h"
|
|
|
|
#include "llvm/Object/SymbolicFile.h"
|
|
|
|
#include "llvm/Support/Allocator.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
2018-01-29 22:52:50 +08:00
|
|
|
#include "llvm/Support/DJB.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/Support/DataExtractor.h"
|
|
|
|
#include "llvm/Support/Error.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/ErrorOr.h"
|
|
|
|
#include "llvm/Support/FileSystem.h"
|
|
|
|
#include "llvm/Support/Format.h"
|
2015-02-14 07:18:34 +08:00
|
|
|
#include "llvm/Support/LEB128.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2015-02-28 08:29:11 +08:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
2018-03-13 22:27:15 +08:00
|
|
|
#include "llvm/Support/ThreadPool.h"
|
2017-10-31 21:54:15 +08:00
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
2018-04-15 05:36:42 +08:00
|
|
|
#include "llvm/Support/WithColor.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2015-02-28 08:29:11 +08:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include "llvm/Target/TargetOptions.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cinttypes>
|
|
|
|
#include <climits>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <limits>
|
|
|
|
#include <map>
|
2016-12-02 02:56:29 +08:00
|
|
|
#include <memory>
|
2015-01-29 02:27:01 +08:00
|
|
|
#include <string>
|
2017-11-02 05:16:06 +08:00
|
|
|
#include <system_error>
|
2015-03-14 02:35:57 +08:00
|
|
|
#include <tuple>
|
2017-11-02 05:16:06 +08:00
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
2014-12-13 01:31:24 +08:00
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace dsymutil {
|
|
|
|
|
2015-09-23 02:50:58 +08:00
|
|
|
/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
|
|
|
|
/// CompileUnit object instead.
|
2018-06-28 23:01:42 +08:00
|
|
|
static CompileUnit *getUnitForOffset(const UnitListTy &Units, unsigned Offset) {
|
2018-02-22 19:32:51 +08:00
|
|
|
auto CU = std::upper_bound(
|
|
|
|
Units.begin(), Units.end(), Offset,
|
|
|
|
[](uint32_t LHS, const std::unique_ptr<CompileUnit> &RHS) {
|
|
|
|
return LHS < RHS->getOrigUnit().getNextUnitOffset();
|
|
|
|
});
|
2016-12-02 02:56:29 +08:00
|
|
|
return CU != Units.end() ? CU->get() : nullptr;
|
2015-02-14 07:18:29 +08:00
|
|
|
}
|
|
|
|
|
2018-02-22 19:32:51 +08:00
|
|
|
/// Resolve the DIE attribute reference that has been extracted in \p RefValue.
|
|
|
|
/// The resulting DIE might be in another CompileUnit which is stored into \p
|
|
|
|
/// ReferencedCU. \returns null if resolving fails for any reason.
|
2018-06-28 23:01:42 +08:00
|
|
|
static DWARFDie resolveDIEReference(const DwarfLinker &Linker,
|
|
|
|
const DebugMapObject &DMO,
|
|
|
|
const UnitListTy &Units,
|
|
|
|
const DWARFFormValue &RefValue,
|
|
|
|
const DWARFUnit &Unit, const DWARFDie &DIE,
|
|
|
|
CompileUnit *&RefCU) {
|
2015-02-14 07:18:29 +08:00
|
|
|
assert(RefValue.isFormClass(DWARFFormValue::FC_Reference));
|
2016-11-01 00:46:02 +08:00
|
|
|
uint64_t RefOffset = *RefValue.getAsReference();
|
2015-02-14 07:18:29 +08:00
|
|
|
|
2015-09-23 02:50:58 +08:00
|
|
|
if ((RefCU = getUnitForOffset(Units, RefOffset)))
|
2017-09-21 18:28:33 +08:00
|
|
|
if (const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) {
|
|
|
|
// In a file with broken references, an attribute might point to a NULL
|
|
|
|
// DIE.
|
2018-02-22 19:32:51 +08:00
|
|
|
if (!RefDie.isNULL())
|
2017-09-21 18:28:33 +08:00
|
|
|
return RefDie;
|
|
|
|
}
|
2015-02-14 07:18:29 +08:00
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
Linker.reportWarning("could not find referenced DIE", DMO, &DIE);
|
2016-12-14 02:25:19 +08:00
|
|
|
return DWARFDie();
|
2015-02-14 07:18:29 +08:00
|
|
|
}
|
|
|
|
|
2018-02-22 19:32:51 +08:00
|
|
|
/// \returns whether the passed \a Attr type might contain a DIE reference
|
|
|
|
/// suitable for ODR uniquing.
|
2015-07-22 06:41:43 +08:00
|
|
|
static bool isODRAttribute(uint16_t Attr) {
|
|
|
|
switch (Attr) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case dwarf::DW_AT_type:
|
|
|
|
case dwarf::DW_AT_containing_type:
|
|
|
|
case dwarf::DW_AT_specification:
|
|
|
|
case dwarf::DW_AT_abstract_origin:
|
|
|
|
case dwarf::DW_AT_import:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Improper attribute.");
|
|
|
|
}
|
|
|
|
|
2018-08-31 05:21:16 +08:00
|
|
|
static bool isTypeTag(uint16_t Tag) {
|
|
|
|
switch (Tag) {
|
|
|
|
case dwarf::DW_TAG_array_type:
|
|
|
|
case dwarf::DW_TAG_class_type:
|
|
|
|
case dwarf::DW_TAG_enumeration_type:
|
|
|
|
case dwarf::DW_TAG_pointer_type:
|
|
|
|
case dwarf::DW_TAG_reference_type:
|
|
|
|
case dwarf::DW_TAG_string_type:
|
|
|
|
case dwarf::DW_TAG_structure_type:
|
|
|
|
case dwarf::DW_TAG_subroutine_type:
|
|
|
|
case dwarf::DW_TAG_typedef:
|
|
|
|
case dwarf::DW_TAG_union_type:
|
|
|
|
case dwarf::DW_TAG_ptr_to_member_type:
|
|
|
|
case dwarf::DW_TAG_set_type:
|
|
|
|
case dwarf::DW_TAG_subrange_type:
|
|
|
|
case dwarf::DW_TAG_base_type:
|
|
|
|
case dwarf::DW_TAG_const_type:
|
|
|
|
case dwarf::DW_TAG_constant:
|
|
|
|
case dwarf::DW_TAG_file_type:
|
|
|
|
case dwarf::DW_TAG_namelist:
|
|
|
|
case dwarf::DW_TAG_packed_type:
|
|
|
|
case dwarf::DW_TAG_volatile_type:
|
|
|
|
case dwarf::DW_TAG_restrict_type:
|
|
|
|
case dwarf::DW_TAG_atomic_type:
|
|
|
|
case dwarf::DW_TAG_interface_type:
|
|
|
|
case dwarf::DW_TAG_unspecified_type:
|
|
|
|
case dwarf::DW_TAG_shared_type:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-12-14 02:25:19 +08:00
|
|
|
bool DwarfLinker::DIECloner::getDIENames(const DWARFDie &Die,
|
2018-01-29 22:52:50 +08:00
|
|
|
AttributesInfo &Info,
|
2018-03-13 18:52:49 +08:00
|
|
|
OffsetsStringPool &StringPool,
|
2018-01-29 22:52:50 +08:00
|
|
|
bool StripTemplate) {
|
|
|
|
// This function will be called on DIEs having low_pcs and
|
|
|
|
// ranges. As getting the name might be more expansive, filter out
|
|
|
|
// blocks directly.
|
|
|
|
if (Die.getTag() == dwarf::DW_TAG_lexical_block)
|
|
|
|
return false;
|
|
|
|
|
2015-09-15 00:46:10 +08:00
|
|
|
// FIXME: a bit wasteful as the first getName might return the
|
2015-03-16 10:05:10 +08:00
|
|
|
// short name.
|
2018-01-29 22:52:50 +08:00
|
|
|
if (!Info.MangledName)
|
|
|
|
if (const char *MangledName = Die.getName(DINameKind::LinkageName))
|
2018-03-13 18:52:49 +08:00
|
|
|
Info.MangledName = StringPool.getEntry(MangledName);
|
2015-03-16 10:05:10 +08:00
|
|
|
|
2018-01-29 22:52:50 +08:00
|
|
|
if (!Info.Name)
|
|
|
|
if (const char *Name = Die.getName(DINameKind::ShortName))
|
2018-03-13 18:52:49 +08:00
|
|
|
Info.Name = StringPool.getEntry(Name);
|
2018-01-29 22:52:50 +08:00
|
|
|
|
|
|
|
if (StripTemplate && Info.Name && Info.MangledName != Info.Name) {
|
|
|
|
// FIXME: dsymutil compatibility. This is wrong for operator<
|
|
|
|
auto Split = Info.Name.getString().split('<');
|
|
|
|
if (!Split.second.empty())
|
2018-03-13 18:52:49 +08:00
|
|
|
Info.NameWithoutTemplate = StringPool.getEntry(Split.first);
|
2018-01-29 22:52:50 +08:00
|
|
|
}
|
2015-03-16 10:05:10 +08:00
|
|
|
|
|
|
|
return Info.Name || Info.MangledName;
|
|
|
|
}
|
|
|
|
|
2018-02-22 19:32:51 +08:00
|
|
|
/// Report a warning to the user, optionally including information about a
|
|
|
|
/// specific \p DIE related to the warning.
|
2018-03-13 18:52:49 +08:00
|
|
|
void DwarfLinker::reportWarning(const Twine &Warning, const DebugMapObject &DMO,
|
2016-12-14 02:25:19 +08:00
|
|
|
const DWARFDie *DIE) const {
|
2018-03-13 18:52:49 +08:00
|
|
|
StringRef Context = DMO.getObjectFilename();
|
2015-02-28 08:29:01 +08:00
|
|
|
warn(Warning, Context);
|
2015-02-14 07:18:29 +08:00
|
|
|
|
2015-02-28 08:29:07 +08:00
|
|
|
if (!Options.Verbose || !DIE)
|
2015-02-14 07:18:29 +08:00
|
|
|
return;
|
|
|
|
|
2017-09-13 17:43:05 +08:00
|
|
|
DIDumpOptions DumpOpts;
|
2017-09-21 01:44:00 +08:00
|
|
|
DumpOpts.RecurseDepth = 0;
|
2017-09-13 17:43:05 +08:00
|
|
|
DumpOpts.Verbose = Options.Verbose;
|
|
|
|
|
2018-04-15 05:36:42 +08:00
|
|
|
WithColor::note() << " in DIE:\n";
|
2017-09-21 01:44:00 +08:00
|
|
|
DIE->dump(errs(), 6 /* Indent */, DumpOpts);
|
2015-02-14 07:18:29 +08:00
|
|
|
}
|
|
|
|
|
2016-06-09 03:09:22 +08:00
|
|
|
bool DwarfLinker::createStreamer(const Triple &TheTriple,
|
2017-11-16 04:55:53 +08:00
|
|
|
raw_fd_ostream &OutFile) {
|
2015-02-28 08:29:11 +08:00
|
|
|
if (Options.NoOutput)
|
|
|
|
return true;
|
|
|
|
|
2018-07-10 00:58:48 +08:00
|
|
|
Streamer = llvm::make_unique<DwarfStreamer>(OutFile, Options);
|
2017-11-16 04:55:53 +08:00
|
|
|
return Streamer->init(TheTriple);
|
2015-02-28 08:29:11 +08:00
|
|
|
}
|
|
|
|
|
2015-09-24 01:35:52 +08:00
|
|
|
/// Recursive helper to build the global DeclContext information and
|
|
|
|
/// gather the child->parent relationships in the original compile unit.
|
|
|
|
///
|
|
|
|
/// \return true when this DIE and all of its children are only
|
|
|
|
/// forward declarations to types defined in external clang modules
|
|
|
|
/// (i.e., forward declarations that are children of a DW_TAG_module).
|
2018-02-22 19:32:51 +08:00
|
|
|
static bool analyzeContextInfo(const DWARFDie &DIE, unsigned ParentIdx,
|
|
|
|
CompileUnit &CU, DeclContext *CurrentDeclContext,
|
2018-03-13 18:52:49 +08:00
|
|
|
UniquingStringPool &StringPool,
|
2015-09-24 01:35:52 +08:00
|
|
|
DeclContextTree &Contexts,
|
2018-09-07 18:29:22 +08:00
|
|
|
uint64_t ModulesEndOffset,
|
2015-09-24 04:44:37 +08:00
|
|
|
bool InImportedModule = false) {
|
2015-01-29 06:15:14 +08:00
|
|
|
unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
|
2015-07-22 06:41:43 +08:00
|
|
|
CompileUnit::DIEInfo &Info = CU.getInfo(MyIdx);
|
|
|
|
|
2015-09-24 01:35:52 +08:00
|
|
|
// Clang imposes an ODR on modules(!) regardless of the language:
|
|
|
|
// "The module-id should consist of only a single identifier,
|
|
|
|
// which provides the name of the module being defined. Each
|
|
|
|
// module shall have a single definition."
|
|
|
|
//
|
|
|
|
// This does not extend to the types inside the modules:
|
|
|
|
// "[I]n C, this implies that if two structs are defined in
|
|
|
|
// different submodules with the same name, those two types are
|
|
|
|
// distinct types (but may be compatible types if their
|
|
|
|
// definitions match)."
|
|
|
|
//
|
|
|
|
// We treat non-C++ modules like namespaces for this reason.
|
2016-12-14 02:25:19 +08:00
|
|
|
if (DIE.getTag() == dwarf::DW_TAG_module && ParentIdx == 0 &&
|
2017-09-30 08:22:24 +08:00
|
|
|
dwarf::toString(DIE.find(dwarf::DW_AT_name), "") !=
|
|
|
|
CU.getClangModuleName()) {
|
2015-09-24 04:44:37 +08:00
|
|
|
InImportedModule = true;
|
|
|
|
}
|
2015-09-24 01:35:52 +08:00
|
|
|
|
2015-07-22 06:41:43 +08:00
|
|
|
Info.ParentIdx = ParentIdx;
|
2015-10-02 08:27:08 +08:00
|
|
|
bool InClangModule = CU.isClangModule() || InImportedModule;
|
|
|
|
if (CU.hasODR() || InClangModule) {
|
2015-07-22 06:41:43 +08:00
|
|
|
if (CurrentDeclContext) {
|
2015-10-02 08:27:08 +08:00
|
|
|
auto PtrInvalidPair = Contexts.getChildDeclContext(
|
|
|
|
*CurrentDeclContext, DIE, CU, StringPool, InClangModule);
|
2015-07-22 06:41:43 +08:00
|
|
|
CurrentDeclContext = PtrInvalidPair.getPointer();
|
|
|
|
Info.Ctxt =
|
|
|
|
PtrInvalidPair.getInt() ? nullptr : PtrInvalidPair.getPointer();
|
2017-07-21 10:07:33 +08:00
|
|
|
if (Info.Ctxt)
|
|
|
|
Info.Ctxt->setDefinedInClangModule(InClangModule);
|
2015-07-22 06:41:43 +08:00
|
|
|
} else
|
|
|
|
Info.Ctxt = CurrentDeclContext = nullptr;
|
|
|
|
}
|
2015-01-29 06:15:14 +08:00
|
|
|
|
2015-09-24 04:44:37 +08:00
|
|
|
Info.Prune = InImportedModule;
|
2016-12-14 02:25:19 +08:00
|
|
|
if (DIE.hasChildren())
|
2018-02-22 19:32:51 +08:00
|
|
|
for (auto Child : DIE.children())
|
2018-09-07 18:29:22 +08:00
|
|
|
Info.Prune &=
|
|
|
|
analyzeContextInfo(Child, MyIdx, CU, CurrentDeclContext, StringPool,
|
|
|
|
Contexts, ModulesEndOffset, InImportedModule);
|
2015-09-24 01:35:52 +08:00
|
|
|
|
|
|
|
// Prune this DIE if it is either a forward declaration inside a
|
|
|
|
// DW_TAG_module or a DW_TAG_module that contains nothing but
|
|
|
|
// forward declarations.
|
2018-02-22 19:32:51 +08:00
|
|
|
Info.Prune &= (DIE.getTag() == dwarf::DW_TAG_module) ||
|
2018-08-31 05:21:16 +08:00
|
|
|
(isTypeTag(DIE.getTag()) &&
|
|
|
|
dwarf::toUnsigned(DIE.find(dwarf::DW_AT_declaration), 0));
|
2015-09-24 01:35:52 +08:00
|
|
|
|
2018-09-07 18:29:22 +08:00
|
|
|
// Only prune forward declarations inside a DW_TAG_module for which a
|
|
|
|
// definition exists elsewhere.
|
|
|
|
if (ModulesEndOffset == 0)
|
|
|
|
Info.Prune &= Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset();
|
|
|
|
else
|
|
|
|
Info.Prune &= Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset() > 0 &&
|
|
|
|
Info.Ctxt->getCanonicalDIEOffset() <= ModulesEndOffset;
|
2015-10-06 07:11:20 +08:00
|
|
|
|
2015-09-24 01:35:52 +08:00
|
|
|
return Info.Prune;
|
2018-09-07 18:29:22 +08:00
|
|
|
} // namespace dsymutil
|
2015-01-29 06:15:14 +08:00
|
|
|
|
2015-02-14 07:18:34 +08:00
|
|
|
static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {
|
|
|
|
switch (Tag) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case dwarf::DW_TAG_subprogram:
|
|
|
|
case dwarf::DW_TAG_lexical_block:
|
|
|
|
case dwarf::DW_TAG_subroutine_type:
|
|
|
|
case dwarf::DW_TAG_structure_type:
|
|
|
|
case dwarf::DW_TAG_class_type:
|
|
|
|
case dwarf::DW_TAG_union_type:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Invalid Tag");
|
|
|
|
}
|
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
void DwarfLinker::startDebugObject(LinkContext &Context) {
|
2015-03-16 04:45:43 +08:00
|
|
|
// Iterate over the debug map entries and put all the ones that are
|
2018-03-13 18:52:49 +08:00
|
|
|
// functions (because they have a size) into the Ranges map. This map is
|
|
|
|
// very similar to the FunctionRanges that are stored in each unit, with 2
|
|
|
|
// notable differences:
|
|
|
|
//
|
|
|
|
// 1. Obviously this one is global, while the other ones are per-unit.
|
|
|
|
//
|
|
|
|
// 2. This one contains not only the functions described in the DIE
|
|
|
|
// tree, but also the ones that are only in the debug map.
|
|
|
|
//
|
|
|
|
// The latter information is required to reproduce dsymutil's logic while
|
|
|
|
// linking line tables. The cases where this information matters look like
|
|
|
|
// bugs that need to be investigated, but for now we need to reproduce
|
|
|
|
// dsymutil's behavior.
|
2015-03-16 04:45:43 +08:00
|
|
|
// FIXME: Once we understood exactly if that information is needed,
|
|
|
|
// maybe totally remove this (or try to use it to do a real
|
|
|
|
// -gline-tables-only on Darwin.
|
2018-03-13 18:52:49 +08:00
|
|
|
for (const auto &Entry : Context.DMO.symbols()) {
|
2015-03-16 04:45:43 +08:00
|
|
|
const auto &Mapping = Entry.getValue();
|
2016-01-31 12:29:22 +08:00
|
|
|
if (Mapping.Size && Mapping.ObjectAddress)
|
2018-03-13 18:52:49 +08:00
|
|
|
Context.Ranges[*Mapping.ObjectAddress] = DebugMapObjectRange(
|
2016-01-31 12:29:22 +08:00
|
|
|
*Mapping.ObjectAddress + Mapping.Size,
|
|
|
|
int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress);
|
2015-03-16 04:45:43 +08:00
|
|
|
}
|
2015-01-29 06:15:14 +08:00
|
|
|
}
|
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
void DwarfLinker::endDebugObject(LinkContext &Context) {
|
|
|
|
Context.Clear();
|
2018-07-26 07:01:38 +08:00
|
|
|
|
2015-06-26 22:51:22 +08:00
|
|
|
for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I)
|
|
|
|
(*I)->~DIEBlock();
|
|
|
|
for (auto I = DIELocs.begin(), E = DIELocs.end(); I != E; ++I)
|
|
|
|
(*I)->~DIELoc();
|
2015-03-05 06:07:44 +08:00
|
|
|
|
|
|
|
DIEBlocks.clear();
|
|
|
|
DIELocs.clear();
|
|
|
|
DIEAlloc.Reset();
|
2015-02-14 07:18:22 +08:00
|
|
|
}
|
|
|
|
|
2016-02-01 12:43:14 +08:00
|
|
|
static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) {
|
|
|
|
switch (Arch) {
|
|
|
|
case Triple::x86:
|
|
|
|
return RelocType == MachO::GENERIC_RELOC_SECTDIFF ||
|
|
|
|
RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
|
|
|
|
case Triple::x86_64:
|
|
|
|
return RelocType == MachO::X86_64_RELOC_SUBTRACTOR;
|
|
|
|
case Triple::arm:
|
|
|
|
case Triple::thumb:
|
|
|
|
return RelocType == MachO::ARM_RELOC_SECTDIFF ||
|
|
|
|
RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
|
|
|
|
RelocType == MachO::ARM_RELOC_HALF ||
|
|
|
|
RelocType == MachO::ARM_RELOC_HALF_SECTDIFF;
|
|
|
|
case Triple::aarch64:
|
|
|
|
return RelocType == MachO::ARM64_RELOC_SUBTRACTOR;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Iterate over the relocations of the given \p Section and
|
2015-02-14 07:18:22 +08:00
|
|
|
/// store the ones that correspond to debug map entries into the
|
|
|
|
/// ValidRelocs array.
|
2018-02-22 19:32:51 +08:00
|
|
|
void DwarfLinker::RelocationManager::findValidRelocsMachO(
|
|
|
|
const object::SectionRef &Section, const object::MachOObjectFile &Obj,
|
|
|
|
const DebugMapObject &DMO) {
|
2015-02-14 07:18:22 +08:00
|
|
|
StringRef Contents;
|
|
|
|
Section.getContents(Contents);
|
|
|
|
DataExtractor Data(Contents, Obj.isLittleEndian(), 0);
|
2016-02-01 12:43:14 +08:00
|
|
|
bool SkipNext = false;
|
2015-02-14 07:18:22 +08:00
|
|
|
|
|
|
|
for (const object::RelocationRef &Reloc : Section.relocations()) {
|
2016-02-01 12:43:14 +08:00
|
|
|
if (SkipNext) {
|
|
|
|
SkipNext = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-02-14 07:18:22 +08:00
|
|
|
object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
|
|
|
|
MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
|
2016-02-01 12:43:14 +08:00
|
|
|
|
|
|
|
if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
|
|
|
|
Obj.getArch())) {
|
|
|
|
SkipNext = true;
|
2018-03-13 18:52:49 +08:00
|
|
|
Linker.reportWarning("unsupported relocation in debug_info section.",
|
|
|
|
DMO);
|
2016-02-01 12:43:14 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-02-14 07:18:22 +08:00
|
|
|
unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
|
2015-06-30 07:29:12 +08:00
|
|
|
uint64_t Offset64 = Reloc.getOffset();
|
|
|
|
if ((RelocSize != 4 && RelocSize != 8)) {
|
2018-03-13 18:52:49 +08:00
|
|
|
Linker.reportWarning("unsupported relocation in debug_info section.",
|
|
|
|
DMO);
|
2015-02-14 07:18:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
uint32_t Offset = Offset64;
|
|
|
|
// Mach-o uses REL relocations, the addend is at the relocation offset.
|
|
|
|
uint64_t Addend = Data.getUnsigned(&Offset, RelocSize);
|
2016-02-01 11:44:22 +08:00
|
|
|
uint64_t SymAddress;
|
|
|
|
int64_t SymOffset;
|
|
|
|
|
|
|
|
if (Obj.isRelocationScattered(MachOReloc)) {
|
|
|
|
// The address of the base symbol for scattered relocations is
|
|
|
|
// stored in the reloc itself. The actual addend will store the
|
|
|
|
// base address plus the offset.
|
|
|
|
SymAddress = Obj.getScatteredRelocationValue(MachOReloc);
|
|
|
|
SymOffset = int64_t(Addend) - SymAddress;
|
|
|
|
} else {
|
|
|
|
SymAddress = Addend;
|
|
|
|
SymOffset = 0;
|
|
|
|
}
|
2015-02-14 07:18:22 +08:00
|
|
|
|
|
|
|
auto Sym = Reloc.getSymbol();
|
|
|
|
if (Sym != Obj.symbol_end()) {
|
2016-04-21 05:24:34 +08:00
|
|
|
Expected<StringRef> SymbolName = Sym->getName();
|
2015-07-03 04:55:21 +08:00
|
|
|
if (!SymbolName) {
|
2016-04-21 05:24:34 +08:00
|
|
|
consumeError(SymbolName.takeError());
|
2018-03-13 18:52:49 +08:00
|
|
|
Linker.reportWarning("error getting relocation symbol name.", DMO);
|
2015-02-14 07:18:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
2015-07-03 04:55:21 +08:00
|
|
|
if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
|
2015-02-14 07:18:22 +08:00
|
|
|
ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
|
2016-02-01 11:44:22 +08:00
|
|
|
} else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) {
|
2018-02-22 19:32:51 +08:00
|
|
|
// Do not store the addend. The addend was the address of the symbol in
|
|
|
|
// the object file, the address in the binary that is stored in the debug
|
|
|
|
// map doesn't need to be offset.
|
2016-02-01 11:44:22 +08:00
|
|
|
ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping);
|
2015-02-14 07:18:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Dispatch the valid relocation finding logic to the
|
2015-02-14 07:18:22 +08:00
|
|
|
/// appropriate handler depending on the object file format.
|
2015-09-12 07:45:30 +08:00
|
|
|
bool DwarfLinker::RelocationManager::findValidRelocs(
|
|
|
|
const object::SectionRef &Section, const object::ObjectFile &Obj,
|
|
|
|
const DebugMapObject &DMO) {
|
2015-02-14 07:18:22 +08:00
|
|
|
// Dispatch to the right handler depending on the file type.
|
|
|
|
if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
|
|
|
|
findValidRelocsMachO(Section, *MachOObj, DMO);
|
|
|
|
else
|
2018-03-13 18:52:49 +08:00
|
|
|
Linker.reportWarning(
|
|
|
|
Twine("unsupported object file type: ") + Obj.getFileName(), DMO);
|
2015-02-14 07:18:22 +08:00
|
|
|
|
|
|
|
if (ValidRelocs.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Sort the relocations by offset. We will walk the DIEs linearly in
|
|
|
|
// the file, this allows us to just keep an index in the relocation
|
|
|
|
// array that we advance during our walk, rather than resorting to
|
|
|
|
// some associative container. See DwarfLinker::NextValidReloc.
|
llvm::sort(C.begin(), C.end(), ...) -> llvm::sort(C, ...)
Summary: The convenience wrapper in STLExtras is available since rL342102.
Reviewers: dblaikie, javed.absar, JDevlieghere, andreadb
Subscribers: MatzeB, sanjoy, arsenm, dschuff, mehdi_amini, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, eraman, aheejin, kbarton, JDevlieghere, javed.absar, gbedwell, jrtc27, mgrang, atanasyan, steven_wu, george.burgess.iv, dexonsmith, kristina, jsji, llvm-commits
Differential Revision: https://reviews.llvm.org/D52573
llvm-svn: 343163
2018-09-27 10:13:45 +08:00
|
|
|
llvm::sort(ValidRelocs);
|
2015-02-14 07:18:22 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Look for relocations in the debug_info section that match
|
2015-02-14 07:18:22 +08:00
|
|
|
/// entries in the debug map. These relocations will drive the Dwarf
|
|
|
|
/// link by indicating which DIEs refer to symbols present in the
|
|
|
|
/// linked binary.
|
2018-02-22 19:32:51 +08:00
|
|
|
/// \returns whether there are any valid relocations in the debug info.
|
|
|
|
bool DwarfLinker::RelocationManager::findValidRelocsInDebugInfo(
|
|
|
|
const object::ObjectFile &Obj, const DebugMapObject &DMO) {
|
2015-02-14 07:18:22 +08:00
|
|
|
// Find the debug_info section.
|
|
|
|
for (const object::SectionRef &Section : Obj.sections()) {
|
|
|
|
StringRef SectionName;
|
|
|
|
Section.getName(SectionName);
|
|
|
|
SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
|
|
|
|
if (SectionName != "debug_info")
|
|
|
|
continue;
|
|
|
|
return findValidRelocs(Section, Obj, DMO);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2015-01-29 06:15:14 +08:00
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Checks that there is a relocation against an actual debug
|
2015-02-14 07:18:34 +08:00
|
|
|
/// map entry between \p StartOffset and \p NextOffset.
|
|
|
|
///
|
|
|
|
/// This function must be called with offsets in strictly ascending
|
|
|
|
/// order because it never looks back at relocations it already 'went past'.
|
|
|
|
/// \returns true and sets Info.InDebugMap if it is the case.
|
2018-02-22 19:32:51 +08:00
|
|
|
bool DwarfLinker::RelocationManager::hasValidRelocation(
|
|
|
|
uint32_t StartOffset, uint32_t EndOffset, CompileUnit::DIEInfo &Info) {
|
2015-02-14 07:18:34 +08:00
|
|
|
assert(NextValidReloc == 0 ||
|
|
|
|
StartOffset > ValidRelocs[NextValidReloc - 1].Offset);
|
|
|
|
if (NextValidReloc >= ValidRelocs.size())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
uint64_t RelocOffset = ValidRelocs[NextValidReloc].Offset;
|
|
|
|
|
|
|
|
// We might need to skip some relocs that we didn't consider. For
|
|
|
|
// example the high_pc of a discarded DIE might contain a reloc that
|
|
|
|
// is in the list because it actually corresponds to the start of a
|
|
|
|
// function that is in the debug map.
|
|
|
|
while (RelocOffset < StartOffset && NextValidReloc < ValidRelocs.size() - 1)
|
|
|
|
RelocOffset = ValidRelocs[++NextValidReloc].Offset;
|
|
|
|
|
|
|
|
if (RelocOffset < StartOffset || RelocOffset >= EndOffset)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const auto &ValidReloc = ValidRelocs[NextValidReloc++];
|
2015-06-02 05:12:45 +08:00
|
|
|
const auto &Mapping = ValidReloc.Mapping->getValue();
|
2017-11-02 05:16:06 +08:00
|
|
|
uint64_t ObjectAddress = Mapping.ObjectAddress
|
|
|
|
? uint64_t(*Mapping.ObjectAddress)
|
|
|
|
: std::numeric_limits<uint64_t>::max();
|
2015-09-12 07:45:30 +08:00
|
|
|
if (Linker.Options.Verbose)
|
2015-02-14 07:18:34 +08:00
|
|
|
outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey()
|
2018-02-22 19:32:51 +08:00
|
|
|
<< " "
|
|
|
|
<< format("\t%016" PRIx64 " => %016" PRIx64, ObjectAddress,
|
|
|
|
uint64_t(Mapping.BinaryAddress));
|
2015-02-14 07:18:34 +08:00
|
|
|
|
2016-01-31 12:29:22 +08:00
|
|
|
Info.AddrAdjust = int64_t(Mapping.BinaryAddress) + ValidReloc.Addend;
|
|
|
|
if (Mapping.ObjectAddress)
|
|
|
|
Info.AddrAdjust -= ObjectAddress;
|
2015-02-14 07:18:34 +08:00
|
|
|
Info.InDebugMap = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Get the starting and ending (exclusive) offset for the
|
2015-02-14 07:18:34 +08:00
|
|
|
/// attribute with index \p Idx descibed by \p Abbrev. \p Offset is
|
|
|
|
/// supposed to point to the position of the first attribute described
|
|
|
|
/// by \p Abbrev.
|
|
|
|
/// \return [StartOffset, EndOffset) as a pair.
|
|
|
|
static std::pair<uint32_t, uint32_t>
|
|
|
|
getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
|
|
|
|
unsigned Offset, const DWARFUnit &Unit) {
|
|
|
|
DataExtractor Data = Unit.getDebugInfoExtractor();
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < Idx; ++i)
|
2017-06-27 02:43:01 +08:00
|
|
|
DWARFFormValue::skipValue(Abbrev->getFormByIndex(i), Data, &Offset,
|
|
|
|
Unit.getFormParams());
|
2015-02-14 07:18:34 +08:00
|
|
|
|
|
|
|
uint32_t End = Offset;
|
2017-06-27 02:43:01 +08:00
|
|
|
DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End,
|
|
|
|
Unit.getFormParams());
|
2015-02-14 07:18:34 +08:00
|
|
|
|
|
|
|
return std::make_pair(Offset, End);
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Check if a variable describing DIE should be kept.
|
2015-02-14 07:18:34 +08:00
|
|
|
/// \returns updated TraversalFlags.
|
2015-09-12 07:45:30 +08:00
|
|
|
unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr,
|
2016-12-14 02:25:19 +08:00
|
|
|
const DWARFDie &DIE,
|
2015-09-12 07:45:30 +08:00
|
|
|
CompileUnit &Unit,
|
|
|
|
CompileUnit::DIEInfo &MyInfo,
|
|
|
|
unsigned Flags) {
|
2015-02-14 07:18:34 +08:00
|
|
|
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
|
|
|
|
|
|
|
|
// Global variables with constant value can always be kept.
|
|
|
|
if (!(Flags & TF_InFunctionScope) &&
|
2016-11-15 09:23:06 +08:00
|
|
|
Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
|
2015-02-14 07:18:34 +08:00
|
|
|
MyInfo.InDebugMap = true;
|
|
|
|
return Flags | TF_Keep;
|
|
|
|
}
|
|
|
|
|
2016-11-15 09:23:06 +08:00
|
|
|
Optional<uint32_t> LocationIdx =
|
|
|
|
Abbrev->findAttributeIndex(dwarf::DW_AT_location);
|
|
|
|
if (!LocationIdx)
|
2015-02-14 07:18:34 +08:00
|
|
|
return Flags;
|
|
|
|
|
|
|
|
uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
|
|
|
|
const DWARFUnit &OrigUnit = Unit.getOrigUnit();
|
|
|
|
uint32_t LocationOffset, LocationEndOffset;
|
|
|
|
std::tie(LocationOffset, LocationEndOffset) =
|
2016-11-15 09:23:06 +08:00
|
|
|
getAttributeOffsets(Abbrev, *LocationIdx, Offset, OrigUnit);
|
2015-02-14 07:18:34 +08:00
|
|
|
|
|
|
|
// See if there is a relocation to a valid debug map entry inside
|
|
|
|
// this variable's location. The order is important here. We want to
|
|
|
|
// always check in the variable has a valid relocation, so that the
|
|
|
|
// DIEInfo is filled. However, we don't want a static variable in a
|
|
|
|
// function to force us to keep the enclosing function.
|
2015-09-12 07:45:30 +08:00
|
|
|
if (!RelocMgr.hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) ||
|
2015-02-14 07:18:34 +08:00
|
|
|
(Flags & TF_InFunctionScope))
|
|
|
|
return Flags;
|
|
|
|
|
2017-09-13 17:43:05 +08:00
|
|
|
if (Options.Verbose) {
|
|
|
|
DIDumpOptions DumpOpts;
|
2017-09-21 01:44:00 +08:00
|
|
|
DumpOpts.RecurseDepth = 0;
|
2017-09-13 17:43:05 +08:00
|
|
|
DumpOpts.Verbose = Options.Verbose;
|
2017-09-21 01:44:00 +08:00
|
|
|
DIE.dump(outs(), 8 /* Indent */, DumpOpts);
|
2017-09-13 17:43:05 +08:00
|
|
|
}
|
2015-02-14 07:18:34 +08:00
|
|
|
|
|
|
|
return Flags | TF_Keep;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Check if a function describing DIE should be kept.
|
2015-02-14 07:18:34 +08:00
|
|
|
/// \returns updated TraversalFlags.
|
2018-03-13 18:52:49 +08:00
|
|
|
unsigned DwarfLinker::shouldKeepSubprogramDIE(
|
|
|
|
RelocationManager &RelocMgr, RangesTy &Ranges, const DWARFDie &DIE,
|
|
|
|
const DebugMapObject &DMO, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
|
|
|
|
unsigned Flags) {
|
2015-02-14 07:18:34 +08:00
|
|
|
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
|
|
|
|
|
|
|
|
Flags |= TF_InFunctionScope;
|
|
|
|
|
2016-11-15 09:23:06 +08:00
|
|
|
Optional<uint32_t> LowPcIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc);
|
|
|
|
if (!LowPcIdx)
|
2015-02-14 07:18:34 +08:00
|
|
|
return Flags;
|
|
|
|
|
|
|
|
uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
|
2018-02-21 01:34:29 +08:00
|
|
|
DWARFUnit &OrigUnit = Unit.getOrigUnit();
|
2015-02-14 07:18:34 +08:00
|
|
|
uint32_t LowPcOffset, LowPcEndOffset;
|
|
|
|
std::tie(LowPcOffset, LowPcEndOffset) =
|
2016-11-15 09:23:06 +08:00
|
|
|
getAttributeOffsets(Abbrev, *LowPcIdx, Offset, OrigUnit);
|
2015-02-14 07:18:34 +08:00
|
|
|
|
2017-01-14 05:08:18 +08:00
|
|
|
auto LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc));
|
2016-12-15 06:38:08 +08:00
|
|
|
assert(LowPc.hasValue() && "low_pc attribute is not an address.");
|
|
|
|
if (!LowPc ||
|
2015-09-12 07:45:30 +08:00
|
|
|
!RelocMgr.hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
|
2015-02-14 07:18:34 +08:00
|
|
|
return Flags;
|
|
|
|
|
2017-09-13 17:43:05 +08:00
|
|
|
if (Options.Verbose) {
|
|
|
|
DIDumpOptions DumpOpts;
|
2017-09-21 01:44:00 +08:00
|
|
|
DumpOpts.RecurseDepth = 0;
|
2017-09-13 17:43:05 +08:00
|
|
|
DumpOpts.Verbose = Options.Verbose;
|
2017-09-21 01:44:00 +08:00
|
|
|
DIE.dump(outs(), 8 /* Indent */, DumpOpts);
|
2017-09-13 17:43:05 +08:00
|
|
|
}
|
2015-02-14 07:18:34 +08:00
|
|
|
|
2018-02-21 01:34:29 +08:00
|
|
|
if (DIE.getTag() == dwarf::DW_TAG_label) {
|
|
|
|
if (Unit.hasLabelAt(*LowPc))
|
|
|
|
return Flags;
|
|
|
|
// FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider labels
|
|
|
|
// that don't fall into the CU's aranges. This is wrong IMO. Debug info
|
|
|
|
// generation bugs aside, this is really wrong in the case of labels, where
|
|
|
|
// a label marking the end of a function will have a PC == CU's high_pc.
|
|
|
|
if (dwarf::toAddress(OrigUnit.getUnitDIE().find(dwarf::DW_AT_high_pc))
|
2018-02-22 19:32:51 +08:00
|
|
|
.getValueOr(UINT64_MAX) <= LowPc)
|
2018-02-21 01:34:29 +08:00
|
|
|
return Flags;
|
|
|
|
Unit.addLabelLowPc(*LowPc, MyInfo.AddrAdjust);
|
|
|
|
return Flags | TF_Keep;
|
|
|
|
}
|
|
|
|
|
2015-03-13 02:45:10 +08:00
|
|
|
Flags |= TF_Keep;
|
|
|
|
|
2016-12-20 04:36:41 +08:00
|
|
|
Optional<uint64_t> HighPc = DIE.getHighPC(*LowPc);
|
|
|
|
if (!HighPc) {
|
2018-03-13 18:52:49 +08:00
|
|
|
reportWarning("Function without high_pc. Range will be discarded.\n", DMO,
|
|
|
|
&DIE);
|
2015-03-13 02:45:10 +08:00
|
|
|
return Flags;
|
|
|
|
}
|
|
|
|
|
2015-03-16 04:45:43 +08:00
|
|
|
// Replace the debug map range with a more accurate one.
|
2018-03-13 18:52:49 +08:00
|
|
|
Ranges[*LowPc] = DebugMapObjectRange(*HighPc, MyInfo.AddrAdjust);
|
2016-12-20 04:36:41 +08:00
|
|
|
Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust);
|
2015-03-13 02:45:10 +08:00
|
|
|
return Flags;
|
2015-02-14 07:18:34 +08:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Check if a DIE should be kept.
|
2015-02-14 07:18:34 +08:00
|
|
|
/// \returns updated TraversalFlags.
|
2015-09-12 07:45:30 +08:00
|
|
|
unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr,
|
2018-03-13 18:52:49 +08:00
|
|
|
RangesTy &Ranges, const DWARFDie &DIE,
|
|
|
|
const DebugMapObject &DMO,
|
|
|
|
CompileUnit &Unit,
|
2015-02-14 07:18:34 +08:00
|
|
|
CompileUnit::DIEInfo &MyInfo,
|
|
|
|
unsigned Flags) {
|
|
|
|
switch (DIE.getTag()) {
|
|
|
|
case dwarf::DW_TAG_constant:
|
|
|
|
case dwarf::DW_TAG_variable:
|
2015-09-12 07:45:30 +08:00
|
|
|
return shouldKeepVariableDIE(RelocMgr, DIE, Unit, MyInfo, Flags);
|
2015-02-14 07:18:34 +08:00
|
|
|
case dwarf::DW_TAG_subprogram:
|
2018-02-21 01:34:29 +08:00
|
|
|
case dwarf::DW_TAG_label:
|
2018-03-13 18:52:49 +08:00
|
|
|
return shouldKeepSubprogramDIE(RelocMgr, Ranges, DIE, DMO, Unit, MyInfo,
|
|
|
|
Flags);
|
2015-02-14 07:18:34 +08:00
|
|
|
case dwarf::DW_TAG_imported_module:
|
|
|
|
case dwarf::DW_TAG_imported_declaration:
|
|
|
|
case dwarf::DW_TAG_imported_unit:
|
|
|
|
// We always want to keep these.
|
|
|
|
return Flags | TF_Keep;
|
2016-12-02 02:56:29 +08:00
|
|
|
default:
|
|
|
|
break;
|
2015-02-14 07:18:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return Flags;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Mark the passed DIE as well as all the ones it depends on
|
2015-02-14 07:18:34 +08:00
|
|
|
/// as kept.
|
|
|
|
///
|
|
|
|
/// This function is called by lookForDIEsToKeep on DIEs that are
|
|
|
|
/// newly discovered to be needed in the link. It recursively calls
|
|
|
|
/// back to lookForDIEsToKeep while adding TF_DependencyWalk to the
|
|
|
|
/// TraversalFlags to inform it that it's not doing the primary DIE
|
|
|
|
/// tree walk.
|
2018-06-28 23:01:42 +08:00
|
|
|
void DwarfLinker::keepDIEAndDependencies(
|
|
|
|
RelocationManager &RelocMgr, RangesTy &Ranges, const UnitListTy &Units,
|
|
|
|
const DWARFDie &Die, CompileUnit::DIEInfo &MyInfo,
|
|
|
|
const DebugMapObject &DMO, CompileUnit &CU, bool UseODR) {
|
2016-12-14 02:25:19 +08:00
|
|
|
DWARFUnit &Unit = CU.getOrigUnit();
|
2015-02-14 07:18:34 +08:00
|
|
|
MyInfo.Keep = true;
|
|
|
|
|
2017-09-01 04:22:31 +08:00
|
|
|
// We're looking for incomplete types.
|
|
|
|
MyInfo.Incomplete = Die.getTag() != dwarf::DW_TAG_subprogram &&
|
|
|
|
Die.getTag() != dwarf::DW_TAG_member &&
|
|
|
|
dwarf::toUnsigned(Die.find(dwarf::DW_AT_declaration), 0);
|
|
|
|
|
2015-02-14 07:18:34 +08:00
|
|
|
// First mark all the parent chain as kept.
|
|
|
|
unsigned AncestorIdx = MyInfo.ParentIdx;
|
|
|
|
while (!CU.getInfo(AncestorIdx).Keep) {
|
2015-07-22 06:41:43 +08:00
|
|
|
unsigned ODRFlag = UseODR ? TF_ODR : 0;
|
2018-03-13 18:52:49 +08:00
|
|
|
lookForDIEsToKeep(RelocMgr, Ranges, Units, Unit.getDIEAtIndex(AncestorIdx),
|
|
|
|
DMO, CU,
|
2015-07-22 06:41:43 +08:00
|
|
|
TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag);
|
2015-02-14 07:18:34 +08:00
|
|
|
AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then we need to mark all the DIEs referenced by this DIE's
|
|
|
|
// attributes as kept.
|
2017-06-30 00:52:08 +08:00
|
|
|
DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
|
2015-09-11 12:17:25 +08:00
|
|
|
const auto *Abbrev = Die.getAbbreviationDeclarationPtr();
|
|
|
|
uint32_t Offset = Die.getOffset() + getULEB128Size(Abbrev->getCode());
|
2015-02-14 07:18:34 +08:00
|
|
|
|
2017-09-01 04:22:31 +08:00
|
|
|
// Mark all DIEs referenced through attributes as kept.
|
2015-02-14 07:18:34 +08:00
|
|
|
for (const auto &AttrSpec : Abbrev->attributes()) {
|
|
|
|
DWARFFormValue Val(AttrSpec.Form);
|
|
|
|
|
2018-02-28 03:24:36 +08:00
|
|
|
if (!Val.isFormClass(DWARFFormValue::FC_Reference) ||
|
|
|
|
AttrSpec.Attr == dwarf::DW_AT_sibling) {
|
2017-06-27 02:43:01 +08:00
|
|
|
DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
|
|
|
|
Unit.getFormParams());
|
2015-02-14 07:18:34 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-11-08 03:57:12 +08:00
|
|
|
Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
|
2015-02-14 07:18:34 +08:00
|
|
|
CompileUnit *ReferencedCU;
|
2018-03-13 18:52:49 +08:00
|
|
|
if (auto RefDie = resolveDIEReference(*this, DMO, Units, Val, Unit, Die,
|
|
|
|
ReferencedCU)) {
|
2017-07-22 00:51:09 +08:00
|
|
|
uint32_t RefIdx = ReferencedCU->getOrigUnit().getDIEIndex(RefDie);
|
2015-07-22 06:41:43 +08:00
|
|
|
CompileUnit::DIEInfo &Info = ReferencedCU->getInfo(RefIdx);
|
2017-07-21 10:07:33 +08:00
|
|
|
bool IsModuleRef = Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset() &&
|
|
|
|
Info.Ctxt->isDefinedInClangModule();
|
2015-07-22 06:41:43 +08:00
|
|
|
// If the referenced DIE has a DeclContext that has already been
|
|
|
|
// emitted, then do not keep the one in this CU. We'll link to
|
|
|
|
// the canonical DIE in cloneDieReferenceAttribute.
|
|
|
|
// FIXME: compatibility with dsymutil-classic. UseODR shouldn't
|
|
|
|
// be necessary and could be advantageously replaced by
|
|
|
|
// ReferencedCU->hasODR() && CU.hasODR().
|
|
|
|
// FIXME: compatibility with dsymutil-classic. There is no
|
|
|
|
// reason not to unique ref_addr references.
|
2017-07-21 10:07:33 +08:00
|
|
|
if (AttrSpec.Form != dwarf::DW_FORM_ref_addr && (UseODR || IsModuleRef) &&
|
|
|
|
Info.Ctxt &&
|
2015-07-22 06:41:43 +08:00
|
|
|
Info.Ctxt != ReferencedCU->getInfo(Info.ParentIdx).Ctxt &&
|
|
|
|
Info.Ctxt->getCanonicalDIEOffset() && isODRAttribute(AttrSpec.Attr))
|
|
|
|
continue;
|
|
|
|
|
2015-11-11 05:31:05 +08:00
|
|
|
// Keep a module forward declaration if there is no definition.
|
|
|
|
if (!(isODRAttribute(AttrSpec.Attr) && Info.Ctxt &&
|
|
|
|
Info.Ctxt->getCanonicalDIEOffset()))
|
|
|
|
Info.Prune = false;
|
|
|
|
|
2015-07-22 06:41:43 +08:00
|
|
|
unsigned ODRFlag = UseODR ? TF_ODR : 0;
|
2018-03-13 18:52:49 +08:00
|
|
|
lookForDIEsToKeep(RelocMgr, Ranges, Units, RefDie, DMO, *ReferencedCU,
|
2015-07-22 06:41:43 +08:00
|
|
|
TF_Keep | TF_DependencyWalk | ODRFlag);
|
2017-09-01 04:22:31 +08:00
|
|
|
|
|
|
|
// The incomplete property is propagated if the current DIE is complete
|
|
|
|
// but references an incomplete DIE.
|
|
|
|
if (Info.Incomplete && !MyInfo.Incomplete &&
|
|
|
|
(Die.getTag() == dwarf::DW_TAG_typedef ||
|
|
|
|
Die.getTag() == dwarf::DW_TAG_member ||
|
|
|
|
Die.getTag() == dwarf::DW_TAG_reference_type ||
|
|
|
|
Die.getTag() == dwarf::DW_TAG_ptr_to_member_type ||
|
|
|
|
Die.getTag() == dwarf::DW_TAG_pointer_type))
|
|
|
|
MyInfo.Incomplete = true;
|
2015-07-22 06:41:43 +08:00
|
|
|
}
|
2015-02-14 07:18:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-01 21:24:39 +08:00
|
|
|
namespace {
|
|
|
|
/// This class represents an item in the work list. In addition to it's obvious
|
|
|
|
/// purpose of representing the state associated with a particular run of the
|
|
|
|
/// work loop, it also serves as a marker to indicate that we should run the
|
|
|
|
/// "continuation" code.
|
|
|
|
///
|
|
|
|
/// Originally, the latter was lambda which allowed arbitrary code to be run.
|
|
|
|
/// Because we always need to run the exact same code, it made more sense to
|
|
|
|
/// use a boolean and repurpose the already existing DIE field.
|
|
|
|
struct WorklistItem {
|
|
|
|
DWARFDie Die;
|
|
|
|
unsigned Flags;
|
|
|
|
bool IsContinuation;
|
|
|
|
CompileUnit::DIEInfo *ChildInfo = nullptr;
|
|
|
|
|
|
|
|
/// Construct a classic worklist item.
|
|
|
|
WorklistItem(DWARFDie Die, unsigned Flags)
|
|
|
|
: Die(Die), Flags(Flags), IsContinuation(false){};
|
|
|
|
|
|
|
|
/// Creates a continuation marker.
|
|
|
|
WorklistItem(DWARFDie Die) : Die(Die), IsContinuation(true){};
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
// Helper that updates the completeness of the current DIE. It depends on the
|
|
|
|
// fact that the incompletness of its children is already computed.
|
|
|
|
static void updateIncompleteness(const DWARFDie &Die,
|
|
|
|
CompileUnit::DIEInfo &ChildInfo,
|
|
|
|
CompileUnit &CU) {
|
|
|
|
// Only propagate incomplete members.
|
|
|
|
if (Die.getTag() != dwarf::DW_TAG_structure_type &&
|
|
|
|
Die.getTag() != dwarf::DW_TAG_class_type)
|
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned Idx = CU.getOrigUnit().getDIEIndex(Die);
|
|
|
|
CompileUnit::DIEInfo &MyInfo = CU.getInfo(Idx);
|
|
|
|
|
|
|
|
if (MyInfo.Incomplete)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ChildInfo.Incomplete || ChildInfo.Prune)
|
|
|
|
MyInfo.Incomplete = true;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Recursively walk the \p DIE tree and look for DIEs to
|
2015-02-14 07:18:34 +08:00
|
|
|
/// keep. Store that information in \p CU's DIEInfo.
|
|
|
|
///
|
|
|
|
/// This function is the entry point of the DIE selection
|
|
|
|
/// algorithm. It is expected to walk the DIE tree in file order and
|
|
|
|
/// (though the mediation of its helper) call hasValidRelocation() on
|
|
|
|
/// each DIE that might be a 'root DIE' (See DwarfLinker class
|
|
|
|
/// comment).
|
|
|
|
/// While walking the dependencies of root DIEs, this function is
|
|
|
|
/// also called, but during these dependency walks the file order is
|
|
|
|
/// not respected. The TF_DependencyWalk flag tells us which kind of
|
|
|
|
/// traversal we are currently doing.
|
2017-09-01 04:22:31 +08:00
|
|
|
///
|
|
|
|
/// The return value indicates whether the DIE is incomplete.
|
2018-08-01 21:24:39 +08:00
|
|
|
void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr,
|
2018-06-28 23:01:42 +08:00
|
|
|
RangesTy &Ranges, const UnitListTy &Units,
|
2016-12-14 02:25:19 +08:00
|
|
|
const DWARFDie &Die,
|
2015-02-14 07:18:34 +08:00
|
|
|
const DebugMapObject &DMO, CompileUnit &CU,
|
|
|
|
unsigned Flags) {
|
2018-08-01 21:24:39 +08:00
|
|
|
// LIFO work list.
|
|
|
|
SmallVector<WorklistItem, 4> Worklist;
|
|
|
|
Worklist.emplace_back(Die, Flags);
|
2015-02-14 07:18:34 +08:00
|
|
|
|
2018-08-01 21:24:39 +08:00
|
|
|
while (!Worklist.empty()) {
|
|
|
|
WorklistItem Current = Worklist.back();
|
|
|
|
Worklist.pop_back();
|
|
|
|
|
|
|
|
if (Current.IsContinuation) {
|
|
|
|
updateIncompleteness(Current.Die, *Current.ChildInfo, CU);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Idx = CU.getOrigUnit().getDIEIndex(Current.Die);
|
|
|
|
CompileUnit::DIEInfo &MyInfo = CU.getInfo(Idx);
|
|
|
|
|
|
|
|
// At this point we are guaranteed to have a continuation marker before us
|
|
|
|
// in the worklist, except for the last DIE.
|
|
|
|
if (!Worklist.empty())
|
|
|
|
Worklist.back().ChildInfo = &MyInfo;
|
|
|
|
|
|
|
|
if (MyInfo.Prune)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If the Keep flag is set, we are marking a required DIE's dependencies.
|
|
|
|
// If our target is already marked as kept, we're all set.
|
|
|
|
bool AlreadyKept = MyInfo.Keep;
|
|
|
|
if ((Current.Flags & TF_DependencyWalk) && AlreadyKept)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// We must not call shouldKeepDIE while called from keepDIEAndDependencies,
|
|
|
|
// because it would screw up the relocation finding logic.
|
|
|
|
if (!(Current.Flags & TF_DependencyWalk))
|
|
|
|
Current.Flags = shouldKeepDIE(RelocMgr, Ranges, Current.Die, DMO, CU,
|
|
|
|
MyInfo, Current.Flags);
|
|
|
|
|
|
|
|
// If it is a newly kept DIE mark it as well as all its dependencies as
|
|
|
|
// kept.
|
|
|
|
if (!AlreadyKept && (Current.Flags & TF_Keep)) {
|
|
|
|
bool UseOdr = (Current.Flags & TF_DependencyWalk)
|
|
|
|
? (Current.Flags & TF_ODR)
|
|
|
|
: CU.hasODR();
|
|
|
|
keepDIEAndDependencies(RelocMgr, Ranges, Units, Current.Die, MyInfo, DMO,
|
|
|
|
CU, UseOdr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The TF_ParentWalk flag tells us that we are currently walking up
|
|
|
|
// the parent chain of a required DIE, and we don't want to mark all
|
|
|
|
// the children of the parents as kept (consider for example a
|
|
|
|
// DW_TAG_namespace node in the parent chain). There are however a
|
|
|
|
// set of DIE types for which we want to ignore that directive and still
|
|
|
|
// walk their children.
|
|
|
|
if (dieNeedsChildrenToBeMeaningful(Current.Die.getTag()))
|
|
|
|
Current.Flags &= ~TF_ParentWalk;
|
|
|
|
|
|
|
|
if (!Current.Die.hasChildren() || (Current.Flags & TF_ParentWalk))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Add children in reverse order to the worklist to effectively process
|
|
|
|
// them in order.
|
|
|
|
for (auto Child : reverse(Current.Die.children())) {
|
|
|
|
// Add continuation marker before every child to calculate incompleteness
|
|
|
|
// after the last child is processed. We can't store this information in
|
|
|
|
// the same item because we might have to process other continuations
|
|
|
|
// first.
|
|
|
|
Worklist.emplace_back(Current.Die);
|
|
|
|
Worklist.emplace_back(Child, Current.Flags);
|
|
|
|
}
|
2017-09-01 04:22:31 +08:00
|
|
|
}
|
2015-02-14 07:18:34 +08:00
|
|
|
}
|
|
|
|
|
2018-02-22 19:32:51 +08:00
|
|
|
/// Assign an abbreviation number to \p Abbrev.
|
2015-03-05 06:07:44 +08:00
|
|
|
///
|
|
|
|
/// Our DIEs get freed after every DebugMapObject has been processed,
|
|
|
|
/// thus the FoldingSet we use to unique DIEAbbrevs cannot refer to
|
|
|
|
/// the instances hold by the DIEs. When we encounter an abbreviation
|
|
|
|
/// that we don't know, we create a permanent copy of it.
|
|
|
|
void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) {
|
|
|
|
// Check the set for priors.
|
|
|
|
FoldingSetNodeID ID;
|
|
|
|
Abbrev.Profile(ID);
|
|
|
|
void *InsertToken;
|
|
|
|
DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(ID, InsertToken);
|
|
|
|
|
|
|
|
// If it's newly added.
|
|
|
|
if (InSet) {
|
|
|
|
// Assign existing abbreviation number.
|
|
|
|
Abbrev.setNumber(InSet->getNumber());
|
|
|
|
} else {
|
|
|
|
// Add to abbreviation list.
|
|
|
|
Abbreviations.push_back(
|
2015-11-18 08:34:10 +08:00
|
|
|
llvm::make_unique<DIEAbbrev>(Abbrev.getTag(), Abbrev.hasChildren()));
|
2015-03-05 06:07:44 +08:00
|
|
|
for (const auto &Attr : Abbrev.getData())
|
|
|
|
Abbreviations.back()->AddAttribute(Attr.getAttribute(), Attr.getForm());
|
2015-11-18 08:34:10 +08:00
|
|
|
AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken);
|
2015-03-05 06:07:44 +08:00
|
|
|
// Assign the unique abbreviation number.
|
|
|
|
Abbrev.setNumber(Abbreviations.size());
|
|
|
|
Abbreviations.back()->setNumber(Abbreviations.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
unsigned DwarfLinker::DIECloner::cloneStringAttribute(
|
|
|
|
DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
|
|
|
|
const DWARFUnit &U, OffsetsStringPool &StringPool, AttributesInfo &Info) {
|
2015-03-05 06:07:44 +08:00
|
|
|
// Switch everything to out of line strings.
|
2016-11-01 00:46:02 +08:00
|
|
|
const char *String = *Val.getAsCString();
|
2018-03-13 18:52:49 +08:00
|
|
|
auto StringEntry = StringPool.getEntry(String);
|
|
|
|
|
|
|
|
// Update attributes info.
|
2018-02-08 18:48:54 +08:00
|
|
|
if (AttrSpec.Attr == dwarf::DW_AT_name)
|
|
|
|
Info.Name = StringEntry;
|
|
|
|
else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||
|
|
|
|
AttrSpec.Attr == dwarf::DW_AT_linkage_name)
|
|
|
|
Info.MangledName = StringEntry;
|
2018-03-13 18:52:49 +08:00
|
|
|
|
2015-06-26 07:46:41 +08:00
|
|
|
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
|
2018-02-08 18:48:54 +08:00
|
|
|
DIEInteger(StringEntry.getOffset()));
|
2018-03-13 18:52:49 +08:00
|
|
|
|
2015-03-05 06:07:44 +08:00
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
2015-09-15 00:46:10 +08:00
|
|
|
unsigned DwarfLinker::DIECloner::cloneDieReferenceAttribute(
|
2018-02-22 19:32:51 +08:00
|
|
|
DIE &Die, const DWARFDie &InputDIE, AttributeSpec AttrSpec,
|
2018-03-13 18:52:49 +08:00
|
|
|
unsigned AttrSize, const DWARFFormValue &Val, const DebugMapObject &DMO,
|
|
|
|
CompileUnit &Unit) {
|
2015-07-22 06:41:43 +08:00
|
|
|
const DWARFUnit &U = Unit.getOrigUnit();
|
2016-11-01 00:46:02 +08:00
|
|
|
uint32_t Ref = *Val.getAsReference();
|
2015-03-07 07:22:53 +08:00
|
|
|
DIE *NewRefDie = nullptr;
|
|
|
|
CompileUnit *RefUnit = nullptr;
|
2015-07-22 06:41:43 +08:00
|
|
|
DeclContext *Ctxt = nullptr;
|
|
|
|
|
2018-02-22 19:32:51 +08:00
|
|
|
DWARFDie RefDie =
|
2018-03-13 18:52:49 +08:00
|
|
|
resolveDIEReference(Linker, DMO, CompileUnits, Val, U, InputDIE, RefUnit);
|
2015-07-22 06:41:43 +08:00
|
|
|
|
|
|
|
// If the referenced DIE is not found, drop the attribute.
|
2018-02-28 03:24:36 +08:00
|
|
|
if (!RefDie || AttrSpec.Attr == dwarf::DW_AT_sibling)
|
2015-03-07 07:22:53 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
unsigned Idx = RefUnit->getOrigUnit().getDIEIndex(RefDie);
|
|
|
|
CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(Idx);
|
2015-07-22 06:41:43 +08:00
|
|
|
|
|
|
|
// If we already have emitted an equivalent DeclContext, just point
|
|
|
|
// at it.
|
|
|
|
if (isODRAttribute(AttrSpec.Attr)) {
|
|
|
|
Ctxt = RefInfo.Ctxt;
|
|
|
|
if (Ctxt && Ctxt->getCanonicalDIEOffset()) {
|
|
|
|
DIEInteger Attr(Ctxt->getCanonicalDIEOffset());
|
|
|
|
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::DW_FORM_ref_addr, Attr);
|
2016-11-01 00:46:02 +08:00
|
|
|
return U.getRefAddrByteSize();
|
2015-07-22 06:41:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-07 07:22:53 +08:00
|
|
|
if (!RefInfo.Clone) {
|
|
|
|
assert(Ref > InputDIE.getOffset());
|
|
|
|
// We haven't cloned this DIE yet. Just create an empty one and
|
|
|
|
// store it. It'll get really cloned when we process it.
|
2016-12-14 02:25:19 +08:00
|
|
|
RefInfo.Clone = DIE::get(DIEAlloc, dwarf::Tag(RefDie.getTag()));
|
2015-03-07 07:22:53 +08:00
|
|
|
}
|
|
|
|
NewRefDie = RefInfo.Clone;
|
|
|
|
|
2015-07-22 06:41:43 +08:00
|
|
|
if (AttrSpec.Form == dwarf::DW_FORM_ref_addr ||
|
|
|
|
(Unit.hasODR() && isODRAttribute(AttrSpec.Attr))) {
|
2015-03-07 07:22:53 +08:00
|
|
|
// We cannot currently rely on a DIEEntry to emit ref_addr
|
|
|
|
// references, because the implementation calls back to DwarfDebug
|
|
|
|
// to find the unit offset. (We don't have a DwarfDebug)
|
|
|
|
// FIXME: we should be able to design DIEEntry reliance on
|
|
|
|
// DwarfDebug away.
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
uint64_t Attr;
|
2015-03-07 07:22:53 +08:00
|
|
|
if (Ref < InputDIE.getOffset()) {
|
|
|
|
// We must have already cloned that DIE.
|
|
|
|
uint32_t NewRefOffset =
|
|
|
|
RefUnit->getStartOffset() + NewRefDie->getOffset();
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
Attr = NewRefOffset;
|
2015-06-26 07:46:41 +08:00
|
|
|
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::DW_FORM_ref_addr, DIEInteger(Attr));
|
2015-03-07 07:22:53 +08:00
|
|
|
} else {
|
|
|
|
// A forward reference. Note and fixup later.
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
Attr = 0xBADDEF;
|
2015-06-26 07:46:41 +08:00
|
|
|
Unit.noteForwardReference(
|
2015-07-22 06:41:43 +08:00
|
|
|
NewRefDie, RefUnit, Ctxt,
|
2015-06-26 07:46:41 +08:00
|
|
|
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::DW_FORM_ref_addr, DIEInteger(Attr)));
|
2015-03-07 07:22:53 +08:00
|
|
|
}
|
2016-11-01 00:46:02 +08:00
|
|
|
return U.getRefAddrByteSize();
|
2015-03-07 07:22:53 +08:00
|
|
|
}
|
|
|
|
|
2015-06-26 07:46:41 +08:00
|
|
|
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::Form(AttrSpec.Form), DIEEntry(*NewRefDie));
|
2015-03-05 06:07:44 +08:00
|
|
|
return AttrSize;
|
|
|
|
}
|
|
|
|
|
2015-09-15 00:46:10 +08:00
|
|
|
unsigned DwarfLinker::DIECloner::cloneBlockAttribute(DIE &Die,
|
|
|
|
AttributeSpec AttrSpec,
|
|
|
|
const DWARFFormValue &Val,
|
|
|
|
unsigned AttrSize) {
|
2015-08-03 04:48:47 +08:00
|
|
|
DIEValueList *Attr;
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
DIEValue Value;
|
2015-03-05 06:07:44 +08:00
|
|
|
DIELoc *Loc = nullptr;
|
|
|
|
DIEBlock *Block = nullptr;
|
|
|
|
// Just copy the block data over.
|
2015-03-14 02:35:39 +08:00
|
|
|
if (AttrSpec.Form == dwarf::DW_FORM_exprloc) {
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
Loc = new (DIEAlloc) DIELoc;
|
2015-09-15 00:46:10 +08:00
|
|
|
Linker.DIELocs.push_back(Loc);
|
2015-03-05 06:07:44 +08:00
|
|
|
} else {
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
Block = new (DIEAlloc) DIEBlock;
|
2015-09-15 00:46:10 +08:00
|
|
|
Linker.DIEBlocks.push_back(Block);
|
2015-03-05 06:07:44 +08:00
|
|
|
}
|
2015-08-03 04:48:47 +08:00
|
|
|
Attr = Loc ? static_cast<DIEValueList *>(Loc)
|
|
|
|
: static_cast<DIEValueList *>(Block);
|
2015-05-28 06:31:41 +08:00
|
|
|
|
|
|
|
if (Loc)
|
|
|
|
Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::Form(AttrSpec.Form), Loc);
|
|
|
|
else
|
|
|
|
Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::Form(AttrSpec.Form), Block);
|
2015-03-05 06:07:44 +08:00
|
|
|
ArrayRef<uint8_t> Bytes = *Val.getAsBlock();
|
|
|
|
for (auto Byte : Bytes)
|
2015-06-26 07:46:41 +08:00
|
|
|
Attr->addValue(DIEAlloc, static_cast<dwarf::Attribute>(0),
|
|
|
|
dwarf::DW_FORM_data1, DIEInteger(Byte));
|
2015-03-05 06:07:44 +08:00
|
|
|
// FIXME: If DIEBlock and DIELoc just reuses the Size field of
|
|
|
|
// the DIE class, this if could be replaced by
|
|
|
|
// Attr->setSize(Bytes.size()).
|
2015-09-15 00:46:10 +08:00
|
|
|
if (Linker.Streamer) {
|
|
|
|
auto *AsmPrinter = &Linker.Streamer->getAsmPrinter();
|
2015-03-05 06:07:44 +08:00
|
|
|
if (Loc)
|
2015-09-15 00:46:10 +08:00
|
|
|
Loc->ComputeSize(AsmPrinter);
|
2015-03-05 06:07:44 +08:00
|
|
|
else
|
2015-09-15 00:46:10 +08:00
|
|
|
Block->ComputeSize(AsmPrinter);
|
2015-03-05 06:07:44 +08:00
|
|
|
}
|
2015-06-26 07:46:41 +08:00
|
|
|
Die.addValue(DIEAlloc, Value);
|
2015-03-05 06:07:44 +08:00
|
|
|
return AttrSize;
|
|
|
|
}
|
|
|
|
|
2015-09-15 00:46:10 +08:00
|
|
|
unsigned DwarfLinker::DIECloner::cloneAddressAttribute(
|
|
|
|
DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
|
|
|
|
const CompileUnit &Unit, AttributesInfo &Info) {
|
2016-11-01 00:46:02 +08:00
|
|
|
uint64_t Addr = *Val.getAsAddress();
|
2018-01-29 22:52:50 +08:00
|
|
|
|
2018-02-08 18:48:54 +08:00
|
|
|
if (LLVM_UNLIKELY(Linker.Options.Update)) {
|
|
|
|
if (AttrSpec.Attr == dwarf::DW_AT_low_pc)
|
|
|
|
Info.HasLowPc = true;
|
|
|
|
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::Form(AttrSpec.Form), DIEInteger(Addr));
|
|
|
|
return Unit.getOrigUnit().getAddressByteSize();
|
|
|
|
}
|
|
|
|
|
2015-03-12 02:45:52 +08:00
|
|
|
if (AttrSpec.Attr == dwarf::DW_AT_low_pc) {
|
|
|
|
if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine ||
|
|
|
|
Die.getTag() == dwarf::DW_TAG_lexical_block)
|
2015-08-31 09:43:14 +08:00
|
|
|
// The low_pc of a block or inline subroutine might get
|
|
|
|
// relocated because it happens to match the low_pc of the
|
|
|
|
// enclosing subprogram. To prevent issues with that, always use
|
|
|
|
// the low_pc from the input DIE if relocations have been applied.
|
2017-11-02 05:16:06 +08:00
|
|
|
Addr = (Info.OrigLowPc != std::numeric_limits<uint64_t>::max()
|
|
|
|
? Info.OrigLowPc
|
|
|
|
: Addr) +
|
2015-08-31 09:43:14 +08:00
|
|
|
Info.PCOffset;
|
2015-03-14 02:35:54 +08:00
|
|
|
else if (Die.getTag() == dwarf::DW_TAG_compile_unit) {
|
|
|
|
Addr = Unit.getLowPc();
|
2017-11-02 05:16:06 +08:00
|
|
|
if (Addr == std::numeric_limits<uint64_t>::max())
|
2015-03-14 02:35:54 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-03-16 10:05:10 +08:00
|
|
|
Info.HasLowPc = true;
|
2015-03-12 02:45:52 +08:00
|
|
|
} else if (AttrSpec.Attr == dwarf::DW_AT_high_pc) {
|
2015-03-14 02:35:54 +08:00
|
|
|
if (Die.getTag() == dwarf::DW_TAG_compile_unit) {
|
|
|
|
if (uint64_t HighPc = Unit.getHighPc())
|
|
|
|
Addr = HighPc;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
// If we have a high_pc recorded for the input DIE, use
|
|
|
|
// it. Otherwise (when no relocations where applied) just use the
|
|
|
|
// one we just decoded.
|
|
|
|
Addr = (Info.OrigHighPc ? Info.OrigHighPc : Addr) + Info.PCOffset;
|
2015-03-12 02:45:52 +08:00
|
|
|
}
|
|
|
|
|
2015-06-26 07:46:41 +08:00
|
|
|
Die.addValue(DIEAlloc, static_cast<dwarf::Attribute>(AttrSpec.Attr),
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
static_cast<dwarf::Form>(AttrSpec.Form), DIEInteger(Addr));
|
2015-03-12 02:45:52 +08:00
|
|
|
return Unit.getOrigUnit().getAddressByteSize();
|
|
|
|
}
|
|
|
|
|
2015-09-15 00:46:10 +08:00
|
|
|
unsigned DwarfLinker::DIECloner::cloneScalarAttribute(
|
2018-03-13 18:52:49 +08:00
|
|
|
DIE &Die, const DWARFDie &InputDIE, const DebugMapObject &DMO,
|
|
|
|
CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val,
|
|
|
|
unsigned AttrSize, AttributesInfo &Info) {
|
2015-03-05 06:07:44 +08:00
|
|
|
uint64_t Value;
|
2018-02-08 18:48:54 +08:00
|
|
|
|
|
|
|
if (LLVM_UNLIKELY(Linker.Options.Update)) {
|
|
|
|
if (auto OptionalValue = Val.getAsUnsignedConstant())
|
|
|
|
Value = *OptionalValue;
|
|
|
|
else if (auto OptionalValue = Val.getAsSignedConstant())
|
|
|
|
Value = *OptionalValue;
|
|
|
|
else if (auto OptionalValue = Val.getAsSectionOffset())
|
|
|
|
Value = *OptionalValue;
|
|
|
|
else {
|
|
|
|
Linker.reportWarning(
|
2018-03-13 18:52:49 +08:00
|
|
|
"Unsupported scalar attribute form. Dropping attribute.", DMO,
|
|
|
|
&InputDIE);
|
2018-02-08 18:48:54 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
|
|
|
|
Info.IsDeclaration = true;
|
|
|
|
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::Form(AttrSpec.Form), DIEInteger(Value));
|
|
|
|
return AttrSize;
|
|
|
|
}
|
|
|
|
|
2015-03-14 02:35:54 +08:00
|
|
|
if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
|
|
|
|
Die.getTag() == dwarf::DW_TAG_compile_unit) {
|
|
|
|
if (Unit.getLowPc() == -1ULL)
|
|
|
|
return 0;
|
|
|
|
// Dwarf >= 4 high_pc is an size, not an address.
|
|
|
|
Value = Unit.getHighPc() - Unit.getLowPc();
|
|
|
|
} else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
|
2015-03-05 06:07:44 +08:00
|
|
|
Value = *Val.getAsSectionOffset();
|
|
|
|
else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
|
|
|
|
Value = *Val.getAsSignedConstant();
|
|
|
|
else if (auto OptionalValue = Val.getAsUnsignedConstant())
|
|
|
|
Value = *OptionalValue;
|
|
|
|
else {
|
2015-09-15 00:46:10 +08:00
|
|
|
Linker.reportWarning(
|
2018-03-13 18:52:49 +08:00
|
|
|
"Unsupported scalar attribute form. Dropping attribute.", DMO,
|
|
|
|
&InputDIE);
|
2015-03-05 06:07:44 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-06-26 07:46:41 +08:00
|
|
|
PatchLocation Patch =
|
|
|
|
Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
|
|
|
|
dwarf::Form(AttrSpec.Form), DIEInteger(Value));
|
2018-01-29 22:52:50 +08:00
|
|
|
if (AttrSpec.Attr == dwarf::DW_AT_ranges) {
|
2015-06-26 07:46:41 +08:00
|
|
|
Unit.noteRangeAttribute(Die, Patch);
|
2018-01-29 22:52:50 +08:00
|
|
|
Info.HasRanges = true;
|
|
|
|
}
|
2015-09-11 12:17:30 +08:00
|
|
|
|
2015-03-14 23:49:07 +08:00
|
|
|
// A more generic way to check for location attributes would be
|
|
|
|
// nice, but it's very unlikely that any other attribute needs a
|
|
|
|
// location list.
|
|
|
|
else if (AttrSpec.Attr == dwarf::DW_AT_location ||
|
|
|
|
AttrSpec.Attr == dwarf::DW_AT_frame_base)
|
2015-06-26 07:46:41 +08:00
|
|
|
Unit.noteLocationAttribute(Patch, Info.PCOffset);
|
2015-03-16 10:05:10 +08:00
|
|
|
else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
|
|
|
|
Info.IsDeclaration = true;
|
2015-03-14 23:49:07 +08:00
|
|
|
|
2015-03-05 06:07:44 +08:00
|
|
|
return AttrSize;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Clone \p InputDIE's attribute described by \p AttrSpec with
|
2015-03-05 06:07:44 +08:00
|
|
|
/// value \p Val, and add it to \p Die.
|
|
|
|
/// \returns the size of the cloned attribute.
|
2015-09-15 00:46:10 +08:00
|
|
|
unsigned DwarfLinker::DIECloner::cloneAttribute(
|
2018-03-13 18:52:49 +08:00
|
|
|
DIE &Die, const DWARFDie &InputDIE, const DebugMapObject &DMO,
|
|
|
|
CompileUnit &Unit, OffsetsStringPool &StringPool, const DWARFFormValue &Val,
|
|
|
|
const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &Info) {
|
2015-03-05 06:07:44 +08:00
|
|
|
const DWARFUnit &U = Unit.getOrigUnit();
|
|
|
|
|
|
|
|
switch (AttrSpec.Form) {
|
|
|
|
case dwarf::DW_FORM_strp:
|
|
|
|
case dwarf::DW_FORM_string:
|
2018-03-13 18:52:49 +08:00
|
|
|
return cloneStringAttribute(Die, AttrSpec, Val, U, StringPool, Info);
|
2015-03-05 06:07:44 +08:00
|
|
|
case dwarf::DW_FORM_ref_addr:
|
|
|
|
case dwarf::DW_FORM_ref1:
|
|
|
|
case dwarf::DW_FORM_ref2:
|
|
|
|
case dwarf::DW_FORM_ref4:
|
|
|
|
case dwarf::DW_FORM_ref8:
|
2015-03-07 07:22:53 +08:00
|
|
|
return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val,
|
2018-03-13 18:52:49 +08:00
|
|
|
DMO, Unit);
|
2015-03-05 06:07:44 +08:00
|
|
|
case dwarf::DW_FORM_block:
|
|
|
|
case dwarf::DW_FORM_block1:
|
|
|
|
case dwarf::DW_FORM_block2:
|
|
|
|
case dwarf::DW_FORM_block4:
|
|
|
|
case dwarf::DW_FORM_exprloc:
|
|
|
|
return cloneBlockAttribute(Die, AttrSpec, Val, AttrSize);
|
|
|
|
case dwarf::DW_FORM_addr:
|
2015-03-12 02:45:52 +08:00
|
|
|
return cloneAddressAttribute(Die, AttrSpec, Val, Unit, Info);
|
2015-03-05 06:07:44 +08:00
|
|
|
case dwarf::DW_FORM_data1:
|
|
|
|
case dwarf::DW_FORM_data2:
|
|
|
|
case dwarf::DW_FORM_data4:
|
|
|
|
case dwarf::DW_FORM_data8:
|
|
|
|
case dwarf::DW_FORM_udata:
|
|
|
|
case dwarf::DW_FORM_sdata:
|
|
|
|
case dwarf::DW_FORM_sec_offset:
|
|
|
|
case dwarf::DW_FORM_flag:
|
|
|
|
case dwarf::DW_FORM_flag_present:
|
2018-03-13 18:52:49 +08:00
|
|
|
return cloneScalarAttribute(Die, InputDIE, DMO, Unit, AttrSpec, Val,
|
|
|
|
AttrSize, Info);
|
2015-03-05 06:07:44 +08:00
|
|
|
default:
|
2015-09-15 00:46:10 +08:00
|
|
|
Linker.reportWarning(
|
2018-03-13 18:52:49 +08:00
|
|
|
"Unsupported attribute form in cloneAttribute. Dropping.", DMO,
|
|
|
|
&InputDIE);
|
2015-03-05 06:07:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Apply the valid relocations found by findValidRelocs() to
|
2015-03-07 09:25:09 +08:00
|
|
|
/// the buffer \p Data, taking into account that Data is at \p BaseOffset
|
|
|
|
/// in the debug_info section.
|
|
|
|
///
|
|
|
|
/// Like for findValidRelocs(), this function must be called with
|
|
|
|
/// monotonic \p BaseOffset values.
|
|
|
|
///
|
2018-02-22 19:32:51 +08:00
|
|
|
/// \returns whether any reloc has been applied.
|
|
|
|
bool DwarfLinker::RelocationManager::applyValidRelocs(
|
|
|
|
MutableArrayRef<char> Data, uint32_t BaseOffset, bool isLittleEndian) {
|
2015-03-07 23:16:27 +08:00
|
|
|
assert((NextValidReloc == 0 ||
|
2015-03-12 02:45:57 +08:00
|
|
|
BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
|
|
|
|
"BaseOffset should only be increasing.");
|
2015-03-07 09:25:09 +08:00
|
|
|
if (NextValidReloc >= ValidRelocs.size())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Skip relocs that haven't been applied.
|
|
|
|
while (NextValidReloc < ValidRelocs.size() &&
|
|
|
|
ValidRelocs[NextValidReloc].Offset < BaseOffset)
|
|
|
|
++NextValidReloc;
|
|
|
|
|
|
|
|
bool Applied = false;
|
|
|
|
uint64_t EndOffset = BaseOffset + Data.size();
|
|
|
|
while (NextValidReloc < ValidRelocs.size() &&
|
|
|
|
ValidRelocs[NextValidReloc].Offset >= BaseOffset &&
|
|
|
|
ValidRelocs[NextValidReloc].Offset < EndOffset) {
|
|
|
|
const auto &ValidReloc = ValidRelocs[NextValidReloc++];
|
|
|
|
assert(ValidReloc.Offset - BaseOffset < Data.size());
|
|
|
|
assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size());
|
|
|
|
char Buf[8];
|
|
|
|
uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress;
|
|
|
|
Value += ValidReloc.Addend;
|
|
|
|
for (unsigned i = 0; i != ValidReloc.Size; ++i) {
|
|
|
|
unsigned Index = isLittleEndian ? i : (ValidReloc.Size - i - 1);
|
|
|
|
Buf[i] = uint8_t(Value >> (Index * 8));
|
|
|
|
}
|
|
|
|
assert(ValidReloc.Size <= sizeof(Buf));
|
|
|
|
memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size);
|
|
|
|
Applied = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Applied;
|
|
|
|
}
|
|
|
|
|
2018-01-29 22:52:50 +08:00
|
|
|
static bool isObjCSelector(StringRef Name) {
|
|
|
|
return Name.size() > 2 && (Name[0] == '-' || Name[0] == '+') &&
|
|
|
|
(Name[1] == '[');
|
|
|
|
}
|
|
|
|
|
|
|
|
void DwarfLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit,
|
|
|
|
const DIE *Die,
|
|
|
|
DwarfStringPoolEntryRef Name,
|
2018-03-13 18:52:49 +08:00
|
|
|
OffsetsStringPool &StringPool,
|
2018-01-29 22:52:50 +08:00
|
|
|
bool SkipPubSection) {
|
|
|
|
assert(isObjCSelector(Name.getString()) && "not an objc selector");
|
|
|
|
// Objective C method or class function.
|
|
|
|
// "- [Class(Category) selector :withArg ...]"
|
|
|
|
StringRef ClassNameStart(Name.getString().drop_front(2));
|
|
|
|
size_t FirstSpace = ClassNameStart.find(' ');
|
|
|
|
if (FirstSpace == StringRef::npos)
|
|
|
|
return;
|
|
|
|
|
|
|
|
StringRef SelectorStart(ClassNameStart.data() + FirstSpace + 1);
|
|
|
|
if (!SelectorStart.size())
|
|
|
|
return;
|
|
|
|
|
|
|
|
StringRef Selector(SelectorStart.data(), SelectorStart.size() - 1);
|
2018-03-13 18:52:49 +08:00
|
|
|
Unit.addNameAccelerator(Die, StringPool.getEntry(Selector), SkipPubSection);
|
2018-01-29 22:52:50 +08:00
|
|
|
|
|
|
|
// Add an entry for the class name that points to this
|
|
|
|
// method/class function.
|
|
|
|
StringRef ClassName(ClassNameStart.data(), FirstSpace);
|
2018-03-13 18:52:49 +08:00
|
|
|
Unit.addObjCAccelerator(Die, StringPool.getEntry(ClassName), SkipPubSection);
|
2018-01-29 22:52:50 +08:00
|
|
|
|
|
|
|
if (ClassName[ClassName.size() - 1] == ')') {
|
|
|
|
size_t OpenParens = ClassName.find('(');
|
|
|
|
if (OpenParens != StringRef::npos) {
|
|
|
|
StringRef ClassNameNoCategory(ClassName.data(), OpenParens);
|
2018-03-13 18:52:49 +08:00
|
|
|
Unit.addObjCAccelerator(Die, StringPool.getEntry(ClassNameNoCategory),
|
|
|
|
SkipPubSection);
|
2018-01-29 22:52:50 +08:00
|
|
|
|
|
|
|
std::string MethodNameNoCategory(Name.getString().data(), OpenParens + 2);
|
|
|
|
// FIXME: The missing space here may be a bug, but
|
|
|
|
// dsymutil-classic also does it this way.
|
|
|
|
MethodNameNoCategory.append(SelectorStart);
|
2018-03-13 18:52:49 +08:00
|
|
|
Unit.addNameAccelerator(Die, StringPool.getEntry(MethodNameNoCategory),
|
2018-01-29 22:52:50 +08:00
|
|
|
SkipPubSection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-11 12:17:30 +08:00
|
|
|
static bool
|
|
|
|
shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
|
|
|
|
uint16_t Tag, bool InDebugMap, bool SkipPC,
|
|
|
|
bool InFunctionScope) {
|
|
|
|
switch (AttrSpec.Attr) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case dwarf::DW_AT_low_pc:
|
|
|
|
case dwarf::DW_AT_high_pc:
|
|
|
|
case dwarf::DW_AT_ranges:
|
|
|
|
return SkipPC;
|
|
|
|
case dwarf::DW_AT_location:
|
|
|
|
case dwarf::DW_AT_frame_base:
|
2018-02-22 19:32:51 +08:00
|
|
|
// FIXME: for some reason dsymutil-classic keeps the location attributes
|
|
|
|
// when they are of block type (i.e. not location lists). This is totally
|
|
|
|
// wrong for globals where we will keep a wrong address. It is mostly
|
|
|
|
// harmless for locals, but there is no point in keeping these anyway when
|
|
|
|
// the function wasn't linked.
|
2015-09-11 12:17:30 +08:00
|
|
|
return (SkipPC || (!InFunctionScope && Tag == dwarf::DW_TAG_variable &&
|
|
|
|
!InDebugMap)) &&
|
|
|
|
!DWARFFormValue(AttrSpec.Form).isFormClass(DWARFFormValue::FC_Block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-22 19:32:51 +08:00
|
|
|
DIE *DwarfLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
|
2018-03-13 18:52:49 +08:00
|
|
|
const DebugMapObject &DMO,
|
|
|
|
CompileUnit &Unit,
|
|
|
|
OffsetsStringPool &StringPool,
|
|
|
|
int64_t PCOffset, uint32_t OutOffset,
|
|
|
|
unsigned Flags, DIE *Die) {
|
2015-03-05 06:07:44 +08:00
|
|
|
DWARFUnit &U = Unit.getOrigUnit();
|
2016-12-14 02:25:19 +08:00
|
|
|
unsigned Idx = U.getDIEIndex(InputDIE);
|
2015-03-07 07:22:53 +08:00
|
|
|
CompileUnit::DIEInfo &Info = Unit.getInfo(Idx);
|
2015-03-05 06:07:44 +08:00
|
|
|
|
|
|
|
// Should the DIE appear in the output?
|
|
|
|
if (!Unit.getInfo(Idx).Keep)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
uint32_t Offset = InputDIE.getOffset();
|
2016-12-02 02:56:29 +08:00
|
|
|
assert(!(Die && Info.Clone) && "Can't supply a DIE and a cloned DIE");
|
|
|
|
if (!Die) {
|
|
|
|
// The DIE might have been already created by a forward reference
|
|
|
|
// (see cloneDieReferenceAttribute()).
|
2016-12-02 06:04:16 +08:00
|
|
|
if (!Info.Clone)
|
|
|
|
Info.Clone = DIE::get(DIEAlloc, dwarf::Tag(InputDIE.getTag()));
|
|
|
|
Die = Info.Clone;
|
2016-12-02 02:56:29 +08:00
|
|
|
}
|
|
|
|
|
2015-03-07 07:22:53 +08:00
|
|
|
assert(Die->getTag() == InputDIE.getTag());
|
2015-03-05 06:07:44 +08:00
|
|
|
Die->setOffset(OutOffset);
|
2017-09-01 04:22:31 +08:00
|
|
|
if ((Unit.hasODR() || Unit.isClangModule()) && !Info.Incomplete &&
|
2015-09-24 01:35:52 +08:00
|
|
|
Die->getTag() != dwarf::DW_TAG_namespace && Info.Ctxt &&
|
2015-07-22 06:41:43 +08:00
|
|
|
Info.Ctxt != Unit.getInfo(Info.ParentIdx).Ctxt &&
|
|
|
|
!Info.Ctxt->getCanonicalDIEOffset()) {
|
|
|
|
// We are about to emit a DIE that is the root of its own valid
|
|
|
|
// DeclContext tree. Make the current offset the canonical offset
|
|
|
|
// for this context.
|
|
|
|
Info.Ctxt->setCanonicalDIEOffset(OutOffset + Unit.getStartOffset());
|
|
|
|
}
|
2015-03-05 06:07:44 +08:00
|
|
|
|
|
|
|
// Extract and clone every attribute.
|
2017-06-30 00:52:08 +08:00
|
|
|
DWARFDataExtractor Data = U.getDebugInfoExtractor();
|
2015-09-23 06:20:50 +08:00
|
|
|
// 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.
|
2018-02-22 19:32:51 +08:00
|
|
|
uint32_t NextOffset = (Idx + 1 < U.getNumDIEs())
|
|
|
|
? U.getDIEAtIndex(Idx + 1).getOffset()
|
|
|
|
: U.getNextUnitOffset();
|
2015-03-12 02:45:52 +08:00
|
|
|
AttributesInfo AttrInfo;
|
2015-03-07 09:25:09 +08:00
|
|
|
|
2018-02-22 19:32:51 +08:00
|
|
|
// We could copy the data only if we need to apply a relocation to it. After
|
|
|
|
// testing, it seems there is no performance downside to doing the copy
|
|
|
|
// unconditionally, and it makes the code simpler.
|
2015-03-07 09:25:09 +08:00
|
|
|
SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset));
|
2017-06-30 00:52:08 +08:00
|
|
|
Data =
|
|
|
|
DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
|
2015-03-07 09:25:09 +08:00
|
|
|
// Modify the copy with relocated addresses.
|
2015-09-12 07:45:30 +08:00
|
|
|
if (RelocMgr.applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) {
|
2015-03-12 02:45:52 +08:00
|
|
|
// If we applied relocations, we store the value of high_pc that was
|
|
|
|
// potentially stored in the input DIE. If high_pc is an address
|
|
|
|
// (Dwarf version == 2), then it might have been relocated to a
|
|
|
|
// totally unrelated value (because the end address in the object
|
|
|
|
// file might be start address of another function which got moved
|
2018-02-22 19:32:51 +08:00
|
|
|
// independently by the linker). The computation of the actual
|
2015-03-12 02:45:52 +08:00
|
|
|
// high_pc value is done in cloneAddressAttribute().
|
2017-09-30 08:22:24 +08:00
|
|
|
AttrInfo.OrigHighPc =
|
|
|
|
dwarf::toAddress(InputDIE.find(dwarf::DW_AT_high_pc), 0);
|
2015-08-31 09:43:14 +08:00
|
|
|
// Also store the low_pc. It might get relocated in an
|
|
|
|
// inline_subprogram that happens at the beginning of its
|
|
|
|
// inlining function.
|
2017-11-02 05:16:06 +08:00
|
|
|
AttrInfo.OrigLowPc = dwarf::toAddress(InputDIE.find(dwarf::DW_AT_low_pc),
|
|
|
|
std::numeric_limits<uint64_t>::max());
|
2015-03-12 02:45:52 +08:00
|
|
|
}
|
2015-03-07 09:25:09 +08:00
|
|
|
|
|
|
|
// Reset the Offset to 0 as we will be working on the local copy of
|
|
|
|
// the data.
|
|
|
|
Offset = 0;
|
|
|
|
|
2015-03-05 06:07:44 +08:00
|
|
|
const auto *Abbrev = InputDIE.getAbbreviationDeclarationPtr();
|
|
|
|
Offset += getULEB128Size(Abbrev->getCode());
|
|
|
|
|
2015-03-12 02:45:52 +08:00
|
|
|
// We are entering a subprogram. Get and propagate the PCOffset.
|
|
|
|
if (Die->getTag() == dwarf::DW_TAG_subprogram)
|
|
|
|
PCOffset = Info.AddrAdjust;
|
|
|
|
AttrInfo.PCOffset = PCOffset;
|
|
|
|
|
2015-09-11 12:17:30 +08:00
|
|
|
if (Abbrev->getTag() == dwarf::DW_TAG_subprogram) {
|
|
|
|
Flags |= TF_InFunctionScope;
|
2018-02-08 18:48:54 +08:00
|
|
|
if (!Info.InDebugMap && LLVM_LIKELY(!Options.Update))
|
2015-09-11 12:17:30 +08:00
|
|
|
Flags |= TF_SkipPC;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Copied = false;
|
2015-03-05 06:07:44 +08:00
|
|
|
for (const auto &AttrSpec : Abbrev->attributes()) {
|
2018-02-08 18:48:54 +08:00
|
|
|
if (LLVM_LIKELY(!Options.Update) &&
|
|
|
|
shouldSkipAttribute(AttrSpec, Die->getTag(), Info.InDebugMap,
|
2015-09-11 12:17:30 +08:00
|
|
|
Flags & TF_SkipPC, Flags & TF_InFunctionScope)) {
|
2017-06-27 02:43:01 +08:00
|
|
|
DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
|
|
|
|
U.getFormParams());
|
2015-09-11 12:17:30 +08:00
|
|
|
// FIXME: dsymutil-classic keeps the old abbreviation around
|
|
|
|
// even if it's not used. We can remove this (and the copyAbbrev
|
|
|
|
// helper) as soon as bit-for-bit compatibility is not a goal anymore.
|
|
|
|
if (!Copied) {
|
|
|
|
copyAbbrev(*InputDIE.getAbbreviationDeclarationPtr(), Unit.hasODR());
|
|
|
|
Copied = true;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-03-05 06:07:44 +08:00
|
|
|
DWARFFormValue Val(AttrSpec.Form);
|
|
|
|
uint32_t AttrSize = Offset;
|
2017-11-08 03:57:12 +08:00
|
|
|
Val.extractValue(Data, &Offset, U.getFormParams(), &U);
|
2015-03-05 06:07:44 +08:00
|
|
|
AttrSize = Offset - AttrSize;
|
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
OutOffset += cloneAttribute(*Die, InputDIE, DMO, Unit, StringPool, Val,
|
|
|
|
AttrSpec, AttrSize, AttrInfo);
|
2015-03-05 06:07:44 +08:00
|
|
|
}
|
|
|
|
|
2015-03-16 10:05:10 +08:00
|
|
|
// Look for accelerator entries.
|
|
|
|
uint16_t Tag = InputDIE.getTag();
|
|
|
|
// FIXME: This is slightly wrong. An inline_subroutine without a
|
|
|
|
// low_pc, but with AT_ranges might be interesting to get into the
|
|
|
|
// accelerator tables too. For now stick with dsymutil's behavior.
|
2018-01-29 22:52:50 +08:00
|
|
|
if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
|
2015-03-16 10:05:10 +08:00
|
|
|
Tag != dwarf::DW_TAG_compile_unit &&
|
2018-03-13 18:52:49 +08:00
|
|
|
getDIENames(InputDIE, AttrInfo, StringPool,
|
2018-01-29 22:52:50 +08:00
|
|
|
Tag != dwarf::DW_TAG_inlined_subroutine)) {
|
2015-03-16 10:05:10 +08:00
|
|
|
if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
|
|
|
|
Unit.addNameAccelerator(Die, AttrInfo.MangledName,
|
|
|
|
Tag == dwarf::DW_TAG_inlined_subroutine);
|
2018-01-29 22:52:50 +08:00
|
|
|
if (AttrInfo.Name) {
|
|
|
|
if (AttrInfo.NameWithoutTemplate)
|
|
|
|
Unit.addNameAccelerator(Die, AttrInfo.NameWithoutTemplate,
|
|
|
|
/* SkipPubSection */ true);
|
|
|
|
Unit.addNameAccelerator(Die, AttrInfo.Name,
|
2015-03-16 10:05:10 +08:00
|
|
|
Tag == dwarf::DW_TAG_inlined_subroutine);
|
2018-01-29 22:52:50 +08:00
|
|
|
}
|
|
|
|
if (AttrInfo.Name && isObjCSelector(AttrInfo.Name.getString()))
|
2018-03-13 18:52:49 +08:00
|
|
|
addObjCAccelerator(Unit, Die, AttrInfo.Name, StringPool,
|
|
|
|
/* SkipPubSection =*/true);
|
2018-01-29 22:52:50 +08:00
|
|
|
|
|
|
|
} else if (Tag == dwarf::DW_TAG_namespace) {
|
|
|
|
if (!AttrInfo.Name)
|
2018-03-13 18:52:49 +08:00
|
|
|
AttrInfo.Name = StringPool.getEntry("(anonymous namespace)");
|
2018-01-29 22:52:50 +08:00
|
|
|
Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
|
2015-03-16 10:05:10 +08:00
|
|
|
} else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration &&
|
2018-03-13 18:52:49 +08:00
|
|
|
getDIENames(InputDIE, AttrInfo, StringPool) && AttrInfo.Name &&
|
2018-01-29 22:52:50 +08:00
|
|
|
AttrInfo.Name.getString()[0]) {
|
2018-03-13 18:52:49 +08:00
|
|
|
uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit, DMO);
|
2018-01-29 22:52:50 +08:00
|
|
|
uint64_t RuntimeLang =
|
|
|
|
dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
|
|
|
|
.getValueOr(0);
|
|
|
|
bool ObjCClassIsImplementation =
|
|
|
|
(RuntimeLang == dwarf::DW_LANG_ObjC ||
|
|
|
|
RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
|
|
|
|
dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
|
|
|
|
.getValueOr(0);
|
|
|
|
Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,
|
|
|
|
Hash);
|
2015-03-16 10:05:10 +08:00
|
|
|
}
|
|
|
|
|
2015-11-11 05:31:05 +08:00
|
|
|
// Determine whether there are any children that we want to keep.
|
|
|
|
bool HasChildren = false;
|
2018-01-29 22:52:50 +08:00
|
|
|
for (auto Child : InputDIE.children()) {
|
2015-11-11 05:31:05 +08:00
|
|
|
unsigned Idx = U.getDIEIndex(Child);
|
|
|
|
if (Unit.getInfo(Idx).Keep) {
|
|
|
|
HasChildren = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-28 06:31:41 +08:00
|
|
|
DIEAbbrev NewAbbrev = Die->generateAbbrev();
|
2015-11-11 05:31:05 +08:00
|
|
|
if (HasChildren)
|
2015-03-05 06:07:44 +08:00
|
|
|
NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);
|
|
|
|
// Assign a permanent abbrev number
|
2015-09-15 00:46:10 +08:00
|
|
|
Linker.AssignAbbrev(NewAbbrev);
|
2015-05-28 06:31:41 +08:00
|
|
|
Die->setAbbrevNumber(NewAbbrev.getNumber());
|
2015-03-05 06:07:44 +08:00
|
|
|
|
|
|
|
// Add the size of the abbreviation number to the output offset.
|
|
|
|
OutOffset += getULEB128Size(Die->getAbbrevNumber());
|
|
|
|
|
2015-11-11 05:31:05 +08:00
|
|
|
if (!HasChildren) {
|
2015-03-05 06:07:44 +08:00
|
|
|
// Update our size.
|
|
|
|
Die->setSize(OutOffset - Die->getOffset());
|
|
|
|
return Die;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recursively clone children.
|
2018-02-22 19:32:51 +08:00
|
|
|
for (auto Child : InputDIE.children()) {
|
2018-03-13 18:52:49 +08:00
|
|
|
if (DIE *Clone = cloneDIE(Child, DMO, Unit, StringPool, PCOffset, OutOffset,
|
|
|
|
Flags)) {
|
2015-06-26 07:52:10 +08:00
|
|
|
Die->addChild(Clone);
|
2015-03-05 06:07:44 +08:00
|
|
|
OutOffset = Clone->getOffset() + Clone->getSize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Account for the end of children marker.
|
|
|
|
OutOffset += sizeof(int8_t);
|
|
|
|
// Update our size.
|
|
|
|
Die->setSize(OutOffset - Die->getOffset());
|
|
|
|
return Die;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Patch the input object file relevant debug_ranges entries
|
2015-03-14 07:30:31 +08:00
|
|
|
/// and emit them in the output file. Update the relevant attributes
|
|
|
|
/// to point at the new entries.
|
|
|
|
void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit,
|
2018-03-13 18:52:49 +08:00
|
|
|
DWARFContext &OrigDwarf,
|
|
|
|
const DebugMapObject &DMO) const {
|
2018-10-31 09:12:58 +08:00
|
|
|
DWARFDebugRangeList RangeList;
|
2015-03-14 07:30:31 +08:00
|
|
|
const auto &FunctionRanges = Unit.getFunctionRanges();
|
|
|
|
unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
|
2017-07-20 06:27:28 +08:00
|
|
|
DWARFDataExtractor RangeExtractor(OrigDwarf.getDWARFObj(),
|
|
|
|
OrigDwarf.getDWARFObj().getRangeSection(),
|
2017-06-30 00:52:08 +08:00
|
|
|
OrigDwarf.isLittleEndian(), AddressSize);
|
2015-03-14 07:30:31 +08:00
|
|
|
auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
|
|
|
|
DWARFUnit &OrigUnit = Unit.getOrigUnit();
|
2016-12-14 02:25:19 +08:00
|
|
|
auto OrigUnitDie = OrigUnit.getUnitDIE(false);
|
2017-09-30 08:22:24 +08:00
|
|
|
uint64_t OrigLowPc =
|
|
|
|
dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc), -1ULL);
|
2015-03-14 07:30:31 +08:00
|
|
|
// Ranges addresses are based on the unit's low_pc. Compute the
|
2015-12-08 03:21:39 +08:00
|
|
|
// offset we need to apply to adapt to the new unit's low_pc.
|
2015-03-14 07:30:31 +08:00
|
|
|
int64_t UnitPcOffset = 0;
|
|
|
|
if (OrigLowPc != -1ULL)
|
|
|
|
UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc();
|
|
|
|
|
|
|
|
for (const auto &RangeAttribute : Unit.getRangesAttributes()) {
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
uint32_t Offset = RangeAttribute.get();
|
|
|
|
RangeAttribute.set(Streamer->getRangesSectionSize());
|
2018-10-31 09:12:58 +08:00
|
|
|
if (Error E = RangeList.extract(RangeExtractor, &Offset)) {
|
2018-06-21 06:56:37 +08:00
|
|
|
llvm::consumeError(std::move(E));
|
|
|
|
reportWarning("invalid range list ignored.", DMO);
|
|
|
|
RangeList.clear();
|
|
|
|
}
|
2015-03-14 07:30:31 +08:00
|
|
|
const auto &Entries = RangeList.getEntries();
|
2018-10-31 09:12:58 +08:00
|
|
|
if (!Entries.empty()) {
|
|
|
|
const DWARFDebugRangeList::RangeListEntry &First = Entries.front();
|
|
|
|
|
2015-03-14 07:30:31 +08:00
|
|
|
if (CurrRange == InvalidRange ||
|
2018-10-31 09:12:58 +08:00
|
|
|
First.StartAddress + OrigLowPc < CurrRange.start() ||
|
|
|
|
First.StartAddress + OrigLowPc >= CurrRange.stop()) {
|
|
|
|
CurrRange = FunctionRanges.find(First.StartAddress + OrigLowPc);
|
2015-08-31 13:09:32 +08:00
|
|
|
if (CurrRange == InvalidRange ||
|
2018-10-31 09:12:58 +08:00
|
|
|
CurrRange.start() > First.StartAddress + OrigLowPc) {
|
2018-03-13 18:52:49 +08:00
|
|
|
reportWarning("no mapping for range.", DMO);
|
2015-08-31 13:09:32 +08:00
|
|
|
continue;
|
|
|
|
}
|
2015-03-14 07:30:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-31 09:12:58 +08:00
|
|
|
Streamer->emitRangesEntries(UnitPcOffset, OrigLowPc, CurrRange, Entries,
|
2015-03-14 07:30:31 +08:00
|
|
|
AddressSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Generate the debug_aranges entries for \p Unit and if the
|
2015-03-14 11:46:51 +08:00
|
|
|
/// unit has a DW_AT_ranges attribute, also emit the debug_ranges
|
|
|
|
/// contribution for this attribute.
|
2015-03-14 07:30:31 +08:00
|
|
|
/// FIXME: this could actually be done right in patchRangesForUnit,
|
|
|
|
/// but for the sake of initial bit-for-bit compatibility with legacy
|
|
|
|
/// dsymutil, we have to do it in a delayed pass.
|
|
|
|
void DwarfLinker::generateUnitRanges(CompileUnit &Unit) const {
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
auto Attr = Unit.getUnitRangesAttribute();
|
2015-03-14 11:46:51 +08:00
|
|
|
if (Attr)
|
Reapply "AsmPrinter: Change DIEValue to be stored by value"
This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:
- MSVC can only handle `sizeof()` on types, not values. Change the
assert.
- GCC doesn't know the `is_trivially_copyable` type trait. Instead of
asserting it, add destructors.
- Call placement new even when constructing POD (i.e., the pointers).
- Instead of copying the char buffer, copy the casted classes.
I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle. If the bots disagree with me, I'll remove them.
- Check that the constructed type is either standard layout or a
pointer. This protects against a programming error: we really want
the "small" `DIEValue`s to be small and simple, so don't
accidentally change them not to be.
- Similarly, check that the size of the buffer is no bigger than a
`uint64_t` or a pointer. (I thought checking against
`sizeof(uint64_t)` would be good enough, but Chandler suggested that
pointers might sometimes be bigger than that in the context of
sanitizers.)
I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie). Without that, this commit would
be almost unintelligible.
Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference. It's now a discriminated union, with a `Val` field storing
the actual type. The classes that used to inherit from `DIEValue` no
longer do. There are two categories of these:
- Small values fit in a single pointer and are stored by value.
- Large values require auxiliary storage, and are stored by reference.
The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp. It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.
This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit. I
measured an increase from 845 MB to 879 MB, around 3.9%. The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental. (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)
(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--
llvm-svn: 238362
2015-05-28 06:14:58 +08:00
|
|
|
Attr->set(Streamer->getRangesSectionSize());
|
|
|
|
Streamer->emitUnitRangesEntries(Unit, static_cast<bool>(Attr));
|
2015-03-14 07:30:31 +08:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Insert the new line info sequence \p Seq into the current
|
2015-03-16 04:45:43 +08:00
|
|
|
/// set of already linked line info \p Rows.
|
|
|
|
static void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
|
|
|
|
std::vector<DWARFDebugLine::Row> &Rows) {
|
|
|
|
if (Seq.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!Rows.empty() && Rows.back().Address < Seq.front().Address) {
|
|
|
|
Rows.insert(Rows.end(), Seq.begin(), Seq.end());
|
|
|
|
Seq.clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto InsertPoint = std::lower_bound(
|
|
|
|
Rows.begin(), Rows.end(), Seq.front(),
|
|
|
|
[](const DWARFDebugLine::Row &LHS, const DWARFDebugLine::Row &RHS) {
|
|
|
|
return LHS.Address < RHS.Address;
|
|
|
|
});
|
|
|
|
|
|
|
|
// FIXME: this only removes the unneeded end_sequence if the
|
2018-02-22 19:32:51 +08:00
|
|
|
// sequences have been inserted in order. Using a global sort like
|
2015-03-16 04:45:43 +08:00
|
|
|
// described in patchLineTableForUnit() and delaying the end_sequene
|
|
|
|
// elimination to emitLineTableForUnit() we can get rid of all of them.
|
|
|
|
if (InsertPoint != Rows.end() &&
|
|
|
|
InsertPoint->Address == Seq.front().Address && InsertPoint->EndSequence) {
|
|
|
|
*InsertPoint = Seq.front();
|
|
|
|
Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end());
|
|
|
|
} else {
|
|
|
|
Rows.insert(InsertPoint, Seq.begin(), Seq.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
Seq.clear();
|
|
|
|
}
|
|
|
|
|
2015-06-26 05:42:46 +08:00
|
|
|
static void patchStmtList(DIE &Die, DIEInteger Offset) {
|
|
|
|
for (auto &V : Die.values())
|
|
|
|
if (V.getAttribute() == dwarf::DW_AT_stmt_list) {
|
2015-06-26 07:46:41 +08:00
|
|
|
V = DIEValue(V.getAttribute(), V.getForm(), Offset);
|
2015-06-26 05:42:46 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Didn't find DW_AT_stmt_list in cloned DIE!");
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Extract the line table for \p Unit from \p OrigDwarf, and
|
2015-03-16 04:45:43 +08:00
|
|
|
/// recreate a relocated version of these for the address ranges that
|
|
|
|
/// are present in the binary.
|
|
|
|
void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
|
2018-03-13 18:52:49 +08:00
|
|
|
DWARFContext &OrigDwarf,
|
|
|
|
RangesTy &Ranges,
|
|
|
|
const DebugMapObject &DMO) {
|
2016-12-14 02:25:19 +08:00
|
|
|
DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
|
2017-01-14 05:08:18 +08:00
|
|
|
auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list));
|
2016-12-15 06:38:08 +08:00
|
|
|
if (!StmtList)
|
2015-03-16 04:45:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Update the cloned DW_AT_stmt_list with the correct debug_line offset.
|
2015-06-26 05:42:46 +08:00
|
|
|
if (auto *OutputDIE = Unit.getOutputUnitDIE())
|
|
|
|
patchStmtList(*OutputDIE, DIEInteger(Streamer->getLineSectionSize()));
|
2015-03-16 04:45:43 +08:00
|
|
|
|
|
|
|
// Parse the original line info for the unit.
|
|
|
|
DWARFDebugLine::LineTable LineTable;
|
2016-12-15 06:38:08 +08:00
|
|
|
uint32_t StmtOffset = *StmtList;
|
2017-07-20 06:27:28 +08:00
|
|
|
DWARFDataExtractor LineExtractor(
|
|
|
|
OrigDwarf.getDWARFObj(), OrigDwarf.getDWARFObj().getLineSection(),
|
|
|
|
OrigDwarf.isLittleEndian(), Unit.getOrigUnit().getAddressByteSize());
|
2019-01-08 07:27:25 +08:00
|
|
|
if (Options.Translator)
|
|
|
|
return Streamer->translateLineTable(LineExtractor, StmtOffset, Options);
|
[DWARF] Rework debug line parsing to use llvm::Error and callbacks
Reviewed by: dblaikie, JDevlieghere, espindola
Differential Revision: https://reviews.llvm.org/D44560
Summary:
The .debug_line parser previously reported errors by printing to stderr and
return false. This is not particularly helpful for clients of the library code,
as it prevents them from handling the errors in a manner based on the calling
context. This change switches to using llvm::Error and callbacks to indicate
what problems were detected during parsing, and has updated clients to handle
the errors in a location-specific manner. In general, this means that they
continue to do the same thing to external users. Below, I have outlined what
the known behaviour changes are, relating to this change.
There are two levels of "errors" in the new error mechanism, to broadly
distinguish between different fail states of the parser, since not every
failure will prevent parsing of the unit, or of subsequent unit. Malformed
table errors that prevent reading the remainder of the table (reported by
returning them) and other minor issues representing problems with parsing that
do not prevent attempting to continue reading the table (reported by calling a
specified callback funciton). The only example of this currently is when the
last sequence of a unit is unterminated. However, I think it would be good to
change the handling of unrecognised opcodes to report as minor issues as well,
rather than just printing to the stream if --verbose is used (this would be a
subsequent change however).
I have substantially extended the DwarfGenerator to be able to handle
custom-crafted .debug_line sections, allowing for comprehensive unit-testing
of the parser code. For now, I am just adding unit tests to cover the basic
error reporting, and positive cases, and do not currently intend to test every
part of the parser, although the framework should be sufficient to do so at a
later point.
Known behaviour changes:
- The dump function in DWARFContext now does not attempt to read subsequent
tables when searching for a specific offset, if the unit length field of a
table before the specified offset is a reserved value.
- getOrParseLineTable now returns a useful Error if an invalid offset is
encountered, rather than simply a nullptr.
- The parse functions no longer use `WithColor::warning` directly to report
errors, allowing LLD to call its own warning function.
- The existing parse error messages have been updated to not specifically
include "warning" in their message, allowing consumers to determine what
severity the problem is.
- If the line table version field appears to have a value less than 2, an
informative error is returned, instead of just false.
- If the line table unit length field uses a reserved value, an informative
error is returned, instead of just false.
- Dumping of .debug_line.dwo sections is now implemented the same as regular
.debug_line sections.
- Verbose dumping of .debug_line[.dwo] sections now prints the prologue, if
there is a prologue error, just like non-verbose dumping.
As a helper for the generator code, I have re-added emitInt64 to the
AsmPrinter code. This previously existed, but was removed way back in r100296,
presumably because it was dead at the time.
This change also requires a change to LLD, which will be committed separately.
llvm-svn: 331971
2018-05-10 18:51:33 +08:00
|
|
|
|
|
|
|
Error Err = LineTable.parse(LineExtractor, &StmtOffset, OrigDwarf,
|
2018-08-23 20:43:33 +08:00
|
|
|
&Unit.getOrigUnit(), DWARFContext::dumpWarning);
|
|
|
|
DWARFContext::dumpWarning(std::move(Err));
|
2015-03-16 04:45:43 +08:00
|
|
|
|
|
|
|
// This vector is the output line table.
|
|
|
|
std::vector<DWARFDebugLine::Row> NewRows;
|
|
|
|
NewRows.reserve(LineTable.Rows.size());
|
|
|
|
|
|
|
|
// Current sequence of rows being extracted, before being inserted
|
|
|
|
// in NewRows.
|
|
|
|
std::vector<DWARFDebugLine::Row> Seq;
|
|
|
|
const auto &FunctionRanges = Unit.getFunctionRanges();
|
|
|
|
auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
|
|
|
|
|
|
|
|
// FIXME: This logic is meant to generate exactly the same output as
|
2018-02-22 19:32:51 +08:00
|
|
|
// Darwin's classic dsymutil. There is a nicer way to implement this
|
2015-03-16 04:45:43 +08:00
|
|
|
// by simply putting all the relocated line info in NewRows and simply
|
|
|
|
// sorting NewRows before passing it to emitLineTableForUnit. This
|
|
|
|
// should be correct as sequences for a function should stay
|
|
|
|
// together in the sorted output. There are a few corner cases that
|
|
|
|
// look suspicious though, and that required to implement the logic
|
|
|
|
// this way. Revisit that once initial validation is finished.
|
|
|
|
|
|
|
|
// Iterate over the object file line info and extract the sequences
|
|
|
|
// that correspond to linked functions.
|
|
|
|
for (auto &Row : LineTable.Rows) {
|
2018-02-22 19:32:51 +08:00
|
|
|
// Check whether we stepped out of the range. The range is
|
2015-03-16 04:45:43 +08:00
|
|
|
// half-open, but consider accept the end address of the range if
|
|
|
|
// it is marked as end_sequence in the input (because in that
|
|
|
|
// case, the relocation offset is accurate and that entry won't
|
|
|
|
// serve as the start of another function).
|
|
|
|
if (CurrRange == InvalidRange || Row.Address < CurrRange.start() ||
|
|
|
|
Row.Address > CurrRange.stop() ||
|
|
|
|
(Row.Address == CurrRange.stop() && !Row.EndSequence)) {
|
|
|
|
// We just stepped out of a known range. Insert a end_sequence
|
|
|
|
// corresponding to the end of the range.
|
|
|
|
uint64_t StopAddress = CurrRange != InvalidRange
|
|
|
|
? CurrRange.stop() + CurrRange.value()
|
|
|
|
: -1ULL;
|
|
|
|
CurrRange = FunctionRanges.find(Row.Address);
|
|
|
|
bool CurrRangeValid =
|
|
|
|
CurrRange != InvalidRange && CurrRange.start() <= Row.Address;
|
|
|
|
if (!CurrRangeValid) {
|
|
|
|
CurrRange = InvalidRange;
|
|
|
|
if (StopAddress != -1ULL) {
|
|
|
|
// Try harder by looking in the DebugMapObject function
|
|
|
|
// ranges map. There are corner cases where this finds a
|
|
|
|
// valid entry. It's unclear if this is right or wrong, but
|
|
|
|
// for now do as dsymutil.
|
|
|
|
// FIXME: Understand exactly what cases this addresses and
|
|
|
|
// potentially remove it along with the Ranges map.
|
|
|
|
auto Range = Ranges.lower_bound(Row.Address);
|
|
|
|
if (Range != Ranges.begin() && Range != Ranges.end())
|
|
|
|
--Range;
|
|
|
|
|
|
|
|
if (Range != Ranges.end() && Range->first <= Row.Address &&
|
2018-03-13 18:52:49 +08:00
|
|
|
Range->second.HighPC >= Row.Address) {
|
|
|
|
StopAddress = Row.Address + Range->second.Offset;
|
2015-03-16 04:45:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (StopAddress != -1ULL && !Seq.empty()) {
|
|
|
|
// Insert end sequence row with the computed end address, but
|
|
|
|
// the same line as the previous one.
|
2015-08-11 00:15:51 +08:00
|
|
|
auto NextLine = Seq.back();
|
2015-08-11 02:27:51 +08:00
|
|
|
NextLine.Address = StopAddress;
|
|
|
|
NextLine.EndSequence = 1;
|
|
|
|
NextLine.PrologueEnd = 0;
|
|
|
|
NextLine.BasicBlock = 0;
|
|
|
|
NextLine.EpilogueBegin = 0;
|
2015-08-11 02:03:35 +08:00
|
|
|
Seq.push_back(NextLine);
|
2015-03-16 04:45:43 +08:00
|
|
|
insertLineSequence(Seq, NewRows);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CurrRangeValid)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore empty sequences.
|
|
|
|
if (Row.EndSequence && Seq.empty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Relocate row address and add it to the current sequence.
|
|
|
|
Row.Address += CurrRange.value();
|
|
|
|
Seq.emplace_back(Row);
|
|
|
|
|
|
|
|
if (Row.EndSequence)
|
|
|
|
insertLineSequence(Seq, NewRows);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finished extracting, now emit the line tables.
|
2018-02-22 19:32:51 +08:00
|
|
|
// FIXME: LLVM hard-codes its prologue values. We just copy the
|
2015-03-16 04:45:43 +08:00
|
|
|
// prologue over and that works because we act as both producer and
|
|
|
|
// consumer. It would be nicer to have a real configurable line
|
|
|
|
// table emitter.
|
2017-12-12 19:32:21 +08:00
|
|
|
if (LineTable.Prologue.getVersion() < 2 ||
|
|
|
|
LineTable.Prologue.getVersion() > 5 ||
|
2015-03-16 04:45:43 +08:00
|
|
|
LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT ||
|
2015-08-07 23:14:13 +08:00
|
|
|
LineTable.Prologue.OpcodeBase > 13)
|
2018-03-13 18:52:49 +08:00
|
|
|
reportWarning("line table parameters mismatch. Cannot emit.", DMO);
|
2015-08-07 23:14:13 +08:00
|
|
|
else {
|
2017-12-12 19:32:21 +08:00
|
|
|
uint32_t PrologueEnd = *StmtList + 10 + LineTable.Prologue.PrologueLength;
|
2018-02-01 18:19:56 +08:00
|
|
|
// DWARF v5 has an extra 2 bytes of information before the header_length
|
2017-12-12 19:32:21 +08:00
|
|
|
// field.
|
|
|
|
if (LineTable.Prologue.getVersion() == 5)
|
|
|
|
PrologueEnd += 2;
|
2017-07-20 06:27:28 +08:00
|
|
|
StringRef LineData = OrigDwarf.getDWARFObj().getLineSection().Data;
|
2015-08-07 23:14:13 +08:00
|
|
|
MCDwarfLineTableParams Params;
|
|
|
|
Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
|
|
|
|
Params.DWARF2LineBase = LineTable.Prologue.LineBase;
|
|
|
|
Params.DWARF2LineRange = LineTable.Prologue.LineRange;
|
|
|
|
Streamer->emitLineTableForUnit(Params,
|
2016-12-15 06:38:08 +08:00
|
|
|
LineData.slice(*StmtList + 4, PrologueEnd),
|
2015-03-16 04:45:43 +08:00
|
|
|
LineTable.Prologue.MinInstLength, NewRows,
|
|
|
|
Unit.getOrigUnit().getAddressByteSize());
|
2015-08-07 23:14:13 +08:00
|
|
|
}
|
2015-03-16 04:45:43 +08:00
|
|
|
}
|
|
|
|
|
2015-03-16 10:05:10 +08:00
|
|
|
void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
|
2018-07-26 07:01:38 +08:00
|
|
|
switch (Options.TheAccelTableKind) {
|
|
|
|
case AccelTableKind::Apple:
|
|
|
|
emitAppleAcceleratorEntriesForUnit(Unit);
|
|
|
|
break;
|
|
|
|
case AccelTableKind::Dwarf:
|
|
|
|
emitDwarfAcceleratorEntriesForUnit(Unit);
|
|
|
|
break;
|
|
|
|
case AccelTableKind::Default:
|
|
|
|
llvm_unreachable("The default must be updated to a concrete value.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DwarfLinker::emitAppleAcceleratorEntriesForUnit(CompileUnit &Unit) {
|
2018-01-29 22:52:50 +08:00
|
|
|
// Add namespaces.
|
|
|
|
for (const auto &Namespace : Unit.getNamespaces())
|
|
|
|
AppleNamespaces.addName(Namespace.Name,
|
|
|
|
Namespace.Die->getOffset() + Unit.getStartOffset());
|
|
|
|
|
|
|
|
/// Add names.
|
|
|
|
if (!Options.Minimize)
|
|
|
|
Streamer->emitPubNamesForUnit(Unit);
|
|
|
|
for (const auto &Pubname : Unit.getPubnames())
|
|
|
|
AppleNames.addName(Pubname.Name,
|
|
|
|
Pubname.Die->getOffset() + Unit.getStartOffset());
|
|
|
|
|
|
|
|
/// Add types.
|
|
|
|
if (!Options.Minimize)
|
|
|
|
Streamer->emitPubTypesForUnit(Unit);
|
|
|
|
for (const auto &Pubtype : Unit.getPubtypes())
|
|
|
|
AppleTypes.addName(
|
|
|
|
Pubtype.Name, Pubtype.Die->getOffset() + Unit.getStartOffset(),
|
|
|
|
Pubtype.Die->getTag(),
|
|
|
|
Pubtype.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation
|
|
|
|
: 0,
|
|
|
|
Pubtype.QualifiedNameHash);
|
|
|
|
|
|
|
|
/// Add ObjC names.
|
|
|
|
for (const auto &ObjC : Unit.getObjC())
|
|
|
|
AppleObjc.addName(ObjC.Name, ObjC.Die->getOffset() + Unit.getStartOffset());
|
2015-03-16 10:05:10 +08:00
|
|
|
}
|
|
|
|
|
2018-07-26 07:01:38 +08:00
|
|
|
void DwarfLinker::emitDwarfAcceleratorEntriesForUnit(CompileUnit &Unit) {
|
|
|
|
for (const auto &Namespace : Unit.getNamespaces())
|
|
|
|
DebugNames.addName(Namespace.Name, Namespace.Die->getOffset(),
|
|
|
|
Namespace.Die->getTag(), Unit.getUniqueID());
|
|
|
|
for (const auto &Pubname : Unit.getPubnames())
|
|
|
|
DebugNames.addName(Pubname.Name, Pubname.Die->getOffset(),
|
|
|
|
Pubname.Die->getTag(), Unit.getUniqueID());
|
|
|
|
for (const auto &Pubtype : Unit.getPubtypes())
|
|
|
|
DebugNames.addName(Pubtype.Name, Pubtype.Die->getOffset(),
|
|
|
|
Pubtype.Die->getTag(), Unit.getUniqueID());
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:51:17 +08:00
|
|
|
/// Read the frame info stored in the object, and emit the
|
2015-06-06 07:06:11 +08:00
|
|
|
/// patched frame descriptions for the linked binary.
|
|
|
|
///
|
|
|
|
/// This is actually pretty easy as the data of the CIEs and FDEs can
|
|
|
|
/// be considered as black boxes and moved as is. The only thing to do
|
|
|
|
/// is to patch the addresses in the headers.
|
|
|
|
void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO,
|
2018-03-13 18:52:49 +08:00
|
|
|
RangesTy &Ranges,
|
2015-06-06 07:06:11 +08:00
|
|
|
DWARFContext &OrigDwarf,
|
|
|
|
unsigned AddrSize) {
|
2017-07-20 06:27:28 +08:00
|
|
|
StringRef FrameData = OrigDwarf.getDWARFObj().getDebugFrameSection();
|
2015-06-06 07:06:11 +08:00
|
|
|
if (FrameData.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
DataExtractor Data(FrameData, OrigDwarf.isLittleEndian(), 0);
|
|
|
|
uint32_t InputOffset = 0;
|
|
|
|
|
|
|
|
// Store the data of the CIEs defined in this object, keyed by their
|
|
|
|
// offsets.
|
|
|
|
DenseMap<uint32_t, StringRef> LocalCIES;
|
|
|
|
|
|
|
|
while (Data.isValidOffset(InputOffset)) {
|
|
|
|
uint32_t EntryOffset = InputOffset;
|
|
|
|
uint32_t InitialLength = Data.getU32(&InputOffset);
|
|
|
|
if (InitialLength == 0xFFFFFFFF)
|
2018-03-13 18:52:49 +08:00
|
|
|
return reportWarning("Dwarf64 bits no supported", DMO);
|
2015-06-06 07:06:11 +08:00
|
|
|
|
|
|
|
uint32_t CIEId = Data.getU32(&InputOffset);
|
|
|
|
if (CIEId == 0xFFFFFFFF) {
|
|
|
|
// This is a CIE, store it.
|
|
|
|
StringRef CIEData = FrameData.substr(EntryOffset, InitialLength + 4);
|
|
|
|
LocalCIES[EntryOffset] = CIEData;
|
|
|
|
// The -4 is to account for the CIEId we just read.
|
|
|
|
InputOffset += InitialLength - 4;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Loc = Data.getUnsigned(&InputOffset, AddrSize);
|
|
|
|
|
|
|
|
// Some compilers seem to emit frame info that doesn't start at
|
|
|
|
// the function entry point, thus we can't just lookup the address
|
|
|
|
// in the debug map. Use the linker's range map to see if the FDE
|
|
|
|
// describes something that we can relocate.
|
|
|
|
auto Range = Ranges.upper_bound(Loc);
|
|
|
|
if (Range != Ranges.begin())
|
|
|
|
--Range;
|
|
|
|
if (Range == Ranges.end() || Range->first > Loc ||
|
2018-03-13 18:52:49 +08:00
|
|
|
Range->second.HighPC <= Loc) {
|
2015-06-06 07:06:11 +08:00
|
|
|
// The +4 is to account for the size of the InitialLength field itself.
|
|
|
|
InputOffset = EntryOffset + InitialLength + 4;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is an FDE, and we have a mapping.
|
|
|
|
// Have we already emitted a corresponding CIE?
|
|
|
|
StringRef CIEData = LocalCIES[CIEId];
|
|
|
|
if (CIEData.empty())
|
2018-03-13 18:52:49 +08:00
|
|
|
return reportWarning("Inconsistent debug_frame content. Dropping.", DMO);
|
2015-06-06 07:06:11 +08:00
|
|
|
|
|
|
|
// Look if we already emitted a CIE that corresponds to the
|
|
|
|
// referenced one (the CIE data is the key of that lookup).
|
|
|
|
auto IteratorInserted = EmittedCIEs.insert(
|
|
|
|
std::make_pair(CIEData, Streamer->getFrameSectionSize()));
|
|
|
|
// If there is no CIE yet for this ID, emit it.
|
|
|
|
if (IteratorInserted.second ||
|
|
|
|
// FIXME: dsymutil-classic only caches the last used CIE for
|
|
|
|
// reuse. Mimic that behavior for now. Just removing that
|
|
|
|
// second half of the condition and the LastCIEOffset variable
|
|
|
|
// makes the code DTRT.
|
|
|
|
LastCIEOffset != IteratorInserted.first->getValue()) {
|
|
|
|
LastCIEOffset = Streamer->getFrameSectionSize();
|
|
|
|
IteratorInserted.first->getValue() = LastCIEOffset;
|
|
|
|
Streamer->emitCIE(CIEData);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the FDE with updated address and CIE pointer.
|
|
|
|
// (4 + AddrSize) is the size of the CIEId + initial_location
|
|
|
|
// fields that will get reconstructed by emitFDE().
|
|
|
|
unsigned FDERemainingBytes = InitialLength - (4 + AddrSize);
|
|
|
|
Streamer->emitFDE(IteratorInserted.first->getValue(), AddrSize,
|
2018-03-13 18:52:49 +08:00
|
|
|
Loc + Range->second.Offset,
|
2015-06-06 07:06:11 +08:00
|
|
|
FrameData.substr(InputOffset, FDERemainingBytes));
|
|
|
|
InputOffset += FDERemainingBytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-15 00:46:10 +08:00
|
|
|
void DwarfLinker::DIECloner::copyAbbrev(
|
|
|
|
const DWARFAbbreviationDeclaration &Abbrev, bool hasODR) {
|
2015-09-11 12:17:30 +08:00
|
|
|
DIEAbbrev Copy(dwarf::Tag(Abbrev.getTag()),
|
|
|
|
dwarf::Form(Abbrev.hasChildren()));
|
|
|
|
|
|
|
|
for (const auto &Attr : Abbrev.attributes()) {
|
|
|
|
uint16_t Form = Attr.Form;
|
|
|
|
if (hasODR && isODRAttribute(Attr.Attr))
|
|
|
|
Form = dwarf::DW_FORM_ref_addr;
|
|
|
|
Copy.AddAttribute(dwarf::Attribute(Attr.Attr), dwarf::Form(Form));
|
|
|
|
}
|
|
|
|
|
2015-09-15 00:46:10 +08:00
|
|
|
Linker.AssignAbbrev(Copy);
|
2015-09-11 12:17:30 +08:00
|
|
|
}
|
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
uint32_t DwarfLinker::DIECloner::hashFullyQualifiedName(
|
|
|
|
DWARFDie DIE, CompileUnit &U, const DebugMapObject &DMO, int RecurseDepth) {
|
2018-01-29 22:52:50 +08:00
|
|
|
const char *Name = nullptr;
|
|
|
|
DWARFUnit *OrigUnit = &U.getOrigUnit();
|
|
|
|
CompileUnit *CU = &U;
|
|
|
|
Optional<DWARFFormValue> Ref;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (const char *CurrentName = DIE.getName(DINameKind::ShortName))
|
|
|
|
Name = CurrentName;
|
|
|
|
|
|
|
|
if (!(Ref = DIE.find(dwarf::DW_AT_specification)) &&
|
|
|
|
!(Ref = DIE.find(dwarf::DW_AT_abstract_origin)))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!Ref->isFormClass(DWARFFormValue::FC_Reference))
|
|
|
|
break;
|
|
|
|
|
|
|
|
CompileUnit *RefCU;
|
2018-03-13 18:52:49 +08:00
|
|
|
if (auto RefDIE = resolveDIEReference(Linker, DMO, CompileUnits, *Ref,
|
2018-01-29 22:52:50 +08:00
|
|
|
U.getOrigUnit(), DIE, RefCU)) {
|
|
|
|
CU = RefCU;
|
|
|
|
OrigUnit = &RefCU->getOrigUnit();
|
|
|
|
DIE = RefDIE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Idx = OrigUnit->getDIEIndex(DIE);
|
|
|
|
if (!Name && DIE.getTag() == dwarf::DW_TAG_namespace)
|
|
|
|
Name = "(anonymous namespace)";
|
|
|
|
|
|
|
|
if (CU->getInfo(Idx).ParentIdx == 0 ||
|
|
|
|
// FIXME: dsymutil-classic compatibility. Ignore modules.
|
|
|
|
CU->getOrigUnit().getDIEAtIndex(CU->getInfo(Idx).ParentIdx).getTag() ==
|
|
|
|
dwarf::DW_TAG_module)
|
|
|
|
return djbHash(Name ? Name : "", djbHash(RecurseDepth ? "" : "::"));
|
|
|
|
|
|
|
|
DWARFDie Die = OrigUnit->getDIEAtIndex(CU->getInfo(Idx).ParentIdx);
|
2018-03-13 18:52:49 +08:00
|
|
|
return djbHash(
|
|
|
|
(Name ? Name : ""),
|
|
|
|
djbHash((Name ? "::" : ""),
|
|
|
|
hashFullyQualifiedName(Die, *CU, DMO, ++RecurseDepth)));
|
2018-01-29 22:52:50 +08:00
|
|
|
}
|
|
|
|
|
2018-02-22 19:32:51 +08:00
|
|
|
static uint64_t getDwoId(const DWARFDie &CUDie, const DWARFUnit &Unit) {
|
|
|
|
auto DwoId = dwarf::toUnsigned(
|
|
|
|
CUDie.find({dwarf::DW_AT_dwo_id, dwarf::DW_AT_GNU_dwo_id}));
|
2016-12-15 06:38:08 +08:00
|
|
|
if (DwoId)
|
|
|
|
return *DwoId;
|
|
|
|
return 0;
|
2015-09-24 01:11:10 +08:00
|
|
|
}
|
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
bool DwarfLinker::registerModuleReference(
|
|
|
|
const DWARFDie &CUDie, const DWARFUnit &Unit, DebugMap &ModuleMap,
|
|
|
|
const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool,
|
|
|
|
UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts,
|
2018-09-07 18:29:22 +08:00
|
|
|
uint64_t ModulesEndOffset, unsigned &UnitID, unsigned Indent, bool Quiet) {
|
2018-02-22 19:32:51 +08:00
|
|
|
std::string PCMfile = dwarf::toString(
|
|
|
|
CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), "");
|
2015-09-23 06:20:50 +08:00
|
|
|
if (PCMfile.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Clang module DWARF skeleton CUs abuse this for the path to the module.
|
2017-01-14 05:08:18 +08:00
|
|
|
std::string PCMpath = dwarf::toString(CUDie.find(dwarf::DW_AT_comp_dir), "");
|
2015-09-24 01:11:10 +08:00
|
|
|
uint64_t DwoId = getDwoId(CUDie, Unit);
|
2015-09-23 06:20:50 +08:00
|
|
|
|
2017-01-14 05:08:18 +08:00
|
|
|
std::string Name = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");
|
2015-09-24 01:35:52 +08:00
|
|
|
if (Name.empty()) {
|
2018-08-25 04:41:08 +08:00
|
|
|
if (!Quiet)
|
|
|
|
reportWarning("Anonymous module skeleton CU for " + PCMfile, DMO);
|
2015-09-24 01:35:52 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-25 04:41:08 +08:00
|
|
|
if (!Quiet && Options.Verbose) {
|
2015-09-23 06:20:50 +08:00
|
|
|
outs().indent(Indent);
|
|
|
|
outs() << "Found clang module reference " << PCMfile;
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:11:10 +08:00
|
|
|
auto Cached = ClangModules.find(PCMfile);
|
|
|
|
if (Cached != ClangModules.end()) {
|
2016-05-13 08:17:58 +08:00
|
|
|
// FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is
|
|
|
|
// fixed in clang, only warn about DWO_id mismatches in verbose mode.
|
|
|
|
// ASTFileSignatures will change randomly when a module is rebuilt.
|
2018-08-25 04:41:08 +08:00
|
|
|
if (!Quiet && Options.Verbose && (Cached->second != DwoId))
|
2015-09-24 01:11:10 +08:00
|
|
|
reportWarning(Twine("hash mismatch: this object file was built against a "
|
2018-02-22 19:32:51 +08:00
|
|
|
"different version of the module ") +
|
2018-03-13 18:52:49 +08:00
|
|
|
PCMfile,
|
|
|
|
DMO);
|
2018-08-25 04:41:08 +08:00
|
|
|
if (!Quiet && Options.Verbose)
|
2015-09-23 06:20:50 +08:00
|
|
|
outs() << " [cached].\n";
|
|
|
|
return true;
|
|
|
|
}
|
2018-08-25 04:41:08 +08:00
|
|
|
if (!Quiet && Options.Verbose)
|
2015-09-23 06:20:50 +08:00
|
|
|
outs() << " ...\n";
|
|
|
|
|
|
|
|
// Cyclic dependencies are disallowed by Clang, but we still
|
|
|
|
// shouldn't run into an infinite loop, so mark it as processed now.
|
2015-09-24 01:11:10 +08:00
|
|
|
ClangModules.insert({PCMfile, DwoId});
|
2018-09-07 18:29:22 +08:00
|
|
|
if (Error E =
|
|
|
|
loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, DMO, Ranges,
|
|
|
|
StringPool, UniquingStringPool, ODRContexts,
|
|
|
|
ModulesEndOffset, UnitID, Indent + 2, Quiet)) {
|
2017-11-17 01:46:43 +08:00
|
|
|
consumeError(std::move(E));
|
|
|
|
return false;
|
|
|
|
}
|
2015-09-23 06:20:50 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-24 14:41:11 +08:00
|
|
|
ErrorOr<const object::ObjectFile &>
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-30 00:50:41 +08:00
|
|
|
DwarfLinker::loadObject(const DebugMapObject &Obj, const DebugMap &Map) {
|
|
|
|
auto ObjectEntry =
|
|
|
|
BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp());
|
|
|
|
if (!ObjectEntry) {
|
|
|
|
auto Err = ObjectEntry.takeError();
|
|
|
|
reportWarning(
|
|
|
|
Twine(Obj.getObjectFilename()) + ": " + toString(std::move(Err)), Obj);
|
|
|
|
return errorToErrorCode(std::move(Err));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Object = ObjectEntry->getObject(Map.getTriple());
|
|
|
|
if (!Object) {
|
|
|
|
auto Err = Object.takeError();
|
|
|
|
reportWarning(
|
|
|
|
Twine(Obj.getObjectFilename()) + ": " + toString(std::move(Err)), Obj);
|
|
|
|
return errorToErrorCode(std::move(Err));
|
|
|
|
}
|
|
|
|
|
|
|
|
return *Object;
|
2015-07-24 14:41:11 +08:00
|
|
|
}
|
|
|
|
|
2018-08-25 04:41:08 +08:00
|
|
|
Error DwarfLinker::loadClangModule(
|
|
|
|
StringRef Filename, StringRef ModulePath, StringRef ModuleName,
|
|
|
|
uint64_t DwoId, DebugMap &ModuleMap, const DebugMapObject &DMO,
|
|
|
|
RangesTy &Ranges, OffsetsStringPool &StringPool,
|
|
|
|
UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts,
|
2018-09-07 18:29:22 +08:00
|
|
|
uint64_t ModulesEndOffset, unsigned &UnitID, unsigned Indent, bool Quiet) {
|
2015-09-23 06:20:50 +08:00
|
|
|
SmallString<80> Path(Options.PrependPath);
|
|
|
|
if (sys::path::is_relative(Filename))
|
|
|
|
sys::path::append(Path, ModulePath, Filename);
|
|
|
|
else
|
|
|
|
sys::path::append(Path, Filename);
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-30 00:50:41 +08:00
|
|
|
// Don't use the cached binary holder because we have no thread-safety
|
|
|
|
// guarantee and the lifetime is limited.
|
2017-10-06 22:49:20 +08:00
|
|
|
auto &Obj = ModuleMap.addDebugMapObject(
|
|
|
|
Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-30 00:50:41 +08:00
|
|
|
auto ErrOrObj = loadObject(Obj, ModuleMap);
|
2016-01-15 02:31:07 +08:00
|
|
|
if (!ErrOrObj) {
|
|
|
|
// Try and emit more helpful warnings by applying some heuristics.
|
2018-03-13 18:52:49 +08:00
|
|
|
StringRef ObjFile = DMO.getObjectFilename();
|
2016-01-15 02:31:07 +08:00
|
|
|
bool isClangModule = sys::path::extension(Filename).equals(".pcm");
|
|
|
|
bool isArchive = ObjFile.endswith(")");
|
|
|
|
if (isClangModule) {
|
|
|
|
StringRef ModuleCacheDir = sys::path::parent_path(Path);
|
|
|
|
if (sys::fs::exists(ModuleCacheDir)) {
|
|
|
|
// If the module's parent directory exists, we assume that the module
|
|
|
|
// cache has expired and was pruned by clang. A more adventurous
|
|
|
|
// dsymutil would invoke clang to rebuild the module now.
|
|
|
|
if (!ModuleCacheHintDisplayed) {
|
2018-04-15 05:36:42 +08:00
|
|
|
WithColor::note() << "The clang module cache may have expired since "
|
|
|
|
"this object file was built. Rebuilding the "
|
|
|
|
"object file will rebuild the module cache.\n";
|
2016-01-15 02:31:07 +08:00
|
|
|
ModuleCacheHintDisplayed = true;
|
|
|
|
}
|
|
|
|
} else if (isArchive) {
|
|
|
|
// If the module cache directory doesn't exist at all and the object
|
|
|
|
// file is inside a static library, we assume that the static library
|
|
|
|
// was built on a different machine. We don't want to discourage module
|
|
|
|
// debugging for convenience libraries within a project though.
|
|
|
|
if (!ArchiveHintDisplayed) {
|
2018-04-15 05:36:42 +08:00
|
|
|
WithColor::note()
|
|
|
|
<< "Linking a static library that was built with "
|
|
|
|
"-gmodules, but the module cache was not found. "
|
|
|
|
"Redistributable static libraries should never be "
|
|
|
|
"built with module debugging enabled. The debug "
|
|
|
|
"experience will be degraded due to incomplete "
|
|
|
|
"debug information.\n";
|
2016-01-15 02:31:07 +08:00
|
|
|
ArchiveHintDisplayed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-11-17 01:46:43 +08:00
|
|
|
return Error::success();
|
2016-01-15 02:31:07 +08:00
|
|
|
}
|
2015-09-23 06:20:50 +08:00
|
|
|
|
2015-09-23 18:38:59 +08:00
|
|
|
std::unique_ptr<CompileUnit> Unit;
|
2015-09-23 06:20:50 +08:00
|
|
|
|
|
|
|
// Setup access to the debug info.
|
2017-07-20 06:27:28 +08:00
|
|
|
auto DwarfContext = DWARFContext::create(*ErrOrObj);
|
2015-09-23 06:20:50 +08:00
|
|
|
RelocationManager RelocMgr(*this);
|
2017-08-09 02:26:12 +08:00
|
|
|
|
2018-07-26 07:01:38 +08:00
|
|
|
for (const auto &CU : DwarfContext->compile_units()) {
|
|
|
|
updateDwarfVersion(CU->getVersion());
|
2015-09-23 06:20:50 +08:00
|
|
|
// Recursively get all modules imported by this one.
|
2017-08-09 02:26:12 +08:00
|
|
|
auto CUDie = CU->getUnitDIE(false);
|
2018-04-09 01:35:17 +08:00
|
|
|
if (!CUDie)
|
|
|
|
continue;
|
2018-03-13 18:52:49 +08:00
|
|
|
if (!registerModuleReference(CUDie, *CU, ModuleMap, DMO, Ranges, StringPool,
|
2018-09-07 18:29:22 +08:00
|
|
|
UniquingStringPool, ODRContexts,
|
|
|
|
ModulesEndOffset, UnitID, Indent, Quiet)) {
|
2015-09-23 06:20:50 +08:00
|
|
|
if (Unit) {
|
2017-11-17 01:46:43 +08:00
|
|
|
std::string Err =
|
|
|
|
(Filename +
|
|
|
|
": Clang modules are expected to have exactly 1 compile unit.\n")
|
|
|
|
.str();
|
2018-03-09 23:22:42 +08:00
|
|
|
error(Err);
|
2017-11-17 01:46:43 +08:00
|
|
|
return make_error<StringError>(Err, inconvertibleErrorCode());
|
2015-09-23 06:20:50 +08:00
|
|
|
}
|
2016-04-26 01:04:32 +08:00
|
|
|
// FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is
|
|
|
|
// fixed in clang, only warn about DWO_id mismatches in verbose mode.
|
|
|
|
// ASTFileSignatures will change randomly when a module is rebuilt.
|
2016-12-14 02:25:19 +08:00
|
|
|
uint64_t PCMDwoId = getDwoId(CUDie, *CU);
|
2016-05-13 08:17:58 +08:00
|
|
|
if (PCMDwoId != DwoId) {
|
2018-08-25 04:41:08 +08:00
|
|
|
if (!Quiet && Options.Verbose)
|
2016-05-13 08:17:58 +08:00
|
|
|
reportWarning(
|
|
|
|
Twine("hash mismatch: this object file was built against a "
|
2018-02-22 19:32:51 +08:00
|
|
|
"different version of the module ") +
|
2018-03-13 18:52:49 +08:00
|
|
|
Filename,
|
|
|
|
DMO);
|
2016-05-13 08:17:58 +08:00
|
|
|
// Update the cache entry with the DwoId of the module loaded from disk.
|
|
|
|
ClangModules[Filename] = PCMDwoId;
|
|
|
|
}
|
2015-09-24 01:11:10 +08:00
|
|
|
|
|
|
|
// Add this module.
|
2015-09-24 01:35:52 +08:00
|
|
|
Unit = llvm::make_unique<CompileUnit>(*CU, UnitID++, !Options.NoODR,
|
|
|
|
ModuleName);
|
2015-09-23 06:20:50 +08:00
|
|
|
Unit->setHasInterestingContent();
|
2018-03-13 18:52:49 +08:00
|
|
|
analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(),
|
2018-09-07 18:29:22 +08:00
|
|
|
UniquingStringPool, ODRContexts, ModulesEndOffset);
|
2015-09-23 06:20:50 +08:00
|
|
|
// Keep everything.
|
|
|
|
Unit->markEverythingAsKept();
|
|
|
|
}
|
|
|
|
}
|
2017-08-22 09:10:48 +08:00
|
|
|
if (!Unit->getOrigUnit().getUnitDIE().hasChildren())
|
2017-11-17 01:46:43 +08:00
|
|
|
return Error::success();
|
2018-08-25 04:41:08 +08:00
|
|
|
if (!Quiet && Options.Verbose) {
|
2015-09-23 06:20:50 +08:00
|
|
|
outs().indent(Indent);
|
|
|
|
outs() << "cloning .debug_info from " << Filename << "\n";
|
|
|
|
}
|
|
|
|
|
2018-06-28 23:01:42 +08:00
|
|
|
UnitListTy CompileUnits;
|
2016-12-02 02:56:29 +08:00
|
|
|
CompileUnits.push_back(std::move(Unit));
|
|
|
|
DIECloner(*this, RelocMgr, DIEAlloc, CompileUnits, Options)
|
2018-03-13 18:52:49 +08:00
|
|
|
.cloneAllCompileUnits(*DwarfContext, DMO, Ranges, StringPool);
|
2017-11-17 01:46:43 +08:00
|
|
|
return Error::success();
|
2015-09-23 06:20:50 +08:00
|
|
|
}
|
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
void DwarfLinker::DIECloner::cloneAllCompileUnits(
|
|
|
|
DWARFContext &DwarfContext, const DebugMapObject &DMO, RangesTy &Ranges,
|
|
|
|
OffsetsStringPool &StringPool) {
|
2015-09-15 00:46:10 +08:00
|
|
|
if (!Linker.Streamer)
|
2015-09-12 07:45:30 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
for (auto &CurrentUnit : CompileUnits) {
|
2016-12-14 02:25:19 +08:00
|
|
|
auto InputDIE = CurrentUnit->getOrigUnit().getUnitDIE();
|
2016-12-02 02:56:29 +08:00
|
|
|
CurrentUnit->setStartOffset(Linker.OutputDebugInfoSize);
|
2018-04-09 01:35:17 +08:00
|
|
|
if (!InputDIE) {
|
|
|
|
Linker.OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset();
|
|
|
|
continue;
|
|
|
|
}
|
2017-02-10 03:41:55 +08:00
|
|
|
if (CurrentUnit->getInfo(0).Keep) {
|
|
|
|
// Clone the InputDIE into your Unit DIE in our compile unit since it
|
|
|
|
// already has a DIE inside of it.
|
|
|
|
CurrentUnit->createOutputDIE();
|
2018-03-13 18:52:49 +08:00
|
|
|
cloneDIE(InputDIE, DMO, *CurrentUnit, StringPool, 0 /* PC offset */,
|
2017-02-10 03:41:55 +08:00
|
|
|
11 /* Unit Header size */, 0, CurrentUnit->getOutputUnitDIE());
|
|
|
|
}
|
2016-12-02 02:56:29 +08:00
|
|
|
Linker.OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset();
|
2015-09-15 00:46:10 +08:00
|
|
|
if (Linker.Options.NoOutput)
|
2015-09-12 07:45:30 +08:00
|
|
|
continue;
|
2018-02-08 18:48:54 +08:00
|
|
|
|
2019-01-08 07:27:25 +08:00
|
|
|
// FIXME: for compatibility with the classic dsymutil, we emit
|
|
|
|
// an empty line table for the unit, even if the unit doesn't
|
|
|
|
// actually exist in the DIE tree.
|
|
|
|
if (LLVM_LIKELY(!Linker.Options.Update) || Linker.Options.Translator)
|
2018-03-13 18:52:49 +08:00
|
|
|
Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext, Ranges, DMO);
|
2019-01-08 07:27:25 +08:00
|
|
|
Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
|
|
|
|
if (Linker.Options.Update)
|
|
|
|
continue;
|
|
|
|
Linker.patchRangesForUnit(*CurrentUnit, DwarfContext, DMO);
|
|
|
|
Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext);
|
2015-09-12 07:45:30 +08:00
|
|
|
}
|
|
|
|
|
2015-09-15 00:46:10 +08:00
|
|
|
if (Linker.Options.NoOutput)
|
2015-09-12 07:45:30 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Emit all the compile unit's debug information.
|
|
|
|
for (auto &CurrentUnit : CompileUnits) {
|
2018-02-08 18:48:54 +08:00
|
|
|
if (LLVM_LIKELY(!Linker.Options.Update))
|
|
|
|
Linker.generateUnitRanges(*CurrentUnit);
|
2016-12-02 02:56:29 +08:00
|
|
|
CurrentUnit->fixupForwardReferences();
|
|
|
|
Linker.Streamer->emitCompileUnitHeader(*CurrentUnit);
|
|
|
|
if (!CurrentUnit->getOutputUnitDIE())
|
2015-09-12 07:45:30 +08:00
|
|
|
continue;
|
2016-12-02 02:56:29 +08:00
|
|
|
Linker.Streamer->emitDIE(*CurrentUnit->getOutputUnitDIE());
|
2015-09-12 07:45:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-26 07:01:38 +08:00
|
|
|
void DwarfLinker::updateAccelKind(DWARFContext &Dwarf) {
|
|
|
|
if (Options.TheAccelTableKind != AccelTableKind::Default)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto &DwarfObj = Dwarf.getDWARFObj();
|
|
|
|
|
|
|
|
if (!AtLeastOneDwarfAccelTable &&
|
|
|
|
(!DwarfObj.getAppleNamesSection().Data.empty() ||
|
|
|
|
!DwarfObj.getAppleTypesSection().Data.empty() ||
|
|
|
|
!DwarfObj.getAppleNamespacesSection().Data.empty() ||
|
|
|
|
!DwarfObj.getAppleObjCSection().Data.empty())) {
|
|
|
|
AtLeastOneAppleAccelTable = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!AtLeastOneDwarfAccelTable &&
|
|
|
|
!DwarfObj.getDebugNamesSection().Data.empty()) {
|
|
|
|
AtLeastOneDwarfAccelTable = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-02 18:40:43 +08:00
|
|
|
bool DwarfLinker::emitPaperTrailWarnings(const DebugMapObject &DMO,
|
|
|
|
const DebugMap &Map,
|
|
|
|
OffsetsStringPool &StringPool) {
|
|
|
|
if (DMO.getWarnings().empty() || !DMO.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Streamer->switchToDebugInfoSection(/* Version */ 2);
|
|
|
|
DIE *CUDie = DIE::get(DIEAlloc, dwarf::DW_TAG_compile_unit);
|
|
|
|
CUDie->setOffset(11);
|
|
|
|
StringRef Producer = StringPool.internString("dsymutil");
|
|
|
|
StringRef File = StringPool.internString(DMO.getObjectFilename());
|
|
|
|
CUDie->addValue(DIEAlloc, dwarf::DW_AT_producer, dwarf::DW_FORM_strp,
|
|
|
|
DIEInteger(StringPool.getStringOffset(Producer)));
|
|
|
|
DIEBlock *String = new (DIEAlloc) DIEBlock();
|
|
|
|
DIEBlocks.push_back(String);
|
|
|
|
for (auto &C : File)
|
|
|
|
String->addValue(DIEAlloc, dwarf::Attribute(0), dwarf::DW_FORM_data1,
|
|
|
|
DIEInteger(C));
|
|
|
|
String->addValue(DIEAlloc, dwarf::Attribute(0), dwarf::DW_FORM_data1,
|
|
|
|
DIEInteger(0));
|
|
|
|
|
|
|
|
CUDie->addValue(DIEAlloc, dwarf::DW_AT_name, dwarf::DW_FORM_string, String);
|
|
|
|
for (const auto &Warning : DMO.getWarnings()) {
|
|
|
|
DIE &ConstDie = CUDie->addChild(DIE::get(DIEAlloc, dwarf::DW_TAG_constant));
|
|
|
|
ConstDie.addValue(
|
|
|
|
DIEAlloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp,
|
|
|
|
DIEInteger(StringPool.getStringOffset("dsymutil_warning")));
|
|
|
|
ConstDie.addValue(DIEAlloc, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag,
|
|
|
|
DIEInteger(1));
|
|
|
|
ConstDie.addValue(DIEAlloc, dwarf::DW_AT_const_value, dwarf::DW_FORM_strp,
|
|
|
|
DIEInteger(StringPool.getStringOffset(Warning)));
|
|
|
|
}
|
|
|
|
unsigned Size = 4 /* FORM_strp */ + File.size() + 1 +
|
|
|
|
DMO.getWarnings().size() * (4 + 1 + 4) +
|
|
|
|
1 /* End of children */;
|
|
|
|
DIEAbbrev Abbrev = CUDie->generateAbbrev();
|
|
|
|
AssignAbbrev(Abbrev);
|
|
|
|
CUDie->setAbbrevNumber(Abbrev.getNumber());
|
|
|
|
Size += getULEB128Size(Abbrev.getNumber());
|
|
|
|
// Abbreviation ordering needed for classic compatibility.
|
|
|
|
for (auto &Child : CUDie->children()) {
|
|
|
|
Abbrev = Child.generateAbbrev();
|
|
|
|
AssignAbbrev(Abbrev);
|
|
|
|
Child.setAbbrevNumber(Abbrev.getNumber());
|
|
|
|
Size += getULEB128Size(Abbrev.getNumber());
|
|
|
|
}
|
|
|
|
CUDie->setSize(Size);
|
|
|
|
auto &Asm = Streamer->getAsmPrinter();
|
|
|
|
Asm.emitInt32(11 + CUDie->getSize() - 4);
|
|
|
|
Asm.emitInt16(2);
|
|
|
|
Asm.emitInt32(0);
|
|
|
|
Asm.emitInt8(Map.getTriple().isArch64Bit() ? 8 : 4);
|
|
|
|
Streamer->emitDIE(*CUDie);
|
|
|
|
OutputDebugInfoSize += 11 /* Header */ + Size;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-01-29 02:27:01 +08:00
|
|
|
bool DwarfLinker::link(const DebugMap &Map) {
|
2017-11-16 04:55:53 +08:00
|
|
|
if (!createStreamer(Map.getTriple(), OutFile))
|
2015-02-28 08:29:11 +08:00
|
|
|
return false;
|
|
|
|
|
2015-03-05 06:07:44 +08:00
|
|
|
// Size of the DIEs (and headers) generated for the linked output.
|
2015-09-12 07:45:30 +08:00
|
|
|
OutputDebugInfoSize = 0;
|
2015-03-14 11:46:40 +08:00
|
|
|
// A unique ID that identifies each compile unit.
|
2018-03-13 18:52:49 +08:00
|
|
|
unsigned UnitID = 0;
|
2015-09-23 06:20:50 +08:00
|
|
|
DebugMap ModuleMap(Map.getTriple(), Map.getBinaryPath());
|
|
|
|
|
2018-03-13 22:27:15 +08:00
|
|
|
// First populate the data structure we need for each iteration of the
|
|
|
|
// parallel loop.
|
|
|
|
unsigned NumObjects = Map.getNumberOfObjects();
|
|
|
|
std::vector<LinkContext> ObjectContexts;
|
|
|
|
ObjectContexts.reserve(NumObjects);
|
2018-07-26 07:01:38 +08:00
|
|
|
for (const auto &Obj : Map.objects()) {
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-30 00:50:41 +08:00
|
|
|
ObjectContexts.emplace_back(Map, *this, *Obj.get());
|
2018-07-26 07:01:38 +08:00
|
|
|
LinkContext &LC = ObjectContexts.back();
|
|
|
|
if (LC.ObjectFile)
|
|
|
|
updateAccelKind(*LC.DwarfContext);
|
|
|
|
}
|
2018-03-13 22:27:15 +08:00
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
// This Dwarf string pool which is only used for uniquing. This one should
|
|
|
|
// never be used for offsets as its not thread-safe or predictable.
|
|
|
|
UniquingStringPool UniquingStringPool;
|
|
|
|
|
|
|
|
// This Dwarf string pool which is used for emission. It must be used
|
|
|
|
// serially as the order of calling getStringOffset matters for
|
|
|
|
// reproducibility.
|
2019-01-08 07:27:25 +08:00
|
|
|
OffsetsStringPool OffsetsStringPool(Options.Translator);
|
2018-03-13 18:52:49 +08:00
|
|
|
|
|
|
|
// ODR Contexts for the link.
|
|
|
|
DeclContextTree ODRContexts;
|
|
|
|
|
2018-07-26 07:01:38 +08:00
|
|
|
// If we haven't decided on an accelerator table kind yet, we base ourselves
|
|
|
|
// on the DWARF we have seen so far. At this point we haven't pulled in debug
|
|
|
|
// information from modules yet, so it is technically possible that they
|
|
|
|
// would affect the decision. However, as they're built with the same
|
|
|
|
// compiler and flags, it is safe to assume that they will follow the
|
|
|
|
// decision made here.
|
|
|
|
if (Options.TheAccelTableKind == AccelTableKind::Default) {
|
|
|
|
if (AtLeastOneDwarfAccelTable && !AtLeastOneAppleAccelTable)
|
|
|
|
Options.TheAccelTableKind = AccelTableKind::Dwarf;
|
|
|
|
else
|
|
|
|
Options.TheAccelTableKind = AccelTableKind::Apple;
|
|
|
|
}
|
|
|
|
|
2018-03-13 22:27:15 +08:00
|
|
|
for (LinkContext &LinkContext : ObjectContexts) {
|
2015-02-28 08:29:07 +08:00
|
|
|
if (Options.Verbose)
|
2018-03-13 22:27:15 +08:00
|
|
|
outs() << "DEBUG MAP OBJECT: " << LinkContext.DMO.getObjectFilename()
|
|
|
|
<< "\n";
|
2017-10-06 22:49:20 +08:00
|
|
|
|
|
|
|
// N_AST objects (swiftmodule files) should get dumped directly into the
|
|
|
|
// appropriate DWARF section.
|
2018-03-13 18:52:49 +08:00
|
|
|
if (LinkContext.DMO.getType() == MachO::N_AST) {
|
|
|
|
StringRef File = LinkContext.DMO.getObjectFilename();
|
2017-10-13 22:41:23 +08:00
|
|
|
auto ErrorOrMem = MemoryBuffer::getFile(File);
|
|
|
|
if (!ErrorOrMem) {
|
2018-03-13 23:47:38 +08:00
|
|
|
warn("Could not open '" + File + "'\n");
|
2017-10-06 22:49:20 +08:00
|
|
|
continue;
|
2017-10-13 22:41:23 +08:00
|
|
|
}
|
|
|
|
sys::fs::file_status Stat;
|
2018-03-09 23:22:42 +08:00
|
|
|
if (auto Err = sys::fs::status(File, Stat)) {
|
|
|
|
warn(Err.message());
|
2017-10-13 22:41:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
2018-12-05 01:15:23 +08:00
|
|
|
if (!Options.NoTimestamp) {
|
|
|
|
// The modification can have sub-second precision so we need to cast
|
|
|
|
// away the extra precision that's not present in the debug map.
|
|
|
|
auto ModificationTime =
|
|
|
|
std::chrono::time_point_cast<std::chrono::seconds>(
|
|
|
|
Stat.getLastModificationTime());
|
|
|
|
if (ModificationTime != LinkContext.DMO.getTimestamp()) {
|
|
|
|
// Not using the helper here as we can easily stream TimePoint<>.
|
|
|
|
WithColor::warning()
|
|
|
|
<< "Timestamp mismatch for " << File << ": "
|
|
|
|
<< Stat.getLastModificationTime() << " and "
|
|
|
|
<< sys::TimePoint<>(LinkContext.DMO.getTimestamp()) << "\n";
|
|
|
|
continue;
|
|
|
|
}
|
2017-10-13 22:41:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the module into the .swift_ast section.
|
2017-10-06 22:49:20 +08:00
|
|
|
if (!Options.NoOutput)
|
2017-10-13 22:41:23 +08:00
|
|
|
Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
|
2017-10-06 22:49:20 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-04-02 18:40:43 +08:00
|
|
|
if (emitPaperTrailWarnings(LinkContext.DMO, Map, OffsetsStringPool))
|
|
|
|
continue;
|
2018-03-13 22:27:15 +08:00
|
|
|
|
2018-04-02 18:40:43 +08:00
|
|
|
if (!LinkContext.ObjectFile)
|
2015-01-29 02:27:01 +08:00
|
|
|
continue;
|
|
|
|
|
2015-02-14 07:18:22 +08:00
|
|
|
// Look for relocations that correspond to debug map entries.
|
2018-03-13 22:27:15 +08:00
|
|
|
|
2018-02-08 18:48:54 +08:00
|
|
|
if (LLVM_LIKELY(!Options.Update) &&
|
2018-03-13 18:52:49 +08:00
|
|
|
!LinkContext.RelocMgr.findValidRelocsInDebugInfo(
|
|
|
|
*LinkContext.ObjectFile, LinkContext.DMO)) {
|
2015-02-28 08:29:07 +08:00
|
|
|
if (Options.Verbose)
|
2018-03-13 22:27:15 +08:00
|
|
|
outs() << "No valid relocations found. Skipping.\n";
|
|
|
|
|
|
|
|
// Clear this ObjFile entry as a signal to other loops that we should not
|
|
|
|
// process this iteration.
|
|
|
|
LinkContext.ObjectFile = nullptr;
|
2015-02-14 07:18:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-01-29 06:15:14 +08:00
|
|
|
// Setup access to the debug info.
|
2018-03-13 18:52:49 +08:00
|
|
|
if (!LinkContext.DwarfContext)
|
|
|
|
continue;
|
2015-01-29 02:27:01 +08:00
|
|
|
|
2018-03-13 22:27:15 +08:00
|
|
|
startDebugObject(LinkContext);
|
|
|
|
|
2015-10-06 07:11:20 +08:00
|
|
|
// In a first phase, just read in the debug info and load all clang modules.
|
2018-03-13 18:52:49 +08:00
|
|
|
LinkContext.CompileUnits.reserve(
|
|
|
|
LinkContext.DwarfContext->getNumCompileUnits());
|
2018-07-26 07:01:38 +08:00
|
|
|
|
2018-03-13 18:52:49 +08:00
|
|
|
for (const auto &CU : LinkContext.DwarfContext->compile_units()) {
|
2018-07-26 07:01:38 +08:00
|
|
|
updateDwarfVersion(CU->getVersion());
|
2016-12-14 02:25:19 +08:00
|
|
|
auto CUDie = CU->getUnitDIE(false);
|
2015-02-28 08:29:07 +08:00
|
|
|
if (Options.Verbose) {
|
2015-01-29 02:27:01 +08:00
|
|
|
outs() << "Input compilation unit:";
|
2017-09-13 17:43:05 +08:00
|
|
|
DIDumpOptions DumpOpts;
|
2017-09-21 01:44:00 +08:00
|
|
|
DumpOpts.RecurseDepth = 0;
|
2017-09-13 17:43:05 +08:00
|
|
|
DumpOpts.Verbose = Options.Verbose;
|
2017-09-21 01:44:00 +08:00
|
|
|
CUDie.dump(outs(), 0, DumpOpts);
|
2015-01-29 02:27:01 +08:00
|
|
|
}
|
2018-08-25 04:41:08 +08:00
|
|
|
if (CUDie && !LLVM_UNLIKELY(Options.Update))
|
|
|
|
registerModuleReference(CUDie, *CU, ModuleMap, LinkContext.DMO,
|
|
|
|
LinkContext.Ranges, OffsetsStringPool,
|
2018-09-07 18:29:22 +08:00
|
|
|
UniquingStringPool, ODRContexts, 0, UnitID);
|
2015-01-29 02:27:01 +08:00
|
|
|
}
|
2018-03-13 22:27:15 +08:00
|
|
|
}
|
2015-01-29 06:15:14 +08:00
|
|
|
|
2018-07-26 07:01:38 +08:00
|
|
|
// If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
|
2018-04-02 18:40:43 +08:00
|
|
|
if (MaxDwarfVersion == 0)
|
|
|
|
MaxDwarfVersion = 3;
|
|
|
|
|
2018-09-07 18:29:22 +08:00
|
|
|
// At this point we know how much data we have emitted. We use this value to
|
|
|
|
// compare canonical DIE offsets in analyzeContextInfo to see if a definition
|
|
|
|
// is already emitted, without being affected by canonical die offsets set
|
|
|
|
// later. This prevents undeterminism when analyze and clone execute
|
|
|
|
// concurrently, as clone set the canonical DIE offset and analyze reads it.
|
|
|
|
const uint64_t ModulesEndOffset = OutputDebugInfoSize;
|
|
|
|
|
2018-03-13 22:27:15 +08:00
|
|
|
// These variables manage the list of processed object files.
|
|
|
|
// The mutex and condition variable are to ensure that this is thread safe.
|
|
|
|
std::mutex ProcessedFilesMutex;
|
|
|
|
std::condition_variable ProcessedFilesConditionVariable;
|
|
|
|
BitVector ProcessedFiles(NumObjects, false);
|
|
|
|
|
2018-09-07 01:31:59 +08:00
|
|
|
// Analyzing the context info is particularly expensive so it is executed in
|
|
|
|
// parallel with emitting the previous compile unit.
|
|
|
|
auto AnalyzeLambda = [&](size_t i) {
|
|
|
|
auto &LinkContext = ObjectContexts[i];
|
2018-03-13 22:27:15 +08:00
|
|
|
|
2018-09-07 01:31:59 +08:00
|
|
|
if (!LinkContext.ObjectFile || !LinkContext.DwarfContext)
|
|
|
|
return;
|
2018-03-13 22:27:15 +08:00
|
|
|
|
2018-09-07 01:31:59 +08:00
|
|
|
for (const auto &CU : LinkContext.DwarfContext->compile_units()) {
|
|
|
|
updateDwarfVersion(CU->getVersion());
|
|
|
|
// The !registerModuleReference() condition effectively skips
|
|
|
|
// over fully resolved skeleton units. This second pass of
|
|
|
|
// registerModuleReferences doesn't do any new work, but it
|
|
|
|
// will collect top-level errors, which are suppressed. Module
|
|
|
|
// warnings were already displayed in the first iteration.
|
|
|
|
bool Quiet = true;
|
|
|
|
auto CUDie = CU->getUnitDIE(false);
|
|
|
|
if (!CUDie || LLVM_UNLIKELY(Options.Update) ||
|
|
|
|
!registerModuleReference(CUDie, *CU, ModuleMap, LinkContext.DMO,
|
|
|
|
LinkContext.Ranges, OffsetsStringPool,
|
2018-09-07 18:29:22 +08:00
|
|
|
UniquingStringPool, ODRContexts,
|
|
|
|
ModulesEndOffset, UnitID, Quiet)) {
|
2018-09-07 01:31:59 +08:00
|
|
|
LinkContext.CompileUnits.push_back(llvm::make_unique<CompileUnit>(
|
|
|
|
*CU, UnitID++, !Options.NoODR && !Options.Update, ""));
|
2018-04-09 01:35:17 +08:00
|
|
|
}
|
2018-09-07 01:31:59 +08:00
|
|
|
}
|
2018-03-13 22:27:15 +08:00
|
|
|
|
2018-09-07 01:31:59 +08:00
|
|
|
// Now build the DIE parent links that we will use during the next phase.
|
|
|
|
for (auto &CurrentUnit : LinkContext.CompileUnits) {
|
|
|
|
auto CUDie = CurrentUnit->getOrigUnit().getUnitDIE();
|
|
|
|
if (!CUDie)
|
|
|
|
continue;
|
|
|
|
analyzeContextInfo(CurrentUnit->getOrigUnit().getUnitDIE(), 0,
|
|
|
|
*CurrentUnit, &ODRContexts.getRoot(),
|
2018-09-07 18:29:22 +08:00
|
|
|
UniquingStringPool, ODRContexts, ModulesEndOffset);
|
2018-02-08 18:48:54 +08:00
|
|
|
}
|
2018-04-04 02:01:18 +08:00
|
|
|
};
|
2018-03-13 22:27:15 +08:00
|
|
|
|
|
|
|
// And then the remaining work in serial again.
|
|
|
|
// Note, although this loop runs in serial, it can run in parallel with
|
|
|
|
// the analyzeContextInfo loop so long as we process files with indices >=
|
|
|
|
// than those processed by analyzeContextInfo.
|
2018-09-07 01:31:59 +08:00
|
|
|
auto CloneLambda = [&](size_t i) {
|
|
|
|
auto &LinkContext = ObjectContexts[i];
|
|
|
|
if (!LinkContext.ObjectFile)
|
|
|
|
return;
|
2018-03-13 22:27:15 +08:00
|
|
|
|
2018-09-07 01:31:59 +08:00
|
|
|
// Then mark all the DIEs that need to be present in the linked output
|
|
|
|
// and collect some information about them.
|
|
|
|
// Note that this loop can not be merged with the previous one because
|
|
|
|
// cross-cu references require the ParentIdx to be setup for every CU in
|
|
|
|
// the object file before calling this.
|
|
|
|
if (LLVM_UNLIKELY(Options.Update)) {
|
|
|
|
for (auto &CurrentUnit : LinkContext.CompileUnits)
|
|
|
|
CurrentUnit->markEverythingAsKept();
|
|
|
|
Streamer->copyInvariantDebugSection(*LinkContext.ObjectFile);
|
|
|
|
} else {
|
|
|
|
for (auto &CurrentUnit : LinkContext.CompileUnits)
|
|
|
|
lookForDIEsToKeep(LinkContext.RelocMgr, LinkContext.Ranges,
|
|
|
|
LinkContext.CompileUnits,
|
|
|
|
CurrentUnit->getOrigUnit().getUnitDIE(),
|
|
|
|
LinkContext.DMO, *CurrentUnit, 0);
|
2018-03-13 22:27:15 +08:00
|
|
|
}
|
|
|
|
|
2018-09-07 01:31:59 +08:00
|
|
|
// The calls to applyValidRelocs inside cloneDIE will walk the reloc
|
|
|
|
// array again (in the same way findValidRelocsInDebugInfo() did). We
|
|
|
|
// need to reset the NextValidReloc index to the beginning.
|
|
|
|
LinkContext.RelocMgr.resetValidRelocs();
|
|
|
|
if (LinkContext.RelocMgr.hasValidRelocs() || LLVM_UNLIKELY(Options.Update))
|
|
|
|
DIECloner(*this, LinkContext.RelocMgr, DIEAlloc, LinkContext.CompileUnits,
|
|
|
|
Options)
|
|
|
|
.cloneAllCompileUnits(*LinkContext.DwarfContext, LinkContext.DMO,
|
|
|
|
LinkContext.Ranges, OffsetsStringPool);
|
|
|
|
if (!Options.NoOutput && !LinkContext.CompileUnits.empty() &&
|
|
|
|
LLVM_LIKELY(!Options.Update))
|
|
|
|
patchFrameInfoForObject(
|
|
|
|
LinkContext.DMO, LinkContext.Ranges, *LinkContext.DwarfContext,
|
|
|
|
LinkContext.CompileUnits[0]->getOrigUnit().getAddressByteSize());
|
|
|
|
|
|
|
|
// Clean-up before starting working on the next object.
|
|
|
|
endDebugObject(LinkContext);
|
|
|
|
};
|
|
|
|
|
|
|
|
auto EmitLambda = [&]() {
|
2018-03-13 22:27:15 +08:00
|
|
|
// Emit everything that's global.
|
|
|
|
if (!Options.NoOutput) {
|
|
|
|
Streamer->emitAbbrevs(Abbreviations, MaxDwarfVersion);
|
|
|
|
Streamer->emitStrings(OffsetsStringPool);
|
2018-07-26 07:01:38 +08:00
|
|
|
switch (Options.TheAccelTableKind) {
|
|
|
|
case AccelTableKind::Apple:
|
|
|
|
Streamer->emitAppleNames(AppleNames);
|
|
|
|
Streamer->emitAppleNamespaces(AppleNamespaces);
|
|
|
|
Streamer->emitAppleTypes(AppleTypes);
|
|
|
|
Streamer->emitAppleObjc(AppleObjc);
|
|
|
|
break;
|
|
|
|
case AccelTableKind::Dwarf:
|
|
|
|
Streamer->emitDebugNames(DebugNames);
|
|
|
|
break;
|
|
|
|
case AccelTableKind::Default:
|
|
|
|
llvm_unreachable("Default should have already been resolved.");
|
|
|
|
break;
|
|
|
|
}
|
2018-03-13 22:27:15 +08:00
|
|
|
}
|
2018-04-04 02:01:18 +08:00
|
|
|
};
|
2018-03-13 22:27:15 +08:00
|
|
|
|
2018-09-07 01:31:59 +08:00
|
|
|
auto AnalyzeAll = [&]() {
|
|
|
|
for (unsigned i = 0, e = NumObjects; i != e; ++i) {
|
|
|
|
AnalyzeLambda(i);
|
|
|
|
|
|
|
|
std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
|
|
|
|
ProcessedFiles.set(i);
|
|
|
|
ProcessedFilesConditionVariable.notify_one();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
auto CloneAll = [&]() {
|
|
|
|
for (unsigned i = 0, e = NumObjects; i != e; ++i) {
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> LockGuard(ProcessedFilesMutex);
|
|
|
|
if (!ProcessedFiles[i]) {
|
|
|
|
ProcessedFilesConditionVariable.wait(
|
|
|
|
LockGuard, [&]() { return ProcessedFiles[i]; });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CloneLambda(i);
|
|
|
|
}
|
|
|
|
EmitLambda();
|
|
|
|
};
|
|
|
|
|
|
|
|
// To limit memory usage in the single threaded case, analyze and clone are
|
|
|
|
// run sequentially so the LinkContext is freed after processing each object
|
|
|
|
// in endDebugObject.
|
2018-04-04 02:01:18 +08:00
|
|
|
if (Options.Threads == 1) {
|
2018-09-07 01:31:59 +08:00
|
|
|
for (unsigned i = 0, e = NumObjects; i != e; ++i) {
|
|
|
|
AnalyzeLambda(i);
|
|
|
|
CloneLambda(i);
|
|
|
|
}
|
|
|
|
EmitLambda();
|
2018-04-04 02:01:18 +08:00
|
|
|
} else {
|
|
|
|
ThreadPool pool(2);
|
2018-09-07 01:31:59 +08:00
|
|
|
pool.async(AnalyzeAll);
|
|
|
|
pool.async(CloneAll);
|
2018-04-04 02:01:18 +08:00
|
|
|
pool.wait();
|
|
|
|
}
|
2015-03-05 06:07:44 +08:00
|
|
|
|
2019-01-08 07:27:25 +08:00
|
|
|
return Options.NoOutput ? true : Streamer->finish(Map, Options.Translator);
|
2018-07-26 07:01:38 +08:00
|
|
|
} // namespace dsymutil
|
2015-01-29 02:27:01 +08:00
|
|
|
|
2018-06-30 00:51:52 +08:00
|
|
|
bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-30 00:50:41 +08:00
|
|
|
const DebugMap &DM, const LinkOptions &Options) {
|
|
|
|
DwarfLinker Linker(OutFile, BinHolder, Options);
|
2015-01-29 02:27:01 +08:00
|
|
|
return Linker.link(DM);
|
|
|
|
}
|
2017-11-02 05:16:06 +08:00
|
|
|
|
2018-03-13 23:47:38 +08:00
|
|
|
} // namespace dsymutil
|
|
|
|
} // namespace llvm
|