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
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(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({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, 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, addr) != nullptr;
55}
56
57const DWARFExpression *
58DWARFExpressionList::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(index)->data;
69}
70
71DWARFExpression *
72DWARFExpressionList::GetMutableExpressionAtAddress(lldb::addr_t func_load_addr,
73                                                   lldb::addr_t load_addr) {
74  if (IsAlwaysValidSingleExpr())
75    return &m_exprs.GetMutableEntryAtIndex(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(index)->data;
83}
84
85bool 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(0).data;
93  return expr.ContainsThreadLocalStorage(m_dwarf_cu);
94}
95
96bool 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(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(m_dwarf_cu, link_address_callback))
111    m_module_wp = new_module_sp;
112  return true;
113}
114
115bool 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(0)->data;
124  else {
125    SymbolContext sc = frame.GetSymbolContext(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, pc);
136  }
137  if (!expr)
138    return false;
139  return expr->MatchesOperand(frame, operand);
140}
141
142bool 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(load_base, 2 + 2 * addr_size);
166    os << ", ";
167    os << llvm::format_hex(load_end, 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
176void 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("0x%8.8" PRIx64 ": ", 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(s->GetIndentLevel() + 2);
192    os << "[";
193    llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeBase());
194    os << ", ";
195    llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeEnd());
196    os << "): ";
197    expr.DumpLocation(s, level, abi);
198  }
199}
200
201bool 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(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(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(exe_ctx->GetTargetPtr());
233    const DWARFExpression *entry =
234        GetExpressionAtAddress(func_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, data,
246                                   m_dwarf_cu, reg_kind, initial_value_ptr,
247                                   object_address_ptr, result, error_ptr);
248}
249