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
17using namespace lldb;
18using namespace lldb_private;
19
20bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {
21 return GetAlwaysValidExpr() != nullptr;
22}
23
24const 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
33bool 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
41bool 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, load_addr: file_addr))
46 return expr->GetExpressionData(data);
47 return false;
48}
49
50bool 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
57std::optional<DWARFExpressionList::DWARFExpressionEntry>
58DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
59 lldb::addr_t load_addr) const {
60 if (const DWARFExpression *always = GetAlwaysValidExpr()) {
61 return DWARFExpressionEntry{.file_range: std::nullopt, .expr: 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(addr: file_pc)) {
80 AddressRange range_in_file(entry->GetRangeBase(),
81 entry->GetRangeEnd() - entry->GetRangeBase());
82 return DWARFExpressionEntry{.file_range: range_in_file, .expr: &entry->data};
83 }
84
85 // No entry covers this PC:
86 return std::nullopt;
87}
88
89const DWARFExpression *
90DWARFExpressionList::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(i: index)->data;
101}
102
103DWARFExpression *
104DWARFExpressionList::GetMutableExpressionAtAddress(lldb::addr_t func_load_addr,
105 lldb::addr_t load_addr) {
106 if (IsAlwaysValidSingleExpr())
107 return &m_exprs.GetMutableEntryAtIndex(i: 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(i: index)->data;
115}
116
117bool 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(i: 0).data;
125 return expr.ContainsThreadLocalStorage(dwarf_cu: m_dwarf_cu);
126}
127
128bool 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(i: 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(dwarf_cu: m_dwarf_cu, link_address_callback))
143 m_module_wp = new_module_sp;
144 return true;
145}
146
147bool 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(i: 0)->data;
156 else {
157 SymbolContext sc = frame.GetSymbolContext(resolve_scope: 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, load_addr: pc);
167 }
168 if (!expr)
169 return false;
170 return expr->MatchesOperand(frame, op: operand);
171}
172
173bool 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(N: load_base, Width: 2 + 2 * addr_size);
197 os << ", ";
198 os << llvm::format_hex(N: load_end, Width: 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
207void 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(Fmt: "0x%8.8" PRIx64 ": ", Vals: 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(NumSpaces: s->GetIndentLevel() + 2);
223 os << "[";
224 llvm::DWARFFormValue::dumpAddress(OS&: os, AddressSize: addr_size, Address: entry.GetRangeBase());
225 os << ", ";
226 llvm::DWARFFormValue::dumpAddress(OS&: os, AddressSize: addr_size, Address: entry.GetRangeEnd());
227 os << "): ";
228 expr.DumpLocation(s, level, abi);
229 }
230}
231
232llvm::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(address&: pc)) {
246 if (exe_ctx)
247 frame = exe_ctx->GetFramePtr();
248 if (!frame)
249 return llvm::createStringError(Fmt: "no frame");
250 RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
251 if (!reg_ctx_sp)
252 return llvm::createStringError(Fmt: "no register context");
253 reg_ctx_sp->GetPCForSymbolication(address&: pc);
254 }
255
256 if (!pc.IsValid()) {
257 return llvm::createStringError(Fmt: "Invalid PC in frame.");
258 }
259 addr_t pc_load_addr = pc.GetLoadAddress(target: exe_ctx->GetTargetPtr());
260 const DWARFExpression *entry =
261 GetExpressionAtAddress(func_load_addr, load_addr: pc_load_addr);
262 if (!entry)
263 return llvm::createStringError(Fmt: "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, opcodes: data,
269 dwarf_cu: m_dwarf_cu, reg_set: reg_kind, initial_value_ptr,
270 object_address_ptr);
271}
272

source code of lldb/source/Expression/DWARFExpressionList.cpp