llvm-capstone/lldb/source/Expression/DWARFExpressionList.cpp
Philip Pfaffe c08d3b08f6 [lldb] Allow plugins to extend DWARF expression parsing for vendor extensions
Parsing DWARF expressions currently does not support DW_OPs that are vendor
extensions. With this change expression parsing calls into SymbolFileDWARF for
unknown opcodes, which is the semantically "closest" plugin that we have right
now. Plugins can then extend SymbolFileDWARF to add support for vendor
extensions.

Reviewed By: labath

Differential Revision: https://reviews.llvm.org/D137247
2022-11-22 14:38:07 +00:00

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);
}