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 | |
20 | bool DWARFExpressionList::IsAlwaysValidSingleExpr() const { |
21 | return GetAlwaysValidExpr() != nullptr; |
22 | } |
23 | |
24 | const DWARFExpression * DWARFExpressionList::GetAlwaysValidExpr() const { |
25 | if (m_exprs.GetSize() != 1) |
26 | return nullptr; |
27 | const auto *expr = m_exprs.GetEntryAtIndex(i: 0); |
28 | if (expr->base == 0 && expr->size == LLDB_INVALID_ADDRESS) |
29 | return &expr->data; |
30 | return nullptr; |
31 | } |
32 | |
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(entry: {base, end - base, expr}); |
38 | return true; |
39 | } |
40 | |
41 | bool DWARFExpressionList::(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, load_addr: file_addr)) |
46 | return expr->GetExpressionData(data); |
47 | return false; |
48 | } |
49 | |
50 | 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, load_addr: addr) != nullptr; |
55 | } |
56 | |
57 | const DWARFExpression * |
58 | 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(i: index)->data; |
69 | } |
70 | |
71 | DWARFExpression * |
72 | DWARFExpressionList::GetMutableExpressionAtAddress(lldb::addr_t func_load_addr, |
73 | lldb::addr_t load_addr) { |
74 | if (IsAlwaysValidSingleExpr()) |
75 | return &m_exprs.GetMutableEntryAtIndex(i: 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(i: index)->data; |
83 | } |
84 | |
85 | 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(i: 0).data; |
93 | return expr.ContainsThreadLocalStorage(dwarf_cu: m_dwarf_cu); |
94 | } |
95 | |
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(i: 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(dwarf_cu: m_dwarf_cu, link_address_callback)) |
111 | m_module_wp = new_module_sp; |
112 | return true; |
113 | } |
114 | |
115 | 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(i: 0)->data; |
124 | else { |
125 | SymbolContext sc = frame.GetSymbolContext(resolve_scope: 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, load_addr: pc); |
136 | } |
137 | if (!expr) |
138 | return false; |
139 | return expr->MatchesOperand(frame, op: operand); |
140 | } |
141 | |
142 | 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(N: load_base, Width: 2 + 2 * addr_size); |
166 | os << ", " ; |
167 | os << llvm::format_hex(N: load_end, Width: 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 | |
176 | 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(Fmt: "0x%8.8" PRIx64 ": " , Vals: 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(NumSpaces: s->GetIndentLevel() + 2); |
192 | os << "[" ; |
193 | llvm::DWARFFormValue::dumpAddress(OS&: os, AddressSize: addr_size, Address: entry.GetRangeBase()); |
194 | os << ", " ; |
195 | llvm::DWARFFormValue::dumpAddress(OS&: os, AddressSize: addr_size, Address: entry.GetRangeEnd()); |
196 | os << "): " ; |
197 | expr.DumpLocation(s, level, abi); |
198 | } |
199 | } |
200 | |
201 | 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(address&: 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(address&: 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(target: exe_ctx->GetTargetPtr()); |
233 | const DWARFExpression *entry = |
234 | GetExpressionAtAddress(func_load_addr, 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, opcodes: data, |
246 | dwarf_cu: m_dwarf_cu, reg_set: reg_kind, initial_value_ptr, |
247 | object_address_ptr, result, error_ptr); |
248 | } |
249 | |