Home | History | Annotate | Download | only in Utility
      1 //===-- UnwindMacOSXFrameBackchain.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 // C Includes
     11 // C++ Includes
     12 // Other libraries and framework includes
     13 // Project includes
     14 #include "lldb/Core/ArchSpec.h"
     15 #include "lldb/Symbol/Function.h"
     16 #include "lldb/Symbol/Symbol.h"
     17 #include "lldb/Symbol/ObjectFile.h"
     18 #include "lldb/Target/ExecutionContext.h"
     19 #include "lldb/Target/Process.h"
     20 #include "lldb/Target/Target.h"
     21 #include "lldb/Target/Thread.h"
     22 
     23 #include "RegisterContextMacOSXFrameBackchain.h"
     24 
     25 using namespace lldb;
     26 using namespace lldb_private;
     27 
     28 UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain (Thread &thread) :
     29     Unwind (thread),
     30     m_cursors()
     31 {
     32 }
     33 
     34 uint32_t
     35 UnwindMacOSXFrameBackchain::DoGetFrameCount()
     36 {
     37     if (m_cursors.empty())
     38     {
     39         ExecutionContext exe_ctx (m_thread.shared_from_this());
     40         Target *target = exe_ctx.GetTargetPtr();
     41         if (target)
     42         {
     43             const ArchSpec& target_arch = target->GetArchitecture ();
     44             // Frame zero should always be supplied by the thread...
     45             exe_ctx.SetFrameSP (m_thread.GetStackFrameAtIndex (0));
     46 
     47             if (target_arch.GetAddressByteSize() == 8)
     48                 GetStackFrameData_x86_64 (exe_ctx);
     49             else
     50                 GetStackFrameData_i386 (exe_ctx);
     51         }
     52     }
     53     return m_cursors.size();
     54 }
     55 
     56 bool
     57 UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
     58 {
     59     const uint32_t frame_count = GetFrameCount();
     60     if (idx < frame_count)
     61     {
     62         if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
     63             return false;
     64         if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
     65             return false;
     66 
     67         pc = m_cursors[idx].pc;
     68         cfa = m_cursors[idx].fp;
     69 
     70         return true;
     71     }
     72     return false;
     73 }
     74 
     75 lldb::RegisterContextSP
     76 UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame (StackFrame *frame)
     77 {
     78     lldb::RegisterContextSP reg_ctx_sp;
     79     uint32_t concrete_idx = frame->GetConcreteFrameIndex ();
     80     const uint32_t frame_count = GetFrameCount();
     81     if (concrete_idx < frame_count)
     82         reg_ctx_sp.reset (new RegisterContextMacOSXFrameBackchain (m_thread, concrete_idx, m_cursors[concrete_idx]));
     83     return reg_ctx_sp;
     84 }
     85 
     86 size_t
     87 UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (const ExecutionContext &exe_ctx)
     88 {
     89     m_cursors.clear();
     90 
     91     StackFrame *first_frame = exe_ctx.GetFramePtr();
     92 
     93     Process *process = exe_ctx.GetProcessPtr();
     94     if (process == NULL)
     95         return 0;
     96 
     97     std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
     98 
     99     struct Frame_i386
    100     {
    101         uint32_t fp;
    102         uint32_t pc;
    103     };
    104 
    105     RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
    106     assert (reg_ctx);
    107 
    108     Cursor cursor;
    109     cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
    110     cursor.fp = reg_ctx->GetFP (0);
    111 
    112     Frame_i386 frame = { static_cast<uint32_t>(cursor.fp), static_cast<uint32_t>(cursor.pc) };
    113 
    114     m_cursors.push_back(cursor);
    115 
    116     const size_t k_frame_size = sizeof(frame);
    117     Error error;
    118     while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
    119     {
    120         // Read both the FP and PC (8 bytes)
    121         if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
    122             break;
    123         if (frame.pc >= 0x1000)
    124         {
    125             cursor.pc = frame.pc;
    126             cursor.fp = frame.fp;
    127             m_cursors.push_back (cursor);
    128         }
    129     }
    130     if (!m_cursors.empty())
    131     {
    132         lldb::addr_t first_frame_pc = m_cursors.front().pc;
    133         if (first_frame_pc != LLDB_INVALID_ADDRESS)
    134         {
    135             const uint32_t resolve_scope = eSymbolContextModule |
    136                                            eSymbolContextCompUnit |
    137                                            eSymbolContextFunction |
    138                                            eSymbolContextSymbol;
    139 
    140             SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
    141             const AddressRange *addr_range_ptr = NULL;
    142             AddressRange range;
    143             if (first_frame_sc.function)
    144                 addr_range_ptr = &first_frame_sc.function->GetAddressRange();
    145             else if (first_frame_sc.symbol)
    146             {
    147                 range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
    148                 range.SetByteSize (first_frame_sc.symbol->GetByteSize());
    149                 addr_range_ptr = &range;
    150             }
    151 
    152             if (addr_range_ptr)
    153             {
    154                 if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
    155                 {
    156                     // We are at the first instruction, so we can recover the
    157                     // previous PC by dereferencing the SP
    158                     lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
    159                     // Read the real second frame return address into frame.pc
    160                     if (first_frame_sp && process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
    161                     {
    162                         cursor.fp = m_cursors.front().fp;
    163                         cursor.pc = frame.pc;           // Set the new second frame PC
    164 
    165                         // Insert the second frame
    166                         m_cursors.insert(m_cursors.begin()+1, cursor);
    167 
    168                         m_cursors.front().fp = first_frame_sp;
    169                     }
    170                 }
    171             }
    172         }
    173     }
    174 //    uint32_t i=0;
    175 //    printf("      PC                 FP\n");
    176 //    printf("      ------------------ ------------------ \n");
    177 //    for (i=0; i<m_cursors.size(); ++i)
    178 //    {
    179 //        printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, m_cursors[i].pc, m_cursors[i].fp);
    180 //    }
    181     return m_cursors.size();
    182 }
    183 
    184 
    185 size_t
    186 UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64 (const ExecutionContext &exe_ctx)
    187 {
    188     m_cursors.clear();
    189 
    190     Process *process = exe_ctx.GetProcessPtr();
    191     if (process == NULL)
    192         return 0;
    193 
    194     StackFrame *first_frame = exe_ctx.GetFramePtr();
    195 
    196     std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
    197 
    198     struct Frame_x86_64
    199     {
    200         uint64_t fp;
    201         uint64_t pc;
    202     };
    203 
    204     RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
    205     assert (reg_ctx);
    206 
    207     Cursor cursor;
    208     cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
    209     cursor.fp = reg_ctx->GetFP (0);
    210 
    211     Frame_x86_64 frame = { cursor.fp, cursor.pc };
    212 
    213     m_cursors.push_back(cursor);
    214     Error error;
    215     const size_t k_frame_size = sizeof(frame);
    216     while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
    217     {
    218         // Read both the FP and PC (16 bytes)
    219         if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
    220             break;
    221 
    222         if (frame.pc >= 0x1000)
    223         {
    224             cursor.pc = frame.pc;
    225             cursor.fp = frame.fp;
    226             m_cursors.push_back (cursor);
    227         }
    228     }
    229     if (!m_cursors.empty())
    230     {
    231         lldb::addr_t first_frame_pc = m_cursors.front().pc;
    232         if (first_frame_pc != LLDB_INVALID_ADDRESS)
    233         {
    234             const uint32_t resolve_scope = eSymbolContextModule |
    235                                            eSymbolContextCompUnit |
    236                                            eSymbolContextFunction |
    237                                            eSymbolContextSymbol;
    238 
    239             SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
    240             const AddressRange *addr_range_ptr = NULL;
    241             AddressRange range;
    242             if (first_frame_sc.function)
    243                 addr_range_ptr = &first_frame_sc.function->GetAddressRange();
    244             else if (first_frame_sc.symbol)
    245             {
    246                 range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
    247                 range.SetByteSize (first_frame_sc.symbol->GetByteSize());
    248                 addr_range_ptr = &range;
    249             }
    250 
    251             if (addr_range_ptr)
    252             {
    253                 if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
    254                 {
    255                     // We are at the first instruction, so we can recover the
    256                     // previous PC by dereferencing the SP
    257                     lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
    258                     // Read the real second frame return address into frame.pc
    259                     if (process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
    260                     {
    261                         cursor.fp = m_cursors.front().fp;
    262                         cursor.pc = frame.pc;           // Set the new second frame PC
    263 
    264                         // Insert the second frame
    265                         m_cursors.insert(m_cursors.begin()+1, cursor);
    266 
    267                         m_cursors.front().fp = first_frame_sp;
    268                     }
    269                 }
    270             }
    271         }
    272     }
    273     return m_cursors.size();
    274 }
    275 
    276