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 "llvm-c/EnhancedDisassembly.h"
13 
14 #include "lldb/Core/Address.h"
15 #include "lldb/Core/ArchSpec.h"
16 #include "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/DataExtractor.h"
18 #include "lldb/Core/Disassembler.h"
19 #include "lldb/Core/Error.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/Thread.h"
26 #include "lldb/Target/Target.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 
32 
33 //-----------------------------------------------------------------------------------------------
34 //  UnwindAssemblyInstEmulation method definitions
35 //-----------------------------------------------------------------------------------------------
36 
37 bool
38 UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& range,
39                                                                    Thread& thread,
40                                                                    UnwindPlan& unwind_plan)
41 {
42     if (range.GetByteSize() > 0 &&
43         range.GetBaseAddress().IsValid() &&
44         m_inst_emulator_ap.get())
45     {
46 
47         // The the instruction emulation subclass setup the unwind plan for the
48         // first instruction.
49         m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan);
50 
51         // CreateFunctionEntryUnwind should have created the first row. If it
52         // doesn't, then we are done.
53         if (unwind_plan.GetRowCount() == 0)
54             return false;
55 
56         ExecutionContext exe_ctx;
57         thread.CalculateExecutionContext(exe_ctx);
58         DisassemblerSP disasm_sp (Disassembler::DisassembleRange (m_arch,
59                                                                   NULL,
60                                                                   exe_ctx,
61                                                                   range));
62 
63         LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
64 
65         if (disasm_sp)
66         {
67 
68             m_range_ptr = ⦥
69             m_thread_ptr = &thread;
70             m_unwind_plan_ptr = &unwind_plan;
71 
72             const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
73             const bool show_address = true;
74             const bool show_bytes = true;
75             m_inst_emulator_ap->GetRegisterInfo (unwind_plan.GetRegisterKind(),
76                                                  unwind_plan.GetInitialCFARegister(),
77                                                  m_cfa_reg_info);
78 
79             m_fp_is_cfa = false;
80             m_register_values.clear();
81             m_pushed_regs.clear();
82 
83             // Initialize the CFA with a known value. In the 32 bit case
84             // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
85             // We use the address byte size to be safe for any future addresss sizes
86             m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
87             RegisterValue cfa_reg_value;
88             cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size);
89             SetRegisterValue (m_cfa_reg_info, cfa_reg_value);
90 
91             const InstructionList &inst_list = disasm_sp->GetInstructionList ();
92             const size_t num_instructions = inst_list.GetSize();
93 
94             if (num_instructions > 0)
95             {
96                 Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
97                 const addr_t base_addr = inst->GetAddress().GetFileAddress();
98 
99                 // Make a copy of the current instruction Row and save it in m_curr_row
100                 // so we can add updates as we process the instructions.
101                 UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
102                 UnwindPlan::Row *newrow = new UnwindPlan::Row;
103                 if (last_row.get())
104                     *newrow = *last_row.get();
105                 m_curr_row.reset(newrow);
106 
107                 // Once we've seen the initial prologue instructions complete, save a
108                 // copy of the CFI at that point into prologue_completed_row for possible
109                 // use later.
110                 int instructions_since_last_prologue_insn = 0;     // # of insns since last CFI was update
111                 bool prologue_complete = false;                    // true if we have finished prologue setup
112                 bool reinstate_prologue_next_instruction = false;  // Next iteration, re-install the prologue row of CFI
113                 UnwindPlan::RowSP prologue_completed_row;          // copy of prologue row of CFI
114 
115                 // cache the pc register number (in whatever register numbering this UnwindPlan uses) for
116                 // quick reference during instruction parsing.
117                 uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
118                 RegisterInfo pc_reg_info;
119                 if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
120                     pc_reg_num = pc_reg_info.kinds[unwind_plan.GetRegisterKind()];
121 
122 
123                 for (size_t idx=0; idx<num_instructions; ++idx)
124                 {
125                     m_curr_row_modified = false;
126                     inst = inst_list.GetInstructionAtIndex (idx).get();
127                     if (inst)
128                     {
129                         if (log && log->GetVerbose ())
130                         {
131                             StreamString strm;
132                             inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL);
133                             log->PutCString (strm.GetData());
134                         }
135 
136                         m_inst_emulator_ap->SetInstruction (inst->GetOpcode(),
137                                                             inst->GetAddress(),
138                                                             exe_ctx.GetTargetPtr());
139 
140                         m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
141 
142                         // Were there any changes to the CFI while evaluating this instruction?
143                         if (m_curr_row_modified)
144                         {
145                             reinstate_prologue_next_instruction = false;
146                             m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
147                             // Append the new row
148                             unwind_plan.AppendRow (m_curr_row);
149 
150                             // Allocate a new Row for m_curr_row, copy the current state into it
151                             UnwindPlan::Row *newrow = new UnwindPlan::Row;
152                             *newrow = *m_curr_row.get();
153                             m_curr_row.reset(newrow);
154 
155                             instructions_since_last_prologue_insn = 0;
156 
157                             // If the caller's pc is "same", we've just executed an epilogue and we return to the caller
158                             // after this instruction completes executing.
159                             // If there are any instructions past this, there must have been flow control over this
160                             // epilogue so we'll reinstate the original prologue setup instructions.
161                             UnwindPlan::Row::RegisterLocation pc_regloc;
162                             if (prologue_complete
163                                 && pc_reg_num != LLDB_INVALID_REGNUM
164                                 && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
165                                 && pc_regloc.IsSame())
166                             {
167                                 if (log && log->GetVerbose())
168                                     log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
169                                 reinstate_prologue_next_instruction = true;
170                             }
171                         }
172                         else
173                         {
174                             // If the previous instruction was a return-to-caller (epilogue), and we're still executing
175                             // instructions in this function, there must be a code path that jumps over that epilogue.
176                             // Reinstate the frame setup from the prologue.
177                             if (reinstate_prologue_next_instruction)
178                             {
179                                 if (log && log->GetVerbose())
180                                     log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
181                                 UnwindPlan::Row *newrow = new UnwindPlan::Row;
182                                 *newrow = *prologue_completed_row.get();
183                                 m_curr_row.reset(newrow);
184                                 m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
185                                 unwind_plan.AppendRow(m_curr_row);
186 
187                                 newrow = new UnwindPlan::Row;
188                                 *newrow = *m_curr_row.get();
189                                 m_curr_row.reset(newrow);
190 
191                                 reinstate_prologue_next_instruction = false;
192                             }
193 
194                             // If we haven't seen any prologue instructions for a while (4 instructions in a row),
195                             // the function prologue has probably completed.  Save a copy of that Row.
196                             if (prologue_complete == false && instructions_since_last_prologue_insn++ > 3)
197                             {
198                                 prologue_complete = true;
199                                 UnwindPlan::Row *newrow = new UnwindPlan::Row;
200                                 *newrow = *m_curr_row.get();
201                                 prologue_completed_row.reset(newrow);
202                                 if (log && log->GetVerbose())
203                                     log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- prologue has been set up, saving a copy.");
204                             }
205                         }
206                     }
207                 }
208             }
209         }
210 
211         if (log && log->GetVerbose ())
212         {
213             StreamString strm;
214             lldb::addr_t base_addr = range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get());
215             strm.Printf ("Resulting unwind rows for [0x%llx - 0x%llx):", base_addr, base_addr + range.GetByteSize());
216             unwind_plan.Dump(strm, &thread, base_addr);
217             log->PutCString (strm.GetData());
218         }
219         return unwind_plan.GetRowCount() > 0;
220     }
221     return false;
222 }
223 
224 bool
225 UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func,
226                                                 Thread& thread,
227                                                 UnwindPlan &unwind_plan)
228 {
229     return false;
230 }
231 
232 bool
233 UnwindAssemblyInstEmulation::FirstNonPrologueInsn (AddressRange& func,
234                                                    const ExecutionContext &exe_ctx,
235                                                    Address& first_non_prologue_insn)
236 {
237     return false;
238 }
239 
240 UnwindAssembly *
241 UnwindAssemblyInstEmulation::CreateInstance (const ArchSpec &arch)
242 {
243     std::auto_ptr<EmulateInstruction> inst_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypePrologueEpilogue, NULL));
244     // Make sure that all prologue instructions are handled
245     if (inst_emulator_ap.get())
246         return new UnwindAssemblyInstEmulation (arch, inst_emulator_ap.release());
247     return NULL;
248 }
249 
250 
251 //------------------------------------------------------------------
252 // PluginInterface protocol in UnwindAssemblyParser_x86
253 //------------------------------------------------------------------
254 
255 const char *
256 UnwindAssemblyInstEmulation::GetPluginName()
257 {
258     return "UnwindAssemblyInstEmulation";
259 }
260 
261 const char *
262 UnwindAssemblyInstEmulation::GetShortPluginName()
263 {
264     return "unwindassembly.inst-emulation";
265 }
266 
267 
268 uint32_t
269 UnwindAssemblyInstEmulation::GetPluginVersion()
270 {
271     return 1;
272 }
273 
274 void
275 UnwindAssemblyInstEmulation::Initialize()
276 {
277     PluginManager::RegisterPlugin (GetPluginNameStatic(),
278                                    GetPluginDescriptionStatic(),
279                                    CreateInstance);
280 }
281 
282 void
283 UnwindAssemblyInstEmulation::Terminate()
284 {
285     PluginManager::UnregisterPlugin (CreateInstance);
286 }
287 
288 
289 const char *
290 UnwindAssemblyInstEmulation::GetPluginNameStatic()
291 {
292     return "UnwindAssemblyInstEmulation";
293 }
294 
295 const char *
296 UnwindAssemblyInstEmulation::GetPluginDescriptionStatic()
297 {
298     return "Instruction emulation based unwind information.";
299 }
300 
301 
302 uint64_t
303 UnwindAssemblyInstEmulation::MakeRegisterKindValuePair (const RegisterInfo &reg_info)
304 {
305     uint32_t reg_kind, reg_num;
306     if (EmulateInstruction::GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
307         return (uint64_t)reg_kind << 24 | reg_num;
308     return 0ull;
309 }
310 
311 void
312 UnwindAssemblyInstEmulation::SetRegisterValue (const RegisterInfo &reg_info, const RegisterValue &reg_value)
313 {
314     m_register_values[MakeRegisterKindValuePair (reg_info)] = reg_value;
315 }
316 
317 bool
318 UnwindAssemblyInstEmulation::GetRegisterValue (const RegisterInfo &reg_info, RegisterValue &reg_value)
319 {
320     const uint64_t reg_id = MakeRegisterKindValuePair (reg_info);
321     RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
322     if (pos != m_register_values.end())
323     {
324         reg_value = pos->second;
325         return true; // We had a real value that comes from an opcode that wrote
326                      // to it...
327     }
328     // We are making up a value that is recognizable...
329     reg_value.SetUInt(reg_id, reg_info.byte_size);
330     return false;
331 }
332 
333 
334 size_t
335 UnwindAssemblyInstEmulation::ReadMemory (EmulateInstruction *instruction,
336                                          void *baton,
337                                          const EmulateInstruction::Context &context,
338                                          lldb::addr_t addr,
339                                          void *dst,
340                                          size_t dst_len)
341 {
342     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
343 
344     if (log && log->GetVerbose ())
345     {
346         StreamString strm;
347         strm.Printf ("UnwindAssemblyInstEmulation::ReadMemory    (addr = 0x%16.16llx, dst = %p, dst_len = %llu, context = ",
348                      addr,
349                      dst,
350                      (uint64_t)dst_len);
351         context.Dump(strm, instruction);
352         log->PutCString (strm.GetData ());
353     }
354     memset (dst, 0, dst_len);
355     return dst_len;
356 }
357 
358 size_t
359 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
360                                           void *baton,
361                                           const EmulateInstruction::Context &context,
362                                           lldb::addr_t addr,
363                                           const void *dst,
364                                           size_t dst_len)
365 {
366     if (baton && dst && dst_len)
367         return ((UnwindAssemblyInstEmulation *)baton)->WriteMemory (instruction, context, addr, dst, dst_len);
368     return 0;
369 }
370 
371 size_t
372 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
373                                           const EmulateInstruction::Context &context,
374                                           lldb::addr_t addr,
375                                           const void *dst,
376                                           size_t dst_len)
377 {
378     DataExtractor data (dst,
379                         dst_len,
380                         instruction->GetArchitecture ().GetByteOrder(),
381                         instruction->GetArchitecture ().GetAddressByteSize());
382 
383     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
384 
385     if (log && log->GetVerbose ())
386     {
387         StreamString strm;
388 
389         strm.PutCString ("UnwindAssemblyInstEmulation::WriteMemory   (");
390         data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
391         strm.PutCString (", context = ");
392         context.Dump(strm, instruction);
393         log->PutCString (strm.GetData());
394     }
395 
396     const bool can_replace = true;
397     const bool cant_replace = false;
398 
399     switch (context.type)
400     {
401         default:
402         case EmulateInstruction::eContextInvalid:
403         case EmulateInstruction::eContextReadOpcode:
404         case EmulateInstruction::eContextImmediate:
405         case EmulateInstruction::eContextAdjustBaseRegister:
406         case EmulateInstruction::eContextRegisterPlusOffset:
407         case EmulateInstruction::eContextAdjustPC:
408         case EmulateInstruction::eContextRegisterStore:
409         case EmulateInstruction::eContextRegisterLoad:
410         case EmulateInstruction::eContextRelativeBranchImmediate:
411         case EmulateInstruction::eContextAbsoluteBranchRegister:
412         case EmulateInstruction::eContextSupervisorCall:
413         case EmulateInstruction::eContextTableBranchReadMemory:
414         case EmulateInstruction::eContextWriteRegisterRandomBits:
415         case EmulateInstruction::eContextWriteMemoryRandomBits:
416         case EmulateInstruction::eContextArithmetic:
417         case EmulateInstruction::eContextAdvancePC:
418         case EmulateInstruction::eContextReturnFromException:
419         case EmulateInstruction::eContextPopRegisterOffStack:
420         case EmulateInstruction::eContextAdjustStackPointer:
421             break;
422 
423         case EmulateInstruction::eContextPushRegisterOnStack:
424             {
425                 uint32_t reg_num = LLDB_INVALID_REGNUM;
426                 bool is_return_address_reg = false;
427                 const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
428                 if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
429                 {
430                     reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
431                     if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
432                         is_return_address_reg = true;
433                 }
434                 else
435                 {
436                     assert (!"unhandled case, add code to handle this!");
437                 }
438 
439                 if (reg_num != LLDB_INVALID_REGNUM)
440                 {
441                     if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
442                     {
443                         m_pushed_regs[reg_num] = addr;
444                         const int32_t offset = addr - m_initial_sp;
445                         m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
446                         m_curr_row_modified = true;
447                         if (is_return_address_reg)
448                         {
449                             // This push was pushing the return address register,
450                             // so this is also how we will unwind the PC...
451                             RegisterInfo pc_reg_info;
452                             if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
453                             {
454                                 uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
455                                 if (pc_reg_num != LLDB_INVALID_REGNUM)
456                                 {
457                                     m_curr_row->SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
458                                     m_curr_row_modified = true;
459                                 }
460                             }
461                         }
462                     }
463                 }
464             }
465             break;
466 
467     }
468 
469     return dst_len;
470 }
471 
472 bool
473 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
474                                            void *baton,
475                                            const RegisterInfo *reg_info,
476                                            RegisterValue &reg_value)
477 {
478 
479     if (baton && reg_info)
480         return ((UnwindAssemblyInstEmulation *)baton)->ReadRegister (instruction, reg_info, reg_value);
481     return false;
482 }
483 bool
484 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
485                                            const RegisterInfo *reg_info,
486                                            RegisterValue &reg_value)
487 {
488     bool synthetic = GetRegisterValue (*reg_info, reg_value);
489 
490     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
491 
492     if (log && log->GetVerbose ())
493     {
494 
495         StreamString strm;
496         strm.Printf ("UnwindAssemblyInstEmulation::ReadRegister  (name = \"%s\") => synthetic_value = %i, value = ", reg_info->name, synthetic);
497         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
498         log->PutCString(strm.GetData());
499     }
500     return true;
501 }
502 
503 bool
504 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
505                                             void *baton,
506                                             const EmulateInstruction::Context &context,
507                                             const RegisterInfo *reg_info,
508                                             const RegisterValue &reg_value)
509 {
510     if (baton && reg_info)
511         return ((UnwindAssemblyInstEmulation *)baton)->WriteRegister (instruction, context, reg_info, reg_value);
512     return false;
513 }
514 bool
515 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
516                                             const EmulateInstruction::Context &context,
517                                             const RegisterInfo *reg_info,
518                                             const RegisterValue &reg_value)
519 {
520     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
521 
522     if (log && log->GetVerbose ())
523     {
524 
525         StreamString strm;
526         strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name);
527         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
528         strm.PutCString (", context = ");
529         context.Dump(strm, instruction);
530         log->PutCString(strm.GetData());
531     }
532 
533     const bool must_replace = true;
534     SetRegisterValue (*reg_info, reg_value);
535 
536     switch (context.type)
537     {
538         default:
539         case EmulateInstruction::eContextInvalid:
540         case EmulateInstruction::eContextReadOpcode:
541         case EmulateInstruction::eContextImmediate:
542         case EmulateInstruction::eContextAdjustBaseRegister:
543         case EmulateInstruction::eContextRegisterPlusOffset:
544         case EmulateInstruction::eContextAdjustPC:
545         case EmulateInstruction::eContextRegisterStore:
546         case EmulateInstruction::eContextRegisterLoad:
547         case EmulateInstruction::eContextRelativeBranchImmediate:
548         case EmulateInstruction::eContextAbsoluteBranchRegister:
549         case EmulateInstruction::eContextSupervisorCall:
550         case EmulateInstruction::eContextTableBranchReadMemory:
551         case EmulateInstruction::eContextWriteRegisterRandomBits:
552         case EmulateInstruction::eContextWriteMemoryRandomBits:
553         case EmulateInstruction::eContextArithmetic:
554         case EmulateInstruction::eContextAdvancePC:
555         case EmulateInstruction::eContextReturnFromException:
556         case EmulateInstruction::eContextPushRegisterOnStack:
557 //            {
558 //                const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
559 //                if (reg_num != LLDB_INVALID_REGNUM)
560 //                {
561 //                    const bool can_replace_only_if_unspecified = true;
562 //
563 //                    m_curr_row.SetRegisterLocationToUndefined (reg_num,
564 //                                                               can_replace_only_if_unspecified,
565 //                                                               can_replace_only_if_unspecified);
566 //                    m_curr_row_modified = true;
567 //                }
568 //            }
569             break;
570 
571         case EmulateInstruction::eContextPopRegisterOffStack:
572             {
573                 const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
574                 if (reg_num != LLDB_INVALID_REGNUM)
575                 {
576                     m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
577                     m_curr_row_modified = true;
578                 }
579             }
580             break;
581 
582         case EmulateInstruction::eContextSetFramePointer:
583             if (!m_fp_is_cfa)
584             {
585                 m_fp_is_cfa = true;
586                 m_cfa_reg_info = *reg_info;
587                 const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
588                 assert (cfa_reg_num != LLDB_INVALID_REGNUM);
589                 m_curr_row->SetCFARegister(cfa_reg_num);
590                 m_curr_row->SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
591                 m_curr_row_modified = true;
592             }
593             break;
594 
595         case EmulateInstruction::eContextAdjustStackPointer:
596             // If we have created a frame using the frame pointer, don't follow
597             // subsequent adjustments to the stack pointer.
598             if (!m_fp_is_cfa)
599             {
600                 m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
601                 m_curr_row_modified = true;
602             }
603             break;
604     }
605     return true;
606 }
607 
608 
609