| /* |
| * \file ocsd_code_follower.h |
| * \brief OpenCSD : Code follower for instruction trace decode |
| * |
| * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. |
| */ |
| |
| /* |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * 3. Neither the name of the copyright holder nor the names of its contributors |
| * may be used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef ARM_OCSD_CODE_FOLLOWER_H_INCLUDED |
| #define ARM_OCSD_CODE_FOLLOWER_H_INCLUDED |
| |
| #include "opencsd/ocsd_if_types.h" |
| #include "opencsd/trc_pkt_types.h" |
| #include "comp_attach_pt_t.h" |
| #include "interfaces/trc_tgt_mem_access_i.h" |
| #include "interfaces/trc_instr_decode_i.h" |
| |
| /*! |
| * @class OcsdCodeFollower |
| * @brief The code follower looks for waypoints or addresses. |
| * |
| * Code follower used to determine the trace ranges for Atom or other waypoint |
| * elements. Uses memory accessor and I decoder to follow the code path. |
| * |
| */ |
| class OcsdCodeFollower |
| { |
| public: |
| OcsdCodeFollower(); |
| ~OcsdCodeFollower(); |
| |
| //*********** setup API |
| void initInterfaces(componentAttachPt<ITargetMemAccess> *pMemAccess, componentAttachPt<IInstrDecode> *pIDecode); |
| |
| // set information for decode operation - static or occasionally changing settings |
| // per decode values are passed as parameters into the decode API calls. |
| void setArchProfile(const ocsd_arch_profile_t profile); //!< core profile |
| void setMemSpaceAccess(const ocsd_mem_space_acc_t mem_acc_rule); //!< memory space to use for access (filtered by S/NS, EL etc). |
| void setMemSpaceCSID(const uint8_t csid); //!< memory spaces might be partitioned by CSID |
| void setISA(const ocsd_isa isa); //!< set the ISA for the decode. |
| void setDSBDMBasWP(); //!< DSB and DMB can be treated as WP in some archs. |
| |
| //********** code following API |
| |
| // standard WP search - for program flow trace |
| //ocsd_err_t followToAtomWP(idec_res_t &op_result, const ocsd_vaddr_t addrStart, const ocsd_atm_val A); |
| |
| // PTM exception code may require follow to an address |
| //ocsd_err_t followToAddress(idec_res_t &op_result, const ocsd_vaddr_t addrStart, const ocsd_atm_val A, const ocsd_vaddr_t addrMatch); |
| |
| // single instruction atom format such as ETMv3 |
| ocsd_err_t followSingleAtom(const ocsd_vaddr_t addrStart, const ocsd_atm_val A); |
| |
| // follow N instructions |
| // ocsd_err_t followNInstructions(idec_res_t &op_result) // ETMv4 Q elements |
| |
| //*********************** results API |
| const ocsd_vaddr_t getRangeSt() const; //!< inclusive start address of decoded range (value passed in) |
| const ocsd_vaddr_t getRangeEn() const; //!< exclusive end address of decoded range (first instruction _not_ executed / potential next instruction). |
| const bool hasRange() const; //!< we have a valid range executed (may be false if nacc). |
| |
| const bool hasNextAddr() const; //!< we have calulated the next address - otherwise this is needed from trace packets. |
| const ocsd_vaddr_t getNextAddr() const; //!< next address - valid if hasNextAddr() true. |
| |
| // information on last instruction executed in range. |
| const ocsd_instr_type getInstrType() const; //!< last instruction type |
| const ocsd_instr_subtype getInstrSubType() const; //!< last instruction sub-type |
| const bool isCondInstr() const; //!< is a conditional instruction |
| const bool isLink() const; //!< is a link (branch with link etc) |
| const bool ISAChanged() const; //!< next ISA different from input ISA. |
| const ocsd_isa nextISA() const; //!< ISA for next instruction |
| const uint8_t getInstrSize() const; //!< Get the last instruction size. |
| |
| // information on error conditions |
| const bool isNacc() const; //!< true if Memory Not Accessible (nacc) error occurred |
| void clearNacc(); //!< clear the nacc error flag |
| const ocsd_vaddr_t getNaccAddr() const; //!< get the nacc error address. |
| const ocsd_mem_space_acc_t getMemSpaceAccess() const; //!< get the memory space used for access. |
| |
| private: |
| bool initFollowerState(); //!< clear all the o/p data and flags, check init valid. |
| |
| ocsd_err_t decodeSingleOpCode(); //!< decode single opcode address from current m_inst_info packet |
| |
| ocsd_instr_info m_instr_info; |
| |
| ocsd_vaddr_t m_st_range_addr; //!< start of excuted range - inclusive address. |
| ocsd_vaddr_t m_en_range_addr; //!< end of executed range - exclusive address. |
| ocsd_vaddr_t m_next_addr; //!< calcuated next address (could be eo range of branch address, not set for indirect branches) |
| bool m_b_next_valid; //!< true if next address valid, false if need address from trace packets. |
| |
| //! memory space rule to use when accessing memory. |
| ocsd_mem_space_acc_t m_mem_acc_rule; |
| //! memory space csid to use when accessing memory. |
| uint8_t m_mem_space_csid; |
| |
| ocsd_vaddr_t m_nacc_address; //!< memory address that was inaccessible - failed read @ start, or during follow operation |
| bool m_b_nacc_err; //!< memory NACC error - required address was unavailable. |
| |
| //! pointers to the memory access and i decode interfaces. |
| componentAttachPt<ITargetMemAccess> *m_pMemAccess; |
| componentAttachPt<IInstrDecode> *m_pIDecode; |
| |
| }; |
| |
| #endif // ARM_OCSD_CODE_FOLLOWER_H_INCLUDED |
| |
| //*********** setup API |
| inline void OcsdCodeFollower::setArchProfile(const ocsd_arch_profile_t profile) |
| { |
| m_instr_info.pe_type = profile; |
| } |
| |
| inline void OcsdCodeFollower::setMemSpaceAccess(const ocsd_mem_space_acc_t mem_acc_rule) |
| { |
| m_mem_acc_rule = mem_acc_rule; |
| } |
| |
| inline const ocsd_mem_space_acc_t OcsdCodeFollower::getMemSpaceAccess() const |
| { |
| return m_mem_acc_rule; |
| } |
| |
| inline void OcsdCodeFollower::setMemSpaceCSID(const uint8_t csid) |
| { |
| m_mem_space_csid = csid; |
| } |
| |
| inline void OcsdCodeFollower::setISA(const ocsd_isa isa) |
| { |
| m_instr_info.isa = isa; |
| } |
| |
| inline void OcsdCodeFollower::setDSBDMBasWP() |
| { |
| m_instr_info.dsb_dmb_waypoints = 1; |
| } |
| |
| //**************************************** results API |
| inline const ocsd_vaddr_t OcsdCodeFollower::getRangeSt() const |
| { |
| return m_st_range_addr; |
| } |
| |
| inline const ocsd_vaddr_t OcsdCodeFollower::getRangeEn() const |
| { |
| return m_en_range_addr; |
| } |
| |
| inline const bool OcsdCodeFollower::hasRange() const |
| { |
| return m_st_range_addr < m_en_range_addr; |
| } |
| |
| inline const bool OcsdCodeFollower::hasNextAddr() const |
| { |
| return m_b_next_valid; |
| } |
| |
| inline const ocsd_vaddr_t OcsdCodeFollower::getNextAddr() const |
| { |
| return m_next_addr; |
| } |
| |
| // information on last instruction executed in range. |
| inline const ocsd_instr_type OcsdCodeFollower::getInstrType() const |
| { |
| return m_instr_info.type; |
| } |
| |
| inline const ocsd_instr_subtype OcsdCodeFollower::getInstrSubType() const |
| { |
| return m_instr_info.sub_type; |
| } |
| |
| inline const uint8_t OcsdCodeFollower::getInstrSize() const |
| { |
| return m_instr_info.instr_size; |
| } |
| |
| inline const bool OcsdCodeFollower::isCondInstr() const |
| { |
| return (bool)(m_instr_info.is_conditional == 1); |
| } |
| |
| inline const bool OcsdCodeFollower::isLink() const |
| { |
| return (bool)(m_instr_info.is_link == 1); |
| } |
| |
| inline const bool OcsdCodeFollower::ISAChanged() const |
| { |
| return (bool)(m_instr_info.isa != m_instr_info.next_isa); |
| } |
| |
| inline const ocsd_isa OcsdCodeFollower::nextISA() const |
| { |
| return m_instr_info.next_isa; |
| } |
| |
| // information on error conditions |
| inline const bool OcsdCodeFollower::isNacc() const |
| { |
| return m_b_nacc_err; |
| } |
| |
| inline void OcsdCodeFollower::clearNacc() |
| { |
| m_b_nacc_err = false; |
| } |
| |
| inline const ocsd_vaddr_t OcsdCodeFollower::getNaccAddr() const |
| { |
| return m_nacc_address; |
| } |
| |
| /* End of File ocsd_code_follower.h */ |