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