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) const201 llvm::Expected<Value> DWARFExpressionList::Evaluate(
202 ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
203 lldb::addr_t func_load_addr, const Value *initial_value_ptr,
204 const Value *object_address_ptr) const {
205 ModuleSP module_sp = m_module_wp.lock();
206 DataExtractor data;
207 RegisterKind reg_kind;
208 DWARFExpression expr;
209 if (IsAlwaysValidSingleExpr()) {
210 expr = m_exprs.Back()->data;
211 } else {
212 Address pc;
213 StackFrame *frame = nullptr;
214 if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) {
215 if (exe_ctx)
216 frame = exe_ctx->GetFramePtr();
217 if (!frame)
218 return llvm::createStringError("no frame");
219 RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
220 if (!reg_ctx_sp)
221 return llvm::createStringError("no register context");
222 reg_ctx_sp->GetPCForSymbolication(pc);
223 }
224
225 if (!pc.IsValid()) {
226 return llvm::createStringError("Invalid PC in frame.");
227 }
228 addr_t pc_load_addr = pc.GetLoadAddress(exe_ctx->GetTargetPtr());
229 const DWARFExpression *entry =
230 GetExpressionAtAddress(func_load_addr, pc_load_addr);
231 if (!entry)
232 return llvm::createStringError("variable not available");
233 expr = *entry;
234 }
235 expr.GetExpressionData(data);
236 reg_kind = expr.GetRegisterKind();
237 return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, data,
238 m_dwarf_cu, reg_kind, initial_value_ptr,
239 object_address_ptr);
240 }
241