blob: 45b13f7aed8e53b3f1e049276f45c6f043d73e4a [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_binary_impl.h"
#include <lib/syslog/cpp/macros.h>
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ObjectFile.h"
#include "src/developer/debug/zxdb/common/file_util.h"
#include "src/developer/debug/zxdb/symbols/dwarf_unit_impl.h"
#include "src/lib/elflib/elflib.h"
namespace zxdb {
namespace {
uint64_t ComputeMappedLength(elflib::ElfLib& elf) {
uint64_t max = 0;
for (const elflib::Elf64_Phdr& header : elf.GetSegmentHeaders()) {
// Only check segments that are loaded. Some segments contain things like DWARF symbols that
// won't be loaded. Here we only want the size in-memory to resolve addresses in the program's
// address space.
if (header.p_type == elflib::PT_LOAD)
max = std::max(max, header.p_vaddr + header.p_memsz);
}
return max;
}
} // namespace
DwarfBinaryImpl::DwarfBinaryImpl(const std::string& name, const std::string& binary_name,
const std::string& build_id)
: name_(name), binary_name_(binary_name), build_id_(build_id), weak_factory_(this) {}
DwarfBinaryImpl::~DwarfBinaryImpl() {}
fxl::WeakPtr<DwarfBinaryImpl> DwarfBinaryImpl::GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
std::string DwarfBinaryImpl::GetName() const { return name_; }
std::string DwarfBinaryImpl::GetBuildID() const { return build_id_; }
std::time_t DwarfBinaryImpl::GetModificationTime() const { return modification_time_; }
bool DwarfBinaryImpl::HasBinary() const {
if (!binary_name_.empty())
return true;
if (auto debug = elflib::ElfLib::Create(name_))
return debug->ProbeHasProgramBits();
return false;
}
Err DwarfBinaryImpl::Load() {
if (auto debug = elflib::ElfLib::Create(name_)) {
if (debug->ProbeHasProgramBits()) {
// Found in ".debug" file.
plt_symbols_ = debug->GetPLTOffsets();
if (const auto opt_syms = debug->GetAllSymbols())
elf_symbols_ = std::move(*opt_syms);
mapped_length_ = ComputeMappedLength(*debug);
} else if (auto elf = elflib::ElfLib::Create(binary_name_)) {
// Found in binary file.
plt_symbols_ = elf->GetPLTOffsets();
if (const auto opt_syms = elf->GetAllSymbols())
elf_symbols_ = std::move(*opt_syms);
mapped_length_ = ComputeMappedLength(*elf);
}
}
llvm::Expected<llvm::object::OwningBinary<llvm::object::Binary>> bin_or_err =
llvm::object::createBinary(name_);
if (!bin_or_err) {
auto err_str = llvm::toString(bin_or_err.takeError());
return Err("Error loading symbols for \"" + name_ + "\": " + err_str);
}
modification_time_ = GetFileModificationTime(name_);
auto binary_pair = bin_or_err->takeBinary();
binary_buffer_ = std::move(binary_pair.second);
binary_ = std::move(binary_pair.first);
context_ = llvm::DWARFContext::create(*object_file());
context_->getDWARFObj().forEachInfoSections([this](const llvm::DWARFSection& s) {
compile_units_.addUnitsForSection(*context_, s, llvm::DW_SECT_INFO);
});
return Err();
}
llvm::object::ObjectFile* DwarfBinaryImpl::GetLLVMObjectFile() { return object_file(); }
llvm::DWARFContext* DwarfBinaryImpl::GetLLVMContext() { return context(); }
uint64_t DwarfBinaryImpl::GetMappedLength() const { return mapped_length_; }
const std::map<std::string, llvm::ELF::Elf64_Sym>& DwarfBinaryImpl::GetELFSymbols() const {
return elf_symbols_;
}
const std::map<std::string, uint64_t> DwarfBinaryImpl::GetPLTSymbols() const {
return plt_symbols_;
}
size_t DwarfBinaryImpl::GetUnitCount() const {
auto unit_range = context_->normal_units();
return unit_range.end() - unit_range.begin();
}
fxl::RefPtr<DwarfUnit> DwarfBinaryImpl::GetUnitAtIndex(size_t i) {
FX_DCHECK(i < GetUnitCount());
return FromLLVMUnit(context_->getUnitAtIndex(i));
}
fxl::RefPtr<DwarfUnit> DwarfBinaryImpl::UnitForRelativeAddress(uint64_t relative_address) {
return FromLLVMUnit(
compile_units_.getUnitForOffset(context_->getDebugAranges()->findAddress(relative_address)));
}
fxl::RefPtr<DwarfUnit> DwarfBinaryImpl::FromLLVMUnit(llvm::DWARFUnit* llvm_unit) {
if (!llvm_unit)
return fxl::RefPtr<DwarfUnit>();
auto found = unit_map_.find(llvm_unit);
if (found == unit_map_.end()) {
auto unit = fxl::MakeRefCounted<DwarfUnitImpl>(this, llvm_unit);
unit_map_[llvm_unit] = unit;
return unit;
}
return found->second;
}
} // namespace zxdb