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 ®ister_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