1 //===-- UnwindPlan.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/Symbol/UnwindPlan.h"
11 #include "lldb/Target/Process.h"
12 #include "lldb/Target/RegisterContext.h"
13 #include "lldb/Target/Target.h"
14 #include "lldb/Target/Thread.h"
15 #include "lldb/Utility/ConstString.h"
16 #include "lldb/Utility/Log.h"
17 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
20 using namespace lldb_private
;
22 bool UnwindPlan::Row::RegisterLocation::
23 operator==(const UnwindPlan::Row::RegisterLocation
&rhs
) const {
24 if (m_type
== rhs
.m_type
) {
35 return m_location
.offset
== rhs
.m_location
.offset
;
38 return m_location
.reg_num
== rhs
.m_location
.reg_num
;
40 case atDWARFExpression
:
41 case isDWARFExpression
:
42 if (m_location
.expr
.length
== rhs
.m_location
.expr
.length
)
43 return !memcmp(m_location
.expr
.opcodes
, rhs
.m_location
.expr
.opcodes
,
44 m_location
.expr
.length
);
51 // This function doesn't copy the dwarf expression bytes; they must remain in
52 // allocated memory for the lifespan of this UnwindPlan object.
53 void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
54 const uint8_t *opcodes
, uint32_t len
) {
55 m_type
= atDWARFExpression
;
56 m_location
.expr
.opcodes
= opcodes
;
57 m_location
.expr
.length
= len
;
60 // This function doesn't copy the dwarf expression bytes; they must remain in
61 // allocated memory for the lifespan of this UnwindPlan object.
62 void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
63 const uint8_t *opcodes
, uint32_t len
) {
64 m_type
= isDWARFExpression
;
65 m_location
.expr
.opcodes
= opcodes
;
66 m_location
.expr
.length
= len
;
69 static llvm::Optional
<std::pair
<lldb::ByteOrder
, uint32_t>>
70 GetByteOrderAndAddrSize(Thread
*thread
) {
73 ProcessSP process_sp
= thread
->GetProcess();
76 ArchSpec arch
= process_sp
->GetTarget().GetArchitecture();
77 return std::make_pair(arch
.GetByteOrder(), arch
.GetAddressByteSize());
80 static void DumpDWARFExpr(Stream
&s
, llvm::ArrayRef
<uint8_t> expr
, Thread
*thread
) {
81 if (auto order_and_width
= GetByteOrderAndAddrSize(thread
)) {
82 llvm::DataExtractor
data(expr
, order_and_width
->first
== eByteOrderLittle
,
83 order_and_width
->second
);
84 llvm::DWARFExpression(data
, order_and_width
->second
, llvm::dwarf::DWARF32
)
85 .print(s
.AsRawOstream(), llvm::DIDumpOptions(), nullptr, nullptr);
87 s
.PutCString("dwarf-expr");
90 void UnwindPlan::Row::RegisterLocation::Dump(Stream
&s
,
91 const UnwindPlan
*unwind_plan
,
92 const UnwindPlan::Row
*row
,
98 s
.PutCString("=<unspec>");
104 s
.PutCString("=<undef>");
109 s
.PutCString("= <same>");
112 case atCFAPlusOffset
:
113 case isCFAPlusOffset
: {
115 if (m_type
== atCFAPlusOffset
)
117 s
.Printf("CFA%+d", m_location
.offset
);
118 if (m_type
== atCFAPlusOffset
)
122 case atAFAPlusOffset
:
123 case isAFAPlusOffset
: {
125 if (m_type
== atAFAPlusOffset
)
127 s
.Printf("AFA%+d", m_location
.offset
);
128 if (m_type
== atAFAPlusOffset
)
132 case inOtherRegister
: {
133 const RegisterInfo
*other_reg_info
= nullptr;
135 other_reg_info
= unwind_plan
->GetRegisterInfo(thread
, m_location
.reg_num
);
137 s
.Printf("=%s", other_reg_info
->name
);
139 s
.Printf("=reg(%u)", m_location
.reg_num
);
142 case atDWARFExpression
:
143 case isDWARFExpression
: {
145 if (m_type
== atDWARFExpression
)
148 s
, llvm::makeArrayRef(m_location
.expr
.opcodes
, m_location
.expr
.length
),
150 if (m_type
== atDWARFExpression
)
156 static void DumpRegisterName(Stream
&s
, const UnwindPlan
*unwind_plan
,
157 Thread
*thread
, uint32_t reg_num
) {
158 const RegisterInfo
*reg_info
= unwind_plan
->GetRegisterInfo(thread
, reg_num
);
160 s
.PutCString(reg_info
->name
);
162 s
.Printf("reg(%u)", reg_num
);
165 bool UnwindPlan::Row::FAValue::
166 operator==(const UnwindPlan::Row::FAValue
&rhs
) const {
167 if (m_type
== rhs
.m_type
) {
171 return m_value
.ra_search_offset
== rhs
.m_value
.ra_search_offset
;
173 case isRegisterPlusOffset
:
174 return m_value
.reg
.offset
== rhs
.m_value
.reg
.offset
;
176 case isRegisterDereferenced
:
177 return m_value
.reg
.reg_num
== rhs
.m_value
.reg
.reg_num
;
179 case isDWARFExpression
:
180 if (m_value
.expr
.length
== rhs
.m_value
.expr
.length
)
181 return !memcmp(m_value
.expr
.opcodes
, rhs
.m_value
.expr
.opcodes
,
182 m_value
.expr
.length
);
189 void UnwindPlan::Row::FAValue::Dump(Stream
&s
, const UnwindPlan
*unwind_plan
,
190 Thread
*thread
) const {
192 case isRegisterPlusOffset
:
193 DumpRegisterName(s
, unwind_plan
, thread
, m_value
.reg
.reg_num
);
194 s
.Printf("%+3d", m_value
.reg
.offset
);
196 case isRegisterDereferenced
:
198 DumpRegisterName(s
, unwind_plan
, thread
, m_value
.reg
.reg_num
);
201 case isDWARFExpression
:
203 llvm::makeArrayRef(m_value
.expr
.opcodes
, m_value
.expr
.length
),
207 s
.PutCString("unspecified");
210 s
.Printf("RaSearch@SP%+d", m_value
.ra_search_offset
);
215 void UnwindPlan::Row::Clear() {
216 m_cfa_value
.SetUnspecified();
217 m_afa_value
.SetUnspecified();
219 m_unspecified_registers_are_undefined
= false;
220 m_register_locations
.clear();
223 void UnwindPlan::Row::Dump(Stream
&s
, const UnwindPlan
*unwind_plan
,
224 Thread
*thread
, addr_t base_addr
) const {
225 if (base_addr
!= LLDB_INVALID_ADDRESS
)
226 s
.Printf("0x%16.16" PRIx64
": CFA=", base_addr
+ GetOffset());
228 s
.Printf("%4" PRId64
": CFA=", GetOffset());
230 m_cfa_value
.Dump(s
, unwind_plan
, thread
);
232 if (!m_afa_value
.IsUnspecified()) {
234 m_afa_value
.Dump(s
, unwind_plan
, thread
);
238 for (collection::const_iterator idx
= m_register_locations
.begin();
239 idx
!= m_register_locations
.end(); ++idx
) {
240 DumpRegisterName(s
, unwind_plan
, thread
, idx
->first
);
241 const bool verbose
= false;
242 idx
->second
.Dump(s
, unwind_plan
, this, thread
, verbose
);
247 UnwindPlan::Row::Row() : m_cfa_value(), m_afa_value(), m_register_locations() {}
249 bool UnwindPlan::Row::GetRegisterInfo(
251 UnwindPlan::Row::RegisterLocation
®ister_location
) const {
252 collection::const_iterator pos
= m_register_locations
.find(reg_num
);
253 if (pos
!= m_register_locations
.end()) {
254 register_location
= pos
->second
;
257 if (m_unspecified_registers_are_undefined
) {
258 register_location
.SetUndefined();
264 void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num
) {
265 collection::const_iterator pos
= m_register_locations
.find(reg_num
);
266 if (pos
!= m_register_locations
.end()) {
267 m_register_locations
.erase(pos
);
271 void UnwindPlan::Row::SetRegisterInfo(
273 const UnwindPlan::Row::RegisterLocation register_location
) {
274 m_register_locations
[reg_num
] = register_location
;
277 bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num
,
281 m_register_locations
.find(reg_num
) != m_register_locations
.end())
283 RegisterLocation reg_loc
;
284 reg_loc
.SetAtCFAPlusOffset(offset
);
285 m_register_locations
[reg_num
] = reg_loc
;
289 bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num
,
293 m_register_locations
.find(reg_num
) != m_register_locations
.end())
295 RegisterLocation reg_loc
;
296 reg_loc
.SetIsCFAPlusOffset(offset
);
297 m_register_locations
[reg_num
] = reg_loc
;
301 bool UnwindPlan::Row::SetRegisterLocationToUndefined(
302 uint32_t reg_num
, bool can_replace
, bool can_replace_only_if_unspecified
) {
303 collection::iterator pos
= m_register_locations
.find(reg_num
);
304 collection::iterator end
= m_register_locations
.end();
309 if (can_replace_only_if_unspecified
&& !pos
->second
.IsUnspecified())
312 RegisterLocation reg_loc
;
313 reg_loc
.SetUndefined();
314 m_register_locations
[reg_num
] = reg_loc
;
318 bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num
,
321 m_register_locations
.find(reg_num
) != m_register_locations
.end())
323 RegisterLocation reg_loc
;
324 reg_loc
.SetUnspecified();
325 m_register_locations
[reg_num
] = reg_loc
;
329 bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num
,
330 uint32_t other_reg_num
,
333 m_register_locations
.find(reg_num
) != m_register_locations
.end())
335 RegisterLocation reg_loc
;
336 reg_loc
.SetInRegister(other_reg_num
);
337 m_register_locations
[reg_num
] = reg_loc
;
341 bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num
,
344 m_register_locations
.find(reg_num
) == m_register_locations
.end())
346 RegisterLocation reg_loc
;
348 m_register_locations
[reg_num
] = reg_loc
;
352 bool UnwindPlan::Row::operator==(const UnwindPlan::Row
&rhs
) const {
353 return m_offset
== rhs
.m_offset
&& m_cfa_value
== rhs
.m_cfa_value
&&
354 m_afa_value
== rhs
.m_afa_value
&&
355 m_unspecified_registers_are_undefined
==
356 rhs
.m_unspecified_registers_are_undefined
&&
357 m_register_locations
== rhs
.m_register_locations
;
360 void UnwindPlan::AppendRow(const UnwindPlan::RowSP
&row_sp
) {
361 if (m_row_list
.empty() ||
362 m_row_list
.back()->GetOffset() != row_sp
->GetOffset())
363 m_row_list
.push_back(row_sp
);
365 m_row_list
.back() = row_sp
;
368 void UnwindPlan::InsertRow(const UnwindPlan::RowSP
&row_sp
,
369 bool replace_existing
) {
370 collection::iterator it
= m_row_list
.begin();
371 while (it
!= m_row_list
.end()) {
373 if (row
->GetOffset() >= row_sp
->GetOffset())
377 if (it
== m_row_list
.end() || (*it
)->GetOffset() != row_sp
->GetOffset())
378 m_row_list
.insert(it
, row_sp
);
379 else if (replace_existing
)
383 UnwindPlan::RowSP
UnwindPlan::GetRowForFunctionOffset(int offset
) const {
385 if (!m_row_list
.empty()) {
387 row
= m_row_list
.back();
389 collection::const_iterator pos
, end
= m_row_list
.end();
390 for (pos
= m_row_list
.begin(); pos
!= end
; ++pos
) {
391 if ((*pos
)->GetOffset() <= static_cast<lldb::offset_t
>(offset
))
401 bool UnwindPlan::IsValidRowIndex(uint32_t idx
) const {
402 return idx
< m_row_list
.size();
405 const UnwindPlan::RowSP
UnwindPlan::GetRowAtIndex(uint32_t idx
) const {
406 if (idx
< m_row_list
.size())
407 return m_row_list
[idx
];
409 Log
*log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND
));
411 "error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
412 "(number rows is %u)",
413 idx
, (uint32_t)m_row_list
.size());
414 return UnwindPlan::RowSP();
418 const UnwindPlan::RowSP
UnwindPlan::GetLastRow() const {
419 if (m_row_list
.empty()) {
420 Log
*log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND
));
421 LLDB_LOGF(log
, "UnwindPlan::GetLastRow() when rows are empty");
422 return UnwindPlan::RowSP();
424 return m_row_list
.back();
427 int UnwindPlan::GetRowCount() const { return m_row_list
.size(); }
429 void UnwindPlan::SetPlanValidAddressRange(const AddressRange
&range
) {
430 if (range
.GetBaseAddress().IsValid() && range
.GetByteSize() != 0)
431 m_plan_valid_address_range
= range
;
434 bool UnwindPlan::PlanValidAtAddress(Address addr
) {
435 // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
436 if (GetRowCount() == 0) {
437 Log
*log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND
));
440 if (addr
.Dump(&s
, nullptr, Address::DumpStyleSectionNameOffset
)) {
442 "UnwindPlan is invalid -- no unwind rows for UnwindPlan "
443 "'%s' at address %s",
444 m_source_name
.GetCString(), s
.GetData());
447 "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
448 m_source_name
.GetCString());
454 // If the 0th Row of unwind instructions is missing, or if it doesn't provide
455 // a register to use to find the Canonical Frame Address, this is not a valid
457 if (GetRowAtIndex(0).get() == nullptr ||
458 GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
459 Row::FAValue::unspecified
) {
460 Log
*log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND
));
463 if (addr
.Dump(&s
, nullptr, Address::DumpStyleSectionNameOffset
)) {
465 "UnwindPlan is invalid -- no CFA register defined in row 0 "
466 "for UnwindPlan '%s' at address %s",
467 m_source_name
.GetCString(), s
.GetData());
470 "UnwindPlan is invalid -- no CFA register defined in row 0 "
471 "for UnwindPlan '%s'",
472 m_source_name
.GetCString());
478 if (!m_plan_valid_address_range
.GetBaseAddress().IsValid() ||
479 m_plan_valid_address_range
.GetByteSize() == 0)
485 if (m_plan_valid_address_range
.ContainsFileAddress(addr
))
491 void UnwindPlan::Dump(Stream
&s
, Thread
*thread
, lldb::addr_t base_addr
) const {
492 if (!m_source_name
.IsEmpty()) {
493 s
.Printf("This UnwindPlan originally sourced from %s\n",
494 m_source_name
.GetCString());
496 if (m_lsda_address
.IsValid() && m_personality_func_addr
.IsValid()) {
497 TargetSP
target_sp(thread
->CalculateTarget());
498 addr_t lsda_load_addr
= m_lsda_address
.GetLoadAddress(target_sp
.get());
499 addr_t personality_func_load_addr
=
500 m_personality_func_addr
.GetLoadAddress(target_sp
.get());
502 if (lsda_load_addr
!= LLDB_INVALID_ADDRESS
&&
503 personality_func_load_addr
!= LLDB_INVALID_ADDRESS
) {
504 s
.Printf("LSDA address 0x%" PRIx64
505 ", personality routine is at address 0x%" PRIx64
"\n",
506 lsda_load_addr
, personality_func_load_addr
);
509 s
.Printf("This UnwindPlan is sourced from the compiler: ");
510 switch (m_plan_is_sourced_from_compiler
) {
517 case eLazyBoolCalculate
:
518 s
.Printf("not specified.\n");
521 s
.Printf("This UnwindPlan is valid at all instruction locations: ");
522 switch (m_plan_is_valid_at_all_instruction_locations
) {
529 case eLazyBoolCalculate
:
530 s
.Printf("not specified.\n");
533 s
.Printf("This UnwindPlan is for a trap handler function: ");
534 switch (m_plan_is_for_signal_trap
) {
541 case eLazyBoolCalculate
:
542 s
.Printf("not specified.\n");
545 if (m_plan_valid_address_range
.GetBaseAddress().IsValid() &&
546 m_plan_valid_address_range
.GetByteSize() > 0) {
547 s
.PutCString("Address range of this UnwindPlan: ");
548 TargetSP
target_sp(thread
->CalculateTarget());
549 m_plan_valid_address_range
.Dump(&s
, target_sp
.get(),
550 Address::DumpStyleSectionNameOffset
);
553 collection::const_iterator pos
, begin
= m_row_list
.begin(),
554 end
= m_row_list
.end();
555 for (pos
= begin
; pos
!= end
; ++pos
) {
556 s
.Printf("row[%u]: ", (uint32_t)std::distance(begin
, pos
));
557 (*pos
)->Dump(s
, this, thread
, base_addr
);
562 void UnwindPlan::SetSourceName(const char *source
) {
563 m_source_name
= ConstString(source
);
566 ConstString
UnwindPlan::GetSourceName() const { return m_source_name
; }
568 const RegisterInfo
*UnwindPlan::GetRegisterInfo(Thread
*thread
,
569 uint32_t unwind_reg
) const {
571 RegisterContext
*reg_ctx
= thread
->GetRegisterContext().get();
574 if (m_register_kind
== eRegisterKindLLDB
)
577 reg
= reg_ctx
->ConvertRegisterKindToRegisterNumber(m_register_kind
,
579 if (reg
!= LLDB_INVALID_REGNUM
)
580 return reg_ctx
->GetRegisterInfoAtIndex(reg
);