mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-30 09:01:19 +00:00
[Reland][Reland][DWARFLinkerParallel] Add limited functionality to DWARFLinkerParallel.
This patch is extracted from D96035, it adds support for the existing DWARFLinker functionality. What is not supported yet: 1. Types deduplication(--odr mode). 2. Modules deduplication. 3. Generation of index tables. Reland2: temporarily disabled call to "--linker llvm" for tls-variable.test and location-expression.test as it does not work properly on bigendian architecture. Differential Revision: https://reviews.llvm.org/D153268
This commit is contained in:
parent
91088978d7
commit
5f2a7fa67e
@ -27,29 +27,34 @@ struct DwarfStringPoolEntry {
|
||||
bool isIndexed() const { return Index != NotIndexed; }
|
||||
};
|
||||
|
||||
/// DwarfStringPoolEntry with string keeping externally.
|
||||
struct DwarfStringPoolEntryWithExtString : public DwarfStringPoolEntry {
|
||||
StringRef String;
|
||||
};
|
||||
|
||||
/// DwarfStringPoolEntryRef: Dwarf string pool entry reference.
|
||||
///
|
||||
/// Dwarf string pool entry keeps string value and its data.
|
||||
/// There are two variants how data are represented:
|
||||
///
|
||||
/// 1. By value - StringMapEntry<DwarfStringPoolEntry>.
|
||||
/// 2. By pointer - StringMapEntry<DwarfStringPoolEntry *>.
|
||||
/// 1. String data in pool - StringMapEntry<DwarfStringPoolEntry>.
|
||||
/// 2. External string data - DwarfStringPoolEntryWithExtString.
|
||||
///
|
||||
/// The "By pointer" variant allows for reducing memory usage for the case
|
||||
/// when string pool entry does not have data: it keeps the null pointer
|
||||
/// and so no need to waste space for the full DwarfStringPoolEntry.
|
||||
/// It is recommended to use "By pointer" variant if not all entries
|
||||
/// of dwarf string pool have corresponding DwarfStringPoolEntry.
|
||||
/// The external data variant allows reducing memory usage for the case
|
||||
/// when string pool entry does not have data: string entry does not
|
||||
/// keep any data and so no need to waste space for the full
|
||||
/// DwarfStringPoolEntry. It is recommended to use external variant if not all
|
||||
/// entries of dwarf string pool have corresponding DwarfStringPoolEntry.
|
||||
|
||||
class DwarfStringPoolEntryRef {
|
||||
/// Pointer type for "By value" string entry.
|
||||
using ByValStringEntryPtr = const StringMapEntry<DwarfStringPoolEntry> *;
|
||||
|
||||
/// Pointer type for "By pointer" string entry.
|
||||
using ByPtrStringEntryPtr = const StringMapEntry<DwarfStringPoolEntry *> *;
|
||||
/// Pointer type for external string entry.
|
||||
using ExtStringEntryPtr = const DwarfStringPoolEntryWithExtString *;
|
||||
|
||||
/// Pointer to the dwarf string pool Entry.
|
||||
PointerUnion<ByValStringEntryPtr, ByPtrStringEntryPtr> MapEntry = nullptr;
|
||||
PointerUnion<ByValStringEntryPtr, ExtStringEntryPtr> MapEntry = nullptr;
|
||||
|
||||
public:
|
||||
DwarfStringPoolEntryRef() = default;
|
||||
@ -61,10 +66,8 @@ public:
|
||||
|
||||
/// ASSUMPTION: DwarfStringPoolEntryRef keeps pointer to \p Entry,
|
||||
/// thus specified entry mustn`t be reallocated.
|
||||
DwarfStringPoolEntryRef(const StringMapEntry<DwarfStringPoolEntry *> &Entry)
|
||||
: MapEntry(&Entry) {
|
||||
assert(cast<ByPtrStringEntryPtr>(MapEntry)->second != nullptr);
|
||||
}
|
||||
DwarfStringPoolEntryRef(const DwarfStringPoolEntryWithExtString &Entry)
|
||||
: MapEntry(&Entry) {}
|
||||
|
||||
explicit operator bool() const { return !MapEntry.isNull(); }
|
||||
|
||||
@ -88,7 +91,7 @@ public:
|
||||
if (isa<ByValStringEntryPtr>(MapEntry))
|
||||
return cast<ByValStringEntryPtr>(MapEntry)->first();
|
||||
|
||||
return cast<ByPtrStringEntryPtr>(MapEntry)->first();
|
||||
return cast<ExtStringEntryPtr>(MapEntry)->String;
|
||||
}
|
||||
|
||||
/// \returns the entire string pool entry for convenience.
|
||||
@ -96,7 +99,7 @@ public:
|
||||
if (isa<ByValStringEntryPtr>(MapEntry))
|
||||
return cast<ByValStringEntryPtr>(MapEntry)->second;
|
||||
|
||||
return *cast<ByPtrStringEntryPtr>(MapEntry)->second;
|
||||
return *cast<ExtStringEntryPtr>(MapEntry);
|
||||
}
|
||||
|
||||
bool operator==(const DwarfStringPoolEntryRef &X) const {
|
||||
|
@ -270,9 +270,11 @@ using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>;
|
||||
/// and its address map.
|
||||
class DWARFFile {
|
||||
public:
|
||||
using UnloadCallbackTy = std::function<void(StringRef FileName)>;
|
||||
DWARFFile(StringRef Name, std::unique_ptr<DWARFContext> Dwarf,
|
||||
std::unique_ptr<AddressesMap> Addresses,
|
||||
const std::vector<std::string> &Warnings)
|
||||
const std::vector<std::string> &Warnings,
|
||||
UnloadCallbackTy = nullptr)
|
||||
: FileName(Name), Dwarf(std::move(Dwarf)),
|
||||
Addresses(std::move(Addresses)), Warnings(Warnings) {}
|
||||
|
||||
|
@ -10,8 +10,10 @@
|
||||
#define LLVM_DWARFLINKERPARALLEL_ADDRESSESMAP_H
|
||||
|
||||
#include "llvm/ADT/AddressRanges.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
@ -62,6 +64,108 @@ public:
|
||||
|
||||
/// Erases all data.
|
||||
virtual void clear() = 0;
|
||||
|
||||
/// This function checks whether variable has DWARF expression containing
|
||||
/// operation referencing live address(f.e. DW_OP_addr, DW_OP_addrx...).
|
||||
/// \returns first is true if the expression has an operation referencing an
|
||||
/// address.
|
||||
/// second is the relocation adjustment value if the live address is
|
||||
/// referenced.
|
||||
std::pair<bool, std::optional<int64_t>>
|
||||
getVariableRelocAdjustment(const DWARFDie &DIE) {
|
||||
assert((DIE.getTag() == dwarf::DW_TAG_variable ||
|
||||
DIE.getTag() == dwarf::DW_TAG_constant) &&
|
||||
"Wrong type of input die");
|
||||
|
||||
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
|
||||
|
||||
// Check if DIE has DW_AT_location attribute.
|
||||
DWARFUnit *U = DIE.getDwarfUnit();
|
||||
std::optional<uint32_t> LocationIdx =
|
||||
Abbrev->findAttributeIndex(dwarf::DW_AT_location);
|
||||
if (!LocationIdx)
|
||||
return std::make_pair(false, std::nullopt);
|
||||
|
||||
// Get offset to the DW_AT_location attribute.
|
||||
uint64_t AttrOffset =
|
||||
Abbrev->getAttributeOffsetFromIndex(*LocationIdx, DIE.getOffset(), *U);
|
||||
|
||||
// Get value of the DW_AT_location attribute.
|
||||
std::optional<DWARFFormValue> LocationValue =
|
||||
Abbrev->getAttributeValueFromOffset(*LocationIdx, AttrOffset, *U);
|
||||
if (!LocationValue)
|
||||
return std::make_pair(false, std::nullopt);
|
||||
|
||||
// Check that DW_AT_location attribute is of 'exprloc' class.
|
||||
// Handling value of location expressions for attributes of 'loclist'
|
||||
// class is not implemented yet.
|
||||
std::optional<ArrayRef<uint8_t>> Expr = LocationValue->getAsBlock();
|
||||
if (!Expr)
|
||||
return std::make_pair(false, std::nullopt);
|
||||
|
||||
// Parse 'exprloc' expression.
|
||||
DataExtractor Data(toStringRef(*Expr), U->getContext().isLittleEndian(),
|
||||
U->getAddressByteSize());
|
||||
DWARFExpression Expression(Data, U->getAddressByteSize(),
|
||||
U->getFormParams().Format);
|
||||
|
||||
bool HasLocationAddress = false;
|
||||
uint64_t CurExprOffset = 0;
|
||||
for (DWARFExpression::iterator It = Expression.begin();
|
||||
It != Expression.end(); ++It) {
|
||||
DWARFExpression::iterator NextIt = It;
|
||||
++NextIt;
|
||||
|
||||
const DWARFExpression::Operation &Op = *It;
|
||||
switch (Op.getCode()) {
|
||||
case dwarf::DW_OP_const2u:
|
||||
case dwarf::DW_OP_const4u:
|
||||
case dwarf::DW_OP_const8u:
|
||||
case dwarf::DW_OP_const2s:
|
||||
case dwarf::DW_OP_const4s:
|
||||
case dwarf::DW_OP_const8s:
|
||||
if (NextIt == Expression.end() || !isTlsAddressCode(NextIt->getCode()))
|
||||
break;
|
||||
[[fallthrough]];
|
||||
case dwarf::DW_OP_addr: {
|
||||
HasLocationAddress = true;
|
||||
// Check relocation for the address.
|
||||
if (std::optional<int64_t> RelocAdjustment =
|
||||
getExprOpAddressRelocAdjustment(*U, Op,
|
||||
AttrOffset + CurExprOffset,
|
||||
AttrOffset + Op.getEndOffset()))
|
||||
return std::make_pair(HasLocationAddress, *RelocAdjustment);
|
||||
} break;
|
||||
case dwarf::DW_OP_constx:
|
||||
case dwarf::DW_OP_addrx: {
|
||||
HasLocationAddress = true;
|
||||
if (std::optional<uint64_t> AddressOffset =
|
||||
DIE.getDwarfUnit()->getIndexedAddressOffset(
|
||||
Op.getRawOperand(0))) {
|
||||
// Check relocation for the address.
|
||||
if (std::optional<int64_t> RelocAdjustment =
|
||||
getExprOpAddressRelocAdjustment(
|
||||
*U, Op, *AddressOffset,
|
||||
*AddressOffset +
|
||||
DIE.getDwarfUnit()->getAddressByteSize()))
|
||||
return std::make_pair(HasLocationAddress, *RelocAdjustment);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
// Nothing to do.
|
||||
} break;
|
||||
}
|
||||
CurExprOffset = Op.getEndOffset();
|
||||
}
|
||||
|
||||
return std::make_pair(HasLocationAddress, std::nullopt);
|
||||
}
|
||||
|
||||
protected:
|
||||
inline bool isTlsAddressCode(uint8_t DW_OP_Code) {
|
||||
return DW_OP_Code == dwarf::DW_OP_form_tls_address ||
|
||||
DW_OP_Code == dwarf::DW_OP_GNU_push_tls_address;
|
||||
}
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
|
@ -30,14 +30,7 @@ public:
|
||||
DWARFFile(StringRef Name, std::unique_ptr<DWARFContext> Dwarf,
|
||||
std::unique_ptr<AddressesMap> Addresses,
|
||||
const std::vector<std::string> &Warnings,
|
||||
UnloadCallbackTy UnloadFunc = nullptr)
|
||||
: FileName(Name), Dwarf(std::move(Dwarf)),
|
||||
Addresses(std::move(Addresses)), Warnings(Warnings),
|
||||
UnloadFunc(UnloadFunc) {
|
||||
if (this->Dwarf)
|
||||
Endianess = this->Dwarf->isLittleEndian() ? support::endianness::little
|
||||
: support::endianness::big;
|
||||
}
|
||||
UnloadCallbackTy UnloadFunc = nullptr);
|
||||
|
||||
/// Object file name.
|
||||
StringRef FileName;
|
||||
@ -51,9 +44,6 @@ public:
|
||||
/// Warnings for object file.
|
||||
const std::vector<std::string> &Warnings;
|
||||
|
||||
/// Endiannes of source DWARF information.
|
||||
support::endianness Endianess = support::endianness::little;
|
||||
|
||||
/// Callback to the module keeping object file to unload.
|
||||
UnloadCallbackTy UnloadFunc;
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace dwarflinker_parallel {
|
||||
|
||||
/// StringEntry keeps data of the string: the length, external offset
|
||||
/// and a string body which is placed right after StringEntry.
|
||||
using StringEntry = StringMapEntry<DwarfStringPoolEntry *>;
|
||||
using StringEntry = StringMapEntry<std::nullopt_t>;
|
||||
|
||||
class StringPoolEntryInfo {
|
||||
public:
|
||||
@ -64,6 +64,8 @@ public:
|
||||
|
||||
parallel::PerThreadBumpPtrAllocator &getAllocatorRef() { return Allocator; }
|
||||
|
||||
void clear() { Allocator.Reset(); }
|
||||
|
||||
private:
|
||||
parallel::PerThreadBumpPtrAllocator Allocator;
|
||||
};
|
||||
|
@ -1,88 +0,0 @@
|
||||
//===- StringTable.h --------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DWARFLINKERPARALLEL_STRINGTABLE_H
|
||||
#define LLVM_DWARFLINKERPARALLEL_STRINGTABLE_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/DWARFLinkerParallel/StringPool.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
using StringsVector = SmallVector<StringEntry *>;
|
||||
|
||||
/// This class prepares strings for emission into .debug_str table:
|
||||
/// translates string if necessary, assigns index and offset, keeps in order.
|
||||
class StringTable {
|
||||
public:
|
||||
StringTable(StringPool &Strings,
|
||||
std::function<StringRef(StringRef)> StringsTranslator)
|
||||
: Strings(Strings), StringsTranslator(StringsTranslator) {}
|
||||
~StringTable() {}
|
||||
|
||||
/// Add string to the vector of strings which should be emitted.
|
||||
/// Translate input string if neccessary, assign index and offset.
|
||||
/// \returns updated string entry.
|
||||
StringEntry *add(StringEntry *String) {
|
||||
// Translate string if necessary.
|
||||
if (StringsTranslator)
|
||||
String = Strings.insert(StringsTranslator(String->first())).first;
|
||||
|
||||
// Store String for emission and assign index and offset.
|
||||
if (String->getValue() == nullptr) {
|
||||
DwarfStringPoolEntry *NewEntry =
|
||||
Strings.getAllocatorRef().Allocate<DwarfStringPoolEntry>();
|
||||
|
||||
NewEntry->Symbol = nullptr;
|
||||
NewEntry->Index = StringEntriesForEmission.size();
|
||||
|
||||
if (StringEntriesForEmission.empty())
|
||||
NewEntry->Offset = 0;
|
||||
else {
|
||||
StringEntry *PrevString = StringEntriesForEmission.back();
|
||||
NewEntry->Offset =
|
||||
PrevString->getValue()->Offset + PrevString->getKeyLength() + 1;
|
||||
}
|
||||
|
||||
String->getValue() = NewEntry;
|
||||
StringEntriesForEmission.push_back(String);
|
||||
}
|
||||
|
||||
return String;
|
||||
}
|
||||
|
||||
/// Erase contents of StringsForEmission.
|
||||
void clear() { StringEntriesForEmission.clear(); }
|
||||
|
||||
/// Enumerate all strings in sequential order and call \p Handler for each
|
||||
/// string.
|
||||
void forEach(function_ref<void(DwarfStringPoolEntryRef)> Handler) const {
|
||||
for (const StringEntry *Entry : StringEntriesForEmission)
|
||||
Handler(*Entry);
|
||||
}
|
||||
|
||||
std::function<StringRef(StringRef)> getTranslator() {
|
||||
return StringsTranslator;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// List of strings for emission.
|
||||
StringsVector StringEntriesForEmission;
|
||||
|
||||
/// String pool for the translated strings.
|
||||
StringPool &Strings;
|
||||
|
||||
/// Translator for the strings.
|
||||
std::function<StringRef(StringRef)> StringsTranslator;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DWARFLINKERPARALLEL_STRINGTABLE_H
|
@ -22,6 +22,7 @@ class DwarfStreamer;
|
||||
|
||||
class DWARFDebugMacro {
|
||||
friend DwarfStreamer;
|
||||
friend dwarflinker_parallel::CompileUnit;
|
||||
|
||||
/// DWARFv5 section 6.3.1 Macro Information Header.
|
||||
enum HeaderFlagMask {
|
||||
|
@ -444,8 +444,10 @@ DWARFLinker::getVariableRelocAdjustment(AddressesMap &RelocMgr,
|
||||
|
||||
const DWARFExpression::Operation &Op = *It;
|
||||
switch (Op.getCode()) {
|
||||
case dwarf::DW_OP_const2u:
|
||||
case dwarf::DW_OP_const4u:
|
||||
case dwarf::DW_OP_const8u:
|
||||
case dwarf::DW_OP_const2s:
|
||||
case dwarf::DW_OP_const4s:
|
||||
case dwarf::DW_OP_const8s:
|
||||
if (NextIt == Expression.end() || !isTlsAddressCode(NextIt->getCode()))
|
||||
|
@ -97,8 +97,10 @@ void CompileUnit::markEverythingAsKept() {
|
||||
++NextIt;
|
||||
|
||||
switch (It->getCode()) {
|
||||
case dwarf::DW_OP_const2u:
|
||||
case dwarf::DW_OP_const4u:
|
||||
case dwarf::DW_OP_const8u:
|
||||
case dwarf::DW_OP_const2s:
|
||||
case dwarf::DW_OP_const4s:
|
||||
case dwarf::DW_OP_const8s:
|
||||
if (NextIt == Expression.end() ||
|
||||
|
92
llvm/lib/DWARFLinkerParallel/ArrayList.h
Normal file
92
llvm/lib/DWARFLinkerParallel/ArrayList.h
Normal file
@ -0,0 +1,92 @@
|
||||
//===- ArrayList.h ----------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_ARRAYLIST_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_ARRAYLIST_H
|
||||
|
||||
#include "DWARFLinkerGlobalData.h"
|
||||
#include "llvm/Support/PerThreadBumpPtrAllocator.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
/// This class is a simple list of T structures. It keeps elements as
|
||||
/// pre-allocated groups to save memory for each element's next pointer.
|
||||
/// It allocates internal data using specified per-thread BumpPtrAllocator.
|
||||
template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
|
||||
public:
|
||||
/// Copy specified \p Item into the list.
|
||||
T ¬eItem(const T &Item) {
|
||||
assert(Allocator != nullptr);
|
||||
|
||||
ItemsGroup *CurGroup = LastGroup;
|
||||
|
||||
if (CurGroup == nullptr) {
|
||||
// Allocate first ItemsGroup.
|
||||
LastGroup = Allocator->Allocate<ItemsGroup>();
|
||||
LastGroup->ItemsCount = 0;
|
||||
LastGroup->Next = nullptr;
|
||||
GroupsHead = LastGroup;
|
||||
CurGroup = LastGroup;
|
||||
}
|
||||
|
||||
if (CurGroup->ItemsCount == ItemsGroupSize) {
|
||||
// Allocate next ItemsGroup if current one is full.
|
||||
LastGroup = Allocator->Allocate<ItemsGroup>();
|
||||
LastGroup->ItemsCount = 0;
|
||||
LastGroup->Next = nullptr;
|
||||
CurGroup->Next = LastGroup;
|
||||
CurGroup = LastGroup;
|
||||
}
|
||||
|
||||
// Copy item into the next position inside current ItemsGroup.
|
||||
CurGroup->Items[CurGroup->ItemsCount] = Item;
|
||||
return CurGroup->Items[CurGroup->ItemsCount++];
|
||||
}
|
||||
|
||||
using ItemHandlerTy = function_ref<void(T &)>;
|
||||
|
||||
/// Enumerate all items and apply specified \p Handler to each.
|
||||
void forEach(ItemHandlerTy Handler) {
|
||||
for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr;
|
||||
CurGroup = CurGroup->Next) {
|
||||
for (size_t Idx = 0; Idx < CurGroup->ItemsCount; Idx++) {
|
||||
Handler(CurGroup->Items[Idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether list is empty.
|
||||
bool empty() { return GroupsHead == nullptr; }
|
||||
|
||||
/// Erase list.
|
||||
void erase() {
|
||||
GroupsHead = nullptr;
|
||||
LastGroup = nullptr;
|
||||
}
|
||||
|
||||
void setAllocator(parallel::PerThreadBumpPtrAllocator *Allocator) {
|
||||
this->Allocator = Allocator;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct ItemsGroup {
|
||||
std::array<T, ItemsGroupSize> Items;
|
||||
ItemsGroup *Next = nullptr;
|
||||
size_t ItemsCount = 0;
|
||||
};
|
||||
|
||||
ItemsGroup *GroupsHead = nullptr;
|
||||
ItemsGroup *LastGroup = nullptr;
|
||||
parallel::PerThreadBumpPtrAllocator *Allocator = nullptr;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_DWARFLINKERPARALLEL_ARRAYLIST_H
|
@ -1,7 +1,12 @@
|
||||
add_llvm_component_library(LLVMDWARFLinkerParallel
|
||||
DependencyTracker.cpp
|
||||
DIEAttributeCloner.cpp
|
||||
DWARFEmitterImpl.cpp
|
||||
DWARFFile.cpp
|
||||
DWARFLinker.cpp
|
||||
DWARFLinkerCompileUnit.cpp
|
||||
DWARFLinkerImpl.cpp
|
||||
DWARFLinkerUnit.cpp
|
||||
OutputSections.cpp
|
||||
StringPool.cpp
|
||||
|
||||
|
568
llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
Normal file
568
llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
Normal file
@ -0,0 +1,568 @@
|
||||
//=== DIEAttributeCloner.cpp ----------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DIEAttributeCloner.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
void DIEAttributeCloner::clone() {
|
||||
DWARFUnit &U = CU.getOrigUnit();
|
||||
|
||||
// Extract and clone every attribute.
|
||||
DWARFDataExtractor Data = U.getDebugInfoExtractor();
|
||||
|
||||
uint64_t Offset = InputDieEntry->getOffset();
|
||||
// Point to the next DIE (generally there is always at least a NULL
|
||||
// entry after the current one). If this is a lone
|
||||
// DW_TAG_compile_unit without any children, point to the next unit.
|
||||
uint64_t NextOffset = (InputDIEIdx + 1 < U.getNumDIEs())
|
||||
? U.getDIEAtIndex(InputDIEIdx + 1).getOffset()
|
||||
: U.getNextUnitOffset();
|
||||
|
||||
// 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.
|
||||
SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset));
|
||||
Data =
|
||||
DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
|
||||
|
||||
// Modify the copy with relocated addresses.
|
||||
CU.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset,
|
||||
Data.isLittleEndian());
|
||||
|
||||
// Reset the Offset to 0 as we will be working on the local copy of
|
||||
// the data.
|
||||
Offset = 0;
|
||||
|
||||
const auto *Abbrev = InputDieEntry->getAbbreviationDeclarationPtr();
|
||||
Offset += getULEB128Size(Abbrev->getCode());
|
||||
|
||||
// Set current output offset.
|
||||
AttrOutOffset = OutDIE->getOffset();
|
||||
for (const auto &AttrSpec : Abbrev->attributes()) {
|
||||
// Check whether current attribute should be skipped.
|
||||
if (shouldSkipAttribute(AttrSpec)) {
|
||||
DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
|
||||
U.getFormParams());
|
||||
continue;
|
||||
}
|
||||
|
||||
DWARFFormValue Val = AttrSpec.getFormValue();
|
||||
Val.extractValue(Data, &Offset, U.getFormParams(), &U);
|
||||
|
||||
// Clone current attribute.
|
||||
switch (AttrSpec.Form) {
|
||||
case dwarf::DW_FORM_strp:
|
||||
case dwarf::DW_FORM_line_strp:
|
||||
case dwarf::DW_FORM_string:
|
||||
case dwarf::DW_FORM_strx:
|
||||
case dwarf::DW_FORM_strx1:
|
||||
case dwarf::DW_FORM_strx2:
|
||||
case dwarf::DW_FORM_strx3:
|
||||
case dwarf::DW_FORM_strx4:
|
||||
AttrOutOffset += cloneStringAttr(Val, AttrSpec);
|
||||
break;
|
||||
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:
|
||||
case dwarf::DW_FORM_ref_udata:
|
||||
AttrOutOffset += cloneDieRefAttr(Val, AttrSpec);
|
||||
break;
|
||||
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:
|
||||
case dwarf::DW_FORM_rnglistx:
|
||||
case dwarf::DW_FORM_loclistx:
|
||||
case dwarf::DW_FORM_implicit_const:
|
||||
AttrOutOffset += cloneScalarAttr(Val, AttrSpec);
|
||||
break;
|
||||
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:
|
||||
AttrOutOffset += cloneBlockAttr(Val, AttrSpec);
|
||||
break;
|
||||
case dwarf::DW_FORM_addr:
|
||||
case dwarf::DW_FORM_addrx:
|
||||
case dwarf::DW_FORM_addrx1:
|
||||
case dwarf::DW_FORM_addrx2:
|
||||
case dwarf::DW_FORM_addrx3:
|
||||
case dwarf::DW_FORM_addrx4:
|
||||
AttrOutOffset += cloneAddressAttr(Val, AttrSpec);
|
||||
break;
|
||||
default:
|
||||
CU.warn("unsupported attribute form " +
|
||||
dwarf::FormEncodingString(AttrSpec.Form) +
|
||||
" in DieAttributeCloner::clone(). Dropping.",
|
||||
InputDieEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// We convert source strings into the indexed form for DWARFv5.
|
||||
// Check if original compile unit already has DW_AT_str_offsets_base
|
||||
// attribute.
|
||||
if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
|
||||
CU.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) {
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugOffsetPatch{
|
||||
AttrOutOffset,
|
||||
&CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets),
|
||||
true},
|
||||
PatchesOffsets);
|
||||
|
||||
AttrOutOffset += Generator
|
||||
.addScalarAttribute(dwarf::DW_AT_str_offsets_base,
|
||||
dwarf::DW_FORM_sec_offset,
|
||||
CU.getDebugStrOffsetsHeaderSize())
|
||||
.second;
|
||||
}
|
||||
}
|
||||
|
||||
bool DIEAttributeCloner::shouldSkipAttribute(
|
||||
DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) {
|
||||
switch (AttrSpec.Attr) {
|
||||
default:
|
||||
return false;
|
||||
case dwarf::DW_AT_low_pc:
|
||||
case dwarf::DW_AT_high_pc:
|
||||
case dwarf::DW_AT_ranges:
|
||||
if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
|
||||
return false;
|
||||
|
||||
// Skip address attribute if we are in function scope and function does not
|
||||
// reference live address.
|
||||
return CU.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
|
||||
!FuncAddressAdjustment.has_value();
|
||||
case dwarf::DW_AT_rnglists_base:
|
||||
// In case !Update the .debug_addr table is not generated/preserved.
|
||||
// Thus instead of DW_FORM_rnglistx the DW_FORM_sec_offset is used.
|
||||
// Since DW_AT_rnglists_base is used for only DW_FORM_rnglistx the
|
||||
// DW_AT_rnglists_base is removed.
|
||||
return !CU.getGlobalData().getOptions().UpdateIndexTablesOnly;
|
||||
case dwarf::DW_AT_loclists_base:
|
||||
// In case !Update the .debug_addr table is not generated/preserved.
|
||||
// Thus instead of DW_FORM_loclistx the DW_FORM_sec_offset is used.
|
||||
// Since DW_AT_loclists_base is used for only DW_FORM_loclistx the
|
||||
// DW_AT_loclists_base is removed.
|
||||
return !CU.getGlobalData().getOptions().UpdateIndexTablesOnly;
|
||||
case dwarf::DW_AT_location:
|
||||
case dwarf::DW_AT_frame_base:
|
||||
if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
|
||||
return false;
|
||||
|
||||
// When location expression contains an address: skip this attribute
|
||||
// if it does not reference live address.
|
||||
if (HasLocationExpressionAddress)
|
||||
return !VarAddressAdjustment.has_value();
|
||||
|
||||
// Skip location attribute if we are in function scope and function does not
|
||||
// reference live address.
|
||||
return CU.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
|
||||
!FuncAddressAdjustment.has_value();
|
||||
}
|
||||
}
|
||||
|
||||
size_t DIEAttributeCloner::cloneStringAttr(
|
||||
const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
|
||||
std::optional<const char *> String = dwarf::toString(Val);
|
||||
if (!String) {
|
||||
CU.warn("cann't read string attribute.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
StringEntry *StringInPool =
|
||||
CU.getGlobalData().getStringPool().insert(*String).first;
|
||||
if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugLineStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
|
||||
return Generator
|
||||
.addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_line_strp)
|
||||
.second;
|
||||
}
|
||||
|
||||
// Update attributes info.
|
||||
if (AttrSpec.Attr == dwarf::DW_AT_name)
|
||||
AttrInfo.Name = StringInPool;
|
||||
else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||
|
||||
AttrSpec.Attr == dwarf::DW_AT_linkage_name)
|
||||
AttrInfo.MangledName = StringInPool;
|
||||
|
||||
if (CU.getVersion() < 5) {
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
|
||||
|
||||
return Generator
|
||||
.addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_strp)
|
||||
.second;
|
||||
}
|
||||
|
||||
return Generator
|
||||
.addIndexedStringAttribute(AttrSpec.Attr, dwarf::DW_FORM_strx,
|
||||
CU.getDebugStrIndex(StringInPool))
|
||||
.second;
|
||||
}
|
||||
|
||||
size_t DIEAttributeCloner::cloneDieRefAttr(
|
||||
const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
|
||||
if (AttrSpec.Attr == dwarf::DW_AT_sibling)
|
||||
return 0;
|
||||
|
||||
std::optional<std::pair<CompileUnit *, uint32_t>> RefDiePair =
|
||||
CU.resolveDIEReference(Val);
|
||||
if (!RefDiePair) {
|
||||
// If the referenced DIE is not found, drop the attribute.
|
||||
CU.warn("cann't find referenced DIE.", InputDieEntry);
|
||||
return 0;
|
||||
}
|
||||
assert(RefDiePair->first->getStage() >= CompileUnit::Stage::Loaded);
|
||||
assert(RefDiePair->second != 0);
|
||||
|
||||
// Get output offset for referenced DIE.
|
||||
uint64_t OutDieOffset =
|
||||
RefDiePair->first->getDieOutOffset(RefDiePair->second);
|
||||
|
||||
// Examine whether referenced DIE is in current compile unit.
|
||||
bool IsLocal = CU.getUniqueID() == RefDiePair->first->getUniqueID();
|
||||
|
||||
// Set attribute form basing on the kind of referenced DIE(local or not?).
|
||||
dwarf::Form NewForm = IsLocal ? dwarf::DW_FORM_ref4 : dwarf::DW_FORM_ref_addr;
|
||||
|
||||
// Check whether current attribute references already cloned DIE inside
|
||||
// the same compilation unit. If true - write the already known offset value.
|
||||
if (IsLocal && (OutDieOffset != 0))
|
||||
return Generator.addScalarAttribute(AttrSpec.Attr, NewForm, OutDieOffset)
|
||||
.second;
|
||||
|
||||
// If offset value is not known at this point then create patch for the
|
||||
// reference value and write dummy value into the attribute.
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugDieRefPatch{AttrOutOffset, &CU, RefDiePair->first,
|
||||
RefDiePair->second},
|
||||
PatchesOffsets);
|
||||
return Generator.addScalarAttribute(AttrSpec.Attr, NewForm, 0xBADDEF).second;
|
||||
}
|
||||
|
||||
size_t DIEAttributeCloner::cloneScalarAttr(
|
||||
const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
|
||||
|
||||
// Create patches for attribute referencing other non invariant section.
|
||||
// Invariant section could not be updated here as this section and
|
||||
// reference to it do not change value in case --update.
|
||||
if (AttrSpec.Attr == dwarf::DW_AT_macro_info) {
|
||||
if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {
|
||||
const DWARFDebugMacro *Macro =
|
||||
CU.getContaingFile().Dwarf->getDebugMacinfo();
|
||||
if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset))
|
||||
return 0;
|
||||
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
|
||||
DebugSectionKind::DebugMacinfo)},
|
||||
PatchesOffsets);
|
||||
}
|
||||
} else if (AttrSpec.Attr == dwarf::DW_AT_macros) {
|
||||
if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {
|
||||
const DWARFDebugMacro *Macro =
|
||||
CU.getContaingFile().Dwarf->getDebugMacro();
|
||||
if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset))
|
||||
return 0;
|
||||
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
|
||||
DebugSectionKind::DebugMacro)},
|
||||
PatchesOffsets);
|
||||
}
|
||||
} else if (AttrSpec.Attr == dwarf::DW_AT_stmt_list) {
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
|
||||
DebugSectionKind::DebugLine)},
|
||||
PatchesOffsets);
|
||||
} else if (AttrSpec.Attr == dwarf::DW_AT_str_offsets_base) {
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugOffsetPatch{
|
||||
AttrOutOffset,
|
||||
&CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets),
|
||||
true},
|
||||
PatchesOffsets);
|
||||
|
||||
// Use size of .debug_str_offsets header as attribute value. The offset
|
||||
// to .debug_str_offsets would be added later while patching.
|
||||
AttrInfo.HasStringOffsetBaseAttr = true;
|
||||
return Generator
|
||||
.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form,
|
||||
CU.getDebugStrOffsetsHeaderSize())
|
||||
.second;
|
||||
}
|
||||
|
||||
uint64_t Value;
|
||||
if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly) {
|
||||
if (auto OptionalValue = Val.getAsUnsignedConstant())
|
||||
Value = *OptionalValue;
|
||||
else if (auto OptionalValue = Val.getAsSignedConstant())
|
||||
Value = *OptionalValue;
|
||||
else if (auto OptionalValue = Val.getAsSectionOffset())
|
||||
Value = *OptionalValue;
|
||||
else {
|
||||
CU.warn("unsupported scalar attribute form. Dropping attribute.",
|
||||
InputDieEntry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
|
||||
AttrInfo.IsDeclaration = true;
|
||||
|
||||
if (AttrSpec.Form == dwarf::DW_FORM_loclistx)
|
||||
return Generator.addLocListAttribute(AttrSpec.Attr, AttrSpec.Form, Value)
|
||||
.second;
|
||||
|
||||
return Generator.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, Value)
|
||||
.second;
|
||||
}
|
||||
|
||||
dwarf::Form ResultingForm = AttrSpec.Form;
|
||||
if (AttrSpec.Form == dwarf::DW_FORM_rnglistx) {
|
||||
// DWARFLinker does not generate .debug_addr table. Thus we need to change
|
||||
// all "addrx" related forms to "addr" version. Change DW_FORM_rnglistx
|
||||
// to DW_FORM_sec_offset here.
|
||||
std::optional<uint64_t> Index = Val.getAsSectionOffset();
|
||||
if (!Index) {
|
||||
CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
|
||||
return 0;
|
||||
}
|
||||
std::optional<uint64_t> Offset = CU.getOrigUnit().getRnglistOffset(*Index);
|
||||
if (!Offset) {
|
||||
CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Value = *Offset;
|
||||
ResultingForm = dwarf::DW_FORM_sec_offset;
|
||||
} else if (AttrSpec.Form == dwarf::DW_FORM_loclistx) {
|
||||
// DWARFLinker does not generate .debug_addr table. Thus we need to change
|
||||
// all "addrx" related forms to "addr" version. Change DW_FORM_loclistx
|
||||
// to DW_FORM_sec_offset here.
|
||||
std::optional<uint64_t> Index = Val.getAsSectionOffset();
|
||||
if (!Index) {
|
||||
CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
|
||||
return 0;
|
||||
}
|
||||
std::optional<uint64_t> Offset = CU.getOrigUnit().getLoclistOffset(*Index);
|
||||
if (!Offset) {
|
||||
CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Value = *Offset;
|
||||
ResultingForm = dwarf::DW_FORM_sec_offset;
|
||||
} else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
|
||||
InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
|
||||
std::optional<uint64_t> LowPC = CU.getLowPc();
|
||||
if (!LowPC)
|
||||
return 0;
|
||||
// Dwarf >= 4 high_pc is an size, not an address.
|
||||
Value = CU.getHighPc() - *LowPC;
|
||||
} else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
|
||||
Value = *Val.getAsSectionOffset();
|
||||
else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
|
||||
Value = *Val.getAsSignedConstant();
|
||||
else if (auto OptionalValue = Val.getAsUnsignedConstant())
|
||||
Value = *OptionalValue;
|
||||
else {
|
||||
CU.warn("unsupported scalar attribute form. Dropping attribute.",
|
||||
InputDieEntry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (AttrSpec.Attr == dwarf::DW_AT_ranges ||
|
||||
AttrSpec.Attr == dwarf::DW_AT_start_scope) {
|
||||
// Create patch for the range offset value.
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugRangePatch{{AttrOutOffset},
|
||||
InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit},
|
||||
PatchesOffsets);
|
||||
AttrInfo.HasRanges = true;
|
||||
} else if (DWARFAttribute::mayHaveLocationList(AttrSpec.Attr) &&
|
||||
dwarf::doesFormBelongToClass(AttrSpec.Form,
|
||||
DWARFFormValue::FC_SectionOffset,
|
||||
CU.getOrigUnit().getVersion())) {
|
||||
int64_t AddrAdjustmentValue = 0;
|
||||
if (VarAddressAdjustment)
|
||||
AddrAdjustmentValue = *VarAddressAdjustment;
|
||||
else if (FuncAddressAdjustment)
|
||||
AddrAdjustmentValue = *FuncAddressAdjustment;
|
||||
|
||||
// Create patch for the location offset value.
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugLocPatch{{AttrOutOffset}, AddrAdjustmentValue}, PatchesOffsets);
|
||||
} else if (AttrSpec.Attr == dwarf::DW_AT_addr_base) {
|
||||
DebugInfoOutputSection.notePatchWithOffsetUpdate(
|
||||
DebugOffsetPatch{
|
||||
AttrOutOffset,
|
||||
&CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr),
|
||||
true},
|
||||
PatchesOffsets);
|
||||
|
||||
// Use size of .debug_addr header as attribute value. The offset to
|
||||
// .debug_addr would be added later while patching.
|
||||
return Generator
|
||||
.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form,
|
||||
CU.getDebugAddrHeaderSize())
|
||||
.second;
|
||||
} else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
|
||||
AttrInfo.IsDeclaration = true;
|
||||
|
||||
return Generator.addScalarAttribute(AttrSpec.Attr, ResultingForm, Value)
|
||||
.second;
|
||||
}
|
||||
|
||||
size_t DIEAttributeCloner::cloneBlockAttr(
|
||||
const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
|
||||
|
||||
size_t NumberOfPatchesAtStart = PatchesOffsets.size();
|
||||
|
||||
// If the block is a DWARF Expression, clone it into the temporary
|
||||
// buffer using cloneExpression(), otherwise copy the data directly.
|
||||
SmallVector<uint8_t, 32> Buffer;
|
||||
ArrayRef<uint8_t> Bytes = *Val.getAsBlock();
|
||||
if (DWARFAttribute::mayHaveLocationExpr(AttrSpec.Attr) &&
|
||||
(Val.isFormClass(DWARFFormValue::FC_Block) ||
|
||||
Val.isFormClass(DWARFFormValue::FC_Exprloc))) {
|
||||
DWARFUnit &OrigUnit = CU.getOrigUnit();
|
||||
DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()),
|
||||
OrigUnit.isLittleEndian(),
|
||||
OrigUnit.getAddressByteSize());
|
||||
DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(),
|
||||
OrigUnit.getFormParams().Format);
|
||||
|
||||
CU.cloneDieAttrExpression(Expr, Buffer, DebugInfoOutputSection,
|
||||
VarAddressAdjustment, PatchesOffsets);
|
||||
Bytes = Buffer;
|
||||
}
|
||||
|
||||
// The expression location data might be updated and exceed the original size.
|
||||
// Check whether the new data fits into the original form.
|
||||
dwarf::Form ResultForm = AttrSpec.Form;
|
||||
if ((ResultForm == dwarf::DW_FORM_block1 && Bytes.size() > UINT8_MAX) ||
|
||||
(ResultForm == dwarf::DW_FORM_block2 && Bytes.size() > UINT16_MAX) ||
|
||||
(ResultForm == dwarf::DW_FORM_block4 && Bytes.size() > UINT32_MAX))
|
||||
ResultForm = dwarf::DW_FORM_block;
|
||||
|
||||
size_t FinalAttributeSize;
|
||||
if (AttrSpec.Form == dwarf::DW_FORM_exprloc)
|
||||
FinalAttributeSize =
|
||||
Generator.addLocationAttribute(AttrSpec.Attr, ResultForm, Bytes).second;
|
||||
else
|
||||
FinalAttributeSize =
|
||||
Generator.addBlockAttribute(AttrSpec.Attr, ResultForm, Bytes).second;
|
||||
|
||||
// Update patches offsets with the size of length field for Bytes.
|
||||
for (size_t Idx = NumberOfPatchesAtStart; Idx < PatchesOffsets.size();
|
||||
Idx++) {
|
||||
assert(FinalAttributeSize > Bytes.size());
|
||||
*PatchesOffsets[Idx] +=
|
||||
(AttrOutOffset + (FinalAttributeSize - Bytes.size()));
|
||||
}
|
||||
|
||||
return FinalAttributeSize;
|
||||
}
|
||||
|
||||
size_t DIEAttributeCloner::cloneAddressAttr(
|
||||
const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
|
||||
if (AttrSpec.Attr == dwarf::DW_AT_low_pc)
|
||||
AttrInfo.HasLowPc = true;
|
||||
|
||||
if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
|
||||
return Generator
|
||||
.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, Val.getRawUValue())
|
||||
.second;
|
||||
|
||||
// Cloned Die may have address attributes relocated to a
|
||||
// totally unrelated value. This can happen:
|
||||
// - 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
|
||||
// independently by the linker).
|
||||
// - If address relocated in an inline_subprogram that happens at the
|
||||
// beginning of its inlining function.
|
||||
// To avoid above cases and to not apply relocation twice (in
|
||||
// applyValidRelocs and here), read address attribute from InputDIE and apply
|
||||
// Info.PCOffset here.
|
||||
|
||||
std::optional<DWARFFormValue> AddrAttribute =
|
||||
CU.find(InputDieEntry, AttrSpec.Attr);
|
||||
if (!AddrAttribute)
|
||||
llvm_unreachable("Cann't find attribute");
|
||||
|
||||
std::optional<uint64_t> Addr = AddrAttribute->getAsAddress();
|
||||
if (!Addr) {
|
||||
CU.warn("cann't read address attribute value.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
|
||||
AttrSpec.Attr == dwarf::DW_AT_low_pc) {
|
||||
if (std::optional<uint64_t> LowPC = CU.getLowPc())
|
||||
Addr = *LowPC;
|
||||
else
|
||||
return 0;
|
||||
} else if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
|
||||
AttrSpec.Attr == dwarf::DW_AT_high_pc) {
|
||||
if (uint64_t HighPc = CU.getHighPc())
|
||||
Addr = HighPc;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
if (VarAddressAdjustment)
|
||||
*Addr += *VarAddressAdjustment;
|
||||
else if (FuncAddressAdjustment)
|
||||
*Addr += *FuncAddressAdjustment;
|
||||
}
|
||||
|
||||
if (AttrSpec.Form == dwarf::DW_FORM_addr) {
|
||||
return Generator.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, *Addr)
|
||||
.second;
|
||||
}
|
||||
|
||||
return Generator
|
||||
.addScalarAttribute(AttrSpec.Attr, dwarf::Form::DW_FORM_addrx,
|
||||
CU.getDebugAddrIndex(*Addr))
|
||||
.second;
|
||||
}
|
||||
|
||||
unsigned DIEAttributeCloner::finalizeAbbreviations(bool HasChildrenToClone) {
|
||||
size_t SizeOfAbbreviationNumber =
|
||||
Generator.finalizeAbbreviations(HasChildrenToClone);
|
||||
|
||||
// We need to update patches offsets after we know the size of the
|
||||
// abbreviation number.
|
||||
updatePatchesWithSizeOfAbbreviationNumber(SizeOfAbbreviationNumber);
|
||||
|
||||
// Add the size of the abbreviation number to the output offset.
|
||||
AttrOutOffset += SizeOfAbbreviationNumber;
|
||||
|
||||
return AttrOutOffset;
|
||||
}
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // namespace llvm
|
147
llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
Normal file
147
llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
Normal file
@ -0,0 +1,147 @@
|
||||
//===- DIEAttributeCloner.h -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DIEATTRIBUTECLONER_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_DIEATTRIBUTECLONER_H
|
||||
|
||||
#include "ArrayList.h"
|
||||
#include "DIEGenerator.h"
|
||||
#include "DWARFLinkerCompileUnit.h"
|
||||
#include "DWARFLinkerGlobalData.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
/// This class creates clones of input DIE attributes.
|
||||
/// It enumerates attributes of input DIE, creates clone for each
|
||||
/// attribute, adds cloned attribute to the output DIE.
|
||||
class DIEAttributeCloner {
|
||||
public:
|
||||
DIEAttributeCloner(DIE *OutDIE, CompileUnit &CU,
|
||||
const DWARFDebugInfoEntry *InputDieEntry,
|
||||
DIEGenerator &Generator,
|
||||
std::optional<int64_t> FuncAddressAdjustment,
|
||||
std::optional<int64_t> VarAddressAdjustment,
|
||||
bool HasLocationExpressionAddress)
|
||||
: OutDIE(OutDIE), CU(CU),
|
||||
DebugInfoOutputSection(
|
||||
CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)),
|
||||
InputDieEntry(InputDieEntry), Generator(Generator),
|
||||
FuncAddressAdjustment(FuncAddressAdjustment),
|
||||
VarAddressAdjustment(VarAddressAdjustment),
|
||||
HasLocationExpressionAddress(HasLocationExpressionAddress) {
|
||||
InputDIEIdx = CU.getDIEIndex(InputDieEntry);
|
||||
}
|
||||
|
||||
/// Clone attributes of input DIE.
|
||||
void clone();
|
||||
|
||||
/// Create abbreviations for the output DIE after all attributes are cloned.
|
||||
unsigned finalizeAbbreviations(bool HasChildrenToClone);
|
||||
|
||||
/// Information gathered and exchanged between the various
|
||||
/// clone*Attr helpers about the attributes of a particular DIE.
|
||||
///
|
||||
/// Cannot be used concurrently.
|
||||
struct AttributesInfo {
|
||||
/// Names.
|
||||
StringEntry *Name = nullptr;
|
||||
StringEntry *MangledName = nullptr;
|
||||
StringEntry *NameWithoutTemplate = nullptr;
|
||||
|
||||
/// Does the DIE have a low_pc attribute?
|
||||
bool HasLowPc = false;
|
||||
|
||||
/// Is this DIE only a declaration?
|
||||
bool IsDeclaration = false;
|
||||
|
||||
/// Does the DIE have a ranges attribute?
|
||||
bool HasRanges = false;
|
||||
|
||||
/// Does the DIE have a string offset attribute?
|
||||
bool HasStringOffsetBaseAttr = false;
|
||||
};
|
||||
|
||||
AttributesInfo AttrInfo;
|
||||
|
||||
protected:
|
||||
/// Clone string attribute.
|
||||
size_t
|
||||
cloneStringAttr(const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec);
|
||||
|
||||
/// Clone attribute referencing another DIE.
|
||||
size_t
|
||||
cloneDieRefAttr(const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec);
|
||||
|
||||
/// Clone scalar attribute.
|
||||
size_t
|
||||
cloneScalarAttr(const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec);
|
||||
|
||||
/// Clone block or exprloc attribute.
|
||||
size_t
|
||||
cloneBlockAttr(const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec);
|
||||
|
||||
/// Clone address attribute.
|
||||
size_t
|
||||
cloneAddressAttr(const DWARFFormValue &Val,
|
||||
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec);
|
||||
|
||||
/// Returns true if attribute should be skipped.
|
||||
bool
|
||||
shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec);
|
||||
|
||||
/// Update patches offsets with the size of abbreviation number.
|
||||
void
|
||||
updatePatchesWithSizeOfAbbreviationNumber(unsigned SizeOfAbbreviationNumber) {
|
||||
for (uint64_t *OffsetPtr : PatchesOffsets)
|
||||
*OffsetPtr += SizeOfAbbreviationNumber;
|
||||
}
|
||||
|
||||
/// Output DIE.
|
||||
DIE *OutDIE = nullptr;
|
||||
|
||||
/// Compile unit for the output DIE.
|
||||
CompileUnit &CU;
|
||||
|
||||
/// .debug_info section descriptor.
|
||||
SectionDescriptor &DebugInfoOutputSection;
|
||||
|
||||
/// Input DIE entry.
|
||||
const DWARFDebugInfoEntry *InputDieEntry = nullptr;
|
||||
|
||||
/// Input DIE index.
|
||||
uint32_t InputDIEIdx = 0;
|
||||
|
||||
/// Output DIE generator.
|
||||
DIEGenerator &Generator;
|
||||
|
||||
/// Relocation adjustment for the function address ranges.
|
||||
std::optional<int64_t> FuncAddressAdjustment;
|
||||
|
||||
/// Relocation adjustment for the variable locations.
|
||||
std::optional<int64_t> VarAddressAdjustment;
|
||||
|
||||
/// Indicates whether InputDieEntry has an location attribute
|
||||
/// containg address expression.
|
||||
bool HasLocationExpressionAddress = false;
|
||||
|
||||
/// Output offset after all attributes.
|
||||
unsigned AttrOutOffset = 0;
|
||||
|
||||
/// Patches for the cloned attributes.
|
||||
OffsetsPtrVector PatchesOffsets;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_DWARFLINKERPARALLEL_DIEATTRIBUTECLONER_H
|
165
llvm/lib/DWARFLinkerParallel/DIEGenerator.h
Normal file
165
llvm/lib/DWARFLinkerParallel/DIEGenerator.h
Normal file
@ -0,0 +1,165 @@
|
||||
//===- DIEGenerator.h -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DIEGENERATOR_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_DIEGENERATOR_H
|
||||
|
||||
#include "DWARFLinkerGlobalData.h"
|
||||
#include "DWARFLinkerUnit.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
/// This class is a helper to create output DIE tree.
|
||||
class DIEGenerator {
|
||||
public:
|
||||
DIEGenerator(BumpPtrAllocator &Allocator, DwarfUnit &CU)
|
||||
: Allocator(Allocator), CU(CU) {}
|
||||
|
||||
/// Creates a DIE of specified tag \p DieTag and \p OutOffset.
|
||||
DIE *createDIE(dwarf::Tag DieTag, uint32_t OutOffset) {
|
||||
OutputDIE = DIE::get(Allocator, DieTag);
|
||||
|
||||
OutputDIE->setOffset(OutOffset);
|
||||
|
||||
return OutputDIE;
|
||||
}
|
||||
|
||||
/// Adds a specified \p Child to the current DIE.
|
||||
void addChild(DIE *Child) {
|
||||
assert(Child != nullptr);
|
||||
assert(OutputDIE != nullptr);
|
||||
|
||||
OutputDIE->addChild(Child);
|
||||
}
|
||||
|
||||
/// Adds specified scalar attribute to the current DIE.
|
||||
std::pair<DIEValue &, size_t> addScalarAttribute(dwarf::Attribute Attr,
|
||||
dwarf::Form AttrForm,
|
||||
uint64_t Value) {
|
||||
return addAttribute(Attr, AttrForm, DIEInteger(Value));
|
||||
}
|
||||
|
||||
/// Adds specified location attribute to the current DIE.
|
||||
std::pair<DIEValue &, size_t> addLocationAttribute(dwarf::Attribute Attr,
|
||||
dwarf::Form AttrForm,
|
||||
ArrayRef<uint8_t> Bytes) {
|
||||
DIELoc *Loc = new (Allocator) DIELoc;
|
||||
for (auto Byte : Bytes)
|
||||
static_cast<DIEValueList *>(Loc)->addValue(
|
||||
Allocator, static_cast<dwarf::Attribute>(0), dwarf::DW_FORM_data1,
|
||||
DIEInteger(Byte));
|
||||
Loc->setSize(Bytes.size());
|
||||
|
||||
return addAttribute(Attr, AttrForm, Loc);
|
||||
}
|
||||
|
||||
/// Adds specified block or exprloc attribute to the current DIE.
|
||||
std::pair<DIEValue &, size_t> addBlockAttribute(dwarf::Attribute Attr,
|
||||
dwarf::Form AttrForm,
|
||||
ArrayRef<uint8_t> Bytes) {
|
||||
// The expression location data might be updated and exceed the original
|
||||
// size. Check whether the new data fits into the original form.
|
||||
assert((AttrForm == dwarf::DW_FORM_block) ||
|
||||
(AttrForm == dwarf::DW_FORM_exprloc) ||
|
||||
(AttrForm == dwarf::DW_FORM_block1 && Bytes.size() <= UINT8_MAX) ||
|
||||
(AttrForm == dwarf::DW_FORM_block2 && Bytes.size() <= UINT16_MAX) ||
|
||||
(AttrForm == dwarf::DW_FORM_block4 && Bytes.size() <= UINT32_MAX));
|
||||
|
||||
DIEBlock *Block = new (Allocator) DIEBlock;
|
||||
for (auto Byte : Bytes)
|
||||
static_cast<DIEValueList *>(Block)->addValue(
|
||||
Allocator, static_cast<dwarf::Attribute>(0), dwarf::DW_FORM_data1,
|
||||
DIEInteger(Byte));
|
||||
Block->setSize(Bytes.size());
|
||||
|
||||
return addAttribute(Attr, AttrForm, Block);
|
||||
}
|
||||
|
||||
/// Adds specified location list attribute to the current DIE.
|
||||
std::pair<DIEValue &, size_t> addLocListAttribute(dwarf::Attribute Attr,
|
||||
dwarf::Form AttrForm,
|
||||
uint64_t Value) {
|
||||
return addAttribute(Attr, AttrForm, DIELocList(Value));
|
||||
}
|
||||
|
||||
/// Adds indexed string attribute.
|
||||
std::pair<DIEValue &, size_t> addIndexedStringAttribute(dwarf::Attribute Attr,
|
||||
dwarf::Form AttrForm,
|
||||
uint64_t Idx) {
|
||||
assert(AttrForm == dwarf::DW_FORM_strx);
|
||||
return addAttribute(Attr, AttrForm, DIEInteger(Idx));
|
||||
}
|
||||
|
||||
/// Adds string attribute with dummy offset to the current DIE.
|
||||
std::pair<DIEValue &, size_t>
|
||||
addStringPlaceholderAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm) {
|
||||
assert(AttrForm == dwarf::DW_FORM_strp ||
|
||||
AttrForm == dwarf::DW_FORM_line_strp);
|
||||
return addAttribute(Attr, AttrForm, DIEInteger(0xBADDEF));
|
||||
}
|
||||
|
||||
/// Adds inplace string attribute to the current DIE.
|
||||
std::pair<DIEValue &, size_t> addInplaceString(dwarf::Attribute Attr,
|
||||
StringRef String) {
|
||||
DIEBlock *Block = new (Allocator) DIEBlock;
|
||||
for (auto Byte : String.bytes())
|
||||
static_cast<DIEValueList *>(Block)->addValue(
|
||||
Allocator, static_cast<dwarf::Attribute>(0), dwarf::DW_FORM_data1,
|
||||
DIEInteger(Byte));
|
||||
|
||||
static_cast<DIEValueList *>(Block)->addValue(
|
||||
Allocator, static_cast<dwarf::Attribute>(0), dwarf::DW_FORM_data1,
|
||||
DIEInteger(0));
|
||||
Block->setSize(String.size() + 1);
|
||||
|
||||
DIEValue &ValueRef =
|
||||
*OutputDIE->addValue(Allocator, Attr, dwarf::DW_FORM_string, Block);
|
||||
return std::pair<DIEValue &, size_t>(ValueRef, String.size() + 1);
|
||||
}
|
||||
|
||||
/// Creates appreviations for the current DIE. Returns value of
|
||||
/// abbreviation number.
|
||||
size_t finalizeAbbreviations(bool CHILDREN_yes) {
|
||||
// Create abbreviations for output DIE.
|
||||
DIEAbbrev NewAbbrev = OutputDIE->generateAbbrev();
|
||||
if (CHILDREN_yes)
|
||||
NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);
|
||||
|
||||
CU.assignAbbrev(NewAbbrev);
|
||||
OutputDIE->setAbbrevNumber(NewAbbrev.getNumber());
|
||||
|
||||
return getULEB128Size(OutputDIE->getAbbrevNumber());
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
std::pair<DIEValue &, size_t> addAttribute(dwarf::Attribute Attr,
|
||||
dwarf::Form AttrForm, T &&Value) {
|
||||
DIEValue &ValueRef =
|
||||
*OutputDIE->addValue(Allocator, Attr, AttrForm, std::forward<T>(Value));
|
||||
unsigned ValueSize = ValueRef.sizeOf(CU.getFormParams());
|
||||
return std::pair<DIEValue &, size_t>(ValueRef, ValueSize);
|
||||
}
|
||||
|
||||
// Allocator for output DIEs and values.
|
||||
BumpPtrAllocator &Allocator;
|
||||
|
||||
// Unit for the output DIE.
|
||||
DwarfUnit &CU;
|
||||
|
||||
// OutputDIE.
|
||||
DIE *OutputDIE = nullptr;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_DWARFLINKERPARALLEL_DIEGENERATOR_H
|
@ -114,18 +114,115 @@ Error DwarfEmitterImpl::init(Triple TheTriple,
|
||||
TripleName.c_str());
|
||||
Asm->setDwarfUsesRelocationsAcrossSections(false);
|
||||
|
||||
RangesSectionSize = 0;
|
||||
RngListsSectionSize = 0;
|
||||
LocSectionSize = 0;
|
||||
LocListsSectionSize = 0;
|
||||
LineSectionSize = 0;
|
||||
FrameSectionSize = 0;
|
||||
DebugInfoSectionSize = 0;
|
||||
MacInfoSectionSize = 0;
|
||||
MacroSectionSize = 0;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void DwarfEmitterImpl::emitSwiftAST(StringRef Buffer) {
|
||||
MCSection *SwiftASTSection = MOFI->getDwarfSwiftASTSection();
|
||||
SwiftASTSection->setAlignment(Align(32));
|
||||
MS->switchSection(SwiftASTSection);
|
||||
MS->emitBytes(Buffer);
|
||||
}
|
||||
|
||||
/// Emit the swift reflection section stored in \p Buffer.
|
||||
void DwarfEmitterImpl::emitSwiftReflectionSection(
|
||||
llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind,
|
||||
StringRef Buffer, uint32_t Alignment, uint32_t) {
|
||||
MCSection *ReflectionSection =
|
||||
MOFI->getSwift5ReflectionSection(ReflSectionKind);
|
||||
if (ReflectionSection == nullptr)
|
||||
return;
|
||||
ReflectionSection->setAlignment(Align(Alignment));
|
||||
MS->switchSection(ReflectionSection);
|
||||
MS->emitBytes(Buffer);
|
||||
}
|
||||
|
||||
void DwarfEmitterImpl::emitSectionContents(StringRef SecData,
|
||||
StringRef SecName) {
|
||||
if (SecData.empty())
|
||||
return;
|
||||
|
||||
if (MCSection *Section = switchSection(SecName)) {
|
||||
MS->switchSection(Section);
|
||||
|
||||
MS->emitBytes(SecData);
|
||||
}
|
||||
}
|
||||
|
||||
MCSection *DwarfEmitterImpl::switchSection(StringRef SecName) {
|
||||
return StringSwitch<MCSection *>(SecName)
|
||||
.Case("debug_info", MC->getObjectFileInfo()->getDwarfInfoSection())
|
||||
.Case("debug_abbrev", MC->getObjectFileInfo()->getDwarfAbbrevSection())
|
||||
.Case("debug_line", MC->getObjectFileInfo()->getDwarfLineSection())
|
||||
.Case("debug_loc", MC->getObjectFileInfo()->getDwarfLocSection())
|
||||
.Case("debug_ranges", MC->getObjectFileInfo()->getDwarfRangesSection())
|
||||
.Case("debug_frame", MC->getObjectFileInfo()->getDwarfFrameSection())
|
||||
.Case("debug_aranges", MC->getObjectFileInfo()->getDwarfARangesSection())
|
||||
.Case("debug_rnglists",
|
||||
MC->getObjectFileInfo()->getDwarfRnglistsSection())
|
||||
.Case("debug_loclists",
|
||||
MC->getObjectFileInfo()->getDwarfLoclistsSection())
|
||||
.Case("debug_macro", MC->getObjectFileInfo()->getDwarfMacroSection())
|
||||
.Case("debug_macinfo", MC->getObjectFileInfo()->getDwarfMacinfoSection())
|
||||
.Case("debug_addr", MC->getObjectFileInfo()->getDwarfAddrSection())
|
||||
.Case("debug_str", MC->getObjectFileInfo()->getDwarfStrSection())
|
||||
.Case("debug_line_str", MC->getObjectFileInfo()->getDwarfLineStrSection())
|
||||
.Case("debug_str_offsets",
|
||||
MC->getObjectFileInfo()->getDwarfStrOffSection())
|
||||
.Default(nullptr);
|
||||
}
|
||||
|
||||
MCSymbol *DwarfEmitterImpl::emitTempSym(StringRef SecName, StringRef SymName) {
|
||||
if (MCSection *Section = switchSection(SecName)) {
|
||||
MS->switchSection(Section);
|
||||
MCSymbol *Res = Asm->createTempSymbol(SymName);
|
||||
Asm->OutStreamer->emitLabel(Res);
|
||||
return Res;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DwarfEmitterImpl::emitAbbrevs(
|
||||
const SmallVector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
|
||||
unsigned DwarfVersion) {
|
||||
MS->switchSection(MOFI->getDwarfAbbrevSection());
|
||||
MC->setDwarfVersion(DwarfVersion);
|
||||
Asm->emitDwarfAbbrevs(Abbrevs);
|
||||
}
|
||||
|
||||
void DwarfEmitterImpl::emitCompileUnitHeader(DwarfUnit &Unit) {
|
||||
MS->switchSection(MOFI->getDwarfInfoSection());
|
||||
MC->setDwarfVersion(Unit.getVersion());
|
||||
|
||||
// Emit size of content not including length itself. The size has already
|
||||
// been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to
|
||||
// account for the length field.
|
||||
Asm->emitInt32(Unit.getDebugInfoHeaderSize() +
|
||||
Unit.getOutUnitDIE()->getSize() - 4);
|
||||
Asm->emitInt16(Unit.getVersion());
|
||||
|
||||
if (Unit.getVersion() >= 5) {
|
||||
Asm->emitInt8(dwarf::DW_UT_compile);
|
||||
Asm->emitInt8(Unit.getFormParams().AddrSize);
|
||||
// Proper offset to the abbreviations table will be set later.
|
||||
Asm->emitInt32(0);
|
||||
DebugInfoSectionSize += 12;
|
||||
} else {
|
||||
// Proper offset to the abbreviations table will be set later.
|
||||
Asm->emitInt32(0);
|
||||
Asm->emitInt8(Unit.getFormParams().AddrSize);
|
||||
DebugInfoSectionSize += 11;
|
||||
}
|
||||
}
|
||||
|
||||
void DwarfEmitterImpl::emitDIE(DIE &Die) {
|
||||
MS->switchSection(MOFI->getDwarfInfoSection());
|
||||
Asm->emitDwarfDIE(Die);
|
||||
DebugInfoSectionSize += Die.getSize();
|
||||
}
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // namespace llvm
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "llvm/CodeGen/AccelTable.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||
#include "llvm/DWARFLinkerParallel/StringTable.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
@ -40,186 +39,66 @@ class DWARFDebugMacro;
|
||||
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
struct UnitStartSymbol {
|
||||
unsigned UnitID = 0;
|
||||
MCSymbol *Symbol = 0;
|
||||
};
|
||||
using UnitStartSymbolsTy = SmallVector<UnitStartSymbol>;
|
||||
using Offset2UnitMapTy = DenseMap<uint64_t, CompileUnit *>;
|
||||
|
||||
struct RangeAttrPatch;
|
||||
struct LocAttrPatch;
|
||||
|
||||
/// The Dwarf emission logic.
|
||||
///
|
||||
/// All interactions with the MC layer that is used to build the debug
|
||||
/// information binary representation are handled in this class.
|
||||
/// This class emits DWARF data to the output stream. It emits already
|
||||
/// generated section data and specific data, which could not be generated
|
||||
/// by CompileUnit.
|
||||
class DwarfEmitterImpl : public ExtraDwarfEmitter {
|
||||
public:
|
||||
DwarfEmitterImpl(DWARFLinker::OutputFileType OutFileType,
|
||||
raw_pwrite_stream &OutFile,
|
||||
std::function<StringRef(StringRef Input)> Translator,
|
||||
DWARFLinker::MessageHandlerTy Warning)
|
||||
: OutFile(OutFile), OutFileType(OutFileType), Translator(Translator),
|
||||
WarningHandler(Warning) {}
|
||||
raw_pwrite_stream &OutFile)
|
||||
: OutFile(OutFile), OutFileType(OutFileType) {}
|
||||
|
||||
/// Initialize AsmPrinter data.
|
||||
Error init(Triple TheTriple, StringRef Swift5ReflectionSegmentName);
|
||||
|
||||
/// Returns triple of output stream.
|
||||
const Triple &getTargetTriple() { return MC->getTargetTriple(); }
|
||||
|
||||
/// Dump the file to the disk.
|
||||
void finish() override { MS->finish(); }
|
||||
|
||||
/// Returns AsmPrinter.
|
||||
AsmPrinter &getAsmPrinter() const override { return *Asm; }
|
||||
|
||||
/// Set the current output section to debug_info and change
|
||||
/// the MC Dwarf version to \p DwarfVersion.
|
||||
void switchToDebugInfoSection(unsigned DwarfVersion) {}
|
||||
|
||||
/// Emit the swift_ast section stored in \p Buffer.
|
||||
void emitSwiftAST(StringRef Buffer) override {}
|
||||
void emitSwiftAST(StringRef Buffer) override;
|
||||
|
||||
/// Emit the swift reflection section stored in \p Buffer.
|
||||
void emitSwiftReflectionSection(
|
||||
llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind,
|
||||
StringRef Buffer, uint32_t Alignment, uint32_t Size) override {}
|
||||
StringRef Buffer, uint32_t Alignment, uint32_t) override;
|
||||
|
||||
void emitPaperTrailWarningsDie(DIE &Die) {}
|
||||
/// Emit specified section data.
|
||||
void emitSectionContents(StringRef SecData, StringRef SecName) override;
|
||||
|
||||
void emitSectionContents(StringRef SecData, StringRef SecName) override {}
|
||||
|
||||
MCSymbol *emitTempSym(StringRef SecName, StringRef SymName) override {
|
||||
return nullptr;
|
||||
}
|
||||
/// Emit temporary symbol.
|
||||
MCSymbol *emitTempSym(StringRef SecName, StringRef SymName) override;
|
||||
|
||||
/// Emit abbreviations.
|
||||
void emitAbbrevs(const SmallVector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
|
||||
unsigned DwarfVersion) {}
|
||||
unsigned DwarfVersion);
|
||||
|
||||
void emitStrings(const StringTable &Strings) {}
|
||||
/// Emit compile unit header.
|
||||
void emitCompileUnitHeader(DwarfUnit &Unit);
|
||||
|
||||
void emitLineStrings(const StringTable &Strings) {}
|
||||
|
||||
void emitDebugNames(AccelTable<DWARF5AccelTableStaticData> &,
|
||||
UnitStartSymbolsTy &UnitOffsets) {}
|
||||
|
||||
void emitAppleNamespaces(AccelTable<AppleAccelTableStaticOffsetData> &) {}
|
||||
|
||||
void emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> &) {}
|
||||
|
||||
void emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> &) {}
|
||||
|
||||
void emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &) {}
|
||||
|
||||
MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void emitDwarfDebugRangeListFragment(const CompileUnit &Unit,
|
||||
const AddressRanges &LinkedRanges,
|
||||
RangeAttrPatch &Patch) {}
|
||||
|
||||
void emitDwarfDebugRangeListFooter(const CompileUnit &Unit,
|
||||
MCSymbol *EndLabel) {}
|
||||
|
||||
MCSymbol *emitDwarfDebugLocListHeader(const CompileUnit &Unit) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void emitDwarfDebugLocListFragment(
|
||||
const CompileUnit &Unit,
|
||||
const DWARFLocationExpressionsVector &LinkedLocationExpression,
|
||||
LocAttrPatch &Patch) {}
|
||||
|
||||
void emitDwarfDebugLocListFooter(const CompileUnit &Unit,
|
||||
MCSymbol *EndLabel) {}
|
||||
|
||||
void emitDwarfDebugArangesTable(const CompileUnit &Unit,
|
||||
const AddressRanges &LinkedRanges) {}
|
||||
|
||||
void translateLineTable(DataExtractor LineData, uint64_t Offset) {}
|
||||
|
||||
void emitLineTableForUnit(MCDwarfLineTableParams Params,
|
||||
StringRef PrologueBytes, unsigned MinInstLength,
|
||||
std::vector<DWARFDebugLine::Row> &Rows,
|
||||
unsigned AdddressSize) {}
|
||||
|
||||
void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable,
|
||||
const CompileUnit &Unit, const StringTable &Strings,
|
||||
const StringTable &LineTableStrings) {}
|
||||
|
||||
void emitPubNamesForUnit(const CompileUnit &Unit) {}
|
||||
|
||||
void emitPubTypesForUnit(const CompileUnit &Unit) {}
|
||||
|
||||
void emitCIE(StringRef CIEBytes) {}
|
||||
|
||||
void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint64_t Address,
|
||||
StringRef Bytes) {}
|
||||
|
||||
void emitCompileUnitHeader(CompileUnit &Unit, unsigned DwarfVersion) {}
|
||||
|
||||
void emitDIE(DIE &Die) {}
|
||||
|
||||
void emitMacroTables(DWARFContext *Context,
|
||||
const Offset2UnitMapTy &UnitMacroMap,
|
||||
StringTable &Strings) {}
|
||||
|
||||
/// Returns size of generated .debug_line section.
|
||||
uint64_t getDebugLineSectionSize() const { return LineSectionSize; }
|
||||
|
||||
/// Returns size of generated .debug_frame section.
|
||||
uint64_t getDebugFrameSectionSize() const { return FrameSectionSize; }
|
||||
|
||||
/// Returns size of generated .debug_ranges section.
|
||||
uint64_t getDebugRangesSectionSize() const { return RangesSectionSize; }
|
||||
|
||||
/// Returns size of generated .debug_rnglists section.
|
||||
uint64_t getDebugRngListsSectionSize() const { return RngListsSectionSize; }
|
||||
/// Emit DIE recursively.
|
||||
void emitDIE(DIE &Die);
|
||||
|
||||
/// Returns size of generated .debug_info section.
|
||||
uint64_t getDebugInfoSectionSize() const { return DebugInfoSectionSize; }
|
||||
|
||||
/// Returns size of generated .debug_macinfo section.
|
||||
uint64_t getDebugMacInfoSectionSize() const { return MacInfoSectionSize; }
|
||||
|
||||
/// Returns size of generated .debug_macro section.
|
||||
uint64_t getDebugMacroSectionSize() const { return MacroSectionSize; }
|
||||
|
||||
/// Returns size of generated .debug_loc section.
|
||||
uint64_t getDebugLocSectionSize() const { return LocSectionSize; }
|
||||
|
||||
/// Returns size of generated .debug_loclists section.
|
||||
uint64_t getDebugLocListsSectionSize() const { return LocListsSectionSize; }
|
||||
|
||||
private:
|
||||
inline void warn(const Twine &Warning, StringRef Context = "") {
|
||||
if (WarningHandler)
|
||||
WarningHandler(Warning, Context, nullptr);
|
||||
}
|
||||
// Enumerate all string patches and write them into the destination section.
|
||||
// Order of patches is the same as in original input file. To avoid emitting
|
||||
// the same string twice we accumulate NextOffset value. Thus if string
|
||||
// offset smaller than NextOffset value then the patch is skipped (as that
|
||||
// string was emitted earlier).
|
||||
template <typename PatchTy>
|
||||
void emitStringsImpl(ArrayList<PatchTy> &StringPatches,
|
||||
const StringEntryToDwarfStringPoolEntryMap &Strings,
|
||||
uint64_t &NextOffset, MCSection *OutSection);
|
||||
|
||||
void emitMacroTableImpl(const DWARFDebugMacro *MacroTable,
|
||||
const Offset2UnitMapTy &UnitMacroMap,
|
||||
StringPool &StringPool, uint64_t &OutOffset) {}
|
||||
|
||||
/// Emit piece of .debug_ranges for \p LinkedRanges.
|
||||
void emitDwarfDebugRangesTableFragment(const CompileUnit &Unit,
|
||||
const AddressRanges &LinkedRanges,
|
||||
RangeAttrPatch &Patch) {}
|
||||
|
||||
/// Emit piece of .debug_rnglists for \p LinkedRanges.
|
||||
void emitDwarfDebugRngListsTableFragment(const CompileUnit &Unit,
|
||||
const AddressRanges &LinkedRanges,
|
||||
RangeAttrPatch &Patch) {}
|
||||
|
||||
/// Emit piece of .debug_loc for \p LinkedRanges.
|
||||
void emitDwarfDebugLocTableFragment(
|
||||
const CompileUnit &Unit,
|
||||
const DWARFLocationExpressionsVector &LinkedLocationExpression,
|
||||
LocAttrPatch &Patch) {}
|
||||
|
||||
/// Emit piece of .debug_loclists for \p LinkedRanges.
|
||||
void emitDwarfDebugLocListsTableFragment(
|
||||
const CompileUnit &Unit,
|
||||
const DWARFLocationExpressionsVector &LinkedLocationExpression,
|
||||
LocAttrPatch &Patch) {}
|
||||
MCSection *switchSection(StringRef SecName);
|
||||
|
||||
/// \defgroup MCObjects MC layer objects constructed by the streamer
|
||||
/// @{
|
||||
@ -240,32 +119,8 @@ private:
|
||||
/// The output file we stream the linked Dwarf to.
|
||||
raw_pwrite_stream &OutFile;
|
||||
DWARFLinker::OutputFileType OutFileType = DWARFLinker::OutputFileType::Object;
|
||||
std::function<StringRef(StringRef Input)> Translator;
|
||||
|
||||
uint64_t RangesSectionSize = 0;
|
||||
uint64_t RngListsSectionSize = 0;
|
||||
uint64_t LocSectionSize = 0;
|
||||
uint64_t LocListsSectionSize = 0;
|
||||
uint64_t LineSectionSize = 0;
|
||||
uint64_t FrameSectionSize = 0;
|
||||
uint64_t DebugInfoSectionSize = 0;
|
||||
uint64_t MacInfoSectionSize = 0;
|
||||
uint64_t MacroSectionSize = 0;
|
||||
|
||||
/// Keep track of emitted CUs and their Unique ID.
|
||||
struct EmittedUnit {
|
||||
unsigned ID;
|
||||
MCSymbol *LabelBegin;
|
||||
};
|
||||
std::vector<EmittedUnit> EmittedUnitsTy;
|
||||
|
||||
/// Emit the pubnames or pubtypes section contribution for \p
|
||||
/// Unit into \p Sec. The data is provided in \p Names.
|
||||
void emitPubSectionForUnit(MCSection *Sec, StringRef Name,
|
||||
const CompileUnit &Unit,
|
||||
const std::vector<CompileUnit::AccelInfo> &Names);
|
||||
|
||||
DWARFLinker::MessageHandlerTy WarningHandler = nullptr;
|
||||
};
|
||||
|
||||
} // end namespace dwarflinker_parallel
|
||||
|
18
llvm/lib/DWARFLinkerParallel/DWARFFile.cpp
Normal file
18
llvm/lib/DWARFLinkerParallel/DWARFFile.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
//=== DWARFFile.cpp -------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DWARFLinkerParallel/DWARFFile.h"
|
||||
#include "DWARFLinkerGlobalData.h"
|
||||
|
||||
llvm::dwarflinker_parallel::DWARFFile::DWARFFile(
|
||||
StringRef Name, std::unique_ptr<DWARFContext> Dwarf,
|
||||
std::unique_ptr<AddressesMap> Addresses,
|
||||
const std::vector<std::string> &Warnings,
|
||||
DWARFFile::UnloadCallbackTy UnloadFunc)
|
||||
: FileName(Name), Dwarf(std::move(Dwarf)), Addresses(std::move(Addresses)),
|
||||
Warnings(Warnings), UnloadFunc(UnloadFunc) {}
|
1402
llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
Normal file
1402
llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,54 +10,334 @@
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
|
||||
|
||||
#include "DWARFLinkerUnit.h"
|
||||
#include "IndexedValuesMap.h"
|
||||
#include "llvm/DWARFLinkerParallel/DWARFFile.h"
|
||||
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||
#include <optional>
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
struct LinkContext;
|
||||
class DWARFFile;
|
||||
using OffsetToUnitTy = function_ref<CompileUnit *(uint64_t Offset)>;
|
||||
|
||||
/// Stores all information related to a compile unit, be it in its original
|
||||
/// instance of the object file or its brand new cloned and generated DIE tree.
|
||||
class CompileUnit : public DwarfUnit {
|
||||
public:
|
||||
CompileUnit(LinkContext &, unsigned ID, StringRef ClangModuleName,
|
||||
DWARFFile &File,
|
||||
DWARFLinker::SwiftInterfacesMapTy *,
|
||||
UnitMessageHandlerTy WarningHandler)
|
||||
: DwarfUnit(ID, ClangModuleName, WarningHandler), ContaingFile(File) {
|
||||
FormParams.Version = 4;
|
||||
FormParams.Format = dwarf::DWARF32;
|
||||
FormParams.AddrSize = 4;
|
||||
UnitName = ContaingFile.FileName;
|
||||
/// The stages of new compile unit processing.
|
||||
enum class Stage : uint8_t {
|
||||
/// Created, linked with input DWARF file.
|
||||
CreatedNotLoaded = 0,
|
||||
|
||||
/// Input DWARF is loaded.
|
||||
Loaded,
|
||||
|
||||
/// Input DWARF is analysed(DIEs pointing to the real code section are
|
||||
/// discovered, type names are assigned if ODR is requested).
|
||||
LivenessAnalysisDone,
|
||||
|
||||
/// Output DWARF is generated.
|
||||
Cloned,
|
||||
|
||||
/// Offsets inside patch records are updated.
|
||||
PatchesUpdated,
|
||||
|
||||
/// Resources(Input DWARF, Output DWARF tree) are released.
|
||||
Cleaned,
|
||||
};
|
||||
|
||||
CompileUnit(LinkingGlobalData &GlobalData, unsigned ID,
|
||||
StringRef ClangModuleName, DWARFFile &File,
|
||||
OffsetToUnitTy UnitFromOffset)
|
||||
: DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
|
||||
getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded) {
|
||||
UnitName = File.FileName;
|
||||
}
|
||||
|
||||
CompileUnit(LinkContext &, DWARFUnit &OrigUnit, unsigned ID,
|
||||
CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit, unsigned ID,
|
||||
StringRef ClangModuleName, DWARFFile &File,
|
||||
UnitMessageHandlerTy WarningHandler)
|
||||
: DwarfUnit(ID, ClangModuleName, WarningHandler),
|
||||
ContaingFile(File), OrigUnit(&OrigUnit) {
|
||||
OffsetToUnitTy UnitFromOffset)
|
||||
: DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
|
||||
OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset),
|
||||
Stage(Stage::CreatedNotLoaded) {
|
||||
DWARFDie CUDie = OrigUnit.getUnitDIE();
|
||||
if (!CUDie)
|
||||
return;
|
||||
|
||||
if (File.Dwarf)
|
||||
Endianess = File.Dwarf->isLittleEndian() ? support::endianness::little
|
||||
: support::endianness::big;
|
||||
|
||||
FormParams.Version = OrigUnit.getVersion();
|
||||
FormParams.Format = dwarf::DWARF32;
|
||||
FormParams.AddrSize = OrigUnit.getAddressByteSize();
|
||||
setOutputFormat(OrigUnit);
|
||||
|
||||
Language = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language), 0);
|
||||
|
||||
UnitName = ContaingFile.FileName;
|
||||
if (const char *CUName = CUDie.getName(DINameKind::ShortName))
|
||||
UnitName = CUName;
|
||||
else
|
||||
UnitName = File.FileName;
|
||||
SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str();
|
||||
}
|
||||
|
||||
/// Returns stage of overall processing.
|
||||
Stage getStage() const { return Stage; }
|
||||
|
||||
/// Set stage of overall processing.
|
||||
void setStage(Stage Stage) { this->Stage = Stage; }
|
||||
|
||||
/// Loads unit line table.
|
||||
void loadLineTable();
|
||||
|
||||
/// Returns name of the file for the \p FileIdx
|
||||
/// from the unit`s line table.
|
||||
StringEntry *getFileName(unsigned FileIdx, StringPool &GlobalStrings);
|
||||
|
||||
/// Returns DWARFFile containing this compile unit.
|
||||
const DWARFFile &getContaingFile() const { return File; }
|
||||
|
||||
/// Load DIEs of input compilation unit. \returns true if input DIEs
|
||||
/// successfully loaded.
|
||||
bool loadInputDIEs();
|
||||
|
||||
/// Reset compile units data(results of liveness analysis, clonning)
|
||||
/// if current stage greater than Stage::Loaded. We need to reset data
|
||||
/// as we are going to repeat stages.
|
||||
void maybeResetToLoadedStage();
|
||||
|
||||
/// Collect references to parseable Swift interfaces in imported
|
||||
/// DW_TAG_module blocks.
|
||||
void analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry);
|
||||
|
||||
/// Navigate DWARF tree and set die properties.
|
||||
void analyzeDWARFStructure() {
|
||||
analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false, false);
|
||||
}
|
||||
|
||||
/// Cleanup unneeded resources after compile unit is cloned.
|
||||
void cleanupDataAfterClonning();
|
||||
|
||||
/// After cloning stage the output DIEs offsets are deallocated.
|
||||
/// This method copies output offsets for referenced DIEs into DIEs patches.
|
||||
void updateDieRefPatchesWithClonedOffsets();
|
||||
|
||||
/// Kinds of placement for the output die.
|
||||
enum DieOutputPlacement : uint8_t {
|
||||
NotSet = 0,
|
||||
|
||||
/// Corresponding DIE goes to the type table only.
|
||||
/// NOTE: Not used yet.
|
||||
TypeTable = 1,
|
||||
|
||||
/// Corresponding DIE goes to the plain dwarf only.
|
||||
PlainDwarf = 2,
|
||||
|
||||
/// Corresponding DIE goes to type table and to plain dwarf.
|
||||
/// NOTE: Not used yet.
|
||||
Both = 3,
|
||||
|
||||
/// Corresponding DIE needs to examine parent to determine
|
||||
/// the point of placement.
|
||||
/// NOTE: Not used yet.
|
||||
Parent = 4
|
||||
};
|
||||
|
||||
/// Information gathered about source DIEs.
|
||||
struct DIEInfo {
|
||||
DIEInfo() = default;
|
||||
DIEInfo(const DIEInfo &Other) { Flags = Other.Flags.load(); }
|
||||
DIEInfo &operator=(const DIEInfo &Other) {
|
||||
Flags = Other.Flags.load();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Data member keeping various flags.
|
||||
std::atomic<uint16_t> Flags = {0};
|
||||
|
||||
/// \returns Placement kind for the corresponding die.
|
||||
DieOutputPlacement getPlacement() const {
|
||||
return DieOutputPlacement(Flags & 0x7);
|
||||
}
|
||||
|
||||
/// Sets Placement kind for the corresponding die.
|
||||
void setPlacement(DieOutputPlacement Placement) {
|
||||
auto InputData = Flags.load();
|
||||
while (!Flags.compare_exchange_weak(InputData,
|
||||
((InputData & ~0x7) | Placement))) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Unsets Placement kind for the corresponding die.
|
||||
void unsetPlacement() {
|
||||
auto InputData = Flags.load();
|
||||
while (!Flags.compare_exchange_weak(InputData, (InputData & ~0x7))) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets Placement kind for the corresponding die.
|
||||
bool setPlacementIfUnset(DieOutputPlacement Placement) {
|
||||
auto InputData = Flags.load();
|
||||
if ((InputData & 0x7) == NotSet)
|
||||
if (Flags.compare_exchange_weak(InputData, (InputData | Placement)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define SINGLE_FLAG_METHODS_SET(Name, Value) \
|
||||
bool get##Name() const { return Flags & Value; } \
|
||||
void set##Name() { \
|
||||
auto InputData = Flags.load(); \
|
||||
while (!Flags.compare_exchange_weak(InputData, InputData | Value)) { \
|
||||
} \
|
||||
} \
|
||||
void unset##Name() { \
|
||||
auto InputData = Flags.load(); \
|
||||
while (!Flags.compare_exchange_weak(InputData, InputData & ~Value)) { \
|
||||
} \
|
||||
}
|
||||
|
||||
/// DIE is a part of the linked output.
|
||||
SINGLE_FLAG_METHODS_SET(Keep, 0x08)
|
||||
|
||||
/// DIE has children which are part of the linked output.
|
||||
SINGLE_FLAG_METHODS_SET(KeepChildren, 0x10)
|
||||
|
||||
/// DIE is referenced by other DIE.
|
||||
SINGLE_FLAG_METHODS_SET(ReferrencedBy, 0x20)
|
||||
|
||||
/// DIE is in module scope.
|
||||
SINGLE_FLAG_METHODS_SET(IsInMouduleScope, 0x40)
|
||||
|
||||
/// DIE is in function scope.
|
||||
SINGLE_FLAG_METHODS_SET(IsInFunctionScope, 0x80)
|
||||
|
||||
void unsetFlagsWhichSetDuringLiveAnalysis() {
|
||||
auto InputData = Flags.load();
|
||||
while (!Flags.compare_exchange_weak(
|
||||
InputData, InputData & ~(0x7 | 0x8 | 0x10 | 0x20))) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Erase all flags.
|
||||
void eraseData() { Flags = 0; }
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump();
|
||||
#endif
|
||||
};
|
||||
|
||||
/// \defgroup Group of functions returning DIE info.
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// \p Idx index of the DIE.
|
||||
/// \returns DieInfo descriptor.
|
||||
DIEInfo &getDIEInfo(unsigned Idx) { return DieInfoArray[Idx]; }
|
||||
|
||||
/// \p Idx index of the DIE.
|
||||
/// \returns DieInfo descriptor.
|
||||
const DIEInfo &getDIEInfo(unsigned Idx) const { return DieInfoArray[Idx]; }
|
||||
|
||||
/// \p Idx index of the DIE.
|
||||
/// \returns DieInfo descriptor.
|
||||
DIEInfo &getDIEInfo(const DWARFDebugInfoEntry *Entry) {
|
||||
return DieInfoArray[getOrigUnit().getDIEIndex(Entry)];
|
||||
}
|
||||
|
||||
/// \p Idx index of the DIE.
|
||||
/// \returns DieInfo descriptor.
|
||||
const DIEInfo &getDIEInfo(const DWARFDebugInfoEntry *Entry) const {
|
||||
return DieInfoArray[getOrigUnit().getDIEIndex(Entry)];
|
||||
}
|
||||
|
||||
/// \p Die
|
||||
/// \returns PlainDieInfo descriptor.
|
||||
DIEInfo &getDIEInfo(const DWARFDie &Die) {
|
||||
return DieInfoArray[getOrigUnit().getDIEIndex(Die)];
|
||||
}
|
||||
|
||||
/// \p Die
|
||||
/// \returns PlainDieInfo descriptor.
|
||||
const DIEInfo &getDIEInfo(const DWARFDie &Die) const {
|
||||
return DieInfoArray[getOrigUnit().getDIEIndex(Die)];
|
||||
}
|
||||
|
||||
/// \p Idx index of the DIE.
|
||||
/// \returns DieInfo descriptor.
|
||||
uint64_t getDieOutOffset(uint32_t Idx) {
|
||||
return reinterpret_cast<std::atomic<uint64_t> *>(&OutDieOffsetArray[Idx])
|
||||
->load();
|
||||
}
|
||||
|
||||
/// \p Idx index of the DIE.
|
||||
/// \returns DieInfo descriptor.
|
||||
void rememberDieOutOffset(uint32_t Idx, uint64_t Offset) {
|
||||
reinterpret_cast<std::atomic<uint64_t> *>(&OutDieOffsetArray[Idx])
|
||||
->store(Offset);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// Returns value of DW_AT_low_pc attribute.
|
||||
std::optional<uint64_t> getLowPc() const { return LowPc; }
|
||||
|
||||
/// Returns value of DW_AT_high_pc attribute.
|
||||
uint64_t getHighPc() const { return HighPc; }
|
||||
|
||||
/// Returns true if there is a label corresponding to the specified \p Addr.
|
||||
bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); }
|
||||
|
||||
/// Add the low_pc of a label that is relocated by applying
|
||||
/// offset \p PCOffset.
|
||||
void addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset);
|
||||
|
||||
/// Resolve the DIE attribute reference that has been extracted in \p
|
||||
/// RefValue. The resulting DIE might be in another CompileUnit.
|
||||
/// \returns referenced die and corresponding compilation unit.
|
||||
/// compilation unit is null if reference could not be resolved.
|
||||
std::optional<std::pair<CompileUnit *, uint32_t>>
|
||||
resolveDIEReference(const DWARFFormValue &RefValue);
|
||||
/// @}
|
||||
|
||||
/// Add a function range [\p LowPC, \p HighPC) that is relocated by applying
|
||||
/// offset \p PCOffset.
|
||||
void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset);
|
||||
|
||||
/// Returns function ranges of this unit.
|
||||
const RangesTy &getFunctionRanges() const { return Ranges; }
|
||||
|
||||
/// Clone and emit this compilation unit.
|
||||
Error cloneAndEmit(std::optional<Triple> TargetTriple);
|
||||
|
||||
/// Clone and emit debug locations(.debug_loc/.debug_loclists).
|
||||
Error cloneAndEmitDebugLocations();
|
||||
|
||||
/// Clone and emit ranges.
|
||||
Error cloneAndEmitRanges();
|
||||
|
||||
/// Clone and emit debug macros(.debug_macinfo/.debug_macro).
|
||||
Error cloneAndEmitDebugMacro();
|
||||
|
||||
// Clone input DIE entry.
|
||||
DIE *cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset,
|
||||
std::optional<int64_t> FuncAddressAdjustment,
|
||||
std::optional<int64_t> VarAddressAdjustment,
|
||||
BumpPtrAllocator &Allocator);
|
||||
|
||||
// Clone and emit line table.
|
||||
Error cloneAndEmitLineTable(Triple &TargetTriple);
|
||||
|
||||
/// Clone attribute location axpression.
|
||||
void cloneDieAttrExpression(const DWARFExpression &InputExpression,
|
||||
SmallVectorImpl<uint8_t> &OutputExpression,
|
||||
SectionDescriptor &Section,
|
||||
std::optional<int64_t> VarAddressAdjustment,
|
||||
OffsetsPtrVector &PatchesOffsets);
|
||||
|
||||
/// Returns index(inside .debug_addr) of an address.
|
||||
uint64_t getDebugAddrIndex(uint64_t Addr) {
|
||||
return DebugAddrIndexMap.getValueIndex(Addr);
|
||||
}
|
||||
|
||||
/// Returns index(inside .debug_str_offsets) of specified string.
|
||||
uint64_t getDebugStrIndex(const StringEntry *String) {
|
||||
return DebugStringIndexMap.getValueIndex(String);
|
||||
}
|
||||
|
||||
/// \defgroup Helper methods to access OrigUnit.
|
||||
///
|
||||
/// @{
|
||||
@ -142,12 +422,144 @@ public:
|
||||
|
||||
/// @}
|
||||
|
||||
/// \defgroup Methods used for reporting warnings and errors:
|
||||
///
|
||||
/// @{
|
||||
|
||||
void warn(const Twine &Warning, const DWARFDie *DIE = nullptr) {
|
||||
GlobalData.warn(Warning, getUnitName(), DIE);
|
||||
}
|
||||
|
||||
void warn(Error Warning, const DWARFDie *DIE = nullptr) {
|
||||
handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
|
||||
GlobalData.warn(Info.message(), getUnitName(), DIE);
|
||||
});
|
||||
}
|
||||
|
||||
void warn(const Twine &Warning, const DWARFDebugInfoEntry *DieEntry) {
|
||||
if (DieEntry != nullptr) {
|
||||
DWARFDie DIE(&getOrigUnit(), DieEntry);
|
||||
GlobalData.warn(Warning, getUnitName(), &DIE);
|
||||
return;
|
||||
}
|
||||
|
||||
GlobalData.warn(Warning, getUnitName());
|
||||
}
|
||||
|
||||
void error(const Twine &Err, const DWARFDie *DIE = nullptr) {
|
||||
GlobalData.warn(Err, getUnitName(), DIE);
|
||||
}
|
||||
|
||||
void error(Error Err, const DWARFDie *DIE = nullptr) {
|
||||
handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
|
||||
GlobalData.error(Info.message(), getUnitName(), DIE);
|
||||
});
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
/// Navigate DWARF tree recursively and set die properties.
|
||||
void analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry,
|
||||
bool IsInModule, bool IsInFunction);
|
||||
|
||||
struct LinkedLocationExpressionsWithOffsetPatches {
|
||||
DWARFLocationExpression Expression;
|
||||
OffsetsPtrVector Patches;
|
||||
};
|
||||
using LinkedLocationExpressionsVector =
|
||||
SmallVector<LinkedLocationExpressionsWithOffsetPatches>;
|
||||
|
||||
/// Emit debug locations.
|
||||
void emitLocations(DebugSectionKind LocationSectionKind);
|
||||
|
||||
/// Emit location list header.
|
||||
uint64_t emitLocListHeader(SectionDescriptor &OutLocationSection);
|
||||
|
||||
/// Emit location list fragment.
|
||||
uint64_t emitLocListFragment(
|
||||
const LinkedLocationExpressionsVector &LinkedLocationExpression,
|
||||
SectionDescriptor &OutLocationSection);
|
||||
|
||||
/// Emit the .debug_addr section fragment for current unit.
|
||||
Error emitDebugAddrSection();
|
||||
|
||||
/// Emit the .debug_str_offsets section for current unit.
|
||||
Error emitDebugStringOffsetSection();
|
||||
|
||||
/// Emit .debug_aranges.
|
||||
void emitAranges(AddressRanges &LinkedFunctionRanges);
|
||||
|
||||
/// Clone and emit .debug_ranges/.debug_rnglists.
|
||||
void cloneAndEmitRangeList(DebugSectionKind RngSectionKind,
|
||||
AddressRanges &LinkedFunctionRanges);
|
||||
|
||||
/// Emit range list header.
|
||||
uint64_t emitRangeListHeader(SectionDescriptor &OutRangeSection);
|
||||
|
||||
/// Emit range list fragment.
|
||||
void emitRangeListFragment(const AddressRanges &LinkedRanges,
|
||||
SectionDescriptor &OutRangeSection);
|
||||
|
||||
/// Insert the new line info sequence \p Seq into the current
|
||||
/// set of already linked line info \p Rows.
|
||||
void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
|
||||
std::vector<DWARFDebugLine::Row> &Rows);
|
||||
|
||||
/// Emits body for both macro sections.
|
||||
void emitMacroTableImpl(const DWARFDebugMacro *MacroTable,
|
||||
uint64_t OffsetToMacroTable, bool hasDWARFv5Header);
|
||||
|
||||
/// DWARFFile containing this compile unit.
|
||||
DWARFFile &ContaingFile;
|
||||
DWARFFile &File;
|
||||
|
||||
/// Pointer to the paired compile unit from the input DWARF.
|
||||
DWARFUnit *OrigUnit = nullptr;
|
||||
|
||||
/// Line table for this unit.
|
||||
const DWARFDebugLine::LineTable *LineTablePtr = nullptr;
|
||||
|
||||
/// Cached resolved paths from the line table.
|
||||
/// The key is <UniqueUnitID, FileIdx>.
|
||||
using ResolvedPathsMap = DenseMap<unsigned, StringEntry *>;
|
||||
ResolvedPathsMap ResolvedFullPaths;
|
||||
StringMap<StringEntry *> ResolvedParentPaths;
|
||||
|
||||
/// This field instructs compile unit to store DIE name with stripped
|
||||
/// template parameters into the accelerator table.
|
||||
bool CanStripTemplateName = false;
|
||||
|
||||
/// Maps an address into the index inside .debug_addr section.
|
||||
IndexedValuesMap<uint64_t> DebugAddrIndexMap;
|
||||
|
||||
/// Maps a string into the index inside .debug_str_offsets section.
|
||||
IndexedValuesMap<const StringEntry *> DebugStringIndexMap;
|
||||
|
||||
/// \defgroup Data Members accessed asinchroniously.
|
||||
///
|
||||
/// @{
|
||||
OffsetToUnitTy getUnitFromOffset;
|
||||
|
||||
std::optional<uint64_t> LowPc;
|
||||
uint64_t HighPc = 0;
|
||||
|
||||
/// The ranges in that map are the PC ranges for functions in this unit,
|
||||
/// associated with the PC offset to apply to the addresses to get
|
||||
/// the linked address.
|
||||
RangesTy Ranges;
|
||||
std::mutex RangesMutex;
|
||||
|
||||
/// The DW_AT_low_pc of each DW_TAG_label.
|
||||
SmallDenseMap<uint64_t, uint64_t, 1> Labels;
|
||||
std::mutex LabelsMutex;
|
||||
|
||||
/// This field keeps current stage of overall compile unit processing.
|
||||
std::atomic<Stage> Stage;
|
||||
|
||||
/// DIE info indexed by DIE index.
|
||||
SmallVector<DIEInfo> DieInfoArray;
|
||||
SmallVector<uint64_t> OutDieOffsetArray;
|
||||
/// @}
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
|
159
llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
Normal file
159
llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
Normal file
@ -0,0 +1,159 @@
|
||||
//===- DWARFLinkerGlobalData.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H
|
||||
|
||||
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||
#include "llvm/DWARFLinkerParallel/StringPool.h"
|
||||
#include "llvm/Support/PerThreadBumpPtrAllocator.h"
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class DWARFDie;
|
||||
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
using TranslatorFuncTy = std::function<StringRef(StringRef)>;
|
||||
using MessageHandlerTy = std::function<void(
|
||||
const Twine &Warning, StringRef Context, const DWARFDie *DIE)>;
|
||||
|
||||
/// linking options
|
||||
struct DWARFLinkerOptions {
|
||||
/// DWARF version for the output.
|
||||
uint16_t TargetDWARFVersion = 0;
|
||||
|
||||
/// Generate processing log to the standard output.
|
||||
bool Verbose = false;
|
||||
|
||||
/// Print statistics.
|
||||
bool Statistics = false;
|
||||
|
||||
/// Verify the input DWARF.
|
||||
bool VerifyInputDWARF = false;
|
||||
|
||||
/// Do not emit output.
|
||||
bool NoOutput = false;
|
||||
|
||||
/// Do not unique types according to ODR
|
||||
bool NoODR = false;
|
||||
|
||||
/// Update index tables.
|
||||
bool UpdateIndexTablesOnly = false;
|
||||
|
||||
/// Whether we want a static variable to force us to keep its enclosing
|
||||
/// function.
|
||||
bool KeepFunctionForStatic = false;
|
||||
|
||||
/// Allow to generate valid, but non deterministic output.
|
||||
bool AllowNonDeterministicOutput = false;
|
||||
|
||||
/// Number of threads.
|
||||
unsigned Threads = 1;
|
||||
|
||||
/// The accelerator table kinds
|
||||
SmallVector<DWARFLinker::AccelTableKind, 1> AccelTables;
|
||||
|
||||
/// Prepend path for the clang modules.
|
||||
std::string PrependPath;
|
||||
|
||||
/// input verification handler(it might be called asynchronously).
|
||||
DWARFLinker::InputVerificationHandlerTy InputVerificationHandler = nullptr;
|
||||
|
||||
/// A list of all .swiftinterface files referenced by the debug
|
||||
/// info, mapping Module name to path on disk. The entries need to
|
||||
/// be uniqued and sorted and there are only few entries expected
|
||||
/// per compile unit, which is why this is a std::map.
|
||||
/// this is dsymutil specific fag.
|
||||
///
|
||||
/// (it might be called asynchronously).
|
||||
DWARFLinker::SwiftInterfacesMapTy *ParseableSwiftInterfaces = nullptr;
|
||||
|
||||
/// A list of remappings to apply to file paths.
|
||||
///
|
||||
/// (it might be called asynchronously).
|
||||
DWARFLinker::ObjectPrefixMapTy *ObjectPrefixMap = nullptr;
|
||||
};
|
||||
|
||||
class DWARFLinkerImpl;
|
||||
|
||||
/// This class keeps data and services common for the whole linking process.
|
||||
class LinkingGlobalData {
|
||||
friend DWARFLinkerImpl;
|
||||
|
||||
public:
|
||||
/// Returns global per-thread allocator.
|
||||
parallel::PerThreadBumpPtrAllocator &getAllocator() { return Allocator; }
|
||||
|
||||
/// Returns global string pool.
|
||||
StringPool &getStringPool() { return Strings; }
|
||||
|
||||
/// Set translation function.
|
||||
void setTranslator(TranslatorFuncTy Translator) {
|
||||
this->Translator = Translator;
|
||||
}
|
||||
|
||||
/// Translate specified string.
|
||||
StringRef translateString(StringRef String) {
|
||||
if (Translator)
|
||||
return Translator(String);
|
||||
|
||||
return String;
|
||||
}
|
||||
|
||||
/// Returns linking options.
|
||||
const DWARFLinkerOptions &getOptions() const { return Options; }
|
||||
|
||||
/// Set warning handler.
|
||||
void setWarningHandler(MessageHandlerTy Handler) { WarningHandler = Handler; }
|
||||
|
||||
/// Set error handler.
|
||||
void setErrorHandler(MessageHandlerTy Handler) { ErrorHandler = Handler; }
|
||||
|
||||
/// Report warning.
|
||||
void warn(const Twine &Warning, StringRef Context,
|
||||
const DWARFDie *DIE = nullptr) {
|
||||
if (WarningHandler)
|
||||
(WarningHandler)(Warning, Context, DIE);
|
||||
}
|
||||
|
||||
/// Report warning.
|
||||
void warn(Error Warning, StringRef Context, const DWARFDie *DIE = nullptr) {
|
||||
handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
|
||||
warn(Info.message(), Context, DIE);
|
||||
});
|
||||
}
|
||||
|
||||
/// Report error.
|
||||
void error(const Twine &Err, StringRef Context,
|
||||
const DWARFDie *DIE = nullptr) {
|
||||
if (ErrorHandler)
|
||||
(ErrorHandler)(Err, Context, DIE);
|
||||
}
|
||||
|
||||
/// Report error.
|
||||
void error(Error Err, StringRef Context, const DWARFDie *DIE = nullptr) {
|
||||
handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
|
||||
error(Info.message(), Context, DIE);
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
parallel::PerThreadBumpPtrAllocator Allocator;
|
||||
StringPool Strings;
|
||||
TranslatorFuncTy Translator;
|
||||
DWARFLinkerOptions Options;
|
||||
MessageHandlerTy WarningHandler;
|
||||
MessageHandlerTy ErrorHandler;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H
|
File diff suppressed because it is too large
Load Diff
@ -11,29 +11,29 @@
|
||||
|
||||
#include "DWARFEmitterImpl.h"
|
||||
#include "DWARFLinkerCompileUnit.h"
|
||||
#include "StringEntryToDwarfStringPoolEntryMap.h"
|
||||
#include "llvm/ADT/AddressRanges.h"
|
||||
#include "llvm/CodeGen/AccelTable.h"
|
||||
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||
#include "llvm/DWARFLinkerParallel/StringPool.h"
|
||||
#include "llvm/DWARFLinkerParallel/StringTable.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
using Offset2UnitMapTy = DenseMap<uint64_t, CompileUnit *>;
|
||||
|
||||
struct RangeAttrPatch;
|
||||
struct LocAttrPatch;
|
||||
|
||||
/// This class links debug info.
|
||||
class DWARFLinkerImpl : public DWARFLinker {
|
||||
public:
|
||||
DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
|
||||
MessageHandlerTy WarningHandler,
|
||||
TranslatorFuncTy StringsTranslator)
|
||||
: UniqueUnitID(0), ErrorHandler(ErrorHandler),
|
||||
WarningHandler(WarningHandler),
|
||||
OutputStrings(Strings, StringsTranslator) {}
|
||||
: UniqueUnitID(0), DebugStrStrings(GlobalData),
|
||||
DebugLineStrStrings(GlobalData), CommonSections(GlobalData) {
|
||||
GlobalData.setTranslator(StringsTranslator);
|
||||
GlobalData.setErrorHandler(ErrorHandler);
|
||||
GlobalData.setWarningHandler(WarningHandler);
|
||||
}
|
||||
|
||||
/// Create debug info emitter.
|
||||
Error createEmitter(const Triple &TheTriple, OutputFileType FileType,
|
||||
raw_pwrite_stream &OutFile) override;
|
||||
|
||||
@ -47,13 +47,11 @@ public:
|
||||
/// \pre NoODR, Update options should be set before call to addObjectFile.
|
||||
void addObjectFile(
|
||||
DWARFFile &File, ObjFileLoaderTy Loader = nullptr,
|
||||
CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override {}
|
||||
|
||||
CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override;
|
||||
|
||||
/// Link debug info for added files.
|
||||
Error link() override {
|
||||
reportWarning("LLVM parallel dwarflinker is not implemented yet.", "");
|
||||
return Error::success();
|
||||
}
|
||||
Error link() override;
|
||||
|
||||
/// \defgroup Methods setting various linking options:
|
||||
///
|
||||
@ -61,51 +59,58 @@ public:
|
||||
///
|
||||
|
||||
/// Allows to generate log of linking process to the standard output.
|
||||
void setVerbosity(bool Verbose) override { Options.Verbose = Verbose; }
|
||||
void setVerbosity(bool Verbose) override {
|
||||
GlobalData.Options.Verbose = Verbose;
|
||||
}
|
||||
|
||||
/// Print statistics to standard output.
|
||||
void setStatistics(bool Statistics) override {
|
||||
Options.Statistics = Statistics;
|
||||
GlobalData.Options.Statistics = Statistics;
|
||||
}
|
||||
|
||||
/// Verify the input DWARF.
|
||||
void setVerifyInputDWARF(bool Verify) override {
|
||||
Options.VerifyInputDWARF = Verify;
|
||||
GlobalData.Options.VerifyInputDWARF = Verify;
|
||||
}
|
||||
|
||||
/// Do not unique types according to ODR.
|
||||
void setNoODR(bool NoODR) override { Options.NoODR = NoODR; }
|
||||
void setNoODR(bool) override {
|
||||
// FIXME: set option when ODR mode will be supported.
|
||||
// getOptions().NoODR = NoODR;
|
||||
GlobalData.Options.NoODR = true;
|
||||
}
|
||||
|
||||
/// Update index tables only(do not modify rest of DWARF).
|
||||
void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override {
|
||||
Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly;
|
||||
GlobalData.Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly;
|
||||
}
|
||||
|
||||
/// Allow generating valid, but non-deterministic output.
|
||||
void
|
||||
setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override {
|
||||
Options.AllowNonDeterministicOutput = AllowNonDeterministicOutput;
|
||||
GlobalData.Options.AllowNonDeterministicOutput =
|
||||
AllowNonDeterministicOutput;
|
||||
}
|
||||
|
||||
/// Set to keep the enclosing function for a static variable.
|
||||
void setKeepFunctionForStatic(bool KeepFunctionForStatic) override {
|
||||
Options.KeepFunctionForStatic = KeepFunctionForStatic;
|
||||
GlobalData.Options.KeepFunctionForStatic = KeepFunctionForStatic;
|
||||
}
|
||||
|
||||
/// Use specified number of threads for parallel files linking.
|
||||
void setNumThreads(unsigned NumThreads) override {
|
||||
Options.Threads = NumThreads;
|
||||
GlobalData.Options.Threads = NumThreads;
|
||||
}
|
||||
|
||||
/// Add kind of accelerator tables to be generated.
|
||||
void addAccelTableKind(AccelTableKind Kind) override {
|
||||
assert(!llvm::is_contained(Options.AccelTables, Kind));
|
||||
Options.AccelTables.emplace_back(Kind);
|
||||
assert(!llvm::is_contained(GlobalData.getOptions().AccelTables, Kind));
|
||||
GlobalData.Options.AccelTables.emplace_back(Kind);
|
||||
}
|
||||
|
||||
/// Set prepend path for clang modules.
|
||||
void setPrependPath(const std::string &Ppath) override {
|
||||
Options.PrependPath = Ppath;
|
||||
GlobalData.Options.PrependPath = Ppath;
|
||||
}
|
||||
|
||||
/// Set estimated objects files amount, for preliminary data allocation.
|
||||
@ -117,17 +122,17 @@ public:
|
||||
/// errors.
|
||||
void
|
||||
setInputVerificationHandler(InputVerificationHandlerTy Handler) override {
|
||||
Options.InputVerificationHandler = Handler;
|
||||
GlobalData.Options.InputVerificationHandler = Handler;
|
||||
}
|
||||
|
||||
/// Set map for Swift interfaces.
|
||||
void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override {
|
||||
Options.ParseableSwiftInterfaces = Map;
|
||||
GlobalData.Options.ParseableSwiftInterfaces = Map;
|
||||
}
|
||||
|
||||
/// Set prefix map for objects.
|
||||
void setObjectPrefixMap(ObjectPrefixMapTy *Map) override {
|
||||
Options.ObjectPrefixMap = Map;
|
||||
GlobalData.Options.ObjectPrefixMap = Map;
|
||||
}
|
||||
|
||||
/// Set target DWARF version.
|
||||
@ -137,36 +142,28 @@ public:
|
||||
"unsupported DWARF version: %d",
|
||||
TargetDWARFVersion);
|
||||
|
||||
Options.TargetDWARFVersion = TargetDWARFVersion;
|
||||
GlobalData.Options.TargetDWARFVersion = TargetDWARFVersion;
|
||||
return Error::success();
|
||||
}
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
/// Reports Warning.
|
||||
void reportWarning(const Twine &Warning, const DWARFFile &File,
|
||||
const DWARFDie *DIE = nullptr) const {
|
||||
if (WarningHandler != nullptr)
|
||||
WarningHandler(Warning, File.FileName, DIE);
|
||||
}
|
||||
/// Verify input DWARF file.
|
||||
void verifyInput(const DWARFFile &File);
|
||||
|
||||
/// Reports Warning.
|
||||
void reportWarning(const Twine &Warning, StringRef FileName,
|
||||
const DWARFDie *DIE = nullptr) const {
|
||||
if (WarningHandler != nullptr)
|
||||
WarningHandler(Warning, FileName, DIE);
|
||||
}
|
||||
/// Validate specified options.
|
||||
Error validateAndUpdateOptions();
|
||||
|
||||
/// Reports Error.
|
||||
void reportError(const Twine &Warning, StringRef FileName,
|
||||
const DWARFDie *DIE = nullptr) const {
|
||||
if (ErrorHandler != nullptr)
|
||||
ErrorHandler(Warning, FileName, DIE);
|
||||
}
|
||||
/// Take already linked compile units and glue them into single file.
|
||||
void glueCompileUnitsAndWriteToTheOutput();
|
||||
|
||||
/// Returns next available unique Compile Unit ID.
|
||||
unsigned getNextUniqueUnitID() { return UniqueUnitID.fetch_add(1); }
|
||||
/// Hold the input and output of the debug info size in bytes.
|
||||
struct DebugInfoSize {
|
||||
uint64_t Input;
|
||||
uint64_t Output;
|
||||
};
|
||||
|
||||
friend class DependencyTracker;
|
||||
/// Keeps track of data associated with one object during linking.
|
||||
/// i.e. source file descriptor, compilation units, output data
|
||||
/// for compilation units common tables.
|
||||
@ -188,7 +185,7 @@ protected:
|
||||
using ModuleUnitListTy = SmallVector<RefModuleUnit>;
|
||||
|
||||
/// Object file descriptor.
|
||||
DWARFFile &File;
|
||||
DWARFFile &InputDWARFFile;
|
||||
|
||||
/// Set of Compilation Units(may be accessed asynchroniously for reading).
|
||||
UnitListTy CompileUnits;
|
||||
@ -199,117 +196,190 @@ protected:
|
||||
/// Size of Debug info before optimizing.
|
||||
uint64_t OriginalDebugInfoSize = 0;
|
||||
|
||||
/// Output sections, common for all compilation units.
|
||||
OutTablesFileTy OutDebugInfoBytes;
|
||||
/// Flag indicating that all inter-connected units are loaded
|
||||
/// and the dwarf linking process for these units is started.
|
||||
bool InterCUProcessingStarted = false;
|
||||
|
||||
/// Endianness for the final file.
|
||||
support::endianness Endianess = support::endianness::little;
|
||||
StringMap<uint64_t> &ClangModules;
|
||||
|
||||
std::optional<Triple> TargetTriple;
|
||||
|
||||
/// Flag indicating that new inter-connected compilation units were
|
||||
/// discovered. It is used for restarting units processing
|
||||
/// if new inter-connected units were found.
|
||||
std::atomic<bool> HasNewInterconnectedCUs = {false};
|
||||
|
||||
/// Counter for compile units ID.
|
||||
std::atomic<size_t> &UniqueUnitID;
|
||||
|
||||
LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File,
|
||||
StringMap<uint64_t> &ClangModules,
|
||||
std::atomic<size_t> &UniqueUnitID,
|
||||
std::optional<Triple> TargetTriple)
|
||||
: OutputSections(GlobalData), InputDWARFFile(File),
|
||||
ClangModules(ClangModules), TargetTriple(TargetTriple),
|
||||
UniqueUnitID(UniqueUnitID) {
|
||||
|
||||
LinkContext(DWARFFile &File) : File(File) {
|
||||
if (File.Dwarf) {
|
||||
if (!File.Dwarf->compile_units().empty())
|
||||
CompileUnits.reserve(File.Dwarf->getNumCompileUnits());
|
||||
|
||||
Endianess = File.Dwarf->isLittleEndian() ? support::endianness::little
|
||||
: support::endianness::big;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether specified \p CUDie is a Clang module reference.
|
||||
/// if \p Quiet is false then display error messages.
|
||||
/// \return first == true if CUDie is a Clang module reference.
|
||||
/// second == true if module is already loaded.
|
||||
std::pair<bool, bool> isClangModuleRef(const DWARFDie &CUDie,
|
||||
std::string &PCMFile,
|
||||
unsigned Indent, bool Quiet);
|
||||
|
||||
/// If this compile unit is really a skeleton CU that points to a
|
||||
/// clang module, register it in ClangModules and return true.
|
||||
///
|
||||
/// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
|
||||
/// pointing to the module, and a DW_AT_gnu_dwo_id with the module
|
||||
/// hash.
|
||||
bool registerModuleReference(const DWARFDie &CUDie, ObjFileLoaderTy Loader,
|
||||
CompileUnitHandlerTy OnCUDieLoaded,
|
||||
unsigned Indent = 0);
|
||||
|
||||
/// Recursively add the debug info in this clang module .pcm
|
||||
/// file (and all the modules imported by it in a bottom-up fashion)
|
||||
/// to ModuleUnits.
|
||||
Error loadClangModule(ObjFileLoaderTy Loader, const DWARFDie &CUDie,
|
||||
const std::string &PCMFile,
|
||||
CompileUnitHandlerTy OnCUDieLoaded,
|
||||
unsigned Indent = 0);
|
||||
|
||||
/// Add Compile Unit corresponding to the module.
|
||||
void addModulesCompileUnit(RefModuleUnit &&Unit) {
|
||||
ModulesCompileUnits.emplace_back(std::move(Unit));
|
||||
}
|
||||
|
||||
/// Return Endiannes of the source DWARF information.
|
||||
support::endianness getEndianness() { return Endianess; }
|
||||
/// Computes the total size of the debug info.
|
||||
uint64_t getInputDebugInfoSize() const {
|
||||
uint64_t Size = 0;
|
||||
|
||||
/// \returns pointer to compilation unit which corresponds \p Offset.
|
||||
CompileUnit *getUnitForOffset(CompileUnit &CU, uint64_t Offset) const;
|
||||
if (InputDWARFFile.Dwarf == nullptr)
|
||||
return Size;
|
||||
|
||||
for (auto &Unit : InputDWARFFile.Dwarf->compile_units())
|
||||
Size += Unit->getLength();
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
/// Link compile units for this context.
|
||||
Error link();
|
||||
|
||||
/// Link specified compile unit until specified stage.
|
||||
void linkSingleCompileUnit(
|
||||
CompileUnit &CU,
|
||||
enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned);
|
||||
|
||||
/// Emit invariant sections.
|
||||
Error emitInvariantSections();
|
||||
|
||||
/// Clone and emit .debug_frame.
|
||||
Error cloneAndEmitDebugFrame();
|
||||
|
||||
/// Emit FDE record.
|
||||
void emitFDE(uint32_t CIEOffset, uint32_t AddrSize, uint64_t Address,
|
||||
StringRef FDEBytes, SectionDescriptor &Section);
|
||||
|
||||
/// Clone and emit paper trails.
|
||||
Error cloneAndEmitPaperTrails();
|
||||
|
||||
std::function<CompileUnit *(uint64_t)> getUnitForOffset =
|
||||
[&](uint64_t Offset) -> CompileUnit * {
|
||||
auto CU = llvm::upper_bound(
|
||||
CompileUnits, Offset,
|
||||
[](uint64_t LHS, const std::unique_ptr<CompileUnit> &RHS) {
|
||||
return LHS < RHS->getOrigUnit().getNextUnitOffset();
|
||||
});
|
||||
|
||||
return CU != CompileUnits.end() ? CU->get() : nullptr;
|
||||
};
|
||||
};
|
||||
|
||||
/// linking options
|
||||
struct DWARFLinkerOptions {
|
||||
/// DWARF version for the output.
|
||||
uint16_t TargetDWARFVersion = 0;
|
||||
/// Enumerate all compile units and assign offsets to their sections and
|
||||
/// strings.
|
||||
void assignOffsets();
|
||||
|
||||
/// Generate processing log to the standard output.
|
||||
bool Verbose = false;
|
||||
/// Enumerate all compile units and assign offsets to their sections.
|
||||
void assignOffsetsToSections();
|
||||
|
||||
/// Print statistics.
|
||||
bool Statistics = false;
|
||||
/// Enumerate all compile units and assign offsets to their strings.
|
||||
void assignOffsetsToStrings();
|
||||
|
||||
/// Verify the input DWARF.
|
||||
bool VerifyInputDWARF = false;
|
||||
/// Enumerates specified string patches, assigns offset and index.
|
||||
template <typename PatchTy>
|
||||
void assignOffsetsToStringsImpl(
|
||||
ArrayList<PatchTy> &Section, size_t &IndexAccumulator,
|
||||
uint64_t &OffsetAccumulator,
|
||||
StringEntryToDwarfStringPoolEntryMap &StringsForEmission);
|
||||
|
||||
/// Do not unique types according to ODR
|
||||
bool NoODR = false;
|
||||
/// Print statistic for processed Debug Info.
|
||||
void printStatistic();
|
||||
|
||||
/// Update index tables.
|
||||
bool UpdateIndexTablesOnly = false;
|
||||
/// Enumerates sections for modules, invariant for object files, compile
|
||||
/// units.
|
||||
void forEachObjectSectionsSet(
|
||||
function_ref<void(OutputSections &SectionsSet)> SectionsSetHandler);
|
||||
|
||||
/// Whether we want a static variable to force us to keep its enclosing
|
||||
/// function.
|
||||
bool KeepFunctionForStatic = false;
|
||||
/// Enumerates all patches and update them with the correct values.
|
||||
void patchOffsetsAndSizes();
|
||||
|
||||
/// Allow to generate valid, but non deterministic output.
|
||||
bool AllowNonDeterministicOutput = false;
|
||||
/// Emit debug sections common for all input files.
|
||||
void emitCommonSections();
|
||||
|
||||
/// Number of threads.
|
||||
unsigned Threads = 1;
|
||||
/// Cleanup data(string pools) after output sections are generated.
|
||||
void cleanupDataAfterOutputSectionsAreGenerated();
|
||||
|
||||
/// The accelerator table kinds
|
||||
SmallVector<AccelTableKind, 1> AccelTables;
|
||||
/// Enumerate all compile units and put their data into the output stream.
|
||||
void writeDWARFToTheOutput();
|
||||
|
||||
/// Prepend path for the clang modules.
|
||||
std::string PrependPath;
|
||||
|
||||
/// input verification handler(it might be called asynchronously).
|
||||
InputVerificationHandlerTy InputVerificationHandler = nullptr;
|
||||
|
||||
/// A list of all .swiftinterface files referenced by the debug
|
||||
/// info, mapping Module name to path on disk. The entries need to
|
||||
/// be uniqued and sorted and there are only few entries expected
|
||||
/// per compile unit, which is why this is a std::map.
|
||||
/// this is dsymutil specific fag.
|
||||
///
|
||||
/// (it might be called asynchronously).
|
||||
SwiftInterfacesMapTy *ParseableSwiftInterfaces = nullptr;
|
||||
|
||||
/// A list of remappings to apply to file paths.
|
||||
///
|
||||
/// (it might be called asynchronously).
|
||||
ObjectPrefixMapTy *ObjectPrefixMap = nullptr;
|
||||
} Options;
|
||||
template <typename PatchTy>
|
||||
void emitStringsImpl(ArrayList<PatchTy> &StringPatches,
|
||||
const StringEntryToDwarfStringPoolEntryMap &Strings,
|
||||
uint64_t &NextOffset, SectionDescriptor &OutSection);
|
||||
|
||||
/// \defgroup Data members accessed asinchroniously.
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// Unique ID for compile unit.
|
||||
std::atomic<unsigned> UniqueUnitID;
|
||||
std::atomic<size_t> UniqueUnitID;
|
||||
|
||||
/// Strings pool. Keeps all strings.
|
||||
StringPool Strings;
|
||||
|
||||
/// error handler(it might be called asynchronously).
|
||||
MessageHandlerTy ErrorHandler = nullptr;
|
||||
|
||||
/// warning handler(it might be called asynchronously).
|
||||
MessageHandlerTy WarningHandler = nullptr;
|
||||
/// Mapping the PCM filename to the DwoId.
|
||||
StringMap<uint64_t> ClangModules;
|
||||
std::mutex ClangModulesMutex;
|
||||
/// @}
|
||||
|
||||
/// \defgroup Data members accessed sequentially.
|
||||
///
|
||||
/// @{
|
||||
/// DwarfStringPoolEntries for .debug_str section.
|
||||
StringEntryToDwarfStringPoolEntryMap DebugStrStrings;
|
||||
|
||||
/// Set of strings which should be emitted.
|
||||
StringTable OutputStrings;
|
||||
/// DwarfStringPoolEntries for .debug_line_str section.
|
||||
StringEntryToDwarfStringPoolEntryMap DebugLineStrStrings;
|
||||
|
||||
/// Keeps all linking contexts.
|
||||
SmallVector<std::unique_ptr<LinkContext>> ObjectContexts;
|
||||
|
||||
/// Common sections.
|
||||
OutputSections CommonSections;
|
||||
|
||||
/// The emitter of final dwarf file.
|
||||
std::unique_ptr<DwarfEmitterImpl> TheDwarfEmitter;
|
||||
|
||||
/// Overall compile units number.
|
||||
uint64_t OverallNumberOfCU = 0;
|
||||
|
||||
/// Data global for the whole linking process.
|
||||
LinkingGlobalData GlobalData;
|
||||
/// @}
|
||||
};
|
||||
|
||||
|
130
llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
Normal file
130
llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
//===- DWARFLinkerUnit.cpp ------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DWARFLinkerUnit.h"
|
||||
#include "DWARFEmitterImpl.h"
|
||||
#include "DebugLineSectionEmitter.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
void DwarfUnit::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(
|
||||
std::make_unique<DIEAbbrev>(Abbrev.getTag(), Abbrev.hasChildren()));
|
||||
for (const auto &Attr : Abbrev.getData())
|
||||
Abbreviations.back()->AddAttribute(Attr);
|
||||
AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken);
|
||||
// Assign the unique abbreviation number.
|
||||
Abbrev.setNumber(Abbreviations.size());
|
||||
Abbreviations.back()->setNumber(Abbreviations.size());
|
||||
}
|
||||
}
|
||||
|
||||
Error DwarfUnit::emitAbbreviations() {
|
||||
const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs = getAbbreviations();
|
||||
if (Abbrevs.empty())
|
||||
return Error::success();
|
||||
|
||||
SectionDescriptor &AbbrevSection =
|
||||
getOrCreateSectionDescriptor(DebugSectionKind::DebugAbbrev);
|
||||
|
||||
// For each abbreviation.
|
||||
for (const auto &Abbrev : Abbrevs)
|
||||
emitDwarfAbbrevEntry(*Abbrev, AbbrevSection);
|
||||
|
||||
// Mark end of abbreviations.
|
||||
encodeULEB128(0, AbbrevSection.OS);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void DwarfUnit::emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev,
|
||||
SectionDescriptor &AbbrevSection) {
|
||||
// Emit the abbreviations code (base 1 index.)
|
||||
encodeULEB128(Abbrev.getNumber(), AbbrevSection.OS);
|
||||
|
||||
// Emit the abbreviations data.
|
||||
// Emit its Dwarf tag type.
|
||||
encodeULEB128(Abbrev.getTag(), AbbrevSection.OS);
|
||||
|
||||
// Emit whether it has children DIEs.
|
||||
encodeULEB128((unsigned)Abbrev.hasChildren(), AbbrevSection.OS);
|
||||
|
||||
// For each attribute description.
|
||||
const SmallVectorImpl<DIEAbbrevData> &Data = Abbrev.getData();
|
||||
for (unsigned i = 0, N = Data.size(); i < N; ++i) {
|
||||
const DIEAbbrevData &AttrData = Data[i];
|
||||
|
||||
// Emit attribute type.
|
||||
encodeULEB128(AttrData.getAttribute(), AbbrevSection.OS);
|
||||
|
||||
// Emit form type.
|
||||
encodeULEB128(AttrData.getForm(), AbbrevSection.OS);
|
||||
|
||||
// Emit value for DW_FORM_implicit_const.
|
||||
if (AttrData.getForm() == dwarf::DW_FORM_implicit_const)
|
||||
encodeSLEB128(AttrData.getValue(), AbbrevSection.OS);
|
||||
}
|
||||
|
||||
// Mark end of abbreviation.
|
||||
encodeULEB128(0, AbbrevSection.OS);
|
||||
encodeULEB128(0, AbbrevSection.OS);
|
||||
}
|
||||
|
||||
Error DwarfUnit::emitDebugInfo(Triple &TargetTriple) {
|
||||
DIE *OutUnitDIE = getOutUnitDIE();
|
||||
if (OutUnitDIE == nullptr)
|
||||
return Error::success();
|
||||
|
||||
// FIXME: Remove dependence on DwarfEmitterImpl/AsmPrinter and emit DIEs
|
||||
// directly.
|
||||
|
||||
SectionDescriptor &OutSection =
|
||||
getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
|
||||
DwarfEmitterImpl Emitter(DWARFLinker::OutputFileType::Object, OutSection.OS);
|
||||
if (Error Err = Emitter.init(TargetTriple, "__DWARF"))
|
||||
return Err;
|
||||
|
||||
// Emit compile unit header.
|
||||
Emitter.emitCompileUnitHeader(*this);
|
||||
size_t OffsetToAbbreviationTableOffset =
|
||||
(getFormParams().Version >= 5) ? 8 : 6;
|
||||
OutSection.notePatch(DebugOffsetPatch{
|
||||
OffsetToAbbreviationTableOffset,
|
||||
&getOrCreateSectionDescriptor(DebugSectionKind::DebugAbbrev)});
|
||||
|
||||
// Emit DIEs.
|
||||
Emitter.emitDIE(*OutUnitDIE);
|
||||
Emitter.finish();
|
||||
|
||||
// Set start offset ans size for .debug_info section.
|
||||
OutSection.setSizesForSectionCreatedByAsmPrinter();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DwarfUnit::emitDebugLine(Triple &TargetTriple,
|
||||
const DWARFDebugLine::LineTable &OutLineTable) {
|
||||
DebugLineSectionEmitter DebugLineEmitter(TargetTriple, *this);
|
||||
|
||||
return DebugLineEmitter.emit(OutLineTable);
|
||||
}
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end of namespace llvm
|
@ -9,9 +9,11 @@
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
|
||||
|
||||
#include "DWARFLinkerGlobalData.h"
|
||||
#include "OutputSections.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||
#include "llvm/DWARFLinkerParallel/StringPool.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
@ -19,44 +21,17 @@
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
using UnitMessageHandlerTy = function_ref<void(
|
||||
const Twine &Error, StringRef Context, const DWARFDie *DIE)>;
|
||||
|
||||
/// Each unit keeps output data as a file with debug tables
|
||||
/// corresponding to the concrete unit.
|
||||
using OutTablesFileTy = SmallString<0>;
|
||||
class DwarfUnit;
|
||||
using MacroOffset2UnitMapTy = DenseMap<uint64_t, DwarfUnit *>;
|
||||
|
||||
/// Base class for all Dwarf units(Compile unit/Type table unit).
|
||||
class DwarfUnit : public OutputSections {
|
||||
public:
|
||||
virtual ~DwarfUnit() {}
|
||||
DwarfUnit(unsigned ID, StringRef ClangModuleName,
|
||||
UnitMessageHandlerTy WarningHandler)
|
||||
: ID(ID), ClangModuleName(ClangModuleName),
|
||||
WarningHandler(WarningHandler) {
|
||||
FormParams.Version = 4;
|
||||
FormParams.Format = dwarf::DWARF32;
|
||||
FormParams.AddrSize = 4;
|
||||
}
|
||||
|
||||
/// Endiannes for the compile unit.
|
||||
support::endianness getEndianness() const { return Endianess; }
|
||||
|
||||
/// Return DWARF version.
|
||||
uint16_t getVersion() const { return FormParams.Version; }
|
||||
|
||||
/// Return size of header of debug_info table.
|
||||
uint16_t getHeaderSize() const { return FormParams.Version >= 5 ? 12 : 11; }
|
||||
|
||||
/// Return size of address.
|
||||
uint8_t getAddressByteSize() const { return FormParams.AddrSize; }
|
||||
|
||||
/// Return size of reference.
|
||||
uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); }
|
||||
|
||||
/// Return format of the Dwarf(DWARF32 or DWARF64).
|
||||
/// TODO: DWARF64 is not currently supported.
|
||||
dwarf::DwarfFormat getDwarfFormat() const { return FormParams.Format; }
|
||||
DwarfUnit(LinkingGlobalData &GlobalData, unsigned ID,
|
||||
StringRef ClangModuleName)
|
||||
: OutputSections(GlobalData), ID(ID), ClangModuleName(ClangModuleName),
|
||||
OutUnitDIE(nullptr) {}
|
||||
|
||||
/// Unique id of the unit.
|
||||
unsigned getUniqueID() const { return ID; }
|
||||
@ -76,41 +51,48 @@ public:
|
||||
/// Return the DW_AT_LLVM_sysroot of the compile unit or an empty StringRef.
|
||||
StringRef getSysRoot() { return SysRoot; }
|
||||
|
||||
/// Create a Die for this unit.
|
||||
void setOutputDIE(DIE *UnitDie) { NewUnit = UnitDie; }
|
||||
|
||||
/// Return Die for this compile unit.
|
||||
DIE *getOutputUnitDIE() const { return NewUnit; }
|
||||
|
||||
/// Return true if this compile unit is from Clang module.
|
||||
bool isClangModule() const { return !ClangModuleName.empty(); }
|
||||
|
||||
/// Return Clang module name;
|
||||
const std::string &getClangModuleName() const { return ClangModuleName; }
|
||||
|
||||
/// Returns generated file keeping debug tables for this compile unit.
|
||||
OutTablesFileTy &getOutDwarfBits() { return OutDebugInfoBits; }
|
||||
/// Return global data.
|
||||
LinkingGlobalData &getGlobalData() { return GlobalData; }
|
||||
|
||||
/// Erases generated file keeping debug tables for this compile unit.
|
||||
void eraseDwarfBits() { OutDebugInfoBits = OutTablesFileTy(); }
|
||||
/// Returns true if unit is inter-connected(it references/referenced by other
|
||||
/// unit).
|
||||
bool isInterconnectedCU() const { return IsInterconnectedCU; }
|
||||
|
||||
MCSymbol *getLabelBegin() { return LabelBegin; }
|
||||
void setLabelBegin(MCSymbol *S) { LabelBegin = S; }
|
||||
/// Mark this unit as inter-connected(it references/referenced by other unit).
|
||||
void setInterconnectedCU() { IsInterconnectedCU = true; }
|
||||
|
||||
/// Error reporting methods.
|
||||
/// Adds \p Abbrev into unit`s abbreviation table.
|
||||
void assignAbbrev(DIEAbbrev &Abbrev);
|
||||
|
||||
/// Returns abbreviations for this compile unit.
|
||||
const std::vector<std::unique_ptr<DIEAbbrev>> &getAbbreviations() const {
|
||||
return Abbreviations;
|
||||
}
|
||||
|
||||
/// Returns output unit DIE.
|
||||
DIE *getOutUnitDIE() { return OutUnitDIE; }
|
||||
|
||||
/// Set output unit DIE.
|
||||
void setOutUnitDIE(DIE *UnitDie) { OutUnitDIE = UnitDie; }
|
||||
|
||||
/// \defgroup Methods used to emit unit's debug info:
|
||||
///
|
||||
/// @{
|
||||
/// Emit unit's abbreviations.
|
||||
Error emitAbbreviations();
|
||||
|
||||
void reportWarning(const Twine &Warning,
|
||||
const DWARFDie *Die = nullptr) const {
|
||||
if (WarningHandler)
|
||||
WarningHandler(Warning, getUnitName(), Die);
|
||||
}
|
||||
void reportWarning(Error Warning) const {
|
||||
handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
|
||||
if (WarningHandler)
|
||||
WarningHandler(Info.message(), getUnitName(), nullptr);
|
||||
});
|
||||
}
|
||||
/// Emit .debug_info section for unit DIEs.
|
||||
Error emitDebugInfo(Triple &TargetTriple);
|
||||
|
||||
/// Emit .debug_line section.
|
||||
Error emitDebugLine(Triple &TargetTriple,
|
||||
const DWARFDebugLine::LineTable &OutLineTable);
|
||||
/// @}
|
||||
|
||||
/// This structure keeps fields which would be used for creating accelerator
|
||||
@ -142,16 +124,22 @@ public:
|
||||
const DIE *Die = nullptr;
|
||||
};
|
||||
|
||||
/// \defgroup Methods used for reporting warnings and errors:
|
||||
///
|
||||
/// @{
|
||||
void warn(const Twine &Warning) { GlobalData.warn(Warning, getUnitName()); }
|
||||
|
||||
void error(const Twine &Err) { GlobalData.warn(Err, getUnitName()); }
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
/// Emit single abbreviation entry.
|
||||
void emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev,
|
||||
SectionDescriptor &AbbrevSection);
|
||||
|
||||
/// Unique ID for the unit.
|
||||
unsigned ID = 0;
|
||||
|
||||
/// Properties of the unit.
|
||||
dwarf::FormParams FormParams;
|
||||
|
||||
/// DIE for newly generated compile unit.
|
||||
DIE *NewUnit = nullptr;
|
||||
|
||||
/// The DW_AT_language of this unit.
|
||||
uint16_t Language = 0;
|
||||
|
||||
@ -166,18 +154,17 @@ protected:
|
||||
|
||||
uint64_t UnitSize = 0;
|
||||
|
||||
/// Elf file containg generated debug tables for this compile unit.
|
||||
OutTablesFileTy OutDebugInfoBits;
|
||||
|
||||
/// Endiannes for this compile unit.
|
||||
support::endianness Endianess = support::endianness::little;
|
||||
|
||||
MCSymbol *LabelBegin = nullptr;
|
||||
|
||||
/// true if current unit references_to/is_referenced by other unit.
|
||||
std::atomic<bool> IsInterconnectedCU = {false};
|
||||
|
||||
UnitMessageHandlerTy WarningHandler;
|
||||
/// FoldingSet that uniques the abbreviations.
|
||||
FoldingSet<DIEAbbrev> AbbreviationsSet;
|
||||
|
||||
/// Storage for the unique Abbreviations.
|
||||
std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
|
||||
|
||||
/// Output unit DIE.
|
||||
DIE *OutUnitDIE = nullptr;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
|
384
llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
Normal file
384
llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
Normal file
@ -0,0 +1,384 @@
|
||||
//===- DebugLineSectionEmitter.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DEBUGLINESECTIONEMITTER_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_DEBUGLINESECTIONEMITTER_H
|
||||
|
||||
#include "DWARFEmitterImpl.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/DWARFLinkerParallel/AddressesMap.h"
|
||||
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFObject.h"
|
||||
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
|
||||
#include "llvm/MC/TargetRegistry.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
/// This class emits specified line table into the .debug_line section.
|
||||
class DebugLineSectionEmitter {
|
||||
public:
|
||||
DebugLineSectionEmitter(const Triple &TheTriple, DwarfUnit &U)
|
||||
: TheTriple(TheTriple), U(U) {}
|
||||
|
||||
Error emit(const DWARFDebugLine::LineTable &LineTable) {
|
||||
// FIXME: remove dependence on MCDwarfLineAddr::encode.
|
||||
// As we reuse MCDwarfLineAddr::encode, we need to create/initialize
|
||||
// some MC* classes.
|
||||
if (Error Err = init(TheTriple))
|
||||
return Err;
|
||||
|
||||
// Get descriptor for output .debug_line section.
|
||||
SectionDescriptor &OutSection =
|
||||
U.getOrCreateSectionDescriptor(DebugSectionKind::DebugLine);
|
||||
|
||||
// unit_length.
|
||||
OutSection.emitUnitLength(0xBADDEF);
|
||||
uint64_t OffsetAfterUnitLength = OutSection.OS.tell();
|
||||
|
||||
// Emit prologue.
|
||||
emitLineTablePrologue(LineTable.Prologue, OutSection);
|
||||
|
||||
// Emit rows.
|
||||
emitLineTableRows(LineTable, OutSection);
|
||||
uint64_t OffsetAfterEnd = OutSection.OS.tell();
|
||||
|
||||
// Update unit length field with actual length value.
|
||||
assert(OffsetAfterUnitLength -
|
||||
OutSection.getFormParams().getDwarfOffsetByteSize() <
|
||||
OffsetAfterUnitLength);
|
||||
OutSection.apply(OffsetAfterUnitLength -
|
||||
OutSection.getFormParams().getDwarfOffsetByteSize(),
|
||||
dwarf::DW_FORM_sec_offset,
|
||||
OffsetAfterEnd - OffsetAfterUnitLength);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
Error init(Triple TheTriple) {
|
||||
std::string ErrorStr;
|
||||
std::string TripleName;
|
||||
|
||||
// Get the target.
|
||||
const Target *TheTarget =
|
||||
TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
|
||||
if (!TheTarget)
|
||||
return createStringError(std::errc::invalid_argument, ErrorStr.c_str());
|
||||
TripleName = TheTriple.getTriple();
|
||||
|
||||
// Create all the MC Objects.
|
||||
MRI.reset(TheTarget->createMCRegInfo(TripleName));
|
||||
if (!MRI)
|
||||
return createStringError(std::errc::invalid_argument,
|
||||
"no register info for target %s",
|
||||
TripleName.c_str());
|
||||
|
||||
MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
|
||||
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
|
||||
if (!MAI)
|
||||
return createStringError(std::errc::invalid_argument,
|
||||
"no asm info for target %s", TripleName.c_str());
|
||||
|
||||
MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
|
||||
if (!MSTI)
|
||||
return createStringError(std::errc::invalid_argument,
|
||||
"no subtarget info for target %s",
|
||||
TripleName.c_str());
|
||||
|
||||
MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr,
|
||||
nullptr, true, "__DWARF"));
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void emitLineTablePrologue(const DWARFDebugLine::Prologue &P,
|
||||
SectionDescriptor &Section) {
|
||||
// version (uhalf).
|
||||
Section.emitIntVal(P.getVersion(), 2);
|
||||
if (P.getVersion() == 5) {
|
||||
// address_size (ubyte).
|
||||
Section.emitIntVal(P.getAddressSize(), 1);
|
||||
|
||||
// segment_selector_size (ubyte).
|
||||
Section.emitIntVal(P.SegSelectorSize, 1);
|
||||
}
|
||||
|
||||
// header_length.
|
||||
Section.emitOffset(0xBADDEF);
|
||||
|
||||
uint64_t OffsetAfterPrologueLength = Section.OS.tell();
|
||||
emitLineTableProloguePayload(P, Section);
|
||||
uint64_t OffsetAfterPrologueEnd = Section.OS.tell();
|
||||
|
||||
// Update prologue length field with actual length value.
|
||||
Section.apply(OffsetAfterPrologueLength -
|
||||
Section.getFormParams().getDwarfOffsetByteSize(),
|
||||
dwarf::DW_FORM_sec_offset,
|
||||
OffsetAfterPrologueEnd - OffsetAfterPrologueLength);
|
||||
}
|
||||
|
||||
void
|
||||
emitLineTablePrologueV2IncludeAndFileTable(const DWARFDebugLine::Prologue &P,
|
||||
SectionDescriptor &Section) {
|
||||
// include_directories (sequence of path names).
|
||||
for (const DWARFFormValue &Include : P.IncludeDirectories) {
|
||||
std::optional<const char *> IncludeStr = dwarf::toString(Include);
|
||||
if (!IncludeStr) {
|
||||
U.warn("cann't read string from line table.");
|
||||
return;
|
||||
}
|
||||
|
||||
Section.emitString(Include.getForm(), *IncludeStr);
|
||||
}
|
||||
// The last entry is followed by a single null byte.
|
||||
Section.emitIntVal(0, 1);
|
||||
|
||||
// file_names (sequence of file entries).
|
||||
for (const DWARFDebugLine::FileNameEntry &File : P.FileNames) {
|
||||
std::optional<const char *> FileNameStr = dwarf::toString(File.Name);
|
||||
if (!FileNameStr) {
|
||||
U.warn("cann't read string from line table.");
|
||||
return;
|
||||
}
|
||||
|
||||
// A null-terminated string containing the full or relative path name of a
|
||||
// source file.
|
||||
Section.emitString(File.Name.getForm(), *FileNameStr);
|
||||
// An unsigned LEB128 number representing the directory index of a
|
||||
// directory in the include_directories section.
|
||||
encodeULEB128(File.DirIdx, Section.OS);
|
||||
// An unsigned LEB128 number representing the (implementation-defined)
|
||||
// time of last modification for the file, or 0 if not available.
|
||||
encodeULEB128(File.ModTime, Section.OS);
|
||||
// An unsigned LEB128 number representing the length in bytes of the file,
|
||||
// or 0 if not available.
|
||||
encodeULEB128(File.Length, Section.OS);
|
||||
}
|
||||
// The last entry is followed by a single null byte.
|
||||
Section.emitIntVal(0, 1);
|
||||
}
|
||||
|
||||
void
|
||||
emitLineTablePrologueV5IncludeAndFileTable(const DWARFDebugLine::Prologue &P,
|
||||
SectionDescriptor &Section) {
|
||||
if (P.IncludeDirectories.empty()) {
|
||||
// directory_entry_format_count(ubyte).
|
||||
Section.emitIntVal(0, 1);
|
||||
} else {
|
||||
// directory_entry_format_count(ubyte).
|
||||
Section.emitIntVal(1, 1);
|
||||
|
||||
// directory_entry_format (sequence of ULEB128 pairs).
|
||||
encodeULEB128(dwarf::DW_LNCT_path, Section.OS);
|
||||
encodeULEB128(P.IncludeDirectories[0].getForm(), Section.OS);
|
||||
}
|
||||
|
||||
// directories_count (ULEB128).
|
||||
encodeULEB128(P.IncludeDirectories.size(), Section.OS);
|
||||
// directories (sequence of directory names).
|
||||
for (auto Include : P.IncludeDirectories) {
|
||||
std::optional<const char *> IncludeStr = dwarf::toString(Include);
|
||||
if (!IncludeStr) {
|
||||
U.warn("cann't read string from line table.");
|
||||
return;
|
||||
}
|
||||
|
||||
Section.emitString(Include.getForm(), *IncludeStr);
|
||||
}
|
||||
|
||||
if (P.FileNames.empty()) {
|
||||
// file_name_entry_format_count (ubyte).
|
||||
Section.emitIntVal(0, 1);
|
||||
} else {
|
||||
// file_name_entry_format_count (ubyte).
|
||||
Section.emitIntVal(2, 1);
|
||||
|
||||
// file_name_entry_format (sequence of ULEB128 pairs).
|
||||
encodeULEB128(dwarf::DW_LNCT_path, Section.OS);
|
||||
encodeULEB128(P.FileNames[0].Name.getForm(), Section.OS);
|
||||
|
||||
encodeULEB128(dwarf::DW_LNCT_directory_index, Section.OS);
|
||||
encodeULEB128(dwarf::DW_FORM_data1, Section.OS);
|
||||
}
|
||||
|
||||
// file_names_count (ULEB128).
|
||||
encodeULEB128(P.FileNames.size(), Section.OS);
|
||||
|
||||
// file_names (sequence of file name entries).
|
||||
for (auto File : P.FileNames) {
|
||||
std::optional<const char *> FileNameStr = dwarf::toString(File.Name);
|
||||
if (!FileNameStr) {
|
||||
U.warn("cann't read string from line table.");
|
||||
return;
|
||||
}
|
||||
|
||||
// A null-terminated string containing the full or relative path name of a
|
||||
// source file.
|
||||
Section.emitString(File.Name.getForm(), *FileNameStr);
|
||||
Section.emitIntVal(File.DirIdx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void emitLineTableProloguePayload(const DWARFDebugLine::Prologue &P,
|
||||
SectionDescriptor &Section) {
|
||||
// minimum_instruction_length (ubyte).
|
||||
Section.emitIntVal(P.MinInstLength, 1);
|
||||
if (P.FormParams.Version >= 4) {
|
||||
// maximum_operations_per_instruction (ubyte).
|
||||
Section.emitIntVal(P.MaxOpsPerInst, 1);
|
||||
}
|
||||
// default_is_stmt (ubyte).
|
||||
Section.emitIntVal(P.DefaultIsStmt, 1);
|
||||
// line_base (sbyte).
|
||||
Section.emitIntVal(P.LineBase, 1);
|
||||
// line_range (ubyte).
|
||||
Section.emitIntVal(P.LineRange, 1);
|
||||
// opcode_base (ubyte).
|
||||
Section.emitIntVal(P.OpcodeBase, 1);
|
||||
|
||||
// standard_opcode_lengths (array of ubyte).
|
||||
for (auto Length : P.StandardOpcodeLengths)
|
||||
Section.emitIntVal(Length, 1);
|
||||
|
||||
if (P.FormParams.Version < 5)
|
||||
emitLineTablePrologueV2IncludeAndFileTable(P, Section);
|
||||
else
|
||||
emitLineTablePrologueV5IncludeAndFileTable(P, Section);
|
||||
}
|
||||
|
||||
void emitLineTableRows(const DWARFDebugLine::LineTable &LineTable,
|
||||
SectionDescriptor &Section) {
|
||||
|
||||
MCDwarfLineTableParams Params;
|
||||
Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
|
||||
Params.DWARF2LineBase = LineTable.Prologue.LineBase;
|
||||
Params.DWARF2LineRange = LineTable.Prologue.LineRange;
|
||||
|
||||
SmallString<128> EncodingBuffer;
|
||||
|
||||
if (LineTable.Rows.empty()) {
|
||||
// We only have the dummy entry, dsymutil emits an entry with a 0
|
||||
// address in that case.
|
||||
MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),
|
||||
0, EncodingBuffer);
|
||||
Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// Line table state machine fields
|
||||
unsigned FileNum = 1;
|
||||
unsigned LastLine = 1;
|
||||
unsigned Column = 0;
|
||||
unsigned IsStatement = 1;
|
||||
unsigned Isa = 0;
|
||||
uint64_t Address = -1ULL;
|
||||
|
||||
unsigned RowsSinceLastSequence = 0;
|
||||
|
||||
for (const DWARFDebugLine::Row &Row : LineTable.Rows) {
|
||||
int64_t AddressDelta;
|
||||
if (Address == -1ULL) {
|
||||
Section.emitIntVal(dwarf::DW_LNS_extended_op, 1);
|
||||
encodeULEB128(Section.getFormParams().AddrSize + 1, Section.OS);
|
||||
Section.emitIntVal(dwarf::DW_LNE_set_address, 1);
|
||||
Section.emitIntVal(Row.Address.Address,
|
||||
Section.getFormParams().AddrSize);
|
||||
AddressDelta = 0;
|
||||
} else {
|
||||
AddressDelta =
|
||||
(Row.Address.Address - Address) / LineTable.Prologue.MinInstLength;
|
||||
}
|
||||
|
||||
// FIXME: code copied and transformed from
|
||||
// MCDwarf.cpp::EmitDwarfLineTable. We should find a way to share this
|
||||
// code, but the current compatibility requirement with classic dsymutil
|
||||
// makes it hard. Revisit that once this requirement is dropped.
|
||||
|
||||
if (FileNum != Row.File) {
|
||||
FileNum = Row.File;
|
||||
Section.emitIntVal(dwarf::DW_LNS_set_file, 1);
|
||||
encodeULEB128(FileNum, Section.OS);
|
||||
}
|
||||
if (Column != Row.Column) {
|
||||
Column = Row.Column;
|
||||
Section.emitIntVal(dwarf::DW_LNS_set_column, 1);
|
||||
encodeULEB128(Column, Section.OS);
|
||||
}
|
||||
|
||||
// FIXME: We should handle the discriminator here, but dsymutil doesn't
|
||||
// consider it, thus ignore it for now.
|
||||
|
||||
if (Isa != Row.Isa) {
|
||||
Isa = Row.Isa;
|
||||
Section.emitIntVal(dwarf::DW_LNS_set_isa, 1);
|
||||
encodeULEB128(Isa, Section.OS);
|
||||
}
|
||||
if (IsStatement != Row.IsStmt) {
|
||||
IsStatement = Row.IsStmt;
|
||||
Section.emitIntVal(dwarf::DW_LNS_negate_stmt, 1);
|
||||
}
|
||||
if (Row.BasicBlock)
|
||||
Section.emitIntVal(dwarf::DW_LNS_set_basic_block, 1);
|
||||
|
||||
if (Row.PrologueEnd)
|
||||
Section.emitIntVal(dwarf::DW_LNS_set_prologue_end, 1);
|
||||
|
||||
if (Row.EpilogueBegin)
|
||||
Section.emitIntVal(dwarf::DW_LNS_set_epilogue_begin, 1);
|
||||
|
||||
int64_t LineDelta = int64_t(Row.Line) - LastLine;
|
||||
if (!Row.EndSequence) {
|
||||
MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta,
|
||||
EncodingBuffer);
|
||||
Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
|
||||
EncodingBuffer.resize(0);
|
||||
Address = Row.Address.Address;
|
||||
LastLine = Row.Line;
|
||||
RowsSinceLastSequence++;
|
||||
} else {
|
||||
if (LineDelta) {
|
||||
Section.emitIntVal(dwarf::DW_LNS_advance_line, 1);
|
||||
encodeSLEB128(LineDelta, Section.OS);
|
||||
}
|
||||
if (AddressDelta) {
|
||||
Section.emitIntVal(dwarf::DW_LNS_advance_pc, 1);
|
||||
encodeULEB128(AddressDelta, Section.OS);
|
||||
}
|
||||
MCDwarfLineAddr::encode(*MC, Params,
|
||||
std::numeric_limits<int64_t>::max(), 0,
|
||||
EncodingBuffer);
|
||||
Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
|
||||
EncodingBuffer.resize(0);
|
||||
Address = -1ULL;
|
||||
LastLine = FileNum = IsStatement = 1;
|
||||
RowsSinceLastSequence = Column = Isa = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (RowsSinceLastSequence) {
|
||||
MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),
|
||||
0, EncodingBuffer);
|
||||
Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
|
||||
EncodingBuffer.resize(0);
|
||||
}
|
||||
}
|
||||
|
||||
Triple TheTriple;
|
||||
DwarfUnit &U;
|
||||
|
||||
std::unique_ptr<MCRegisterInfo> MRI;
|
||||
std::unique_ptr<MCAsmInfo> MAI;
|
||||
std::unique_ptr<MCContext> MC;
|
||||
std::unique_ptr<MCSubtargetInfo> MSTI;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_DWARFLINKERPARALLEL_DEBUGLINESECTIONEMITTER_H
|
428
llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
Normal file
428
llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
//=== DependencyTracker.cpp -----------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DependencyTracker.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// A broken link in the keep chain. By recording both the parent and the child
|
||||
/// we can show only broken links for DIEs with multiple children.
|
||||
struct BrokenLink {
|
||||
BrokenLink(DWARFDie Parent, DWARFDie Child) : Parent(Parent), Child(Child) {}
|
||||
DWARFDie Parent;
|
||||
DWARFDie Child;
|
||||
};
|
||||
|
||||
/// Verify the keep chain by looking for DIEs that are kept but who's parent
|
||||
/// isn't.
|
||||
void DependencyTracker::verifyKeepChain(CompileUnit &CU) {
|
||||
SmallVector<DWARFDie> Worklist;
|
||||
Worklist.push_back(CU.getOrigUnit().getUnitDIE());
|
||||
|
||||
// List of broken links.
|
||||
SmallVector<BrokenLink> BrokenLinks;
|
||||
|
||||
while (!Worklist.empty()) {
|
||||
const DWARFDie Current = Worklist.back();
|
||||
Worklist.pop_back();
|
||||
|
||||
if (!Current.isValid())
|
||||
continue;
|
||||
|
||||
const bool CurrentDieIsKept = CU.getDIEInfo(Current).getKeep() ||
|
||||
CU.getDIEInfo(Current).getKeepChildren();
|
||||
|
||||
for (DWARFDie Child : reverse(Current.children())) {
|
||||
Worklist.push_back(Child);
|
||||
|
||||
const bool ChildDieIsKept = CU.getDIEInfo(Child).getKeep() ||
|
||||
CU.getDIEInfo(Child).getKeepChildren();
|
||||
if (!CurrentDieIsKept && ChildDieIsKept)
|
||||
BrokenLinks.emplace_back(Current, Child);
|
||||
}
|
||||
}
|
||||
|
||||
if (!BrokenLinks.empty()) {
|
||||
for (BrokenLink Link : BrokenLinks) {
|
||||
WithColor::error() << formatv(
|
||||
"Found invalid link in keep chain between {0:x} and {1:x}\n",
|
||||
Link.Parent.getOffset(), Link.Child.getOffset());
|
||||
|
||||
errs() << "Parent:";
|
||||
Link.Parent.dump(errs(), 0, {});
|
||||
CU.getDIEInfo(Link.Parent).dump();
|
||||
|
||||
errs() << "Child:";
|
||||
Link.Child.dump(errs(), 2, {});
|
||||
CU.getDIEInfo(Link.Child).dump();
|
||||
}
|
||||
report_fatal_error("invalid keep chain");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool DependencyTracker::resolveDependenciesAndMarkLiveness(CompileUnit &CU) {
|
||||
// We do not track liveness inside Clang modules. We also do not track
|
||||
// liveness if UpdateIndexTablesOnly is requested.
|
||||
TrackLiveness = !(CU.isClangModule() ||
|
||||
CU.getGlobalData().getOptions().UpdateIndexTablesOnly);
|
||||
RootEntriesWorkList.clear();
|
||||
|
||||
// Search for live root DIEs.
|
||||
collectRootsToKeep(CU, CU.getDebugInfoEntry(0));
|
||||
|
||||
// Mark live DIEs as kept.
|
||||
return markLiveRootsAsKept();
|
||||
}
|
||||
|
||||
void DependencyTracker::collectRootsToKeep(CompileUnit &CU,
|
||||
const DWARFDebugInfoEntry *Entry) {
|
||||
if (!TrackLiveness) {
|
||||
addItemToWorklist(CU, Entry);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Entry->getTag()) {
|
||||
case dwarf::DW_TAG_subprogram:
|
||||
case dwarf::DW_TAG_label:
|
||||
if (isLiveSubprogramEntry(CU, Entry)) {
|
||||
addItemToWorklist(CU, Entry);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case dwarf::DW_TAG_compile_unit:
|
||||
case dwarf::DW_TAG_namespace:
|
||||
case dwarf::DW_TAG_module:
|
||||
case dwarf::DW_TAG_lexical_block: {
|
||||
for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(Entry);
|
||||
CurChild && CurChild->getAbbreviationDeclarationPtr();
|
||||
CurChild = CU.getSiblingEntry(CurChild))
|
||||
collectRootsToKeep(CU, CurChild);
|
||||
} break;
|
||||
case dwarf::DW_TAG_constant:
|
||||
case dwarf::DW_TAG_variable: {
|
||||
if (isLiveVariableEntry(CU, Entry))
|
||||
addItemToWorklist(CU, Entry);
|
||||
} break;
|
||||
case dwarf::DW_TAG_base_type: {
|
||||
addItemToWorklist(CU, Entry);
|
||||
} break;
|
||||
case dwarf::DW_TAG_imported_module:
|
||||
case dwarf::DW_TAG_imported_declaration:
|
||||
case dwarf::DW_TAG_imported_unit: {
|
||||
addItemToWorklist(CU, Entry);
|
||||
} break;
|
||||
default:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool DependencyTracker::markLiveRootsAsKept() {
|
||||
bool Res = true;
|
||||
|
||||
while (!RootEntriesWorkList.empty()) {
|
||||
RootEntryTy CurrentItem = RootEntriesWorkList.pop_back_val();
|
||||
|
||||
if (!markDIEEntryAsKeptRec(CurrentItem, CurrentItem.CU,
|
||||
CurrentItem.RootEntry))
|
||||
Res = false;
|
||||
}
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool DependencyTracker::markDIEEntryAsKeptRec(
|
||||
const RootEntryTy &RootItem, CompileUnit &CU,
|
||||
const DWARFDebugInfoEntry *Entry) {
|
||||
if (Entry->getAbbreviationDeclarationPtr() == nullptr)
|
||||
return true;
|
||||
|
||||
CompileUnit::DIEInfo &Info = CU.getDIEInfo(Entry);
|
||||
|
||||
if (Info.getKeep())
|
||||
return true;
|
||||
|
||||
// Mark parents as 'KeepChildren'.
|
||||
std::optional<uint32_t> ParentIdx = Entry->getParentIdx();
|
||||
while (ParentIdx) {
|
||||
const DWARFDebugInfoEntry *ParentEntry = CU.getDebugInfoEntry(*ParentIdx);
|
||||
CompileUnit::DIEInfo &ParentInfo = CU.getDIEInfo(*ParentIdx);
|
||||
if (ParentInfo.getKeepChildren())
|
||||
break;
|
||||
ParentInfo.setKeepChildren();
|
||||
ParentIdx = ParentEntry->getParentIdx();
|
||||
}
|
||||
|
||||
// Mark current DIE as kept.
|
||||
Info.setKeep();
|
||||
setDIEPlacementAndTypename(Info);
|
||||
|
||||
// Set liveness information.
|
||||
switch (Entry->getTag()) {
|
||||
case dwarf::DW_TAG_constant:
|
||||
case dwarf::DW_TAG_variable: {
|
||||
isLiveVariableEntry(CU, Entry);
|
||||
} break;
|
||||
case dwarf::DW_TAG_subprogram:
|
||||
case dwarf::DW_TAG_label: {
|
||||
isLiveSubprogramEntry(CU, Entry);
|
||||
} break;
|
||||
default:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
|
||||
// Analyse referenced DIEs.
|
||||
bool Res = true;
|
||||
if (!maybeAddReferencedRoots(RootItem, CU, Entry))
|
||||
Res = false;
|
||||
|
||||
// Navigate children.
|
||||
for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(Entry);
|
||||
CurChild && CurChild->getAbbreviationDeclarationPtr();
|
||||
CurChild = CU.getSiblingEntry(CurChild)) {
|
||||
if (!markDIEEntryAsKeptRec(RootItem, CU, CurChild))
|
||||
Res = false;
|
||||
}
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool DependencyTracker::maybeAddReferencedRoots(
|
||||
const RootEntryTy &RootItem, CompileUnit &CU,
|
||||
const DWARFDebugInfoEntry *Entry) {
|
||||
const auto *Abbrev = Entry->getAbbreviationDeclarationPtr();
|
||||
if (Abbrev == nullptr)
|
||||
return true;
|
||||
|
||||
DWARFUnit &Unit = CU.getOrigUnit();
|
||||
DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
|
||||
uint64_t Offset = Entry->getOffset() + getULEB128Size(Abbrev->getCode());
|
||||
|
||||
// For each DIE attribute...
|
||||
for (const auto &AttrSpec : Abbrev->attributes()) {
|
||||
DWARFFormValue Val(AttrSpec.Form);
|
||||
if (!Val.isFormClass(DWARFFormValue::FC_Reference) ||
|
||||
AttrSpec.Attr == dwarf::DW_AT_sibling) {
|
||||
DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
|
||||
Unit.getFormParams());
|
||||
continue;
|
||||
}
|
||||
Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
|
||||
|
||||
// Resolve reference.
|
||||
std::optional<std::pair<CompileUnit *, uint32_t>> RefDie =
|
||||
CU.resolveDIEReference(Val);
|
||||
if (!RefDie) {
|
||||
CU.warn("cann't find referenced DIE", Entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CU.getUniqueID() == RefDie->first->getUniqueID()) {
|
||||
// Check if referenced DIE entry is already kept.
|
||||
if (RefDie->first->getDIEInfo(RefDie->second).getKeep())
|
||||
continue;
|
||||
|
||||
// If referenced DIE is inside current compilation unit.
|
||||
const DWARFDebugInfoEntry *RefEntry =
|
||||
RefDie->first->getDebugInfoEntry(RefDie->second);
|
||||
|
||||
if (RootItem.RootEntry->getTag() == dwarf::DW_TAG_compile_unit)
|
||||
addItemToWorklist(*RefDie->first, RefEntry);
|
||||
else {
|
||||
uint64_t RootStartOffset = RootItem.RootEntry->getOffset();
|
||||
uint64_t RootEndOffset;
|
||||
if (std::optional<uint32_t> SiblingIdx =
|
||||
RootItem.RootEntry->getSiblingIdx()) {
|
||||
RootEndOffset =
|
||||
RootItem.CU.getDebugInfoEntry(*SiblingIdx)->getOffset();
|
||||
} else {
|
||||
RootEndOffset = RootItem.CU.getOrigUnit().getNextUnitOffset();
|
||||
}
|
||||
|
||||
// Do not put item in work list if it is an ancestor of RootItem.
|
||||
// (since we will visit and mark it as kept during normal traversing of
|
||||
// RootItem children)
|
||||
if (RootStartOffset > RefEntry->getOffset() ||
|
||||
RefEntry->getOffset() >= RootEndOffset)
|
||||
addItemToWorklist(*RefDie->first, RefEntry);
|
||||
}
|
||||
} else if (Context.InterCUProcessingStarted && RefDie->second != 0) {
|
||||
// If referenced DIE is in other compilation unit and
|
||||
// it is safe to navigate other units DIEs.
|
||||
addItemToWorklist(*RefDie->first,
|
||||
RefDie->first->getDebugInfoEntry(RefDie->second));
|
||||
} else {
|
||||
// Delay resolving reference.
|
||||
RefDie->first->setInterconnectedCU();
|
||||
CU.setInterconnectedCU();
|
||||
Context.HasNewInterconnectedCUs = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if the specified DIE type allows removing children.
|
||||
static bool childrenCanBeRemoved(uint32_t Tag) {
|
||||
switch (Tag) {
|
||||
default:
|
||||
return true;
|
||||
case dwarf::DW_TAG_class_type:
|
||||
case dwarf::DW_TAG_common_block:
|
||||
case dwarf::DW_TAG_lexical_block:
|
||||
case dwarf::DW_TAG_structure_type:
|
||||
case dwarf::DW_TAG_subprogram:
|
||||
case dwarf::DW_TAG_subroutine_type:
|
||||
case dwarf::DW_TAG_union_type:
|
||||
case dwarf::DW_TAG_array_type:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("Invalid Tag");
|
||||
}
|
||||
|
||||
void DependencyTracker::addItemToWorklist(CompileUnit &CU,
|
||||
const DWARFDebugInfoEntry *Entry) {
|
||||
if (Entry->getAbbreviationDeclarationPtr() == nullptr)
|
||||
return;
|
||||
|
||||
const DWARFDebugInfoEntry *EntryToAdd = Entry;
|
||||
|
||||
// If parent does not allow children removing then use that parent as a root
|
||||
// DIE.
|
||||
std::optional<uint32_t> ParentIdx = Entry->getParentIdx();
|
||||
while (ParentIdx) {
|
||||
const DWARFDebugInfoEntry *ParentEntry = CU.getDebugInfoEntry(*ParentIdx);
|
||||
if (childrenCanBeRemoved(ParentEntry->getTag()))
|
||||
break;
|
||||
EntryToAdd = ParentEntry;
|
||||
ParentIdx = ParentEntry->getParentIdx();
|
||||
}
|
||||
|
||||
// Check if the DIE entry is already kept.
|
||||
if (CU.getDIEInfo(EntryToAdd).getKeep())
|
||||
return;
|
||||
|
||||
RootEntriesWorkList.emplace_back(CU, EntryToAdd);
|
||||
}
|
||||
|
||||
bool DependencyTracker::isLiveVariableEntry(CompileUnit &CU,
|
||||
const DWARFDebugInfoEntry *Entry) {
|
||||
DWARFDie DIE = CU.getDIE(Entry);
|
||||
CompileUnit::DIEInfo &Info = CU.getDIEInfo(DIE);
|
||||
|
||||
if (TrackLiveness) {
|
||||
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
|
||||
|
||||
// Global variables with constant value can always be kept.
|
||||
if (!Info.getIsInFunctionScope() &&
|
||||
Abbrev->findAttributeIndex(dwarf::DW_AT_const_value))
|
||||
return true;
|
||||
|
||||
// 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
|
||||
// if the variable has a location expression address.
|
||||
// However, we don't want a static variable in a function to force us to
|
||||
// keep the enclosing function, unless requested explicitly.
|
||||
std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
|
||||
CU.getContaingFile().Addresses->getVariableRelocAdjustment(DIE);
|
||||
|
||||
if (!LocExprAddrAndRelocAdjustment.second)
|
||||
return false;
|
||||
|
||||
if ((Info.getIsInFunctionScope()) &&
|
||||
!LLVM_UNLIKELY(CU.getGlobalData().getOptions().KeepFunctionForStatic))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CU.getGlobalData().getOptions().Verbose) {
|
||||
outs() << "Keeping variable DIE:";
|
||||
DIDumpOptions DumpOpts;
|
||||
DumpOpts.ChildRecurseDepth = 0;
|
||||
DumpOpts.Verbose = CU.getGlobalData().getOptions().Verbose;
|
||||
DIE.dump(outs(), 8 /* Indent */, DumpOpts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DependencyTracker::isLiveSubprogramEntry(
|
||||
CompileUnit &CU, const DWARFDebugInfoEntry *Entry) {
|
||||
DWARFDie DIE = CU.getDIE(Entry);
|
||||
|
||||
std::optional<uint64_t> LowPc;
|
||||
std::optional<uint64_t> HighPc;
|
||||
std::optional<int64_t> RelocAdjustment;
|
||||
|
||||
if (TrackLiveness) {
|
||||
LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc));
|
||||
if (!LowPc)
|
||||
return false;
|
||||
|
||||
RelocAdjustment =
|
||||
CU.getContaingFile().Addresses->getSubprogramRelocAdjustment(DIE);
|
||||
if (!RelocAdjustment)
|
||||
return false;
|
||||
|
||||
if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
|
||||
// Validate subprogram address range.
|
||||
|
||||
HighPc = DIE.getHighPC(*LowPc);
|
||||
if (!HighPc) {
|
||||
CU.warn("function without high_pc. Range will be discarded.", &DIE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*LowPc > *HighPc) {
|
||||
CU.warn("low_pc greater than high_pc. Range will be discarded.", &DIE);
|
||||
return false;
|
||||
}
|
||||
} else if (DIE.getTag() == dwarf::DW_TAG_variable) {
|
||||
if (CU.hasLabelAt(*LowPc))
|
||||
return false;
|
||||
|
||||
// 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(
|
||||
CU.getOrigUnit().getUnitDIE().find(dwarf::DW_AT_high_pc))
|
||||
.value_or(UINT64_MAX) <= LowPc)
|
||||
return false;
|
||||
|
||||
CU.addLabelLowPc(*LowPc, *RelocAdjustment);
|
||||
}
|
||||
}
|
||||
|
||||
if (CU.getGlobalData().getOptions().Verbose) {
|
||||
outs() << "Keeping subprogram DIE:";
|
||||
DIDumpOptions DumpOpts;
|
||||
DumpOpts.ChildRecurseDepth = 0;
|
||||
DumpOpts.Verbose = CU.getGlobalData().getOptions().Verbose;
|
||||
DIE.dump(outs(), 8 /* Indent */, DumpOpts);
|
||||
}
|
||||
|
||||
if (!TrackLiveness || DIE.getTag() == dwarf::DW_TAG_label)
|
||||
return true;
|
||||
|
||||
CU.addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DependencyTracker::setDIEPlacementAndTypename(CompileUnit::DIEInfo &Info) {
|
||||
Info.setPlacement(CompileUnit::PlainDwarf);
|
||||
}
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // namespace llvm
|
102
llvm/lib/DWARFLinkerParallel/DependencyTracker.h
Normal file
102
llvm/lib/DWARFLinkerParallel/DependencyTracker.h
Normal file
@ -0,0 +1,102 @@
|
||||
//===- "DependencyTracker.h" ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H
|
||||
|
||||
#include "DWARFLinkerCompileUnit.h"
|
||||
#include "DWARFLinkerImpl.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace llvm {
|
||||
class DWARFDebugInfoEntry;
|
||||
class DWARFDie;
|
||||
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
/// This class discovers DIEs dependencies and marks "live" DIEs.
|
||||
class DependencyTracker {
|
||||
public:
|
||||
DependencyTracker(DWARFLinkerImpl::LinkContext &Context) : Context(Context) {}
|
||||
|
||||
/// Recursively walk the \p DIE tree and look for DIEs to 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 and(through the mediation of
|
||||
/// Context.File.Addresses) ask for relocation adjustment value on each
|
||||
/// DIE that might be a 'root DIE'.
|
||||
///
|
||||
/// Returns true if all dependencies are correctly discovered. Inter-CU
|
||||
/// dependencies cannot be discovered if referenced CU is not analyzed yet.
|
||||
/// If that is the case this method returns false.
|
||||
bool resolveDependenciesAndMarkLiveness(CompileUnit &CU);
|
||||
|
||||
/// Recursively walk the \p DIE tree and check "keepness" information.
|
||||
/// It is an error if parent node does not have "keep" flag, while
|
||||
/// child have one. This function dump error at stderr in that case.
|
||||
#ifndef NDEBUG
|
||||
static void verifyKeepChain(CompileUnit &CU);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
struct RootEntryTy {
|
||||
RootEntryTy(CompileUnit &CU, const DWARFDebugInfoEntry *RootEntry)
|
||||
: CU(CU), RootEntry(RootEntry) {}
|
||||
|
||||
// Compile unit keeping root entry.
|
||||
CompileUnit &CU;
|
||||
|
||||
// Root entry.
|
||||
const DWARFDebugInfoEntry *RootEntry;
|
||||
};
|
||||
|
||||
using RootEntriesListTy = SmallVector<RootEntryTy>;
|
||||
|
||||
/// This function navigates DIEs tree starting from specified \p Entry.
|
||||
/// It puts 'root DIE' into the worklist.
|
||||
void collectRootsToKeep(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
|
||||
|
||||
/// Returns true if specified variable references live code section.
|
||||
bool isLiveVariableEntry(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
|
||||
|
||||
/// Returns true if specified subprogram references live code section.
|
||||
bool isLiveSubprogramEntry(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
|
||||
|
||||
/// Examine worklist and mark all 'root DIE's as kept.
|
||||
bool markLiveRootsAsKept();
|
||||
|
||||
/// Mark whole DIE tree as kept recursively.
|
||||
bool markDIEEntryAsKeptRec(const RootEntryTy &RootItem, CompileUnit &CU,
|
||||
const DWARFDebugInfoEntry *Entry);
|
||||
|
||||
/// Check referenced DIEs and add them into the worklist if neccessary.
|
||||
bool maybeAddReferencedRoots(const RootEntryTy &RootItem, CompileUnit &CU,
|
||||
const DWARFDebugInfoEntry *Entry);
|
||||
|
||||
/// Add 'root DIE' into the worklist.
|
||||
void addItemToWorklist(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
|
||||
|
||||
/// Set kind of placement(whether it goes into type table, plain dwarf or
|
||||
/// both) for the specified die \p DieIdx.
|
||||
void setDIEPlacementAndTypename(CompileUnit::DIEInfo &Info);
|
||||
|
||||
/// Flag indicating whether liveness information should be examined.
|
||||
bool TrackLiveness = false;
|
||||
|
||||
/// List of CU, Entry pairs which are 'root DIE's.
|
||||
RootEntriesListTy RootEntriesWorkList;
|
||||
|
||||
/// Link context for the analyzed CU.
|
||||
DWARFLinkerImpl::LinkContext &Context;
|
||||
};
|
||||
|
||||
} // end namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H
|
49
llvm/lib/DWARFLinkerParallel/IndexedValuesMap.h
Normal file
49
llvm/lib/DWARFLinkerParallel/IndexedValuesMap.h
Normal file
@ -0,0 +1,49 @@
|
||||
//===- IndexedValuesMap.h ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_INDEXEDVALUESMAP_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_INDEXEDVALUESMAP_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
template <typename T> class IndexedValuesMap {
|
||||
public:
|
||||
uint64_t getValueIndex(T Value) {
|
||||
typename ValueToIndexMapTy::iterator It = ValueToIndexMap.find(Value);
|
||||
if (It == ValueToIndexMap.end()) {
|
||||
It = ValueToIndexMap.insert(std::make_pair(Value, Values.size())).first;
|
||||
Values.push_back(Value);
|
||||
}
|
||||
return It->second;
|
||||
}
|
||||
|
||||
const SmallVector<T> &getValues() { return Values; }
|
||||
|
||||
void clear() {
|
||||
ValueToIndexMap.clear();
|
||||
Values.clear();
|
||||
}
|
||||
|
||||
bool empty() { return Values.empty(); }
|
||||
|
||||
protected:
|
||||
using ValueToIndexMapTy = DenseMap<T, uint64_t>;
|
||||
ValueToIndexMapTy ValueToIndexMap;
|
||||
SmallVector<T> Values;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_DWARFLINKERPARALLEL_INDEXEDVALUESMAP_H
|
@ -7,30 +7,400 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "OutputSections.h"
|
||||
#include "DWARFLinkerCompileUnit.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
std::optional<OutputSections::DebugSectionKind>
|
||||
OutputSections::parseDebugSectionName(llvm::StringRef SecName) {
|
||||
return llvm::StringSwitch<std::optional<OutputSections::DebugSectionKind>>(
|
||||
SecName)
|
||||
.Case("debug_info", DebugSectionKind::DebugInfo)
|
||||
.Case("debug_line", DebugSectionKind::DebugLine)
|
||||
.Case("debug_frame", DebugSectionKind::DebugFrame)
|
||||
.Case("debug_ranges", DebugSectionKind::DebugRange)
|
||||
.Case("debug_rnglists", DebugSectionKind::DebugRngLists)
|
||||
.Case("debug_loc", DebugSectionKind::DebugLoc)
|
||||
.Case("debug_loclists", DebugSectionKind::DebugLocLists)
|
||||
.Case("debug_aranges", DebugSectionKind::DebugARanges)
|
||||
.Case("debug_abbrev", DebugSectionKind::DebugAbbrev)
|
||||
.Case("debug_macinfo", DebugSectionKind::DebugMacinfo)
|
||||
.Case("debug_macro", DebugSectionKind::DebugMacro)
|
||||
static constexpr StringLiteral SectionNames[SectionKindsNum] = {
|
||||
"debug_info", "debug_line", "debug_frame", "debug_ranges",
|
||||
"debug_rnglists", "debug_loc", "debug_loclists", "debug_aranges",
|
||||
"debug_abbrev", "debug_macinfo", "debug_macro", "debug_addr",
|
||||
"debug_str", "debug_line_str", "debug_str_offsets"};
|
||||
|
||||
const StringLiteral &getSectionName(DebugSectionKind SectionKind) {
|
||||
return SectionNames[static_cast<uint8_t>(SectionKind)];
|
||||
}
|
||||
|
||||
std::optional<DebugSectionKind> parseDebugTableName(llvm::StringRef SecName) {
|
||||
return llvm::StringSwitch<std::optional<DebugSectionKind>>(
|
||||
SecName.substr(SecName.find_first_not_of("._")))
|
||||
.Case(getSectionName(DebugSectionKind::DebugInfo),
|
||||
DebugSectionKind::DebugInfo)
|
||||
.Case(getSectionName(DebugSectionKind::DebugLine),
|
||||
DebugSectionKind::DebugLine)
|
||||
.Case(getSectionName(DebugSectionKind::DebugFrame),
|
||||
DebugSectionKind::DebugFrame)
|
||||
.Case(getSectionName(DebugSectionKind::DebugRange),
|
||||
DebugSectionKind::DebugRange)
|
||||
.Case(getSectionName(DebugSectionKind::DebugRngLists),
|
||||
DebugSectionKind::DebugRngLists)
|
||||
.Case(getSectionName(DebugSectionKind::DebugLoc),
|
||||
DebugSectionKind::DebugLoc)
|
||||
.Case(getSectionName(DebugSectionKind::DebugLocLists),
|
||||
DebugSectionKind::DebugLocLists)
|
||||
.Case(getSectionName(DebugSectionKind::DebugARanges),
|
||||
DebugSectionKind::DebugARanges)
|
||||
.Case(getSectionName(DebugSectionKind::DebugAbbrev),
|
||||
DebugSectionKind::DebugAbbrev)
|
||||
.Case(getSectionName(DebugSectionKind::DebugMacinfo),
|
||||
DebugSectionKind::DebugMacinfo)
|
||||
.Case(getSectionName(DebugSectionKind::DebugMacro),
|
||||
DebugSectionKind::DebugMacro)
|
||||
.Case(getSectionName(DebugSectionKind::DebugAddr),
|
||||
DebugSectionKind::DebugAddr)
|
||||
.Case(getSectionName(DebugSectionKind::DebugStr),
|
||||
DebugSectionKind::DebugStr)
|
||||
.Case(getSectionName(DebugSectionKind::DebugLineStr),
|
||||
DebugSectionKind::DebugLineStr)
|
||||
.Case(getSectionName(DebugSectionKind::DebugStrOffsets),
|
||||
DebugSectionKind::DebugStrOffsets)
|
||||
.Default(std::nullopt);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
DebugDieRefPatch::DebugDieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU,
|
||||
CompileUnit *RefCU, uint32_t RefIdx)
|
||||
: SectionPatch({PatchOffset}),
|
||||
RefCU(RefCU, (SrcCU != nullptr) &&
|
||||
(SrcCU->getUniqueID() == RefCU->getUniqueID())),
|
||||
RefDieIdxOrClonedOffset(RefIdx) {}
|
||||
|
||||
DebugULEB128DieRefPatch::DebugULEB128DieRefPatch(uint64_t PatchOffset,
|
||||
CompileUnit *SrcCU,
|
||||
CompileUnit *RefCU,
|
||||
uint32_t RefIdx)
|
||||
: SectionPatch({PatchOffset}),
|
||||
RefCU(RefCU, SrcCU->getUniqueID() == RefCU->getUniqueID()),
|
||||
RefDieIdxOrClonedOffset(RefIdx) {}
|
||||
|
||||
void SectionDescriptor::erase() {
|
||||
StartOffset = 0;
|
||||
Contents = OutSectionDataTy();
|
||||
ListDebugStrPatch.erase();
|
||||
ListDebugLineStrPatch.erase();
|
||||
ListDebugRangePatch.erase();
|
||||
ListDebugLocPatch.erase();
|
||||
ListDebugDieRefPatch.erase();
|
||||
ListDebugULEB128DieRefPatch.erase();
|
||||
ListDebugOffsetPatch.erase();
|
||||
}
|
||||
|
||||
void SectionDescriptor::setSizesForSectionCreatedByAsmPrinter() {
|
||||
if (Contents.empty())
|
||||
return;
|
||||
|
||||
MemoryBufferRef Mem(Contents, "obj");
|
||||
Expected<std::unique_ptr<object::ObjectFile>> Obj =
|
||||
object::ObjectFile::createObjectFile(Mem);
|
||||
if (!Obj) {
|
||||
consumeError(Obj.takeError());
|
||||
Contents.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const object::SectionRef &Sect : (*Obj).get()->sections()) {
|
||||
Expected<StringRef> SectNameOrErr = Sect.getName();
|
||||
if (!SectNameOrErr) {
|
||||
consumeError(SectNameOrErr.takeError());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::optional<DebugSectionKind> SectKind =
|
||||
parseDebugTableName(*SectNameOrErr)) {
|
||||
if (*SectKind == SectionKind) {
|
||||
Expected<StringRef> Data = Sect.getContents();
|
||||
if (!Data) {
|
||||
consumeError(SectNameOrErr.takeError());
|
||||
Contents.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
SectionOffsetInsideAsmPrinterOutputStart =
|
||||
Data->data() - Contents.data();
|
||||
SectionOffsetInsideAsmPrinterOutputEnd =
|
||||
SectionOffsetInsideAsmPrinterOutputStart + Data->size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void SectionDescriptor::emitIntVal(uint64_t Val, unsigned Size) {
|
||||
switch (Size) {
|
||||
case 1: {
|
||||
OS.write(static_cast<uint8_t>(Val));
|
||||
} break;
|
||||
case 2: {
|
||||
uint16_t ShortVal = static_cast<uint16_t>(Val);
|
||||
if ((Endianess == support::endianness::little) != sys::IsLittleEndianHost)
|
||||
sys::swapByteOrder(ShortVal);
|
||||
OS.write(reinterpret_cast<const char *>(&ShortVal), Size);
|
||||
} break;
|
||||
case 4: {
|
||||
uint32_t ShortVal = static_cast<uint32_t>(Val);
|
||||
if ((Endianess == support::endianness::little) != sys::IsLittleEndianHost)
|
||||
sys::swapByteOrder(ShortVal);
|
||||
OS.write(reinterpret_cast<const char *>(&ShortVal), Size);
|
||||
} break;
|
||||
case 8: {
|
||||
if ((Endianess == support::endianness::little) != sys::IsLittleEndianHost)
|
||||
sys::swapByteOrder(Val);
|
||||
OS.write(reinterpret_cast<const char *>(&Val), Size);
|
||||
} break;
|
||||
default:
|
||||
llvm_unreachable("Unsupported integer type size");
|
||||
}
|
||||
}
|
||||
|
||||
void SectionDescriptor::emitString(dwarf::Form StringForm,
|
||||
const char *StringVal) {
|
||||
assert(StringVal != nullptr);
|
||||
|
||||
switch (StringForm) {
|
||||
case dwarf::DW_FORM_string: {
|
||||
emitInplaceString(GlobalData.translateString(StringVal));
|
||||
} break;
|
||||
case dwarf::DW_FORM_strp: {
|
||||
notePatch(DebugStrPatch{
|
||||
{OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
|
||||
emitStringPlaceholder();
|
||||
} break;
|
||||
case dwarf::DW_FORM_line_strp: {
|
||||
notePatch(DebugLineStrPatch{
|
||||
{OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
|
||||
emitStringPlaceholder();
|
||||
} break;
|
||||
default:
|
||||
llvm_unreachable("Unsupported string form");
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void SectionDescriptor::apply(uint64_t PatchOffset, dwarf::Form AttrForm,
|
||||
uint64_t Val) {
|
||||
switch (AttrForm) {
|
||||
case dwarf::DW_FORM_strp:
|
||||
case dwarf::DW_FORM_line_strp: {
|
||||
applyIntVal(PatchOffset, Val, Format.getDwarfOffsetByteSize());
|
||||
} break;
|
||||
|
||||
case dwarf::DW_FORM_ref_addr: {
|
||||
applyIntVal(PatchOffset, Val, Format.getRefAddrByteSize());
|
||||
} break;
|
||||
case dwarf::DW_FORM_ref1: {
|
||||
applyIntVal(PatchOffset, Val, 1);
|
||||
} break;
|
||||
case dwarf::DW_FORM_ref2: {
|
||||
applyIntVal(PatchOffset, Val, 2);
|
||||
} break;
|
||||
case dwarf::DW_FORM_ref4: {
|
||||
applyIntVal(PatchOffset, Val, 4);
|
||||
} break;
|
||||
case dwarf::DW_FORM_ref8: {
|
||||
applyIntVal(PatchOffset, Val, 8);
|
||||
} break;
|
||||
|
||||
case dwarf::DW_FORM_data1: {
|
||||
applyIntVal(PatchOffset, Val, 1);
|
||||
} break;
|
||||
case dwarf::DW_FORM_data2: {
|
||||
applyIntVal(PatchOffset, Val, 2);
|
||||
} break;
|
||||
case dwarf::DW_FORM_data4: {
|
||||
applyIntVal(PatchOffset, Val, 4);
|
||||
} break;
|
||||
case dwarf::DW_FORM_data8: {
|
||||
applyIntVal(PatchOffset, Val, 8);
|
||||
} break;
|
||||
case dwarf::DW_FORM_udata: {
|
||||
applyULEB128(PatchOffset, Val);
|
||||
} break;
|
||||
case dwarf::DW_FORM_sdata: {
|
||||
applySLEB128(PatchOffset, Val);
|
||||
} break;
|
||||
case dwarf::DW_FORM_sec_offset: {
|
||||
applyIntVal(PatchOffset, Val, Format.getDwarfOffsetByteSize());
|
||||
} break;
|
||||
case dwarf::DW_FORM_flag: {
|
||||
applyIntVal(PatchOffset, Val, 1);
|
||||
} break;
|
||||
|
||||
default:
|
||||
llvm_unreachable("Unsupported attribute form");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t SectionDescriptor::getIntVal(uint64_t PatchOffset, unsigned Size) {
|
||||
assert(PatchOffset < getContents().size());
|
||||
switch (Size) {
|
||||
case 1: {
|
||||
return *reinterpret_cast<const uint8_t *>(
|
||||
(getContents().data() + PatchOffset));
|
||||
}
|
||||
case 2: {
|
||||
return support::endian::read16(getContents().data() + PatchOffset,
|
||||
Endianess);
|
||||
}
|
||||
case 4: {
|
||||
return support::endian::read32(getContents().data() + PatchOffset,
|
||||
Endianess);
|
||||
}
|
||||
case 8: {
|
||||
return support::endian::read64(getContents().data() + PatchOffset,
|
||||
Endianess);
|
||||
}
|
||||
}
|
||||
llvm_unreachable("Unsupported integer type size");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SectionDescriptor::applyIntVal(uint64_t PatchOffset, uint64_t Val,
|
||||
unsigned Size) {
|
||||
assert(PatchOffset < getContents().size());
|
||||
|
||||
switch (Size) {
|
||||
case 1: {
|
||||
support::endian::write(
|
||||
const_cast<char *>(getContents().data() + PatchOffset),
|
||||
static_cast<uint8_t>(Val), Endianess);
|
||||
} break;
|
||||
case 2: {
|
||||
support::endian::write(
|
||||
const_cast<char *>(getContents().data() + PatchOffset),
|
||||
static_cast<uint16_t>(Val), Endianess);
|
||||
} break;
|
||||
case 4: {
|
||||
support::endian::write(
|
||||
const_cast<char *>(getContents().data() + PatchOffset),
|
||||
static_cast<uint32_t>(Val), Endianess);
|
||||
} break;
|
||||
case 8: {
|
||||
support::endian::write(
|
||||
const_cast<char *>(getContents().data() + PatchOffset),
|
||||
static_cast<uint64_t>(Val), Endianess);
|
||||
} break;
|
||||
default:
|
||||
llvm_unreachable("Unsupported integer type size");
|
||||
}
|
||||
}
|
||||
|
||||
void SectionDescriptor::applyULEB128(uint64_t PatchOffset, uint64_t Val) {
|
||||
assert(PatchOffset < getContents().size());
|
||||
|
||||
uint8_t ULEB[16];
|
||||
uint8_t DestSize = Format.getDwarfOffsetByteSize() + 1;
|
||||
uint8_t RealSize = encodeULEB128(Val, ULEB, DestSize);
|
||||
|
||||
memcpy(const_cast<char *>(getContents().data() + PatchOffset), ULEB,
|
||||
RealSize);
|
||||
}
|
||||
|
||||
/// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset.
|
||||
void SectionDescriptor::applySLEB128(uint64_t PatchOffset, uint64_t Val) {
|
||||
assert(PatchOffset < getContents().size());
|
||||
|
||||
uint8_t SLEB[16];
|
||||
uint8_t DestSize = Format.getDwarfOffsetByteSize() + 1;
|
||||
uint8_t RealSize = encodeSLEB128(Val, SLEB, DestSize);
|
||||
|
||||
memcpy(const_cast<char *>(getContents().data() + PatchOffset), SLEB,
|
||||
RealSize);
|
||||
}
|
||||
|
||||
void OutputSections::applyPatches(
|
||||
SectionDescriptor &Section,
|
||||
StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
|
||||
StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings) {
|
||||
|
||||
Section.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) {
|
||||
DwarfStringPoolEntryWithExtString *Entry =
|
||||
DebugStrStrings.getExistingEntry(Patch.String);
|
||||
assert(Entry != nullptr);
|
||||
|
||||
Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset);
|
||||
});
|
||||
|
||||
Section.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) {
|
||||
DwarfStringPoolEntryWithExtString *Entry =
|
||||
DebugLineStrStrings.getExistingEntry(Patch.String);
|
||||
assert(Entry != nullptr);
|
||||
|
||||
Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset);
|
||||
});
|
||||
|
||||
std::optional<SectionDescriptor *> RangeSection;
|
||||
if (Format.Version >= 5)
|
||||
RangeSection = getSectionDescriptor(DebugSectionKind::DebugRngLists);
|
||||
else
|
||||
RangeSection = getSectionDescriptor(DebugSectionKind::DebugRange);
|
||||
|
||||
if (RangeSection) {
|
||||
Section.ListDebugRangePatch.forEach([&](DebugRangePatch &Patch) {
|
||||
uint64_t FinalValue =
|
||||
Section.getIntVal(Patch.PatchOffset, Format.getDwarfOffsetByteSize());
|
||||
FinalValue += (*RangeSection)->StartOffset;
|
||||
|
||||
Section.apply(Patch.PatchOffset, dwarf::DW_FORM_sec_offset, FinalValue);
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<SectionDescriptor *> LocationSection;
|
||||
if (Format.Version >= 5)
|
||||
LocationSection = getSectionDescriptor(DebugSectionKind::DebugLocLists);
|
||||
else
|
||||
LocationSection = getSectionDescriptor(DebugSectionKind::DebugLoc);
|
||||
|
||||
if (LocationSection) {
|
||||
Section.ListDebugLocPatch.forEach([&](DebugLocPatch &Patch) {
|
||||
uint64_t FinalValue =
|
||||
Section.getIntVal(Patch.PatchOffset, Format.getDwarfOffsetByteSize());
|
||||
FinalValue += (*LocationSection)->StartOffset;
|
||||
|
||||
Section.apply(Patch.PatchOffset, dwarf::DW_FORM_sec_offset, FinalValue);
|
||||
});
|
||||
}
|
||||
|
||||
Section.ListDebugDieRefPatch.forEach([&](DebugDieRefPatch &Patch) {
|
||||
uint64_t FinalOffset = Patch.RefDieIdxOrClonedOffset;
|
||||
dwarf::Form FinalForm = dwarf::DW_FORM_ref4;
|
||||
|
||||
if (!Patch.RefCU.getInt()) {
|
||||
std::optional<SectionDescriptor *> ReferencedSectionDescriptor =
|
||||
Patch.RefCU.getPointer()->getSectionDescriptor(
|
||||
DebugSectionKind::DebugInfo);
|
||||
if (!ReferencedSectionDescriptor) {
|
||||
// Referenced section should be already created at this point.
|
||||
llvm_unreachable("Referenced section does not exist");
|
||||
}
|
||||
|
||||
FinalForm = dwarf::DW_FORM_ref_addr;
|
||||
FinalOffset += (*ReferencedSectionDescriptor)->StartOffset;
|
||||
}
|
||||
|
||||
Section.apply(Patch.PatchOffset, FinalForm, FinalOffset);
|
||||
});
|
||||
|
||||
Section.ListDebugULEB128DieRefPatch.forEach(
|
||||
[&](DebugULEB128DieRefPatch &Patch) {
|
||||
assert(Patch.RefCU.getInt());
|
||||
Section.apply(Patch.PatchOffset, dwarf::DW_FORM_udata,
|
||||
Patch.RefDieIdxOrClonedOffset);
|
||||
});
|
||||
|
||||
Section.ListDebugOffsetPatch.forEach([&](DebugOffsetPatch &Patch) {
|
||||
uint64_t FinalValue = Patch.SectionPtr.getPointer()->StartOffset;
|
||||
if (Patch.SectionPtr.getInt())
|
||||
FinalValue +=
|
||||
Section.getIntVal(Patch.PatchOffset, Format.getDwarfOffsetByteSize());
|
||||
|
||||
Section.apply(Patch.PatchOffset, dwarf::DW_FORM_sec_offset, FinalValue);
|
||||
});
|
||||
}
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end of namespace llvm
|
||||
|
@ -9,56 +9,397 @@
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
|
||||
|
||||
#include "ArrayList.h"
|
||||
#include "StringEntryToDwarfStringPoolEntryMap.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
|
||||
#include "llvm/DWARFLinkerParallel/StringPool.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFObject.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
#include "llvm/Support/MemoryBufferRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
/// This class keeps offsets to the debug sections. Any object which is
|
||||
/// supposed to be emitted into the debug section should use this class to
|
||||
/// track debug sections offsets.
|
||||
class OutputSections {
|
||||
public:
|
||||
/// List of tracked debug sections.
|
||||
enum class DebugSectionKind : uint8_t {
|
||||
DebugInfo = 0,
|
||||
DebugLine,
|
||||
DebugFrame,
|
||||
DebugRange,
|
||||
DebugRngLists,
|
||||
DebugLoc,
|
||||
DebugLocLists,
|
||||
DebugARanges,
|
||||
DebugAbbrev,
|
||||
DebugMacinfo,
|
||||
DebugMacro,
|
||||
};
|
||||
constexpr static size_t SectionKindsNum = 11;
|
||||
/// List of tracked debug tables.
|
||||
enum class DebugSectionKind : uint8_t {
|
||||
DebugInfo = 0,
|
||||
DebugLine,
|
||||
DebugFrame,
|
||||
DebugRange,
|
||||
DebugRngLists,
|
||||
DebugLoc,
|
||||
DebugLocLists,
|
||||
DebugARanges,
|
||||
DebugAbbrev,
|
||||
DebugMacinfo,
|
||||
DebugMacro,
|
||||
DebugAddr,
|
||||
DebugStr,
|
||||
DebugLineStr,
|
||||
DebugStrOffsets,
|
||||
NumberOfEnumEntries // must be last
|
||||
};
|
||||
constexpr static size_t SectionKindsNum =
|
||||
static_cast<size_t>(DebugSectionKind::NumberOfEnumEntries);
|
||||
|
||||
/// Recognise the section name and match it with the DebugSectionKind.
|
||||
static std::optional<DebugSectionKind> parseDebugSectionName(StringRef Name);
|
||||
/// Recognise the table name and match it with the DebugSectionKind.
|
||||
std::optional<DebugSectionKind> parseDebugTableName(StringRef Name);
|
||||
|
||||
/// Return the name of the section.
|
||||
const StringLiteral &getSectionName(DebugSectionKind SectionKind);
|
||||
|
||||
/// There are fields(sizes, offsets) which should be updated after
|
||||
/// sections are generated. To remember offsets and related data
|
||||
/// the descendants of SectionPatch structure should be used.
|
||||
|
||||
struct SectionPatch {
|
||||
uint64_t PatchOffset = 0;
|
||||
};
|
||||
|
||||
/// This structure is used to update strings offsets into .debug_str.
|
||||
struct DebugStrPatch : SectionPatch {
|
||||
const StringEntry *String = nullptr;
|
||||
};
|
||||
|
||||
/// This structure is used to update strings offsets into .debug_line_str.
|
||||
struct DebugLineStrPatch : SectionPatch {
|
||||
const StringEntry *String = nullptr;
|
||||
};
|
||||
|
||||
/// This structure is used to update range list offset into
|
||||
/// .debug_ranges/.debug_rnglists.
|
||||
struct DebugRangePatch : SectionPatch {
|
||||
/// Indicates patch which points to immediate compile unit's attribute.
|
||||
bool IsCompileUnitRanges = false;
|
||||
};
|
||||
|
||||
/// This structure is used to update location list offset into
|
||||
/// .debug_loc/.debug_loclists.
|
||||
struct DebugLocPatch : SectionPatch {
|
||||
int64_t AddrAdjustmentValue = 0;
|
||||
};
|
||||
|
||||
/// This structure is used to update offset with start of another section.
|
||||
struct SectionDescriptor;
|
||||
struct DebugOffsetPatch : SectionPatch {
|
||||
DebugOffsetPatch(uint64_t PatchOffset, SectionDescriptor *SectionPtr,
|
||||
bool AddLocalValue = false)
|
||||
: SectionPatch({PatchOffset}), SectionPtr(SectionPtr, AddLocalValue) {}
|
||||
|
||||
PointerIntPair<SectionDescriptor *, 1> SectionPtr;
|
||||
};
|
||||
|
||||
/// This structure is used to update reference to the DIE.
|
||||
struct DebugDieRefPatch : SectionPatch {
|
||||
DebugDieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU, CompileUnit *RefCU,
|
||||
uint32_t RefIdx);
|
||||
|
||||
PointerIntPair<CompileUnit *, 1> RefCU;
|
||||
uint64_t RefDieIdxOrClonedOffset;
|
||||
};
|
||||
|
||||
/// This structure is used to update reference to the DIE of ULEB128 form.
|
||||
struct DebugULEB128DieRefPatch : SectionPatch {
|
||||
DebugULEB128DieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU,
|
||||
CompileUnit *RefCU, uint32_t RefIdx);
|
||||
|
||||
PointerIntPair<CompileUnit *, 1> RefCU;
|
||||
uint64_t RefDieIdxOrClonedOffset;
|
||||
};
|
||||
|
||||
/// Type for section data.
|
||||
using OutSectionDataTy = SmallString<0>;
|
||||
|
||||
/// Type for list of pointers to patches offsets.
|
||||
using OffsetsPtrVector = SmallVector<uint64_t *>;
|
||||
|
||||
class OutputSections;
|
||||
|
||||
/// This structure is used to keep data of the concrete section.
|
||||
/// Like data bits, list of patches, format.
|
||||
struct SectionDescriptor {
|
||||
friend OutputSections;
|
||||
|
||||
SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,
|
||||
dwarf::FormParams Format, support::endianness Endianess)
|
||||
: OS(Contents), GlobalData(GlobalData), SectionKind(SectionKind),
|
||||
Format(Format), Endianess(Endianess) {
|
||||
ListDebugStrPatch.setAllocator(&GlobalData.getAllocator());
|
||||
ListDebugLineStrPatch.setAllocator(&GlobalData.getAllocator());
|
||||
ListDebugRangePatch.setAllocator(&GlobalData.getAllocator());
|
||||
ListDebugLocPatch.setAllocator(&GlobalData.getAllocator());
|
||||
ListDebugDieRefPatch.setAllocator(&GlobalData.getAllocator());
|
||||
ListDebugULEB128DieRefPatch.setAllocator(&GlobalData.getAllocator());
|
||||
ListDebugOffsetPatch.setAllocator(&GlobalData.getAllocator());
|
||||
}
|
||||
|
||||
/// Erase whole section contents(data bits, list of patches, format).
|
||||
void erase();
|
||||
|
||||
/// When objects(f.e. compile units) are glued into the single file,
|
||||
/// the debug sections corresponding to the concrete object are assigned
|
||||
/// with offsets inside the whole file. This method returns offset
|
||||
/// to the \p SectionKind debug section, corresponding to this object.
|
||||
uint64_t getStartOffset(DebugSectionKind SectionKind) const {
|
||||
return Offsets[static_cast<
|
||||
typename std::underlying_type<DebugSectionKind>::type>(SectionKind)];
|
||||
/// with offsets inside the whole file. This field keeps offset
|
||||
/// to the debug section, corresponding to this object.
|
||||
uint64_t StartOffset = 0;
|
||||
|
||||
/// Stream which stores data to the Contents.
|
||||
raw_svector_ostream OS;
|
||||
|
||||
/// Section patches.
|
||||
#define ADD_PATCHES_LIST(T) \
|
||||
T ¬ePatch(const T &Patch) { return List##T.noteItem(Patch); } \
|
||||
ArrayList<T> List##T;
|
||||
|
||||
ADD_PATCHES_LIST(DebugStrPatch)
|
||||
ADD_PATCHES_LIST(DebugLineStrPatch)
|
||||
ADD_PATCHES_LIST(DebugRangePatch)
|
||||
ADD_PATCHES_LIST(DebugLocPatch)
|
||||
ADD_PATCHES_LIST(DebugDieRefPatch)
|
||||
ADD_PATCHES_LIST(DebugULEB128DieRefPatch)
|
||||
ADD_PATCHES_LIST(DebugOffsetPatch)
|
||||
|
||||
/// Offsets to some fields are not known at the moment of noting patch.
|
||||
/// In that case we remember pointers to patch offset to update them later.
|
||||
template <typename T>
|
||||
void notePatchWithOffsetUpdate(const T &Patch,
|
||||
OffsetsPtrVector &PatchesOffsetsList) {
|
||||
PatchesOffsetsList.emplace_back(¬ePatch(Patch).PatchOffset);
|
||||
}
|
||||
|
||||
/// Set offset to the start of specified \p SectionKind debug section,
|
||||
/// corresponding to this object.
|
||||
void setStartOffset(DebugSectionKind SectionKind, uint64_t Offset) {
|
||||
Offsets[static_cast<typename std::underlying_type<DebugSectionKind>::type>(
|
||||
SectionKind)] = Offset;
|
||||
/// Some sections are emitted using AsmPrinter. In that case "Contents"
|
||||
/// member of SectionDescriptor contains elf file. This method searches
|
||||
/// for section data inside elf file and remember offset to it.
|
||||
void setSizesForSectionCreatedByAsmPrinter();
|
||||
|
||||
/// Returns section content.
|
||||
StringRef getContents() {
|
||||
if (SectionOffsetInsideAsmPrinterOutputStart == 0)
|
||||
return StringRef(Contents.data(), Contents.size());
|
||||
|
||||
return Contents.slice(SectionOffsetInsideAsmPrinterOutputStart,
|
||||
SectionOffsetInsideAsmPrinterOutputEnd);
|
||||
}
|
||||
|
||||
/// Emit unit length into the current section contents.
|
||||
void emitUnitLength(uint64_t Length) {
|
||||
maybeEmitDwarf64Mark();
|
||||
emitIntVal(Length, getFormParams().getDwarfOffsetByteSize());
|
||||
}
|
||||
|
||||
/// Emit DWARF64 mark into the current section contents.
|
||||
void maybeEmitDwarf64Mark() {
|
||||
if (getFormParams().Format != dwarf::DWARF64)
|
||||
return;
|
||||
emitIntVal(dwarf::DW_LENGTH_DWARF64, 4);
|
||||
}
|
||||
|
||||
/// Emit specified offset value into the current section contents.
|
||||
void emitOffset(uint64_t Val) {
|
||||
emitIntVal(Val, getFormParams().getDwarfOffsetByteSize());
|
||||
}
|
||||
|
||||
/// Emit specified integer value into the current section contents.
|
||||
void emitIntVal(uint64_t Val, unsigned Size);
|
||||
|
||||
/// Emit specified string value into the current section contents.
|
||||
void emitString(dwarf::Form StringForm, const char *StringVal);
|
||||
|
||||
/// Emit specified inplace string value into the current section contents.
|
||||
void emitInplaceString(StringRef String) {
|
||||
OS << String;
|
||||
emitIntVal(0, 1);
|
||||
}
|
||||
|
||||
/// Emit string placeholder into the current section contents.
|
||||
void emitStringPlaceholder() {
|
||||
// emit bad offset which should be updated later.
|
||||
emitOffset(0xBADDEF);
|
||||
}
|
||||
|
||||
/// Write specified \p Value of \p AttrForm to the \p PatchOffset.
|
||||
void apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val);
|
||||
|
||||
/// Returns section kind.
|
||||
DebugSectionKind getKind() { return SectionKind; }
|
||||
|
||||
/// Returns section name.
|
||||
const StringLiteral &getName() const { return getSectionName(SectionKind); }
|
||||
|
||||
/// Returns endianess used by section.
|
||||
support::endianness getEndianess() const { return Endianess; }
|
||||
|
||||
/// Returns FormParams used by section.
|
||||
dwarf::FormParams getFormParams() const { return Format; }
|
||||
|
||||
/// Returns integer value of \p Size located by specified \p PatchOffset.
|
||||
uint64_t getIntVal(uint64_t PatchOffset, unsigned Size);
|
||||
|
||||
protected:
|
||||
/// Offsets to the debug sections composing this object.
|
||||
std::array<uint64_t, SectionKindsNum> Offsets = {0};
|
||||
/// Writes integer value \p Val of \p Size by specified \p PatchOffset.
|
||||
void applyIntVal(uint64_t PatchOffset, uint64_t Val, unsigned Size);
|
||||
|
||||
/// Writes integer value \p Val of ULEB128 format by specified \p PatchOffset.
|
||||
void applyULEB128(uint64_t PatchOffset, uint64_t Val);
|
||||
|
||||
/// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset.
|
||||
void applySLEB128(uint64_t PatchOffset, uint64_t Val);
|
||||
|
||||
/// Sets output format.
|
||||
void setOutputFormat(dwarf::FormParams Format,
|
||||
support::endianness Endianess) {
|
||||
this->Format = Format;
|
||||
this->Endianess = Endianess;
|
||||
}
|
||||
|
||||
LinkingGlobalData &GlobalData;
|
||||
|
||||
/// The section kind.
|
||||
DebugSectionKind SectionKind = DebugSectionKind::NumberOfEnumEntries;
|
||||
|
||||
/// Section data bits.
|
||||
OutSectionDataTy Contents;
|
||||
|
||||
/// Some sections are generated using AsmPrinter. The real section data
|
||||
/// located inside elf file in that case. Following fields points to the
|
||||
/// real section content inside elf file.
|
||||
size_t SectionOffsetInsideAsmPrinterOutputStart = 0;
|
||||
size_t SectionOffsetInsideAsmPrinterOutputEnd = 0;
|
||||
|
||||
/// Output format.
|
||||
dwarf::FormParams Format = {4, 4, dwarf::DWARF32};
|
||||
support::endianness Endianess = support::endianness::little;
|
||||
};
|
||||
|
||||
/// This class keeps contents and offsets to the debug sections. Any objects
|
||||
/// which is supposed to be emitted into the debug sections should use this
|
||||
/// class to track debug sections offsets and keep sections data.
|
||||
class OutputSections {
|
||||
public:
|
||||
OutputSections(LinkingGlobalData &GlobalData) : GlobalData(GlobalData) {}
|
||||
|
||||
/// Sets output format for all keeping sections.
|
||||
void setOutputFormat(DWARFUnit &OriginalUnit) {
|
||||
setOutputFormat(OriginalUnit.getFormParams(),
|
||||
OriginalUnit.isLittleEndian() ? support::endianness::little
|
||||
: support::endianness::big);
|
||||
}
|
||||
|
||||
/// Sets output format for all keeping sections.
|
||||
void setOutputFormat(dwarf::FormParams Format,
|
||||
support::endianness Endianess) {
|
||||
this->Format = Format;
|
||||
this->Endianess = Endianess;
|
||||
}
|
||||
|
||||
/// Returns descriptor for the specified section of \p SectionKind.
|
||||
std::optional<const SectionDescriptor *>
|
||||
getSectionDescriptor(DebugSectionKind SectionKind) const {
|
||||
SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);
|
||||
|
||||
if (It == SectionDescriptors.end())
|
||||
return std::nullopt;
|
||||
|
||||
return &It->second;
|
||||
}
|
||||
|
||||
/// Returns descriptor for the specified section of \p SectionKind.
|
||||
std::optional<SectionDescriptor *>
|
||||
getSectionDescriptor(DebugSectionKind SectionKind) {
|
||||
SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);
|
||||
|
||||
if (It == SectionDescriptors.end())
|
||||
return std::nullopt;
|
||||
|
||||
return &It->second;
|
||||
}
|
||||
|
||||
/// Returns descriptor for the specified section of \p SectionKind.
|
||||
/// If descriptor does not exist then create it.
|
||||
SectionDescriptor &
|
||||
getOrCreateSectionDescriptor(DebugSectionKind SectionKind) {
|
||||
return SectionDescriptors
|
||||
.try_emplace(SectionKind, SectionKind, GlobalData, Format, Endianess)
|
||||
.first->second;
|
||||
}
|
||||
|
||||
/// Erases data of all sections.
|
||||
void eraseSections() {
|
||||
for (auto &Section : SectionDescriptors)
|
||||
Section.second.erase();
|
||||
}
|
||||
|
||||
/// Enumerate all sections and call \p Handler for each.
|
||||
void forEach(function_ref<void(SectionDescriptor &)> Handler) {
|
||||
for (auto &Section : SectionDescriptors)
|
||||
Handler(Section.second);
|
||||
}
|
||||
|
||||
/// Enumerate all sections, for each section set current offset
|
||||
/// (kept by \p SectionSizesAccumulator), update current offset with section
|
||||
/// length.
|
||||
void assignSectionsOffsetAndAccumulateSize(
|
||||
std::array<uint64_t, SectionKindsNum> &SectionSizesAccumulator) {
|
||||
for (auto &Section : SectionDescriptors) {
|
||||
Section.second.StartOffset = SectionSizesAccumulator[static_cast<uint8_t>(
|
||||
Section.second.getKind())];
|
||||
SectionSizesAccumulator[static_cast<uint8_t>(Section.second.getKind())] +=
|
||||
Section.second.getContents().size();
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumerate all sections, for each section apply all section patches.
|
||||
void applyPatches(SectionDescriptor &Section,
|
||||
StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
|
||||
StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings);
|
||||
|
||||
/// Endiannes for the sections.
|
||||
support::endianness getEndianness() const { return Endianess; }
|
||||
|
||||
/// Return DWARF version.
|
||||
uint16_t getVersion() const { return Format.Version; }
|
||||
|
||||
/// Return size of header of debug_info table.
|
||||
uint16_t getDebugInfoHeaderSize() const {
|
||||
return Format.Version >= 5 ? 12 : 11;
|
||||
}
|
||||
|
||||
/// Return size of header of debug_ table.
|
||||
uint16_t getDebugAddrHeaderSize() const {
|
||||
assert(Format.Version >= 5);
|
||||
return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
|
||||
}
|
||||
|
||||
/// Return size of header of debug_str_offsets table.
|
||||
uint16_t getDebugStrOffsetsHeaderSize() const {
|
||||
assert(Format.Version >= 5);
|
||||
return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
|
||||
}
|
||||
|
||||
/// Return size of address.
|
||||
const dwarf::FormParams &getFormParams() const { return Format; }
|
||||
|
||||
protected:
|
||||
LinkingGlobalData &GlobalData;
|
||||
|
||||
/// Format for sections.
|
||||
dwarf::FormParams Format = {4, 4, dwarf::DWARF32};
|
||||
|
||||
/// Endiannes for sections.
|
||||
support::endianness Endianess = support::endianness::little;
|
||||
|
||||
/// All keeping sections.
|
||||
using SectionsSetTy = std::map<DebugSectionKind, SectionDescriptor>;
|
||||
SectionsSetTy SectionDescriptors;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
|
@ -0,0 +1,72 @@
|
||||
//===- StringEntryToDwarfStringPoolEntryMap.h -------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_STRINGENTRYTODWARFSTRINGPOOLENTRYMAP_H
|
||||
#define LLVM_LIB_DWARFLINKERPARALLEL_STRINGENTRYTODWARFSTRINGPOOLENTRYMAP_H
|
||||
|
||||
#include "DWARFLinkerGlobalData.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/DWARFLinkerParallel/StringPool.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace dwarflinker_parallel {
|
||||
|
||||
/// This class creates a DwarfStringPoolEntry for the corresponding StringEntry.
|
||||
class StringEntryToDwarfStringPoolEntryMap {
|
||||
public:
|
||||
StringEntryToDwarfStringPoolEntryMap(LinkingGlobalData &GlobalData)
|
||||
: GlobalData(GlobalData) {}
|
||||
~StringEntryToDwarfStringPoolEntryMap() {}
|
||||
|
||||
/// Create DwarfStringPoolEntry for specified StringEntry if necessary.
|
||||
/// Initialize DwarfStringPoolEntry with initial values.
|
||||
DwarfStringPoolEntryWithExtString *add(const StringEntry *String) {
|
||||
DwarfStringPoolEntriesTy::iterator it = DwarfStringPoolEntries.find(String);
|
||||
|
||||
if (it == DwarfStringPoolEntries.end()) {
|
||||
DwarfStringPoolEntryWithExtString *DataPtr =
|
||||
GlobalData.getAllocator()
|
||||
.Allocate<DwarfStringPoolEntryWithExtString>();
|
||||
DataPtr->String = GlobalData.translateString(String->getKey());
|
||||
DataPtr->Index = DwarfStringPoolEntry::NotIndexed;
|
||||
DataPtr->Offset = 0;
|
||||
DataPtr->Symbol = nullptr;
|
||||
it = DwarfStringPoolEntries.insert(std::make_pair(String, DataPtr)).first;
|
||||
}
|
||||
|
||||
assert(it->second != nullptr);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/// Returns already existed DwarfStringPoolEntry for the specified
|
||||
/// StringEntry.
|
||||
DwarfStringPoolEntryWithExtString *
|
||||
getExistingEntry(const StringEntry *String) const {
|
||||
DwarfStringPoolEntriesTy::const_iterator it =
|
||||
DwarfStringPoolEntries.find(String);
|
||||
|
||||
assert(it != DwarfStringPoolEntries.end());
|
||||
assert(it->second != nullptr);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/// Erase contents of StringsForEmission.
|
||||
void clear() { DwarfStringPoolEntries.clear(); }
|
||||
|
||||
protected:
|
||||
using DwarfStringPoolEntriesTy =
|
||||
DenseMap<const StringEntry *, DwarfStringPoolEntryWithExtString *>;
|
||||
DwarfStringPoolEntriesTy DwarfStringPoolEntries;
|
||||
|
||||
LinkingGlobalData &GlobalData;
|
||||
};
|
||||
|
||||
} // end of namespace dwarflinker_parallel
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_DWARFLINKERPARALLEL_STRINGENTRYTODWARFSTRINGPOOLENTRYMAP_H
|
@ -0,0 +1,200 @@
|
||||
; This test checks to ensure that if a DWARF v5 and DWARF v4 object file is used to
|
||||
; generate a dsym, dsymutil correctly outputs the debug information, by keeping
|
||||
; the DWARF v5 and DWARF v4 debug info distinct, and that all the section headers
|
||||
; have the correct format.
|
||||
|
||||
; 1.o was produced with the source file:
|
||||
|
||||
; a.cpp
|
||||
; __attribute__((section("1,__text_foo"))) void foo() {}
|
||||
;
|
||||
; int foo2(int a) {
|
||||
; return a+5;
|
||||
; }
|
||||
; int main () {
|
||||
; return 1;
|
||||
; }
|
||||
|
||||
; clang -g -c -O1 a.cpp -Xclang -gdwarf-5 -o 1.o
|
||||
|
||||
; 2.o was produced with the following source file:
|
||||
|
||||
; b.cpp
|
||||
; __attribute__((section("1,__text_foo2"))) void foo2() {}
|
||||
;
|
||||
; int bar(int x) {
|
||||
; int y = x + 2;
|
||||
; return y;
|
||||
; }
|
||||
|
||||
; clang -g -c -O1 b.cpp -gdwarf-4 -o 2.o
|
||||
|
||||
|
||||
RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: dsymutil --linker llvm -y %p/../dummy-debug-map-amr64.map \
|
||||
RUN: -oso-prepend-path=%p/../../Inputs/DWARF5-DWARF4-combination \
|
||||
RUN: -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM -a --verbose | FileCheck %s
|
||||
|
||||
|
||||
CHECK:.debug_abbrev contents:
|
||||
CHECK-NEXT: Abbrev table for offset: 0x00000000
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
|
||||
CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 14.0.3 (clang-1403.0.22.14.1)")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000001) string = "a.cpp")
|
||||
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")
|
||||
CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) string = "MacOSX.sdk")
|
||||
CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485")
|
||||
CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[RANGELIST_OFFSET:[0-9a-f]+]]
|
||||
CHECK-NEXT: [0x[[RANGELIST_OFFSET_START:[0-9a-f]+]], 0x[[RANGELIST_OFFSET_END:[0-9a-f]+]]))
|
||||
CHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
|
||||
CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c)
|
||||
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[#%.16x,LOCLIST_LOWPC:]])
|
||||
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000005) string = "_Z4foo2i")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000006) string = "foo2")
|
||||
CHECK: 0x0000003c: DW_TAG_formal_parameter [3] (0x0000002c)
|
||||
CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOCLIST_OFFSET:[0-9a-f]+]]:
|
||||
CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START:]], 0x[[#%.16x,LOCLIST_PAIR_END:]]): [[LOCLIST_EXPR:.*]]
|
||||
CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START2:]], 0x[[#%.16x,LOCLIST_PAIR_END2:]]): [[LOCLIST_EXPR2:.*]])
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000007) string = "a")
|
||||
|
||||
CHECK: 0x0000004e: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = 0x005a, addr_size = 0x08
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple clang version 14.0.3 (clang-1403.0.22.14.1)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000e0] = "b.cpp")
|
||||
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strp] ( .debug_str[0x00000039] = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")
|
||||
CHECK: DW_AT_APPLE_sdk [DW_FORM_strp] ( .debug_str[0x00000098] = "MacOSX.sdk")
|
||||
CHECK-NOT: DW_AT_str_offsets_base
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x000000a3] = "/Users/shubham/Development/test109275485")
|
||||
CHECK: DW_AT_low_pc [DW_FORM_addr] (0x[[#%.16x,RANGE_LOWPC:]])
|
||||
CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
|
||||
CHECK-NEXT: [0x[[#%.16x,RANGE_START:]], 0x[[#%.16x,RANGE_END:]]))
|
||||
CHECK: 0x00000080: DW_TAG_subprogram {{.*}} * (0x00000059)
|
||||
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x[[#%.16x,LOC_LOWPC:]])
|
||||
CHECK: DW_AT_linkage_name [DW_FORM_strp] ( .debug_str[0x000000e6] = "_Z3bari")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000ee] = "bar")
|
||||
CHECK: 0x0000009d: DW_TAG_formal_parameter {{.*}} (0x00000080)
|
||||
CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOC_OFFSET:[0-9a-f]+]]:
|
||||
CHECK-NEXT: [0x[[#%.16x,LOC_PAIR_START:]], 0x[[#%.16x,LOC_PAIR_END:]]): [[LOC_EXPR:.*]]
|
||||
CHECK-NEXT: [0x[[#%.16x,LOC_PAIR_START2:]], 0x[[#%.16x,LOC_PAIR_END2:]]): [[LOC_EXPR2:.*]])
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000f2] = "x")
|
||||
|
||||
CHECK: .debug_loc contents:
|
||||
CHECK-NEXT: 0x[[LOC_OFFSET]]:
|
||||
CHECK-NEXT: (0x[[#sub(LOC_PAIR_START,LOC_LOWPC)]], 0x[[#sub(LOC_PAIR_END,LOC_LOWPC)]]): [[LOC_EXPR:.*]]
|
||||
CHECK-NEXT: (0x[[#sub(LOC_PAIR_START2,LOC_LOWPC)]], 0x[[#sub(LOC_PAIR_END2,LOC_LOWPC)]]): [[LOC_EXPR2:.*]]
|
||||
|
||||
CHECK: .debug_loclists contents:
|
||||
CHECK-NEXT: 0x00000000: locations list header: length = 0x00000018, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
|
||||
CHECK-NEXT: 0x[[LOCLIST_OFFSET]]:
|
||||
CHECK-NEXT: DW_LLE_base_addressx (0x0000000000000000)
|
||||
CHECK-NEXT: DW_LLE_offset_pair (0x[[#sub(LOCLIST_PAIR_START,LOCLIST_LOWPC)]], 0x[[#sub(LOCLIST_PAIR_END,LOCLIST_LOWPC)]])
|
||||
CHECK-NEXT: DW_LLE_offset_pair (0x[[#sub(LOCLIST_PAIR_START2,LOCLIST_LOWPC)]], 0x[[#sub(LOCLIST_PAIR_END2,LOCLIST_LOWPC)]])
|
||||
CHECK-NEXT: DW_LLE_end_of_list ()
|
||||
|
||||
CHECK: .debug_line contents:
|
||||
CHECK-NEXT: debug_line[0x00000000]
|
||||
CHECK-NEXT: Line table prologue:
|
||||
CHECK-NEXT: total_length: 0x00000048
|
||||
CHECK-NEXT: format: DWARF32
|
||||
CHECK-NEXT: version: 5
|
||||
CHECK-NEXT: address_size: 8
|
||||
CHECK-NEXT: seg_select_size: 0
|
||||
CHECK-NEXT: prologue_length: 0x00000025
|
||||
CHECK-NEXT: min_inst_length: 1
|
||||
CHECK-NEXT: max_ops_per_inst: 1
|
||||
CHECK-NEXT: default_is_stmt: 1
|
||||
CHECK-NEXT: line_base: -5
|
||||
CHECK-NEXT: line_range: 14
|
||||
CHECK-NEXT: opcode_base: 13
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_copy] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_advance_pc] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_advance_line] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_file] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_column] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_negate_stmt] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_basic_block] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_const_add_pc] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_isa] = 1
|
||||
CHECK-NEXT: include_directories[ 0] = .debug_line_str[0x00000000] = "/Users/shubham/Development/test109275485"
|
||||
CHECK-NEXT: file_names[ 0]:
|
||||
CHECK-NEXT: name: .debug_line_str[0x00000029] = "a.cpp"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
|
||||
CHECK: debug_line[0x0000004c]
|
||||
CHECK-NEXT: Line table prologue:
|
||||
CHECK-NEXT: total_length: 0x0000003b
|
||||
CHECK-NEXT: format: DWARF32
|
||||
CHECK-NEXT: version: 4
|
||||
CHECK-NEXT: prologue_length: 0x0000001d
|
||||
CHECK-NEXT: min_inst_length: 1
|
||||
CHECK-NEXT: max_ops_per_inst: 1
|
||||
CHECK-NEXT: default_is_stmt: 1
|
||||
CHECK-NEXT: line_base: -5
|
||||
CHECK-NEXT: line_range: 14
|
||||
CHECK-NEXT: opcode_base: 13
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_copy] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_advance_pc] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_advance_line] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_file] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_column] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_negate_stmt] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_basic_block] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_const_add_pc] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_isa] = 1
|
||||
CHECK-NEXT: file_names[ 1]:
|
||||
CHECK-NEXT: name: "b.cpp"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK-NEXT: mod_time: 0x00000000
|
||||
CHECK-NEXT: length: 0x00000000
|
||||
|
||||
CHECK: .debug_str contents:
|
||||
CHECK-NEXT: 0x00000000: ""
|
||||
CHECK-NEXT: 0x00000001: "Apple clang version 14.0.3 (clang-1403.0.22.14.1)"
|
||||
CHECK-NEXT: 0x00000033: "a.cpp"
|
||||
CHECK-NEXT: 0x00000039: "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
|
||||
CHECK-NEXT: 0x00000098: "MacOSX.sdk"
|
||||
CHECK-NEXT: 0x000000a3: "/Users/shubham/Development/test109275485"
|
||||
CHECK-NEXT: 0x000000cc: "_Z4foo2i"
|
||||
CHECK-NEXT: 0x000000d5: "foo2"
|
||||
CHECK-NEXT: 0x000000da: "a"
|
||||
CHECK-NEXT: 0x000000dc: "int"
|
||||
CHECK-NEXT: 0x000000e0: "b.cpp"
|
||||
CHECK-NEXT: 0x000000e6: "_Z3bari"
|
||||
CHECK-NEXT: 0x000000ee: "bar"
|
||||
CHECK-NEXT: 0x000000f2: "x"
|
||||
CHECK-NEXT: 0x000000f4: "y"
|
||||
|
||||
CHECK: .debug_line_str contents:
|
||||
CHECK-NEXT: 0x00000000: "/Users/shubham/Development/test109275485"
|
||||
CHECK-NEXT: 0x00000029: "a.cpp"
|
||||
|
||||
CHECK: .debug_ranges contents:
|
||||
CHECK-NEXT: 00000000 [[#sub(RANGE_START,RANGE_LOWPC)]] [[#sub(RANGE_END,RANGE_LOWPC)]]
|
||||
|
||||
CHECK: .debug_rnglists contents:
|
||||
CHECK-NEXT: 0x00000000: range list header: length = 0x0000000e, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
|
||||
CHECK-NEXT: ranges:
|
||||
CHECK-NEXT: [[RANGELIST_OFFSET]]: [DW_RLE_base_addressx]: 0x0000000000000000
|
||||
CHECK-NEXT: 0x0000000e: [DW_RLE_offset_pair ]: {{.*}}[0x[[RANGELIST_OFFSET_START]], 0x[[RANGELIST_OFFSET_END]])
|
||||
CHECK-NEXT: 0x00000011: [DW_RLE_end_of_list ]
|
||||
|
||||
CHECK: .debug_str_offsets contents:
|
||||
CHECK-NEXT: 0x00000000: Contribution size = 40, Format = DWARF32, Version = 5
|
||||
CHECK-NEXT: 0x00000008: 00000001 "Apple clang version 14.0.3 (clang-1403.0.22.14.1)"
|
||||
CHECK-NEXT: 0x0000000c: 00000033 "a.cpp"
|
||||
CHECK-NEXT: 0x00000010: 00000039 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
|
||||
CHECK-NEXT: 0x00000014: 00000098 "MacOSX.sdk"
|
||||
CHECK-NEXT: 0x00000018: 000000a3 "/Users/shubham/Development/test109275485"
|
||||
CHECK-NEXT: 0x0000001c: 000000cc "_Z4foo2i"
|
||||
CHECK-NEXT: 0x00000020: 000000d5 "foo2"
|
||||
CHECK-NEXT: 0x00000024: 000000da "a"
|
||||
CHECK-NEXT: 0x00000028: 000000dc "int"
|
@ -0,0 +1,92 @@
|
||||
; This test checks to that DWARF v5 debug info can be correctly linked
|
||||
; into a dSYM bundle by dsymutil, with the correct section names and DWARF v5
|
||||
; headers for the different sections.
|
||||
|
||||
; 1.o was produced with the source file:
|
||||
|
||||
; a.cpp
|
||||
; __attribute__((section("1,__text_foo"))) void foo() {}
|
||||
;
|
||||
; int foo2(int a) {
|
||||
; return a+5;
|
||||
; }
|
||||
; int main () {
|
||||
; return 1;
|
||||
; }
|
||||
|
||||
; clang -g -c -O1 a.cpp -Xclang -gdwarf-5 -o 1.o
|
||||
|
||||
|
||||
RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: dsymutil --linker llvm -y %p/../dummy-debug-map-amr64.map \
|
||||
RUN: -oso-prepend-path=%p/../../Inputs/DWARF5 -o %t.dir/dwarf5-macho.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s
|
||||
|
||||
CHECK:.debug_abbrev contents:
|
||||
CHECK-NEXT: Abbrev table for offset: 0x00000000
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK-NEXT: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
|
||||
CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[RANGELIST_OFFSET:[0-9a-f]+]]
|
||||
CHECK-NEXT: [0x[[RANGELIST_OFFSET_START:[0-9a-f]+]], 0x[[RANGELIST_OFFSET_END:[0-9a-f]+]]))
|
||||
CHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
|
||||
CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c)
|
||||
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[#%.16x,LOCLIST_LOWPC:]])
|
||||
CHECK: 0x0000003c: DW_TAG_formal_parameter [3] (0x0000002c)
|
||||
CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOC_OFFSET:[0-9a-f]+]]:
|
||||
CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START:]], 0x[[#%.16x,LOCLIST_PAIR_END:]]): [[LOCLIST_EXPR:.*]]
|
||||
CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START2:]], 0x[[#%.16x,LOCLIST_PAIR_END2:]]): [[LOCLIST_EXPR2:.*]])
|
||||
|
||||
CHECK: .debug_loclists contents:
|
||||
CHECK-NEXT: 0x00000000: locations list header: length = 0x00000018, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
|
||||
CHECK-NEXT: 0x[[LOC_OFFSET]]:
|
||||
CHECK-NEXT: DW_LLE_base_addressx (0x0000000000000000)
|
||||
CHECK-NEXT: DW_LLE_offset_pair (0x[[#sub(LOCLIST_PAIR_START,LOCLIST_LOWPC)]], 0x[[#sub(LOCLIST_PAIR_END,LOCLIST_LOWPC)]])
|
||||
CHECK-NEXT: DW_LLE_offset_pair (0x[[#sub(LOCLIST_PAIR_START2,LOCLIST_LOWPC)]], 0x[[#sub(LOCLIST_PAIR_END2,LOCLIST_LOWPC)]])
|
||||
CHECK-NEXT: DW_LLE_end_of_list ()
|
||||
|
||||
CHECK: .debug_line contents:
|
||||
CHECK-NEXT: debug_line[0x00000000]
|
||||
CHECK-NEXT: Line table prologue:
|
||||
CHECK-NEXT: total_length: 0x00000048
|
||||
CHECK-NEXT: format: DWARF32
|
||||
CHECK-NEXT: version: 5
|
||||
CHECK-NEXT: address_size: 8
|
||||
CHECK-NEXT: seg_select_size: 0
|
||||
CHECK-NEXT: prologue_length: 0x00000025
|
||||
CHECK-NEXT: min_inst_length: 1
|
||||
CHECK-NEXT: max_ops_per_inst: 1
|
||||
CHECK-NEXT: default_is_stmt: 1
|
||||
CHECK-NEXT: line_base: -5
|
||||
CHECK-NEXT: line_range: 14
|
||||
CHECK-NEXT: opcode_base: 13
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_copy] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_advance_pc] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_advance_line] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_file] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_column] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_negate_stmt] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_basic_block] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_const_add_pc] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
|
||||
CHECK-NEXT: standard_opcode_lengths[DW_LNS_set_isa] = 1
|
||||
CHECK-NEXT: include_directories[ 0] = .debug_line_str[0x00000000] = "/Users/shubham/Development/test109275485"
|
||||
CHECK-NEXT: file_names[ 0]:
|
||||
CHECK-NEXT: name: .debug_line_str[0x00000029] = "a.cpp"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
|
||||
|
||||
CHECK: .debug_str contents:
|
||||
|
||||
CHECK: .debug_line_str contents:
|
||||
CHECK-NEXT: 0x00000000: "/Users/shubham/Development/test109275485"
|
||||
CHECK-NEXT: 0x00000029: "a.cpp"
|
||||
|
||||
CHECK: .debug_rnglists contents:
|
||||
CHECK-NEXT: 0x00000000: range list header: length = 0x0000000e, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
|
||||
CHECK-NEXT: ranges:
|
||||
CHECK-NEXT: [[RANGELIST_OFFSET]]: [DW_RLE_base_addressx]: 0x0000000000000000
|
||||
CHECK-NEXT: 0x0000000e: [DW_RLE_offset_pair ]: {{.*}}[0x[[RANGELIST_OFFSET_START]], 0x[[RANGELIST_OFFSET_END]])
|
||||
CHECK-NEXT: 0x00000011: [DW_RLE_end_of_list ]
|
@ -0,0 +1,110 @@
|
||||
# REQUIRES: object-emission,system-darwin
|
||||
# RUN: dsymutil --linker llvm -oso-prepend-path %p/../.. %p/../../Inputs/fat-test.arm.dylib -o %t.dSYM
|
||||
# RUN: llvm-dwarfdump -a -v %t.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s
|
||||
# RUN: dsymutil --linker llvm -u %t.dSYM
|
||||
# RUN: llvm-dwarfdump -a -v %t.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s
|
||||
# RUN: dsymutil --linker llvm -u %t.dSYM -o %t1.dSYM
|
||||
# RUN: llvm-dwarfdump -a -v %t1.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s
|
||||
|
||||
CHECK: /Contents/Resources/DWARF/fat-test.arm.dylib(armv7): file format Mach-O arm
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK: Compile Unit: length = 0x00000034, format = DWARF32, version = 0x0002, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x00000038)
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "clang version 3.8.0 (trunk 243776)")
|
||||
CHECK: DW_AT_language [DW_FORM_data2] (DW_LANG_C99)
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000024] = "fat-test.c")
|
||||
CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x00000000)
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x0000002f] = "/Inputs")
|
||||
CHECK: DW_TAG_variable [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000037] = "armv7_var")
|
||||
CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0030 => {0x00000030}
|
||||
CHECK: DW_AT_external [DW_FORM_flag] (0x01)
|
||||
CHECK: DW_AT_decl_file [DW_FORM_data1] ("/Inputs/fat-test.c")
|
||||
CHECK: DW_AT_decl_line [DW_FORM_data1] (23)
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (DW_OP_addr 0x1000)
|
||||
CHECK: DW_TAG_base_type [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000041] = "int")
|
||||
CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed)
|
||||
CHECK: DW_AT_byte_size [DW_FORM_data1] (0x04)
|
||||
CHECK: NULL
|
||||
|
||||
|
||||
CHECK: .debug_line contents:
|
||||
CHECK: Line table prologue:
|
||||
CHECK: total_length: 0x0000002a
|
||||
CHECK: version: 2
|
||||
CHECK: prologue_length: 0x00000021
|
||||
CHECK: min_inst_length: 1
|
||||
CHECK: default_is_stmt: 1
|
||||
CHECK: line_base: -5
|
||||
CHECK: line_range: 14
|
||||
CHECK: opcode_base: 13
|
||||
|
||||
CHECK: /Contents/Resources/DWARF/fat-test.arm.dylib(armv7s): file format Mach-O arm
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK: Compile Unit: length = 0x00000034, format = DWARF32, version = 0x0002, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x00000038)
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "clang version 3.8.0 (trunk 243776)")
|
||||
CHECK: DW_AT_language [DW_FORM_data2] (DW_LANG_C99)
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000024] = "fat-test.c")
|
||||
CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x00000000)
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x0000002f] = "/Inputs")
|
||||
CHECK: DW_TAG_variable [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000037] = "armv7s_var")
|
||||
CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0030 => {0x00000030}
|
||||
CHECK: DW_AT_external [DW_FORM_flag] (0x01)
|
||||
CHECK: DW_AT_decl_file [DW_FORM_data1] ("/Inputs/fat-test.c")
|
||||
CHECK: DW_AT_decl_line [DW_FORM_data1] (21)
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (DW_OP_addr 0x1000)
|
||||
CHECK: DW_TAG_base_type [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000042] = "int")
|
||||
CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed)
|
||||
CHECK: DW_AT_byte_size [DW_FORM_data1] (0x04)
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: .debug_line contents:
|
||||
CHECK: Line table prologue:
|
||||
CHECK: total_length: 0x0000002a
|
||||
CHECK: version: 2
|
||||
CHECK: prologue_length: 0x00000021
|
||||
CHECK: min_inst_length: 1
|
||||
CHECK: default_is_stmt: 1
|
||||
CHECK: line_base: -5
|
||||
CHECK: line_range: 14
|
||||
CHECK: opcode_base: 13
|
||||
|
||||
CHECK: /Contents/Resources/DWARF/fat-test.arm.dylib(arm64): file format Mach-O arm64
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK: Compile Unit: length = 0x00000038, format = DWARF32, version = 0x0002, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000003c)
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "clang version 3.8.0 (trunk 243776)")
|
||||
CHECK: DW_AT_language [DW_FORM_data2] (DW_LANG_C99)
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000024] = "fat-test.c")
|
||||
CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x00000000)
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x0000002f] = "/Inputs")
|
||||
CHECK: DW_TAG_variable [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000037] = "arm64_var")
|
||||
CHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0034 => {0x00000034}
|
||||
CHECK: DW_AT_external [DW_FORM_flag] (0x01)
|
||||
CHECK: DW_AT_decl_file [DW_FORM_data1] ("/Inputs/fat-test.c")
|
||||
CHECK: DW_AT_decl_line [DW_FORM_data1] (25)
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (DW_OP_addr 0x4000)
|
||||
CHECK: DW_TAG_base_type [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000041] = "int")
|
||||
CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed)
|
||||
CHECK: DW_AT_byte_size [DW_FORM_data1] (0x04)
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: .debug_line contents:
|
||||
CHECK: Line table prologue:
|
||||
CHECK: total_length: 0x0000002a
|
||||
CHECK: version: 2
|
||||
CHECK: prologue_length: 0x00000021
|
||||
CHECK: min_inst_length: 1
|
||||
CHECK: default_is_stmt: 1
|
||||
CHECK: line_base: -5
|
||||
CHECK: line_range: 14
|
||||
CHECK: opcode_base: 13
|
119
llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/obfuscated.test
Normal file
119
llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/obfuscated.test
Normal file
@ -0,0 +1,119 @@
|
||||
REQUIRES: system-darwin
|
||||
|
||||
RUN: dsymutil --linker llvm --symbol-map %p/../../Inputs/obfuscated.map %p/../../Inputs/obfuscated.arm64 -f -o - \
|
||||
RUN: | llvm-dwarfdump -v - \
|
||||
RUN: | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm --symbol-map %p/../../Inputs/obfuscated.map %p/../../Inputs/obfuscated.arm64 -f -o - \
|
||||
RUN: | llvm-dwarfdump -v - \
|
||||
RUN: | FileCheck --check-prefix=NOHIDDEN %s
|
||||
|
||||
RUN: dsymutil --linker llvm --symbol-map %p/../../Inputs/obfuscated.2.map %p/../../Inputs/obfuscated.2.arm64 -f -o - \
|
||||
RUN: | llvm-dwarfdump -v - \
|
||||
RUN: | FileCheck --check-prefix=NOHIDDEN %s
|
||||
|
||||
// Run with plist and make sure dsymutil finds it.
|
||||
RUN: mkdir -p %t.dSYM/Contents/Resources/DWARF/
|
||||
RUN: mkdir -p %t.mapdir
|
||||
RUN: cp %p/../../Inputs/obfuscated.arm64 %t.dSYM/Contents/Resources/DWARF/
|
||||
RUN: cp %p/../../Inputs/E828A486-8433-3A5E-B6DB-A6294D28133D.plist %t.dSYM/Contents/Resources/
|
||||
RUN: cp %p/../../Inputs/obfuscated.map %t.mapdir/506AA50A-6B26-3B37-86D2-DC6EBD57B720.bcsymbolmap
|
||||
RUN: dsymutil --linker llvm --symbol-map %t.mapdir %t.dSYM 2>&1 | FileCheck --check-prefix=OBFUSCATING %s
|
||||
|
||||
// Run without plist and make sure dsymutil doesn't crash.
|
||||
RUN: rm %t.dSYM/Contents/Resources/E828A486-8433-3A5E-B6DB-A6294D28133D.plist
|
||||
RUN: dsymutil --linker llvm --symbol-map %t.mapdir %t.dSYM 2>&1 | FileCheck --check-prefix=NOTOBFUSCATING %s
|
||||
|
||||
OBFUSCATING-NOT: not unobfuscating
|
||||
|
||||
NOTOBFUSCATING: not unobfuscating
|
||||
|
||||
NOHIDDEN-NOT: __hidden#
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "main.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
|
||||
CHECK: DW_TAG_subprogram [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "main")
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "one.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
|
||||
CHECK: DW_TAG_subprogram [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "one")
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "two.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
|
||||
CHECK: DW_TAG_subprogram [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "two")
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "three.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
|
||||
CHECK: DW_TAG_subprogram [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "three")
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "four.c")
|
||||
CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x0000011e)
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
|
||||
CHECK: DW_TAG_subprogram [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "four")
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "five.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
|
||||
CHECK: DW_TAG_subprogram [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "five")
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( {{.*}} "Apple LLVM version 7.0.0 (clang-700.2.38.2)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "six.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( {{.*}} "/Users/steven/dev/alpena/tests/src")
|
||||
CHECK: DW_TAG_subprogram [2]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( {{.*}} "six")
|
||||
|
||||
CHECK: .debug_line contents:
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK: name: "main.c"
|
||||
CHECK: dir_index: 0
|
||||
CHECK: mod_time: 0x00000000
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK: name: "one.c"
|
||||
CHECK: dir_index: 0
|
||||
CHECK: mod_time: 0x00000000
|
||||
CHECK: length: 0x00000000
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK: name: "two.c"
|
||||
CHECK: dir_index: 0
|
||||
CHECK: mod_time: 0x00000000
|
||||
CHECK: length: 0x00000000
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK: name: "three.c"
|
||||
CHECK: dir_index: 0
|
||||
CHECK: mod_time: 0x00000000
|
||||
CHECK: length: 0x00000000
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK: name: "four.c"
|
||||
CHECK: dir_index: 0
|
||||
CHECK: mod_time: 0x00000000
|
||||
CHECK: length: 0x00000000
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK: name: "five.c"
|
||||
CHECK: dir_index: 0
|
||||
CHECK: mod_time: 0x00000000
|
||||
CHECK: length: 0x00000000
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK: name: "six.c"
|
||||
CHECK: dir_index: 0
|
||||
CHECK: mod_time: 0x00000000
|
||||
CHECK: length: 0x00000000
|
@ -17,4 +17,7 @@ $ clang -arch arm64 main.arm64.o -o main.arm64 -g
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/call_pc/main.arm64 -o %t.dSYM
|
||||
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_pc
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/call_pc/main.arm64 -o %t.dSYM
|
||||
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_pc
|
||||
|
||||
CHECK: DW_AT_call_pc (0x0000000100007f94)
|
||||
|
@ -49,9 +49,23 @@ RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s
|
||||
|
||||
RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
|
||||
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
|
||||
RUN: -o %t.dir/dwarf5-addr-base.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s
|
||||
|
||||
RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: dsymutil --update -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefix=UPD
|
||||
|
||||
RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: dsymutil --linker llvm --update -y %p/dummy-debug-map-amr64.map \
|
||||
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
|
||||
RUN: -o %t.dir/dwarf5-addr-base.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
|
||||
RUN: FileCheck %s --check-prefix=UPD
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
|
||||
|
||||
@ -62,7 +76,7 @@ CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c)
|
||||
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[ADDR1:[0-9a-f]+]])
|
||||
|
||||
|
||||
CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
|
||||
CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08
|
||||
|
||||
CHECK: 0x0000005a: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000018)
|
||||
@ -70,9 +84,9 @@ CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000018)
|
||||
CHECK: 0x0000007a: DW_TAG_subprogram [2] * (0x0000005a)
|
||||
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[ADDR2:[0-9a-f]+]])
|
||||
|
||||
CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
|
||||
CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|b4}}, addr_size = 0x08
|
||||
|
||||
CHECK: 0x000000a8: DW_TAG_compile_unit [5] *
|
||||
CHECK: 0x000000a8: DW_TAG_compile_unit {{.*}} *
|
||||
CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000028)
|
||||
|
||||
CHECK: 0x000000c1: DW_TAG_subprogram [2] * (0x000000a8)
|
||||
@ -111,7 +125,7 @@ UPD: 0x00000071: DW_TAG_subprogram [5] (0x0000000c)
|
||||
UPD-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000003) address = 0x0000000000000010)
|
||||
|
||||
|
||||
UPD: 0x00000085: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
|
||||
UPD: 0x00000085: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|99}}, addr_size = 0x08
|
||||
|
||||
UPD: 0x00000091: DW_TAG_compile_unit [1] *
|
||||
UPD: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
|
||||
@ -125,12 +139,12 @@ UPD-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000001) ad
|
||||
UPD: 0x000000dc: DW_TAG_subprogram [3] * (0x00000091)
|
||||
UPD-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000002) address = 0x0000000000000008)
|
||||
|
||||
UPD: 0x000000fb: Compile Unit: length = 0x00000044, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
|
||||
UPD: 0x000000fb: Compile Unit: length = 0x00000044, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0{{000|115}}, addr_size = 0x08
|
||||
|
||||
UPD: 0x00000107: DW_TAG_compile_unit [7] *
|
||||
UPD: 0x00000107: DW_TAG_compile_unit {{.*}} *
|
||||
UPD: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
|
||||
|
||||
UPD: 0x00000124: DW_TAG_subprogram [3] * (0x00000107)
|
||||
UPD: 0x00000124: DW_TAG_subprogram {{.*}} * (0x00000107)
|
||||
UPD-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000000018)
|
||||
|
||||
UPD: .debug_addr contents:
|
||||
|
@ -28,6 +28,14 @@ RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
|
||||
RUN: llvm-dwarfdump --verbose -debug-info %t.dSYM | FileCheck %s --check-prefix DEBUGINFO
|
||||
RUN: llvm-dwarfdump --verbose -debug-line %t.dSYM | FileCheck %s --check-prefix DEBUGLINE
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs \
|
||||
RUN: %p/../Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.out \
|
||||
RUN: -o %t.dSYM 2>&1 | FileCheck %s --allow-empty
|
||||
RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
|
||||
RUN: llvm-dwarfdump --verbose -debug-info %t.dSYM | FileCheck %s --check-prefix DEBUGINFO
|
||||
RUN: llvm-dwarfdump --verbose -debug-line %t.dSYM | FileCheck %s --check-prefix DEBUGLINE
|
||||
|
||||
|
||||
CHECK-NOT: error:
|
||||
|
||||
DEBUGINFO: DW_TAG_subprogram
|
||||
|
@ -1,4 +1,8 @@
|
||||
; This test checks to ensure that if three DWARFv5 object files have correct values for the DW_AT_str_offsets_base and DW_FORM_strx for strings in their compile units.
|
||||
; DWARFLinkerParallel specific : DWARFLinkerParallel uses .debug_str_offsets
|
||||
; table local to the compile unit. That leads to different string indexes.
|
||||
; In such cases test contains both variants for indexes value:
|
||||
; (indexed (0000000{{9|1}}) string = "b.cpp".
|
||||
|
||||
; 1.o was produced with the source file:
|
||||
|
||||
@ -47,10 +51,21 @@
|
||||
|
||||
RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=CHECK,GLOBAL
|
||||
|
||||
RUN: dsymutil --update -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefix=UPD
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=UPD,GLOBALUPD
|
||||
|
||||
RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
|
||||
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
|
||||
RUN: -o %t.dir/dwarf5-addr-base.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=CHECK,LOCAL
|
||||
|
||||
RUN: dsymutil --linker llvm --update -y %p/dummy-debug-map-amr64.map \
|
||||
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
|
||||
RUN: -o %t.dir/dwarf5-addr-base.dSYM
|
||||
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=UPD,LOCALUPD
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000004e)
|
||||
@ -78,19 +93,19 @@ CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000008) strin
|
||||
|
||||
CHECK: 0x0000004d: NULL
|
||||
|
||||
CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000009c)
|
||||
CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08 (next unit at 0x0000009c)
|
||||
|
||||
CHECK: 0x0000005a: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000009) string = "b.cpp")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{9|1}}) string = "b.cpp")
|
||||
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
|
||||
CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) string = "MacOSX14.0.sdk")
|
||||
CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
|
||||
CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x000000{{08|34}})
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485")
|
||||
|
||||
CHECK: 0x0000007a: DW_TAG_subprogram [2] * (0x0000005a)
|
||||
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (0000000a) string = "_Z4bar2i")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000b) string = "bar2")
|
||||
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (0000000{{a|5}}) string = "_Z4bar2i")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{b|6}}) string = "bar2")
|
||||
|
||||
CHECK: 0x0000008a: DW_TAG_formal_parameter [3] (0x0000007a)
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000007) string = "a")
|
||||
@ -102,22 +117,22 @@ CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000008) strin
|
||||
|
||||
CHECK: 0x0000009b: NULL
|
||||
|
||||
CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x000000e3)
|
||||
CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|b4}}, addr_size = 0x08 (next unit at 0x000000e3)
|
||||
|
||||
CHECK: 0x000000a8: DW_TAG_compile_unit [5] *
|
||||
CHECK: 0x000000a8: DW_TAG_compile_unit {{.*}} *
|
||||
CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000c) string = "c.cpp")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{c|1}}) string = "c.cpp")
|
||||
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
|
||||
CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) string = "MacOSX14.0.sdk")
|
||||
CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
|
||||
CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x000000{{08|60}})
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485")
|
||||
|
||||
CHECK: 0x000000c1: DW_TAG_subprogram [2] * (0x000000a8)
|
||||
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (0000000d) string = "_Z3bazi")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000e) string = "baz")
|
||||
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (0000000{{d|5}}) string = "_Z3bazi")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{e|6}}) string = "baz")
|
||||
|
||||
CHECK: 0x000000d1: DW_TAG_formal_parameter [3] (0x000000c1)
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000f) string = "x")
|
||||
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{f|7}}) string = "x")
|
||||
|
||||
CHECK: 0x000000dd: NULL
|
||||
|
||||
@ -145,24 +160,57 @@ CHECK-NEXT: 0x0000011d: "_Z3bazi"
|
||||
CHECK-NEXT: 0x00000125: "baz"
|
||||
CHECK-NEXT: 0x00000129: "x"
|
||||
|
||||
CHECK: .debug_str_offsets contents:
|
||||
CHECK-NEXT: 0x00000000: Contribution size = 68, Format = DWARF32, Version = 5
|
||||
CHECK-NEXT: 0x00000008: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
CHECK-NEXT: 0x0000000c: 00000030 "a.cpp"
|
||||
CHECK-NEXT: 0x00000010: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
CHECK-NEXT: 0x00000014: 000000b7 "MacOSX14.0.sdk"
|
||||
CHECK-NEXT: 0x00000018: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
CHECK-NEXT: 0x0000001c: 000000ef "_Z4foo2i"
|
||||
CHECK-NEXT: 0x00000020: 000000f8 "foo2"
|
||||
CHECK-NEXT: 0x00000024: 000000fd "a"
|
||||
CHECK-NEXT: 0x00000028: 000000ff "int"
|
||||
CHECK-NEXT: 0x0000002c: 00000103 "b.cpp"
|
||||
CHECK-NEXT: 0x00000030: 00000109 "_Z4bar2i"
|
||||
CHECK-NEXT: 0x00000034: 00000112 "bar2"
|
||||
CHECK-NEXT: 0x00000038: 00000117 "c.cpp"
|
||||
CHECK-NEXT: 0x0000003c: 0000011d "_Z3bazi"
|
||||
CHECK-NEXT: 0x00000040: 00000125 "baz"
|
||||
CHECK-NEXT: 0x00000044: 00000129 "x"
|
||||
GLOBAL: .debug_str_offsets contents:
|
||||
GLOBAL-NEXT: 0x00000000: Contribution size = 68, Format = DWARF32, Version = 5
|
||||
GLOBAL-NEXT: 0x00000008: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
GLOBAL-NEXT: 0x0000000c: 00000030 "a.cpp"
|
||||
GLOBAL-NEXT: 0x00000010: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
GLOBAL-NEXT: 0x00000014: 000000b7 "MacOSX14.0.sdk"
|
||||
GLOBAL-NEXT: 0x00000018: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
GLOBAL-NEXT: 0x0000001c: 000000ef "_Z4foo2i"
|
||||
GLOBAL-NEXT: 0x00000020: 000000f8 "foo2"
|
||||
GLOBAL-NEXT: 0x00000024: 000000fd "a"
|
||||
GLOBAL-NEXT: 0x00000028: 000000ff "int"
|
||||
GLOBAL-NEXT: 0x0000002c: 00000103 "b.cpp"
|
||||
GLOBAL-NEXT: 0x00000030: 00000109 "_Z4bar2i"
|
||||
GLOBAL-NEXT: 0x00000034: 00000112 "bar2"
|
||||
GLOBAL-NEXT: 0x00000038: 00000117 "c.cpp"
|
||||
GLOBAL-NEXT: 0x0000003c: 0000011d "_Z3bazi"
|
||||
GLOBAL-NEXT: 0x00000040: 00000125 "baz"
|
||||
GLOBAL-NEXT: 0x00000044: 00000129 "x"
|
||||
|
||||
LOCAL: .debug_str_offsets contents:
|
||||
LOCAL-NEXT: 0x00000000: Contribution size = 40, Format = DWARF32, Version = 5
|
||||
LOCAL-NEXT: 0x00000008: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
LOCAL-NEXT: 0x0000000c: 00000030 "a.cpp"
|
||||
LOCAL-NEXT: 0x00000010: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
LOCAL-NEXT: 0x00000014: 000000b7 "MacOSX14.0.sdk"
|
||||
LOCAL-NEXT: 0x00000018: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
LOCAL-NEXT: 0x0000001c: 000000ef "_Z4foo2i"
|
||||
LOCAL-NEXT: 0x00000020: 000000f8 "foo2"
|
||||
LOCAL-NEXT: 0x00000024: 000000fd "a"
|
||||
LOCAL-NEXT: 0x00000028: 000000ff "int"
|
||||
LOCAL-NEXT: 0x0000002c: Contribution size = 40, Format = DWARF32, Version = 5
|
||||
LOCAL-NEXT: 0x00000034: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
LOCAL-NEXT: 0x00000038: 00000103 "b.cpp"
|
||||
LOCAL-NEXT: 0x0000003c: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
LOCAL-NEXT: 0x00000040: 000000b7 "MacOSX14.0.sdk"
|
||||
LOCAL-NEXT: 0x00000044: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
LOCAL-NEXT: 0x00000048: 00000109 "_Z4bar2i"
|
||||
LOCAL-NEXT: 0x0000004c: 00000112 "bar2"
|
||||
LOCAL-NEXT: 0x00000050: 000000fd "a"
|
||||
LOCAL-NEXT: 0x00000054: 000000ff "int"
|
||||
LOCAL-NEXT: 0x00000058: Contribution size = 40, Format = DWARF32, Version = 5
|
||||
LOCAL-NEXT: 0x00000060: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
LOCAL-NEXT: 0x00000064: 00000117 "c.cpp"
|
||||
LOCAL-NEXT: 0x00000068: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
LOCAL-NEXT: 0x0000006c: 000000b7 "MacOSX14.0.sdk"
|
||||
LOCAL-NEXT: 0x00000070: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
LOCAL-NEXT: 0x00000074: 0000011d "_Z3bazi"
|
||||
LOCAL-NEXT: 0x00000078: 00000125 "baz"
|
||||
LOCAL-NEXT: 0x0000007c: 00000129 "x"
|
||||
LOCAL-NEXT: 0x00000080: 000000ff "int"
|
||||
|
||||
|
||||
UPD: .debug_info contents:
|
||||
UPD: 0x00000000: Compile Unit: length = 0x00000081, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000085)
|
||||
@ -205,23 +253,23 @@ UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000e) string
|
||||
|
||||
UPD: 0x00000084: NULL
|
||||
|
||||
UPD: 0x00000085: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x000000fb)
|
||||
UPD: 0x00000085: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|99}}, addr_size = 0x08 (next unit at 0x000000fb)
|
||||
|
||||
UPD: 0x00000091: DW_TAG_compile_unit [1] *
|
||||
UPD: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000f) string = "b.cpp")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000{{f|1}}) string = "b.cpp")
|
||||
UPD: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
|
||||
UPD: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) string = "MacOSX14.0.sdk")
|
||||
UPD: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
|
||||
UPD: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x000000{{08|4c}})
|
||||
UPD: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485")
|
||||
|
||||
UPD: 0x000000b6: DW_TAG_subprogram [2] (0x00000091)
|
||||
UPD: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000010) string = "_Z3barv")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (00000011) string = "bar")
|
||||
UPD: DW_AT_linkage_name [DW_FORM_strx] (indexed (000000{{10|05}}) string = "_Z3barv")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (000000{{11|06}}) string = "bar")
|
||||
|
||||
UPD: 0x000000c2: DW_TAG_subprogram [3] * (0x00000091)
|
||||
UPD: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000012) string = "_Z4bar2i")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (00000013) string = "bar2")
|
||||
UPD: DW_AT_linkage_name [DW_FORM_strx] (indexed (000000{{12|07}}) string = "_Z4bar2i")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (000000{{13|08}}) string = "bar2")
|
||||
|
||||
UPD: 0x000000d2: DW_TAG_formal_parameter [4] (0x000000c2)
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (00000009) string = "a")
|
||||
@ -229,40 +277,40 @@ UPD: DW_AT_name [DW_FORM_strx] (indexed (00000009) string
|
||||
UPD: 0x000000db: NULL
|
||||
|
||||
UPD: 0x000000dc: DW_TAG_subprogram [3] * (0x00000091)
|
||||
UPD: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000014) string = "_Z4bar3i")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (00000015) string = "bar3")
|
||||
UPD: DW_AT_linkage_name [DW_FORM_strx] (indexed (000000{{14|0a}}) string = "_Z4bar3i")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (000000{{15|0b}}) string = "bar3")
|
||||
|
||||
UPD: 0x000000ec: DW_TAG_formal_parameter [4] (0x000000dc)
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000c) string = "x")
|
||||
|
||||
UPD: 0x000000f5: NULL
|
||||
|
||||
UPD: 0x000000f6: DW_TAG_base_type [6] (0x00000091)
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000e) string = "int")
|
||||
UPD: 0x000000f6: DW_TAG_base_type {{.*}} (0x00000091)
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000{{e|d}}) string = "int")
|
||||
|
||||
UPD: 0x000000fa: NULL
|
||||
|
||||
UPD: 0x000000fb: Compile Unit: length = 0x00000044, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000143)
|
||||
UPD: 0x000000fb: Compile Unit: length = 0x00000044, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0{{000|115}}, addr_size = 0x08 (next unit at 0x00000143)
|
||||
|
||||
UPD: 0x00000107: DW_TAG_compile_unit [7] *
|
||||
UPD: 0x00000107: DW_TAG_compile_unit {{.*}} *
|
||||
UPD: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (00000016) string = "c.cpp")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (000000{{16|01}}) string = "c.cpp")
|
||||
UPD: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
|
||||
UPD: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) string = "MacOSX14.0.sdk")
|
||||
UPD: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
|
||||
UPD: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x000000{{08|8c}})
|
||||
UPD: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485")
|
||||
|
||||
UPD: 0x00000124: DW_TAG_subprogram [3] * (0x00000107)
|
||||
UPD: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000017) string = "_Z3bazi")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (00000018) string = "baz")
|
||||
UPD: 0x00000124: DW_TAG_subprogram {{.*}} * (0x00000107)
|
||||
UPD: DW_AT_linkage_name [DW_FORM_strx] (indexed (000000{{17|05}}) string = "_Z3bazi")
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (000000{{18|06}}) string = "baz")
|
||||
|
||||
UPD: 0x00000134: DW_TAG_formal_parameter [4] (0x00000124)
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000c) string = "x")
|
||||
UPD: 0x00000134: DW_TAG_formal_parameter {{.*}} (0x00000124)
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000{{c|7}}) string = "x")
|
||||
|
||||
UPD: 0x0000013d: NULL
|
||||
|
||||
UPD: 0x0000013e: DW_TAG_base_type [6] (0x00000107)
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000e) string = "int")
|
||||
UPD: 0x0000013e: DW_TAG_base_type {{.*}} (0x00000107)
|
||||
UPD: DW_AT_name [DW_FORM_strx] (indexed (0000000{{e|8}}) string = "int")
|
||||
|
||||
UPD: 0x00000142: NULL
|
||||
|
||||
@ -294,30 +342,73 @@ UPD-NEXT: 0x00000152: "c.cpp"
|
||||
UPD-NEXT: 0x00000158: "_Z3bazi"
|
||||
UPD-NEXT: 0x00000160: "baz"
|
||||
|
||||
UPD: .debug_str_offsets contents:
|
||||
UPD-NEXT: 0x00000000: Contribution size = 104, Format = DWARF32, Version = 5
|
||||
UPD-NEXT: 0x00000008: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
UPD-NEXT: 0x0000000c: 00000030 "a.cpp"
|
||||
UPD-NEXT: 0x00000010: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
UPD-NEXT: 0x00000014: 000000b7 "MacOSX14.0.sdk"
|
||||
UPD-NEXT: 0x00000018: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
UPD-NEXT: 0x0000001c: 000000ef "_Z3foov"
|
||||
UPD-NEXT: 0x00000020: 000000f7 "foo"
|
||||
UPD-NEXT: 0x00000024: 000000fb "_Z4foo2i"
|
||||
UPD-NEXT: 0x00000028: 00000104 "foo2"
|
||||
UPD-NEXT: 0x0000002c: 00000109 "a"
|
||||
UPD-NEXT: 0x00000030: 0000010b "_Z4foo3i"
|
||||
UPD-NEXT: 0x00000034: 00000114 "foo3"
|
||||
UPD-NEXT: 0x00000038: 00000119 "x"
|
||||
UPD-NEXT: 0x0000003c: 0000011b "main"
|
||||
UPD-NEXT: 0x00000040: 00000120 "int"
|
||||
UPD-NEXT: 0x00000044: 00000124 "b.cpp"
|
||||
UPD-NEXT: 0x00000048: 0000012a "_Z3barv"
|
||||
UPD-NEXT: 0x0000004c: 00000132 "bar"
|
||||
UPD-NEXT: 0x00000050: 00000136 "_Z4bar2i"
|
||||
UPD-NEXT: 0x00000054: 0000013f "bar2"
|
||||
UPD-NEXT: 0x00000058: 00000144 "_Z4bar3i"
|
||||
UPD-NEXT: 0x0000005c: 0000014d "bar3"
|
||||
UPD-NEXT: 0x00000060: 00000152 "c.cpp"
|
||||
UPD-NEXT: 0x00000064: 00000158 "_Z3bazi"
|
||||
UPD-NEXT: 0x00000068: 00000160 "baz"
|
||||
GLOBALUPD: .debug_str_offsets contents:
|
||||
GLOBALUPD-NEXT: 0x00000000: Contribution size = 104, Format = DWARF32, Version = 5
|
||||
GLOBALUPD-NEXT: 0x00000008: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
GLOBALUPD-NEXT: 0x0000000c: 00000030 "a.cpp"
|
||||
GLOBALUPD-NEXT: 0x00000010: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
GLOBALUPD-NEXT: 0x00000014: 000000b7 "MacOSX14.0.sdk"
|
||||
GLOBALUPD-NEXT: 0x00000018: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
GLOBALUPD-NEXT: 0x0000001c: 000000ef "_Z3foov"
|
||||
GLOBALUPD-NEXT: 0x00000020: 000000f7 "foo"
|
||||
GLOBALUPD-NEXT: 0x00000024: 000000fb "_Z4foo2i"
|
||||
GLOBALUPD-NEXT: 0x00000028: 00000104 "foo2"
|
||||
GLOBALUPD-NEXT: 0x0000002c: 00000109 "a"
|
||||
GLOBALUPD-NEXT: 0x00000030: 0000010b "_Z4foo3i"
|
||||
GLOBALUPD-NEXT: 0x00000034: 00000114 "foo3"
|
||||
GLOBALUPD-NEXT: 0x00000038: 00000119 "x"
|
||||
GLOBALUPD-NEXT: 0x0000003c: 0000011b "main"
|
||||
GLOBALUPD-NEXT: 0x00000040: 00000120 "int"
|
||||
GLOBALUPD-NEXT: 0x00000044: 00000124 "b.cpp"
|
||||
GLOBALUPD-NEXT: 0x00000048: 0000012a "_Z3barv"
|
||||
GLOBALUPD-NEXT: 0x0000004c: 00000132 "bar"
|
||||
GLOBALUPD-NEXT: 0x00000050: 00000136 "_Z4bar2i"
|
||||
GLOBALUPD-NEXT: 0x00000054: 0000013f "bar2"
|
||||
GLOBALUPD-NEXT: 0x00000058: 00000144 "_Z4bar3i"
|
||||
GLOBALUPD-NEXT: 0x0000005c: 0000014d "bar3"
|
||||
GLOBALUPD-NEXT: 0x00000060: 00000152 "c.cpp"
|
||||
GLOBALUPD-NEXT: 0x00000064: 00000158 "_Z3bazi"
|
||||
GLOBALUPD-NEXT: 0x00000068: 00000160 "baz"
|
||||
|
||||
LOCALUPD: .debug_str_offsets contents:
|
||||
LOCALUPD-NEXT: 0x00000000: Contribution size = 64, Format = DWARF32, Version = 5
|
||||
LOCALUPD-NEXT: 0x00000008: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
LOCALUPD-NEXT: 0x0000000c: 00000030 "a.cpp"
|
||||
LOCALUPD-NEXT: 0x00000010: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
LOCALUPD-NEXT: 0x00000014: 000000b7 "MacOSX14.0.sdk"
|
||||
LOCALUPD-NEXT: 0x00000018: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
LOCALUPD-NEXT: 0x0000001c: 000000ef "_Z3foov"
|
||||
LOCALUPD-NEXT: 0x00000020: 000000f7 "foo"
|
||||
LOCALUPD-NEXT: 0x00000024: 000000fb "_Z4foo2i"
|
||||
LOCALUPD-NEXT: 0x00000028: 00000104 "foo2"
|
||||
LOCALUPD-NEXT: 0x0000002c: 00000109 "a"
|
||||
LOCALUPD-NEXT: 0x00000030: 0000010b "_Z4foo3i"
|
||||
LOCALUPD-NEXT: 0x00000034: 00000114 "foo3"
|
||||
LOCALUPD-NEXT: 0x00000038: 00000119 "x"
|
||||
LOCALUPD-NEXT: 0x0000003c: 0000011b "main"
|
||||
LOCALUPD-NEXT: 0x00000040: 00000120 "int"
|
||||
LOCALUPD-NEXT: 0x00000044: Contribution size = 60, Format = DWARF32, Version = 5
|
||||
LOCALUPD-NEXT: 0x0000004c: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
LOCALUPD-NEXT: 0x00000050: 00000124 "b.cpp"
|
||||
LOCALUPD-NEXT: 0x00000054: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
LOCALUPD-NEXT: 0x00000058: 000000b7 "MacOSX14.0.sdk"
|
||||
LOCALUPD-NEXT: 0x0000005c: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
LOCALUPD-NEXT: 0x00000060: 0000012a "_Z3barv"
|
||||
LOCALUPD-NEXT: 0x00000064: 00000132 "bar"
|
||||
LOCALUPD-NEXT: 0x00000068: 00000136 "_Z4bar2i"
|
||||
LOCALUPD-NEXT: 0x0000006c: 0000013f "bar2"
|
||||
LOCALUPD-NEXT: 0x00000070: 00000109 "a"
|
||||
LOCALUPD-NEXT: 0x00000074: 00000144 "_Z4bar3i"
|
||||
LOCALUPD-NEXT: 0x00000078: 0000014d "bar3"
|
||||
LOCALUPD-NEXT: 0x0000007c: 00000119 "x"
|
||||
LOCALUPD-NEXT: 0x00000080: 00000120 "int"
|
||||
LOCALUPD-NEXT: 0x00000084: Contribution size = 40, Format = DWARF32, Version = 5
|
||||
LOCALUPD-NEXT: 0x0000008c: 00000001 "Apple clang version 15.0.0 (clang-1500.0.31.1)"
|
||||
LOCALUPD-NEXT: 0x00000090: 00000152 "c.cpp"
|
||||
LOCALUPD-NEXT: 0x00000094: 00000036 "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk"
|
||||
LOCALUPD-NEXT: 0x00000098: 000000b7 "MacOSX14.0.sdk"
|
||||
LOCALUPD-NEXT: 0x0000009c: 000000c6 "/Users/shubham/Development/test109275485"
|
||||
LOCALUPD-NEXT: 0x000000a0: 00000158 "_Z3bazi"
|
||||
LOCALUPD-NEXT: 0x000000a4: 00000160 "baz"
|
||||
LOCALUPD-NEXT: 0x000000a8: 00000119 "x"
|
||||
LOCALUPD-NEXT: 0x000000ac: 00000120 "int"
|
||||
|
@ -1,5 +1,7 @@
|
||||
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs -y %s -o - 2>&1 | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs -y %s -o - 2>&1 | FileCheck %s
|
||||
|
||||
---
|
||||
triple: 'thumbv7-apple-darwin'
|
||||
...
|
||||
|
@ -37,6 +37,10 @@ $ xcrun --sdk iphoneos clang private_extern.o main.o -target arm64-apple-ios14.0
|
||||
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/private_extern/private_extern.out -o %t.dSYM --verbose | FileCheck %s
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/extern/extern.out -o %t.dSYM --verbose | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/private_extern/private_extern.out -o %t.dSYM --verbose | FileCheck %s
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/extern/extern.out -o %t.dSYM --verbose | FileCheck %s
|
||||
|
||||
CHECK-NOT: could not find object file symbol for symbol _baz
|
||||
CHECK: { sym: _baz, objAddr: 0x0, binAddr: 0x100007F58, size: 0x0 }
|
||||
CHECK: { sym: _foo, objAddr: 0x0, binAddr: 0x100007F58, size: 0x20 }
|
||||
|
@ -1,5 +1,7 @@
|
||||
# RUN: dsymutil -no-output %p/../Inputs/fat-test.arm.dylib -o /dev/null -verbose 2>&1 | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -no-output %p/../Inputs/fat-test.arm.dylib -o /dev/null -verbose 2>&1 | FileCheck %s
|
||||
|
||||
# We detect thumb triples from the binaries, because those are the only ones
|
||||
# that are guaranteed to be able to generate a Target instance (for example
|
||||
# we would detect armv7m-apple-darwin as non-thumb triple, but you can't
|
||||
|
@ -1,4 +1,6 @@
|
||||
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs -y %s -o - 2>&1 | FileCheck %s
|
||||
#
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs -y %s -o - 2>&1 | FileCheck %s
|
||||
|
||||
---
|
||||
triple: 'armv7-apple-darwin'
|
||||
|
@ -5,6 +5,10 @@ int bar(int a) { return foo(a); }
|
||||
|
||||
// RUN: dsymutil -f -y %p/dummy-debug-map-amr64.map -oso-prepend-path %p/../Inputs/inlined-low_pc -o - | llvm-dwarfdump - | FileCheck %s
|
||||
|
||||
// RUN: dsymutil --linker llvm -f -y %p/dummy-debug-map-amr64.map \
|
||||
// RUN: -oso-prepend-path %p/../Inputs/inlined-low_pc -o - | \
|
||||
// RUN: llvm-dwarfdump - | FileCheck %s
|
||||
|
||||
// CHECK: DW_TAG_subprogram
|
||||
// CHECK: DW_AT_low_pc{{.*}}0x0000000000010000
|
||||
// CHECK: DW_AT_name{{.*}}"bar"
|
||||
|
@ -7,4 +7,9 @@ $ xcrun clang -o foo foo.o -g3 -Wl,-preload -nodefaultlibs
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/preload/foo -o %t.dSYM
|
||||
RUN: llvm-nm %p/../Inputs/private/tmp/preload/foo | FileCheck %s
|
||||
RUN: llvm-nm %t.dSYM/Contents/Resources/DWARF/foo | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/preload/foo -o %t.dSYM
|
||||
RUN: llvm-nm %p/../Inputs/private/tmp/preload/foo | FileCheck %s
|
||||
RUN: llvm-nm %t.dSYM/Contents/Resources/DWARF/foo | FileCheck %s
|
||||
|
||||
CHECK: start
|
||||
|
@ -1,4 +1,10 @@
|
||||
RUN: dsymutil -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/scattered-reloc/ -f -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
RUN: dsymutil -y %p/dummy-debug-map.map -oso-prepend-path \
|
||||
RUN: %p/../Inputs/scattered-reloc/ -f -o - | \
|
||||
RUN: llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -y %p/dummy-debug-map.map \
|
||||
RUN: -oso-prepend-path %p/../Inputs/scattered-reloc/ -f -o - \
|
||||
RUN: | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
// See Inputs/scattered-reloc/scattered.s to see how this test
|
||||
// actually works.
|
||||
|
@ -1,6 +1,11 @@
|
||||
// RUN: dsymutil -f -oso-prepend-path=%p/.. %p/../Inputs/thumb.armv7m -o - | llvm-dwarfdump - | FileCheck %s
|
||||
// RUN: dsymutil -arch armv7m -f -oso-prepend-path=%p/.. %p/../Inputs/thumb.armv7m -o - | llvm-dwarfdump - | FileCheck %s
|
||||
|
||||
// RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/.. \
|
||||
// RUN: %p/../Inputs/thumb.armv7m -o - | llvm-dwarfdump - | FileCheck %s
|
||||
// RUN: dsymutil --linker llvm -arch armv7m -f -oso-prepend-path=%p/.. \
|
||||
// RUN: %p/../Inputs/thumb.armv7m -o - | llvm-dwarfdump - | FileCheck %s
|
||||
|
||||
/* Compile with:
|
||||
clang -c thumb.c -arch armv7m -g
|
||||
clang thumb.o -o thumb.armv7m -arch armv7m -nostdlib -static -Wl,-e,_start
|
||||
|
@ -0,0 +1,41 @@
|
||||
RUN: rm -rf %t
|
||||
RUN: mkdir -p %t/dsymdest
|
||||
RUN: cat %p/../../Inputs/basic.macho.x86_64 > %t/basic.macho.x86_64
|
||||
|
||||
RUN: dsymutil --linker llvm -accelerator=Pub -oso-prepend-path=%p/../.. %t/basic.macho.x86_64
|
||||
|
||||
Check that the object file in the bundle exists and is sane:
|
||||
RUN: llvm-dwarfdump -a %t/basic.macho.x86_64.dSYM/Contents/Resources/DWARF/basic.macho.x86_64 | FileCheck %S/basic-linking-x86.test
|
||||
|
||||
Check that we don't create an empty Remarks directory if there are no remarks.
|
||||
RUN: not ls %t/basic.macho.x86_64.dSYM/Contents/Resources/Remarks
|
||||
|
||||
Check that llvm-dwarfdump -a recognizes the bundle as a dSYM:
|
||||
RUN: llvm-dwarfdump -a %t/basic.macho.x86_64.dSYM | FileCheck %S/basic-linking-x86.test
|
||||
|
||||
RUN: FileCheck %s --input-file %t/basic.macho.x86_64.dSYM/Contents/Info.plist
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/../.. %t/basic.macho.x86_64 -o %t/dsymdest/basic.macho.x86_64.dSYM
|
||||
RUN: llvm-dwarfdump -a %t/dsymdest/basic.macho.x86_64.dSYM/Contents/Resources/DWARF/basic.macho.x86_64 | FileCheck %S/basic-linking-x86.test
|
||||
RUN: FileCheck %s --input-file %t/dsymdest/basic.macho.x86_64.dSYM/Contents/Info.plist
|
||||
|
||||
CHECK: <?xml version="1.0" encoding="UTF-8"?>
|
||||
CHECK-NEXT: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
CHECK-NEXT: <plist version="1.0">
|
||||
CHECK-NEXT: <dict>
|
||||
CHECK-NEXT: <key>CFBundleDevelopmentRegion</key>
|
||||
CHECK-NEXT: <string>English</string>
|
||||
CHECK-NEXT: <key>CFBundleIdentifier</key>
|
||||
CHECK-NEXT: <string>com.apple.xcode.dsym.basic.macho.x86_64</string>
|
||||
CHECK-NEXT: <key>CFBundleInfoDictionaryVersion</key>
|
||||
CHECK-NEXT: <string>6.0</string>
|
||||
CHECK-NEXT: <key>CFBundlePackageType</key>
|
||||
CHECK-NEXT: <string>dSYM</string>
|
||||
CHECK-NEXT: <key>CFBundleSignature</key>
|
||||
CHECK-NEXT: <string>????</string>
|
||||
CHECK-NEXT: <key>CFBundleShortVersionString</key>
|
||||
CHECK-NEXT: <string>1.0</string>
|
||||
CHECK-NEXT: <key>CFBundleVersion</key>
|
||||
CHECK-NEXT: <string>1</string>
|
||||
CHECK-NEXT: </dict>
|
||||
CHECK-NEXT: </plist>
|
@ -1,4 +1,190 @@
|
||||
RUN: cat %p/../../Inputs/basic.macho.x86_64 > %t1
|
||||
RUN: dsymutil --linker llvm --no-output -accelerator=Pub -f -oso-prepend-path=%p/../.. %t1 2>&1 | FileCheck %s --allow-empty
|
||||
RUN: dsymutil --linker llvm -accelerator=Pub -f -oso-prepend-path=%p/../.. %t1
|
||||
RUN: llvm-dwarfdump -a %t1.dwarf | FileCheck %s
|
||||
RUN: dsymutil --linker llvm -accelerator=Pub -f -o %t2 -oso-prepend-path=%p/../.. %p/../../Inputs/basic.macho.x86_64
|
||||
RUN: llvm-dwarfdump -a %t2 | FileCheck %s
|
||||
RUN: dsymutil --linker llvm -accelerator=Pub -f -o - -oso-prepend-path=%p/../.. %p/../../Inputs/basic.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,BASIC
|
||||
RUN: dsymutil --linker llvm -accelerator=Pub -f -o - -oso-prepend-path=%p/../.. %p/../../Inputs/basic-archive.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,ARCHIVE
|
||||
RUN: dsymutil --linker llvm -accelerator=Pub -dump-debug-map -oso-prepend-path=%p/../.. %p/../../Inputs/basic.macho.x86_64 | dsymutil -accelerator=Pub -f -y -o - - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,BASIC
|
||||
RUN: dsymutil --linker llvm -accelerator=Pub -dump-debug-map -oso-prepend-path=%p/../.. %p/../../Inputs/basic-archive.macho.x86_64 | dsymutil -accelerator=Pub -f -o - -y - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,ARCHIVE
|
||||
|
||||
#CHECK: LLVM parallel dwarflinker is not implemented yet.
|
||||
CHECK: file format Mach-O 64-bit x86-64
|
||||
|
||||
CHECK: debug_info contents
|
||||
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_language (DW_LANG_C99)
|
||||
CHECK: DW_AT_name ("basic1.c")
|
||||
CHECK: DW_AT_stmt_list (0x00000000)
|
||||
CHECK: DW_AT_comp_dir ("/Inputs")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000ea0)
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("main")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c")
|
||||
CHECK: DW_AT_decl_line (23)
|
||||
CHECK: DW_AT_prototyped (0x01)
|
||||
CHECK: DW_AT_type (0x00000063
|
||||
CHECK: DW_AT_external (0x01)
|
||||
CHECK: DW_AT_accessibility (DW_ACCESS_public)
|
||||
CHECK: DW_AT_low_pc (0x0000000100000ea0)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000ec4)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_name ("argc")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c")
|
||||
CHECK: DW_AT_decl_line (23)
|
||||
CHECK: DW_AT_type (0x00000063
|
||||
CHECK: DW_AT_location (DW_OP_fbreg -8)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_name ("argv")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c")
|
||||
CHECK: DW_AT_decl_line (23)
|
||||
CHECK: DW_AT_type (0x0000006a
|
||||
CHECK: DW_AT_location (DW_OP_fbreg -16)
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK: DW_AT_name ("int")
|
||||
CHECK: DW_AT_encoding (DW_ATE_signed)
|
||||
CHECK: DW_AT_byte_size (0x04)
|
||||
CHECK: DW_TAG_pointer_type
|
||||
CHECK: DW_AT_type (0x0000006f
|
||||
CHECK: DW_TAG_pointer_type
|
||||
CHECK: DW_AT_type (0x00000074
|
||||
CHECK: DW_TAG_const_type
|
||||
CHECK: DW_AT_type (0x00000079
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK: DW_AT_name ("char")
|
||||
CHECK: DW_AT_encoding (DW_ATE_signed_char)
|
||||
CHECK: DW_AT_byte_size (0x01)
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_name ("basic2.c")
|
||||
CHECK: DW_AT_stmt_list (0x0000003f)
|
||||
CHECK: DW_AT_comp_dir ("/Inputs")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000ed0)
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK: DW_AT_name ("int")
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("private_int")
|
||||
CHECK: DW_AT_type (0x000000a7
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic2.c")
|
||||
BASIC: DW_AT_location (DW_OP_addr 0x100001008)
|
||||
ARCHIVE: DW_AT_location (DW_OP_addr 0x100001004)
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("baz")
|
||||
CHECK: DW_AT_type (0x000000a7
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic2.c")
|
||||
CHECK: DW_AT_location (DW_OP_addr 0x100001000)
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("foo")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic2.c")
|
||||
CHECK: DW_AT_type (0x000000a7
|
||||
CHECK: DW_AT_low_pc (0x0000000100000ed0)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f19)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_name ("arg")
|
||||
CHECK: DW_AT_type (0x000000a7
|
||||
CHECK: DW_AT_location (DW_OP_fbreg -4)
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("inc")
|
||||
CHECK: DW_AT_type (0x000000a7
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f20)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f37)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_name ("basic3.c")
|
||||
CHECK: DW_AT_stmt_list (0x00000093)
|
||||
CHECK: DW_AT_comp_dir ("/Inputs")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f40)
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("val")
|
||||
CHECK: DW_AT_type (0x00000162
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic3.c")
|
||||
BASIC: DW_AT_location (DW_OP_addr 0x100001004)
|
||||
ARCHIVE: DW_AT_location (DW_OP_addr 0x100001008)
|
||||
CHECK: DW_TAG_volatile_type
|
||||
CHECK: DW_AT_type (0x00000167
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK: DW_AT_name ("int")
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("bar")
|
||||
CHECK: DW_AT_type (0x00000167
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f40)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f84)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_name ("arg")
|
||||
CHECK: DW_AT_type (0x00000167
|
||||
CHECK: DW_AT_location (DW_OP_fbreg -8)
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("inc")
|
||||
CHECK: DW_AT_type (0x00000167
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f90)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000fa9)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
|
||||
CHECK: NULL
|
||||
|
||||
CHECK-NOT: .debug_loc contents
|
||||
|
||||
CHECK:.debug_aranges contents:
|
||||
CHECK-NEXT:Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT:[0x0000000100000ea0, 0x0000000100000ec4)
|
||||
CHECK-NEXT:Address Range Header: length = 0x0000003c, format = DWARF32, version = 0x0002, cu_offset = 0x00000081, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT:[0x0000000100000ed0, 0x0000000100000f19)
|
||||
CHECK-NEXT:[0x0000000100000f20, 0x0000000100000f37)
|
||||
CHECK-NEXT:Address Range Header: length = 0x0000003c, format = DWARF32, version = 0x0002, cu_offset = 0x00000126, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT:[0x0000000100000f40, 0x0000000100000f84)
|
||||
CHECK-NEXT:[0x0000000100000f90, 0x0000000100000fa9)
|
||||
|
||||
CHECK: .debug_line contents:
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic1.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: Address Line Column File ISA Discriminator OpIndex Flags
|
||||
CHECK-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
|
||||
CHECK-NEXT: 0x0000000100000ea0 23 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000eb6 24 0 1 0 0 0 is_stmt prologue_end
|
||||
CHECK-NEXT: 0x0000000100000ec4 24 0 1 0 0 0 is_stmt end_sequence
|
||||
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic2.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: Address Line Column File ISA Discriminator OpIndex Flags
|
||||
CHECK-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
|
||||
CHECK-NEXT: 0x0000000100000ed0 19 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000ee2 20 0 1 0 0 0 is_stmt prologue_end
|
||||
CHECK-NEXT: 0x0000000100000f19 20 0 1 0 0 0 is_stmt end_sequence
|
||||
CHECK-NEXT: 0x0000000100000f20 14 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f24 15 0 1 0 0 0 is_stmt prologue_end
|
||||
CHECK-NEXT: 0x0000000100000f37 15 0 1 0 0 0 is_stmt end_sequence
|
||||
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic3.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: Address Line Column File ISA Discriminator OpIndex Flags
|
||||
CHECK-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
|
||||
CHECK-NEXT: 0x0000000100000f40 16 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f4b 17 0 1 0 0 0 is_stmt prologue_end
|
||||
CHECK-NEXT: 0x0000000100000f58 18 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f6c 19 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f7b 20 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f84 20 0 1 0 0 0 is_stmt end_sequence
|
||||
CHECK-NEXT: 0x0000000100000f90 11 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f9b 12 0 1 0 0 0 is_stmt prologue_end
|
||||
CHECK-NEXT: 0x0000000100000fa9 12 0 1 0 0 0 is_stmt end_sequence
|
||||
|
@ -0,0 +1,183 @@
|
||||
RUN: dsymutil --linker llvm -f -o - -oso-prepend-path=%p/../.. %p/../../Inputs/basic-lto-dw4.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s
|
||||
|
||||
CHECK: file format Mach-O 64-bit x86-64
|
||||
|
||||
CHECK: debug_info contents
|
||||
|
||||
CHECK: Compile Unit: {{.*}} version = 0x0004
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("clang version 3.7.0 ")
|
||||
CHECK: DW_AT_language (DW_LANG_C99)
|
||||
CHECK: DW_AT_name ("basic1.c")
|
||||
CHECK: DW_AT_stmt_list (0x00000000)
|
||||
CHECK: DW_AT_comp_dir ("/Inputs")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f40)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f4b)
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f40)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f4b)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_AT_name ("main")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c")
|
||||
CHECK: DW_AT_prototyped (true)
|
||||
CHECK: DW_AT_type (0x00000000000000a1
|
||||
CHECK: DW_AT_external (true)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_location (DW_OP_reg5 RDI, DW_OP_piece 0x4)
|
||||
CHECK: DW_AT_name ("argc")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c")
|
||||
CHECK: DW_AT_type (0x00000000000000a1
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_location (DW_OP_reg4 RSI)
|
||||
CHECK: DW_AT_name ("argv")
|
||||
CHECK: DW_AT_type (0x00000060
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_pointer_type
|
||||
CHECK: DW_AT_type (0x00000065
|
||||
CHECK: DW_TAG_pointer_type
|
||||
CHECK: DW_TAG_const_type
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK: DW_AT_name ("char")
|
||||
CHECK: DW_AT_encoding (DW_ATE_signed_char)
|
||||
CHECK: DW_AT_byte_size (0x01)
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: Compile Unit:{{.*}} version = 0x0004
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("clang version 3.7.0 ")
|
||||
CHECK: DW_AT_language (DW_LANG_C99)
|
||||
CHECK: DW_AT_name ("basic2.c")
|
||||
CHECK: DW_AT_stmt_list (0x00000044)
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f50)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f87)
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK: DW_AT_name ("int")
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("baz")
|
||||
CHECK: DW_AT_location (DW_OP_addr 0x100001000)
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("private_int")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic2.c")
|
||||
CHECK: DW_AT_location (DW_OP_addr 0x100001008)
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("inc")
|
||||
CHECK: DW_AT_type (0x000000a1
|
||||
CHECK: DW_AT_inline (DW_INL_inlined)
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f50)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f87)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_AT_name ("foo")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic2.c")
|
||||
CHECK: DW_AT_prototyped (true)
|
||||
CHECK: DW_AT_type (0x000000a1
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_location (0x00000000
|
||||
CHECK: [0x0000000100000f50, 0x0000000100000f5c): DW_OP_reg5 RDI, DW_OP_piece 0x4)
|
||||
CHECK: DW_AT_name ("arg")
|
||||
CHECK: DW_AT_type (0x000000a1
|
||||
CHECK: DW_TAG_inlined_subroutine
|
||||
CHECK: DW_AT_abstract_origin (0x000000d2 "inc")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f61)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f70)
|
||||
CHECK: NULL
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: Compile Unit: {{.*}} version = 0x0004
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("clang version 3.7.0 ")
|
||||
CHECK: DW_AT_name ("basic3.c")
|
||||
CHECK: DW_AT_stmt_list (0x0000009a)
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f90)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000fb4)
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("val")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic3.c")
|
||||
CHECK: DW_AT_location (DW_OP_addr 0x100001004)
|
||||
CHECK: DW_TAG_volatile_type
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("inc")
|
||||
CHECK: DW_AT_inline (DW_INL_inlined)
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f90)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000fb4)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_AT_name ("bar")
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_location (0x00000025
|
||||
CHECK: [0x0000000100000f90, 0x0000000100000f9f): DW_OP_reg5 RDI, DW_OP_piece 0x4
|
||||
CHECK: [0x0000000100000fa9, 0x0000000100000fad): DW_OP_reg5 RDI, DW_OP_piece 0x4)
|
||||
CHECK: DW_AT_name ("arg")
|
||||
CHECK: DW_TAG_inlined_subroutine
|
||||
CHECK: DW_AT_abstract_origin (0x0000015f "inc")
|
||||
CHECK: DW_AT_ranges (0x00000000
|
||||
CHECK: [0x0000000100000f94, 0x0000000100000f9a)
|
||||
CHECK: [0x0000000100000f9f, 0x0000000100000fa7))
|
||||
|
||||
CHECK: NULL
|
||||
CHECK: NULL
|
||||
|
||||
|
||||
CHECK: .debug_loc contents:
|
||||
CHECK-NEXT: 0x00000000:
|
||||
CHECK-NEXT: (0x0000000000000000, 0x000000000000000c): DW_OP_reg5 RDI, DW_OP_piece 0x4
|
||||
CHECK-NOT: :
|
||||
CHECK: 0x00000025:
|
||||
CHECK-NEXT: (0x0000000000000000, 0x000000000000000f): DW_OP_reg5 RDI, DW_OP_piece 0x4
|
||||
CHECK-NEXT: (0x0000000000000019, 0x000000000000001d): DW_OP_reg5 RDI, DW_OP_piece 0x4
|
||||
|
||||
|
||||
CHECK: .debug_aranges contents:
|
||||
CHECK-NEXT: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT: [0x0000000100000f40, 0x0000000100000f4b)
|
||||
CHECK-NEXT: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000077, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT: [0x0000000100000f50, 0x0000000100000f87)
|
||||
CHECK-NEXT: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x0000011b, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT: [0x0000000100000f90, 0x0000000100000fb4)
|
||||
|
||||
CHECK: .debug_line contents:
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic1.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: Address Line Column File ISA Discriminator OpIndex Flags
|
||||
CHECK-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
|
||||
CHECK-NEXT: 0x0000000100000f40 26 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f44 27 10 1 0 0 0 is_stmt prologue_end
|
||||
CHECK-NEXT: 0x0000000100000f49 27 3 1 0 0 0
|
||||
CHECK-NEXT: 0x0000000100000f4b 27 3 1 0 0 0 end_sequence
|
||||
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic2.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: Address Line Column File ISA Discriminator OpIndex Flags
|
||||
CHECK-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
|
||||
CHECK-NEXT: 0x0000000100000f50 19 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f54 20 18 1 0 0 0 is_stmt prologue_end
|
||||
CHECK-NEXT: 0x0000000100000f5a 20 17 1 0 0 0
|
||||
CHECK-NEXT: 0x0000000100000f5c 20 10 1 0 0 0
|
||||
CHECK-NEXT: 0x0000000100000f61 15 10 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f70 20 23 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f74 20 36 1 0 0 0
|
||||
CHECK-NEXT: 0x0000000100000f83 20 31 1 0 0 0
|
||||
CHECK-NEXT: 0x0000000100000f85 20 3 1 0 0 0
|
||||
CHECK-NEXT: 0x0000000100000f87 20 3 1 0 0 0 end_sequence
|
||||
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic3.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: Address Line Column File ISA Discriminator OpIndex Flags
|
||||
CHECK-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
|
||||
CHECK-NEXT: 0x0000000100000f90 16 0 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f94 12 10 1 0 0 0 is_stmt prologue_end
|
||||
CHECK-NEXT: 0x0000000100000f9a 17 7 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000f9f 12 10 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000fa7 20 1 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000fa9 19 18 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000fab 19 10 1 0 0 0
|
||||
CHECK-NEXT: 0x0000000100000fb2 20 1 1 0 0 0 is_stmt
|
||||
CHECK-NEXT: 0x0000000100000fb4 20 1 1 0 0 0 is_stmt end_sequence
|
||||
|
||||
CHECK-NOT: .debug_pubnames contents:
|
||||
CHECK-NOT: .debug_pubtypes contents:
|
@ -0,0 +1,182 @@
|
||||
RUN: dsymutil --linker llvm -f -o - -oso-prepend-path=%p/../.. %p/../../Inputs/basic-lto.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/../.. -dump-debug-map %p/../../Inputs/basic-lto.macho.x86_64 | dsymutil -f -o - -y - | llvm-dwarfdump -a - | FileCheck %s
|
||||
|
||||
CHECK: file format Mach-O 64-bit x86-64
|
||||
|
||||
CHECK: debug_info contents
|
||||
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_language (DW_LANG_C99)
|
||||
CHECK: DW_AT_name ("basic1.c")
|
||||
CHECK: DW_AT_stmt_list (0x00000000)
|
||||
CHECK: DW_AT_comp_dir ("/Inputs")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f40)
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("main")
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c")
|
||||
CHECK: DW_AT_decl_line (23)
|
||||
CHECK: DW_AT_prototyped (0x01)
|
||||
CHECK: DW_AT_type (0x00000063
|
||||
CHECK: DW_AT_external (0x01)
|
||||
CHECK: DW_AT_accessibility (DW_ACCESS_public)
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f40)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f4b)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_name ("argc")
|
||||
CHECK: DW_AT_type (0x00000063
|
||||
CHECK: DW_AT_location (DW_OP_reg5 RDI, DW_OP_piece 0x4)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_name ("argv")
|
||||
CHECK: DW_AT_type (0x0000006a
|
||||
CHECK: DW_AT_location (DW_OP_reg4 RSI)
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK: DW_AT_name ("int")
|
||||
CHECK: DW_AT_encoding (DW_ATE_signed)
|
||||
CHECK: DW_AT_byte_size (0x04)
|
||||
CHECK: DW_TAG_pointer_type
|
||||
CHECK: DW_AT_type (0x0000006f
|
||||
CHECK: DW_TAG_pointer_type
|
||||
CHECK: DW_AT_type (0x00000074
|
||||
CHECK: DW_TAG_const_type
|
||||
CHECK: DW_AT_type (0x00000079
|
||||
CHECK: DW_TAG_base_type
|
||||
CHECK: DW_AT_name ("char")
|
||||
CHECK: DW_AT_encoding (DW_ATE_signed_char)
|
||||
CHECK: DW_AT_byte_size (0x01)
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_name ("basic2.c")
|
||||
CHECK: DW_AT_stmt_list (0x0000003e)
|
||||
CHECK: DW_AT_comp_dir ("/Inputs")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f50)
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("private_int")
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic2.c")
|
||||
CHECK: DW_AT_location (DW_OP_addr 0x100001008)
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("baz")
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: DW_AT_location (DW_OP_addr 0x100001000)
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("foo")
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f50)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f89)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_name ("arg")
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: DW_AT_location (0x00000000
|
||||
CHECK: [0x0000000100000f50, 0x0000000100000f5e): DW_OP_reg5 RDI, DW_OP_piece 0x4)
|
||||
CHECK:[[INC1:0x[0-9a-f]*]]{{.*}}DW_TAG_inlined_subroutine
|
||||
CHECK: DW_AT_abstract_origin (0x00000128 "inc")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f63)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000f72)
|
||||
CHECK: DW_AT_call_line (20)
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("inc")
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: DW_AT_inline (DW_INL_inlined)
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_producer ("Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_name ("basic3.c")
|
||||
CHECK: DW_AT_stmt_list (0x0000007e)
|
||||
CHECK: DW_AT_comp_dir ("/Inputs")
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f90)
|
||||
CHECK: DW_TAG_variable
|
||||
CHECK: DW_AT_name ("val")
|
||||
CHECK: DW_AT_type (0x00000176
|
||||
CHECK: DW_AT_decl_file ("/Inputs{{[/\\]}}basic3.c")
|
||||
CHECK: DW_AT_location (DW_OP_addr 0x100001004)
|
||||
CHECK: DW_TAG_volatile_type
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("bar")
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f90)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000fb4)
|
||||
CHECK: DW_AT_frame_base (DW_OP_reg6 RBP)
|
||||
CHECK: DW_TAG_formal_parameter
|
||||
CHECK: DW_AT_name ("arg")
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: DW_AT_location (0x00000025
|
||||
CHECK: [0x0000000100000f90, 0x0000000100000f9f): DW_OP_reg5 RDI, DW_OP_piece 0x4
|
||||
CHECK: [0x0000000100000fa9, 0x0000000100000fad): DW_OP_reg5 RDI, DW_OP_piece 0x4)
|
||||
CHECK: DW_TAG_lexical_block
|
||||
CHECK: DW_AT_low_pc (0x0000000100000f94)
|
||||
CHECK: DW_AT_high_pc (0x0000000100000fa7)
|
||||
CHECK:[[INC2:0x[0-9a-f]*]]{{.*}}DW_TAG_inlined_subroutine
|
||||
CHECK: DW_AT_abstract_origin (0x000001d4 "inc")
|
||||
CHECK: DW_AT_ranges (0x00000000
|
||||
CHECK: [0x0000000100000f94, 0x0000000100000f9a)
|
||||
CHECK: [0x0000000100000f9f, 0x0000000100000fa7))
|
||||
CHECK: NULL
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name ("inc")
|
||||
CHECK: DW_AT_type (0x0000000000000063
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: .debug_loc contents:
|
||||
CHECK-NEXT: 0x00000000:
|
||||
CHECK-NEXT: (0x0000000000000000, 0x000000000000000e): DW_OP_reg5 RDI, DW_OP_piece 0x4
|
||||
CHECK-NOT: :
|
||||
CHECK: 0x00000025:
|
||||
CHECK-NEXT: (0x0000000000000000, 0x000000000000000f): DW_OP_reg5 RDI, DW_OP_piece 0x4
|
||||
CHECK-NEXT: (0x0000000000000019, 0x000000000000001d): DW_OP_reg5 RDI, DW_OP_piece 0x4
|
||||
|
||||
CHECK: .debug_aranges contents:
|
||||
CHECK-NEXT: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT: [0x0000000100000f40, 0x0000000100000f4b)
|
||||
CHECK-NEXT: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000081, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT: [0x0000000100000f50, 0x0000000100000f89)
|
||||
CHECK-NEXT: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x0000013a, addr_size = 0x08, seg_size = 0x00
|
||||
CHECK-NEXT: [0x0000000100000f90, 0x0000000100000fb4)
|
||||
|
||||
|
||||
CHECK: .debug_line contents
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic1.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: 0x0000000100000f40 23 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000f44 24 0 1 0 0 0 is_stmt prologue_end
|
||||
CHECK: 0x0000000100000f4b 24 0 1 0 0 0 is_stmt end_sequence
|
||||
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic2.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: 0x0000000100000f50 19 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000f54 20 0 1 0 0 0 is_stmt prologue_end
|
||||
CHECK: 0x0000000100000f63 15 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000f72 20 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000f89 20 0 1 0 0 0 is_stmt end_sequence
|
||||
|
||||
CHECK: file_names[ 1]:
|
||||
CHECK-NEXT: name: "basic3.c"
|
||||
CHECK-NEXT: dir_index: 0
|
||||
CHECK: 0x0000000100000f90 16 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000f94 12 0 1 0 0 0 is_stmt prologue_end
|
||||
CHECK: 0x0000000100000f9a 17 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000f9f 12 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000fa7 20 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000fa9 19 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000fb2 20 0 1 0 0 0 is_stmt
|
||||
CHECK: 0x0000000100000fb4 20 0 1 0 0 0 is_stmt end_sequence
|
||||
|
||||
CHECK-NOT: .debug_pubnames contents:
|
||||
CHECK-NOT: .debug_pubtypes contents:
|
@ -0,0 +1,12 @@
|
||||
RUN: cat %p/../../Inputs/basic-with-libfat-test.macho.x86_64 > %t1
|
||||
RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../.. %t1
|
||||
RUN: llvm-dwarfdump %t1.dwarf | FileCheck %s
|
||||
|
||||
The test binary was created by force-linking the libfat-test.a fat archive
|
||||
with the basic linking test archive, like so:
|
||||
$ clang -all_load libfat-test.a libbasic.a basic1.macho.x86_64.o -Wl,-dead_strip -u _x86_64_var
|
||||
|
||||
CHECK: DW_AT_name{{.*}}"x86_64_var"
|
||||
CHECK: DW_AT_name{{.*}}"basic2.c"
|
||||
CHECK: DW_AT_name{{.*}}"basic3.c"
|
||||
CHECK: DW_AT_name{{.*}}"basic1.c"
|
@ -0,0 +1,53 @@
|
||||
# This test verifies that an empty range list in the .debug_ranges section
|
||||
# doesn't crash dsymutil. As clang does not produce this kind of debug
|
||||
# info anymore, we used this hand-crafted assembly file to produce a testcase
|
||||
# Compile with:
|
||||
# llvm-mc -triple x86_64-apple-darwin -filetype=obj -o 1.o empty_range.o
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -y %p/../dummy-debug-map.map -oso-prepend-path %p/../../Inputs/empty_range -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
.section __TEXT,__text,regular,pure_instructions
|
||||
.macosx_version_min 10, 11
|
||||
.globl __Z3foov
|
||||
.align 4, 0x90
|
||||
__Z3foov: ## @_Z3foov
|
||||
Lfunc_begin0:
|
||||
pushq %rbp
|
||||
movq %rsp, %rbp
|
||||
popq %rbp
|
||||
retq
|
||||
Lfunc_end0:
|
||||
.section __DWARF,__debug_abbrev,regular,debug
|
||||
Lsection_abbrev:
|
||||
.byte 1 ## Abbreviation Code
|
||||
.byte 17 ## DW_TAG_compile_unit
|
||||
.byte 1 ## DW_CHILDREN_yes
|
||||
.byte 0 ## EOM(1)
|
||||
.byte 0 ## EOM(2)
|
||||
.byte 2 ## Abbreviation Code
|
||||
.byte 46 ## DW_TAG_subprogram
|
||||
.byte 0 ## DW_CHILDREN_no
|
||||
.byte 17 ## DW_AT_low_pc
|
||||
.byte 1 ## DW_FORM_addr
|
||||
.byte 0x55 ## DW_AT_ranges
|
||||
.byte 6 ## DW_FORM_data4
|
||||
.byte 0 ## EOM(1)
|
||||
.byte 0 ## EOM(2)
|
||||
.byte 0 ## EOM(3)
|
||||
.section __DWARF,__debug_info,regular,debug
|
||||
Lsection_info:
|
||||
.long 22 ## Length of Unit
|
||||
.short 2 ## DWARF version number
|
||||
.long 0 ## Offset Into Abbrev. Section
|
||||
.byte 8 ## Address Size (in bytes)
|
||||
.byte 1 ## Abbrev [1] DW_TAG_compile_unit
|
||||
.byte 2 ## Abbrev [2] DW_TAG_subprogram
|
||||
.quad Lfunc_begin0 ## DW_AT_low_pc
|
||||
.long 0 ## DW_AT_ranges (pointing at an empty entry)
|
||||
.byte 0 ## End Of Children Mark
|
||||
.section __DWARF,__debug_ranges,regular,debug
|
||||
Ldebug_range:
|
||||
.long 0
|
||||
.long 0
|
||||
|
||||
# CHECK-NOT: DW_TAG_compile_unit
|
@ -0,0 +1,36 @@
|
||||
# RUN: rm -rf %t
|
||||
# RUN: mkdir -p %t
|
||||
# RUN: llc -filetype=obj %p/../../Inputs/frame-dw2.ll -o %t/frame-dw2.o
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%t -y %s -o - | \
|
||||
# RUN: llvm-dwarfdump -debug-frame - | FileCheck %s
|
||||
|
||||
# This test is meant to verify that identical CIEs will get reused
|
||||
# in the same file but not inbetween files. For this to happen, we
|
||||
# link twice the same file using this made-up debug map:
|
||||
|
||||
---
|
||||
triple: 'i386-apple-darwin'
|
||||
objects:
|
||||
- filename: frame-dw2.o
|
||||
symbols:
|
||||
- { sym: _bar, objAddr: 0x0, binAddr: 0x1000, size: 0x12 }
|
||||
- { sym: _baz, objAddr: 0x0, binAddr: 0x2000, size: 0x12 }
|
||||
- filename: frame-dw2.o
|
||||
symbols:
|
||||
- { sym: _bar, objAddr: 0x0, binAddr: 0x3000, size: 0x12 }
|
||||
- { sym: _baz, objAddr: 0x0, binAddr: 0x4000, size: 0x12 }
|
||||
...
|
||||
|
||||
# CHECK: .debug_frame contents:
|
||||
# CHECK: 00000000 {{[0-9a-f]*}} ffffffff CIE
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: FDE cie=00000000 pc=00001000...00001
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: FDE cie=00000000 pc=00002000...00002
|
||||
# CHECK: [[CIECU2:[0-9a-f]*]] {{[0-9a-f]*}} ffffffff CIE
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: FDE cie=[[CIECU2]] pc=00003000...00003
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: FDE cie=[[CIECU2]] pc=00004000...00004
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: .eh_frame contents:
|
@ -0,0 +1,46 @@
|
||||
# RUN: rm -rf %t
|
||||
# RUN: mkdir -p %t
|
||||
# RUN: llc -filetype=obj %p/../../Inputs/frame-dw2.ll -o %t/frame-dw2.o
|
||||
# RUN: llc -filetype=obj %p/../../Inputs/frame-dw4.ll -o %t/frame-dw4.o
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%t -y %s -o - | \
|
||||
# RUN: llvm-dwarfdump -debug-frame - | FileCheck %s
|
||||
|
||||
# Check the handling of multiple different CIEs. To have CIEs that
|
||||
# appear to be different, use a dwarf2 version of the file along with
|
||||
# a dwarf 4 version. The CIE header version (and layout) will be different.
|
||||
---
|
||||
triple: 'i386-apple-darwin'
|
||||
objects:
|
||||
- filename: frame-dw2.o
|
||||
symbols:
|
||||
- { sym: _bar, objAddr: 0x0, binAddr: 0x1000, size: 0x12 }
|
||||
- { sym: _baz, objAddr: 0x0, binAddr: 0x2000, size: 0x12 }
|
||||
- filename: frame-dw4.o
|
||||
symbols:
|
||||
- { sym: _baz, objAddr: 0x0, binAddr: 0x3000, size: 0x12 }
|
||||
- filename: frame-dw2.o
|
||||
symbols:
|
||||
- { sym: _bar, objAddr: 0x0, binAddr: 0x4000, size: 0x12 }
|
||||
...
|
||||
|
||||
# CHECK: .debug_frame contents:
|
||||
# CHECK: 00000000 {{[0-9a-f]*}} ffffffff CIE
|
||||
# CHECK-NEXT: Format: DWARF32
|
||||
# CHECK-NEXT: Version:{{.*}}1
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: FDE cie=00000000 pc=00001000...00001
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: FDE cie=00000000 pc=00002000...00002
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: [[CIEDW4:[0-9a-f]*]] 00000010 ffffffff CIE
|
||||
# CHECK-NEXT: Format: DWARF32
|
||||
# CHECK-NEXT: Version:{{.*}}4
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: FDE cie=[[CIEDW4]] pc=00003000...00003
|
||||
# CHECK: [[CIEDW1_2:[0-9a-f]*]] 00000010 ffffffff CIE
|
||||
# CHECK-NEXT: Format: DWARF32
|
||||
# CHECK-NEXT: Version:{{.*}}1
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: FDE cie=[[CIEDW1_2]] pc=00004000...00004
|
||||
# CHECK-NOT: FDE
|
||||
# CHECK: .eh_frame contents:
|
@ -0,0 +1,30 @@
|
||||
RUN: rm -rf %t
|
||||
RUN: mkdir -p %t
|
||||
|
||||
RUN: cat %p/../../Inputs/basic.macho.x86_64 > %t/basic.macho.x86_64
|
||||
RUN: cat %p/../../Inputs/basic-archive.macho.x86_64 > %t/basic-archive.macho.x86_64
|
||||
RUN: cat %p/../../Inputs/basic-lto.macho.x86_64 > %t/basic-lto.macho.x86_64
|
||||
RUN: cat %p/../../Inputs/basic-lto-dw4.macho.x86_64 > %t/basic-lto-dw4.macho.x86_64
|
||||
|
||||
# Multiple inputs in flat mode
|
||||
RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../.. %t/basic.macho.x86_64 %t/basic-archive.macho.x86_64 %t/basic-lto.macho.x86_64 %t/basic-lto-dw4.macho.x86_64
|
||||
RUN: llvm-dwarfdump -a %t/basic.macho.x86_64.dwarf \
|
||||
RUN: | FileCheck %S/basic-linking-x86.test --check-prefixes=CHECK,BASIC
|
||||
RUN: llvm-dwarfdump -a %t/basic-archive.macho.x86_64.dwarf \
|
||||
RUN: | FileCheck %S/basic-linking-x86.test --check-prefixes=CHECK,ARCHIVE
|
||||
RUN: llvm-dwarfdump -a %t/basic-lto.macho.x86_64.dwarf | FileCheck %S/basic-lto-linking-x86.test
|
||||
RUN: llvm-dwarfdump -a %t/basic-lto-dw4.macho.x86_64.dwarf | FileCheck %S/basic-lto-dw4-linking-x86.test
|
||||
|
||||
# Multiple inputs that end up in the same named bundle
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/../.. %t/basic.macho.x86_64 %t/basic-archive.macho.x86_64 %t/basic-lto.macho.x86_64 %t/basic-lto-dw4.macho.x86_64 -o %t.dSYM
|
||||
RUN: llvm-dwarfdump -a %t.dSYM/Contents/Resources/DWARF/basic.macho.x86_64 \
|
||||
RUN: | FileCheck %S/basic-linking-x86.test --check-prefixes=CHECK,BASIC
|
||||
RUN: llvm-dwarfdump -a %t.dSYM/Contents/Resources/DWARF/basic-archive.macho.x86_64 \
|
||||
RUN: | FileCheck %S/basic-linking-x86.test --check-prefixes=CHECK,ARCHIVE
|
||||
RUN: llvm-dwarfdump -a %t.dSYM/Contents/Resources/DWARF/basic-lto.macho.x86_64 | FileCheck %S/basic-lto-linking-x86.test
|
||||
RUN: llvm-dwarfdump -a %t.dSYM/Contents/Resources/DWARF/basic-lto-dw4.macho.x86_64 | FileCheck %S/basic-lto-dw4-linking-x86.test
|
||||
|
||||
# Multiple inputs in a named bundle in flat mode... impossible.
|
||||
RUN: not dsymutil --linker llvm -f -oso-prepend-path=%p/../.. %t/basic.macho.x86_64 %t/basic-archive.macho.x86_64 %t/basic-lto.macho.x86_64 %t/basic-lto-dw4.macho.x86_64 -o %t.dSYM 2>&1 | FileCheck %s
|
||||
|
||||
CHECK: error: cannot use -o with multiple inputs in flat mode
|
@ -1,5 +1,9 @@
|
||||
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/alias \
|
||||
# RUN: %p/../Inputs/alias/foobar -o - | llvm-dwarfdump - 2>&1 | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs/alias \
|
||||
# RUN: %p/../Inputs/alias/foobar -o - | llvm-dwarfdump - 2>&1 | FileCheck %s
|
||||
|
||||
# CHECK-NOT: could not find object file symbol for symbol
|
||||
# CHECK: DW_AT_name ("foo.c")
|
||||
# CHECK: DW_AT_name ("bar.c")
|
||||
|
@ -1,4 +1,7 @@
|
||||
RUN: dsymutil -oso-prepend-path=%p %p/Inputs/call-site-entry.macho.x86_64 -o %t.dSYM
|
||||
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_return_pc
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p %p/Inputs/call-site-entry.macho.x86_64 -o %t.dSYM
|
||||
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_return_pc
|
||||
|
||||
CHECK: DW_AT_call_return_pc (0x0000000100000fa4)
|
||||
|
@ -22,5 +22,8 @@ twice.
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/call_return_pc/call -o %t.dSYM
|
||||
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_return_pc
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/call_return_pc/call -o %t.dSYM
|
||||
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_return_pc
|
||||
|
||||
CHECK: DW_AT_call_return_pc (0x0000000100000f72)
|
||||
CHECK: DW_AT_call_return_pc (0x0000000100000f78)
|
||||
|
@ -1,6 +1,9 @@
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/common/common.x86_64 -f -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/common/common.x86_64 -dump-debug-map | FileCheck %s --check-prefix DEBUGMAP
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/common/common.x86_64 -f -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/common/common.x86_64 -dump-debug-map | FileCheck %s --check-prefix DEBUGMAP
|
||||
|
||||
The test was compiled from two source files:
|
||||
$ cd /private/tmp/common
|
||||
$ cat common1.c
|
||||
|
@ -1,5 +1,7 @@
|
||||
RUN: dsymutil -oso-prepend-path %p/.. %p/../Inputs/common.macho.x86_64 -f -o - | llvm-dwarfdump -v -debug-info - | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/.. %p/../Inputs/common.macho.x86_64 -f -o - | llvm-dwarfdump -v -debug-info - | FileCheck %s
|
||||
|
||||
The test was compiled from a single source:
|
||||
$ cat common.c
|
||||
char common[16];
|
||||
|
@ -1,4 +1,6 @@
|
||||
# RUN: dsymutil -oso-prepend-path %p/../Inputs -y %s -f -o - | llvm-dwarfdump - --debug-line | FileCheck %s
|
||||
#
|
||||
# RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs -y %s -f -o - | llvm-dwarfdump - --debug-line | FileCheck %s
|
||||
|
||||
# This test runs dsymutil on an object file with non-standard (as far
|
||||
# as llvm is concerned) line table settings.
|
||||
|
@ -11,6 +11,13 @@ RUN: FileCheck %s --input-file %t/dsymdest/basic.macho.x86_64.dSYM/Contents/Info
|
||||
RUN: dsymutil -oso-prepend-path=%p/.. %t/basic.macho.x86_64 -toolchain "toolchain&and'some<symbols" -o %t/dsymdest/basic.macho.x86_64.dSYM
|
||||
RUN: FileCheck %s --input-file %t/dsymdest/basic.macho.x86_64.dSYM/Contents/Info.plist --check-prefix=CHECK --check-prefix=TOOLCHAIN
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/.. %t/basic.macho.x86_64 -o %t/dsymdest/basic.macho.x86_64.dSYM
|
||||
RUN: FileCheck %s --input-file %t/dsymdest/basic.macho.x86_64.dSYM/Contents/Info.plist
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/.. %t/basic.macho.x86_64 -toolchain "toolchain&and'some<symbols" -o %t/dsymdest/basic.macho.x86_64.dSYM
|
||||
RUN: FileCheck %s --input-file %t/dsymdest/basic.macho.x86_64.dSYM/Contents/Info.plist --check-prefix=CHECK --check-prefix=TOOLCHAIN
|
||||
|
||||
|
||||
CHECK: <?xml version="1.0" encoding="UTF-8"?>
|
||||
CHECK-NEXT: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
CHECK-NEXT: <plist version="1.0">
|
||||
|
@ -1,5 +1,10 @@
|
||||
// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
|
||||
|
||||
// RUN: dsymutil --linker llvm -f -y %p/dummy-debug-map.map -oso-prepend-path \
|
||||
// RUN: %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \
|
||||
// RUN: FileCheck %s --implicit-check-not \
|
||||
// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
|
||||
|
||||
// The test was compiled with:
|
||||
// clang++ -O2 -g -c dead-strip.cpp -o 1.o
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/baseaddr/loc1.x86_64 -f -o - | llvm-dwarfdump --debug-info - | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/baseaddr/loc1.x86_64 -f -o - | llvm-dwarfdump --debug-info - | FileCheck %s
|
||||
|
||||
The test was compiled from a single source:
|
||||
$ cat loc1.cpp
|
||||
int f1(int i, int j) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/ -y %s -o - | llvm-dwarfdump -debug-line - | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs/ -y %s -o - | llvm-dwarfdump -debug-line - | FileCheck %s
|
||||
|
||||
# Source:
|
||||
# int main() {
|
||||
# return 0;
|
||||
|
@ -52,6 +52,17 @@ RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
|
||||
|
||||
RUN: llvm-dwarfdump --verbose %t.dSYM | FileCheck %s --check-prefix UPDATE-DWARF
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/dwarf5/dwarf5-addrx.out -o %t.dSYM 2>&1 | FileCheck %s --allow-empty
|
||||
RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
|
||||
|
||||
RUN: llvm-dwarfdump --verbose %t.dSYM | FileCheck %s --check-prefix DWARF
|
||||
|
||||
RUN: dsymutil --linker llvm --update -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/dwarf5/dwarf5-addrx.out -o %t.dSYM 2>&1 | FileCheck %s --allow-empty
|
||||
RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
|
||||
|
||||
RUN: llvm-dwarfdump --verbose %t.dSYM | FileCheck %s --check-prefix UPDATE-DWARF
|
||||
|
||||
|
||||
CHECK-NOT: error:
|
||||
|
||||
DWARF: DW_TAG_compile_unit
|
||||
|
@ -22,6 +22,9 @@
|
||||
#RUN: dsymutil -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_return_pc
|
||||
|
||||
#RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_return_pc
|
||||
|
||||
#CHECK: DW_AT_call_return_pc (0x0000000100000f72)
|
||||
#CHECK: DW_AT_call_return_pc (0x0000000100000f78)
|
||||
|
||||
|
@ -25,6 +25,14 @@
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix UPD-DWARF-CHECK
|
||||
|
||||
#RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix DWARF-CHECK
|
||||
|
||||
#RUN: dsymutil --linker llvm --update -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix UPD-DWARF-CHECK
|
||||
|
||||
#CHECK: No errors.
|
||||
|
||||
#DWARF-CHECK: DW_TAG_compile_unit
|
||||
|
@ -1,5 +1,7 @@
|
||||
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/ -y %s -o - | llvm-dwarfdump -debug-line -debug-line-str --verbose - | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs/ -y %s -o - | llvm-dwarfdump -debug-line -debug-line-str --verbose - | FileCheck %s
|
||||
|
||||
# Source:
|
||||
# int main() {
|
||||
# return 0;
|
||||
|
@ -24,6 +24,14 @@
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix UPD-DWARF-CHECK
|
||||
|
||||
#RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix DWARF-CHECK
|
||||
|
||||
#RUN: dsymutil --linker llvm --update -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix UPD-DWARF-CHECK
|
||||
|
||||
#CHECK: No errors.
|
||||
|
||||
#DWARF-CHECK: DW_TAG_formal_parameter
|
||||
|
@ -32,11 +32,19 @@
|
||||
#RUN: dsymutil -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix DWARF-CHECK
|
||||
#
|
||||
|
||||
#RUN: dsymutil --update -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix UPD-DWARF-CHECK
|
||||
|
||||
#RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix DWARF-CHECK
|
||||
|
||||
#RUN: dsymutil --linker llvm --update -oso-prepend-path %p/../Inputs -y %s -o %t.dSYM
|
||||
#RUN: llvm-dwarfdump --verify %t.dSYM | FileCheck %s
|
||||
#RUN: llvm-dwarfdump -a --verbose %t.dSYM | FileCheck %s --check-prefix UPD-DWARF-CHECK
|
||||
|
||||
#CHECK: No errors.
|
||||
|
||||
#DWARF-CHECK: DW_TAG_compile_unit
|
||||
|
@ -18,5 +18,10 @@ RUN: llvm-dwarfdump --verify %t.dSYM
|
||||
RUN: llvm-otool -s __TEXT __eh_frame %p/../Inputs/private/tmp/eh_frame/eh_frame.out | FileCheck %s
|
||||
RUN: llvm-otool -s __TEXT __eh_frame %t.dSYM/Contents/Resources/DWARF/eh_frame.out | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/eh_frame/eh_frame.out -o %t.dSYM
|
||||
RUN: llvm-dwarfdump --verify %t.dSYM
|
||||
RUN: llvm-otool -s __TEXT __eh_frame %p/../Inputs/private/tmp/eh_frame/eh_frame.out | FileCheck %s
|
||||
RUN: llvm-otool -s __TEXT __eh_frame %t.dSYM/Contents/Resources/DWARF/eh_frame.out | FileCheck %s
|
||||
|
||||
CHECK: 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01
|
||||
CHECK: 10 0c 07 08 90 01 00 00
|
||||
|
@ -1,6 +1,8 @@
|
||||
RUN: llvm-mc %p/../Inputs/empty-CU.s -filetype obj -triple x86_64-apple-darwin -o %t.o
|
||||
RUN: dsymutil --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK: 0x00000000: Compile Unit: length = 0x00000008, format = DWARF32, version = 0x0003, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x0000000c)
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
---
|
||||
triple: 'i386-apple-darwin'
|
||||
objects:
|
||||
|
@ -1,5 +1,7 @@
|
||||
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
---
|
||||
triple: 'x86_64-apple-darwin'
|
||||
objects:
|
||||
|
@ -1,5 +1,7 @@
|
||||
# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
---
|
||||
triple: 'x86_64h-apple-darwin'
|
||||
objects:
|
||||
|
@ -1,7 +1,9 @@
|
||||
# RUN: dsymutil -f -o - -oso-prepend-path=%p/.. -y %s | llvm-dwarfdump -v - | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -o - -oso-prepend-path=%p/.. -y %s | llvm-dwarfdump -v - | FileCheck %s
|
||||
|
||||
# This test on links the Dwarf for an LTO binary and on purpose doesn't retain
|
||||
# any symbol in the second CU out of 3. To be valid DWARF ssymutil must not
|
||||
# any symbol in the second CU out of 3. To be valid DWARF dsymutil must not
|
||||
# generate an empty CU but omit it.
|
||||
|
||||
---
|
||||
@ -22,10 +24,12 @@ CHECK: DW_AT_name {{.*}} "basic1.c"
|
||||
CHECK: DW_TAG_subprogram
|
||||
DW_AT_name {{.*}} "main"
|
||||
|
||||
CHECK: 0x00000081: Compile Unit: length = 0x00000089, format = DWARF32, version = 0x0002, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000010e)
|
||||
CHECK: 0x00000081: Compile Unit: length = 0x00000089, format = DWARF32, version = 0x0002, abbr_offset = 0x00{{00|53}}, addr_size = 0x08 (next unit at 0x0000010e)
|
||||
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK: DW_AT_name {{.*}} "basic3.c"
|
||||
|
||||
CHECK: DW_TAG_subprogram [7] *
|
||||
CHECK: DW_TAG_subprogram
|
||||
CHECK: DW_AT_name {{.*}} = "bar"
|
||||
|
||||
CHECK-NOT: DW_TAG_compile_unit
|
||||
|
@ -1,5 +1,9 @@
|
||||
// REQUIRES : system-darwin
|
||||
// RUN: dsymutil -oso-prepend-path %p/.. -dump-debug-map %p/../Inputs/global_downgraded_to_static.x86_64 2>&1 | FileCheck %s
|
||||
// RUN: dsymutil -oso-prepend-path %p/.. -dump-debug-map \
|
||||
// RUN: %p/../Inputs/global_downgraded_to_static.x86_64 2>&1 | FileCheck %s
|
||||
//
|
||||
// RUN: dsymutil --linker llvm -oso-prepend-path %p/.. -dump-debug-map \
|
||||
// RUN: %p/../Inputs/global_downgraded_to_static.x86_64 2>&1 | FileCheck %s
|
||||
//
|
||||
// To build:
|
||||
// clang -g -c -DFILE1 global_downgraded_to_static.c -o 1.o
|
||||
|
@ -1,5 +1,10 @@
|
||||
// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
|
||||
|
||||
// RUN: dsymutil --linker llvm -f -y %p/dummy-debug-map.map -oso-prepend-path \
|
||||
// RUN: %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | \
|
||||
// RUN: FileCheck %s --implicit-check-not \
|
||||
// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
|
||||
|
||||
// clang -g -c inlined-static-variable.cpp -o 4.o
|
||||
|
||||
// The functions removed and not_removed are not in the debug map and are
|
||||
|
@ -25,6 +25,11 @@ RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/
|
||||
RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
|
||||
RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.omit.dSYM
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.keep.dSYM -keep-function-for-static
|
||||
RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
|
||||
RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
|
||||
|
||||
KEEP: DW_AT_name ("MyDummyVar")
|
||||
KEEP: DW_AT_name ("FOO_VAR_TYPE")
|
||||
KEEP: DW_AT_name ("x1")
|
||||
|
@ -1,5 +1,7 @@
|
||||
# RUN: dsymutil -oso-prepend-path %p/../Inputs -y %s -f -o - | llvm-dwarfdump - --debug-info | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs -y %s -f -o - | llvm-dwarfdump - --debug-info | FileCheck %s
|
||||
|
||||
# Compile with:
|
||||
# echo -e ".global _foo;\nfoo:\nnop" | clang -x assembler -g - -c -o /tmp/label.o
|
||||
|
||||
|
@ -14,6 +14,9 @@ $ clang label.o -o label.out
|
||||
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/label/label.out -o %t.dSYM
|
||||
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/label/label.out -o %t.dSYM
|
||||
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s
|
||||
|
||||
CHECK: DW_TAG_label
|
||||
CHECK-NEXT: DW_AT_name ("foobar")
|
||||
CHECK-NEXT: DW_AT_decl_file ("/tmp/label{{[/\\]}}label.c")
|
||||
|
@ -1,6 +1,9 @@
|
||||
# RUN: dsymutil -f %p/../Inputs/lc_build_version.x86_64 -o - \
|
||||
# RUN: -oso-prepend-path=%p/.. | obj2yaml | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f %p/../Inputs/lc_build_version.x86_64 -o - \
|
||||
# RUN: -oso-prepend-path=%p/.. | obj2yaml | FileCheck %s
|
||||
|
||||
CHECK: LoadCommands:
|
||||
CHECK: - cmd: LC_BUILD_VERSION
|
||||
CHECK-NEXT: cmdsize: 24
|
||||
|
@ -11,6 +11,7 @@
|
||||
# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
|
||||
# RUN: echo '...' >> %t2.map
|
||||
# RUN: dsymutil -y %t2.map -f -o - | llvm-dwarfdump -a --verbose - | FileCheck %s
|
||||
# COM: dsymutil --linker llvm -y %t2.map -f -o - | llvm-dwarfdump -a --verbose - | FileCheck %s
|
||||
|
||||
# CHECK: file format Mach-O 64-bit x86-64
|
||||
# CHECK: .debug_info contents:
|
||||
@ -20,11 +21,11 @@
|
||||
# CHECK: 0x0000001b: DW_TAG_variable
|
||||
# CHECK: DW_AT_name {{.*}}"var1"
|
||||
# CHECK: DW_AT_type {{.*}}"class1"
|
||||
# CHECK: DW_AT_location [DW_FORM_block1] (DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address)
|
||||
# CHECK: DW_AT_location [DW_FORM_block1] (DW_OP_const8u 0x{{.*}}, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address)
|
||||
# CHECK: 0x000000ab: DW_TAG_variable
|
||||
# CHECK: DW_AT_name {{.*}}"var2"
|
||||
# CHECK: DW_AT_type {{.*}}"class1"
|
||||
# CHECK: DW_AT_location [DW_FORM_block] (DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address)
|
||||
# CHECK: DW_AT_location [DW_FORM_block] (DW_OP_const8u 0x{{.*}}, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address)
|
||||
# CHECK: 0x00000146: DW_TAG_variable
|
||||
# CHECK: DW_AT_name {{.*}}"var3"
|
||||
# CHECK: DW_AT_type {{.*}}"class1"
|
||||
@ -72,13 +73,21 @@ LoadCommands:
|
||||
offset: 0x00000410
|
||||
align: 0
|
||||
reloff: 0x00000600
|
||||
nreloc: 1
|
||||
nreloc: 2
|
||||
flags: 0x02000000
|
||||
reserved1: 0x00000000
|
||||
reserved2: 0x00000000
|
||||
reserved3: 0x00000000
|
||||
relocations:
|
||||
- address: 0x1FC
|
||||
- address: 0x30
|
||||
symbolnum: 1
|
||||
pcrel: true
|
||||
length: 3
|
||||
extern: true
|
||||
type: 0
|
||||
scattered: false
|
||||
value: 0
|
||||
- address: 0xc2
|
||||
symbolnum: 1
|
||||
pcrel: true
|
||||
length: 3
|
||||
|
@ -19,6 +19,8 @@
|
||||
// RUN: cp %p/../Inputs/mismatch/1.o %t.dir/2.o
|
||||
// RUN: dsymutil --verbose -f -oso-prepend-path=%t.dir \
|
||||
// RUN: -y %p/dummy-debug-map.map -o %t.bin 2>&1 | FileCheck %s
|
||||
// RUN: dsymutil --linker llvm --verbose -f -oso-prepend-path=%t.dir \
|
||||
// RUN: -y %p/dummy-debug-map.map -o %t.bin 2>&1 | FileCheck %s
|
||||
|
||||
@import mismatch;
|
||||
|
||||
|
@ -11,6 +11,9 @@
|
||||
// RUN: dsymutil -verify -f -oso-prepend-path=%t.dir \
|
||||
// RUN: -y %p/dummy-debug-map.map -o - \
|
||||
// RUN: | llvm-dwarfdump --debug-info - | FileCheck %s
|
||||
// RUN: dsymutil --linker llvm -verify -f -oso-prepend-path=%t.dir \
|
||||
// RUN: -y %p/dummy-debug-map.map -o - \
|
||||
// RUN: | llvm-dwarfdump --debug-info - | FileCheck %s
|
||||
|
||||
@import Bar;
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -12,11 +12,16 @@ EOF
|
||||
|
||||
// RUN: rm -rf %t.dir
|
||||
// RUN: mkdir %t.dir
|
||||
// RUN: cp %p/../Inputs/modules-empty/1.o %p/../Inputs/modules-empty/Empty.pcm %t.dir
|
||||
// RUN: cp %p/../Inputs/modules-empty/1.o %p/../Inputs/modules-empty/Empty.pcm \
|
||||
// RUN: %t.dir
|
||||
// RUN: dsymutil -f -oso-prepend-path=%t.dir \
|
||||
// RUN: -verify \
|
||||
// RUN: -y %p/dummy-debug-map.map -o - \
|
||||
// RUN: | llvm-dwarfdump --debug-info - | FileCheck %s
|
||||
// RUN: dsymutil --linker llvm -f -oso-prepend-path=%t.dir \
|
||||
// RUN: -verify \
|
||||
// RUN: -y %p/dummy-debug-map.map -o - \
|
||||
// RUN: | llvm-dwarfdump --debug-info - | FileCheck %s
|
||||
|
||||
#include "Empty.h"
|
||||
int main() {
|
||||
|
@ -28,4 +28,3 @@ RUN: llvm-dwarfdump -a %t.dSYM/Contents/Resources/DWARF/basic-lto-dw4.macho.x86_
|
||||
RUN: not dsymutil -f -oso-prepend-path=%p/.. %t/basic.macho.x86_64 %t/basic-archive.macho.x86_64 %t/basic-lto.macho.x86_64 %t/basic-lto-dw4.macho.x86_64 -o %t.dSYM 2>&1 | FileCheck %s
|
||||
|
||||
CHECK: error: cannot use -o with multiple inputs in flat mode
|
||||
|
||||
|
@ -7,5 +7,10 @@ RUN: %p/dummy-debug-map.map -o %t \
|
||||
RUN: -object-prefix-map=/ModuleCache=/ModuleCacheRenamed \
|
||||
RUN: 2>&1 | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -verify -f -oso-prepend-path=%t.dir -y \
|
||||
RUN: %p/dummy-debug-map.map -o %t \
|
||||
RUN: -object-prefix-map=/ModuleCache=/ModuleCacheRenamed \
|
||||
RUN: 2>&1 | FileCheck %s
|
||||
|
||||
CHECK: warning: {{.*}}Bar.pcm:
|
||||
CHECK-NOT: warning: {{.*}}Foo.pcm:
|
||||
|
@ -24,6 +24,14 @@ RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/op-convert
|
||||
RUN: llvm-dwarfdump %p/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1 | FileCheck %s --check-prefix OBJ
|
||||
RUN: llvm-dwarfdump %t.dSYM 2>&1 | FileCheck %s --check-prefix DSYM
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs \
|
||||
RUN: %p/../Inputs/private/tmp/op-convert-offset/op-convert-offset \
|
||||
RUN: -o %t.dSYM 2>&1
|
||||
RUN: llvm-dwarfdump \
|
||||
RUN: %p/../Inputs/private/tmp/op-convert-offset/op-convert-offset.o 2>&1 \
|
||||
RUN: | FileCheck %s --check-prefix OBJ
|
||||
RUN: llvm-dwarfdump %t.dSYM 2>&1 | FileCheck %s --check-prefix DSYM
|
||||
|
||||
OBJ: 0x0000007d: DW_TAG_base_type
|
||||
OBJ: DW_AT_name ("DW_ATE_unsigned_1")
|
||||
OBJ: DW_AT_encoding (DW_ATE_unsigned)
|
||||
@ -42,4 +50,4 @@ DSYM: DW_AT_byte_size (0x01)
|
||||
DSYM: 0x0000009b: DW_TAG_formal_parameter
|
||||
DSYM: DW_AT_location (DW_OP_breg2 RCX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_convert (0x00000084) "DW_ATE_unsigned_1", DW_OP_convert (0x00000088) "DW_ATE_unsigned_8", DW_OP_stack_value)
|
||||
DSYM: DW_AT_name ("b")
|
||||
DSYM: DW_AT_type (0x000000b6 "_Bool")
|
||||
DSYM: DW_AT_type ({{.*}} "_Bool")
|
||||
|
@ -1,6 +1,9 @@
|
||||
# RUN: dsymutil -f -o %t --verify -oso-prepend-path=%p/../Inputs -y %s
|
||||
# RUN: llvm-dwarfdump %t | FileCheck %s
|
||||
|
||||
# RUN: dsymutil --linker llvm -f -o %t --verify -oso-prepend-path=%p/../Inputs -y %s
|
||||
# RUN: llvm-dwarfdump %t | FileCheck %s
|
||||
|
||||
---
|
||||
triple: 'x86_64-apple-darwin'
|
||||
objects:
|
||||
|
@ -1,5 +1,7 @@
|
||||
RUN: env RC_DEBUG_OPTIONS=1 dsymutil -f %p/../Inputs/basic.macho.x86_64 -o - | llvm-dwarfdump -v - | FileCheck -DMSG=%errc_ENOENT %s
|
||||
|
||||
RUN: env RC_DEBUG_OPTIONS=1 dsymutil --linker llvm -f %p/../Inputs/basic.macho.x86_64 -o - | llvm-dwarfdump -v - | FileCheck -DMSG=%errc_ENOENT %s
|
||||
|
||||
CHECK: .debug_info contents:
|
||||
CHECK: Compile Unit:
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
|
@ -9,6 +9,9 @@ RUN: yaml2obj %p/../Inputs/reflection_metadata.yaml -o %t.dir/tmp/reflection_met
|
||||
RUN: dsymutil -oso-prepend-path=%t.dir %t.dir/main -o %t.dir/main.dSYM
|
||||
RUN: llvm-objdump -s %t.dir/main.dSYM/Contents/Resources/DWARF/main | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%t.dir %t.dir/main -o %t.dir/main.dSYM
|
||||
RUN: llvm-objdump -s %t.dir/main.dSYM/Contents/Resources/DWARF/main | FileCheck %s
|
||||
|
||||
REQUIRES: host-byteorder-little-endian
|
||||
|
||||
|
||||
|
@ -7,10 +7,17 @@ RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs
|
||||
Check that the remark file in the bundle exists and is sane:
|
||||
RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.archive.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.archive.x86_64 | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.archive.x86_64
|
||||
|
||||
Check that the remark file in the bundle exists and is sane:
|
||||
RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.archive.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.archive.x86_64 | FileCheck %s
|
||||
|
||||
Check that we don't error if we're missing remark files from an archive, but we warn instead.
|
||||
Instead of creating a new binary, just remove the remarks prepend path.
|
||||
RUN: dsymutil -oso-prepend-path=%p/../Inputs %t/basic.macho.remarks.archive.x86_64 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/../Inputs %t/basic.macho.remarks.archive.x86_64 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING
|
||||
|
||||
CHECK: <Meta
|
||||
CHECK: <Remark Num
|
||||
CHECK: <Remark Num
|
||||
|
@ -6,3 +6,8 @@ RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs
|
||||
|
||||
Check that the remark file in the bundle does not exist:
|
||||
RUN: not cat %t/basic.macho.remarks.empty.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.empty.x86_64 2>&1
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.empty.x86_64
|
||||
|
||||
Check that the remark file in the bundle does not exist:
|
||||
RUN: not cat %t/basic.macho.remarks.empty.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.empty.x86_64 2>&1
|
||||
|
@ -7,10 +7,18 @@ RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs
|
||||
Check that the remark file in the bundle exists and is sane:
|
||||
RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.x86_64 | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.x86_64
|
||||
|
||||
Check that the remark file in the bundle exists and is sane:
|
||||
RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.x86_64 | FileCheck %s
|
||||
|
||||
Now emit it in a different format: YAML.
|
||||
RUN: dsymutil -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.x86_64
|
||||
RUN: cat %t/basic.macho.remarks.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.x86_64 | FileCheck %s --check-prefix=CHECK-YAML
|
||||
|
||||
RUN: dsymutil --linker llvm -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.x86_64
|
||||
RUN: cat %t/basic.macho.remarks.x86_64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.x86_64 | FileCheck %s --check-prefix=CHECK-YAML
|
||||
|
||||
CHECK: <Meta
|
||||
CHECK: <Remark Num
|
||||
CHECK: <Remark Num
|
||||
|
@ -11,6 +11,13 @@ RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Rema
|
||||
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64 | FileCheck %s
|
||||
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-i386 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-i386
|
||||
|
||||
RUN: dsymutil --linker llvm -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/fat.macho.remarks.x86
|
||||
|
||||
Check that the remark files in the bundle exist and are all sane:
|
||||
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64h | FileCheck %s
|
||||
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64 | FileCheck %s
|
||||
RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-i386 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-i386
|
||||
|
||||
CHECK: <Meta
|
||||
CHECK: <Remark Num
|
||||
CHECK: <Remark Num
|
||||
|
@ -28,12 +28,18 @@ RUN: llvm-dwarfdump -a %t.generate | FileCheck %s
|
||||
RUN: rm -rf %t
|
||||
RUN: not dsymutil -f -o %t.error -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 2>&1 | FileCheck %s --check-prefix=ERROR
|
||||
|
||||
RUN: not dsymutil --linker llvm -f -o %t.error -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 2>&1 | FileCheck %s --check-prefix=ERROR
|
||||
|
||||
# Use the reproducer.
|
||||
RUN: dsymutil -use-reproducer %t.repro -f -o - -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -use-reproducer %t.repro -f -o - -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s
|
||||
|
||||
# Using a reproducer takes precedence.
|
||||
RUN: dsymutil -gen-reproducer -use-reproducer %t.repro -f -o - -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s
|
||||
|
||||
RUN: dsymutil --linker llvm -gen-reproducer -use-reproducer %t.repro -f -o - -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s
|
||||
|
||||
CHECK: .debug_info
|
||||
CHECK: DW_TAG_compile_unit
|
||||
CHECK-NEXT: DW_AT_producer ("Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
|
@ -1,4 +1,5 @@
|
||||
# RUN: dsymutil -statistics -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 %p/../Inputs/basic-archive.macho.x86_64 %p/../Inputs/basic-lto.macho.x86_64 %p/../Inputs/basic-lto-dw4.macho.x86_64 -o %t 2>&1 | FileCheck %s
|
||||
# RUN: dsymutil --linker llvm -statistics -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 %p/../Inputs/basic-archive.macho.x86_64 %p/../Inputs/basic-lto.macho.x86_64 %p/../Inputs/basic-lto-dw4.macho.x86_64 -o %t 2>&1 | FileCheck %s
|
||||
#
|
||||
# CHECK: -------------------------------------------------------------------------------
|
||||
# CHECK-NEXT: Filename Object dSYM Change
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user