249 lines
8.8 KiB
C++
249 lines
8.8 KiB
C++
//===-- DWARFExpressionList.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 "lldb/Expression/DWARFExpressionList.h"
|
|
#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
|
|
#include "lldb/Symbol/Function.h"
|
|
#include "lldb/Target/RegisterContext.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
|
|
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {
|
|
return GetAlwaysValidExpr() != nullptr;
|
|
}
|
|
|
|
const DWARFExpression * DWARFExpressionList::GetAlwaysValidExpr() const {
|
|
if (m_exprs.GetSize() != 1)
|
|
return nullptr;
|
|
const auto *expr = m_exprs.GetEntryAtIndex(0);
|
|
if (expr->base == 0 && expr->size == LLDB_INVALID_ADDRESS)
|
|
return &expr->data;
|
|
return nullptr;
|
|
}
|
|
|
|
bool DWARFExpressionList::AddExpression(addr_t base, addr_t end,
|
|
DWARFExpression expr) {
|
|
if (IsAlwaysValidSingleExpr() || base >= end)
|
|
return false;
|
|
m_exprs.Append({base, end - base, expr});
|
|
return true;
|
|
}
|
|
|
|
bool DWARFExpressionList::GetExpressionData(DataExtractor &data,
|
|
lldb::addr_t func_load_addr,
|
|
lldb::addr_t file_addr) const {
|
|
if (const DWARFExpression *expr =
|
|
GetExpressionAtAddress(func_load_addr, file_addr))
|
|
return expr->GetExpressionData(data);
|
|
return false;
|
|
}
|
|
|
|
bool DWARFExpressionList::ContainsAddress(lldb::addr_t func_load_addr,
|
|
lldb::addr_t addr) const {
|
|
if (IsAlwaysValidSingleExpr())
|
|
return true;
|
|
return GetExpressionAtAddress(func_load_addr, addr) != nullptr;
|
|
}
|
|
|
|
const DWARFExpression *
|
|
DWARFExpressionList::GetExpressionAtAddress(lldb::addr_t func_load_addr,
|
|
lldb::addr_t load_addr) const {
|
|
if (const DWARFExpression *expr = GetAlwaysValidExpr())
|
|
return expr;
|
|
if (func_load_addr == LLDB_INVALID_ADDRESS)
|
|
func_load_addr = m_func_file_addr;
|
|
addr_t addr = load_addr - func_load_addr + m_func_file_addr;
|
|
uint32_t index = m_exprs.FindEntryIndexThatContains(addr);
|
|
if (index == UINT32_MAX)
|
|
return nullptr;
|
|
return &m_exprs.GetEntryAtIndex(index)->data;
|
|
}
|
|
|
|
DWARFExpression *
|
|
DWARFExpressionList::GetMutableExpressionAtAddress(lldb::addr_t func_load_addr,
|
|
lldb::addr_t load_addr) {
|
|
if (IsAlwaysValidSingleExpr())
|
|
return &m_exprs.GetMutableEntryAtIndex(0)->data;
|
|
if (func_load_addr == LLDB_INVALID_ADDRESS)
|
|
func_load_addr = m_func_file_addr;
|
|
addr_t addr = load_addr - func_load_addr + m_func_file_addr;
|
|
uint32_t index = m_exprs.FindEntryIndexThatContains(addr);
|
|
if (index == UINT32_MAX)
|
|
return nullptr;
|
|
return &m_exprs.GetMutableEntryAtIndex(index)->data;
|
|
}
|
|
|
|
bool DWARFExpressionList::ContainsThreadLocalStorage() const {
|
|
// We are assuming for now that any thread local variable will not have a
|
|
// location list. This has been true for all thread local variables we have
|
|
// seen so far produced by any compiler.
|
|
if (!IsAlwaysValidSingleExpr())
|
|
return false;
|
|
|
|
const DWARFExpression &expr = m_exprs.GetEntryRef(0).data;
|
|
return expr.ContainsThreadLocalStorage(m_dwarf_cu);
|
|
}
|
|
|
|
bool DWARFExpressionList::LinkThreadLocalStorage(
|
|
lldb::ModuleSP new_module_sp,
|
|
std::function<lldb::addr_t(lldb::addr_t file_addr)> const
|
|
&link_address_callback) {
|
|
// We are assuming for now that any thread local variable will not have a
|
|
// location list. This has been true for all thread local variables we have
|
|
// seen so far produced by any compiler.
|
|
if (!IsAlwaysValidSingleExpr())
|
|
return false;
|
|
|
|
DWARFExpression &expr = m_exprs.GetEntryRef(0).data;
|
|
// If we linked the TLS address correctly, update the module so that when the
|
|
// expression is evaluated it can resolve the file address to a load address
|
|
// and read the TLS data
|
|
if (expr.LinkThreadLocalStorage(m_dwarf_cu, link_address_callback))
|
|
m_module_wp = new_module_sp;
|
|
return true;
|
|
}
|
|
|
|
bool DWARFExpressionList::MatchesOperand(
|
|
StackFrame &frame, const Instruction::Operand &operand) const {
|
|
RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
|
|
if (!reg_ctx_sp) {
|
|
return false;
|
|
}
|
|
const DWARFExpression *expr = nullptr;
|
|
if (IsAlwaysValidSingleExpr())
|
|
expr = &m_exprs.GetEntryAtIndex(0)->data;
|
|
else {
|
|
SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction);
|
|
if (!sc.function)
|
|
return false;
|
|
|
|
addr_t load_function_start =
|
|
sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
|
|
if (load_function_start == LLDB_INVALID_ADDRESS)
|
|
return false;
|
|
|
|
addr_t pc = frame.GetFrameCodeAddressForSymbolication().GetFileAddress();
|
|
expr = GetExpressionAtAddress(LLDB_INVALID_ADDRESS, pc);
|
|
}
|
|
if (!expr)
|
|
return false;
|
|
return expr->MatchesOperand(frame, operand);
|
|
}
|
|
|
|
bool DWARFExpressionList::DumpLocations(Stream *s, lldb::DescriptionLevel level,
|
|
lldb::addr_t func_load_addr,
|
|
lldb::addr_t file_addr,
|
|
ABI *abi) const {
|
|
llvm::raw_ostream &os = s->AsRawOstream();
|
|
llvm::ListSeparator separator;
|
|
if (const DWARFExpression *expr = GetAlwaysValidExpr()) {
|
|
expr->DumpLocation(s, level, abi);
|
|
return true;
|
|
}
|
|
for (const Entry &entry : *this) {
|
|
addr_t load_base = entry.GetRangeBase() + func_load_addr - m_func_file_addr;
|
|
addr_t load_end = entry.GetRangeEnd() + func_load_addr - m_func_file_addr;
|
|
if (file_addr != LLDB_INVALID_ADDRESS &&
|
|
(file_addr < load_base || file_addr >= load_end))
|
|
continue;
|
|
const auto &expr = entry.data;
|
|
DataExtractor data;
|
|
expr.GetExpressionData(data);
|
|
uint32_t addr_size = data.GetAddressByteSize();
|
|
|
|
os << separator;
|
|
os << "[";
|
|
os << llvm::format_hex(load_base, 2 + 2 * addr_size);
|
|
os << ", ";
|
|
os << llvm::format_hex(load_end, 2 + 2 * addr_size);
|
|
os << ") -> ";
|
|
expr.DumpLocation(s, level, abi);
|
|
if (file_addr != LLDB_INVALID_ADDRESS)
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void DWARFExpressionList::GetDescription(Stream *s,
|
|
lldb::DescriptionLevel level,
|
|
ABI *abi) const {
|
|
llvm::raw_ostream &os = s->AsRawOstream();
|
|
if (IsAlwaysValidSingleExpr()) {
|
|
m_exprs.Back()->data.DumpLocation(s, level, abi);
|
|
return;
|
|
}
|
|
os << llvm::format("0x%8.8" PRIx64 ": ", 0);
|
|
for (const Entry &entry : *this) {
|
|
const auto &expr = entry.data;
|
|
DataExtractor data;
|
|
expr.GetExpressionData(data);
|
|
uint32_t addr_size = data.GetAddressByteSize();
|
|
os << "\n";
|
|
os.indent(s->GetIndentLevel() + 2);
|
|
os << "[";
|
|
llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeBase());
|
|
os << ", ";
|
|
llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeEnd());
|
|
os << "): ";
|
|
expr.DumpLocation(s, level, abi);
|
|
}
|
|
}
|
|
|
|
bool DWARFExpressionList::Evaluate(ExecutionContext *exe_ctx,
|
|
RegisterContext *reg_ctx,
|
|
lldb::addr_t func_load_addr,
|
|
const Value *initial_value_ptr,
|
|
const Value *object_address_ptr,
|
|
Value &result, Status *error_ptr) const {
|
|
ModuleSP module_sp = m_module_wp.lock();
|
|
DataExtractor data;
|
|
RegisterKind reg_kind;
|
|
DWARFExpression expr;
|
|
if (IsAlwaysValidSingleExpr()) {
|
|
expr = m_exprs.Back()->data;
|
|
} else {
|
|
Address pc;
|
|
StackFrame *frame = nullptr;
|
|
if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) {
|
|
if (exe_ctx)
|
|
frame = exe_ctx->GetFramePtr();
|
|
if (!frame)
|
|
return false;
|
|
RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
|
|
if (!reg_ctx_sp)
|
|
return false;
|
|
reg_ctx_sp->GetPCForSymbolication(pc);
|
|
}
|
|
|
|
if (!pc.IsValid()) {
|
|
if (error_ptr)
|
|
error_ptr->SetErrorString("Invalid PC in frame.");
|
|
return false;
|
|
}
|
|
addr_t pc_load_addr = pc.GetLoadAddress(exe_ctx->GetTargetPtr());
|
|
const DWARFExpression *entry =
|
|
GetExpressionAtAddress(func_load_addr, pc_load_addr);
|
|
if (!entry) {
|
|
if (error_ptr) {
|
|
error_ptr->SetErrorString("variable not available");
|
|
}
|
|
return false;
|
|
}
|
|
expr = *entry;
|
|
}
|
|
expr.GetExpressionData(data);
|
|
reg_kind = expr.GetRegisterKind();
|
|
return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, data,
|
|
m_dwarf_cu, reg_kind, initial_value_ptr,
|
|
object_address_ptr, result, error_ptr);
|
|
}
|