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