1673 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1673 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- RegisterContextLLDB.cpp --------------------------------*- C++ -*-===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
 | 
						|
#include "lldb/lldb-private.h"
 | 
						|
#include "lldb/Core/Address.h"
 | 
						|
#include "lldb/Core/AddressRange.h"
 | 
						|
#include "lldb/Core/DataBufferHeap.h"
 | 
						|
#include "lldb/Core/Log.h"
 | 
						|
#include "lldb/Core/Module.h"
 | 
						|
#include "lldb/Core/RegisterValue.h"
 | 
						|
#include "lldb/Core/Value.h"
 | 
						|
#include "lldb/Expression/DWARFExpression.h"
 | 
						|
#include "lldb/Symbol/DWARFCallFrameInfo.h"
 | 
						|
#include "lldb/Symbol/FuncUnwinders.h"
 | 
						|
#include "lldb/Symbol/Function.h"
 | 
						|
#include "lldb/Symbol/ObjectFile.h"
 | 
						|
#include "lldb/Symbol/Symbol.h"
 | 
						|
#include "lldb/Symbol/SymbolContext.h"
 | 
						|
#include "lldb/Target/ABI.h"
 | 
						|
#include "lldb/Target/DynamicLoader.h"
 | 
						|
#include "lldb/Target/ExecutionContext.h"
 | 
						|
#include "lldb/Target/Platform.h"
 | 
						|
#include "lldb/Target/Process.h"
 | 
						|
#include "lldb/Target/SectionLoadList.h"
 | 
						|
#include "lldb/Target/StackFrame.h"
 | 
						|
#include "lldb/Target/Target.h"
 | 
						|
#include "lldb/Target/Thread.h"
 | 
						|
 | 
						|
#include "RegisterContextLLDB.h"
 | 
						|
 | 
						|
using namespace lldb;
 | 
						|
using namespace lldb_private;
 | 
						|
 | 
						|
RegisterContextLLDB::RegisterContextLLDB
 | 
						|
(
 | 
						|
    Thread& thread,
 | 
						|
    const SharedPtr &next_frame,
 | 
						|
    SymbolContext& sym_ctx,
 | 
						|
    uint32_t frame_number,
 | 
						|
    UnwindLLDB& unwind_lldb
 | 
						|
) :
 | 
						|
    RegisterContext (thread, frame_number),
 | 
						|
    m_thread(thread),
 | 
						|
    m_fast_unwind_plan_sp (),
 | 
						|
    m_full_unwind_plan_sp (),
 | 
						|
    m_fallback_unwind_plan_sp (),
 | 
						|
    m_all_registers_available(false),
 | 
						|
    m_frame_type (-1),
 | 
						|
    m_cfa (LLDB_INVALID_ADDRESS),
 | 
						|
    m_start_pc (),
 | 
						|
    m_current_pc (),
 | 
						|
    m_current_offset (0),
 | 
						|
    m_current_offset_backed_up_one (0),
 | 
						|
    m_sym_ctx(sym_ctx),
 | 
						|
    m_sym_ctx_valid (false),
 | 
						|
    m_frame_number (frame_number),
 | 
						|
    m_registers(),
 | 
						|
    m_parent_unwind (unwind_lldb)
 | 
						|
{
 | 
						|
    m_sym_ctx.Clear(false);
 | 
						|
    m_sym_ctx_valid = false;
 | 
						|
 | 
						|
    if (IsFrameZero ())
 | 
						|
    {
 | 
						|
        InitializeZerothFrame ();
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        InitializeNonZerothFrame ();
 | 
						|
    }
 | 
						|
 | 
						|
    // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet
 | 
						|
    if (IsFrameZero()
 | 
						|
        || next_frame->m_frame_type == eTrapHandlerFrame
 | 
						|
        || next_frame->m_frame_type == eDebuggerFrame)
 | 
						|
    {
 | 
						|
        m_all_registers_available = true;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset)
 | 
						|
{
 | 
						|
    if (!unwind_plan_sp)
 | 
						|
        return false;
 | 
						|
 | 
						|
    // check if m_current_pc is valid
 | 
						|
    if (unwind_plan_sp->PlanValidAtAddress(m_current_pc))
 | 
						|
    {
 | 
						|
        // yes - current offset can be used as is
 | 
						|
        valid_pc_offset = m_current_offset;
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // if m_current_offset <= 0, we've got nothing else to try
 | 
						|
    if (m_current_offset <= 0)
 | 
						|
        return false;
 | 
						|
 | 
						|
    // check pc - 1 to see if it's valid
 | 
						|
    Address pc_minus_one (m_current_pc);
 | 
						|
    pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1);
 | 
						|
    if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one))
 | 
						|
    {
 | 
						|
        // *valid_pc_offset = m_current_offset - 1;
 | 
						|
        valid_pc_offset = m_current_pc.GetOffset() - 1;
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
 | 
						|
// executing frame.
 | 
						|
 | 
						|
void
 | 
						|
RegisterContextLLDB::InitializeZerothFrame()
 | 
						|
{
 | 
						|
    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
 | 
						|
    ExecutionContext exe_ctx(m_thread.shared_from_this());
 | 
						|
    RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext();
 | 
						|
 | 
						|
    if (reg_ctx_sp.get() == NULL)
 | 
						|
    {
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        UnwindLogMsg ("frame does not have a register context");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    addr_t current_pc = reg_ctx_sp->GetPC();
 | 
						|
 | 
						|
    if (current_pc == LLDB_INVALID_ADDRESS)
 | 
						|
    {
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        UnwindLogMsg ("frame does not have a pc");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    Process *process = exe_ctx.GetProcessPtr();
 | 
						|
 | 
						|
    // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
 | 
						|
    // this will strip bit zero in case we read a PC from memory or from the LR.
 | 
						|
    // (which would be a no-op in frame 0 where we get it from the register set,
 | 
						|
    // but still a good idea to make the call here for other ABIs that may exist.)
 | 
						|
    ABI *abi = process->GetABI().get();
 | 
						|
    if (abi)
 | 
						|
        current_pc = abi->FixCodeAddress(current_pc);
 | 
						|
 | 
						|
    // Initialize m_current_pc, an Address object, based on current_pc, an addr_t.
 | 
						|
    m_current_pc.SetLoadAddress (current_pc, &process->GetTarget());
 | 
						|
 | 
						|
    // If we don't have a Module for some reason, we're not going to find symbol/function information - just
 | 
						|
    // stick in some reasonable defaults and hope we can unwind past this frame.
 | 
						|
    ModuleSP pc_module_sp (m_current_pc.GetModule());
 | 
						|
    if (!m_current_pc.IsValid() || !pc_module_sp)
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("using architectural default unwind method");
 | 
						|
    }
 | 
						|
 | 
						|
    // We require either a symbol or function in the symbols context to be successfully
 | 
						|
    // filled in or this context is of no use to us.
 | 
						|
    const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
 | 
						|
    if (pc_module_sp.get()
 | 
						|
        && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, resolve_scope, m_sym_ctx) & resolve_scope))
 | 
						|
    {
 | 
						|
        m_sym_ctx_valid = true;
 | 
						|
    }
 | 
						|
 | 
						|
    AddressRange addr_range;
 | 
						|
    m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range);
 | 
						|
 | 
						|
    if (IsTrapHandlerSymbol (process, m_sym_ctx))
 | 
						|
    {
 | 
						|
        m_frame_type = eTrapHandlerFrame;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        // FIXME:  Detect eDebuggerFrame here.
 | 
						|
        m_frame_type = eNormalFrame;
 | 
						|
    }
 | 
						|
 | 
						|
    // If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function.
 | 
						|
    // else treat the current pc value as the start_pc and record no offset.
 | 
						|
    if (addr_range.GetBaseAddress().IsValid())
 | 
						|
    {
 | 
						|
        m_start_pc = addr_range.GetBaseAddress();
 | 
						|
        if (m_current_pc.GetSection() == m_start_pc.GetSection())
 | 
						|
        {
 | 
						|
            m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
 | 
						|
        }
 | 
						|
        else if (m_current_pc.GetModule() == m_start_pc.GetModule())
 | 
						|
        {
 | 
						|
            // This means that whatever symbol we kicked up isn't really correct
 | 
						|
            // --- we should not cross section boundaries ... We really should NULL out
 | 
						|
            // the function/symbol in this case unless there is a bad assumption
 | 
						|
            // here due to inlined functions?
 | 
						|
            m_current_offset = m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
 | 
						|
        }
 | 
						|
        m_current_offset_backed_up_one = m_current_offset;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        m_start_pc = m_current_pc;
 | 
						|
        m_current_offset = -1;
 | 
						|
        m_current_offset_backed_up_one = -1;
 | 
						|
    }
 | 
						|
 | 
						|
    // We've set m_frame_type and m_sym_ctx before these calls.
 | 
						|
 | 
						|
    m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
 | 
						|
    m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
 | 
						|
 | 
						|
    UnwindPlan::RowSP active_row;
 | 
						|
    int cfa_offset = 0;
 | 
						|
    int row_register_kind = -1;
 | 
						|
    if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
 | 
						|
    {
 | 
						|
        active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
 | 
						|
        row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
 | 
						|
        if (active_row.get() && log)
 | 
						|
        {
 | 
						|
            StreamString active_row_strm;
 | 
						|
            active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
 | 
						|
            UnwindLogMsg ("%s", active_row_strm.GetString().c_str());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!active_row.get())
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("could not find an unwindplan row for this frame's pc");
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    addr_t cfa_regval = LLDB_INVALID_ADDRESS;
 | 
						|
    if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("could not read CFA register for this frame.");
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    cfa_offset = active_row->GetCFAOffset ();
 | 
						|
    m_cfa = cfa_regval + cfa_offset;
 | 
						|
 | 
						|
    UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
 | 
						|
    UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan",
 | 
						|
            (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()),
 | 
						|
            (uint64_t) m_cfa,
 | 
						|
            m_full_unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
}
 | 
						|
 | 
						|
// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the RegisterContextLLDB "below" it
 | 
						|
// to provide things like its current pc value.
 | 
						|
 | 
						|
void
 | 
						|
RegisterContextLLDB::InitializeNonZerothFrame()
 | 
						|
{
 | 
						|
    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
 | 
						|
    if (IsFrameZero ())
 | 
						|
    {
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        UnwindLogMsg ("non-zeroth frame tests positive for IsFrameZero -- that shouldn't happen.");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!GetNextFrame().get() || !GetNextFrame()->IsValid())
 | 
						|
    {
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        UnwindLogMsg ("Could not get next frame, marking this frame as invalid.");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    if (!m_thread.GetRegisterContext())
 | 
						|
    {
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        UnwindLogMsg ("Could not get register context for this thread, marking this frame as invalid.");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    addr_t pc;
 | 
						|
    if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("could not get pc value");
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (log)
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc);
 | 
						|
        addr_t reg_val;
 | 
						|
        if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
 | 
						|
            UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val);
 | 
						|
        if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
 | 
						|
            UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val);
 | 
						|
    }
 | 
						|
 | 
						|
    // A pc of 0x0 means it's the end of the stack crawl
 | 
						|
    if (pc == 0)
 | 
						|
    {
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        UnwindLogMsg ("this frame has a pc of 0x0");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    ExecutionContext exe_ctx(m_thread.shared_from_this());
 | 
						|
    Process *process = exe_ctx.GetProcessPtr();
 | 
						|
    // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
 | 
						|
    // this will strip bit zero in case we read a PC from memory or from the LR.
 | 
						|
    ABI *abi = process->GetABI().get();
 | 
						|
    if (abi)
 | 
						|
        pc = abi->FixCodeAddress(pc);
 | 
						|
 | 
						|
    m_current_pc.SetLoadAddress (pc, &process->GetTarget());
 | 
						|
 | 
						|
    // If we don't have a Module for some reason, we're not going to find symbol/function information - just
 | 
						|
    // stick in some reasonable defaults and hope we can unwind past this frame.
 | 
						|
    ModuleSP pc_module_sp (m_current_pc.GetModule());
 | 
						|
    if (!m_current_pc.IsValid() || !pc_module_sp)
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("using architectural default unwind method");
 | 
						|
 | 
						|
        // Test the pc value to see if we know it's in an unmapped/non-executable region of memory.
 | 
						|
        uint32_t permissions;
 | 
						|
        if (process->GetLoadAddressPermissions(pc, permissions)
 | 
						|
            && (permissions & ePermissionsExecutable) == 0)
 | 
						|
        {
 | 
						|
            // If this is the second frame off the stack, we may have unwound the first frame
 | 
						|
            // incorrectly.  But using the architecture default unwind plan may get us back on
 | 
						|
            // track -- albeit possibly skipping a real frame.  Give this frame a clearly-invalid
 | 
						|
            // pc and see if we can get any further.
 | 
						|
            if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero())
 | 
						|
            {
 | 
						|
                UnwindLogMsg ("had a pc of 0x%" PRIx64 " which is not in executable memory but on frame 1 -- allowing it once.",
 | 
						|
                         (uint64_t) pc);
 | 
						|
                m_frame_type = eSkipFrame;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.
 | 
						|
                m_frame_type = eNotAValidFrame;
 | 
						|
                UnwindLogMsg ("pc is in a non-executable section of memory and this isn't the 2nd frame in the stack walk.");
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (abi)
 | 
						|
        {
 | 
						|
            m_fast_unwind_plan_sp.reset ();
 | 
						|
            m_full_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
 | 
						|
            abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp);
 | 
						|
            if (m_frame_type != eSkipFrame)  // don't override eSkipFrame
 | 
						|
            {
 | 
						|
                m_frame_type = eNormalFrame;
 | 
						|
            }
 | 
						|
            m_all_registers_available = false;
 | 
						|
            m_current_offset = -1;
 | 
						|
            m_current_offset_backed_up_one = -1;
 | 
						|
            addr_t cfa_regval = LLDB_INVALID_ADDRESS;
 | 
						|
            int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
 | 
						|
            UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
 | 
						|
            if (row.get())
 | 
						|
            {
 | 
						|
                uint32_t cfa_regnum = row->GetCFARegister();
 | 
						|
                int cfa_offset = row->GetCFAOffset();
 | 
						|
                if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval))
 | 
						|
                {
 | 
						|
                    UnwindLogMsg ("failed to get cfa value");
 | 
						|
                    if (m_frame_type != eSkipFrame)   // don't override eSkipFrame
 | 
						|
                    {
 | 
						|
                        m_frame_type = eNormalFrame;
 | 
						|
                    }
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
                m_cfa = cfa_regval + cfa_offset;
 | 
						|
 | 
						|
                // A couple of sanity checks..
 | 
						|
                if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
 | 
						|
                {
 | 
						|
                    UnwindLogMsg ("could not find a valid cfa address");
 | 
						|
                    m_frame_type = eNotAValidFrame;
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
 | 
						|
                // cfa_regval should point into the stack memory; if we can query memory region permissions,
 | 
						|
                // see if the memory is allocated & readable.
 | 
						|
                if (process->GetLoadAddressPermissions(cfa_regval, permissions)
 | 
						|
                    && (permissions & ePermissionsReadable) == 0)
 | 
						|
                {
 | 
						|
                    m_frame_type = eNotAValidFrame;
 | 
						|
                    UnwindLogMsg ("the CFA points to a region of memory that is not readable");
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                UnwindLogMsg ("could not find a row for function offset zero");
 | 
						|
                m_frame_type = eNotAValidFrame;
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        UnwindLogMsg ("could not find any symbol for this pc, or a default unwind plan, to continue unwind.");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function...
 | 
						|
                                           // This will handle the case where the saved pc does not point to 
 | 
						|
                                           // a function/symbol because it is beyond the bounds of the correct
 | 
						|
                                           // function and there's no symbol there.  ResolveSymbolContextForAddress
 | 
						|
                                           // will fail to find a symbol, back up the pc by 1 and re-search.
 | 
						|
    const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
 | 
						|
    uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc,
 | 
						|
                                                                            resolve_scope,
 | 
						|
                                                                            m_sym_ctx, resolve_tail_call_address);
 | 
						|
 | 
						|
    // We require either a symbol or function in the symbols context to be successfully
 | 
						|
    // filled in or this context is of no use to us.
 | 
						|
    if (resolve_scope & resolved_scope)
 | 
						|
    {
 | 
						|
        m_sym_ctx_valid = true;
 | 
						|
    }
 | 
						|
 | 
						|
    AddressRange addr_range;
 | 
						|
    if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
 | 
						|
    {
 | 
						|
        m_sym_ctx_valid = false;
 | 
						|
    }
 | 
						|
 | 
						|
    bool decr_pc_and_recompute_addr_range = false;
 | 
						|
 | 
						|
    // If the symbol lookup failed...
 | 
						|
    if (m_sym_ctx_valid == false)
 | 
						|
       decr_pc_and_recompute_addr_range = true;
 | 
						|
 | 
						|
    // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp),
 | 
						|
    // and our "current" pc is the start of a function...
 | 
						|
    if (m_sym_ctx_valid
 | 
						|
        && GetNextFrame()->m_frame_type != eTrapHandlerFrame
 | 
						|
        && GetNextFrame()->m_frame_type != eDebuggerFrame
 | 
						|
        && addr_range.GetBaseAddress().IsValid()
 | 
						|
        && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
 | 
						|
        && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
 | 
						|
    {
 | 
						|
        decr_pc_and_recompute_addr_range = true;
 | 
						|
    }
 | 
						|
 | 
						|
    // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc"
 | 
						|
    // value is pointing to the next function, e.g. if a function ends with a CALL instruction.
 | 
						|
    // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function
 | 
						|
    // to the ABI plugin and consult that.
 | 
						|
    if (decr_pc_and_recompute_addr_range)
 | 
						|
    {
 | 
						|
        Address temporary_pc(m_current_pc);
 | 
						|
        temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
 | 
						|
        m_sym_ctx.Clear(false);
 | 
						|
        m_sym_ctx_valid = false;
 | 
						|
        uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
 | 
						|
        
 | 
						|
        if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope)
 | 
						|
        {
 | 
						|
            if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false,  addr_range))
 | 
						|
                m_sym_ctx_valid = true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
 | 
						|
    // else treat the current pc value as the start_pc and record no offset.
 | 
						|
    if (addr_range.GetBaseAddress().IsValid())
 | 
						|
    {
 | 
						|
        m_start_pc = addr_range.GetBaseAddress();
 | 
						|
        m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
 | 
						|
        m_current_offset_backed_up_one = m_current_offset;
 | 
						|
        if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
 | 
						|
        {
 | 
						|
            m_current_offset_backed_up_one--;
 | 
						|
            if (m_sym_ctx_valid)
 | 
						|
                m_current_pc.SetOffset(m_current_pc.GetOffset() - 1);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        m_start_pc = m_current_pc;
 | 
						|
        m_current_offset = -1;
 | 
						|
        m_current_offset_backed_up_one = -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsTrapHandlerSymbol (process, m_sym_ctx))
 | 
						|
    {
 | 
						|
        m_frame_type = eTrapHandlerFrame;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        // FIXME:  Detect eDebuggerFrame here.
 | 
						|
        if (m_frame_type != eSkipFrame) // don't override eSkipFrame
 | 
						|
        {
 | 
						|
            m_frame_type = eNormalFrame;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // We've set m_frame_type and m_sym_ctx before this call.
 | 
						|
    m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
 | 
						|
 | 
						|
    UnwindPlan::RowSP active_row;
 | 
						|
    int cfa_offset = 0;
 | 
						|
    int row_register_kind = -1;
 | 
						|
 | 
						|
    // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
 | 
						|
    // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.)
 | 
						|
 | 
						|
    if (m_fast_unwind_plan_sp && m_fast_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
 | 
						|
    {
 | 
						|
        active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
 | 
						|
        row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind ();
 | 
						|
        if (active_row.get() && log)
 | 
						|
        {
 | 
						|
            StreamString active_row_strm;
 | 
						|
            active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
 | 
						|
            UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
 | 
						|
        int valid_offset = -1;
 | 
						|
        if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset))
 | 
						|
        {
 | 
						|
            active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (valid_offset);
 | 
						|
            row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
 | 
						|
            if (active_row.get() && log)
 | 
						|
            {
 | 
						|
                StreamString active_row_strm;
 | 
						|
                active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
 | 
						|
                UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!active_row.get())
 | 
						|
    {
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        UnwindLogMsg ("could not find unwind row for this pc");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    addr_t cfa_regval = LLDB_INVALID_ADDRESS;
 | 
						|
    if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister());
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    cfa_offset = active_row->GetCFAOffset ();
 | 
						|
    m_cfa = cfa_regval + cfa_offset;
 | 
						|
 | 
						|
    UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
 | 
						|
 | 
						|
    // A couple of sanity checks..
 | 
						|
    if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("could not find a valid cfa address");
 | 
						|
        m_frame_type = eNotAValidFrame;
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    // If we have a bad stack setup, we can get the same CFA value multiple times -- or even
 | 
						|
    // more devious, we can actually oscillate between two CFA values.  Detect that here and
 | 
						|
    // break out to avoid a possible infinite loop in lldb trying to unwind the stack.
 | 
						|
    addr_t next_frame_cfa;
 | 
						|
    addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
 | 
						|
    if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa))
 | 
						|
    {
 | 
						|
        bool repeating_frames = false;
 | 
						|
        if (next_frame_cfa == m_cfa)
 | 
						|
        {
 | 
						|
            repeating_frames = true;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if (GetNextFrame()->GetNextFrame() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa)
 | 
						|
                && next_next_frame_cfa == m_cfa)
 | 
						|
            {
 | 
						|
                repeating_frames = true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (repeating_frames && abi && abi->FunctionCallsChangeCFA())
 | 
						|
        {
 | 
						|
            UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
 | 
						|
            m_frame_type = eNotAValidFrame;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64,
 | 
						|
            (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::IsFrameZero () const
 | 
						|
{
 | 
						|
    return m_frame_number == 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Find a fast unwind plan for this frame, if possible.
 | 
						|
//
 | 
						|
// On entry to this method,
 | 
						|
//
 | 
						|
//   1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct,
 | 
						|
//   2. m_sym_ctx should already be filled in, and
 | 
						|
//   3. m_current_pc should have the current pc value for this frame
 | 
						|
//   4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
 | 
						|
 | 
						|
UnwindPlanSP
 | 
						|
RegisterContextLLDB::GetFastUnwindPlanForFrame ()
 | 
						|
{
 | 
						|
    UnwindPlanSP unwind_plan_sp;
 | 
						|
    ModuleSP pc_module_sp (m_current_pc.GetModule());
 | 
						|
 | 
						|
    if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
 | 
						|
        return unwind_plan_sp;
 | 
						|
 | 
						|
    if (IsFrameZero ())
 | 
						|
        return unwind_plan_sp;
 | 
						|
 | 
						|
    FuncUnwindersSP func_unwinders_sp (pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx));
 | 
						|
    if (!func_unwinders_sp)
 | 
						|
        return unwind_plan_sp;
 | 
						|
 | 
						|
    // If we're in _sigtramp(), unwinding past this frame requires special knowledge.
 | 
						|
    if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame)
 | 
						|
        return unwind_plan_sp;
 | 
						|
 | 
						|
    unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
 | 
						|
    if (unwind_plan_sp)
 | 
						|
    {
 | 
						|
        if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
 | 
						|
        {
 | 
						|
            Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
 | 
						|
            if (log && log->GetVerbose())
 | 
						|
            {
 | 
						|
                if (m_fast_unwind_plan_sp)
 | 
						|
                    UnwindLogMsgVerbose ("frame, and has a fast UnwindPlan");
 | 
						|
                else
 | 
						|
                    UnwindLogMsgVerbose ("frame");
 | 
						|
            }
 | 
						|
            m_frame_type = eNormalFrame;
 | 
						|
            return unwind_plan_sp;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            unwind_plan_sp.reset();
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return unwind_plan_sp;
 | 
						|
}
 | 
						|
 | 
						|
// On entry to this method,
 | 
						|
//
 | 
						|
//   1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct,
 | 
						|
//   2. m_sym_ctx should already be filled in, and
 | 
						|
//   3. m_current_pc should have the current pc value for this frame
 | 
						|
//   4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
 | 
						|
 | 
						|
UnwindPlanSP
 | 
						|
RegisterContextLLDB::GetFullUnwindPlanForFrame ()
 | 
						|
{
 | 
						|
    UnwindPlanSP unwind_plan_sp;
 | 
						|
    UnwindPlanSP arch_default_unwind_plan_sp;
 | 
						|
    ExecutionContext exe_ctx(m_thread.shared_from_this());
 | 
						|
    Process *process = exe_ctx.GetProcessPtr();
 | 
						|
    ABI *abi = process ? process->GetABI().get() : NULL;
 | 
						|
    if (abi)
 | 
						|
    {
 | 
						|
        arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
 | 
						|
        abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        UnwindLogMsg ("unable to get architectural default UnwindPlan from ABI plugin");
 | 
						|
    }
 | 
						|
 | 
						|
    bool behaves_like_zeroth_frame = false;
 | 
						|
    if (IsFrameZero ()
 | 
						|
        || GetNextFrame()->m_frame_type == eTrapHandlerFrame
 | 
						|
        || GetNextFrame()->m_frame_type == eDebuggerFrame)
 | 
						|
    {
 | 
						|
        behaves_like_zeroth_frame = true;
 | 
						|
        // If this frame behaves like a 0th frame (currently executing or
 | 
						|
        // interrupted asynchronously), all registers can be retrieved.
 | 
						|
        m_all_registers_available = true;
 | 
						|
    }
 | 
						|
 | 
						|
    // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
 | 
						|
    // in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
 | 
						|
    // Also, if this Process can report on memory region attributes, any non-executable region means
 | 
						|
    // we jumped through a bad function pointer - handle the same way as 0x0.
 | 
						|
    // Note, if we have a symbol context & a symbol, we don't want to follow this code path.  This is
 | 
						|
    // for jumping to memory regions without any information available.
 | 
						|
 | 
						|
    if ((!m_sym_ctx_valid || (m_sym_ctx.function == NULL && m_sym_ctx.symbol == NULL)) && behaves_like_zeroth_frame && m_current_pc.IsValid())
 | 
						|
    {
 | 
						|
        uint32_t permissions;
 | 
						|
        addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());
 | 
						|
        if (current_pc_addr == 0
 | 
						|
            || (process->GetLoadAddressPermissions (current_pc_addr, permissions)
 | 
						|
                && (permissions & ePermissionsExecutable) == 0))
 | 
						|
        {
 | 
						|
            unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
 | 
						|
            abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
 | 
						|
            m_frame_type = eNormalFrame;
 | 
						|
            return unwind_plan_sp;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // No Module for the current pc, try using the architecture default unwind.
 | 
						|
    ModuleSP pc_module_sp (m_current_pc.GetModule());
 | 
						|
    if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
 | 
						|
    {
 | 
						|
        m_frame_type = eNormalFrame;
 | 
						|
        return arch_default_unwind_plan_sp;
 | 
						|
    }
 | 
						|
 | 
						|
    FuncUnwindersSP func_unwinders_sp;
 | 
						|
    if (m_sym_ctx_valid)
 | 
						|
    {
 | 
						|
        func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
 | 
						|
    }
 | 
						|
 | 
						|
    // No FuncUnwinders available for this pc (i.e. a stripped function symbol and -fomit-frame-pointer).
 | 
						|
    // Try using the eh_frame information relative to the current PC,
 | 
						|
    // and finally fall back on the architectural default unwind.
 | 
						|
    if (!func_unwinders_sp)
 | 
						|
    {
 | 
						|
        DWARFCallFrameInfo *eh_frame = pc_module_sp && pc_module_sp->GetObjectFile() ? 
 | 
						|
            pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo() : nullptr;
 | 
						|
 | 
						|
        m_frame_type = eNormalFrame;
 | 
						|
        if (eh_frame && m_current_pc.IsValid())
 | 
						|
        {
 | 
						|
            unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
 | 
						|
            // Even with -fomit-frame-pointer, we can try eh_frame to get back on track.
 | 
						|
            if (eh_frame->GetUnwindPlan (m_current_pc, *unwind_plan_sp))
 | 
						|
                return unwind_plan_sp;
 | 
						|
            else
 | 
						|
                unwind_plan_sp.reset();
 | 
						|
        }
 | 
						|
        return arch_default_unwind_plan_sp;
 | 
						|
    }
 | 
						|
 | 
						|
    // If we're in _sigtramp(), unwinding past this frame requires special knowledge.  On Mac OS X this knowledge
 | 
						|
    // is properly encoded in the eh_frame section, so prefer that if available.
 | 
						|
    // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of
 | 
						|
    // how to unwind out of sigtramp.
 | 
						|
    if (m_frame_type == eTrapHandlerFrame)
 | 
						|
    {
 | 
						|
        m_fast_unwind_plan_sp.reset();
 | 
						|
        unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
 | 
						|
        if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc) && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes)
 | 
						|
        {
 | 
						|
            return unwind_plan_sp;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
 | 
						|
    // This comes up if we have hand-written functions in a Module and hand-written eh_frame.  The assembly
 | 
						|
    // instruction inspection may fail and the eh_frame CFI were probably written with some care to do the
 | 
						|
    // right thing.  It'd be nice if there was a way to ask the eh_frame directly if it is asynchronous
 | 
						|
    // (can be trusted at every instruction point) or synchronous (the normal case - only at call sites).
 | 
						|
    // But there is not.
 | 
						|
    if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx))
 | 
						|
    {
 | 
						|
        unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
 | 
						|
        if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
 | 
						|
        {
 | 
						|
            UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it",
 | 
						|
                           unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
            return unwind_plan_sp;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
 | 
						|
    if (behaves_like_zeroth_frame)
 | 
						|
    {
 | 
						|
        unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
 | 
						|
        if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
 | 
						|
        {
 | 
						|
            if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
 | 
						|
            {
 | 
						|
                // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably
 | 
						|
                // don't have any eh_frame instructions available.
 | 
						|
                // The assembly profilers work really well with compiler-generated functions but hand-written
 | 
						|
                // assembly can be problematic.  We'll set the architecture default UnwindPlan as our fallback
 | 
						|
                // UnwindPlan in case this doesn't work out when we try to unwind.
 | 
						|
                m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
 | 
						|
            }
 | 
						|
            UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
            return unwind_plan_sp;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
 | 
						|
    unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
 | 
						|
    int valid_offset = -1;
 | 
						|
    if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
 | 
						|
    {
 | 
						|
        UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
        return unwind_plan_sp;
 | 
						|
    }
 | 
						|
 | 
						|
    // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
 | 
						|
    // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
 | 
						|
    unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
 | 
						|
    if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
 | 
						|
    {
 | 
						|
        // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably
 | 
						|
        // don't have any eh_frame instructions available.
 | 
						|
        // The assembly profilers work really well with compiler-generated functions but hand-written
 | 
						|
        // assembly can be problematic.  We'll set the architecture default UnwindPlan as our fallback
 | 
						|
        // UnwindPlan in case this doesn't work out when we try to unwind.
 | 
						|
        m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
 | 
						|
    {
 | 
						|
        UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
        return unwind_plan_sp;
 | 
						|
    }
 | 
						|
 | 
						|
    // If we're on the first instruction of a function, and we have an architectural default UnwindPlan
 | 
						|
    // for the initial instruction of a function, use that.
 | 
						|
    if (m_current_offset_backed_up_one == 0)
 | 
						|
    {
 | 
						|
        unwind_plan_sp = func_unwinders_sp->GetUnwindPlanArchitectureDefaultAtFunctionEntry (m_thread);
 | 
						|
        if (unwind_plan_sp)
 | 
						|
        {
 | 
						|
            UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
            return unwind_plan_sp;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // If nothing else, use the architectural default UnwindPlan and hope that does the job.
 | 
						|
    if (arch_default_unwind_plan_sp)
 | 
						|
        UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
    else
 | 
						|
        UnwindLogMsg ("Unable to find any UnwindPlan for full unwind of this frame.");
 | 
						|
 | 
						|
    return arch_default_unwind_plan_sp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
RegisterContextLLDB::InvalidateAllRegisters ()
 | 
						|
{
 | 
						|
    m_frame_type = eNotAValidFrame;
 | 
						|
}
 | 
						|
 | 
						|
size_t
 | 
						|
RegisterContextLLDB::GetRegisterCount ()
 | 
						|
{
 | 
						|
    return m_thread.GetRegisterContext()->GetRegisterCount();
 | 
						|
}
 | 
						|
 | 
						|
const RegisterInfo *
 | 
						|
RegisterContextLLDB::GetRegisterInfoAtIndex (size_t reg)
 | 
						|
{
 | 
						|
    return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
 | 
						|
}
 | 
						|
 | 
						|
size_t
 | 
						|
RegisterContextLLDB::GetRegisterSetCount ()
 | 
						|
{
 | 
						|
    return m_thread.GetRegisterContext()->GetRegisterSetCount ();
 | 
						|
}
 | 
						|
 | 
						|
const RegisterSet *
 | 
						|
RegisterContextLLDB::GetRegisterSet (size_t reg_set)
 | 
						|
{
 | 
						|
    return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t
 | 
						|
RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
 | 
						|
{
 | 
						|
    return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
 | 
						|
                                                            const RegisterInfo *reg_info,
 | 
						|
                                                            RegisterValue &value)
 | 
						|
{
 | 
						|
    if (!IsValid())
 | 
						|
        return false;
 | 
						|
    bool success = false;
 | 
						|
 | 
						|
    switch (regloc.type)
 | 
						|
    {
 | 
						|
    case UnwindLLDB::RegisterLocation::eRegisterInRegister:
 | 
						|
        {
 | 
						|
            const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
 | 
						|
 | 
						|
            if (!other_reg_info)
 | 
						|
                return false;
 | 
						|
 | 
						|
            if (IsFrameZero ())
 | 
						|
            {
 | 
						|
                success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                success = GetNextFrame()->ReadRegister (other_reg_info, value);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
 | 
						|
        success = value.SetUInt (regloc.location.inferred_value, reg_info->byte_size);
 | 
						|
        break;
 | 
						|
 | 
						|
    case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
 | 
						|
        break;
 | 
						|
    case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
 | 
						|
        assert ("FIXME debugger inferior function call unwind");
 | 
						|
        break;
 | 
						|
    case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
 | 
						|
        {
 | 
						|
            Error error (ReadRegisterValueFromMemory(reg_info,
 | 
						|
                                                     regloc.location.target_memory_location,
 | 
						|
                                                     reg_info->byte_size,
 | 
						|
                                                     value));
 | 
						|
            success = error.Success();
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    default:
 | 
						|
        assert ("Unknown RegisterLocation type.");
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    return success;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
 | 
						|
                                                           const RegisterInfo *reg_info,
 | 
						|
                                                           const RegisterValue &value)
 | 
						|
{
 | 
						|
    if (!IsValid())
 | 
						|
        return false;
 | 
						|
 | 
						|
    bool success = false;
 | 
						|
 | 
						|
    switch (regloc.type)
 | 
						|
    {
 | 
						|
        case UnwindLLDB::RegisterLocation::eRegisterInRegister:
 | 
						|
            {
 | 
						|
                const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
 | 
						|
                if (IsFrameZero ())
 | 
						|
                {
 | 
						|
                    success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    success = GetNextFrame()->WriteRegister (other_reg_info, value);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
 | 
						|
        case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
 | 
						|
            break;
 | 
						|
        case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
 | 
						|
            assert ("FIXME debugger inferior function call unwind");
 | 
						|
            break;
 | 
						|
        case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
 | 
						|
            {
 | 
						|
                Error error (WriteRegisterValueToMemory (reg_info,
 | 
						|
                                                         regloc.location.target_memory_location,
 | 
						|
                                                         reg_info->byte_size,
 | 
						|
                                                         value));
 | 
						|
                success = error.Success();
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            assert ("Unknown RegisterLocation type.");
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return success;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::IsValid () const
 | 
						|
{
 | 
						|
    return m_frame_type != eNotAValidFrame;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::IsTrapHandlerFrame () const
 | 
						|
{
 | 
						|
    return m_frame_type == eTrapHandlerFrame;
 | 
						|
}
 | 
						|
 | 
						|
// A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther
 | 
						|
// up the stack if we keep looking.  It's always the second frame in an unwind (i.e. the first frame after
 | 
						|
// frame zero) where unwinding can be the trickiest.  Ideally we'll mark up this frame in some way so the
 | 
						|
// user knows we're displaying bad data and we may have skipped one frame of their real program in the
 | 
						|
// process of getting back on track.
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::IsSkipFrame () const
 | 
						|
{
 | 
						|
    return m_frame_type == eSkipFrame;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const
 | 
						|
{
 | 
						|
    PlatformSP platform_sp (process->GetTarget().GetPlatform());
 | 
						|
    if (platform_sp)
 | 
						|
    {
 | 
						|
        const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames());
 | 
						|
        for (ConstString name : trap_handler_names)
 | 
						|
        {
 | 
						|
            if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
 | 
						|
                (m_sym_ctx.symbol   && m_sym_ctx.symbol->GetName()   == name))
 | 
						|
            {
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    const std::vector<ConstString> user_specified_trap_handler_names (m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames());
 | 
						|
    for (ConstString name : user_specified_trap_handler_names)
 | 
						|
    {   
 | 
						|
        if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
 | 
						|
            (m_sym_ctx.symbol   && m_sym_ctx.symbol->GetName()   == name))
 | 
						|
        {   
 | 
						|
            return true;
 | 
						|
        }   
 | 
						|
    }   
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
 | 
						|
 | 
						|
enum UnwindLLDB::RegisterSearchResult
 | 
						|
RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc)
 | 
						|
{
 | 
						|
    // Have we already found this register location?
 | 
						|
    if (!m_registers.empty())
 | 
						|
    {
 | 
						|
        std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator;
 | 
						|
        iterator = m_registers.find (lldb_regnum);
 | 
						|
        if (iterator != m_registers.end())
 | 
						|
        {
 | 
						|
            regloc = iterator->second;
 | 
						|
            UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum);
 | 
						|
            return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    uint32_t sp_regnum = LLDB_INVALID_REGNUM;
 | 
						|
    uint32_t pc_regnum = LLDB_INVALID_REGNUM;
 | 
						|
    m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum);
 | 
						|
    m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum);
 | 
						|
 | 
						|
    // Are we looking for the CALLER's stack pointer?  The stack pointer is defined to be the same as THIS frame's
 | 
						|
    // CFA so just return the CFA value.  This is true on x86-32/x86-64 at least.
 | 
						|
    if (sp_regnum != LLDB_INVALID_REGNUM && sp_regnum == lldb_regnum)
 | 
						|
    {
 | 
						|
        // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value)
 | 
						|
        assert (sizeof (addr_t) <= sizeof (uint64_t));
 | 
						|
        regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
 | 
						|
        regloc.location.inferred_value = m_cfa;
 | 
						|
        m_registers[lldb_regnum] = regloc;
 | 
						|
        UnwindLogMsg ("supplying caller's stack pointer (%d) value, computed from CFA", lldb_regnum);
 | 
						|
        return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
    }
 | 
						|
 | 
						|
    // Look through the available UnwindPlans for the register location.
 | 
						|
 | 
						|
    UnwindPlan::Row::RegisterLocation unwindplan_regloc;
 | 
						|
    bool have_unwindplan_regloc = false;
 | 
						|
    RegisterKind unwindplan_registerkind = (RegisterKind)-1;
 | 
						|
 | 
						|
    if (m_fast_unwind_plan_sp)
 | 
						|
    {
 | 
						|
        UnwindPlan::RowSP active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
 | 
						|
        unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind ();
 | 
						|
        uint32_t row_regnum;
 | 
						|
        if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
 | 
						|
        {
 | 
						|
            UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
 | 
						|
                    lldb_regnum, (int) unwindplan_registerkind);
 | 
						|
            return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
        }
 | 
						|
        if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
 | 
						|
        {
 | 
						|
            UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", lldb_regnum);
 | 
						|
            have_unwindplan_regloc = true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!have_unwindplan_regloc)
 | 
						|
    {
 | 
						|
        // m_full_unwind_plan_sp being NULL means that we haven't tried to find a full UnwindPlan yet
 | 
						|
        if (!m_full_unwind_plan_sp)
 | 
						|
            m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
 | 
						|
 | 
						|
        if (m_full_unwind_plan_sp)
 | 
						|
        {
 | 
						|
            UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
 | 
						|
            unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
 | 
						|
            uint32_t row_regnum;
 | 
						|
            bool row_register_rewritten_to_return_address_reg = false;
 | 
						|
 | 
						|
            // If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm),
 | 
						|
            // look for the return address register number in the UnwindPlan's row.
 | 
						|
            if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
 | 
						|
            {
 | 
						|
               row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister();
 | 
						|
               row_register_rewritten_to_return_address_reg = true;
 | 
						|
               UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead",
 | 
						|
                       row_regnum);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
 | 
						|
                {
 | 
						|
                    if (unwindplan_registerkind == eRegisterKindGeneric)
 | 
						|
                        UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum);
 | 
						|
                    else
 | 
						|
                        UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
 | 
						|
                                lldb_regnum, (int) unwindplan_registerkind);
 | 
						|
                    return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
 | 
						|
            {
 | 
						|
                have_unwindplan_regloc = true;
 | 
						|
                UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum,
 | 
						|
                              m_full_unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
            }
 | 
						|
 | 
						|
            // This is frame 0 and we're retrieving the PC and it's saved in a Return Address register and
 | 
						|
            // it hasn't been saved anywhere yet -- that is, it's still live in the actual register.
 | 
						|
            // Handle this specially.
 | 
						|
 | 
						|
            if (have_unwindplan_regloc == false 
 | 
						|
                && row_register_rewritten_to_return_address_reg == true 
 | 
						|
                && IsFrameZero()
 | 
						|
                && row_regnum != LLDB_INVALID_REGNUM)
 | 
						|
            {
 | 
						|
                uint32_t ra_regnum_in_lldb_reg_numbering;
 | 
						|
                if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering))
 | 
						|
                {
 | 
						|
                    lldb_private::UnwindLLDB::RegisterLocation new_regloc;
 | 
						|
                    new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
 | 
						|
                    new_regloc.location.register_number = ra_regnum_in_lldb_reg_numbering;
 | 
						|
                    m_registers[lldb_regnum] = new_regloc;
 | 
						|
                    regloc = new_regloc;
 | 
						|
                    UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0, saved in %d", lldb_regnum, ra_regnum_in_lldb_reg_numbering);
 | 
						|
                    return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // If this architecture stores the return address in a register (it defines a Return Address register)
 | 
						|
            // and we're on a non-zero stack frame and the Full UnwindPlan says that the pc is stored in the
 | 
						|
            // RA registers (e.g. lr on arm), then we know that the full unwindplan is not trustworthy -- this
 | 
						|
            // is an impossible situation and the instruction emulation code has likely been misled.  
 | 
						|
            // If this stack frame meets those criteria, we need to throw away the Full UnwindPlan that the 
 | 
						|
            // instruction emulation came up with and fall back to the architecture's Default UnwindPlan so
 | 
						|
            // the stack walk can get past this point.
 | 
						|
 | 
						|
            // Special note:  If the Full UnwindPlan was generated from the compiler, don't second-guess it 
 | 
						|
            // when we're at a call site location.
 | 
						|
 | 
						|
            // arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering
 | 
						|
            uint32_t arch_default_ra_regnum = LLDB_INVALID_REGNUM; 
 | 
						|
            if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, unwindplan_registerkind, arch_default_ra_regnum)
 | 
						|
                && arch_default_ra_regnum != LLDB_INVALID_REGNUM
 | 
						|
                && pc_regnum != LLDB_INVALID_REGNUM
 | 
						|
                && pc_regnum == lldb_regnum
 | 
						|
                && unwindplan_regloc.IsInOtherRegister()
 | 
						|
                && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum
 | 
						|
                && m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes
 | 
						|
                && !m_all_registers_available)
 | 
						|
            {
 | 
						|
                UnwindLogMsg ("%s UnwindPlan tried to restore the pc from the link register but this is a non-zero frame",
 | 
						|
                              m_full_unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
 | 
						|
                // Throw away the full unwindplan; install the arch default unwindplan
 | 
						|
                if (TryFallbackUnwindPlan())
 | 
						|
                {
 | 
						|
                    // Now re-fetch the pc value we're searching for
 | 
						|
                    uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM;
 | 
						|
                    UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
 | 
						|
                    if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg)
 | 
						|
                        && arch_default_pc_reg != LLDB_INVALID_REGNUM
 | 
						|
                        && active_row
 | 
						|
                        && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc))
 | 
						|
                    {
 | 
						|
                        have_unwindplan_regloc = true;
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        have_unwindplan_regloc = false;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    ExecutionContext exe_ctx(m_thread.shared_from_this());
 | 
						|
    Process *process = exe_ctx.GetProcessPtr();
 | 
						|
    if (have_unwindplan_regloc == false)
 | 
						|
    {
 | 
						|
        // If a volatile register is being requested, we don't want to forward the next frame's register contents
 | 
						|
        // up the stack -- the register is not retrievable at this frame.
 | 
						|
        ABI *abi = process ? process->GetABI().get() : NULL;
 | 
						|
        if (abi)
 | 
						|
        {
 | 
						|
            const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
 | 
						|
            if (reg_info && abi->RegisterIsVolatile (reg_info))
 | 
						|
            {
 | 
						|
                UnwindLogMsg ("did not supply reg location for %d (%s) because it is volatile",
 | 
						|
                    lldb_regnum, reg_info->name ? reg_info->name : "??");
 | 
						|
                return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (IsFrameZero ())
 | 
						|
        {
 | 
						|
            // This is frame 0 - we should return the actual live register context value
 | 
						|
            lldb_private::UnwindLLDB::RegisterLocation new_regloc;
 | 
						|
            new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
 | 
						|
            new_regloc.location.register_number = lldb_regnum;
 | 
						|
            m_registers[lldb_regnum] = new_regloc;
 | 
						|
            regloc = new_regloc;
 | 
						|
            UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum);
 | 
						|
            return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
 | 
						|
        return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
    }
 | 
						|
 | 
						|
    // unwindplan_regloc has valid contents about where to retrieve the register
 | 
						|
    if (unwindplan_regloc.IsUnspecified())
 | 
						|
    {
 | 
						|
        lldb_private::UnwindLLDB::RegisterLocation new_regloc;
 | 
						|
        new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
 | 
						|
        m_registers[lldb_regnum] = new_regloc;
 | 
						|
        UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
 | 
						|
        return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
    }
 | 
						|
 | 
						|
    if (unwindplan_regloc.IsSame())
 | 
						|
    {
 | 
						|
        if (IsFrameZero ())
 | 
						|
        {
 | 
						|
            UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
 | 
						|
            return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (unwindplan_regloc.IsCFAPlusOffset())
 | 
						|
    {
 | 
						|
        int offset = unwindplan_regloc.GetOffset();
 | 
						|
        regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
 | 
						|
        regloc.location.inferred_value = m_cfa + offset;
 | 
						|
        m_registers[lldb_regnum] = regloc;
 | 
						|
        UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset %d", lldb_regnum, offset);
 | 
						|
        return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
    }
 | 
						|
 | 
						|
    if (unwindplan_regloc.IsAtCFAPlusOffset())
 | 
						|
    {
 | 
						|
        int offset = unwindplan_regloc.GetOffset();
 | 
						|
        regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
 | 
						|
        regloc.location.target_memory_location = m_cfa + offset;
 | 
						|
        m_registers[lldb_regnum] = regloc;
 | 
						|
        UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset %d", lldb_regnum, offset);
 | 
						|
        return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
    }
 | 
						|
 | 
						|
    if (unwindplan_regloc.IsInOtherRegister())
 | 
						|
    {
 | 
						|
        uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
 | 
						|
        uint32_t row_regnum_in_lldb;
 | 
						|
        if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb))
 | 
						|
        {
 | 
						|
            UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
 | 
						|
            return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
        }
 | 
						|
        regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
 | 
						|
        regloc.location.register_number = row_regnum_in_lldb;
 | 
						|
        m_registers[lldb_regnum] = regloc;
 | 
						|
        UnwindLogMsg ("supplying caller's register %d, saved in register %d", lldb_regnum, row_regnum_in_lldb);
 | 
						|
        return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
    }
 | 
						|
 | 
						|
    if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression())
 | 
						|
    {
 | 
						|
        DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(),
 | 
						|
                                 unwindplan_regloc.GetDWARFExpressionLength(),
 | 
						|
                                 process->GetByteOrder(), process->GetAddressByteSize());
 | 
						|
        ModuleSP opcode_ctx;
 | 
						|
        DWARFExpression dwarfexpr (opcode_ctx, dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength());
 | 
						|
        dwarfexpr.SetRegisterKind (unwindplan_registerkind);
 | 
						|
        Value result;
 | 
						|
        Error error;
 | 
						|
        if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error))
 | 
						|
        {
 | 
						|
            addr_t val;
 | 
						|
            val = result.GetScalar().ULongLong();
 | 
						|
            if (unwindplan_regloc.IsDWARFExpression())
 | 
						|
             {
 | 
						|
                regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
 | 
						|
                regloc.location.inferred_value = val;
 | 
						|
                m_registers[lldb_regnum] = regloc;
 | 
						|
                UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsDWARFExpression)", lldb_regnum);
 | 
						|
                return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
 | 
						|
                regloc.location.target_memory_location = val;
 | 
						|
                m_registers[lldb_regnum] = regloc;
 | 
						|
                UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsAtDWARFExpression)", lldb_regnum);
 | 
						|
                return UnwindLLDB::RegisterSearchResult::eRegisterFound;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum);
 | 
						|
        return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
    }
 | 
						|
 | 
						|
    UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
 | 
						|
 | 
						|
    // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported.
 | 
						|
 | 
						|
    return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
 | 
						|
}
 | 
						|
 | 
						|
// If the Full unwindplan has been determined to be incorrect, this method will
 | 
						|
// replace it with the architecture's default unwindplan, if one is defined.
 | 
						|
// It will also find the FuncUnwinders object for this function and replace the
 | 
						|
// Full unwind method for the function there so we don't use the errant Full unwindplan
 | 
						|
// again in the future of this debug session.
 | 
						|
// We're most likely doing this because the Full unwindplan was generated by assembly
 | 
						|
// instruction profiling and the profiler got something wrong.
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::TryFallbackUnwindPlan ()
 | 
						|
{
 | 
						|
    UnwindPlan::Row::RegisterLocation unwindplan_regloc;
 | 
						|
    if (m_fallback_unwind_plan_sp.get() == NULL)
 | 
						|
        return false;
 | 
						|
 | 
						|
    UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
 | 
						|
    UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
 | 
						|
    
 | 
						|
    if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
 | 
						|
    {
 | 
						|
        FuncUnwindersSP func_unwinders_sp;
 | 
						|
        if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule())
 | 
						|
        {
 | 
						|
            func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
 | 
						|
            if (func_unwinders_sp)
 | 
						|
            {
 | 
						|
                func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        m_registers.clear();
 | 
						|
        m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
 | 
						|
        addr_t cfa_regval = LLDB_INVALID_ADDRESS;
 | 
						|
        if (ReadGPRValue (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval))
 | 
						|
        {
 | 
						|
            m_cfa = cfa_regval + active_row->GetCFAOffset ();
 | 
						|
        }
 | 
						|
 | 
						|
        UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.",
 | 
						|
                      original_full_unwind_plan_sp->GetSourceName().GetCString(), m_fallback_unwind_plan_sp->GetSourceName().GetCString());
 | 
						|
        m_fallback_unwind_plan_sp.reset();
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
// Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that
 | 
						|
// this frame called.  e.g.
 | 
						|
//
 | 
						|
//  foo () { }
 | 
						|
//  bar () { foo (); }
 | 
						|
//  main () { bar (); }
 | 
						|
//
 | 
						|
//  stopped in foo() so
 | 
						|
//     frame 0 - foo
 | 
						|
//     frame 1 - bar
 | 
						|
//     frame 2 - main
 | 
						|
//  and this RegisterContext is for frame 1 (bar) - if we want to get the pc value for frame 1, we need to ask
 | 
						|
//  where frame 0 (the "next" frame) saved that and retrieve the value.
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value)
 | 
						|
{
 | 
						|
    if (!IsValid())
 | 
						|
        return false;
 | 
						|
 | 
						|
    uint32_t lldb_regnum;
 | 
						|
    if (register_kind == eRegisterKindLLDB)
 | 
						|
    {
 | 
						|
        lldb_regnum = regnum;
 | 
						|
    }
 | 
						|
    else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindLLDB, lldb_regnum))
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
 | 
						|
    RegisterValue reg_value;
 | 
						|
    // if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers
 | 
						|
    if (IsFrameZero ())
 | 
						|
    {
 | 
						|
        if (m_thread.GetRegisterContext()->ReadRegister (reg_info, reg_value))
 | 
						|
        {
 | 
						|
            value = reg_value.GetAsUInt64();
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    bool pc_register = false;
 | 
						|
    uint32_t generic_regnum;
 | 
						|
    if (register_kind == eRegisterKindGeneric && regnum == LLDB_REGNUM_GENERIC_PC)
 | 
						|
    {
 | 
						|
        pc_register = true;
 | 
						|
    }
 | 
						|
    else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindGeneric, generic_regnum)
 | 
						|
             && generic_regnum == LLDB_REGNUM_GENERIC_PC)
 | 
						|
    {
 | 
						|
        pc_register = true;
 | 
						|
    }
 | 
						|
 | 
						|
    lldb_private::UnwindLLDB::RegisterLocation regloc;
 | 
						|
    if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, pc_register))
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
 | 
						|
    {
 | 
						|
        value = reg_value.GetAsUInt64();
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
// Find the value of a register in THIS frame
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
 | 
						|
{
 | 
						|
    if (!IsValid())
 | 
						|
        return false;
 | 
						|
 | 
						|
    const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
 | 
						|
    UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
 | 
						|
 | 
						|
    // If this is the 0th frame, hand this over to the live register context
 | 
						|
    if (IsFrameZero ())
 | 
						|
    {
 | 
						|
        UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
 | 
						|
        return m_thread.GetRegisterContext()->ReadRegister (reg_info, value);
 | 
						|
    }
 | 
						|
 | 
						|
    lldb_private::UnwindLLDB::RegisterLocation regloc;
 | 
						|
    // Find out where the NEXT frame saved THIS frame's register contents
 | 
						|
    if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
 | 
						|
        return false;
 | 
						|
 | 
						|
    return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value)
 | 
						|
{
 | 
						|
    if (!IsValid())
 | 
						|
        return false;
 | 
						|
 | 
						|
    const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
 | 
						|
    UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
 | 
						|
 | 
						|
    // If this is the 0th frame, hand this over to the live register context
 | 
						|
    if (IsFrameZero ())
 | 
						|
    {
 | 
						|
        UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
 | 
						|
        return m_thread.GetRegisterContext()->WriteRegister (reg_info, value);
 | 
						|
    }
 | 
						|
 | 
						|
    lldb_private::UnwindLLDB::RegisterLocation regloc;
 | 
						|
    // Find out where the NEXT frame saved THIS frame's register contents
 | 
						|
    if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
 | 
						|
        return false;
 | 
						|
 | 
						|
    return WriteRegisterValueToRegisterLocation (regloc, reg_info, value);
 | 
						|
}
 | 
						|
 | 
						|
// Don't need to implement this one
 | 
						|
bool
 | 
						|
RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
 | 
						|
{
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
// Don't need to implement this one
 | 
						|
bool
 | 
						|
RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp)
 | 
						|
{
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
// Retrieve the pc value for THIS from
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::GetCFA (addr_t& cfa)
 | 
						|
{
 | 
						|
    if (!IsValid())
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    if (m_cfa == LLDB_INVALID_ADDRESS)
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    cfa = m_cfa;
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
RegisterContextLLDB::SharedPtr
 | 
						|
RegisterContextLLDB::GetNextFrame () const
 | 
						|
{
 | 
						|
    RegisterContextLLDB::SharedPtr regctx;
 | 
						|
    if (m_frame_number == 0)
 | 
						|
      return regctx;
 | 
						|
    return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number - 1);
 | 
						|
}
 | 
						|
 | 
						|
RegisterContextLLDB::SharedPtr
 | 
						|
RegisterContextLLDB::GetPrevFrame () const
 | 
						|
{
 | 
						|
    RegisterContextLLDB::SharedPtr regctx;
 | 
						|
    return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number + 1);
 | 
						|
}
 | 
						|
 | 
						|
// Retrieve the address of the start of the function of THIS frame
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::GetStartPC (addr_t& start_pc)
 | 
						|
{
 | 
						|
    if (!IsValid())
 | 
						|
        return false;
 | 
						|
 | 
						|
    if (!m_start_pc.IsValid())
 | 
						|
    {
 | 
						|
        return ReadPC (start_pc);
 | 
						|
    }
 | 
						|
    start_pc = m_start_pc.GetLoadAddress (CalculateTarget().get());
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
// Retrieve the current pc value for THIS frame, as saved by the NEXT frame.
 | 
						|
 | 
						|
bool
 | 
						|
RegisterContextLLDB::ReadPC (addr_t& pc)
 | 
						|
{
 | 
						|
    if (!IsValid())
 | 
						|
        return false;
 | 
						|
 | 
						|
    if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
 | 
						|
    {
 | 
						|
        // A pc value of 0 or 1 is impossible in the middle of the stack -- it indicates the end of a stack walk.
 | 
						|
        // On the currently executing frame (or such a frame interrupted asynchronously by sigtramp et al) this may
 | 
						|
        // occur if code has jumped through a NULL pointer -- we want to be able to unwind past that frame to help
 | 
						|
        // find the bug.
 | 
						|
 | 
						|
        if (m_all_registers_available == false
 | 
						|
            && (pc == 0 || pc == 1))
 | 
						|
        {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
RegisterContextLLDB::UnwindLogMsg (const char *fmt, ...)
 | 
						|
{
 | 
						|
    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
 | 
						|
    if (log)
 | 
						|
    {
 | 
						|
        va_list args;
 | 
						|
        va_start (args, fmt);
 | 
						|
 | 
						|
        char *logmsg;
 | 
						|
        if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
 | 
						|
        {
 | 
						|
            if (logmsg)
 | 
						|
                free (logmsg);
 | 
						|
            va_end (args);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        va_end (args);
 | 
						|
 | 
						|
        log->Printf ("%*sth%d/fr%u %s",
 | 
						|
                      m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
 | 
						|
                      logmsg);
 | 
						|
        free (logmsg);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
 | 
						|
{
 | 
						|
    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
 | 
						|
    if (log && log->GetVerbose())
 | 
						|
    {
 | 
						|
        va_list args;
 | 
						|
        va_start (args, fmt);
 | 
						|
 | 
						|
        char *logmsg;
 | 
						|
        if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
 | 
						|
        {
 | 
						|
            if (logmsg)
 | 
						|
                free (logmsg);
 | 
						|
            va_end (args);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        va_end (args);
 | 
						|
 | 
						|
        log->Printf ("%*sth%d/fr%u %s",
 | 
						|
                      m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
 | 
						|
                      logmsg);
 | 
						|
        free (logmsg);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 |