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