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