272 lines · cpp
1//===-- DWARFExpressionList.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Expression/DWARFExpressionList.h"10#include "lldb/Core/AddressRange.h"11#include "lldb/Symbol/Function.h"12#include "lldb/Target/RegisterContext.h"13#include "lldb/Target/StackFrame.h"14#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"15#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"16 17using namespace lldb;18using namespace lldb_private;19 20bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {21 return GetAlwaysValidExpr() != nullptr;22}23 24const DWARFExpression *DWARFExpressionList::GetAlwaysValidExpr() const {25 if (m_exprs.GetSize() != 1)26 return nullptr;27 const auto *expr = m_exprs.GetEntryAtIndex(0);28 if (expr->base == 0 && expr->size == LLDB_INVALID_ADDRESS)29 return &expr->data;30 return nullptr;31}32 33bool DWARFExpressionList::AddExpression(addr_t base, addr_t end,34 DWARFExpression expr) {35 if (IsAlwaysValidSingleExpr() || base >= end)36 return false;37 m_exprs.Append({base, end - base, expr});38 return true;39}40 41bool DWARFExpressionList::GetExpressionData(DataExtractor &data,42 lldb::addr_t func_load_addr,43 lldb::addr_t file_addr) const {44 if (const DWARFExpression *expr =45 GetExpressionAtAddress(func_load_addr, file_addr))46 return expr->GetExpressionData(data);47 return false;48}49 50bool DWARFExpressionList::ContainsAddress(lldb::addr_t func_load_addr,51 lldb::addr_t addr) const {52 if (IsAlwaysValidSingleExpr())53 return true;54 return GetExpressionAtAddress(func_load_addr, addr) != nullptr;55}56 57std::optional<DWARFExpressionList::DWARFExpressionEntry>58DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,59 lldb::addr_t load_addr) const {60 if (const DWARFExpression *always = GetAlwaysValidExpr()) {61 return DWARFExpressionEntry{std::nullopt, always};62 }63 64 if (func_load_addr == LLDB_INVALID_ADDRESS)65 func_load_addr = m_func_file_addr;66 67 // Guard against underflow when translating a load address back into file68 // space.69 if (load_addr < func_load_addr)70 return std::nullopt;71 72 // Guard against overflow.73 lldb::addr_t delta = load_addr - func_load_addr;74 if (delta > std::numeric_limits<lldb::addr_t>::max() - m_func_file_addr)75 return std::nullopt;76 77 lldb::addr_t file_pc = (load_addr - func_load_addr) + m_func_file_addr;78 79 if (const auto *entry = m_exprs.FindEntryThatContains(file_pc)) {80 AddressRange range_in_file(entry->GetRangeBase(),81 entry->GetRangeEnd() - entry->GetRangeBase());82 return DWARFExpressionEntry{range_in_file, &entry->data};83 }84 85 // No entry covers this PC:86 return std::nullopt;87}88 89const DWARFExpression *90DWARFExpressionList::GetExpressionAtAddress(lldb::addr_t func_load_addr,91 lldb::addr_t load_addr) const {92 if (const DWARFExpression *expr = GetAlwaysValidExpr())93 return expr;94 if (func_load_addr == LLDB_INVALID_ADDRESS)95 func_load_addr = m_func_file_addr;96 addr_t addr = load_addr - func_load_addr + m_func_file_addr;97 uint32_t index = m_exprs.FindEntryIndexThatContains(addr);98 if (index == UINT32_MAX)99 return nullptr;100 return &m_exprs.GetEntryAtIndex(index)->data;101}102 103DWARFExpression *104DWARFExpressionList::GetMutableExpressionAtAddress(lldb::addr_t func_load_addr,105 lldb::addr_t load_addr) {106 if (IsAlwaysValidSingleExpr())107 return &m_exprs.GetMutableEntryAtIndex(0)->data;108 if (func_load_addr == LLDB_INVALID_ADDRESS)109 func_load_addr = m_func_file_addr;110 addr_t addr = load_addr - func_load_addr + m_func_file_addr;111 uint32_t index = m_exprs.FindEntryIndexThatContains(addr);112 if (index == UINT32_MAX)113 return nullptr;114 return &m_exprs.GetMutableEntryAtIndex(index)->data;115}116 117bool DWARFExpressionList::ContainsThreadLocalStorage() const {118 // We are assuming for now that any thread local variable will not have a119 // location list. This has been true for all thread local variables we have120 // seen so far produced by any compiler.121 if (!IsAlwaysValidSingleExpr())122 return false;123 124 const DWARFExpression &expr = m_exprs.GetEntryRef(0).data;125 return expr.ContainsThreadLocalStorage(m_dwarf_cu);126}127 128bool DWARFExpressionList::LinkThreadLocalStorage(129 lldb::ModuleSP new_module_sp,130 std::function<lldb::addr_t(lldb::addr_t file_addr)> const131 &link_address_callback) {132 // We are assuming for now that any thread local variable will not have a133 // location list. This has been true for all thread local variables we have134 // seen so far produced by any compiler.135 if (!IsAlwaysValidSingleExpr())136 return false;137 138 DWARFExpression &expr = m_exprs.GetEntryRef(0).data;139 // If we linked the TLS address correctly, update the module so that when the140 // expression is evaluated it can resolve the file address to a load address141 // and read the TLS data142 if (expr.LinkThreadLocalStorage(m_dwarf_cu, link_address_callback))143 m_module_wp = new_module_sp;144 return true;145}146 147bool DWARFExpressionList::MatchesOperand(148 StackFrame &frame, const Instruction::Operand &operand) const {149 RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();150 if (!reg_ctx_sp) {151 return false;152 }153 const DWARFExpression *expr = nullptr;154 if (IsAlwaysValidSingleExpr())155 expr = &m_exprs.GetEntryAtIndex(0)->data;156 else {157 SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction);158 if (!sc.function)159 return false;160 161 addr_t load_function_start = sc.function->GetAddress().GetFileAddress();162 if (load_function_start == LLDB_INVALID_ADDRESS)163 return false;164 165 addr_t pc = frame.GetFrameCodeAddressForSymbolication().GetFileAddress();166 expr = GetExpressionAtAddress(LLDB_INVALID_ADDRESS, pc);167 }168 if (!expr)169 return false;170 return expr->MatchesOperand(frame, operand);171}172 173bool DWARFExpressionList::DumpLocations(Stream *s, lldb::DescriptionLevel level,174 lldb::addr_t func_load_addr,175 lldb::addr_t file_addr,176 ABI *abi) const {177 llvm::raw_ostream &os = s->AsRawOstream();178 llvm::ListSeparator separator;179 if (const DWARFExpression *expr = GetAlwaysValidExpr()) {180 expr->DumpLocation(s, level, abi);181 return true;182 }183 for (const Entry &entry : *this) {184 addr_t load_base = entry.GetRangeBase() + func_load_addr - m_func_file_addr;185 addr_t load_end = entry.GetRangeEnd() + func_load_addr - m_func_file_addr;186 if (file_addr != LLDB_INVALID_ADDRESS &&187 (file_addr < load_base || file_addr >= load_end))188 continue;189 const auto &expr = entry.data;190 DataExtractor data;191 expr.GetExpressionData(data);192 uint32_t addr_size = data.GetAddressByteSize();193 194 os << separator;195 os << "[";196 os << llvm::format_hex(load_base, 2 + 2 * addr_size);197 os << ", ";198 os << llvm::format_hex(load_end, 2 + 2 * addr_size);199 os << ") -> ";200 expr.DumpLocation(s, level, abi);201 if (file_addr != LLDB_INVALID_ADDRESS)202 break;203 }204 return true;205}206 207void DWARFExpressionList::GetDescription(Stream *s,208 lldb::DescriptionLevel level,209 ABI *abi) const {210 llvm::raw_ostream &os = s->AsRawOstream();211 if (IsAlwaysValidSingleExpr()) {212 m_exprs.Back()->data.DumpLocation(s, level, abi);213 return;214 }215 os << llvm::format("0x%8.8" PRIx64 ": ", 0);216 for (const Entry &entry : *this) {217 const auto &expr = entry.data;218 DataExtractor data;219 expr.GetExpressionData(data);220 uint32_t addr_size = data.GetAddressByteSize();221 os << "\n";222 os.indent(s->GetIndentLevel() + 2);223 os << "[";224 llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeBase());225 os << ", ";226 llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeEnd());227 os << "): ";228 expr.DumpLocation(s, level, abi);229 }230}231 232llvm::Expected<Value> DWARFExpressionList::Evaluate(233 ExecutionContext *exe_ctx, RegisterContext *reg_ctx,234 lldb::addr_t func_load_addr, const Value *initial_value_ptr,235 const Value *object_address_ptr) const {236 ModuleSP module_sp = m_module_wp.lock();237 DataExtractor data;238 RegisterKind reg_kind;239 DWARFExpression expr;240 if (IsAlwaysValidSingleExpr()) {241 expr = m_exprs.Back()->data;242 } else {243 Address pc;244 StackFrame *frame = nullptr;245 if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) {246 if (exe_ctx)247 frame = exe_ctx->GetFramePtr();248 if (!frame)249 return llvm::createStringError("no frame");250 RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();251 if (!reg_ctx_sp)252 return llvm::createStringError("no register context");253 reg_ctx_sp->GetPCForSymbolication(pc);254 }255 256 if (!pc.IsValid()) {257 return llvm::createStringError("invalid PC in frame");258 }259 addr_t pc_load_addr = pc.GetLoadAddress(exe_ctx->GetTargetPtr());260 const DWARFExpression *entry =261 GetExpressionAtAddress(func_load_addr, pc_load_addr);262 if (!entry)263 return llvm::createStringError("variable not available");264 expr = *entry;265 }266 expr.GetExpressionData(data);267 reg_kind = expr.GetRegisterKind();268 return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, data,269 m_dwarf_cu, reg_kind, initial_value_ptr,270 object_address_ptr);271}272