xref: /freebsd/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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-exception
6 //
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 
17 using namespace lldb;
18 using namespace lldb_private;
19 
IsAlwaysValidSingleExpr() const20 bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {
21   return GetAlwaysValidExpr() != nullptr;
22 }
23 
GetAlwaysValidExpr() const24 const 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 
AddExpression(addr_t base,addr_t end,DWARFExpression expr)33 bool 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 
GetExpressionData(DataExtractor & data,lldb::addr_t func_load_addr,lldb::addr_t file_addr) const41 bool 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 
ContainsAddress(lldb::addr_t func_load_addr,lldb::addr_t addr) const50 bool 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 
57 std::optional<DWARFExpressionList::DWARFExpressionEntry>
GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,lldb::addr_t load_addr) const58 DWARFExpressionList::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 file
68   // 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 
89 const DWARFExpression *
GetExpressionAtAddress(lldb::addr_t func_load_addr,lldb::addr_t load_addr) const90 DWARFExpressionList::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 
103 DWARFExpression *
GetMutableExpressionAtAddress(lldb::addr_t func_load_addr,lldb::addr_t load_addr)104 DWARFExpressionList::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 
ContainsThreadLocalStorage() const117 bool DWARFExpressionList::ContainsThreadLocalStorage() const {
118   // We are assuming for now that any thread local variable will not have a
119   // location list. This has been true for all thread local variables we have
120   // 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 
LinkThreadLocalStorage(lldb::ModuleSP new_module_sp,std::function<lldb::addr_t (lldb::addr_t file_addr)> const & link_address_callback)128 bool DWARFExpressionList::LinkThreadLocalStorage(
129     lldb::ModuleSP new_module_sp,
130     std::function<lldb::addr_t(lldb::addr_t file_addr)> const
131         &link_address_callback) {
132   // We are assuming for now that any thread local variable will not have a
133   // location list. This has been true for all thread local variables we have
134   // 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 the
140   // expression is evaluated it can resolve the file address to a load address
141   // and read the TLS data
142   if (expr.LinkThreadLocalStorage(m_dwarf_cu, link_address_callback))
143     m_module_wp = new_module_sp;
144   return true;
145 }
146 
MatchesOperand(StackFrame & frame,const Instruction::Operand & operand) const147 bool 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 
DumpLocations(Stream * s,lldb::DescriptionLevel level,lldb::addr_t func_load_addr,lldb::addr_t file_addr,ABI * abi) const173 bool 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 
GetDescription(Stream * s,lldb::DescriptionLevel level,ABI * abi) const207 void 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 
Evaluate(ExecutionContext * exe_ctx,RegisterContext * reg_ctx,lldb::addr_t func_load_addr,const Value * initial_value_ptr,const Value * object_address_ptr) const232 llvm::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