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     return dst_len;
354 }
355 
356 size_t
357 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
358                                           void *baton,
359                                           const EmulateInstruction::Context &context,
360                                           lldb::addr_t addr,
361                                           const void *dst,
362                                           size_t dst_len)
363 {
364     if (baton && dst && dst_len)
365         return ((UnwindAssemblyInstEmulation *)baton)->WriteMemory (instruction, context, addr, dst, dst_len);
366     return 0;
367 }
368 
369 size_t
370 UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
371                                           const EmulateInstruction::Context &context,
372                                           lldb::addr_t addr,
373                                           const void *dst,
374                                           size_t dst_len)
375 {
376     DataExtractor data (dst,
377                         dst_len,
378                         instruction->GetArchitecture ().GetByteOrder(),
379                         instruction->GetArchitecture ().GetAddressByteSize());
380 
381     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
382 
383     if (log && log->GetVerbose ())
384     {
385         StreamString strm;
386 
387         strm.PutCString ("UnwindAssemblyInstEmulation::WriteMemory   (");
388         data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
389         strm.PutCString (", context = ");
390         context.Dump(strm, instruction);
391         log->PutCString (strm.GetData());
392     }
393 
394     const bool can_replace = true;
395     const bool cant_replace = false;
396 
397     switch (context.type)
398     {
399         default:
400         case EmulateInstruction::eContextInvalid:
401         case EmulateInstruction::eContextReadOpcode:
402         case EmulateInstruction::eContextImmediate:
403         case EmulateInstruction::eContextAdjustBaseRegister:
404         case EmulateInstruction::eContextRegisterPlusOffset:
405         case EmulateInstruction::eContextAdjustPC:
406         case EmulateInstruction::eContextRegisterStore:
407         case EmulateInstruction::eContextRegisterLoad:
408         case EmulateInstruction::eContextRelativeBranchImmediate:
409         case EmulateInstruction::eContextAbsoluteBranchRegister:
410         case EmulateInstruction::eContextSupervisorCall:
411         case EmulateInstruction::eContextTableBranchReadMemory:
412         case EmulateInstruction::eContextWriteRegisterRandomBits:
413         case EmulateInstruction::eContextWriteMemoryRandomBits:
414         case EmulateInstruction::eContextArithmetic:
415         case EmulateInstruction::eContextAdvancePC:
416         case EmulateInstruction::eContextReturnFromException:
417         case EmulateInstruction::eContextPopRegisterOffStack:
418         case EmulateInstruction::eContextAdjustStackPointer:
419             break;
420 
421         case EmulateInstruction::eContextPushRegisterOnStack:
422             {
423                 uint32_t reg_num = LLDB_INVALID_REGNUM;
424                 bool is_return_address_reg = false;
425                 const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
426                 if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
427                 {
428                     reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
429                     if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
430                         is_return_address_reg = true;
431                 }
432                 else
433                 {
434                     assert (!"unhandled case, add code to handle this!");
435                 }
436 
437                 if (reg_num != LLDB_INVALID_REGNUM)
438                 {
439                     if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
440                     {
441                         m_pushed_regs[reg_num] = addr;
442                         const int32_t offset = addr - m_initial_sp;
443                         m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
444                         m_curr_row_modified = true;
445                         if (is_return_address_reg)
446                         {
447                             // This push was pushing the return address register,
448                             // so this is also how we will unwind the PC...
449                             RegisterInfo pc_reg_info;
450                             if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
451                             {
452                                 uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
453                                 if (pc_reg_num != LLDB_INVALID_REGNUM)
454                                 {
455                                     m_curr_row->SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
456                                     m_curr_row_modified = true;
457                                 }
458                             }
459                         }
460                     }
461                 }
462             }
463             break;
464 
465     }
466 
467     return dst_len;
468 }
469 
470 bool
471 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
472                                            void *baton,
473                                            const RegisterInfo *reg_info,
474                                            RegisterValue &reg_value)
475 {
476 
477     if (baton && reg_info)
478         return ((UnwindAssemblyInstEmulation *)baton)->ReadRegister (instruction, reg_info, reg_value);
479     return false;
480 }
481 bool
482 UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
483                                            const RegisterInfo *reg_info,
484                                            RegisterValue &reg_value)
485 {
486     bool synthetic = GetRegisterValue (*reg_info, reg_value);
487 
488     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
489 
490     if (log && log->GetVerbose ())
491     {
492 
493         StreamString strm;
494         strm.Printf ("UnwindAssemblyInstEmulation::ReadRegister  (name = \"%s\") => synthetic_value = %i, value = ", reg_info->name, synthetic);
495         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
496         log->PutCString(strm.GetData());
497     }
498     return true;
499 }
500 
501 bool
502 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
503                                             void *baton,
504                                             const EmulateInstruction::Context &context,
505                                             const RegisterInfo *reg_info,
506                                             const RegisterValue &reg_value)
507 {
508     if (baton && reg_info)
509         return ((UnwindAssemblyInstEmulation *)baton)->WriteRegister (instruction, context, reg_info, reg_value);
510     return false;
511 }
512 bool
513 UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
514                                             const EmulateInstruction::Context &context,
515                                             const RegisterInfo *reg_info,
516                                             const RegisterValue &reg_value)
517 {
518     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
519 
520     if (log && log->GetVerbose ())
521     {
522 
523         StreamString strm;
524         strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name);
525         reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
526         strm.PutCString (", context = ");
527         context.Dump(strm, instruction);
528         log->PutCString(strm.GetData());
529     }
530 
531     const bool must_replace = true;
532     SetRegisterValue (*reg_info, reg_value);
533 
534     switch (context.type)
535     {
536         default:
537         case EmulateInstruction::eContextInvalid:
538         case EmulateInstruction::eContextReadOpcode:
539         case EmulateInstruction::eContextImmediate:
540         case EmulateInstruction::eContextAdjustBaseRegister:
541         case EmulateInstruction::eContextRegisterPlusOffset:
542         case EmulateInstruction::eContextAdjustPC:
543         case EmulateInstruction::eContextRegisterStore:
544         case EmulateInstruction::eContextRegisterLoad:
545         case EmulateInstruction::eContextRelativeBranchImmediate:
546         case EmulateInstruction::eContextAbsoluteBranchRegister:
547         case EmulateInstruction::eContextSupervisorCall:
548         case EmulateInstruction::eContextTableBranchReadMemory:
549         case EmulateInstruction::eContextWriteRegisterRandomBits:
550         case EmulateInstruction::eContextWriteMemoryRandomBits:
551         case EmulateInstruction::eContextArithmetic:
552         case EmulateInstruction::eContextAdvancePC:
553         case EmulateInstruction::eContextReturnFromException:
554         case EmulateInstruction::eContextPushRegisterOnStack:
555 //            {
556 //                const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
557 //                if (reg_num != LLDB_INVALID_REGNUM)
558 //                {
559 //                    const bool can_replace_only_if_unspecified = true;
560 //
561 //                    m_curr_row.SetRegisterLocationToUndefined (reg_num,
562 //                                                               can_replace_only_if_unspecified,
563 //                                                               can_replace_only_if_unspecified);
564 //                    m_curr_row_modified = true;
565 //                }
566 //            }
567             break;
568 
569         case EmulateInstruction::eContextPopRegisterOffStack:
570             {
571                 const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
572                 if (reg_num != LLDB_INVALID_REGNUM)
573                 {
574                     m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
575                     m_curr_row_modified = true;
576                 }
577             }
578             break;
579 
580         case EmulateInstruction::eContextSetFramePointer:
581             if (!m_fp_is_cfa)
582             {
583                 m_fp_is_cfa = true;
584                 m_cfa_reg_info = *reg_info;
585                 const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
586                 assert (cfa_reg_num != LLDB_INVALID_REGNUM);
587                 m_curr_row->SetCFARegister(cfa_reg_num);
588                 m_curr_row->SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
589                 m_curr_row_modified = true;
590             }
591             break;
592 
593         case EmulateInstruction::eContextAdjustStackPointer:
594             // If we have created a frame using the frame pointer, don't follow
595             // subsequent adjustments to the stack pointer.
596             if (!m_fp_is_cfa)
597             {
598                 m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
599                 m_curr_row_modified = true;
600             }
601             break;
602     }
603     return true;
604 }
605 
606 
607