aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp248
1 files changed, 248 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp b/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp
new file mode 100644
index 000000000000..5cf722c42fa9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp
@@ -0,0 +1,248 @@
+//===-- 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();
+}
+
+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(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);
+}