Remove legacy reflection API that maps enum --> module
[hiphop-php.git] / hphp / tools / debug-parser / dwarf-context-manager.cpp
blobce5eb20dfdaee3e6b81c3ab30842057aea4834bb
1 #include "hphp/tools/debug-parser/dwarf-context-manager.h"
3 #include <algorithm>
4 #include <filesystem>
6 #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
7 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
8 #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
10 #include "hphp/util/trace.h"
12 namespace debug_parser {
14 namespace {
15 TRACE_SET_MOD(trans);
18 DWARFContextManager::DWARFContextManager(std::string filename) {
19 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> dwarfBufferErrorOr =
20 llvm::MemoryBuffer::getFileOrSTDIN(filename);
22 if (dwarfBufferErrorOr.getError()) {
23 auto const msg = dwarfBufferErrorOr.getError().message();
24 llvm::errs() << fmt::format("Error reading file ({}): {}\n", filename,
25 msg);
26 return;
29 buffer_ = std::move(dwarfBufferErrorOr.get());
30 llvm::Expected<std::unique_ptr<llvm::object::ObjectFile>> objFile =
31 llvm::object::ObjectFile::createObjectFile(buffer_->getMemBufferRef());
33 if (!objFile) {
34 llvm::errs() << fmt::format("Failed to create object file:{}\n",
35 toString(objFile.takeError()));
36 return;
40 objFile_ = std::move(objFile.get());
42 // LLVM has a threadsafe dwarf context but we only modify the context on the
43 // main thread and then access individual units in the worker threads.
44 dwarfContext_ = llvm::DWARFContext::create(*objFile_);
46 // TODO: see if we can use the main dwarf context instead of handling .dwp in
47 // a one-off manner
48 if (std::filesystem::exists(filename + ".dwp")) {
49 dwoContext_ = dwarfContext_->getDWOContext(filename + ".dwp");
52 // Load units into supplementary datastructures
53 loadUnits();
56 void DWARFContextManager::loadUnits() {
57 // Only create the type signature index if the TU index doesn't already exist
58 const auto createIndex = !(dwoContext_ && dwoContext_->getTUIndex());
60 const auto processUnit = [&](const std::unique_ptr<llvm::DWARFUnit>& dwarfUnit, bool isInfo) {
61 // Pre-load type units to speed up lookups
62 if (dwarfUnit->isTypeUnit() || dwoContext_ == nullptr) {
63 dwarfUnit->getNonSkeletonUnitDIE(false);
66 // Store type unit signatures in a lookup table when TU index doesn't exist
67 if (dwarfUnit->isTypeUnit() && createIndex) {
68 const uint64_t typeSignature = cast_or_null<llvm::DWARFTypeUnit>(
69 dwarfUnit.get())->getTypeHash();
70 const uint64_t typeOffset = cast_or_null<llvm::DWARFTypeUnit>(
71 dwarfUnit.get())->getTypeOffset();
72 sig8Map_.emplace(
73 typeSignature,
74 getGlobalOffset(dwarfUnit->getOffset() + typeOffset, isInfo)
78 (isInfo ? infoUnits_ : typeUnits_).push_back(dwarfUnit.get());
80 return true;
83 forEachSectionUnit(processUnit, true);
84 forEachSectionUnit(processUnit, false);
87 llvm::DWARFUnit* DWARFContextManager::findUnitForGlobalOffset(GlobalOff globalOff) const {
88 auto& units = globalOff.isInfo() ? infoUnits_ : typeUnits_;
90 auto it = std::upper_bound(units.begin(), units.end(), globalOff.offset(),
91 [](uint64_t lhs, const llvm::DWARFUnit* rhs) {
92 return lhs < rhs->getNextUnitOffset();
96 // We always expect to find the unit for a given offset
97 always_assert(it != units.end() && (*it)->getOffset() <= globalOff.offset());
98 return *it;
101 DieContext DWARFContextManager::getDieContextAtGlobalOffset(GlobalOff globalOff) const {
102 auto dwarfUnit = findUnitForGlobalOffset(globalOff);
104 return {
105 .die = dwarfUnit->getDIEForOffset(globalOff.offset()),
106 .isInfo = globalOff.isInfo()
110 // Specifically do not resolve DW_AT_specification or DW_AT_abstract_origin to
111 // maintain backwards compatibility with old dwarf parser.
112 std::string DWARFContextManager::getDIEName(llvm::DWARFDie die) const {
113 for (const auto& attr : die.attributes()) {
114 if (attr.Attr == llvm::dwarf::DW_AT_name) {
115 if (auto val = llvm::dwarf::toString(attr.Value)) {
116 return *val;
121 return "";
124 GlobalOff DWARFContextManager::getGlobalOffset(uint64_t offset, bool isInfo) const {
125 // Treat all offsets as info units, this can be cleaned up as we only need
126 // offsets in one file at a time (main binary _or_ dwp)
127 const auto hasDwp = dwoContext_ != nullptr;
128 return GlobalOff{offset, isInfo, hasDwp};
131 GlobalOff DWARFContextManager::getTypeUnitOffset(uint64_t sig8) const {
132 // Use the TU index to retrieve type information, if it exists
133 if (dwoContext_ && dwoContext_->getTUIndex()) {
134 llvm::DWARFTypeUnit* tu = dwoContext_->getTypeUnitForHash(5, sig8, true);
135 if (tu) {
136 return getGlobalOffset(tu->getOffset() + tu->getTypeOffset(), true);
140 // Otherwise, it will have been populated when units were loaded
141 always_assert(sig8Map_.contains(sig8));
142 return sig8Map_.at(sig8);