xref: /openbsd-src/gnu/llvm/lldb/source/Symbol/UnwindPlan.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- UnwindPlan.cpp ----------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Symbol/UnwindPlan.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Target/Process.h"
12061da546Spatrick #include "lldb/Target/RegisterContext.h"
13061da546Spatrick #include "lldb/Target/Target.h"
14061da546Spatrick #include "lldb/Target/Thread.h"
15061da546Spatrick #include "lldb/Utility/ConstString.h"
16*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
17061da546Spatrick #include "lldb/Utility/Log.h"
18*f6aab3d8Srobert #include "llvm/DebugInfo/DIContext.h"
19dda28197Spatrick #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
20*f6aab3d8Srobert #include <optional>
21061da546Spatrick 
22061da546Spatrick using namespace lldb;
23061da546Spatrick using namespace lldb_private;
24061da546Spatrick 
25061da546Spatrick bool UnwindPlan::Row::RegisterLocation::
operator ==(const UnwindPlan::Row::RegisterLocation & rhs) const26061da546Spatrick operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
27061da546Spatrick   if (m_type == rhs.m_type) {
28061da546Spatrick     switch (m_type) {
29061da546Spatrick     case unspecified:
30061da546Spatrick     case undefined:
31061da546Spatrick     case same:
32061da546Spatrick       return true;
33061da546Spatrick 
34061da546Spatrick     case atCFAPlusOffset:
35061da546Spatrick     case isCFAPlusOffset:
36061da546Spatrick     case atAFAPlusOffset:
37061da546Spatrick     case isAFAPlusOffset:
38061da546Spatrick       return m_location.offset == rhs.m_location.offset;
39061da546Spatrick 
40061da546Spatrick     case inOtherRegister:
41061da546Spatrick       return m_location.reg_num == rhs.m_location.reg_num;
42061da546Spatrick 
43061da546Spatrick     case atDWARFExpression:
44061da546Spatrick     case isDWARFExpression:
45061da546Spatrick       if (m_location.expr.length == rhs.m_location.expr.length)
46061da546Spatrick         return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
47061da546Spatrick                        m_location.expr.length);
48061da546Spatrick       break;
49061da546Spatrick     }
50061da546Spatrick   }
51061da546Spatrick   return false;
52061da546Spatrick }
53061da546Spatrick 
54061da546Spatrick // This function doesn't copy the dwarf expression bytes; they must remain in
55061da546Spatrick // allocated memory for the lifespan of this UnwindPlan object.
SetAtDWARFExpression(const uint8_t * opcodes,uint32_t len)56061da546Spatrick void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
57061da546Spatrick     const uint8_t *opcodes, uint32_t len) {
58061da546Spatrick   m_type = atDWARFExpression;
59061da546Spatrick   m_location.expr.opcodes = opcodes;
60061da546Spatrick   m_location.expr.length = len;
61061da546Spatrick }
62061da546Spatrick 
63061da546Spatrick // This function doesn't copy the dwarf expression bytes; they must remain in
64061da546Spatrick // allocated memory for the lifespan of this UnwindPlan object.
SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)65061da546Spatrick void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
66061da546Spatrick     const uint8_t *opcodes, uint32_t len) {
67061da546Spatrick   m_type = isDWARFExpression;
68061da546Spatrick   m_location.expr.opcodes = opcodes;
69061da546Spatrick   m_location.expr.length = len;
70061da546Spatrick }
71061da546Spatrick 
72*f6aab3d8Srobert static std::optional<std::pair<lldb::ByteOrder, uint32_t>>
GetByteOrderAndAddrSize(Thread * thread)73061da546Spatrick GetByteOrderAndAddrSize(Thread *thread) {
74061da546Spatrick   if (!thread)
75*f6aab3d8Srobert     return std::nullopt;
76061da546Spatrick   ProcessSP process_sp = thread->GetProcess();
77061da546Spatrick   if (!process_sp)
78*f6aab3d8Srobert     return std::nullopt;
79061da546Spatrick   ArchSpec arch = process_sp->GetTarget().GetArchitecture();
80061da546Spatrick   return std::make_pair(arch.GetByteOrder(), arch.GetAddressByteSize());
81061da546Spatrick }
82061da546Spatrick 
DumpDWARFExpr(Stream & s,llvm::ArrayRef<uint8_t> expr,Thread * thread)83061da546Spatrick static void DumpDWARFExpr(Stream &s, llvm::ArrayRef<uint8_t> expr, Thread *thread) {
84061da546Spatrick   if (auto order_and_width = GetByteOrderAndAddrSize(thread)) {
85dda28197Spatrick     llvm::DataExtractor data(expr, order_and_width->first == eByteOrderLittle,
86061da546Spatrick                              order_and_width->second);
87dda28197Spatrick     llvm::DWARFExpression(data, order_and_width->second, llvm::dwarf::DWARF32)
88*f6aab3d8Srobert         .print(s.AsRawOstream(), llvm::DIDumpOptions(), nullptr);
89061da546Spatrick   } else
90061da546Spatrick     s.PutCString("dwarf-expr");
91061da546Spatrick }
92061da546Spatrick 
Dump(Stream & s,const UnwindPlan * unwind_plan,const UnwindPlan::Row * row,Thread * thread,bool verbose) const93061da546Spatrick void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
94061da546Spatrick                                              const UnwindPlan *unwind_plan,
95061da546Spatrick                                              const UnwindPlan::Row *row,
96061da546Spatrick                                              Thread *thread,
97061da546Spatrick                                              bool verbose) const {
98061da546Spatrick   switch (m_type) {
99061da546Spatrick   case unspecified:
100061da546Spatrick     if (verbose)
101061da546Spatrick       s.PutCString("=<unspec>");
102061da546Spatrick     else
103061da546Spatrick       s.PutCString("=!");
104061da546Spatrick     break;
105061da546Spatrick   case undefined:
106061da546Spatrick     if (verbose)
107061da546Spatrick       s.PutCString("=<undef>");
108061da546Spatrick     else
109061da546Spatrick       s.PutCString("=?");
110061da546Spatrick     break;
111061da546Spatrick   case same:
112061da546Spatrick     s.PutCString("= <same>");
113061da546Spatrick     break;
114061da546Spatrick 
115061da546Spatrick   case atCFAPlusOffset:
116061da546Spatrick   case isCFAPlusOffset: {
117061da546Spatrick     s.PutChar('=');
118061da546Spatrick     if (m_type == atCFAPlusOffset)
119061da546Spatrick       s.PutChar('[');
120061da546Spatrick     s.Printf("CFA%+d", m_location.offset);
121061da546Spatrick     if (m_type == atCFAPlusOffset)
122061da546Spatrick       s.PutChar(']');
123061da546Spatrick   } break;
124061da546Spatrick 
125061da546Spatrick   case atAFAPlusOffset:
126061da546Spatrick   case isAFAPlusOffset: {
127061da546Spatrick     s.PutChar('=');
128061da546Spatrick     if (m_type == atAFAPlusOffset)
129061da546Spatrick       s.PutChar('[');
130061da546Spatrick     s.Printf("AFA%+d", m_location.offset);
131061da546Spatrick     if (m_type == atAFAPlusOffset)
132061da546Spatrick       s.PutChar(']');
133061da546Spatrick   } break;
134061da546Spatrick 
135061da546Spatrick   case inOtherRegister: {
136061da546Spatrick     const RegisterInfo *other_reg_info = nullptr;
137061da546Spatrick     if (unwind_plan)
138061da546Spatrick       other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
139061da546Spatrick     if (other_reg_info)
140061da546Spatrick       s.Printf("=%s", other_reg_info->name);
141061da546Spatrick     else
142061da546Spatrick       s.Printf("=reg(%u)", m_location.reg_num);
143061da546Spatrick   } break;
144061da546Spatrick 
145061da546Spatrick   case atDWARFExpression:
146061da546Spatrick   case isDWARFExpression: {
147061da546Spatrick     s.PutChar('=');
148061da546Spatrick     if (m_type == atDWARFExpression)
149061da546Spatrick       s.PutChar('[');
150061da546Spatrick     DumpDWARFExpr(
151*f6aab3d8Srobert         s, llvm::ArrayRef(m_location.expr.opcodes, m_location.expr.length),
152061da546Spatrick         thread);
153061da546Spatrick     if (m_type == atDWARFExpression)
154061da546Spatrick       s.PutChar(']');
155061da546Spatrick   } break;
156061da546Spatrick   }
157061da546Spatrick }
158061da546Spatrick 
DumpRegisterName(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,uint32_t reg_num)159061da546Spatrick static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
160061da546Spatrick                              Thread *thread, uint32_t reg_num) {
161061da546Spatrick   const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
162061da546Spatrick   if (reg_info)
163061da546Spatrick     s.PutCString(reg_info->name);
164061da546Spatrick   else
165061da546Spatrick     s.Printf("reg(%u)", reg_num);
166061da546Spatrick }
167061da546Spatrick 
168061da546Spatrick bool UnwindPlan::Row::FAValue::
operator ==(const UnwindPlan::Row::FAValue & rhs) const169061da546Spatrick operator==(const UnwindPlan::Row::FAValue &rhs) const {
170061da546Spatrick   if (m_type == rhs.m_type) {
171061da546Spatrick     switch (m_type) {
172061da546Spatrick     case unspecified:
173061da546Spatrick     case isRaSearch:
174061da546Spatrick       return m_value.ra_search_offset == rhs.m_value.ra_search_offset;
175061da546Spatrick 
176061da546Spatrick     case isRegisterPlusOffset:
177061da546Spatrick       return m_value.reg.offset == rhs.m_value.reg.offset;
178061da546Spatrick 
179061da546Spatrick     case isRegisterDereferenced:
180061da546Spatrick       return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
181061da546Spatrick 
182061da546Spatrick     case isDWARFExpression:
183061da546Spatrick       if (m_value.expr.length == rhs.m_value.expr.length)
184061da546Spatrick         return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
185061da546Spatrick                        m_value.expr.length);
186061da546Spatrick       break;
187061da546Spatrick     }
188061da546Spatrick   }
189061da546Spatrick   return false;
190061da546Spatrick }
191061da546Spatrick 
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread) const192061da546Spatrick void UnwindPlan::Row::FAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
193061da546Spatrick                                      Thread *thread) const {
194061da546Spatrick   switch (m_type) {
195061da546Spatrick   case isRegisterPlusOffset:
196061da546Spatrick     DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
197061da546Spatrick     s.Printf("%+3d", m_value.reg.offset);
198061da546Spatrick     break;
199061da546Spatrick   case isRegisterDereferenced:
200061da546Spatrick     s.PutChar('[');
201061da546Spatrick     DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
202061da546Spatrick     s.PutChar(']');
203061da546Spatrick     break;
204061da546Spatrick   case isDWARFExpression:
205*f6aab3d8Srobert     DumpDWARFExpr(s, llvm::ArrayRef(m_value.expr.opcodes, m_value.expr.length),
206061da546Spatrick                   thread);
207061da546Spatrick     break;
208061da546Spatrick   case unspecified:
209061da546Spatrick     s.PutCString("unspecified");
210061da546Spatrick     break;
211061da546Spatrick   case isRaSearch:
212061da546Spatrick     s.Printf("RaSearch@SP%+d", m_value.ra_search_offset);
213061da546Spatrick     break;
214061da546Spatrick   }
215061da546Spatrick }
216061da546Spatrick 
Clear()217061da546Spatrick void UnwindPlan::Row::Clear() {
218061da546Spatrick   m_cfa_value.SetUnspecified();
219061da546Spatrick   m_afa_value.SetUnspecified();
220061da546Spatrick   m_offset = 0;
221be691f3bSpatrick   m_unspecified_registers_are_undefined = false;
222061da546Spatrick   m_register_locations.clear();
223061da546Spatrick }
224061da546Spatrick 
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,addr_t base_addr) const225061da546Spatrick void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
226061da546Spatrick                            Thread *thread, addr_t base_addr) const {
227061da546Spatrick   if (base_addr != LLDB_INVALID_ADDRESS)
228061da546Spatrick     s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
229061da546Spatrick   else
230061da546Spatrick     s.Printf("%4" PRId64 ": CFA=", GetOffset());
231061da546Spatrick 
232061da546Spatrick   m_cfa_value.Dump(s, unwind_plan, thread);
233061da546Spatrick 
234061da546Spatrick   if (!m_afa_value.IsUnspecified()) {
235061da546Spatrick     s.Printf(" AFA=");
236061da546Spatrick     m_afa_value.Dump(s, unwind_plan, thread);
237061da546Spatrick   }
238061da546Spatrick 
239061da546Spatrick   s.Printf(" => ");
240061da546Spatrick   for (collection::const_iterator idx = m_register_locations.begin();
241061da546Spatrick        idx != m_register_locations.end(); ++idx) {
242061da546Spatrick     DumpRegisterName(s, unwind_plan, thread, idx->first);
243061da546Spatrick     const bool verbose = false;
244061da546Spatrick     idx->second.Dump(s, unwind_plan, this, thread, verbose);
245061da546Spatrick     s.PutChar(' ');
246061da546Spatrick   }
247061da546Spatrick }
248061da546Spatrick 
Row()249be691f3bSpatrick UnwindPlan::Row::Row() : m_cfa_value(), m_afa_value(), m_register_locations() {}
250061da546Spatrick 
GetRegisterInfo(uint32_t reg_num,UnwindPlan::Row::RegisterLocation & register_location) const251061da546Spatrick bool UnwindPlan::Row::GetRegisterInfo(
252061da546Spatrick     uint32_t reg_num,
253061da546Spatrick     UnwindPlan::Row::RegisterLocation &register_location) const {
254061da546Spatrick   collection::const_iterator pos = m_register_locations.find(reg_num);
255061da546Spatrick   if (pos != m_register_locations.end()) {
256061da546Spatrick     register_location = pos->second;
257061da546Spatrick     return true;
258061da546Spatrick   }
259be691f3bSpatrick   if (m_unspecified_registers_are_undefined) {
260be691f3bSpatrick     register_location.SetUndefined();
261be691f3bSpatrick     return true;
262be691f3bSpatrick   }
263061da546Spatrick   return false;
264061da546Spatrick }
265061da546Spatrick 
RemoveRegisterInfo(uint32_t reg_num)266061da546Spatrick void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
267061da546Spatrick   collection::const_iterator pos = m_register_locations.find(reg_num);
268061da546Spatrick   if (pos != m_register_locations.end()) {
269061da546Spatrick     m_register_locations.erase(pos);
270061da546Spatrick   }
271061da546Spatrick }
272061da546Spatrick 
SetRegisterInfo(uint32_t reg_num,const UnwindPlan::Row::RegisterLocation register_location)273061da546Spatrick void UnwindPlan::Row::SetRegisterInfo(
274061da546Spatrick     uint32_t reg_num,
275061da546Spatrick     const UnwindPlan::Row::RegisterLocation register_location) {
276061da546Spatrick   m_register_locations[reg_num] = register_location;
277061da546Spatrick }
278061da546Spatrick 
SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)279061da546Spatrick bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
280061da546Spatrick                                                            int32_t offset,
281061da546Spatrick                                                            bool can_replace) {
282061da546Spatrick   if (!can_replace &&
283061da546Spatrick       m_register_locations.find(reg_num) != m_register_locations.end())
284061da546Spatrick     return false;
285061da546Spatrick   RegisterLocation reg_loc;
286061da546Spatrick   reg_loc.SetAtCFAPlusOffset(offset);
287061da546Spatrick   m_register_locations[reg_num] = reg_loc;
288061da546Spatrick   return true;
289061da546Spatrick }
290061da546Spatrick 
SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)291061da546Spatrick bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
292061da546Spatrick                                                            int32_t offset,
293061da546Spatrick                                                            bool can_replace) {
294061da546Spatrick   if (!can_replace &&
295061da546Spatrick       m_register_locations.find(reg_num) != m_register_locations.end())
296061da546Spatrick     return false;
297061da546Spatrick   RegisterLocation reg_loc;
298061da546Spatrick   reg_loc.SetIsCFAPlusOffset(offset);
299061da546Spatrick   m_register_locations[reg_num] = reg_loc;
300061da546Spatrick   return true;
301061da546Spatrick }
302061da546Spatrick 
SetRegisterLocationToUndefined(uint32_t reg_num,bool can_replace,bool can_replace_only_if_unspecified)303061da546Spatrick bool UnwindPlan::Row::SetRegisterLocationToUndefined(
304061da546Spatrick     uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
305061da546Spatrick   collection::iterator pos = m_register_locations.find(reg_num);
306061da546Spatrick   collection::iterator end = m_register_locations.end();
307061da546Spatrick 
308061da546Spatrick   if (pos != end) {
309061da546Spatrick     if (!can_replace)
310061da546Spatrick       return false;
311061da546Spatrick     if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
312061da546Spatrick       return false;
313061da546Spatrick   }
314061da546Spatrick   RegisterLocation reg_loc;
315061da546Spatrick   reg_loc.SetUndefined();
316061da546Spatrick   m_register_locations[reg_num] = reg_loc;
317061da546Spatrick   return true;
318061da546Spatrick }
319061da546Spatrick 
SetRegisterLocationToUnspecified(uint32_t reg_num,bool can_replace)320061da546Spatrick bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
321061da546Spatrick                                                        bool can_replace) {
322061da546Spatrick   if (!can_replace &&
323061da546Spatrick       m_register_locations.find(reg_num) != m_register_locations.end())
324061da546Spatrick     return false;
325061da546Spatrick   RegisterLocation reg_loc;
326061da546Spatrick   reg_loc.SetUnspecified();
327061da546Spatrick   m_register_locations[reg_num] = reg_loc;
328061da546Spatrick   return true;
329061da546Spatrick }
330061da546Spatrick 
SetRegisterLocationToRegister(uint32_t reg_num,uint32_t other_reg_num,bool can_replace)331061da546Spatrick bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
332061da546Spatrick                                                     uint32_t other_reg_num,
333061da546Spatrick                                                     bool can_replace) {
334061da546Spatrick   if (!can_replace &&
335061da546Spatrick       m_register_locations.find(reg_num) != m_register_locations.end())
336061da546Spatrick     return false;
337061da546Spatrick   RegisterLocation reg_loc;
338061da546Spatrick   reg_loc.SetInRegister(other_reg_num);
339061da546Spatrick   m_register_locations[reg_num] = reg_loc;
340061da546Spatrick   return true;
341061da546Spatrick }
342061da546Spatrick 
SetRegisterLocationToSame(uint32_t reg_num,bool must_replace)343061da546Spatrick bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
344061da546Spatrick                                                 bool must_replace) {
345061da546Spatrick   if (must_replace &&
346061da546Spatrick       m_register_locations.find(reg_num) == m_register_locations.end())
347061da546Spatrick     return false;
348061da546Spatrick   RegisterLocation reg_loc;
349061da546Spatrick   reg_loc.SetSame();
350061da546Spatrick   m_register_locations[reg_num] = reg_loc;
351061da546Spatrick   return true;
352061da546Spatrick }
353061da546Spatrick 
operator ==(const UnwindPlan::Row & rhs) const354061da546Spatrick bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
355be691f3bSpatrick   return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
356061da546Spatrick          m_afa_value == rhs.m_afa_value &&
357be691f3bSpatrick          m_unspecified_registers_are_undefined ==
358be691f3bSpatrick              rhs.m_unspecified_registers_are_undefined &&
359061da546Spatrick          m_register_locations == rhs.m_register_locations;
360061da546Spatrick }
361061da546Spatrick 
AppendRow(const UnwindPlan::RowSP & row_sp)362061da546Spatrick void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
363061da546Spatrick   if (m_row_list.empty() ||
364061da546Spatrick       m_row_list.back()->GetOffset() != row_sp->GetOffset())
365061da546Spatrick     m_row_list.push_back(row_sp);
366061da546Spatrick   else
367061da546Spatrick     m_row_list.back() = row_sp;
368061da546Spatrick }
369061da546Spatrick 
InsertRow(const UnwindPlan::RowSP & row_sp,bool replace_existing)370061da546Spatrick void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
371061da546Spatrick                            bool replace_existing) {
372061da546Spatrick   collection::iterator it = m_row_list.begin();
373061da546Spatrick   while (it != m_row_list.end()) {
374061da546Spatrick     RowSP row = *it;
375061da546Spatrick     if (row->GetOffset() >= row_sp->GetOffset())
376061da546Spatrick       break;
377061da546Spatrick     it++;
378061da546Spatrick   }
379061da546Spatrick   if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
380061da546Spatrick     m_row_list.insert(it, row_sp);
381061da546Spatrick   else if (replace_existing)
382061da546Spatrick     *it = row_sp;
383061da546Spatrick }
384061da546Spatrick 
GetRowForFunctionOffset(int offset) const385061da546Spatrick UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
386061da546Spatrick   RowSP row;
387061da546Spatrick   if (!m_row_list.empty()) {
388061da546Spatrick     if (offset == -1)
389061da546Spatrick       row = m_row_list.back();
390061da546Spatrick     else {
391061da546Spatrick       collection::const_iterator pos, end = m_row_list.end();
392061da546Spatrick       for (pos = m_row_list.begin(); pos != end; ++pos) {
393061da546Spatrick         if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
394061da546Spatrick           row = *pos;
395061da546Spatrick         else
396061da546Spatrick           break;
397061da546Spatrick       }
398061da546Spatrick     }
399061da546Spatrick   }
400061da546Spatrick   return row;
401061da546Spatrick }
402061da546Spatrick 
IsValidRowIndex(uint32_t idx) const403061da546Spatrick bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
404061da546Spatrick   return idx < m_row_list.size();
405061da546Spatrick }
406061da546Spatrick 
GetRowAtIndex(uint32_t idx) const407061da546Spatrick const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
408061da546Spatrick   if (idx < m_row_list.size())
409061da546Spatrick     return m_row_list[idx];
410061da546Spatrick   else {
411*f6aab3d8Srobert     Log *log = GetLog(LLDBLog::Unwind);
412061da546Spatrick     LLDB_LOGF(log,
413061da546Spatrick               "error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
414061da546Spatrick               "(number rows is %u)",
415061da546Spatrick               idx, (uint32_t)m_row_list.size());
416061da546Spatrick     return UnwindPlan::RowSP();
417061da546Spatrick   }
418061da546Spatrick }
419061da546Spatrick 
GetLastRow() const420061da546Spatrick const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
421061da546Spatrick   if (m_row_list.empty()) {
422*f6aab3d8Srobert     Log *log = GetLog(LLDBLog::Unwind);
423061da546Spatrick     LLDB_LOGF(log, "UnwindPlan::GetLastRow() when rows are empty");
424061da546Spatrick     return UnwindPlan::RowSP();
425061da546Spatrick   }
426061da546Spatrick   return m_row_list.back();
427061da546Spatrick }
428061da546Spatrick 
GetRowCount() const429061da546Spatrick int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
430061da546Spatrick 
SetPlanValidAddressRange(const AddressRange & range)431061da546Spatrick void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
432061da546Spatrick   if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
433061da546Spatrick     m_plan_valid_address_range = range;
434061da546Spatrick }
435061da546Spatrick 
PlanValidAtAddress(Address addr)436061da546Spatrick bool UnwindPlan::PlanValidAtAddress(Address addr) {
437061da546Spatrick   // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
438061da546Spatrick   if (GetRowCount() == 0) {
439*f6aab3d8Srobert     Log *log = GetLog(LLDBLog::Unwind);
440061da546Spatrick     if (log) {
441061da546Spatrick       StreamString s;
442061da546Spatrick       if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
443061da546Spatrick         LLDB_LOGF(log,
444061da546Spatrick                   "UnwindPlan is invalid -- no unwind rows for UnwindPlan "
445061da546Spatrick                   "'%s' at address %s",
446061da546Spatrick                   m_source_name.GetCString(), s.GetData());
447061da546Spatrick       } else {
448061da546Spatrick         LLDB_LOGF(log,
449061da546Spatrick                   "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
450061da546Spatrick                   m_source_name.GetCString());
451061da546Spatrick       }
452061da546Spatrick     }
453061da546Spatrick     return false;
454061da546Spatrick   }
455061da546Spatrick 
456061da546Spatrick   // If the 0th Row of unwind instructions is missing, or if it doesn't provide
457061da546Spatrick   // a register to use to find the Canonical Frame Address, this is not a valid
458061da546Spatrick   // UnwindPlan.
459061da546Spatrick   if (GetRowAtIndex(0).get() == nullptr ||
460061da546Spatrick       GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
461061da546Spatrick           Row::FAValue::unspecified) {
462*f6aab3d8Srobert     Log *log = GetLog(LLDBLog::Unwind);
463061da546Spatrick     if (log) {
464061da546Spatrick       StreamString s;
465061da546Spatrick       if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
466061da546Spatrick         LLDB_LOGF(log,
467061da546Spatrick                   "UnwindPlan is invalid -- no CFA register defined in row 0 "
468061da546Spatrick                   "for UnwindPlan '%s' at address %s",
469061da546Spatrick                   m_source_name.GetCString(), s.GetData());
470061da546Spatrick       } else {
471061da546Spatrick         LLDB_LOGF(log,
472061da546Spatrick                   "UnwindPlan is invalid -- no CFA register defined in row 0 "
473061da546Spatrick                   "for UnwindPlan '%s'",
474061da546Spatrick                   m_source_name.GetCString());
475061da546Spatrick       }
476061da546Spatrick     }
477061da546Spatrick     return false;
478061da546Spatrick   }
479061da546Spatrick 
480061da546Spatrick   if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
481061da546Spatrick       m_plan_valid_address_range.GetByteSize() == 0)
482061da546Spatrick     return true;
483061da546Spatrick 
484061da546Spatrick   if (!addr.IsValid())
485061da546Spatrick     return true;
486061da546Spatrick 
487061da546Spatrick   if (m_plan_valid_address_range.ContainsFileAddress(addr))
488061da546Spatrick     return true;
489061da546Spatrick 
490061da546Spatrick   return false;
491061da546Spatrick }
492061da546Spatrick 
Dump(Stream & s,Thread * thread,lldb::addr_t base_addr) const493061da546Spatrick void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
494061da546Spatrick   if (!m_source_name.IsEmpty()) {
495061da546Spatrick     s.Printf("This UnwindPlan originally sourced from %s\n",
496061da546Spatrick              m_source_name.GetCString());
497061da546Spatrick   }
498061da546Spatrick   if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
499061da546Spatrick     TargetSP target_sp(thread->CalculateTarget());
500061da546Spatrick     addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
501061da546Spatrick     addr_t personality_func_load_addr =
502061da546Spatrick         m_personality_func_addr.GetLoadAddress(target_sp.get());
503061da546Spatrick 
504061da546Spatrick     if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
505061da546Spatrick         personality_func_load_addr != LLDB_INVALID_ADDRESS) {
506061da546Spatrick       s.Printf("LSDA address 0x%" PRIx64
507061da546Spatrick                ", personality routine is at address 0x%" PRIx64 "\n",
508061da546Spatrick                lsda_load_addr, personality_func_load_addr);
509061da546Spatrick     }
510061da546Spatrick   }
511061da546Spatrick   s.Printf("This UnwindPlan is sourced from the compiler: ");
512061da546Spatrick   switch (m_plan_is_sourced_from_compiler) {
513061da546Spatrick   case eLazyBoolYes:
514061da546Spatrick     s.Printf("yes.\n");
515061da546Spatrick     break;
516061da546Spatrick   case eLazyBoolNo:
517061da546Spatrick     s.Printf("no.\n");
518061da546Spatrick     break;
519061da546Spatrick   case eLazyBoolCalculate:
520061da546Spatrick     s.Printf("not specified.\n");
521061da546Spatrick     break;
522061da546Spatrick   }
523061da546Spatrick   s.Printf("This UnwindPlan is valid at all instruction locations: ");
524061da546Spatrick   switch (m_plan_is_valid_at_all_instruction_locations) {
525061da546Spatrick   case eLazyBoolYes:
526061da546Spatrick     s.Printf("yes.\n");
527061da546Spatrick     break;
528061da546Spatrick   case eLazyBoolNo:
529061da546Spatrick     s.Printf("no.\n");
530061da546Spatrick     break;
531061da546Spatrick   case eLazyBoolCalculate:
532061da546Spatrick     s.Printf("not specified.\n");
533061da546Spatrick     break;
534061da546Spatrick   }
535be691f3bSpatrick   s.Printf("This UnwindPlan is for a trap handler function: ");
536be691f3bSpatrick   switch (m_plan_is_for_signal_trap) {
537be691f3bSpatrick   case eLazyBoolYes:
538be691f3bSpatrick     s.Printf("yes.\n");
539be691f3bSpatrick     break;
540be691f3bSpatrick   case eLazyBoolNo:
541be691f3bSpatrick     s.Printf("no.\n");
542be691f3bSpatrick     break;
543be691f3bSpatrick   case eLazyBoolCalculate:
544be691f3bSpatrick     s.Printf("not specified.\n");
545be691f3bSpatrick     break;
546be691f3bSpatrick   }
547061da546Spatrick   if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
548061da546Spatrick       m_plan_valid_address_range.GetByteSize() > 0) {
549061da546Spatrick     s.PutCString("Address range of this UnwindPlan: ");
550061da546Spatrick     TargetSP target_sp(thread->CalculateTarget());
551061da546Spatrick     m_plan_valid_address_range.Dump(&s, target_sp.get(),
552061da546Spatrick                                     Address::DumpStyleSectionNameOffset);
553061da546Spatrick     s.EOL();
554061da546Spatrick   }
555061da546Spatrick   collection::const_iterator pos, begin = m_row_list.begin(),
556061da546Spatrick                                   end = m_row_list.end();
557061da546Spatrick   for (pos = begin; pos != end; ++pos) {
558061da546Spatrick     s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
559061da546Spatrick     (*pos)->Dump(s, this, thread, base_addr);
560be691f3bSpatrick     s.Printf("\n");
561061da546Spatrick   }
562061da546Spatrick }
563061da546Spatrick 
SetSourceName(const char * source)564061da546Spatrick void UnwindPlan::SetSourceName(const char *source) {
565061da546Spatrick   m_source_name = ConstString(source);
566061da546Spatrick }
567061da546Spatrick 
GetSourceName() const568061da546Spatrick ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
569061da546Spatrick 
GetRegisterInfo(Thread * thread,uint32_t unwind_reg) const570061da546Spatrick const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
571061da546Spatrick                                                 uint32_t unwind_reg) const {
572061da546Spatrick   if (thread) {
573061da546Spatrick     RegisterContext *reg_ctx = thread->GetRegisterContext().get();
574061da546Spatrick     if (reg_ctx) {
575061da546Spatrick       uint32_t reg;
576061da546Spatrick       if (m_register_kind == eRegisterKindLLDB)
577061da546Spatrick         reg = unwind_reg;
578061da546Spatrick       else
579061da546Spatrick         reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
580061da546Spatrick                                                            unwind_reg);
581061da546Spatrick       if (reg != LLDB_INVALID_REGNUM)
582061da546Spatrick         return reg_ctx->GetRegisterInfoAtIndex(reg);
583061da546Spatrick     }
584061da546Spatrick   }
585061da546Spatrick   return nullptr;
586061da546Spatrick }
587