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