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