forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			248 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			248 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- UnwindMacOSXFrameBackchain.cpp ------------------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "lldb/Symbol/Function.h"
 | 
						|
#include "lldb/Symbol/ObjectFile.h"
 | 
						|
#include "lldb/Symbol/Symbol.h"
 | 
						|
#include "lldb/Target/ExecutionContext.h"
 | 
						|
#include "lldb/Target/Process.h"
 | 
						|
#include "lldb/Target/Target.h"
 | 
						|
#include "lldb/Target/Thread.h"
 | 
						|
#include "lldb/Utility/ArchSpec.h"
 | 
						|
 | 
						|
#include "RegisterContextMacOSXFrameBackchain.h"
 | 
						|
 | 
						|
#include <memory>
 | 
						|
 | 
						|
using namespace lldb;
 | 
						|
using namespace lldb_private;
 | 
						|
 | 
						|
UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain(Thread &thread)
 | 
						|
    : Unwind(thread), m_cursors() {}
 | 
						|
 | 
						|
uint32_t UnwindMacOSXFrameBackchain::DoGetFrameCount() {
 | 
						|
  if (m_cursors.empty()) {
 | 
						|
    ExecutionContext exe_ctx(m_thread.shared_from_this());
 | 
						|
    Target *target = exe_ctx.GetTargetPtr();
 | 
						|
    if (target) {
 | 
						|
      const ArchSpec &target_arch = target->GetArchitecture();
 | 
						|
      // Frame zero should always be supplied by the thread...
 | 
						|
      exe_ctx.SetFrameSP(m_thread.GetStackFrameAtIndex(0));
 | 
						|
 | 
						|
      if (target_arch.GetAddressByteSize() == 8)
 | 
						|
        GetStackFrameData_x86_64(exe_ctx);
 | 
						|
      else
 | 
						|
        GetStackFrameData_i386(exe_ctx);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return m_cursors.size();
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(
 | 
						|
    uint32_t idx, addr_t &cfa, addr_t &pc, bool &behaves_like_zeroth_frame) {
 | 
						|
  const uint32_t frame_count = GetFrameCount();
 | 
						|
  if (idx < frame_count) {
 | 
						|
    if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
 | 
						|
      return false;
 | 
						|
    if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
 | 
						|
      return false;
 | 
						|
 | 
						|
    pc = m_cursors[idx].pc;
 | 
						|
    cfa = m_cursors[idx].fp;
 | 
						|
    behaves_like_zeroth_frame = (idx == 0);
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
lldb::RegisterContextSP
 | 
						|
UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame(StackFrame *frame) {
 | 
						|
  lldb::RegisterContextSP reg_ctx_sp;
 | 
						|
  uint32_t concrete_idx = frame->GetConcreteFrameIndex();
 | 
						|
  const uint32_t frame_count = GetFrameCount();
 | 
						|
  if (concrete_idx < frame_count)
 | 
						|
    reg_ctx_sp = std::make_shared<RegisterContextMacOSXFrameBackchain>(
 | 
						|
        m_thread, concrete_idx, m_cursors[concrete_idx]);
 | 
						|
  return reg_ctx_sp;
 | 
						|
}
 | 
						|
 | 
						|
size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386(
 | 
						|
    const ExecutionContext &exe_ctx) {
 | 
						|
  m_cursors.clear();
 | 
						|
 | 
						|
  StackFrame *first_frame = exe_ctx.GetFramePtr();
 | 
						|
 | 
						|
  Process *process = exe_ctx.GetProcessPtr();
 | 
						|
  if (process == nullptr)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  struct Frame_i386 {
 | 
						|
    uint32_t fp;
 | 
						|
    uint32_t pc;
 | 
						|
  };
 | 
						|
 | 
						|
  RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
 | 
						|
  assert(reg_ctx);
 | 
						|
 | 
						|
  Cursor cursor;
 | 
						|
  cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
 | 
						|
  cursor.fp = reg_ctx->GetFP(0);
 | 
						|
 | 
						|
  Frame_i386 frame = {static_cast<uint32_t>(cursor.fp),
 | 
						|
                      static_cast<uint32_t>(cursor.pc)};
 | 
						|
 | 
						|
  m_cursors.push_back(cursor);
 | 
						|
 | 
						|
  const size_t k_frame_size = sizeof(frame);
 | 
						|
  Status error;
 | 
						|
  while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) {
 | 
						|
    // Read both the FP and PC (8 bytes)
 | 
						|
    if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) !=
 | 
						|
        k_frame_size)
 | 
						|
      break;
 | 
						|
    if (frame.pc >= 0x1000) {
 | 
						|
      cursor.pc = frame.pc;
 | 
						|
      cursor.fp = frame.fp;
 | 
						|
      m_cursors.push_back(cursor);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (!m_cursors.empty()) {
 | 
						|
    lldb::addr_t first_frame_pc = m_cursors.front().pc;
 | 
						|
    if (first_frame_pc != LLDB_INVALID_ADDRESS) {
 | 
						|
      const SymbolContextItem resolve_scope =
 | 
						|
          eSymbolContextModule | eSymbolContextCompUnit |
 | 
						|
          eSymbolContextFunction | eSymbolContextSymbol;
 | 
						|
 | 
						|
      SymbolContext first_frame_sc(
 | 
						|
          first_frame->GetSymbolContext(resolve_scope));
 | 
						|
      const AddressRange *addr_range_ptr = nullptr;
 | 
						|
      AddressRange range;
 | 
						|
      if (first_frame_sc.function)
 | 
						|
        addr_range_ptr = &first_frame_sc.function->GetAddressRange();
 | 
						|
      else if (first_frame_sc.symbol) {
 | 
						|
        range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
 | 
						|
        range.SetByteSize(first_frame_sc.symbol->GetByteSize());
 | 
						|
        addr_range_ptr = ⦥
 | 
						|
      }
 | 
						|
 | 
						|
      if (addr_range_ptr) {
 | 
						|
        if (first_frame->GetFrameCodeAddress() ==
 | 
						|
            addr_range_ptr->GetBaseAddress()) {
 | 
						|
          // We are at the first instruction, so we can recover the previous PC
 | 
						|
          // by dereferencing the SP
 | 
						|
          lldb::addr_t first_frame_sp = reg_ctx->GetSP(0);
 | 
						|
          // Read the real second frame return address into frame.pc
 | 
						|
          if (first_frame_sp &&
 | 
						|
              process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc),
 | 
						|
                                  error) == sizeof(frame.pc)) {
 | 
						|
            cursor.fp = m_cursors.front().fp;
 | 
						|
            cursor.pc = frame.pc; // Set the new second frame PC
 | 
						|
 | 
						|
            // Insert the second frame
 | 
						|
            m_cursors.insert(m_cursors.begin() + 1, cursor);
 | 
						|
 | 
						|
            m_cursors.front().fp = first_frame_sp;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //    uint32_t i=0;
 | 
						|
  //    printf("      PC                 FP\n");
 | 
						|
  //    printf("      ------------------ ------------------ \n");
 | 
						|
  //    for (i=0; i<m_cursors.size(); ++i)
 | 
						|
  //    {
 | 
						|
  //        printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i,
 | 
						|
  //        m_cursors[i].pc, m_cursors[i].fp);
 | 
						|
  //    }
 | 
						|
  return m_cursors.size();
 | 
						|
}
 | 
						|
 | 
						|
size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64(
 | 
						|
    const ExecutionContext &exe_ctx) {
 | 
						|
  m_cursors.clear();
 | 
						|
 | 
						|
  Process *process = exe_ctx.GetProcessPtr();
 | 
						|
  if (process == nullptr)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  StackFrame *first_frame = exe_ctx.GetFramePtr();
 | 
						|
 | 
						|
  struct Frame_x86_64 {
 | 
						|
    uint64_t fp;
 | 
						|
    uint64_t pc;
 | 
						|
  };
 | 
						|
 | 
						|
  RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
 | 
						|
  assert(reg_ctx);
 | 
						|
 | 
						|
  Cursor cursor;
 | 
						|
  cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
 | 
						|
  cursor.fp = reg_ctx->GetFP(0);
 | 
						|
 | 
						|
  Frame_x86_64 frame = {cursor.fp, cursor.pc};
 | 
						|
 | 
						|
  m_cursors.push_back(cursor);
 | 
						|
  Status error;
 | 
						|
  const size_t k_frame_size = sizeof(frame);
 | 
						|
  while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) {
 | 
						|
    // Read both the FP and PC (16 bytes)
 | 
						|
    if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) !=
 | 
						|
        k_frame_size)
 | 
						|
      break;
 | 
						|
 | 
						|
    if (frame.pc >= 0x1000) {
 | 
						|
      cursor.pc = frame.pc;
 | 
						|
      cursor.fp = frame.fp;
 | 
						|
      m_cursors.push_back(cursor);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (!m_cursors.empty()) {
 | 
						|
    lldb::addr_t first_frame_pc = m_cursors.front().pc;
 | 
						|
    if (first_frame_pc != LLDB_INVALID_ADDRESS) {
 | 
						|
      const SymbolContextItem resolve_scope =
 | 
						|
          eSymbolContextModule | eSymbolContextCompUnit |
 | 
						|
          eSymbolContextFunction | eSymbolContextSymbol;
 | 
						|
 | 
						|
      SymbolContext first_frame_sc(
 | 
						|
          first_frame->GetSymbolContext(resolve_scope));
 | 
						|
      const AddressRange *addr_range_ptr = nullptr;
 | 
						|
      AddressRange range;
 | 
						|
      if (first_frame_sc.function)
 | 
						|
        addr_range_ptr = &first_frame_sc.function->GetAddressRange();
 | 
						|
      else if (first_frame_sc.symbol) {
 | 
						|
        range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
 | 
						|
        range.SetByteSize(first_frame_sc.symbol->GetByteSize());
 | 
						|
        addr_range_ptr = ⦥
 | 
						|
      }
 | 
						|
 | 
						|
      if (addr_range_ptr) {
 | 
						|
        if (first_frame->GetFrameCodeAddress() ==
 | 
						|
            addr_range_ptr->GetBaseAddress()) {
 | 
						|
          // We are at the first instruction, so we can recover the previous PC
 | 
						|
          // by dereferencing the SP
 | 
						|
          lldb::addr_t first_frame_sp = reg_ctx->GetSP(0);
 | 
						|
          // Read the real second frame return address into frame.pc
 | 
						|
          if (process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc),
 | 
						|
                                  error) == sizeof(frame.pc)) {
 | 
						|
            cursor.fp = m_cursors.front().fp;
 | 
						|
            cursor.pc = frame.pc; // Set the new second frame PC
 | 
						|
 | 
						|
            // Insert the second frame
 | 
						|
            m_cursors.insert(m_cursors.begin() + 1, cursor);
 | 
						|
 | 
						|
            m_cursors.front().fp = first_frame_sp;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return m_cursors.size();
 | 
						|
}
 |