1 //===-- DWARFExpressionList.cpp -------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
18 using namespace lldb_private
;
20 bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {
21 return GetAlwaysValidExpr() != nullptr;
24 const DWARFExpression
* DWARFExpressionList::GetAlwaysValidExpr() const {
25 if (m_exprs
.GetSize() != 1)
27 const auto *expr
= m_exprs
.GetEntryAtIndex(0);
28 if (expr
->base
== 0 && expr
->size
== LLDB_INVALID_ADDRESS
)
33 bool DWARFExpressionList::AddExpression(addr_t base
, addr_t end
,
34 DWARFExpression expr
) {
35 if (IsAlwaysValidSingleExpr() || base
>= end
)
37 m_exprs
.Append({base
, end
- base
, expr
});
41 bool 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
);
50 bool DWARFExpressionList::ContainsAddress(lldb::addr_t func_load_addr
,
51 lldb::addr_t addr
) const {
52 if (IsAlwaysValidSingleExpr())
54 return GetExpressionAtAddress(func_load_addr
, addr
) != nullptr;
57 const DWARFExpression
*
58 DWARFExpressionList::GetExpressionAtAddress(lldb::addr_t func_load_addr
,
59 lldb::addr_t load_addr
) const {
60 if (const DWARFExpression
*expr
= GetAlwaysValidExpr())
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
)
68 return &m_exprs
.GetEntryAtIndex(index
)->data
;
72 DWARFExpressionList::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
)
82 return &m_exprs
.GetMutableEntryAtIndex(index
)->data
;
85 bool 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())
92 const DWARFExpression
&expr
= m_exprs
.GetEntryRef(0).data
;
93 return expr
.ContainsThreadLocalStorage(m_dwarf_cu
);
96 bool 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())
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
;
115 bool DWARFExpressionList::MatchesOperand(
116 StackFrame
&frame
, const Instruction::Operand
&operand
) const {
117 RegisterContextSP reg_ctx_sp
= frame
.GetRegisterContext();
121 const DWARFExpression
*expr
= nullptr;
122 if (IsAlwaysValidSingleExpr())
123 expr
= &m_exprs
.GetEntryAtIndex(0)->data
;
125 SymbolContext sc
= frame
.GetSymbolContext(eSymbolContextFunction
);
129 addr_t load_function_start
=
130 sc
.function
->GetAddressRange().GetBaseAddress().GetFileAddress();
131 if (load_function_start
== LLDB_INVALID_ADDRESS
)
134 addr_t pc
= frame
.GetFrameCodeAddressForSymbolication().GetFileAddress();
135 expr
= GetExpressionAtAddress(LLDB_INVALID_ADDRESS
, pc
);
139 return expr
->MatchesOperand(frame
, operand
);
142 bool DWARFExpressionList::DumpLocations(Stream
*s
, lldb::DescriptionLevel level
,
143 lldb::addr_t func_load_addr
,
144 lldb::addr_t file_addr
,
146 llvm::raw_ostream
&os
= s
->AsRawOstream();
147 llvm::ListSeparator separator
;
148 if (const DWARFExpression
*expr
= GetAlwaysValidExpr()) {
149 expr
->DumpLocation(s
, level
, abi
);
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
))
158 const auto &expr
= entry
.data
;
160 expr
.GetExpressionData(data
);
161 uint32_t addr_size
= data
.GetAddressByteSize();
165 os
<< llvm::format_hex(load_base
, 2 + 2 * addr_size
);
167 os
<< llvm::format_hex(load_end
, 2 + 2 * addr_size
);
169 expr
.DumpLocation(s
, level
, abi
);
170 if (file_addr
!= LLDB_INVALID_ADDRESS
)
176 void DWARFExpressionList::GetDescription(Stream
*s
,
177 lldb::DescriptionLevel level
,
179 llvm::raw_ostream
&os
= s
->AsRawOstream();
180 if (IsAlwaysValidSingleExpr()) {
181 m_exprs
.Back()->data
.DumpLocation(s
, level
, abi
);
184 os
<< llvm::format("0x%8.8" PRIx64
": ", 0);
185 for (const Entry
&entry
: *this) {
186 const auto &expr
= entry
.data
;
188 expr
.GetExpressionData(data
);
189 uint32_t addr_size
= data
.GetAddressByteSize();
191 os
.indent(s
->GetIndentLevel() + 2);
193 llvm::DWARFFormValue::dumpAddress(os
, addr_size
, entry
.GetRangeBase());
195 llvm::DWARFFormValue::dumpAddress(os
, addr_size
, entry
.GetRangeEnd());
197 expr
.DumpLocation(s
, level
, abi
);
201 bool 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();
209 RegisterKind reg_kind
;
210 DWARFExpression expr
;
211 if (IsAlwaysValidSingleExpr()) {
212 expr
= m_exprs
.Back()->data
;
215 StackFrame
*frame
= nullptr;
216 if (!reg_ctx
|| !reg_ctx
->GetPCForSymbolication(pc
)) {
218 frame
= exe_ctx
->GetFramePtr();
221 RegisterContextSP reg_ctx_sp
= frame
->GetRegisterContext();
224 reg_ctx_sp
->GetPCForSymbolication(pc
);
229 error_ptr
->SetErrorString("Invalid PC in frame.");
232 addr_t pc_load_addr
= pc
.GetLoadAddress(exe_ctx
->GetTargetPtr());
233 const DWARFExpression
*entry
=
234 GetExpressionAtAddress(func_load_addr
, pc_load_addr
);
237 error_ptr
->SetErrorString("variable not available");
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
);