diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 | 
| commit | 9e6d35490a6542f9c97607f93c2ef8ca8e03cbcc (patch) | |
| tree | dd2a1ddf0476664c2b823409c36cbccd52662ca7 /tools/debugserver/source/MacOSX/arm/DNBArchImpl.h | |
| parent | 3bd2e91faeb9eeec1aae82c64a3253afff551cfd (diff) | |
Notes
Diffstat (limited to 'tools/debugserver/source/MacOSX/arm/DNBArchImpl.h')
| -rw-r--r-- | tools/debugserver/source/MacOSX/arm/DNBArchImpl.h | 282 | 
1 files changed, 282 insertions, 0 deletions
| diff --git a/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h new file mode 100644 index 000000000000..ae8974855238 --- /dev/null +++ b/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h @@ -0,0 +1,282 @@ +//===-- DNBArchImpl.h -------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//  Created by Greg Clayton on 6/25/07. +// +//===----------------------------------------------------------------------===// + +#ifndef __DebugNubArchMachARM_h__ +#define __DebugNubArchMachARM_h__ + +#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) + +#include "DNBArch.h" + +#include <map> + +class MachThread; + +class DNBArchMachARM : public DNBArchProtocol +{ +public: +    enum { kMaxNumThumbITBreakpoints = 4 }; + +    DNBArchMachARM(MachThread *thread) : +        m_thread(thread), +        m_state(), +        m_disabled_watchpoints(), +        m_hw_single_chained_step_addr(INVALID_NUB_ADDRESS), +        m_last_decode_pc(INVALID_NUB_ADDRESS), +        m_watchpoint_hw_index(-1), +        m_watchpoint_did_occur(false), +        m_watchpoint_resume_single_step_enabled(false), +        m_saved_register_states() +    { +        m_disabled_watchpoints.resize (16); +        memset(&m_dbg_save, 0, sizeof(m_dbg_save)); +#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) +        ThumbStaticsInit(&m_last_decode_thumb); +#endif +    } + +    virtual ~DNBArchMachARM() +    { +    } + +    static void Initialize(); +    static const DNBRegisterSetInfo * +    GetRegisterSetInfo(nub_size_t *num_reg_sets); + +    virtual bool            GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value); +    virtual bool            SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value); +    virtual nub_size_t      GetRegisterContext (void *buf, nub_size_t buf_len); +    virtual nub_size_t      SetRegisterContext (const void *buf, nub_size_t buf_len); +    virtual uint32_t        SaveRegisterState (); +    virtual bool            RestoreRegisterState (uint32_t save_id); + +    virtual kern_return_t   GetRegisterState  (int set, bool force); +    virtual kern_return_t   SetRegisterState  (int set); +    virtual bool            RegisterSetStateIsValid (int set) const; + +    virtual uint64_t        GetPC(uint64_t failValue);    // Get program counter +    virtual kern_return_t   SetPC(uint64_t value); +    virtual uint64_t        GetSP(uint64_t failValue);    // Get stack pointer +    virtual void            ThreadWillResume(); +    virtual bool            ThreadDidStop(); +    virtual bool            NotifyException(MachException::Data& exc); + +    static DNBArchProtocol *Create (MachThread *thread); +    static const uint8_t *  SoftwareBreakpointOpcode (nub_size_t byte_size); +    static uint32_t         GetCPUType(); + +    virtual uint32_t        NumSupportedHardwareBreakpoints(); +    virtual uint32_t        NumSupportedHardwareWatchpoints(); +    virtual uint32_t        EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size); +    virtual bool            DisableHardwareBreakpoint (uint32_t hw_break_index); + +    virtual uint32_t        EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); +    virtual bool            DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task); +    virtual bool            DisableHardwareWatchpoint_helper (uint32_t hw_break_index, bool also_set_on_task); +    virtual bool            ReenableHardwareWatchpoint (uint32_t hw_break_index); +    virtual bool            ReenableHardwareWatchpoint_helper (uint32_t hw_break_index); + +    virtual bool            StepNotComplete (); +    virtual uint32_t        GetHardwareWatchpointHit(nub_addr_t &addr); + +#if defined (ARM_DEBUG_STATE32) && (defined (__arm64__) || defined (__aarch64__)) +    typedef arm_debug_state32_t DBG; +#else +    typedef arm_debug_state_t DBG; +#endif + +protected: + + +    kern_return_t           EnableHardwareSingleStep (bool enable); +    kern_return_t           SetSingleStepSoftwareBreakpoints (); + +    bool                    ConditionPassed(uint8_t condition, uint32_t cpsr); +#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) +    bool                    ComputeNextPC(nub_addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, nub_addr_t *targetPC); +    arm_error_t             DecodeInstructionUsingDisassembler(nub_addr_t curr_pc, uint32_t curr_cpsr, arm_decoded_instruction_t *decodedInstruction, thumb_static_data_t *thumbStaticData, nub_addr_t *next_pc); +    void                    DecodeITBlockInstructions(nub_addr_t curr_pc); +#endif +    void                    EvaluateNextInstructionForSoftwareBreakpointSetup(nub_addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, nub_addr_t *nextPC, bool *nextPCIsThumb); + + +    typedef enum RegisterSetTag +    { +        e_regSetALL = REGISTER_SET_ALL, +        e_regSetGPR, // ARM_THREAD_STATE +        e_regSetVFP, // ARM_VFP_STATE (ARM_NEON_STATE if defined __arm64__) +        e_regSetEXC, // ARM_EXCEPTION_STATE +        e_regSetDBG, // ARM_DEBUG_STATE (ARM_DEBUG_STATE32 if defined __arm64__) +        kNumRegisterSets +    } RegisterSet; + +    enum +    { +        Read = 0, +        Write = 1, +        kNumErrors = 2 +    }; +     +    typedef arm_thread_state_t GPR; +#if defined (__arm64__) || defined (__aarch64__) +    typedef arm_neon_state_t FPU; +#else +    typedef arm_vfp_state_t FPU; +#endif +    typedef arm_exception_state_t EXC; + +    static const DNBRegisterInfo g_gpr_registers[]; +    static const DNBRegisterInfo g_vfp_registers[]; +    static const DNBRegisterInfo g_exc_registers[]; +    static const DNBRegisterSetInfo g_reg_sets[]; + +    static const size_t k_num_gpr_registers; +    static const size_t k_num_vfp_registers; +    static const size_t k_num_exc_registers; +    static const size_t k_num_all_registers; +    static const size_t k_num_register_sets; + +    struct Context +    { +        GPR gpr; +        FPU vfp; +        EXC exc; +    }; + +    struct State +    { +        Context                 context; +        DBG                     dbg; +        kern_return_t           gpr_errs[2];    // Read/Write errors +        kern_return_t           vfp_errs[2];    // Read/Write errors +        kern_return_t           exc_errs[2];    // Read/Write errors +        kern_return_t           dbg_errs[2];    // Read/Write errors +        State() +        { +            uint32_t i; +            for (i=0; i<kNumErrors; i++) +            { +                gpr_errs[i] = -1; +                vfp_errs[i] = -1; +                exc_errs[i] = -1; +                dbg_errs[i] = -1; +            } +        } +        void InvalidateRegisterSetState(int set) +        { +            SetError (set, Read, -1); +        } +        kern_return_t GetError (int set, uint32_t err_idx) const +        { +            if (err_idx < kNumErrors) +            { +                switch (set) +                { +                // When getting all errors, just OR all values together to see if +                // we got any kind of error. +                case e_regSetALL:   return gpr_errs[err_idx] | +                                           vfp_errs[err_idx] | +                                           exc_errs[err_idx] | +                                           dbg_errs[err_idx] ; +                case e_regSetGPR:   return gpr_errs[err_idx]; +                case e_regSetVFP:   return vfp_errs[err_idx]; +                case e_regSetEXC:   return exc_errs[err_idx]; +                case e_regSetDBG:   return dbg_errs[err_idx]; +                default: break; +                } +            } +            return -1; +        } +        bool SetError (int set, uint32_t err_idx, kern_return_t err) +        { +            if (err_idx < kNumErrors) +            { +                switch (set) +                { +                case e_regSetALL: +                    gpr_errs[err_idx] = err; +                    vfp_errs[err_idx] = err; +                    dbg_errs[err_idx] = err; +                    exc_errs[err_idx] = err; +                    return true; + +                case e_regSetGPR: +                    gpr_errs[err_idx] = err; +                    return true; + +                case e_regSetVFP: +                    vfp_errs[err_idx] = err; +                    return true; + +                case e_regSetEXC: +                    exc_errs[err_idx] = err; +                    return true; + +                case e_regSetDBG: +                    dbg_errs[err_idx] = err; +                    return true; +                default: break; +                } +            } +            return false; +        } +        bool RegsAreValid (int set) const +        { +            return GetError(set, Read) == KERN_SUCCESS; +        } +    }; + +    kern_return_t GetGPRState (bool force); +    kern_return_t GetVFPState (bool force); +    kern_return_t GetEXCState (bool force); +    kern_return_t GetDBGState (bool force); + +    kern_return_t SetGPRState (); +    kern_return_t SetVFPState (); +    kern_return_t SetEXCState (); +    kern_return_t SetDBGState (bool also_set_on_task); + +    bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index); +    nub_addr_t GetWatchpointAddressByIndex (uint32_t hw_index); +    nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + +    class disabled_watchpoint { +    public: +        disabled_watchpoint () { addr = 0; control = 0; } +        nub_addr_t addr; +        uint32_t   control; +    }; + +protected: +    MachThread *    m_thread; +    State           m_state; +    DBG             m_dbg_save; + +    // armv8 doesn't keep the disabled watchpoint values in the debug register context like armv7; +    // we need to save them aside when we disable them temporarily. +    std::vector<disabled_watchpoint> m_disabled_watchpoints; + +    nub_addr_t      m_hw_single_chained_step_addr; +    nub_addr_t      m_last_decode_pc; + +    // The following member variables should be updated atomically. +    int32_t         m_watchpoint_hw_index; +    bool            m_watchpoint_did_occur; +    bool            m_watchpoint_resume_single_step_enabled; + +    typedef std::map<uint32_t, Context> SaveRegisterStates; +    SaveRegisterStates m_saved_register_states; +}; + +#endif    // #if defined (__arm__) +#endif    // #ifndef __DebugNubArchMachARM_h__ | 
