blob: 7928fa7bf98ea0ffcd52330b30f3e28909cc46ca [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/zxdb/symbols/dwarf_unit_impl.h"
#include <lib/syslog/cpp/macros.h>
#include <algorithm>
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "src/developer/debug/zxdb/common/ref_ptr_to.h"
#include "src/developer/debug/zxdb/symbols/address_range_map_builder.h"
#include "src/developer/debug/zxdb/symbols/dwarf_binary_impl.h"
#include "src/developer/debug/zxdb/symbols/function.h"
#include "src/developer/debug/zxdb/symbols/lazy_symbol.h"
#include "src/developer/debug/zxdb/symbols/line_table_impl.h"
namespace zxdb {
DwarfUnitImpl::DwarfUnitImpl(DwarfBinaryImpl* binary, llvm::DWARFUnit* unit)
: binary_(binary->GetWeakPtr()), unit_(unit) {}
DwarfBinary* DwarfUnitImpl::GetBinary() const { return binary_.get(); }
llvm::DWARFUnit* DwarfUnitImpl::GetLLVMUnit() const { return unit_; }
int DwarfUnitImpl::GetDwarfVersion() const { return unit_->getVersion(); }
llvm::DWARFDie DwarfUnitImpl::GetUnitDie() const {
// Request that the unit DIEs be extracted (false parameter means "not unit die only"). Some
// operations that use this will iterate through the unit's DIEs which requires the cache to
// be populated (LLVM doesn't do this lazily and will just report "no children").
return unit_->getUnitDIE(false);
}
LazySymbol DwarfUnitImpl::FunctionForRelativeAddress(uint64_t relative_address) const {
if (!binary_) {
return LazySymbol();
}
// Only create the FuncAddrMap when we're actually dealing with DWO files. This operation is quite
// costly in addition to creating the LLVM DIE index. Note the FuncAddrMap will work in all cases,
// it is purely an optimization to skip creating it for non-DWO binaries. The overhead may be
// avoided by either not indexing the LLVM cache, or by skipping the creation of this mapping. We
// are currently choosing to take the second of those options to support DWO while keeping the
// non-DWO case fast.
if (unit_->isDWOUnit()) {
EnsureFuncAddrMap();
uint64_t offset = func_addr_to_die_offset_.Lookup(relative_address);
if (offset)
return binary_->GetSymbolFactory()->MakeLazy(offset);
} else {
auto die = unit_->getSubroutineForAddress(relative_address);
if (die.isValid())
return binary_->GetSymbolFactory()->MakeLazy(die.getOffset());
}
return LazySymbol();
}
uint64_t DwarfUnitImpl::GetOffset() const {
if (!binary_)
return 0;
return unit_->getOffset();
}
std::string DwarfUnitImpl::GetCompilationDir() const {
if (!binary_)
return std::string();
// getCompilationDir() can return null if unset so be careful not to crash.
const char* comp_dir = unit_->getCompilationDir();
if (!comp_dir)
return std::string();
return std::string(comp_dir);
}
const LineTable& DwarfUnitImpl::GetLineTable() const {
if (!line_table_) {
if (binary_) {
line_table_.emplace(GetWeakPtr(), GetLLVMLineTable());
} else {
line_table_.emplace();
}
}
return *line_table_;
}
const llvm::DWARFDebugLine::LineTable* DwarfUnitImpl::GetLLVMLineTable() const {
if (!binary_)
return nullptr;
return binary_->GetLLVMContext()->getLineTableForUnit(unit_);
}
uint64_t DwarfUnitImpl::GetDieCount() const { return unit_->getNumDIEs(); }
llvm::DWARFDie DwarfUnitImpl::GetLLVMDieAtIndex(uint64_t index) const {
return unit_->getDIEAtIndex(index);
}
llvm::DWARFDie DwarfUnitImpl::GetLLVMDieAtOffset(uint64_t offset) const {
return unit_->getDIEForOffset(offset);
}
uint64_t DwarfUnitImpl::GetIndexForLLVMDie(const llvm::DWARFDie& die) const {
return unit_->getDIEIndex(die);
}
void DwarfUnitImpl::EnsureFuncAddrMap() const {
if (binary_ && func_addr_to_die_offset_.empty()) {
// Recursively collect all DIEs and their begin ranges.
AddressRangeMapBuilder builder;
AddDieToFuncAddr(*binary_, GetUnitDie(), builder);
func_addr_to_die_offset_ = builder.GetMap();
}
}
void DwarfUnitImpl::AddDieToFuncAddr(const DwarfBinary& binary, const llvm::DWARFDie& die,
AddressRangeMapBuilder& builder) const {
// Add all functions and inlines to the map.
llvm::dwarf::Tag tag = die.getTag();
if (tag == llvm::dwarf::DW_TAG_subprogram || tag == llvm::dwarf::DW_TAG_inlined_subroutine) {
auto lazy_func = binary.GetSymbolFactory()->MakeLazy(die.getOffset());
if (const Function* func = lazy_func.Get()->As<Function>()) {
builder.AddRanges(func->code_ranges(), die.getOffset());
}
}
// Recurse into children.
llvm::DWARFDie cur = die.getFirstChild();
while (cur.isValid()) {
AddDieToFuncAddr(binary, cur, builder);
cur = cur.getSibling();
}
}
} // namespace zxdb