180814287SRaphael Isemann //===-- UnwindPlan.cpp ----------------------------------------------------===//
2fbcb7f2cSJason Molenda //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fbcb7f2cSJason Molenda //
7fbcb7f2cSJason Molenda //===----------------------------------------------------------------------===//
8fbcb7f2cSJason Molenda 
9fbcb7f2cSJason Molenda #include "lldb/Symbol/UnwindPlan.h"
1079ea878bSGreg Clayton 
11f5e56de0SGreg Clayton #include "lldb/Target/Process.h"
12fbcb7f2cSJason Molenda #include "lldb/Target/RegisterContext.h"
137a784203SPavel Labath #include "lldb/Target/Target.h"
14f5e56de0SGreg Clayton #include "lldb/Target/Thread.h"
15bf9a7730SZachary Turner #include "lldb/Utility/ConstString.h"
16c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
176f9e6901SZachary Turner #include "lldb/Utility/Log.h"
18*290e4823Sserge-sans-paille #include "llvm/DebugInfo/DIContext.h"
19ba03bcbcSPavel Labath #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
20fbcb7f2cSJason Molenda 
21fbcb7f2cSJason Molenda using namespace lldb;
22fbcb7f2cSJason Molenda using namespace lldb_private;
23fbcb7f2cSJason Molenda 
24b9c1b51eSKate Stone bool UnwindPlan::Row::RegisterLocation::
operator ==(const UnwindPlan::Row::RegisterLocation & rhs) const25b9c1b51eSKate Stone operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
26b9c1b51eSKate Stone   if (m_type == rhs.m_type) {
27b9c1b51eSKate Stone     switch (m_type) {
2831f1d2f5SGreg Clayton     case unspecified:
2931f1d2f5SGreg Clayton     case undefined:
3031f1d2f5SGreg Clayton     case same:
3131f1d2f5SGreg Clayton       return true;
3231f1d2f5SGreg Clayton 
3331f1d2f5SGreg Clayton     case atCFAPlusOffset:
3431f1d2f5SGreg Clayton     case isCFAPlusOffset:
354538ed3bSAleksandr Urakov     case atAFAPlusOffset:
364538ed3bSAleksandr Urakov     case isAFAPlusOffset:
37fbcb7f2cSJason Molenda       return m_location.offset == rhs.m_location.offset;
3831f1d2f5SGreg Clayton 
3931f1d2f5SGreg Clayton     case inOtherRegister:
40fbcb7f2cSJason Molenda       return m_location.reg_num == rhs.m_location.reg_num;
4131f1d2f5SGreg Clayton 
4231f1d2f5SGreg Clayton     case atDWARFExpression:
4331f1d2f5SGreg Clayton     case isDWARFExpression:
44fbcb7f2cSJason Molenda       if (m_location.expr.length == rhs.m_location.expr.length)
45b9c1b51eSKate Stone         return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
46b9c1b51eSKate Stone                        m_location.expr.length);
4731f1d2f5SGreg Clayton       break;
4831f1d2f5SGreg Clayton     }
4931f1d2f5SGreg Clayton   }
50fbcb7f2cSJason Molenda   return false;
51fbcb7f2cSJason Molenda }
52fbcb7f2cSJason Molenda 
53b9c1b51eSKate Stone // This function doesn't copy the dwarf expression bytes; they must remain in
5405097246SAdrian Prantl // allocated memory for the lifespan of this UnwindPlan object.
SetAtDWARFExpression(const uint8_t * opcodes,uint32_t len)55b9c1b51eSKate Stone void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
56b9c1b51eSKate Stone     const uint8_t *opcodes, uint32_t len) {
57fbcb7f2cSJason Molenda   m_type = atDWARFExpression;
58fbcb7f2cSJason Molenda   m_location.expr.opcodes = opcodes;
59fbcb7f2cSJason Molenda   m_location.expr.length = len;
60fbcb7f2cSJason Molenda }
61fbcb7f2cSJason Molenda 
62b9c1b51eSKate Stone // This function doesn't copy the dwarf expression bytes; they must remain in
6305097246SAdrian Prantl // allocated memory for the lifespan of this UnwindPlan object.
SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)64b9c1b51eSKate Stone void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
65b9c1b51eSKate Stone     const uint8_t *opcodes, uint32_t len) {
66fbcb7f2cSJason Molenda   m_type = isDWARFExpression;
67fbcb7f2cSJason Molenda   m_location.expr.opcodes = opcodes;
68fbcb7f2cSJason Molenda   m_location.expr.length = len;
69fbcb7f2cSJason Molenda }
70fbcb7f2cSJason Molenda 
717a784203SPavel Labath static llvm::Optional<std::pair<lldb::ByteOrder, uint32_t>>
GetByteOrderAndAddrSize(Thread * thread)727a784203SPavel Labath GetByteOrderAndAddrSize(Thread *thread) {
737a784203SPavel Labath   if (!thread)
747a784203SPavel Labath     return llvm::None;
757a784203SPavel Labath   ProcessSP process_sp = thread->GetProcess();
767a784203SPavel Labath   if (!process_sp)
777a784203SPavel Labath     return llvm::None;
787a784203SPavel Labath   ArchSpec arch = process_sp->GetTarget().GetArchitecture();
797a784203SPavel Labath   return std::make_pair(arch.GetByteOrder(), arch.GetAddressByteSize());
807a784203SPavel Labath }
817a784203SPavel Labath 
DumpDWARFExpr(Stream & s,llvm::ArrayRef<uint8_t> expr,Thread * thread)827a784203SPavel Labath static void DumpDWARFExpr(Stream &s, llvm::ArrayRef<uint8_t> expr, Thread *thread) {
837a784203SPavel Labath   if (auto order_and_width = GetByteOrderAndAddrSize(thread)) {
84ba03bcbcSPavel Labath     llvm::DataExtractor data(expr, order_and_width->first == eByteOrderLittle,
857a784203SPavel Labath                              order_and_width->second);
86ba03bcbcSPavel Labath     llvm::DWARFExpression(data, order_and_width->second, llvm::dwarf::DWARF32)
870b057320SDavid Blaikie         .print(s.AsRawOstream(), llvm::DIDumpOptions(), nullptr, nullptr);
887a784203SPavel Labath   } else
897a784203SPavel Labath     s.PutCString("dwarf-expr");
907a784203SPavel Labath }
917a784203SPavel Labath 
Dump(Stream & s,const UnwindPlan * unwind_plan,const UnwindPlan::Row * row,Thread * thread,bool verbose) const92b9c1b51eSKate Stone void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
93b9c1b51eSKate Stone                                              const UnwindPlan *unwind_plan,
94b9c1b51eSKate Stone                                              const UnwindPlan::Row *row,
95b9c1b51eSKate Stone                                              Thread *thread,
96b9c1b51eSKate Stone                                              bool verbose) const {
97b9c1b51eSKate Stone   switch (m_type) {
98fbcb7f2cSJason Molenda   case unspecified:
9931f1d2f5SGreg Clayton     if (verbose)
10031f1d2f5SGreg Clayton       s.PutCString("=<unspec>");
10131f1d2f5SGreg Clayton     else
10231f1d2f5SGreg Clayton       s.PutCString("=!");
103fbcb7f2cSJason Molenda     break;
10431f1d2f5SGreg Clayton   case undefined:
10531f1d2f5SGreg Clayton     if (verbose)
10631f1d2f5SGreg Clayton       s.PutCString("=<undef>");
10731f1d2f5SGreg Clayton     else
10831f1d2f5SGreg Clayton       s.PutCString("=?");
109fbcb7f2cSJason Molenda     break;
11031f1d2f5SGreg Clayton   case same:
11131f1d2f5SGreg Clayton     s.PutCString("= <same>");
112fbcb7f2cSJason Molenda     break;
11331f1d2f5SGreg Clayton 
114fbcb7f2cSJason Molenda   case atCFAPlusOffset:
115b9c1b51eSKate Stone   case isCFAPlusOffset: {
11631f1d2f5SGreg Clayton     s.PutChar('=');
11731f1d2f5SGreg Clayton     if (m_type == atCFAPlusOffset)
11831f1d2f5SGreg Clayton       s.PutChar('[');
11931f1d2f5SGreg Clayton     s.Printf("CFA%+d", m_location.offset);
12031f1d2f5SGreg Clayton     if (m_type == atCFAPlusOffset)
12131f1d2f5SGreg Clayton       s.PutChar(']');
122b9c1b51eSKate Stone   } break;
12331f1d2f5SGreg Clayton 
1244538ed3bSAleksandr Urakov   case atAFAPlusOffset:
1254538ed3bSAleksandr Urakov   case isAFAPlusOffset: {
1264538ed3bSAleksandr Urakov     s.PutChar('=');
1274538ed3bSAleksandr Urakov     if (m_type == atAFAPlusOffset)
1284538ed3bSAleksandr Urakov       s.PutChar('[');
1294538ed3bSAleksandr Urakov     s.Printf("AFA%+d", m_location.offset);
1304538ed3bSAleksandr Urakov     if (m_type == atAFAPlusOffset)
1314538ed3bSAleksandr Urakov       s.PutChar(']');
1324538ed3bSAleksandr Urakov   } break;
1334538ed3bSAleksandr Urakov 
134b9c1b51eSKate Stone   case inOtherRegister: {
135d4612ad0SEd Maste     const RegisterInfo *other_reg_info = nullptr;
13631f1d2f5SGreg Clayton     if (unwind_plan)
13731f1d2f5SGreg Clayton       other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
13831f1d2f5SGreg Clayton     if (other_reg_info)
13931f1d2f5SGreg Clayton       s.Printf("=%s", other_reg_info->name);
14031f1d2f5SGreg Clayton     else
14131f1d2f5SGreg Clayton       s.Printf("=reg(%u)", m_location.reg_num);
142b9c1b51eSKate Stone   } break;
14331f1d2f5SGreg Clayton 
144fbcb7f2cSJason Molenda   case atDWARFExpression:
145b9c1b51eSKate Stone   case isDWARFExpression: {
14631f1d2f5SGreg Clayton     s.PutChar('=');
14731f1d2f5SGreg Clayton     if (m_type == atDWARFExpression)
1487a784203SPavel Labath       s.PutChar('[');
1497a784203SPavel Labath     DumpDWARFExpr(
1507a784203SPavel Labath         s, llvm::makeArrayRef(m_location.expr.opcodes, m_location.expr.length),
1517a784203SPavel Labath         thread);
1527a784203SPavel Labath     if (m_type == atDWARFExpression)
1537a784203SPavel Labath       s.PutChar(']');
154b9c1b51eSKate Stone   } break;
155fbcb7f2cSJason Molenda   }
156fbcb7f2cSJason Molenda }
157fbcb7f2cSJason Molenda 
DumpRegisterName(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,uint32_t reg_num)158b9c1b51eSKate Stone static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
159b9c1b51eSKate Stone                              Thread *thread, uint32_t reg_num) {
160ab970f5eSPavel Labath   const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
161ab970f5eSPavel Labath   if (reg_info)
162ab970f5eSPavel Labath     s.PutCString(reg_info->name);
163ab970f5eSPavel Labath   else
164ab970f5eSPavel Labath     s.Printf("reg(%u)", reg_num);
165ab970f5eSPavel Labath }
166ab970f5eSPavel Labath 
1674538ed3bSAleksandr Urakov bool UnwindPlan::Row::FAValue::
operator ==(const UnwindPlan::Row::FAValue & rhs) const1684538ed3bSAleksandr Urakov operator==(const UnwindPlan::Row::FAValue &rhs) const {
169b9c1b51eSKate Stone   if (m_type == rhs.m_type) {
170b9c1b51eSKate Stone     switch (m_type) {
171ab970f5eSPavel Labath     case unspecified:
172a8b284eeSPavel Labath     case isRaSearch:
173a8b284eeSPavel Labath       return m_value.ra_search_offset == rhs.m_value.ra_search_offset;
174ab970f5eSPavel Labath 
175ab970f5eSPavel Labath     case isRegisterPlusOffset:
176ab970f5eSPavel Labath       return m_value.reg.offset == rhs.m_value.reg.offset;
177ab970f5eSPavel Labath 
178ab970f5eSPavel Labath     case isRegisterDereferenced:
179ab970f5eSPavel Labath       return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
180ab970f5eSPavel Labath 
181ab970f5eSPavel Labath     case isDWARFExpression:
182ab970f5eSPavel Labath       if (m_value.expr.length == rhs.m_value.expr.length)
183b9c1b51eSKate Stone         return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
184b9c1b51eSKate Stone                        m_value.expr.length);
185ab970f5eSPavel Labath       break;
186ab970f5eSPavel Labath     }
187ab970f5eSPavel Labath   }
188ab970f5eSPavel Labath   return false;
189ab970f5eSPavel Labath }
190ab970f5eSPavel Labath 
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread) const1914538ed3bSAleksandr Urakov void UnwindPlan::Row::FAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
192b9c1b51eSKate Stone                                      Thread *thread) const {
193ab970f5eSPavel Labath   switch (m_type) {
194ab970f5eSPavel Labath   case isRegisterPlusOffset:
195ab970f5eSPavel Labath     DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
196ab970f5eSPavel Labath     s.Printf("%+3d", m_value.reg.offset);
197ab970f5eSPavel Labath     break;
198ab970f5eSPavel Labath   case isRegisterDereferenced:
199ab970f5eSPavel Labath     s.PutChar('[');
200ab970f5eSPavel Labath     DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
201ab970f5eSPavel Labath     s.PutChar(']');
202ab970f5eSPavel Labath     break;
203ab970f5eSPavel Labath   case isDWARFExpression:
2047a784203SPavel Labath     DumpDWARFExpr(s,
2057a784203SPavel Labath                   llvm::makeArrayRef(m_value.expr.opcodes, m_value.expr.length),
2067a784203SPavel Labath                   thread);
207ab970f5eSPavel Labath     break;
208a8b284eeSPavel Labath   case unspecified:
209ab970f5eSPavel Labath     s.PutCString("unspecified");
210ab970f5eSPavel Labath     break;
211a8b284eeSPavel Labath   case isRaSearch:
212a8b284eeSPavel Labath     s.Printf("RaSearch@SP%+d", m_value.ra_search_offset);
213a8b284eeSPavel Labath     break;
214ab970f5eSPavel Labath   }
215ab970f5eSPavel Labath }
216ab970f5eSPavel Labath 
Clear()217b9c1b51eSKate Stone void UnwindPlan::Row::Clear() {
218ab970f5eSPavel Labath   m_cfa_value.SetUnspecified();
2194538ed3bSAleksandr Urakov   m_afa_value.SetUnspecified();
220fbcb7f2cSJason Molenda   m_offset = 0;
221fcdef15dSJason Molenda   m_unspecified_registers_are_undefined = false;
222fbcb7f2cSJason Molenda   m_register_locations.clear();
223fbcb7f2cSJason Molenda }
224fbcb7f2cSJason Molenda 
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,addr_t base_addr) const225b9c1b51eSKate Stone void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
226b9c1b51eSKate Stone                            Thread *thread, addr_t base_addr) const {
22731f1d2f5SGreg Clayton   if (base_addr != LLDB_INVALID_ADDRESS)
228d01b2953SDaniel Malea     s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
229fbcb7f2cSJason Molenda   else
23034549b8fSJason Molenda     s.Printf("%4" PRId64 ": CFA=", GetOffset());
23131f1d2f5SGreg Clayton 
232ab970f5eSPavel Labath   m_cfa_value.Dump(s, unwind_plan, thread);
2334538ed3bSAleksandr Urakov 
2344538ed3bSAleksandr Urakov   if (!m_afa_value.IsUnspecified()) {
2354538ed3bSAleksandr Urakov     s.Printf(" AFA=");
2364538ed3bSAleksandr Urakov     m_afa_value.Dump(s, unwind_plan, thread);
2374538ed3bSAleksandr Urakov   }
2384538ed3bSAleksandr Urakov 
239ab970f5eSPavel Labath   s.Printf(" => ");
240b9c1b51eSKate Stone   for (collection::const_iterator idx = m_register_locations.begin();
241b9c1b51eSKate Stone        idx != m_register_locations.end(); ++idx) {
242ab970f5eSPavel Labath     DumpRegisterName(s, unwind_plan, thread, idx->first);
24331f1d2f5SGreg Clayton     const bool verbose = false;
24431f1d2f5SGreg Clayton     idx->second.Dump(s, unwind_plan, this, thread, verbose);
24531f1d2f5SGreg Clayton     s.PutChar(' ');
246fbcb7f2cSJason Molenda   }
247fbcb7f2cSJason Molenda }
248fbcb7f2cSJason Molenda 
Row()2499494c510SJonas Devlieghere UnwindPlan::Row::Row() : m_cfa_value(), m_afa_value(), m_register_locations() {}
250fbcb7f2cSJason Molenda 
GetRegisterInfo(uint32_t reg_num,UnwindPlan::Row::RegisterLocation & register_location) const251b9c1b51eSKate Stone bool UnwindPlan::Row::GetRegisterInfo(
252b9c1b51eSKate Stone     uint32_t reg_num,
253b9c1b51eSKate Stone     UnwindPlan::Row::RegisterLocation &register_location) const {
254fbcb7f2cSJason Molenda   collection::const_iterator pos = m_register_locations.find(reg_num);
255b9c1b51eSKate Stone   if (pos != m_register_locations.end()) {
256fbcb7f2cSJason Molenda     register_location = pos->second;
257fbcb7f2cSJason Molenda     return true;
258fbcb7f2cSJason Molenda   }
259fcdef15dSJason Molenda   if (m_unspecified_registers_are_undefined) {
260fcdef15dSJason Molenda     register_location.SetUndefined();
261fcdef15dSJason Molenda     return true;
262fcdef15dSJason Molenda   }
263fbcb7f2cSJason Molenda   return false;
264fbcb7f2cSJason Molenda }
265fbcb7f2cSJason Molenda 
RemoveRegisterInfo(uint32_t reg_num)266b9c1b51eSKate Stone void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
26734549b8fSJason Molenda   collection::const_iterator pos = m_register_locations.find(reg_num);
268b9c1b51eSKate Stone   if (pos != m_register_locations.end()) {
26934549b8fSJason Molenda     m_register_locations.erase(pos);
27034549b8fSJason Molenda   }
27134549b8fSJason Molenda }
27234549b8fSJason Molenda 
SetRegisterInfo(uint32_t reg_num,const UnwindPlan::Row::RegisterLocation register_location)273b9c1b51eSKate Stone void UnwindPlan::Row::SetRegisterInfo(
274b9c1b51eSKate Stone     uint32_t reg_num,
275b9c1b51eSKate Stone     const UnwindPlan::Row::RegisterLocation register_location) {
276fbcb7f2cSJason Molenda   m_register_locations[reg_num] = register_location;
277fbcb7f2cSJason Molenda }
278fbcb7f2cSJason Molenda 
SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)279b9c1b51eSKate Stone bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
280b9c1b51eSKate Stone                                                            int32_t offset,
281b9c1b51eSKate Stone                                                            bool can_replace) {
282b9c1b51eSKate Stone   if (!can_replace &&
283b9c1b51eSKate Stone       m_register_locations.find(reg_num) != m_register_locations.end())
28431f1d2f5SGreg Clayton     return false;
28531f1d2f5SGreg Clayton   RegisterLocation reg_loc;
28631f1d2f5SGreg Clayton   reg_loc.SetAtCFAPlusOffset(offset);
28731f1d2f5SGreg Clayton   m_register_locations[reg_num] = reg_loc;
28831f1d2f5SGreg Clayton   return true;
28931f1d2f5SGreg Clayton }
29031f1d2f5SGreg Clayton 
SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)291b9c1b51eSKate Stone bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
292b9c1b51eSKate Stone                                                            int32_t offset,
293b9c1b51eSKate Stone                                                            bool can_replace) {
294b9c1b51eSKate Stone   if (!can_replace &&
295b9c1b51eSKate Stone       m_register_locations.find(reg_num) != m_register_locations.end())
29631f1d2f5SGreg Clayton     return false;
29731f1d2f5SGreg Clayton   RegisterLocation reg_loc;
29831f1d2f5SGreg Clayton   reg_loc.SetIsCFAPlusOffset(offset);
29931f1d2f5SGreg Clayton   m_register_locations[reg_num] = reg_loc;
30031f1d2f5SGreg Clayton   return true;
30131f1d2f5SGreg Clayton }
30231f1d2f5SGreg Clayton 
SetRegisterLocationToUndefined(uint32_t reg_num,bool can_replace,bool can_replace_only_if_unspecified)303b9c1b51eSKate Stone bool UnwindPlan::Row::SetRegisterLocationToUndefined(
304b9c1b51eSKate Stone     uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
30531f1d2f5SGreg Clayton   collection::iterator pos = m_register_locations.find(reg_num);
30631f1d2f5SGreg Clayton   collection::iterator end = m_register_locations.end();
30731f1d2f5SGreg Clayton 
308b9c1b51eSKate Stone   if (pos != end) {
30931f1d2f5SGreg Clayton     if (!can_replace)
31031f1d2f5SGreg Clayton       return false;
31131f1d2f5SGreg Clayton     if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
31231f1d2f5SGreg Clayton       return false;
31331f1d2f5SGreg Clayton   }
31431f1d2f5SGreg Clayton   RegisterLocation reg_loc;
31531f1d2f5SGreg Clayton   reg_loc.SetUndefined();
31631f1d2f5SGreg Clayton   m_register_locations[reg_num] = reg_loc;
31731f1d2f5SGreg Clayton   return true;
31831f1d2f5SGreg Clayton }
31931f1d2f5SGreg Clayton 
SetRegisterLocationToUnspecified(uint32_t reg_num,bool can_replace)320b9c1b51eSKate Stone bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
321b9c1b51eSKate Stone                                                        bool can_replace) {
322b9c1b51eSKate Stone   if (!can_replace &&
323b9c1b51eSKate Stone       m_register_locations.find(reg_num) != m_register_locations.end())
32431f1d2f5SGreg Clayton     return false;
32531f1d2f5SGreg Clayton   RegisterLocation reg_loc;
32631f1d2f5SGreg Clayton   reg_loc.SetUnspecified();
32731f1d2f5SGreg Clayton   m_register_locations[reg_num] = reg_loc;
32831f1d2f5SGreg Clayton   return true;
32931f1d2f5SGreg Clayton }
33031f1d2f5SGreg Clayton 
SetRegisterLocationToRegister(uint32_t reg_num,uint32_t other_reg_num,bool can_replace)331b9c1b51eSKate Stone bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
33231f1d2f5SGreg Clayton                                                     uint32_t other_reg_num,
333b9c1b51eSKate Stone                                                     bool can_replace) {
334b9c1b51eSKate Stone   if (!can_replace &&
335b9c1b51eSKate Stone       m_register_locations.find(reg_num) != m_register_locations.end())
33631f1d2f5SGreg Clayton     return false;
33731f1d2f5SGreg Clayton   RegisterLocation reg_loc;
33831f1d2f5SGreg Clayton   reg_loc.SetInRegister(other_reg_num);
33931f1d2f5SGreg Clayton   m_register_locations[reg_num] = reg_loc;
34031f1d2f5SGreg Clayton   return true;
34131f1d2f5SGreg Clayton }
34231f1d2f5SGreg Clayton 
SetRegisterLocationToSame(uint32_t reg_num,bool must_replace)343b9c1b51eSKate Stone bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
344b9c1b51eSKate Stone                                                 bool must_replace) {
345b9c1b51eSKate Stone   if (must_replace &&
346b9c1b51eSKate Stone       m_register_locations.find(reg_num) == m_register_locations.end())
34731f1d2f5SGreg Clayton     return false;
34831f1d2f5SGreg Clayton   RegisterLocation reg_loc;
34931f1d2f5SGreg Clayton   reg_loc.SetSame();
35031f1d2f5SGreg Clayton   m_register_locations[reg_num] = reg_loc;
35131f1d2f5SGreg Clayton   return true;
35231f1d2f5SGreg Clayton }
35331f1d2f5SGreg Clayton 
operator ==(const UnwindPlan::Row & rhs) const354b9c1b51eSKate Stone bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
355fcdef15dSJason Molenda   return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
3564538ed3bSAleksandr Urakov          m_afa_value == rhs.m_afa_value &&
357fcdef15dSJason Molenda          m_unspecified_registers_are_undefined ==
358fcdef15dSJason Molenda              rhs.m_unspecified_registers_are_undefined &&
359ab970f5eSPavel Labath          m_register_locations == rhs.m_register_locations;
36024a8378cSJason Molenda }
36124a8378cSJason Molenda 
AppendRow(const UnwindPlan::RowSP & row_sp)362b9c1b51eSKate Stone void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
363b9c1b51eSKate Stone   if (m_row_list.empty() ||
364b9c1b51eSKate Stone       m_row_list.back()->GetOffset() != row_sp->GetOffset())
365358a7897SGreg Clayton     m_row_list.push_back(row_sp);
366fbcb7f2cSJason Molenda   else
367358a7897SGreg Clayton     m_row_list.back() = row_sp;
368fbcb7f2cSJason Molenda }
369fbcb7f2cSJason Molenda 
InsertRow(const UnwindPlan::RowSP & row_sp,bool replace_existing)370b9c1b51eSKate Stone void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
371b9c1b51eSKate Stone                            bool replace_existing) {
3720562524bSTodd Fiala   collection::iterator it = m_row_list.begin();
3730562524bSTodd Fiala   while (it != m_row_list.end()) {
3740562524bSTodd Fiala     RowSP row = *it;
37544ff9cceSTamas Berghammer     if (row->GetOffset() >= row_sp->GetOffset())
3760562524bSTodd Fiala       break;
3770562524bSTodd Fiala     it++;
3780562524bSTodd Fiala   }
37944ff9cceSTamas Berghammer   if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
3800562524bSTodd Fiala     m_row_list.insert(it, row_sp);
38110e99238STamas Berghammer   else if (replace_existing)
38210e99238STamas Berghammer     *it = row_sp;
3830562524bSTodd Fiala }
3840562524bSTodd Fiala 
GetRowForFunctionOffset(int offset) const385b9c1b51eSKate Stone UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
3861d42c7bcSJason Molenda   RowSP row;
387b9c1b51eSKate Stone   if (!m_row_list.empty()) {
388877aaa58SGreg Clayton     if (offset == -1)
3891d42c7bcSJason Molenda       row = m_row_list.back();
390b9c1b51eSKate Stone     else {
391877aaa58SGreg Clayton       collection::const_iterator pos, end = m_row_list.end();
392b9c1b51eSKate Stone       for (pos = m_row_list.begin(); pos != end; ++pos) {
3933985c8c6SSaleem Abdulrasool         if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
3941d42c7bcSJason Molenda           row = *pos;
395877aaa58SGreg Clayton         else
396fbcb7f2cSJason Molenda           break;
397fbcb7f2cSJason Molenda       }
398fbcb7f2cSJason Molenda     }
399877aaa58SGreg Clayton   }
4001d42c7bcSJason Molenda   return row;
401fbcb7f2cSJason Molenda }
402fbcb7f2cSJason Molenda 
IsValidRowIndex(uint32_t idx) const403b9c1b51eSKate Stone bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
404fbcb7f2cSJason Molenda   return idx < m_row_list.size();
405fbcb7f2cSJason Molenda }
406fbcb7f2cSJason Molenda 
GetRowAtIndex(uint32_t idx) const407b9c1b51eSKate Stone const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
408d28fae83SGreg Clayton   if (idx < m_row_list.size())
409fbcb7f2cSJason Molenda     return m_row_list[idx];
410b9c1b51eSKate Stone   else {
411a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Unwind);
41263e5fb76SJonas Devlieghere     LLDB_LOGF(log,
41363e5fb76SJonas Devlieghere               "error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
414b9c1b51eSKate Stone               "(number rows is %u)",
415b9c1b51eSKate Stone               idx, (uint32_t)m_row_list.size());
416d28fae83SGreg Clayton     return UnwindPlan::RowSP();
417d28fae83SGreg Clayton   }
418fbcb7f2cSJason Molenda }
419fbcb7f2cSJason Molenda 
GetLastRow() const420b9c1b51eSKate Stone const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
421b9c1b51eSKate Stone   if (m_row_list.empty()) {
422a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Unwind);
42363e5fb76SJonas Devlieghere     LLDB_LOGF(log, "UnwindPlan::GetLastRow() when rows are empty");
424d28fae83SGreg Clayton     return UnwindPlan::RowSP();
425d28fae83SGreg Clayton   }
42631f1d2f5SGreg Clayton   return m_row_list.back();
42731f1d2f5SGreg Clayton }
42831f1d2f5SGreg Clayton 
GetRowCount() const429b9c1b51eSKate Stone int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
430fbcb7f2cSJason Molenda 
SetPlanValidAddressRange(const AddressRange & range)431b9c1b51eSKate Stone void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
432ab4f1924SJason Molenda   if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
433fbcb7f2cSJason Molenda     m_plan_valid_address_range = range;
434ab4f1924SJason Molenda }
435fbcb7f2cSJason Molenda 
PlanValidAtAddress(Address addr)436b9c1b51eSKate Stone bool UnwindPlan::PlanValidAtAddress(Address addr) {
43761cd0729SJason Molenda   // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
438b9c1b51eSKate Stone   if (GetRowCount() == 0) {
439a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Unwind);
440b9c1b51eSKate Stone     if (log) {
441135e55f8SJason Molenda       StreamString s;
442b9c1b51eSKate Stone       if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
44363e5fb76SJonas Devlieghere         LLDB_LOGF(log,
44463e5fb76SJonas Devlieghere                   "UnwindPlan is invalid -- no unwind rows for UnwindPlan "
445b9c1b51eSKate Stone                   "'%s' at address %s",
446135e55f8SJason Molenda                   m_source_name.GetCString(), s.GetData());
447b9c1b51eSKate Stone       } else {
44863e5fb76SJonas Devlieghere         LLDB_LOGF(log,
449b9c1b51eSKate Stone                   "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
450135e55f8SJason Molenda                   m_source_name.GetCString());
451135e55f8SJason Molenda       }
452135e55f8SJason Molenda     }
45361cd0729SJason Molenda     return false;
45461cd0729SJason Molenda   }
45561cd0729SJason Molenda 
45661cd0729SJason Molenda   // If the 0th Row of unwind instructions is missing, or if it doesn't provide
457b9c1b51eSKate Stone   // a register to use to find the Canonical Frame Address, this is not a valid
458b9c1b51eSKate Stone   // UnwindPlan.
459ab970f5eSPavel Labath   if (GetRowAtIndex(0).get() == nullptr ||
460b9c1b51eSKate Stone       GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
4614538ed3bSAleksandr Urakov           Row::FAValue::unspecified) {
462a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Unwind);
463b9c1b51eSKate Stone     if (log) {
464135e55f8SJason Molenda       StreamString s;
465b9c1b51eSKate Stone       if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
46663e5fb76SJonas Devlieghere         LLDB_LOGF(log,
46763e5fb76SJonas Devlieghere                   "UnwindPlan is invalid -- no CFA register defined in row 0 "
468b9c1b51eSKate Stone                   "for UnwindPlan '%s' at address %s",
469135e55f8SJason Molenda                   m_source_name.GetCString(), s.GetData());
470b9c1b51eSKate Stone       } else {
47163e5fb76SJonas Devlieghere         LLDB_LOGF(log,
47263e5fb76SJonas Devlieghere                   "UnwindPlan is invalid -- no CFA register defined in row 0 "
473b9c1b51eSKate Stone                   "for UnwindPlan '%s'",
474135e55f8SJason Molenda                   m_source_name.GetCString());
475135e55f8SJason Molenda       }
476135e55f8SJason Molenda     }
47761cd0729SJason Molenda     return false;
47861cd0729SJason Molenda   }
47961cd0729SJason Molenda 
480b9c1b51eSKate Stone   if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
481b9c1b51eSKate Stone       m_plan_valid_address_range.GetByteSize() == 0)
482fbcb7f2cSJason Molenda     return true;
483fbcb7f2cSJason Molenda 
4845976200dSJason Molenda   if (!addr.IsValid())
4855976200dSJason Molenda     return true;
4865976200dSJason Molenda 
487fbcb7f2cSJason Molenda   if (m_plan_valid_address_range.ContainsFileAddress(addr))
488fbcb7f2cSJason Molenda     return true;
489fbcb7f2cSJason Molenda 
490fbcb7f2cSJason Molenda   return false;
491fbcb7f2cSJason Molenda }
492fbcb7f2cSJason Molenda 
Dump(Stream & s,Thread * thread,lldb::addr_t base_addr) const493b9c1b51eSKate Stone void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
494b9c1b51eSKate Stone   if (!m_source_name.IsEmpty()) {
495b9c1b51eSKate Stone     s.Printf("This UnwindPlan originally sourced from %s\n",
496b9c1b51eSKate Stone              m_source_name.GetCString());
497ab4f1924SJason Molenda   }
498b9c1b51eSKate Stone   if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
499e9c7ecf6SJason Molenda     TargetSP target_sp(thread->CalculateTarget());
500e9c7ecf6SJason Molenda     addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
501b9c1b51eSKate Stone     addr_t personality_func_load_addr =
502b9c1b51eSKate Stone         m_personality_func_addr.GetLoadAddress(target_sp.get());
503e9c7ecf6SJason Molenda 
504b9c1b51eSKate Stone     if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
505b9c1b51eSKate Stone         personality_func_load_addr != LLDB_INVALID_ADDRESS) {
506b9c1b51eSKate Stone       s.Printf("LSDA address 0x%" PRIx64
507b9c1b51eSKate Stone                ", personality routine is at address 0x%" PRIx64 "\n",
508e9c7ecf6SJason Molenda                lsda_load_addr, personality_func_load_addr);
509e9c7ecf6SJason Molenda     }
510e9c7ecf6SJason Molenda   }
511e9c7ecf6SJason Molenda   s.Printf("This UnwindPlan is sourced from the compiler: ");
512b9c1b51eSKate Stone   switch (m_plan_is_sourced_from_compiler) {
513e9c7ecf6SJason Molenda   case eLazyBoolYes:
514e9c7ecf6SJason Molenda     s.Printf("yes.\n");
515e9c7ecf6SJason Molenda     break;
516e9c7ecf6SJason Molenda   case eLazyBoolNo:
517e9c7ecf6SJason Molenda     s.Printf("no.\n");
518e9c7ecf6SJason Molenda     break;
519e9c7ecf6SJason Molenda   case eLazyBoolCalculate:
520e9c7ecf6SJason Molenda     s.Printf("not specified.\n");
521e9c7ecf6SJason Molenda     break;
522e9c7ecf6SJason Molenda   }
523e9c7ecf6SJason Molenda   s.Printf("This UnwindPlan is valid at all instruction locations: ");
524b9c1b51eSKate Stone   switch (m_plan_is_valid_at_all_instruction_locations) {
525e9c7ecf6SJason Molenda   case eLazyBoolYes:
526e9c7ecf6SJason Molenda     s.Printf("yes.\n");
527e9c7ecf6SJason Molenda     break;
528e9c7ecf6SJason Molenda   case eLazyBoolNo:
529e9c7ecf6SJason Molenda     s.Printf("no.\n");
530e9c7ecf6SJason Molenda     break;
531e9c7ecf6SJason Molenda   case eLazyBoolCalculate:
532e9c7ecf6SJason Molenda     s.Printf("not specified.\n");
533e9c7ecf6SJason Molenda     break;
534e9c7ecf6SJason Molenda   }
53599d187a0SJason Molenda   s.Printf("This UnwindPlan is for a trap handler function: ");
53699d187a0SJason Molenda   switch (m_plan_is_for_signal_trap) {
53799d187a0SJason Molenda   case eLazyBoolYes:
53899d187a0SJason Molenda     s.Printf("yes.\n");
53999d187a0SJason Molenda     break;
54099d187a0SJason Molenda   case eLazyBoolNo:
54199d187a0SJason Molenda     s.Printf("no.\n");
54299d187a0SJason Molenda     break;
54399d187a0SJason Molenda   case eLazyBoolCalculate:
54499d187a0SJason Molenda     s.Printf("not specified.\n");
54599d187a0SJason Molenda     break;
54699d187a0SJason Molenda   }
547b9c1b51eSKate Stone   if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
548b9c1b51eSKate Stone       m_plan_valid_address_range.GetByteSize() > 0) {
549877aaa58SGreg Clayton     s.PutCString("Address range of this UnwindPlan: ");
5501ac04c30SGreg Clayton     TargetSP target_sp(thread->CalculateTarget());
551b9c1b51eSKate Stone     m_plan_valid_address_range.Dump(&s, target_sp.get(),
552b9c1b51eSKate Stone                                     Address::DumpStyleSectionNameOffset);
553877aaa58SGreg Clayton     s.EOL();
554ab4f1924SJason Molenda   }
555b9c1b51eSKate Stone   collection::const_iterator pos, begin = m_row_list.begin(),
556b9c1b51eSKate Stone                                   end = m_row_list.end();
557b9c1b51eSKate Stone   for (pos = begin; pos != end; ++pos) {
55831f1d2f5SGreg Clayton     s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
5591d42c7bcSJason Molenda     (*pos)->Dump(s, this, thread, base_addr);
560fcdef15dSJason Molenda     s.Printf("\n");
561fbcb7f2cSJason Molenda   }
562fbcb7f2cSJason Molenda }
563ab4f1924SJason Molenda 
SetSourceName(const char * source)564b9c1b51eSKate Stone void UnwindPlan::SetSourceName(const char *source) {
565ab4f1924SJason Molenda   m_source_name = ConstString(source);
566ab4f1924SJason Molenda }
567ab4f1924SJason Molenda 
GetSourceName() const568b9c1b51eSKate Stone ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
56931f1d2f5SGreg Clayton 
GetRegisterInfo(Thread * thread,uint32_t unwind_reg) const570b9c1b51eSKate Stone const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
571b9c1b51eSKate Stone                                                 uint32_t unwind_reg) const {
572b9c1b51eSKate Stone   if (thread) {
57331f1d2f5SGreg Clayton     RegisterContext *reg_ctx = thread->GetRegisterContext().get();
574b9c1b51eSKate Stone     if (reg_ctx) {
57531f1d2f5SGreg Clayton       uint32_t reg;
57631f1d2f5SGreg Clayton       if (m_register_kind == eRegisterKindLLDB)
57731f1d2f5SGreg Clayton         reg = unwind_reg;
57831f1d2f5SGreg Clayton       else
579b9c1b51eSKate Stone         reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
580b9c1b51eSKate Stone                                                            unwind_reg);
58131f1d2f5SGreg Clayton       if (reg != LLDB_INVALID_REGNUM)
58231f1d2f5SGreg Clayton         return reg_ctx->GetRegisterInfoAtIndex(reg);
58331f1d2f5SGreg Clayton     }
58431f1d2f5SGreg Clayton   }
585d4612ad0SEd Maste   return nullptr;
58631f1d2f5SGreg Clayton }
587