1 //===-- UnwindAssemblyInstEmulation.cpp --------------------------*- C++
2 //-*-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #include "UnwindAssemblyInstEmulation.h"
12 
13 #include "lldb/Core/Address.h"
14 #include "lldb/Core/ArchSpec.h"
15 #include "lldb/Core/DataBufferHeap.h"
16 #include "lldb/Core/DataExtractor.h"
17 #include "lldb/Core/Disassembler.h"
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/FormatEntity.h"
20 #include "lldb/Core/Log.h"
21 #include "lldb/Core/PluginManager.h"
22 #include "lldb/Core/StreamString.h"
23 #include "lldb/Target/ExecutionContext.h"
24 #include "lldb/Target/Process.h"
25 #include "lldb/Target/Target.h"
26 #include "lldb/Target/Thread.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 //-----------------------------------------------------------------------------------------------
32 //  UnwindAssemblyInstEmulation method definitions
33 //-----------------------------------------------------------------------------------------------
34 
35 bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
36     AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) {
37   if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() &&
38       m_inst_emulator_ap.get()) {
39 
40     // The instruction emulation subclass setup the unwind plan for the
41     // first instruction.
42     m_inst_emulator_ap->CreateFunctionEntryUnwind(unwind_plan);
43 
44     // CreateFunctionEntryUnwind should have created the first row. If it
45     // doesn't, then we are done.
46     if (unwind_plan.GetRowCount() == 0)
47       return false;
48 
49     ExecutionContext exe_ctx;
50     thread.CalculateExecutionContext(exe_ctx);
51     const bool prefer_file_cache = true;
52     DisassemblerSP disasm_sp(Disassembler::DisassembleRange(
53         m_arch, NULL, NULL, exe_ctx, range, prefer_file_cache));
54 
55     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
56 
57     if (disasm_sp) {
58 
59       m_range_ptr = ⦥
60       m_thread_ptr = &thread;
61       m_unwind_plan_ptr = &unwind_plan;
62 
63       const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
64       const bool show_address = true;
65       const bool show_bytes = true;
66       m_inst_emulator_ap->GetRegisterInfo(unwind_plan.GetRegisterKind(),
67                                           unwind_plan.GetInitialCFARegister(),
68                                           m_cfa_reg_info);
69 
70       m_fp_is_cfa = false;
71       m_register_values.clear();
72       m_pushed_regs.clear();
73 
74       // Initialize the CFA with a known value. In the 32 bit case
75       // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
76       // We use the address byte size to be safe for any future address sizes
77       m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
78       RegisterValue cfa_reg_value;
79       cfa_reg_value.SetUInt(m_initial_sp, m_cfa_reg_info.byte_size);
80       SetRegisterValue(m_cfa_reg_info, cfa_reg_value);
81 
82       const InstructionList &inst_list = disasm_sp->GetInstructionList();
83       const size_t num_instructions = inst_list.GetSize();
84 
85       if (num_instructions > 0) {
86         Instruction *inst = inst_list.GetInstructionAtIndex(0).get();
87         const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
88 
89         // Map for storing the unwind plan row and the value of the registers at
90         // a given offset.
91         // When we see a forward branch we add a new entry to this map with the
92         // actual unwind plan
93         // row and register context for the target address of the branch as the
94         // current data have
95         // to be valid for the target address of the branch too if we are in the
96         // same function.
97         std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>>
98             saved_unwind_states;
99 
100         // Make a copy of the current instruction Row and save it in m_curr_row
101         // so we can add updates as we process the instructions.
102         UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
103         UnwindPlan::Row *newrow = new UnwindPlan::Row;
104         if (last_row.get())
105           *newrow = *last_row.get();
106         m_curr_row.reset(newrow);
107 
108         // Add the initial state to the save list with offset 0.
109         saved_unwind_states.insert({0, {last_row, m_register_values}});
110 
111         // cache the pc register number (in whatever register numbering this
112         // UnwindPlan uses) for
113         // quick reference during instruction parsing.
114         RegisterInfo pc_reg_info;
115         m_inst_emulator_ap->GetRegisterInfo(
116             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info);
117 
118         // cache the return address register number (in whatever register
119         // numbering this UnwindPlan uses) for
120         // quick reference during instruction parsing.
121         RegisterInfo ra_reg_info;
122         m_inst_emulator_ap->GetRegisterInfo(
123             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info);
124 
125         // The architecture dependent condition code of the last processed
126         // instruction.
127         EmulateInstruction::InstructionCondition last_condition =
128             EmulateInstruction::UnconditionalCondition;
129         lldb::addr_t condition_block_start_offset = 0;
130 
131         for (size_t idx = 0; idx < num_instructions; ++idx) {
132           m_curr_row_modified = false;
133           m_forward_branch_offset = 0;
134 
135           inst = inst_list.GetInstructionAtIndex(idx).get();
136           if (inst) {
137             lldb::addr_t current_offset =
138                 inst->GetAddress().GetFileAddress() - base_addr;
139             auto it = saved_unwind_states.upper_bound(current_offset);
140             assert(it != saved_unwind_states.begin() &&
141                    "Unwind row for the function entry missing");
142             --it; // Move it to the row corresponding to the current offset
143 
144             // If the offset of m_curr_row don't match with the offset we see in
145             // saved_unwind_states
146             // then we have to update m_curr_row and m_register_values based on
147             // the saved values. It
148             // is happenning after we processed an epilogue and a return to
149             // caller instruction.
150             if (it->second.first->GetOffset() != m_curr_row->GetOffset()) {
151               UnwindPlan::Row *newrow = new UnwindPlan::Row;
152               *newrow = *it->second.first;
153               m_curr_row.reset(newrow);
154               m_register_values = it->second.second;
155             }
156 
157             m_inst_emulator_ap->SetInstruction(
158                 inst->GetOpcode(), inst->GetAddress(), exe_ctx.GetTargetPtr());
159 
160             if (last_condition !=
161                 m_inst_emulator_ap->GetInstructionCondition()) {
162               if (m_inst_emulator_ap->GetInstructionCondition() !=
163                       EmulateInstruction::UnconditionalCondition &&
164                   saved_unwind_states.count(current_offset) == 0) {
165                 // If we don't have a saved row for the current offset then save
166                 // our
167                 // current state because we will have to restore it after the
168                 // conditional block.
169                 auto new_row =
170                     std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
171                 saved_unwind_states.insert(
172                     {current_offset, {new_row, m_register_values}});
173               }
174 
175               // If the last instruction was conditional with a different
176               // condition
177               // then the then current condition then restore the condition.
178               if (last_condition !=
179                   EmulateInstruction::UnconditionalCondition) {
180                 const auto &saved_state =
181                     saved_unwind_states.at(condition_block_start_offset);
182                 m_curr_row =
183                     std::make_shared<UnwindPlan::Row>(*saved_state.first);
184                 m_curr_row->SetOffset(current_offset);
185                 m_register_values = saved_state.second;
186                 bool replace_existing =
187                     true; // The last instruction might already
188                           // created a row for this offset and
189                           // we want to overwrite it.
190                 unwind_plan.InsertRow(
191                     std::make_shared<UnwindPlan::Row>(*m_curr_row),
192                     replace_existing);
193               }
194 
195               // We are starting a new conditional block at the catual offset
196               condition_block_start_offset = current_offset;
197             }
198 
199             if (log && log->GetVerbose()) {
200               StreamString strm;
201               lldb_private::FormatEntity::Entry format;
202               FormatEntity::Parse("${frame.pc}: ", format);
203               inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
204                          show_bytes, NULL, NULL, NULL, &format, 0);
205               log->PutCString(strm.GetData());
206             }
207 
208             last_condition = m_inst_emulator_ap->GetInstructionCondition();
209 
210             m_inst_emulator_ap->EvaluateInstruction(
211                 eEmulateInstructionOptionIgnoreConditions);
212 
213             // If the current instruction is a branch forward then save the
214             // current CFI information
215             // for the offset where we are branching.
216             if (m_forward_branch_offset != 0 &&
217                 range.ContainsFileAddress(inst->GetAddress().GetFileAddress() +
218                                           m_forward_branch_offset)) {
219               auto newrow =
220                   std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
221               newrow->SetOffset(current_offset + m_forward_branch_offset);
222               saved_unwind_states.insert(
223                   {current_offset + m_forward_branch_offset,
224                    {newrow, m_register_values}});
225               unwind_plan.InsertRow(newrow);
226             }
227 
228             // Were there any changes to the CFI while evaluating this
229             // instruction?
230             if (m_curr_row_modified) {
231               // Save the modified row if we don't already have a CFI row in the
232               // currennt address
233               if (saved_unwind_states.count(
234                       current_offset + inst->GetOpcode().GetByteSize()) == 0) {
235                 m_curr_row->SetOffset(current_offset +
236                                       inst->GetOpcode().GetByteSize());
237                 unwind_plan.InsertRow(m_curr_row);
238                 saved_unwind_states.insert(
239                     {current_offset + inst->GetOpcode().GetByteSize(),
240                      {m_curr_row, m_register_values}});
241 
242                 // Allocate a new Row for m_curr_row, copy the current state
243                 // into it
244                 UnwindPlan::Row *newrow = new UnwindPlan::Row;
245                 *newrow = *m_curr_row.get();
246                 m_curr_row.reset(newrow);
247               }
248             }
249           }
250         }
251       }
252     }
253 
254     if (log && log->GetVerbose()) {
255       StreamString strm;
256       lldb::addr_t base_addr =
257           range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get());
258       strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
259                   base_addr, base_addr + range.GetByteSize());
260       unwind_plan.Dump(strm, &thread, base_addr);
261       log->PutCString(strm.GetData());
262     }
263     return unwind_plan.GetRowCount() > 0;
264   }
265   return false;
266 }
267 
268 bool UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite(
269     AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
270   return false;
271 }
272 
273 bool UnwindAssemblyInstEmulation::GetFastUnwindPlan(AddressRange &func,
274                                                     Thread &thread,
275                                                     UnwindPlan &unwind_plan) {
276   return false;
277 }
278 
279 bool UnwindAssemblyInstEmulation::FirstNonPrologueInsn(
280     AddressRange &func, const ExecutionContext &exe_ctx,
281     Address &first_non_prologue_insn) {
282   return false;
283 }
284 
285 UnwindAssembly *
286 UnwindAssemblyInstEmulation::CreateInstance(const ArchSpec &arch) {
287   std::unique_ptr<EmulateInstruction> inst_emulator_ap(
288       EmulateInstruction::FindPlugin(arch, eInstructionTypePrologueEpilogue,
289                                      NULL));
290   // Make sure that all prologue instructions are handled
291   if (inst_emulator_ap.get())
292     return new UnwindAssemblyInstEmulation(arch, inst_emulator_ap.release());
293   return NULL;
294 }
295 
296 //------------------------------------------------------------------
297 // PluginInterface protocol in UnwindAssemblyParser_x86
298 //------------------------------------------------------------------
299 ConstString UnwindAssemblyInstEmulation::GetPluginName() {
300   return GetPluginNameStatic();
301 }
302 
303 uint32_t UnwindAssemblyInstEmulation::GetPluginVersion() { return 1; }
304 
305 void UnwindAssemblyInstEmulation::Initialize() {
306   PluginManager::RegisterPlugin(GetPluginNameStatic(),
307                                 GetPluginDescriptionStatic(), CreateInstance);
308 }
309 
310 void UnwindAssemblyInstEmulation::Terminate() {
311   PluginManager::UnregisterPlugin(CreateInstance);
312 }
313 
314 ConstString UnwindAssemblyInstEmulation::GetPluginNameStatic() {
315   static ConstString g_name("inst-emulation");
316   return g_name;
317 }
318 
319 const char *UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() {
320   return "Instruction emulation based unwind information.";
321 }
322 
323 uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair(
324     const RegisterInfo &reg_info) {
325   lldb::RegisterKind reg_kind;
326   uint32_t reg_num;
327   if (EmulateInstruction::GetBestRegisterKindAndNumber(&reg_info, reg_kind,
328                                                        reg_num))
329     return (uint64_t)reg_kind << 24 | reg_num;
330   return 0ull;
331 }
332 
333 void UnwindAssemblyInstEmulation::SetRegisterValue(
334     const RegisterInfo &reg_info, const RegisterValue &reg_value) {
335   m_register_values[MakeRegisterKindValuePair(reg_info)] = reg_value;
336 }
337 
338 bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo &reg_info,
339                                                    RegisterValue &reg_value) {
340   const uint64_t reg_id = MakeRegisterKindValuePair(reg_info);
341   RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
342   if (pos != m_register_values.end()) {
343     reg_value = pos->second;
344     return true; // We had a real value that comes from an opcode that wrote
345                  // to it...
346   }
347   // We are making up a value that is recognizable...
348   reg_value.SetUInt(reg_id, reg_info.byte_size);
349   return false;
350 }
351 
352 size_t UnwindAssemblyInstEmulation::ReadMemory(
353     EmulateInstruction *instruction, void *baton,
354     const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,
355     size_t dst_len) {
356   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
357 
358   if (log && log->GetVerbose()) {
359     StreamString strm;
360     strm.Printf(
361         "UnwindAssemblyInstEmulation::ReadMemory    (addr = 0x%16.16" PRIx64
362         ", dst = %p, dst_len = %" PRIu64 ", context = ",
363         addr, dst, (uint64_t)dst_len);
364     context.Dump(strm, instruction);
365     log->PutCString(strm.GetData());
366   }
367   memset(dst, 0, dst_len);
368   return dst_len;
369 }
370 
371 size_t UnwindAssemblyInstEmulation::WriteMemory(
372     EmulateInstruction *instruction, void *baton,
373     const EmulateInstruction::Context &context, lldb::addr_t addr,
374     const void *dst, size_t dst_len) {
375   if (baton && dst && dst_len)
376     return ((UnwindAssemblyInstEmulation *)baton)
377         ->WriteMemory(instruction, context, addr, dst, dst_len);
378   return 0;
379 }
380 
381 size_t UnwindAssemblyInstEmulation::WriteMemory(
382     EmulateInstruction *instruction, const EmulateInstruction::Context &context,
383     lldb::addr_t addr, const void *dst, size_t dst_len) {
384   DataExtractor data(dst, dst_len,
385                      instruction->GetArchitecture().GetByteOrder(),
386                      instruction->GetArchitecture().GetAddressByteSize());
387 
388   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
389 
390   if (log && log->GetVerbose()) {
391     StreamString strm;
392 
393     strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory   (");
394     data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
395     strm.PutCString(", context = ");
396     context.Dump(strm, instruction);
397     log->PutCString(strm.GetData());
398   }
399 
400   const bool cant_replace = false;
401 
402   switch (context.type) {
403   default:
404   case EmulateInstruction::eContextInvalid:
405   case EmulateInstruction::eContextReadOpcode:
406   case EmulateInstruction::eContextImmediate:
407   case EmulateInstruction::eContextAdjustBaseRegister:
408   case EmulateInstruction::eContextRegisterPlusOffset:
409   case EmulateInstruction::eContextAdjustPC:
410   case EmulateInstruction::eContextRegisterStore:
411   case EmulateInstruction::eContextRegisterLoad:
412   case EmulateInstruction::eContextRelativeBranchImmediate:
413   case EmulateInstruction::eContextAbsoluteBranchRegister:
414   case EmulateInstruction::eContextSupervisorCall:
415   case EmulateInstruction::eContextTableBranchReadMemory:
416   case EmulateInstruction::eContextWriteRegisterRandomBits:
417   case EmulateInstruction::eContextWriteMemoryRandomBits:
418   case EmulateInstruction::eContextArithmetic:
419   case EmulateInstruction::eContextAdvancePC:
420   case EmulateInstruction::eContextReturnFromException:
421   case EmulateInstruction::eContextPopRegisterOffStack:
422   case EmulateInstruction::eContextAdjustStackPointer:
423     break;
424 
425   case EmulateInstruction::eContextPushRegisterOnStack: {
426     uint32_t reg_num = LLDB_INVALID_REGNUM;
427     uint32_t generic_regnum = LLDB_INVALID_REGNUM;
428     if (context.info_type ==
429         EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset) {
430       const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
431       reg_num = context.info.RegisterToRegisterPlusOffset.data_reg
432                     .kinds[unwind_reg_kind];
433       generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg
434                            .kinds[eRegisterKindGeneric];
435     } else
436       assert(!"unhandled case, add code to handle this!");
437 
438     if (reg_num != LLDB_INVALID_REGNUM &&
439         generic_regnum != LLDB_REGNUM_GENERIC_SP) {
440       if (m_pushed_regs.find(reg_num) == m_pushed_regs.end()) {
441         m_pushed_regs[reg_num] = addr;
442         const int32_t offset = addr - m_initial_sp;
443         m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,
444                                                          cant_replace);
445         m_curr_row_modified = true;
446       }
447     }
448   } break;
449   }
450 
451   return dst_len;
452 }
453 
454 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,
455                                                void *baton,
456                                                const RegisterInfo *reg_info,
457                                                RegisterValue &reg_value) {
458 
459   if (baton && reg_info)
460     return ((UnwindAssemblyInstEmulation *)baton)
461         ->ReadRegister(instruction, reg_info, reg_value);
462   return false;
463 }
464 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,
465                                                const RegisterInfo *reg_info,
466                                                RegisterValue &reg_value) {
467   bool synthetic = GetRegisterValue(*reg_info, reg_value);
468 
469   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
470 
471   if (log && log->GetVerbose()) {
472 
473     StreamString strm;
474     strm.Printf("UnwindAssemblyInstEmulation::ReadRegister  (name = \"%s\") => "
475                 "synthetic_value = %i, value = ",
476                 reg_info->name, synthetic);
477     reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
478     log->PutCString(strm.GetData());
479   }
480   return true;
481 }
482 
483 bool UnwindAssemblyInstEmulation::WriteRegister(
484     EmulateInstruction *instruction, void *baton,
485     const EmulateInstruction::Context &context, const RegisterInfo *reg_info,
486     const RegisterValue &reg_value) {
487   if (baton && reg_info)
488     return ((UnwindAssemblyInstEmulation *)baton)
489         ->WriteRegister(instruction, context, reg_info, reg_value);
490   return false;
491 }
492 bool UnwindAssemblyInstEmulation::WriteRegister(
493     EmulateInstruction *instruction, const EmulateInstruction::Context &context,
494     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
495   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
496 
497   if (log && log->GetVerbose()) {
498 
499     StreamString strm;
500     strm.Printf(
501         "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ",
502         reg_info->name);
503     reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
504     strm.PutCString(", context = ");
505     context.Dump(strm, instruction);
506     log->PutCString(strm.GetData());
507   }
508 
509   SetRegisterValue(*reg_info, reg_value);
510 
511   switch (context.type) {
512   case EmulateInstruction::eContextInvalid:
513   case EmulateInstruction::eContextReadOpcode:
514   case EmulateInstruction::eContextImmediate:
515   case EmulateInstruction::eContextAdjustBaseRegister:
516   case EmulateInstruction::eContextRegisterPlusOffset:
517   case EmulateInstruction::eContextAdjustPC:
518   case EmulateInstruction::eContextRegisterStore:
519   case EmulateInstruction::eContextSupervisorCall:
520   case EmulateInstruction::eContextTableBranchReadMemory:
521   case EmulateInstruction::eContextWriteRegisterRandomBits:
522   case EmulateInstruction::eContextWriteMemoryRandomBits:
523   case EmulateInstruction::eContextAdvancePC:
524   case EmulateInstruction::eContextReturnFromException:
525   case EmulateInstruction::eContextPushRegisterOnStack:
526   case EmulateInstruction::eContextRegisterLoad:
527     //            {
528     //                const uint32_t reg_num =
529     //                reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
530     //                if (reg_num != LLDB_INVALID_REGNUM)
531     //                {
532     //                    const bool can_replace_only_if_unspecified = true;
533     //
534     //                    m_curr_row.SetRegisterLocationToUndefined (reg_num,
535     //                                                               can_replace_only_if_unspecified,
536     //                                                               can_replace_only_if_unspecified);
537     //                    m_curr_row_modified = true;
538     //                }
539     //            }
540     break;
541 
542   case EmulateInstruction::eContextArithmetic: {
543     // If we adjusted the current frame pointer by a constant then adjust the
544     // CFA offset
545     // with the same amount.
546     lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind();
547     if (m_fp_is_cfa && reg_info->kinds[kind] == m_cfa_reg_info.kinds[kind] &&
548         context.info_type == EmulateInstruction::eInfoTypeRegisterPlusOffset &&
549         context.info.RegisterPlusOffset.reg.kinds[kind] ==
550             m_cfa_reg_info.kinds[kind]) {
551       const int64_t offset = context.info.RegisterPlusOffset.signed_offset;
552       m_curr_row->GetCFAValue().IncOffset(-1 * offset);
553       m_curr_row_modified = true;
554     }
555   } break;
556 
557   case EmulateInstruction::eContextAbsoluteBranchRegister:
558   case EmulateInstruction::eContextRelativeBranchImmediate: {
559     if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediate &&
560         context.info.ISAAndImmediate.unsigned_data32 > 0) {
561       m_forward_branch_offset =
562           context.info.ISAAndImmediateSigned.signed_data32;
563     } else if (context.info_type ==
564                    EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
565                context.info.ISAAndImmediateSigned.signed_data32 > 0) {
566       m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
567     } else if (context.info_type == EmulateInstruction::eInfoTypeImmediate &&
568                context.info.unsigned_immediate > 0) {
569       m_forward_branch_offset = context.info.unsigned_immediate;
570     } else if (context.info_type ==
571                    EmulateInstruction::eInfoTypeImmediateSigned &&
572                context.info.signed_immediate > 0) {
573       m_forward_branch_offset = context.info.signed_immediate;
574     }
575   } break;
576 
577   case EmulateInstruction::eContextPopRegisterOffStack: {
578     const uint32_t reg_num =
579         reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
580     const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];
581     if (reg_num != LLDB_INVALID_REGNUM &&
582         generic_regnum != LLDB_REGNUM_GENERIC_SP) {
583       switch (context.info_type) {
584       case EmulateInstruction::eInfoTypeAddress:
585         if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() &&
586             context.info.address == m_pushed_regs[reg_num]) {
587           m_curr_row->SetRegisterLocationToSame(reg_num,
588                                                 false /*must_replace*/);
589           m_curr_row_modified = true;
590         }
591         break;
592       case EmulateInstruction::eInfoTypeISA:
593         assert(
594             (generic_regnum == LLDB_REGNUM_GENERIC_PC ||
595              generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) &&
596             "eInfoTypeISA used for poping a register other the the PC/FLAGS");
597         if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) {
598           m_curr_row->SetRegisterLocationToSame(reg_num,
599                                                 false /*must_replace*/);
600           m_curr_row_modified = true;
601         }
602         break;
603       default:
604         assert(false && "unhandled case, add code to handle this!");
605         break;
606       }
607     }
608   } break;
609 
610   case EmulateInstruction::eContextSetFramePointer:
611     if (!m_fp_is_cfa) {
612       m_fp_is_cfa = true;
613       m_cfa_reg_info = *reg_info;
614       const uint32_t cfa_reg_num =
615           reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
616       assert(cfa_reg_num != LLDB_INVALID_REGNUM);
617       m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
618           cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
619       m_curr_row_modified = true;
620     }
621     break;
622 
623   case EmulateInstruction::eContextAdjustStackPointer:
624     // If we have created a frame using the frame pointer, don't follow
625     // subsequent adjustments to the stack pointer.
626     if (!m_fp_is_cfa) {
627       m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
628           m_curr_row->GetCFAValue().GetRegisterNumber(),
629           m_initial_sp - reg_value.GetAsUInt64());
630       m_curr_row_modified = true;
631     }
632     break;
633   }
634   return true;
635 }
636