xref: /freebsd-src/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1753f127fSDimitry Andric //===-- DWARFExpressionList.cpp -------------------------------------------===//
2753f127fSDimitry Andric //
3753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6753f127fSDimitry Andric //
7753f127fSDimitry Andric //===----------------------------------------------------------------------===//
8753f127fSDimitry Andric 
9753f127fSDimitry Andric #include "lldb/Expression/DWARFExpressionList.h"
10753f127fSDimitry Andric #include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
11753f127fSDimitry Andric #include "lldb/Symbol/Function.h"
12753f127fSDimitry Andric #include "lldb/Target/RegisterContext.h"
13753f127fSDimitry Andric #include "lldb/Target/StackFrame.h"
14753f127fSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
15753f127fSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
16753f127fSDimitry Andric 
17753f127fSDimitry Andric using namespace lldb;
18753f127fSDimitry Andric using namespace lldb_private;
19753f127fSDimitry Andric 
20753f127fSDimitry Andric bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {
21753f127fSDimitry Andric   return GetAlwaysValidExpr() != nullptr;
22753f127fSDimitry Andric }
23753f127fSDimitry Andric 
24753f127fSDimitry Andric const DWARFExpression * DWARFExpressionList::GetAlwaysValidExpr() const {
25753f127fSDimitry Andric   if (m_exprs.GetSize() != 1)
26753f127fSDimitry Andric     return nullptr;
27753f127fSDimitry Andric   const auto *expr = m_exprs.GetEntryAtIndex(0);
28753f127fSDimitry Andric   if (expr->base == 0 && expr->size == LLDB_INVALID_ADDRESS)
29753f127fSDimitry Andric     return &expr->data;
30753f127fSDimitry Andric   return nullptr;
31753f127fSDimitry Andric }
32753f127fSDimitry Andric 
33753f127fSDimitry Andric bool DWARFExpressionList::AddExpression(addr_t base, addr_t end,
34753f127fSDimitry Andric                                         DWARFExpression expr) {
35753f127fSDimitry Andric   if (IsAlwaysValidSingleExpr() || base >= end)
36753f127fSDimitry Andric     return false;
37753f127fSDimitry Andric   m_exprs.Append({base, end - base, expr});
38753f127fSDimitry Andric   return true;
39753f127fSDimitry Andric }
40753f127fSDimitry Andric 
41753f127fSDimitry Andric bool DWARFExpressionList::GetExpressionData(DataExtractor &data,
42753f127fSDimitry Andric                                             lldb::addr_t func_load_addr,
43753f127fSDimitry Andric                                             lldb::addr_t file_addr) const {
44753f127fSDimitry Andric   if (const DWARFExpression *expr =
45753f127fSDimitry Andric           GetExpressionAtAddress(func_load_addr, file_addr))
46753f127fSDimitry Andric     return expr->GetExpressionData(data);
47753f127fSDimitry Andric   return false;
48753f127fSDimitry Andric }
49753f127fSDimitry Andric 
50753f127fSDimitry Andric bool DWARFExpressionList::ContainsAddress(lldb::addr_t func_load_addr,
51753f127fSDimitry Andric                                           lldb::addr_t addr) const {
52753f127fSDimitry Andric   if (IsAlwaysValidSingleExpr())
53753f127fSDimitry Andric     return true;
54753f127fSDimitry Andric   return GetExpressionAtAddress(func_load_addr, addr) != nullptr;
55753f127fSDimitry Andric }
56753f127fSDimitry Andric 
57753f127fSDimitry Andric const DWARFExpression *
58753f127fSDimitry Andric DWARFExpressionList::GetExpressionAtAddress(lldb::addr_t func_load_addr,
59753f127fSDimitry Andric                                             lldb::addr_t load_addr) const {
60753f127fSDimitry Andric   if (const DWARFExpression *expr = GetAlwaysValidExpr())
61753f127fSDimitry Andric     return expr;
62753f127fSDimitry Andric   if (func_load_addr == LLDB_INVALID_ADDRESS)
63753f127fSDimitry Andric     func_load_addr = m_func_file_addr;
64753f127fSDimitry Andric   addr_t addr = load_addr - func_load_addr + m_func_file_addr;
65753f127fSDimitry Andric   uint32_t index = m_exprs.FindEntryIndexThatContains(addr);
66753f127fSDimitry Andric   if (index == UINT32_MAX)
67753f127fSDimitry Andric     return nullptr;
68753f127fSDimitry Andric   return &m_exprs.GetEntryAtIndex(index)->data;
69753f127fSDimitry Andric }
70753f127fSDimitry Andric 
71753f127fSDimitry Andric DWARFExpression *
72753f127fSDimitry Andric DWARFExpressionList::GetMutableExpressionAtAddress(lldb::addr_t func_load_addr,
73753f127fSDimitry Andric                                                    lldb::addr_t load_addr) {
74753f127fSDimitry Andric   if (IsAlwaysValidSingleExpr())
75753f127fSDimitry Andric     return &m_exprs.GetMutableEntryAtIndex(0)->data;
76753f127fSDimitry Andric   if (func_load_addr == LLDB_INVALID_ADDRESS)
77753f127fSDimitry Andric     func_load_addr = m_func_file_addr;
78753f127fSDimitry Andric   addr_t addr = load_addr - func_load_addr + m_func_file_addr;
79753f127fSDimitry Andric   uint32_t index = m_exprs.FindEntryIndexThatContains(addr);
80753f127fSDimitry Andric   if (index == UINT32_MAX)
81753f127fSDimitry Andric     return nullptr;
82753f127fSDimitry Andric   return &m_exprs.GetMutableEntryAtIndex(index)->data;
83753f127fSDimitry Andric }
84753f127fSDimitry Andric 
85753f127fSDimitry Andric bool DWARFExpressionList::ContainsThreadLocalStorage() const {
86753f127fSDimitry Andric   // We are assuming for now that any thread local variable will not have a
87753f127fSDimitry Andric   // location list. This has been true for all thread local variables we have
88753f127fSDimitry Andric   // seen so far produced by any compiler.
89753f127fSDimitry Andric   if (!IsAlwaysValidSingleExpr())
90753f127fSDimitry Andric     return false;
91753f127fSDimitry Andric 
92753f127fSDimitry Andric   const DWARFExpression &expr = m_exprs.GetEntryRef(0).data;
93bdd1243dSDimitry Andric   return expr.ContainsThreadLocalStorage(m_dwarf_cu);
94753f127fSDimitry Andric }
95753f127fSDimitry Andric 
96753f127fSDimitry Andric bool DWARFExpressionList::LinkThreadLocalStorage(
97753f127fSDimitry Andric     lldb::ModuleSP new_module_sp,
98753f127fSDimitry Andric     std::function<lldb::addr_t(lldb::addr_t file_addr)> const
99753f127fSDimitry Andric         &link_address_callback) {
100753f127fSDimitry Andric   // We are assuming for now that any thread local variable will not have a
101753f127fSDimitry Andric   // location list. This has been true for all thread local variables we have
102753f127fSDimitry Andric   // seen so far produced by any compiler.
103753f127fSDimitry Andric   if (!IsAlwaysValidSingleExpr())
104753f127fSDimitry Andric     return false;
105753f127fSDimitry Andric 
106753f127fSDimitry Andric   DWARFExpression &expr = m_exprs.GetEntryRef(0).data;
107753f127fSDimitry Andric   // If we linked the TLS address correctly, update the module so that when the
108753f127fSDimitry Andric   // expression is evaluated it can resolve the file address to a load address
109753f127fSDimitry Andric   // and read the TLS data
110bdd1243dSDimitry Andric   if (expr.LinkThreadLocalStorage(m_dwarf_cu, link_address_callback))
111753f127fSDimitry Andric     m_module_wp = new_module_sp;
112753f127fSDimitry Andric   return true;
113753f127fSDimitry Andric }
114753f127fSDimitry Andric 
115753f127fSDimitry Andric bool DWARFExpressionList::MatchesOperand(
116753f127fSDimitry Andric     StackFrame &frame, const Instruction::Operand &operand) const {
117753f127fSDimitry Andric   RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
118753f127fSDimitry Andric   if (!reg_ctx_sp) {
119753f127fSDimitry Andric     return false;
120753f127fSDimitry Andric   }
121753f127fSDimitry Andric   const DWARFExpression *expr = nullptr;
122753f127fSDimitry Andric   if (IsAlwaysValidSingleExpr())
123753f127fSDimitry Andric     expr = &m_exprs.GetEntryAtIndex(0)->data;
124753f127fSDimitry Andric   else {
125753f127fSDimitry Andric     SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction);
126753f127fSDimitry Andric     if (!sc.function)
127753f127fSDimitry Andric       return false;
128753f127fSDimitry Andric 
129753f127fSDimitry Andric     addr_t load_function_start =
130753f127fSDimitry Andric         sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
131753f127fSDimitry Andric     if (load_function_start == LLDB_INVALID_ADDRESS)
132753f127fSDimitry Andric       return false;
133753f127fSDimitry Andric 
134753f127fSDimitry Andric     addr_t pc = frame.GetFrameCodeAddressForSymbolication().GetFileAddress();
135753f127fSDimitry Andric     expr = GetExpressionAtAddress(LLDB_INVALID_ADDRESS, pc);
136753f127fSDimitry Andric   }
137753f127fSDimitry Andric   if (!expr)
138753f127fSDimitry Andric     return false;
139753f127fSDimitry Andric   return expr->MatchesOperand(frame, operand);
140753f127fSDimitry Andric }
141753f127fSDimitry Andric 
142753f127fSDimitry Andric bool DWARFExpressionList::DumpLocations(Stream *s, lldb::DescriptionLevel level,
143753f127fSDimitry Andric                                         lldb::addr_t func_load_addr,
144753f127fSDimitry Andric                                         lldb::addr_t file_addr,
145753f127fSDimitry Andric                                         ABI *abi) const {
146753f127fSDimitry Andric   llvm::raw_ostream &os = s->AsRawOstream();
147753f127fSDimitry Andric   llvm::ListSeparator separator;
148753f127fSDimitry Andric   if (const DWARFExpression *expr = GetAlwaysValidExpr()) {
149753f127fSDimitry Andric     expr->DumpLocation(s, level, abi);
150753f127fSDimitry Andric     return true;
151753f127fSDimitry Andric   }
152753f127fSDimitry Andric   for (const Entry &entry : *this) {
153753f127fSDimitry Andric     addr_t load_base = entry.GetRangeBase() + func_load_addr - m_func_file_addr;
154753f127fSDimitry Andric     addr_t load_end = entry.GetRangeEnd() + func_load_addr - m_func_file_addr;
155753f127fSDimitry Andric     if (file_addr != LLDB_INVALID_ADDRESS &&
156753f127fSDimitry Andric         (file_addr < load_base || file_addr >= load_end))
157753f127fSDimitry Andric       continue;
158753f127fSDimitry Andric     const auto &expr = entry.data;
159753f127fSDimitry Andric     DataExtractor data;
160753f127fSDimitry Andric     expr.GetExpressionData(data);
161753f127fSDimitry Andric     uint32_t addr_size = data.GetAddressByteSize();
162753f127fSDimitry Andric 
163753f127fSDimitry Andric     os << separator;
164753f127fSDimitry Andric     os << "[";
165753f127fSDimitry Andric     os << llvm::format_hex(load_base, 2 + 2 * addr_size);
166753f127fSDimitry Andric     os << ", ";
167753f127fSDimitry Andric     os << llvm::format_hex(load_end, 2 + 2 * addr_size);
168753f127fSDimitry Andric     os << ") -> ";
169753f127fSDimitry Andric     expr.DumpLocation(s, level, abi);
170753f127fSDimitry Andric     if (file_addr != LLDB_INVALID_ADDRESS)
171753f127fSDimitry Andric       break;
172753f127fSDimitry Andric   }
173753f127fSDimitry Andric   return true;
174753f127fSDimitry Andric }
175753f127fSDimitry Andric 
176753f127fSDimitry Andric void DWARFExpressionList::GetDescription(Stream *s,
177753f127fSDimitry Andric                                          lldb::DescriptionLevel level,
178753f127fSDimitry Andric                                          ABI *abi) const {
179753f127fSDimitry Andric   llvm::raw_ostream &os = s->AsRawOstream();
180753f127fSDimitry Andric   if (IsAlwaysValidSingleExpr()) {
181753f127fSDimitry Andric     m_exprs.Back()->data.DumpLocation(s, level, abi);
182753f127fSDimitry Andric     return;
183753f127fSDimitry Andric   }
184753f127fSDimitry Andric   os << llvm::format("0x%8.8" PRIx64 ": ", 0);
185753f127fSDimitry Andric   for (const Entry &entry : *this) {
186753f127fSDimitry Andric     const auto &expr = entry.data;
187753f127fSDimitry Andric     DataExtractor data;
188753f127fSDimitry Andric     expr.GetExpressionData(data);
189753f127fSDimitry Andric     uint32_t addr_size = data.GetAddressByteSize();
190753f127fSDimitry Andric     os << "\n";
191753f127fSDimitry Andric     os.indent(s->GetIndentLevel() + 2);
192753f127fSDimitry Andric     os << "[";
193753f127fSDimitry Andric     llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeBase());
194753f127fSDimitry Andric     os << ", ";
195753f127fSDimitry Andric     llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeEnd());
196753f127fSDimitry Andric     os << "): ";
197753f127fSDimitry Andric     expr.DumpLocation(s, level, abi);
198753f127fSDimitry Andric   }
199753f127fSDimitry Andric }
200753f127fSDimitry Andric 
201*0fca6ea1SDimitry Andric llvm::Expected<Value> DWARFExpressionList::Evaluate(
202*0fca6ea1SDimitry Andric     ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
203*0fca6ea1SDimitry Andric     lldb::addr_t func_load_addr, const Value *initial_value_ptr,
204*0fca6ea1SDimitry Andric     const Value *object_address_ptr) const {
205753f127fSDimitry Andric   ModuleSP module_sp = m_module_wp.lock();
206753f127fSDimitry Andric   DataExtractor data;
207753f127fSDimitry Andric   RegisterKind reg_kind;
208753f127fSDimitry Andric   DWARFExpression expr;
209753f127fSDimitry Andric   if (IsAlwaysValidSingleExpr()) {
210753f127fSDimitry Andric     expr = m_exprs.Back()->data;
211753f127fSDimitry Andric   } else {
212753f127fSDimitry Andric     Address pc;
213753f127fSDimitry Andric     StackFrame *frame = nullptr;
214753f127fSDimitry Andric     if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) {
215753f127fSDimitry Andric       if (exe_ctx)
216753f127fSDimitry Andric         frame = exe_ctx->GetFramePtr();
217753f127fSDimitry Andric       if (!frame)
218*0fca6ea1SDimitry Andric         return llvm::createStringError("no frame");
219753f127fSDimitry Andric       RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
220753f127fSDimitry Andric       if (!reg_ctx_sp)
221*0fca6ea1SDimitry Andric         return llvm::createStringError("no register context");
222753f127fSDimitry Andric       reg_ctx_sp->GetPCForSymbolication(pc);
223753f127fSDimitry Andric     }
224753f127fSDimitry Andric 
225753f127fSDimitry Andric     if (!pc.IsValid()) {
226*0fca6ea1SDimitry Andric       return llvm::createStringError("Invalid PC in frame.");
227753f127fSDimitry Andric     }
228753f127fSDimitry Andric     addr_t pc_load_addr = pc.GetLoadAddress(exe_ctx->GetTargetPtr());
229753f127fSDimitry Andric     const DWARFExpression *entry =
230753f127fSDimitry Andric         GetExpressionAtAddress(func_load_addr, pc_load_addr);
231*0fca6ea1SDimitry Andric     if (!entry)
232*0fca6ea1SDimitry Andric       return llvm::createStringError("variable not available");
233753f127fSDimitry Andric     expr = *entry;
234753f127fSDimitry Andric   }
235753f127fSDimitry Andric   expr.GetExpressionData(data);
236753f127fSDimitry Andric   reg_kind = expr.GetRegisterKind();
237753f127fSDimitry Andric   return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, data,
238753f127fSDimitry Andric                                    m_dwarf_cu, reg_kind, initial_value_ptr,
239*0fca6ea1SDimitry Andric                                    object_address_ptr);
240753f127fSDimitry Andric }
241