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