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