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         }
233 
234         if (log && log->GetVerbose ())
235         {
236             StreamString strm;
237             lldb::addr_t base_addr = range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get());
238             strm.Printf ("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):", base_addr, base_addr + range.GetByteSize());
239             unwind_plan.Dump(strm, &thread, base_addr);
240             log->PutCString (strm.GetData());
241         }
242         return unwind_plan.GetRowCount() > 0;
243     }
244     return false;
245 }
246 
247 bool
248 UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite (AddressRange& func,
249                                                             Thread& thread,
250                                                             UnwindPlan& unwind_plan)
251 {
252     return false;
253 }
254 
255 bool
256 UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func,
257                                                 Thread& thread,
258                                                 UnwindPlan &unwind_plan)
259 {
260     return false;
261 }
262 
263 bool
264 UnwindAssemblyInstEmulation::FirstNonPrologueInsn (AddressRange& func,
265                                                    const ExecutionContext &exe_ctx,
266                                                    Address& first_non_prologue_insn)
267 {
268     return false;
269 }
270 
271 UnwindAssembly *
272 UnwindAssemblyInstEmulation::CreateInstance (const ArchSpec &arch)
273 {
274     std::unique_ptr<EmulateInstruction> inst_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypePrologueEpilogue, NULL));
275     // Make sure that all prologue instructions are handled
276     if (inst_emulator_ap.get())
277         return new UnwindAssemblyInstEmulation (arch, inst_emulator_ap.release());
278     return NULL;
279 }
280 
281 
282 //------------------------------------------------------------------
283 // PluginInterface protocol in UnwindAssemblyParser_x86
284 //------------------------------------------------------------------
285 ConstString
286 UnwindAssemblyInstEmulation::GetPluginName()
287 {
288     return GetPluginNameStatic();
289 }
290 
291 uint32_t
292 UnwindAssemblyInstEmulation::GetPluginVersion()
293 {
294     return 1;
295 }
296 
297 void
298 UnwindAssemblyInstEmulation::Initialize()
299 {
300     PluginManager::RegisterPlugin (GetPluginNameStatic(),
301                                    GetPluginDescriptionStatic(),
302                                    CreateInstance);
303 }
304 
305 void
306 UnwindAssemblyInstEmulation::Terminate()
307 {
308     PluginManager::UnregisterPlugin (CreateInstance);
309 }
310 
311 
312 ConstString
313 UnwindAssemblyInstEmulation::GetPluginNameStatic()
314 {
315     static ConstString g_name("inst-emulation");
316     return g_name;
317 }
318 
319 const char *
320 UnwindAssemblyInstEmulation::GetPluginDescriptionStatic()
321 {
322     return "Instruction emulation based unwind information.";
323 }
324 
325 
326 uint64_t
327 UnwindAssemblyInstEmulation::MakeRegisterKindValuePair (const RegisterInfo &reg_info)
328 {
329     lldb::RegisterKind reg_kind;
330     uint32_t reg_num;
331     if (EmulateInstruction::GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
332         return (uint64_t)reg_kind << 24 | reg_num;
333     return 0ull;
334 }
335 
336 void
337 UnwindAssemblyInstEmulation::SetRegisterValue (const RegisterInfo &reg_info, const RegisterValue &reg_value)
338 {
339     m_register_values[MakeRegisterKindValuePair (reg_info)] = reg_value;
340 }
341 
342 bool
343 UnwindAssemblyInstEmulation::GetRegisterValue (const RegisterInfo &reg_info, RegisterValue &reg_value)
344 {
345     const uint64_t reg_id = MakeRegisterKindValuePair (reg_info);
346     RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
347     if (pos != m_register_values.end())
348     {
349         reg_value = pos->second;
350         return true; // We had a real value that comes from an opcode that wrote
351                      // to it...
352     }
353     // We are making up a value that is recognizable...
354     reg_value.SetUInt(reg_id, reg_info.byte_size);
355     return false;
356 }
357 
358 
359 size_t
360 UnwindAssemblyInstEmulation::ReadMemory (EmulateInstruction *instruction,
361                                          void *baton,
362                                          const EmulateInstruction::Context &context,
363                                          lldb::addr_t addr,
364                                          void *dst,
365                                          size_t dst_len)
366 {
367     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
368 
369     if (log && log->GetVerbose ())
370     {
371         StreamString strm;
372         strm.Printf ("UnwindAssemblyInstEmulation::ReadMemory    (addr = 0x%16.16" PRIx64 ", dst = %p, dst_len = %" PRIu64 ", context = ",
373                      addr,
374                      dst,
375                      (uint64_t)dst_len);
376         context.Dump(strm, instruction);
377         log->PutCString (strm.GetData ());
378     }
379     memset (dst, 0, dst_len);
380     return dst_len;
381 }
382 
383 size_t
384 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
385                                           void *baton,
386                                           const EmulateInstruction::Context &context,
387                                           lldb::addr_t addr,
388                                           const void *dst,
389                                           size_t dst_len)
390 {
391     if (baton && dst && dst_len)
392         return ((UnwindAssemblyInstEmulation *)baton)->WriteMemory (instruction, context, addr, dst, dst_len);
393     return 0;
394 }
395 
396 size_t
397 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
398                                           const EmulateInstruction::Context &context,
399                                           lldb::addr_t addr,
400                                           const void *dst,
401                                           size_t dst_len)
402 {
403     DataExtractor data (dst,
404                         dst_len,
405                         instruction->GetArchitecture ().GetByteOrder(),
406                         instruction->GetArchitecture ().GetAddressByteSize());
407 
408     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
409 
410     if (log && log->GetVerbose ())
411     {
412         StreamString strm;
413 
414         strm.PutCString ("UnwindAssemblyInstEmulation::WriteMemory   (");
415         data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
416         strm.PutCString (", context = ");
417         context.Dump(strm, instruction);
418         log->PutCString (strm.GetData());
419     }
420 
421     const bool cant_replace = false;
422 
423     switch (context.type)
424     {
425         default:
426         case EmulateInstruction::eContextInvalid:
427         case EmulateInstruction::eContextReadOpcode:
428         case EmulateInstruction::eContextImmediate:
429         case EmulateInstruction::eContextAdjustBaseRegister:
430         case EmulateInstruction::eContextRegisterPlusOffset:
431         case EmulateInstruction::eContextAdjustPC:
432         case EmulateInstruction::eContextRegisterStore:
433         case EmulateInstruction::eContextRegisterLoad:
434         case EmulateInstruction::eContextRelativeBranchImmediate:
435         case EmulateInstruction::eContextAbsoluteBranchRegister:
436         case EmulateInstruction::eContextSupervisorCall:
437         case EmulateInstruction::eContextTableBranchReadMemory:
438         case EmulateInstruction::eContextWriteRegisterRandomBits:
439         case EmulateInstruction::eContextWriteMemoryRandomBits:
440         case EmulateInstruction::eContextArithmetic:
441         case EmulateInstruction::eContextAdvancePC:
442         case EmulateInstruction::eContextReturnFromException:
443         case EmulateInstruction::eContextPopRegisterOffStack:
444         case EmulateInstruction::eContextAdjustStackPointer:
445             break;
446 
447         case EmulateInstruction::eContextPushRegisterOnStack:
448             {
449                 uint32_t reg_num = LLDB_INVALID_REGNUM;
450                 uint32_t generic_regnum = LLDB_INVALID_REGNUM;
451                 if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
452                 {
453                     const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
454                     reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
455                     generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric];
456                 }
457                 else
458                     assert (!"unhandled case, add code to handle this!");
459 
460                 if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP)
461                 {
462                     if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
463                     {
464                         m_pushed_regs[reg_num] = addr;
465                         const int32_t offset = addr - m_initial_sp;
466                         m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
467                         m_curr_row_modified = true;
468                     }
469                 }
470             }
471             break;
472 
473     }
474 
475     return dst_len;
476 }
477 
478 bool
479 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
480                                            void *baton,
481                                            const RegisterInfo *reg_info,
482                                            RegisterValue &reg_value)
483 {
484 
485     if (baton && reg_info)
486         return ((UnwindAssemblyInstEmulation *)baton)->ReadRegister (instruction, reg_info, reg_value);
487     return false;
488 }
489 bool
490 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
491                                            const RegisterInfo *reg_info,
492                                            RegisterValue &reg_value)
493 {
494     bool synthetic = GetRegisterValue (*reg_info, reg_value);
495 
496     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
497 
498     if (log && log->GetVerbose ())
499     {
500 
501         StreamString strm;
502         strm.Printf ("UnwindAssemblyInstEmulation::ReadRegister  (name = \"%s\") => synthetic_value = %i, value = ", reg_info->name, synthetic);
503         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
504         log->PutCString(strm.GetData());
505     }
506     return true;
507 }
508 
509 bool
510 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
511                                             void *baton,
512                                             const EmulateInstruction::Context &context,
513                                             const RegisterInfo *reg_info,
514                                             const RegisterValue &reg_value)
515 {
516     if (baton && reg_info)
517         return ((UnwindAssemblyInstEmulation *)baton)->WriteRegister (instruction, context, reg_info, reg_value);
518     return false;
519 }
520 bool
521 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
522                                             const EmulateInstruction::Context &context,
523                                             const RegisterInfo *reg_info,
524                                             const RegisterValue &reg_value)
525 {
526     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
527 
528     if (log && log->GetVerbose ())
529     {
530 
531         StreamString strm;
532         strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name);
533         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
534         strm.PutCString (", context = ");
535         context.Dump(strm, instruction);
536         log->PutCString(strm.GetData());
537     }
538 
539     SetRegisterValue (*reg_info, reg_value);
540 
541     switch (context.type)
542     {
543         case EmulateInstruction::eContextInvalid:
544         case EmulateInstruction::eContextReadOpcode:
545         case EmulateInstruction::eContextImmediate:
546         case EmulateInstruction::eContextAdjustBaseRegister:
547         case EmulateInstruction::eContextRegisterPlusOffset:
548         case EmulateInstruction::eContextAdjustPC:
549         case EmulateInstruction::eContextRegisterStore:
550         case EmulateInstruction::eContextSupervisorCall:
551         case EmulateInstruction::eContextTableBranchReadMemory:
552         case EmulateInstruction::eContextWriteRegisterRandomBits:
553         case EmulateInstruction::eContextWriteMemoryRandomBits:
554         case EmulateInstruction::eContextAdvancePC:
555         case EmulateInstruction::eContextReturnFromException:
556         case EmulateInstruction::eContextPushRegisterOnStack:
557         case EmulateInstruction::eContextRegisterLoad:
558 //            {
559 //                const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
560 //                if (reg_num != LLDB_INVALID_REGNUM)
561 //                {
562 //                    const bool can_replace_only_if_unspecified = true;
563 //
564 //                    m_curr_row.SetRegisterLocationToUndefined (reg_num,
565 //                                                               can_replace_only_if_unspecified,
566 //                                                               can_replace_only_if_unspecified);
567 //                    m_curr_row_modified = true;
568 //                }
569 //            }
570             break;
571 
572         case EmulateInstruction::eContextArithmetic:
573             {
574                 // If we adjusted the current frame pointer by a constant then adjust the CFA offset
575                 // with the same amount.
576                 lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind();
577                 if (m_fp_is_cfa && reg_info->kinds[kind] == m_cfa_reg_info.kinds[kind] &&
578                     context.info_type == EmulateInstruction::eInfoTypeRegisterPlusOffset &&
579                     context.info.RegisterPlusOffset.reg.kinds[kind] == m_cfa_reg_info.kinds[kind])
580                 {
581                     const int64_t offset = context.info.RegisterPlusOffset.signed_offset;
582                     m_curr_row->GetCFAValue().IncOffset(-1 * offset);
583                     m_curr_row_modified = true;
584                 }
585             }
586             break;
587 
588         case EmulateInstruction::eContextAbsoluteBranchRegister:
589         case EmulateInstruction::eContextRelativeBranchImmediate:
590             {
591                 if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediate &&
592                     context.info.ISAAndImmediate.unsigned_data32 > 0)
593                 {
594                     m_forward_branch_offset = context.info.ISAAndImmediateSigned.signed_data32;
595                 }
596                 else if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
597                          context.info.ISAAndImmediateSigned.signed_data32 > 0)
598                 {
599                     m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
600                 }
601                 else if (context.info_type == EmulateInstruction::eInfoTypeImmediate &&
602                          context.info.unsigned_immediate > 0)
603                 {
604                     m_forward_branch_offset = context.info.unsigned_immediate;
605                 }
606                 else if (context.info_type == EmulateInstruction::eInfoTypeImmediateSigned &&
607                          context.info.signed_immediate > 0)
608                 {
609                     m_forward_branch_offset = context.info.signed_immediate;
610                 }
611             }
612             break;
613 
614         case EmulateInstruction::eContextPopRegisterOffStack:
615             {
616                 const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
617                 const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];
618                 if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP)
619                 {
620                     switch (context.info_type)
621                     {
622                         case EmulateInstruction::eInfoTypeAddress:
623                             if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() &&
624                                 context.info.address == m_pushed_regs[reg_num])
625                             {
626                                 m_curr_row->SetRegisterLocationToSame(reg_num,
627                                                                       false /*must_replace*/);
628                                 m_curr_row_modified = true;
629                             }
630                             break;
631                         case EmulateInstruction::eInfoTypeISA:
632                             assert((generic_regnum == LLDB_REGNUM_GENERIC_PC ||
633                                     generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) &&
634                                    "eInfoTypeISA used for poping a register other the the PC/FLAGS");
635                             if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS)
636                             {
637                                 m_curr_row->SetRegisterLocationToSame(reg_num,
638                                                                       false /*must_replace*/);
639                                 m_curr_row_modified = true;
640                             }
641                             break;
642                         default:
643                             assert(false && "unhandled case, add code to handle this!");
644                             break;
645                     }
646                 }
647             }
648             break;
649 
650         case EmulateInstruction::eContextSetFramePointer:
651             if (!m_fp_is_cfa)
652             {
653                 m_fp_is_cfa = true;
654                 m_cfa_reg_info = *reg_info;
655                 const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
656                 assert (cfa_reg_num != LLDB_INVALID_REGNUM);
657                 m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(cfa_reg_num, m_initial_sp -
658                         reg_value.GetAsUInt64());
659                 m_curr_row_modified = true;
660             }
661             break;
662 
663         case EmulateInstruction::eContextAdjustStackPointer:
664             // If we have created a frame using the frame pointer, don't follow
665             // subsequent adjustments to the stack pointer.
666             if (!m_fp_is_cfa)
667             {
668                 m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
669                         m_curr_row->GetCFAValue().GetRegisterNumber(),
670                         m_initial_sp - reg_value.GetAsUInt64());
671                 m_curr_row_modified = true;
672             }
673             break;
674     }
675     return true;
676 }
677 
678 
679