xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- UnwindAssemblyInstEmulation.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 "UnwindAssemblyInstEmulation.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Core/Address.h"
12061da546Spatrick #include "lldb/Core/Disassembler.h"
13061da546Spatrick #include "lldb/Core/DumpDataExtractor.h"
14061da546Spatrick #include "lldb/Core/DumpRegisterValue.h"
15061da546Spatrick #include "lldb/Core/FormatEntity.h"
16061da546Spatrick #include "lldb/Core/PluginManager.h"
17061da546Spatrick #include "lldb/Target/ExecutionContext.h"
18061da546Spatrick #include "lldb/Target/Process.h"
19061da546Spatrick #include "lldb/Target/Target.h"
20061da546Spatrick #include "lldb/Target/Thread.h"
21061da546Spatrick #include "lldb/Utility/ArchSpec.h"
22061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
23061da546Spatrick #include "lldb/Utility/DataExtractor.h"
24*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
25061da546Spatrick #include "lldb/Utility/Log.h"
26061da546Spatrick #include "lldb/Utility/Status.h"
27061da546Spatrick #include "lldb/Utility/StreamString.h"
28061da546Spatrick 
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick 
LLDB_PLUGIN_DEFINE(UnwindAssemblyInstEmulation)32dda28197Spatrick LLDB_PLUGIN_DEFINE(UnwindAssemblyInstEmulation)
33dda28197Spatrick 
34061da546Spatrick //  UnwindAssemblyInstEmulation method definitions
35061da546Spatrick 
36061da546Spatrick bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
37061da546Spatrick     AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) {
38061da546Spatrick   std::vector<uint8_t> function_text(range.GetByteSize());
39061da546Spatrick   ProcessSP process_sp(thread.GetProcess());
40061da546Spatrick   if (process_sp) {
41061da546Spatrick     Status error;
42be691f3bSpatrick     const bool force_live_memory = true;
43061da546Spatrick     if (process_sp->GetTarget().ReadMemory(
44be691f3bSpatrick             range.GetBaseAddress(), function_text.data(), range.GetByteSize(),
45be691f3bSpatrick             error, force_live_memory) != range.GetByteSize()) {
46061da546Spatrick       return false;
47061da546Spatrick     }
48061da546Spatrick   }
49061da546Spatrick   return GetNonCallSiteUnwindPlanFromAssembly(
50061da546Spatrick       range, function_text.data(), function_text.size(), unwind_plan);
51061da546Spatrick }
52061da546Spatrick 
GetNonCallSiteUnwindPlanFromAssembly(AddressRange & range,uint8_t * opcode_data,size_t opcode_size,UnwindPlan & unwind_plan)53061da546Spatrick bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
54061da546Spatrick     AddressRange &range, uint8_t *opcode_data, size_t opcode_size,
55061da546Spatrick     UnwindPlan &unwind_plan) {
56061da546Spatrick   if (opcode_data == nullptr || opcode_size == 0)
57061da546Spatrick     return false;
58061da546Spatrick 
59061da546Spatrick   if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() &&
60061da546Spatrick       m_inst_emulator_up.get()) {
61061da546Spatrick 
62061da546Spatrick     // The instruction emulation subclass setup the unwind plan for the first
63061da546Spatrick     // instruction.
64061da546Spatrick     m_inst_emulator_up->CreateFunctionEntryUnwind(unwind_plan);
65061da546Spatrick 
66061da546Spatrick     // CreateFunctionEntryUnwind should have created the first row. If it
67061da546Spatrick     // doesn't, then we are done.
68061da546Spatrick     if (unwind_plan.GetRowCount() == 0)
69061da546Spatrick       return false;
70061da546Spatrick 
71061da546Spatrick     const bool prefer_file_cache = true;
72061da546Spatrick     DisassemblerSP disasm_sp(Disassembler::DisassembleBytes(
73061da546Spatrick         m_arch, nullptr, nullptr, range.GetBaseAddress(), opcode_data,
74061da546Spatrick         opcode_size, 99999, prefer_file_cache));
75061da546Spatrick 
76*f6aab3d8Srobert     Log *log = GetLog(LLDBLog::Unwind);
77061da546Spatrick 
78061da546Spatrick     if (disasm_sp) {
79061da546Spatrick 
80061da546Spatrick       m_range_ptr = &range;
81061da546Spatrick       m_unwind_plan_ptr = &unwind_plan;
82061da546Spatrick 
83061da546Spatrick       const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
84061da546Spatrick       const bool show_address = true;
85061da546Spatrick       const bool show_bytes = true;
86*f6aab3d8Srobert       const bool show_control_flow_kind = true;
87*f6aab3d8Srobert       m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(
88*f6aab3d8Srobert           unwind_plan.GetRegisterKind(), unwind_plan.GetInitialCFARegister());
89061da546Spatrick       m_fp_is_cfa = false;
90061da546Spatrick       m_register_values.clear();
91061da546Spatrick       m_pushed_regs.clear();
92061da546Spatrick 
93061da546Spatrick       // Initialize the CFA with a known value. In the 32 bit case it will be
94061da546Spatrick       // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the
95061da546Spatrick       // address byte size to be safe for any future address sizes
96061da546Spatrick       m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
97061da546Spatrick       RegisterValue cfa_reg_value;
98061da546Spatrick       cfa_reg_value.SetUInt(m_initial_sp, m_cfa_reg_info.byte_size);
99061da546Spatrick       SetRegisterValue(m_cfa_reg_info, cfa_reg_value);
100061da546Spatrick 
101061da546Spatrick       const InstructionList &inst_list = disasm_sp->GetInstructionList();
102061da546Spatrick       const size_t num_instructions = inst_list.GetSize();
103061da546Spatrick 
104061da546Spatrick       if (num_instructions > 0) {
105061da546Spatrick         Instruction *inst = inst_list.GetInstructionAtIndex(0).get();
106061da546Spatrick         const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
107061da546Spatrick 
108061da546Spatrick         // Map for storing the unwind plan row and the value of the registers
109061da546Spatrick         // at a given offset. When we see a forward branch we add a new entry
110061da546Spatrick         // to this map with the actual unwind plan row and register context for
111061da546Spatrick         // the target address of the branch as the current data have to be
112061da546Spatrick         // valid for the target address of the branch too if we are in the same
113061da546Spatrick         // function.
114061da546Spatrick         std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>>
115061da546Spatrick             saved_unwind_states;
116061da546Spatrick 
117061da546Spatrick         // Make a copy of the current instruction Row and save it in m_curr_row
118061da546Spatrick         // so we can add updates as we process the instructions.
119061da546Spatrick         UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
120061da546Spatrick         UnwindPlan::Row *newrow = new UnwindPlan::Row;
121061da546Spatrick         if (last_row.get())
122061da546Spatrick           *newrow = *last_row.get();
123061da546Spatrick         m_curr_row.reset(newrow);
124061da546Spatrick 
125061da546Spatrick         // Add the initial state to the save list with offset 0.
126061da546Spatrick         saved_unwind_states.insert({0, {last_row, m_register_values}});
127061da546Spatrick 
128dda28197Spatrick         // cache the stack pointer register number (in whatever register
129061da546Spatrick         // numbering this UnwindPlan uses) for quick reference during
130061da546Spatrick         // instruction parsing.
131*f6aab3d8Srobert         RegisterInfo sp_reg_info = *m_inst_emulator_up->GetRegisterInfo(
132*f6aab3d8Srobert             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
133061da546Spatrick 
134061da546Spatrick         // The architecture dependent condition code of the last processed
135061da546Spatrick         // instruction.
136061da546Spatrick         EmulateInstruction::InstructionCondition last_condition =
137061da546Spatrick             EmulateInstruction::UnconditionalCondition;
138061da546Spatrick         lldb::addr_t condition_block_start_offset = 0;
139061da546Spatrick 
140061da546Spatrick         for (size_t idx = 0; idx < num_instructions; ++idx) {
141061da546Spatrick           m_curr_row_modified = false;
142061da546Spatrick           m_forward_branch_offset = 0;
143061da546Spatrick 
144061da546Spatrick           inst = inst_list.GetInstructionAtIndex(idx).get();
145061da546Spatrick           if (inst) {
146061da546Spatrick             lldb::addr_t current_offset =
147061da546Spatrick                 inst->GetAddress().GetFileAddress() - base_addr;
148061da546Spatrick             auto it = saved_unwind_states.upper_bound(current_offset);
149061da546Spatrick             assert(it != saved_unwind_states.begin() &&
150061da546Spatrick                    "Unwind row for the function entry missing");
151061da546Spatrick             --it; // Move it to the row corresponding to the current offset
152061da546Spatrick 
153061da546Spatrick             // If the offset of m_curr_row don't match with the offset we see
154061da546Spatrick             // in saved_unwind_states then we have to update m_curr_row and
155061da546Spatrick             // m_register_values based on the saved values. It is happening
156061da546Spatrick             // after we processed an epilogue and a return to caller
157061da546Spatrick             // instruction.
158061da546Spatrick             if (it->second.first->GetOffset() != m_curr_row->GetOffset()) {
159061da546Spatrick               UnwindPlan::Row *newrow = new UnwindPlan::Row;
160061da546Spatrick               *newrow = *it->second.first;
161061da546Spatrick               m_curr_row.reset(newrow);
162061da546Spatrick               m_register_values = it->second.second;
163dda28197Spatrick               // re-set the CFA register ivars to match the
164dda28197Spatrick               // new m_curr_row.
165dda28197Spatrick               if (sp_reg_info.name &&
166dda28197Spatrick                   m_curr_row->GetCFAValue().IsRegisterPlusOffset()) {
167dda28197Spatrick                 uint32_t row_cfa_regnum =
168dda28197Spatrick                     m_curr_row->GetCFAValue().GetRegisterNumber();
169dda28197Spatrick                 lldb::RegisterKind row_kind =
170dda28197Spatrick                     m_unwind_plan_ptr->GetRegisterKind();
171dda28197Spatrick                 // set m_cfa_reg_info to the row's CFA reg.
172*f6aab3d8Srobert                 m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(
173*f6aab3d8Srobert                     row_kind, row_cfa_regnum);
174dda28197Spatrick                 // set m_fp_is_cfa.
175dda28197Spatrick                 if (sp_reg_info.kinds[row_kind] == row_cfa_regnum)
176dda28197Spatrick                   m_fp_is_cfa = false;
177dda28197Spatrick                 else
178dda28197Spatrick                   m_fp_is_cfa = true;
179dda28197Spatrick               }
180061da546Spatrick             }
181061da546Spatrick 
182061da546Spatrick             m_inst_emulator_up->SetInstruction(inst->GetOpcode(),
183061da546Spatrick                                                inst->GetAddress(), nullptr);
184061da546Spatrick 
185061da546Spatrick             if (last_condition !=
186061da546Spatrick                 m_inst_emulator_up->GetInstructionCondition()) {
187061da546Spatrick               if (m_inst_emulator_up->GetInstructionCondition() !=
188061da546Spatrick                       EmulateInstruction::UnconditionalCondition &&
189061da546Spatrick                   saved_unwind_states.count(current_offset) == 0) {
190061da546Spatrick                 // If we don't have a saved row for the current offset then
191061da546Spatrick                 // save our current state because we will have to restore it
192061da546Spatrick                 // after the conditional block.
193061da546Spatrick                 auto new_row =
194061da546Spatrick                     std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
195061da546Spatrick                 saved_unwind_states.insert(
196061da546Spatrick                     {current_offset, {new_row, m_register_values}});
197061da546Spatrick               }
198061da546Spatrick 
199061da546Spatrick               // If the last instruction was conditional with a different
200061da546Spatrick               // condition then the then current condition then restore the
201061da546Spatrick               // condition.
202061da546Spatrick               if (last_condition !=
203061da546Spatrick                   EmulateInstruction::UnconditionalCondition) {
204061da546Spatrick                 const auto &saved_state =
205061da546Spatrick                     saved_unwind_states.at(condition_block_start_offset);
206061da546Spatrick                 m_curr_row =
207061da546Spatrick                     std::make_shared<UnwindPlan::Row>(*saved_state.first);
208061da546Spatrick                 m_curr_row->SetOffset(current_offset);
209061da546Spatrick                 m_register_values = saved_state.second;
210dda28197Spatrick                 // re-set the CFA register ivars to match the
211dda28197Spatrick                 // new m_curr_row.
212dda28197Spatrick                 if (sp_reg_info.name &&
213dda28197Spatrick                     m_curr_row->GetCFAValue().IsRegisterPlusOffset()) {
214dda28197Spatrick                   uint32_t row_cfa_regnum =
215dda28197Spatrick                       m_curr_row->GetCFAValue().GetRegisterNumber();
216dda28197Spatrick                   lldb::RegisterKind row_kind =
217dda28197Spatrick                       m_unwind_plan_ptr->GetRegisterKind();
218dda28197Spatrick                   // set m_cfa_reg_info to the row's CFA reg.
219*f6aab3d8Srobert                   m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(
220*f6aab3d8Srobert                       row_kind, row_cfa_regnum);
221dda28197Spatrick                   // set m_fp_is_cfa.
222dda28197Spatrick                   if (sp_reg_info.kinds[row_kind] == row_cfa_regnum)
223dda28197Spatrick                     m_fp_is_cfa = false;
224dda28197Spatrick                   else
225dda28197Spatrick                     m_fp_is_cfa = true;
226dda28197Spatrick                 }
227061da546Spatrick                 bool replace_existing =
228061da546Spatrick                     true; // The last instruction might already
229061da546Spatrick                           // created a row for this offset and
230061da546Spatrick                           // we want to overwrite it.
231061da546Spatrick                 unwind_plan.InsertRow(
232061da546Spatrick                     std::make_shared<UnwindPlan::Row>(*m_curr_row),
233061da546Spatrick                     replace_existing);
234061da546Spatrick               }
235061da546Spatrick 
236061da546Spatrick               // We are starting a new conditional block at the actual offset
237061da546Spatrick               condition_block_start_offset = current_offset;
238061da546Spatrick             }
239061da546Spatrick 
240061da546Spatrick             if (log && log->GetVerbose()) {
241061da546Spatrick               StreamString strm;
242061da546Spatrick               lldb_private::FormatEntity::Entry format;
243061da546Spatrick               FormatEntity::Parse("${frame.pc}: ", format);
244061da546Spatrick               inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
245*f6aab3d8Srobert                          show_bytes, show_control_flow_kind, nullptr, nullptr,
246*f6aab3d8Srobert                          nullptr, &format, 0);
247061da546Spatrick               log->PutString(strm.GetString());
248061da546Spatrick             }
249061da546Spatrick 
250061da546Spatrick             last_condition = m_inst_emulator_up->GetInstructionCondition();
251061da546Spatrick 
252061da546Spatrick             m_inst_emulator_up->EvaluateInstruction(
253061da546Spatrick                 eEmulateInstructionOptionIgnoreConditions);
254061da546Spatrick 
255061da546Spatrick             // If the current instruction is a branch forward then save the
256061da546Spatrick             // current CFI information for the offset where we are branching.
257061da546Spatrick             if (m_forward_branch_offset != 0 &&
258061da546Spatrick                 range.ContainsFileAddress(inst->GetAddress().GetFileAddress() +
259061da546Spatrick                                           m_forward_branch_offset)) {
260061da546Spatrick               auto newrow =
261061da546Spatrick                   std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
262061da546Spatrick               newrow->SetOffset(current_offset + m_forward_branch_offset);
263061da546Spatrick               saved_unwind_states.insert(
264061da546Spatrick                   {current_offset + m_forward_branch_offset,
265061da546Spatrick                    {newrow, m_register_values}});
266061da546Spatrick               unwind_plan.InsertRow(newrow);
267061da546Spatrick             }
268061da546Spatrick 
269061da546Spatrick             // Were there any changes to the CFI while evaluating this
270061da546Spatrick             // instruction?
271061da546Spatrick             if (m_curr_row_modified) {
272061da546Spatrick               // Save the modified row if we don't already have a CFI row in
273061da546Spatrick               // the current address
274061da546Spatrick               if (saved_unwind_states.count(
275061da546Spatrick                       current_offset + inst->GetOpcode().GetByteSize()) == 0) {
276061da546Spatrick                 m_curr_row->SetOffset(current_offset +
277061da546Spatrick                                       inst->GetOpcode().GetByteSize());
278061da546Spatrick                 unwind_plan.InsertRow(m_curr_row);
279061da546Spatrick                 saved_unwind_states.insert(
280061da546Spatrick                     {current_offset + inst->GetOpcode().GetByteSize(),
281061da546Spatrick                      {m_curr_row, m_register_values}});
282061da546Spatrick 
283061da546Spatrick                 // Allocate a new Row for m_curr_row, copy the current state
284061da546Spatrick                 // into it
285061da546Spatrick                 UnwindPlan::Row *newrow = new UnwindPlan::Row;
286061da546Spatrick                 *newrow = *m_curr_row.get();
287061da546Spatrick                 m_curr_row.reset(newrow);
288061da546Spatrick               }
289061da546Spatrick             }
290061da546Spatrick           }
291061da546Spatrick         }
292061da546Spatrick       }
293061da546Spatrick     }
294061da546Spatrick 
295061da546Spatrick     if (log && log->GetVerbose()) {
296061da546Spatrick       StreamString strm;
297061da546Spatrick       lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
298061da546Spatrick       strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
299061da546Spatrick                   base_addr, base_addr + range.GetByteSize());
300061da546Spatrick       unwind_plan.Dump(strm, nullptr, base_addr);
301061da546Spatrick       log->PutString(strm.GetString());
302061da546Spatrick     }
303061da546Spatrick     return unwind_plan.GetRowCount() > 0;
304061da546Spatrick   }
305061da546Spatrick   return false;
306061da546Spatrick }
307061da546Spatrick 
AugmentUnwindPlanFromCallSite(AddressRange & func,Thread & thread,UnwindPlan & unwind_plan)308061da546Spatrick bool UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite(
309061da546Spatrick     AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
310061da546Spatrick   return false;
311061da546Spatrick }
312061da546Spatrick 
GetFastUnwindPlan(AddressRange & func,Thread & thread,UnwindPlan & unwind_plan)313061da546Spatrick bool UnwindAssemblyInstEmulation::GetFastUnwindPlan(AddressRange &func,
314061da546Spatrick                                                     Thread &thread,
315061da546Spatrick                                                     UnwindPlan &unwind_plan) {
316061da546Spatrick   return false;
317061da546Spatrick }
318061da546Spatrick 
FirstNonPrologueInsn(AddressRange & func,const ExecutionContext & exe_ctx,Address & first_non_prologue_insn)319061da546Spatrick bool UnwindAssemblyInstEmulation::FirstNonPrologueInsn(
320061da546Spatrick     AddressRange &func, const ExecutionContext &exe_ctx,
321061da546Spatrick     Address &first_non_prologue_insn) {
322061da546Spatrick   return false;
323061da546Spatrick }
324061da546Spatrick 
325061da546Spatrick UnwindAssembly *
CreateInstance(const ArchSpec & arch)326061da546Spatrick UnwindAssemblyInstEmulation::CreateInstance(const ArchSpec &arch) {
327061da546Spatrick   std::unique_ptr<EmulateInstruction> inst_emulator_up(
328061da546Spatrick       EmulateInstruction::FindPlugin(arch, eInstructionTypePrologueEpilogue,
329061da546Spatrick                                      nullptr));
330061da546Spatrick   // Make sure that all prologue instructions are handled
331061da546Spatrick   if (inst_emulator_up)
332061da546Spatrick     return new UnwindAssemblyInstEmulation(arch, inst_emulator_up.release());
333061da546Spatrick   return nullptr;
334061da546Spatrick }
335061da546Spatrick 
Initialize()336061da546Spatrick void UnwindAssemblyInstEmulation::Initialize() {
337061da546Spatrick   PluginManager::RegisterPlugin(GetPluginNameStatic(),
338061da546Spatrick                                 GetPluginDescriptionStatic(), CreateInstance);
339061da546Spatrick }
340061da546Spatrick 
Terminate()341061da546Spatrick void UnwindAssemblyInstEmulation::Terminate() {
342061da546Spatrick   PluginManager::UnregisterPlugin(CreateInstance);
343061da546Spatrick }
344061da546Spatrick 
GetPluginDescriptionStatic()345*f6aab3d8Srobert llvm::StringRef UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() {
346061da546Spatrick   return "Instruction emulation based unwind information.";
347061da546Spatrick }
348061da546Spatrick 
MakeRegisterKindValuePair(const RegisterInfo & reg_info)349061da546Spatrick uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair(
350061da546Spatrick     const RegisterInfo &reg_info) {
351061da546Spatrick   lldb::RegisterKind reg_kind;
352061da546Spatrick   uint32_t reg_num;
353061da546Spatrick   if (EmulateInstruction::GetBestRegisterKindAndNumber(&reg_info, reg_kind,
354061da546Spatrick                                                        reg_num))
355061da546Spatrick     return (uint64_t)reg_kind << 24 | reg_num;
356061da546Spatrick   return 0ull;
357061da546Spatrick }
358061da546Spatrick 
SetRegisterValue(const RegisterInfo & reg_info,const RegisterValue & reg_value)359061da546Spatrick void UnwindAssemblyInstEmulation::SetRegisterValue(
360061da546Spatrick     const RegisterInfo &reg_info, const RegisterValue &reg_value) {
361061da546Spatrick   m_register_values[MakeRegisterKindValuePair(reg_info)] = reg_value;
362061da546Spatrick }
363061da546Spatrick 
GetRegisterValue(const RegisterInfo & reg_info,RegisterValue & reg_value)364061da546Spatrick bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo &reg_info,
365061da546Spatrick                                                    RegisterValue &reg_value) {
366061da546Spatrick   const uint64_t reg_id = MakeRegisterKindValuePair(reg_info);
367061da546Spatrick   RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
368061da546Spatrick   if (pos != m_register_values.end()) {
369061da546Spatrick     reg_value = pos->second;
370061da546Spatrick     return true; // We had a real value that comes from an opcode that wrote
371061da546Spatrick                  // to it...
372061da546Spatrick   }
373061da546Spatrick   // We are making up a value that is recognizable...
374061da546Spatrick   reg_value.SetUInt(reg_id, reg_info.byte_size);
375061da546Spatrick   return false;
376061da546Spatrick }
377061da546Spatrick 
ReadMemory(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,void * dst,size_t dst_len)378061da546Spatrick size_t UnwindAssemblyInstEmulation::ReadMemory(
379061da546Spatrick     EmulateInstruction *instruction, void *baton,
380061da546Spatrick     const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,
381061da546Spatrick     size_t dst_len) {
382*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Unwind);
383061da546Spatrick 
384061da546Spatrick   if (log && log->GetVerbose()) {
385061da546Spatrick     StreamString strm;
386061da546Spatrick     strm.Printf(
387061da546Spatrick         "UnwindAssemblyInstEmulation::ReadMemory    (addr = 0x%16.16" PRIx64
388061da546Spatrick         ", dst = %p, dst_len = %" PRIu64 ", context = ",
389061da546Spatrick         addr, dst, (uint64_t)dst_len);
390061da546Spatrick     context.Dump(strm, instruction);
391061da546Spatrick     log->PutString(strm.GetString());
392061da546Spatrick   }
393061da546Spatrick   memset(dst, 0, dst_len);
394061da546Spatrick   return dst_len;
395061da546Spatrick }
396061da546Spatrick 
WriteMemory(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,const void * dst,size_t dst_len)397061da546Spatrick size_t UnwindAssemblyInstEmulation::WriteMemory(
398061da546Spatrick     EmulateInstruction *instruction, void *baton,
399061da546Spatrick     const EmulateInstruction::Context &context, lldb::addr_t addr,
400061da546Spatrick     const void *dst, size_t dst_len) {
401061da546Spatrick   if (baton && dst && dst_len)
402061da546Spatrick     return ((UnwindAssemblyInstEmulation *)baton)
403061da546Spatrick         ->WriteMemory(instruction, context, addr, dst, dst_len);
404061da546Spatrick   return 0;
405061da546Spatrick }
406061da546Spatrick 
WriteMemory(EmulateInstruction * instruction,const EmulateInstruction::Context & context,lldb::addr_t addr,const void * dst,size_t dst_len)407061da546Spatrick size_t UnwindAssemblyInstEmulation::WriteMemory(
408061da546Spatrick     EmulateInstruction *instruction, const EmulateInstruction::Context &context,
409061da546Spatrick     lldb::addr_t addr, const void *dst, size_t dst_len) {
410061da546Spatrick   DataExtractor data(dst, dst_len,
411061da546Spatrick                      instruction->GetArchitecture().GetByteOrder(),
412061da546Spatrick                      instruction->GetArchitecture().GetAddressByteSize());
413061da546Spatrick 
414*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Unwind);
415061da546Spatrick 
416061da546Spatrick   if (log && log->GetVerbose()) {
417061da546Spatrick     StreamString strm;
418061da546Spatrick 
419061da546Spatrick     strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory   (");
420061da546Spatrick     DumpDataExtractor(data, &strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX,
421061da546Spatrick                       addr, 0, 0);
422061da546Spatrick     strm.PutCString(", context = ");
423061da546Spatrick     context.Dump(strm, instruction);
424061da546Spatrick     log->PutString(strm.GetString());
425061da546Spatrick   }
426061da546Spatrick 
427061da546Spatrick   const bool cant_replace = false;
428061da546Spatrick 
429061da546Spatrick   switch (context.type) {
430061da546Spatrick   default:
431061da546Spatrick   case EmulateInstruction::eContextInvalid:
432061da546Spatrick   case EmulateInstruction::eContextReadOpcode:
433061da546Spatrick   case EmulateInstruction::eContextImmediate:
434061da546Spatrick   case EmulateInstruction::eContextAdjustBaseRegister:
435061da546Spatrick   case EmulateInstruction::eContextRegisterPlusOffset:
436061da546Spatrick   case EmulateInstruction::eContextAdjustPC:
437061da546Spatrick   case EmulateInstruction::eContextRegisterStore:
438061da546Spatrick   case EmulateInstruction::eContextRegisterLoad:
439061da546Spatrick   case EmulateInstruction::eContextRelativeBranchImmediate:
440061da546Spatrick   case EmulateInstruction::eContextAbsoluteBranchRegister:
441061da546Spatrick   case EmulateInstruction::eContextSupervisorCall:
442061da546Spatrick   case EmulateInstruction::eContextTableBranchReadMemory:
443061da546Spatrick   case EmulateInstruction::eContextWriteRegisterRandomBits:
444061da546Spatrick   case EmulateInstruction::eContextWriteMemoryRandomBits:
445061da546Spatrick   case EmulateInstruction::eContextArithmetic:
446061da546Spatrick   case EmulateInstruction::eContextAdvancePC:
447061da546Spatrick   case EmulateInstruction::eContextReturnFromException:
448061da546Spatrick   case EmulateInstruction::eContextPopRegisterOffStack:
449061da546Spatrick   case EmulateInstruction::eContextAdjustStackPointer:
450061da546Spatrick     break;
451061da546Spatrick 
452061da546Spatrick   case EmulateInstruction::eContextPushRegisterOnStack: {
453061da546Spatrick     uint32_t reg_num = LLDB_INVALID_REGNUM;
454061da546Spatrick     uint32_t generic_regnum = LLDB_INVALID_REGNUM;
455*f6aab3d8Srobert     assert(context.GetInfoType() ==
456061da546Spatrick                EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset &&
457061da546Spatrick            "unhandled case, add code to handle this!");
458061da546Spatrick     const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
459061da546Spatrick     reg_num = context.info.RegisterToRegisterPlusOffset.data_reg
460061da546Spatrick                   .kinds[unwind_reg_kind];
461061da546Spatrick     generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg
462061da546Spatrick                          .kinds[eRegisterKindGeneric];
463061da546Spatrick 
464061da546Spatrick     if (reg_num != LLDB_INVALID_REGNUM &&
465061da546Spatrick         generic_regnum != LLDB_REGNUM_GENERIC_SP) {
466061da546Spatrick       if (m_pushed_regs.find(reg_num) == m_pushed_regs.end()) {
467061da546Spatrick         m_pushed_regs[reg_num] = addr;
468061da546Spatrick         const int32_t offset = addr - m_initial_sp;
469061da546Spatrick         m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,
470061da546Spatrick                                                          cant_replace);
471061da546Spatrick         m_curr_row_modified = true;
472061da546Spatrick       }
473061da546Spatrick     }
474061da546Spatrick   } break;
475061da546Spatrick   }
476061da546Spatrick 
477061da546Spatrick   return dst_len;
478061da546Spatrick }
479061da546Spatrick 
ReadRegister(EmulateInstruction * instruction,void * baton,const RegisterInfo * reg_info,RegisterValue & reg_value)480061da546Spatrick bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,
481061da546Spatrick                                                void *baton,
482061da546Spatrick                                                const RegisterInfo *reg_info,
483061da546Spatrick                                                RegisterValue &reg_value) {
484061da546Spatrick 
485061da546Spatrick   if (baton && reg_info)
486061da546Spatrick     return ((UnwindAssemblyInstEmulation *)baton)
487061da546Spatrick         ->ReadRegister(instruction, reg_info, reg_value);
488061da546Spatrick   return false;
489061da546Spatrick }
ReadRegister(EmulateInstruction * instruction,const RegisterInfo * reg_info,RegisterValue & reg_value)490061da546Spatrick bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,
491061da546Spatrick                                                const RegisterInfo *reg_info,
492061da546Spatrick                                                RegisterValue &reg_value) {
493061da546Spatrick   bool synthetic = GetRegisterValue(*reg_info, reg_value);
494061da546Spatrick 
495*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Unwind);
496061da546Spatrick 
497061da546Spatrick   if (log && log->GetVerbose()) {
498061da546Spatrick 
499061da546Spatrick     StreamString strm;
500061da546Spatrick     strm.Printf("UnwindAssemblyInstEmulation::ReadRegister  (name = \"%s\") => "
501061da546Spatrick                 "synthetic_value = %i, value = ",
502061da546Spatrick                 reg_info->name, synthetic);
503061da546Spatrick     DumpRegisterValue(reg_value, &strm, reg_info, false, false, eFormatDefault);
504061da546Spatrick     log->PutString(strm.GetString());
505061da546Spatrick   }
506061da546Spatrick   return true;
507061da546Spatrick }
508061da546Spatrick 
WriteRegister(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,const RegisterInfo * reg_info,const RegisterValue & reg_value)509061da546Spatrick bool UnwindAssemblyInstEmulation::WriteRegister(
510061da546Spatrick     EmulateInstruction *instruction, void *baton,
511061da546Spatrick     const EmulateInstruction::Context &context, const RegisterInfo *reg_info,
512061da546Spatrick     const RegisterValue &reg_value) {
513061da546Spatrick   if (baton && reg_info)
514061da546Spatrick     return ((UnwindAssemblyInstEmulation *)baton)
515061da546Spatrick         ->WriteRegister(instruction, context, reg_info, reg_value);
516061da546Spatrick   return false;
517061da546Spatrick }
WriteRegister(EmulateInstruction * instruction,const EmulateInstruction::Context & context,const RegisterInfo * reg_info,const RegisterValue & reg_value)518061da546Spatrick bool UnwindAssemblyInstEmulation::WriteRegister(
519061da546Spatrick     EmulateInstruction *instruction, const EmulateInstruction::Context &context,
520061da546Spatrick     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
521*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Unwind);
522061da546Spatrick 
523061da546Spatrick   if (log && log->GetVerbose()) {
524061da546Spatrick 
525061da546Spatrick     StreamString strm;
526061da546Spatrick     strm.Printf(
527061da546Spatrick         "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ",
528061da546Spatrick         reg_info->name);
529061da546Spatrick     DumpRegisterValue(reg_value, &strm, reg_info, false, false, eFormatDefault);
530061da546Spatrick     strm.PutCString(", context = ");
531061da546Spatrick     context.Dump(strm, instruction);
532061da546Spatrick     log->PutString(strm.GetString());
533061da546Spatrick   }
534061da546Spatrick 
535061da546Spatrick   SetRegisterValue(*reg_info, reg_value);
536061da546Spatrick 
537061da546Spatrick   switch (context.type) {
538061da546Spatrick   case EmulateInstruction::eContextInvalid:
539061da546Spatrick   case EmulateInstruction::eContextReadOpcode:
540061da546Spatrick   case EmulateInstruction::eContextImmediate:
541061da546Spatrick   case EmulateInstruction::eContextAdjustBaseRegister:
542061da546Spatrick   case EmulateInstruction::eContextRegisterPlusOffset:
543061da546Spatrick   case EmulateInstruction::eContextAdjustPC:
544061da546Spatrick   case EmulateInstruction::eContextRegisterStore:
545061da546Spatrick   case EmulateInstruction::eContextSupervisorCall:
546061da546Spatrick   case EmulateInstruction::eContextTableBranchReadMemory:
547061da546Spatrick   case EmulateInstruction::eContextWriteRegisterRandomBits:
548061da546Spatrick   case EmulateInstruction::eContextWriteMemoryRandomBits:
549061da546Spatrick   case EmulateInstruction::eContextAdvancePC:
550061da546Spatrick   case EmulateInstruction::eContextReturnFromException:
551061da546Spatrick   case EmulateInstruction::eContextPushRegisterOnStack:
552061da546Spatrick   case EmulateInstruction::eContextRegisterLoad:
553061da546Spatrick     //            {
554061da546Spatrick     //                const uint32_t reg_num =
555061da546Spatrick     //                reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
556061da546Spatrick     //                if (reg_num != LLDB_INVALID_REGNUM)
557061da546Spatrick     //                {
558061da546Spatrick     //                    const bool can_replace_only_if_unspecified = true;
559061da546Spatrick     //
560061da546Spatrick     //                    m_curr_row.SetRegisterLocationToUndefined (reg_num,
561061da546Spatrick     //                                                               can_replace_only_if_unspecified,
562061da546Spatrick     //                                                               can_replace_only_if_unspecified);
563061da546Spatrick     //                    m_curr_row_modified = true;
564061da546Spatrick     //                }
565061da546Spatrick     //            }
566061da546Spatrick     break;
567061da546Spatrick 
568061da546Spatrick   case EmulateInstruction::eContextArithmetic: {
569061da546Spatrick     // If we adjusted the current frame pointer by a constant then adjust the
570061da546Spatrick     // CFA offset
571061da546Spatrick     // with the same amount.
572061da546Spatrick     lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind();
573061da546Spatrick     if (m_fp_is_cfa && reg_info->kinds[kind] == m_cfa_reg_info.kinds[kind] &&
574*f6aab3d8Srobert         context.GetInfoType() ==
575*f6aab3d8Srobert             EmulateInstruction::eInfoTypeRegisterPlusOffset &&
576061da546Spatrick         context.info.RegisterPlusOffset.reg.kinds[kind] ==
577061da546Spatrick             m_cfa_reg_info.kinds[kind]) {
578061da546Spatrick       const int64_t offset = context.info.RegisterPlusOffset.signed_offset;
579061da546Spatrick       m_curr_row->GetCFAValue().IncOffset(-1 * offset);
580061da546Spatrick       m_curr_row_modified = true;
581061da546Spatrick     }
582061da546Spatrick   } break;
583061da546Spatrick 
584061da546Spatrick   case EmulateInstruction::eContextAbsoluteBranchRegister:
585061da546Spatrick   case EmulateInstruction::eContextRelativeBranchImmediate: {
586*f6aab3d8Srobert     if (context.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate &&
587061da546Spatrick         context.info.ISAAndImmediate.unsigned_data32 > 0) {
588061da546Spatrick       m_forward_branch_offset =
589061da546Spatrick           context.info.ISAAndImmediateSigned.signed_data32;
590*f6aab3d8Srobert     } else if (context.GetInfoType() ==
591061da546Spatrick                    EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
592061da546Spatrick                context.info.ISAAndImmediateSigned.signed_data32 > 0) {
593061da546Spatrick       m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
594*f6aab3d8Srobert     } else if (context.GetInfoType() ==
595*f6aab3d8Srobert                    EmulateInstruction::eInfoTypeImmediate &&
596061da546Spatrick                context.info.unsigned_immediate > 0) {
597061da546Spatrick       m_forward_branch_offset = context.info.unsigned_immediate;
598*f6aab3d8Srobert     } else if (context.GetInfoType() ==
599061da546Spatrick                    EmulateInstruction::eInfoTypeImmediateSigned &&
600061da546Spatrick                context.info.signed_immediate > 0) {
601061da546Spatrick       m_forward_branch_offset = context.info.signed_immediate;
602061da546Spatrick     }
603061da546Spatrick   } break;
604061da546Spatrick 
605061da546Spatrick   case EmulateInstruction::eContextPopRegisterOffStack: {
606061da546Spatrick     const uint32_t reg_num =
607061da546Spatrick         reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
608061da546Spatrick     const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];
609061da546Spatrick     if (reg_num != LLDB_INVALID_REGNUM &&
610061da546Spatrick         generic_regnum != LLDB_REGNUM_GENERIC_SP) {
611*f6aab3d8Srobert       switch (context.GetInfoType()) {
612061da546Spatrick       case EmulateInstruction::eInfoTypeAddress:
613061da546Spatrick         if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() &&
614061da546Spatrick             context.info.address == m_pushed_regs[reg_num]) {
615061da546Spatrick           m_curr_row->SetRegisterLocationToSame(reg_num,
616061da546Spatrick                                                 false /*must_replace*/);
617061da546Spatrick           m_curr_row_modified = true;
618*f6aab3d8Srobert 
619*f6aab3d8Srobert           // FP has been restored to its original value, we are back
620*f6aab3d8Srobert           // to using SP to calculate the CFA.
621*f6aab3d8Srobert           if (m_fp_is_cfa) {
622*f6aab3d8Srobert             m_fp_is_cfa = false;
623*f6aab3d8Srobert             lldb::RegisterKind sp_reg_kind = eRegisterKindGeneric;
624*f6aab3d8Srobert             uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP;
625*f6aab3d8Srobert             RegisterInfo sp_reg_info =
626*f6aab3d8Srobert                 *m_inst_emulator_up->GetRegisterInfo(sp_reg_kind, sp_reg_num);
627*f6aab3d8Srobert             RegisterValue sp_reg_val;
628*f6aab3d8Srobert             if (GetRegisterValue(sp_reg_info, sp_reg_val)) {
629*f6aab3d8Srobert               m_cfa_reg_info = sp_reg_info;
630*f6aab3d8Srobert               const uint32_t cfa_reg_num =
631*f6aab3d8Srobert                   sp_reg_info.kinds[m_unwind_plan_ptr->GetRegisterKind()];
632*f6aab3d8Srobert               assert(cfa_reg_num != LLDB_INVALID_REGNUM);
633*f6aab3d8Srobert               m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
634*f6aab3d8Srobert                   cfa_reg_num, m_initial_sp - sp_reg_val.GetAsUInt64());
635*f6aab3d8Srobert             }
636*f6aab3d8Srobert           }
637061da546Spatrick         }
638061da546Spatrick         break;
639061da546Spatrick       case EmulateInstruction::eInfoTypeISA:
640061da546Spatrick         assert(
641061da546Spatrick             (generic_regnum == LLDB_REGNUM_GENERIC_PC ||
642061da546Spatrick              generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) &&
643061da546Spatrick             "eInfoTypeISA used for popping a register other the PC/FLAGS");
644061da546Spatrick         if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) {
645061da546Spatrick           m_curr_row->SetRegisterLocationToSame(reg_num,
646061da546Spatrick                                                 false /*must_replace*/);
647061da546Spatrick           m_curr_row_modified = true;
648061da546Spatrick         }
649061da546Spatrick         break;
650061da546Spatrick       default:
651061da546Spatrick         assert(false && "unhandled case, add code to handle this!");
652061da546Spatrick         break;
653061da546Spatrick       }
654061da546Spatrick     }
655061da546Spatrick   } break;
656061da546Spatrick 
657061da546Spatrick   case EmulateInstruction::eContextSetFramePointer:
658061da546Spatrick     if (!m_fp_is_cfa) {
659061da546Spatrick       m_fp_is_cfa = true;
660061da546Spatrick       m_cfa_reg_info = *reg_info;
661061da546Spatrick       const uint32_t cfa_reg_num =
662061da546Spatrick           reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
663061da546Spatrick       assert(cfa_reg_num != LLDB_INVALID_REGNUM);
664061da546Spatrick       m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
665061da546Spatrick           cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
666061da546Spatrick       m_curr_row_modified = true;
667061da546Spatrick     }
668061da546Spatrick     break;
669061da546Spatrick 
670061da546Spatrick   case EmulateInstruction::eContextRestoreStackPointer:
671061da546Spatrick     if (m_fp_is_cfa) {
672061da546Spatrick       m_fp_is_cfa = false;
673061da546Spatrick       m_cfa_reg_info = *reg_info;
674061da546Spatrick       const uint32_t cfa_reg_num =
675061da546Spatrick           reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
676061da546Spatrick       assert(cfa_reg_num != LLDB_INVALID_REGNUM);
677061da546Spatrick       m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
678061da546Spatrick           cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
679061da546Spatrick       m_curr_row_modified = true;
680061da546Spatrick     }
681061da546Spatrick     break;
682061da546Spatrick 
683061da546Spatrick   case EmulateInstruction::eContextAdjustStackPointer:
684061da546Spatrick     // If we have created a frame using the frame pointer, don't follow
685061da546Spatrick     // subsequent adjustments to the stack pointer.
686061da546Spatrick     if (!m_fp_is_cfa) {
687061da546Spatrick       m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
688061da546Spatrick           m_curr_row->GetCFAValue().GetRegisterNumber(),
689061da546Spatrick           m_initial_sp - reg_value.GetAsUInt64());
690061da546Spatrick       m_curr_row_modified = true;
691061da546Spatrick     }
692061da546Spatrick     break;
693061da546Spatrick   }
694061da546Spatrick   return true;
695061da546Spatrick }
696