diff --git a/contrib/opencsd/decoder/include/common/comp_attach_notifier_i.h b/contrib/opencsd/decoder/include/common/comp_attach_notifier_i.h new file mode 100644 index 000000000000..e0062ef24bb9 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/comp_attach_notifier_i.h @@ -0,0 +1,63 @@ +/*! + * \file comp_attach_notifier_i.h + * \brief OpenCSD : Component attach point notifier interface. + * + * \copyright Copyright (c) 2015, 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_COMP_ATTACH_NOTIFIER_I_H_INCLUDED +#define ARM_COMP_ATTACH_NOTIFIER_I_H_INCLUDED + +/*! + * @class IComponentAttachNotifier + * @addtogroup ocsd_infrastructure + * @brief Notification interface for attachment. + * + * Interface to the componentAttachPt classes that allow notification on component + * connect and disconnect. + */ +class IComponentAttachNotifier { +public: + IComponentAttachNotifier() {}; /**< Default interface constructor */ + virtual ~IComponentAttachNotifier() {}; /**< Default interface destructor */ + + /*! + * Callback called by the componentAttachPt() classes when a component is attached + * to or detached from the attach point. + * + * @param num_attached : number of remaining components attached to the point after the + * operation that triggered the notification. + */ + virtual void attachNotify(const int num_attached) = 0; +}; + +#endif // ARM_COMP_ATTACH_NOTIFIER_I_H_INCLUDED + +/* End of File comp_attach_notifier_i.h */ diff --git a/contrib/opencsd/decoder/include/common/comp_attach_pt_t.h b/contrib/opencsd/decoder/include/common/comp_attach_pt_t.h new file mode 100644 index 000000000000..71f4c84caa2f --- /dev/null +++ b/contrib/opencsd/decoder/include/common/comp_attach_pt_t.h @@ -0,0 +1,240 @@ +/*! + * \file comp_attach_pt_t.h + * \brief OpenCSD : Component attachment point interface class. + * + * \copyright Copyright (c) 2015, 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_COMP_ATTACH_PT_T_H_INCLUDED +#define ARM_COMP_ATTACH_PT_T_H_INCLUDED + +#include +#include "opencsd/ocsd_if_types.h" + +/** @defgroup ocsd_infrastructure OpenCSD Library : Library Component Infrastructure + + @brief Classes providing library infrastructure and auxilary functionality +@{*/ + +#include "comp_attach_notifier_i.h" + +/*! + * @class componentAttachPt + * @brief Single component interface pointer attachment point. + * + * This is a class template to standardise the connections between decode components. + * + * An attachment point connects a component interface pointer to the component providing the + * attachment point. + * + * This attachment point implementation allows a single interface to be connected. + * + */ +template +class componentAttachPt { +public: + componentAttachPt(); /**< Default constructor */ + virtual ~componentAttachPt(); /**< Default destructor */ + + /*! + * Attach an interface of type T to the attachment point. + * + * @param component : interface to attach. + * + * @return ocsd_err_t : OCSD_OK if successful, OCSD_ERR_ATTACH_TOO_MANY if too many connections. + */ + virtual ocsd_err_t attach(T* component); + + /*! + * Detach component from the attachment point. + * + * @param component : Component to detach. + * + * @return virtual ocsd_err_t : OCSD_OK if successful, OCSD_ERR_ATTACH_COMP_NOT_FOUND if no match to component. + */ + virtual ocsd_err_t detach(T* component); + + + // detach current first if anything attached, connect supplied pointer, remain unattached if pointer 0 + virtual ocsd_err_t replace_first(T* component); + + /*! + * Detach all components. + */ + virtual void detach_all(); + + /*! + * Return the current (first) attached interface pointer. + * Will return 0 if nothing attached or the attachment point is disabled. + * + * @return T* : Current Interface pointer of type T or 0. + */ + virtual T* first(); + + /*! + * Return the next attached interface. + * The componentAttachPt base implmentation will always return 0 as only a single attachment is possible + * + * @return T* : Always returns 0. + */ + virtual T* next(); + + /*! + * Returns the number of interface pointers attached to this attachment point. + * + * @return int : number of component interfaces attached. + */ + virtual int num_attached(); + + /*! + * Attach a notifier interface to the attachment point. Will call back on this interface whenever + * a component is attached or detached. + * + * @param *notifier : pointer to the IComponentAttachNotifier interface. + */ + void set_notifier(IComponentAttachNotifier *notifier); + + /* enable state does not affect attach / detach, but can be used to filter access to interfaces */ + const bool enabled() const; /**< return the enabled flag. */ + void set_enabled(const bool enable); + + + /*! + * Check to see if any attachements. Will return attach state independent of enable state. + * + * @return const bool : true if attachment. + */ + const bool hasAttached() const { return m_hasAttached; }; + + + /*! + * Return both the attachment and enabled state. + * + * @return const bool : true if both has attachment and is enabled. + */ + const bool hasAttachedAndEnabled() const { return m_hasAttached && m_enabled; }; + +protected: + bool m_enabled; /**< Flag to indicate if the attachment point is enabled. */ + bool m_hasAttached; /**< Flag indicating at least one attached interface */ + IComponentAttachNotifier *m_notifier; /**< Optional attachement notifier interface. */ + T *m_comp; /**< pointer to the single attached interface */ +}; + + + +template componentAttachPt::componentAttachPt() +{ + m_comp = 0; + m_notifier = 0; + m_enabled = true; + m_hasAttached = false; +} + +template componentAttachPt::~componentAttachPt() +{ + detach_all(); +} + + +template ocsd_err_t componentAttachPt::attach(T* component) +{ + if(m_comp != 0) + return OCSD_ERR_ATTACH_TOO_MANY; + m_comp = component; + if(m_notifier) m_notifier->attachNotify(1); + m_hasAttached = true; + return OCSD_OK; +} + +template ocsd_err_t componentAttachPt::replace_first(T* component) +{ + if(m_hasAttached) + detach(m_comp); + + if(component == 0) + return OCSD_OK; + + return attach(component); +} + +template ocsd_err_t componentAttachPt::detach(T* component) +{ + if(m_comp != component) + return OCSD_ERR_ATTACH_COMP_NOT_FOUND; + m_comp = 0; + m_hasAttached = false; + if(m_notifier) m_notifier->attachNotify(0); + return OCSD_OK; +} + +template T* componentAttachPt::first() +{ + return (m_enabled) ? m_comp : 0; +} + +template T* componentAttachPt::next() +{ + return 0; +} + +template int componentAttachPt::num_attached() +{ + return ((m_comp != 0) ? 1 : 0); +} + +template void componentAttachPt::detach_all() +{ + m_comp = 0; + m_hasAttached = false; + if(m_notifier) m_notifier->attachNotify(0); +} + +template void componentAttachPt::set_notifier(IComponentAttachNotifier *notifier) +{ + m_notifier = notifier; +} + +template const bool componentAttachPt::enabled() const +{ + return m_enabled; +} + +template void componentAttachPt::set_enabled(const bool enable) +{ + m_enabled = enable; +} + + +/** @}*/ + +#endif // ARM_COMP_ATTACH_PT_T_H_INCLUDED + +/* End of File comp_attach_pt_t.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_code_follower.h b/contrib/opencsd/decoder/include/common/ocsd_code_follower.h new file mode 100644 index 000000000000..0e8691034a68 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_code_follower.h @@ -0,0 +1,231 @@ +/* + * \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 *pMemAccess, componentAttachPt *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 + + // 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. + +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 *m_pMemAccess; + componentAttachPt *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 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 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 */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr.h b/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr.h new file mode 100644 index 000000000000..ba7d8a89c46f --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr.h @@ -0,0 +1,396 @@ +/* + * \file ocsd_dcd_mngr.h + * \brief OpenCSD : Decoder manager base class. + * + * \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_DCD_MNGR_H_INCLUDED +#define ARM_OCSD_DCD_MNGR_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" +#include "common/ocsd_dcd_mngr_i.h" +#include "common/ocsd_lib_dcd_register.h" +#include "common/trc_pkt_decode_base.h" +#include "common/trc_pkt_proc_base.h" + +template +class DecoderMngrBase : public IDecoderMngr +{ +public: + DecoderMngrBase(const std::string &decoderTypeName, ocsd_trace_protocol_t builtInProtocol); + virtual ~DecoderMngrBase() {}; + + // create decoder interface. + virtual ocsd_err_t createDecoder(const int create_flags, const int instID, const CSConfig *p_config, TraceComponent **p_component); + virtual ocsd_err_t destroyDecoder(TraceComponent *p_component); + + virtual const ocsd_trace_protocol_t getProtocolType() const { return m_builtInProtocol; } + +// common + virtual ocsd_err_t attachErrorLogger(TraceComponent *pComponent, ITraceErrorLog *pIErrorLog); + +// pkt decoder + virtual ocsd_err_t attachInstrDecoder(TraceComponent *pComponent, IInstrDecode *pIInstrDec); + virtual ocsd_err_t attachMemAccessor(TraceComponent *pComponent, ITargetMemAccess *pMemAccessor); + virtual ocsd_err_t attachOutputSink(TraceComponent *pComponent, ITrcGenElemIn *pOutSink); + +// pkt processor + virtual ocsd_err_t attachPktMonitor(TraceComponent *pComponent, ITrcTypedBase *pPktRawDataMon); + virtual ocsd_err_t attachPktIndexer(TraceComponent *pComponent, ITrcTypedBase *pPktIndexer); + virtual ocsd_err_t attachPktSink(TraceComponent *pComponent, ITrcTypedBase *pPktDataInSink); + +// data input connection interface + virtual ocsd_err_t getDataInputI(TraceComponent *pComponent, ITrcDataIn **ppDataIn); + +// generate a Config object from opaque config struct pointer. + virtual ocsd_err_t createConfigFromDataStruct(CSConfig **pConfigBase, const void *pDataStruct); + +// implemented by decoder handler derived classes + virtual TraceComponent *createPktProc(const bool useInstID, const int instID) = 0; + virtual TraceComponent *createPktDecode(const bool useInstID, const int instID) { return 0; }; + virtual CSConfig *createConfig(const void *pDataStruct) = 0; + + +private: + ocsd_trace_protocol_t m_builtInProtocol; //!< Protocol ID if built in type. +}; + +template +DecoderMngrBase::DecoderMngrBase(const std::string &decoderTypeName, ocsd_trace_protocol_t builtInProtocol) +{ + OcsdLibDcdRegister *pDcdReg = OcsdLibDcdRegister::getDecoderRegister(); + if(pDcdReg) + pDcdReg->registerDecoderTypeByName(decoderTypeName,this); + m_builtInProtocol = builtInProtocol; +} + +template +ocsd_err_t DecoderMngrBase::createDecoder(const int create_flags, const int instID, const CSConfig *pConfig, TraceComponent **ppTrcComp) +{ + TraceComponent *pkt_proc = 0; + TraceComponent *pkt_dcd = 0; + bool bUseInstID = (create_flags & OCSD_CREATE_FLG_INST_ID) != 0; + bool bDecoder = (create_flags & OCSD_CREATE_FLG_FULL_DECODER) != 0; + bool bUnConfigured = (pConfig == 0); + + const Pc *pConf = dynamic_cast< const Pc * >(pConfig); + + // check inputs valid... + if((pConf == 0) && !bUnConfigured) + return OCSD_ERR_INVALID_PARAM_TYPE; + + if((create_flags & (OCSD_CREATE_FLG_PACKET_PROC | OCSD_CREATE_FLG_FULL_DECODER)) == 0) + return OCSD_ERR_INVALID_PARAM_VAL; + + // always need a packet processor + pkt_proc = createPktProc(bUseInstID, instID); + if(!pkt_proc) + return OCSD_ERR_MEM; + + // set the configuration + TrcPktProcBase *pProcBase = dynamic_cast< TrcPktProcBase *>(pkt_proc); + if(pProcBase == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + if(!bUnConfigured) + pProcBase->setProtocolConfig(pConf); + + *ppTrcComp = pkt_proc; + + // may need a packet decoder + if(bDecoder) + { + // create the decoder + pkt_dcd = createPktDecode(bUseInstID, instID); + if(!pkt_dcd) + return OCSD_ERR_MEM; + + // get the decoder base + TrcPktDecodeBase *pBase = dynamic_cast< TrcPktDecodeBase *>(pkt_dcd); + if(pBase == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + if(!bUnConfigured) + pBase->setProtocolConfig(pConf); + + // associate decoder with packet processor + // -> this means a TraceComponent with an associated component is a packet decoder. + // the associated component is the connected packet processor. + pkt_dcd->setAssocComponent(pkt_proc); + + // connect packet processor and decoder + pProcBase->getPacketOutAttachPt()->attach(pBase); + + *ppTrcComp = pkt_dcd; + } + return OCSD_OK; +} + +template +ocsd_err_t DecoderMngrBase::destroyDecoder(TraceComponent *pComponent) +{ + if(pComponent->getAssocComponent() != 0) + delete pComponent->getAssocComponent(); + delete pComponent; + return OCSD_OK; +} + +template +ocsd_err_t DecoderMngrBase::attachErrorLogger(TraceComponent *pComponent, ITraceErrorLog *pIErrorLog) +{ + return pComponent->getErrorLogAttachPt()->replace_first(pIErrorLog); +} + +template +ocsd_err_t DecoderMngrBase::attachInstrDecoder(TraceComponent *pComponent, IInstrDecode *pIInstrDec) +{ + ocsd_err_t err = OCSD_ERR_DCD_INTERFACE_UNUSED; + + if(pComponent->getAssocComponent() == 0) // no associated component - so this is a packet processor + return OCSD_ERR_INVALID_PARAM_TYPE; + + TrcPktDecodeI *pDcdI = dynamic_cast< TrcPktDecodeI * >(pComponent); + if(pDcdI == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + if(pDcdI->getUsesIDecode()) + err = pDcdI->getInstrDecodeAttachPt()->replace_first(pIInstrDec); + + return err; +} + +template +ocsd_err_t DecoderMngrBase::attachMemAccessor(TraceComponent *pComponent, ITargetMemAccess *pMemAccessor) +{ + ocsd_err_t err = OCSD_ERR_DCD_INTERFACE_UNUSED; + + if(pComponent->getAssocComponent() == 0) // no associated component - so this is a packet processor + return OCSD_ERR_INVALID_PARAM_TYPE; + + TrcPktDecodeI *pDcdI = dynamic_cast< TrcPktDecodeI * >(pComponent); + if(pDcdI == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + if(pDcdI->getUsesMemAccess()) + err = pDcdI->getMemoryAccessAttachPt()->replace_first(pMemAccessor); + + return err; +} + +template +ocsd_err_t DecoderMngrBase::attachOutputSink(TraceComponent *pComponent, ITrcGenElemIn *pOutSink) +{ + ocsd_err_t err = OCSD_ERR_INVALID_PARAM_TYPE; + + if(pComponent->getAssocComponent() == 0) // no associated component - so this is a packet processor + return err; + + TrcPktDecodeI *pDcdI = dynamic_cast< TrcPktDecodeI * >(pComponent); + if(pDcdI == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + err = pDcdI->getTraceElemOutAttachPt()->replace_first(pOutSink); + + return err; +} + +template +ocsd_err_t DecoderMngrBase::getDataInputI(TraceComponent *pComponent, ITrcDataIn **ppDataIn) +{ + // find the packet processor + TraceComponent *pPktProc = pComponent; + if(pComponent->getAssocComponent() != 0) + pPktProc = pComponent->getAssocComponent(); + + TrcPktProcI *pPPI = dynamic_cast< TrcPktProcI * >(pPktProc); + if(pPPI == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + *ppDataIn = pPPI; + + return OCSD_OK; +} + +template +ocsd_err_t DecoderMngrBase::attachPktMonitor(TraceComponent *pComponent, ITrcTypedBase *pPktRawDataMon) +{ + // find the packet processor + TraceComponent *pPktProc = pComponent; + if(pComponent->getAssocComponent() != 0) + pPktProc = pComponent->getAssocComponent(); + + // get the packet processor + TrcPktProcBase *pPktProcBase = dynamic_cast< TrcPktProcBase * >(pPktProc); + if(pPktProcBase == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + // get the interface + IPktRawDataMon

*p_If = dynamic_cast< IPktRawDataMon

* >(pPktRawDataMon); + if(p_If == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + return pPktProcBase->getRawPacketMonAttachPt()->replace_first(p_If); +} + +template +ocsd_err_t DecoderMngrBase::attachPktIndexer(TraceComponent *pComponent, ITrcTypedBase *pPktIndexer) +{ + // find the packet processor + TraceComponent *pPktProc = pComponent; + if(pComponent->getAssocComponent() != 0) + pPktProc = pComponent->getAssocComponent(); + + // get the packet processor + TrcPktProcBase *pPktProcBase = dynamic_cast< TrcPktProcBase * >(pPktProc); + if(pPktProcBase == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + // get the interface + ITrcPktIndexer *p_If = dynamic_cast< ITrcPktIndexer * >(pPktIndexer); + if(p_If == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + return pPktProcBase->getTraceIDIndexerAttachPt()->replace_first(p_If); +} + +template +ocsd_err_t DecoderMngrBase::attachPktSink(TraceComponent *pComponent, ITrcTypedBase *pPktDataInSink) +{ + // must be solo packet processor + if(pComponent->getAssocComponent() != 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + // interface must be the correct one. + IPktDataIn

*pkt_in_i = dynamic_cast< IPktDataIn

* >(pPktDataInSink); + if(pkt_in_i == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + // get the packet processor + TrcPktProcBase *pPktProcBase = dynamic_cast< TrcPktProcBase * >(pComponent); + if(pPktProcBase == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + // attach + return pPktProcBase->getPacketOutAttachPt()->replace_first(pkt_in_i); +} + +template +ocsd_err_t DecoderMngrBase::createConfigFromDataStruct(CSConfig **pConfigBase, const void *pDataStruct) +{ + CSConfig *pConfig = createConfig(pDataStruct); + if(!pConfig) + return OCSD_ERR_MEM; + *pConfigBase = pConfig; + return OCSD_OK; +} + +/****************************************************************************************************/ +/* Full decoder / packet process pair, templated base for creating decoder objects */ +/****************************************************************************************************/ + +template< class P, // Packet class. + class Pt, // Packet enum type ID. + class Pc, // Processor config class. + class PcSt, // Processor config struct type + class PktProc, // Packet processor class. + class PktDcd> // Packet decoder class. +class DecodeMngrFullDcd : public DecoderMngrBase +{ +public: + DecodeMngrFullDcd (const std::string &name, ocsd_trace_protocol_t builtInProtocol) + : DecoderMngrBase(name,builtInProtocol) {}; + + virtual ~DecodeMngrFullDcd() {}; + + virtual TraceComponent *createPktProc(const bool useInstID, const int instID) + { + TraceComponent *pComp; + if(useInstID) + pComp = new (std::nothrow) PktProc(instID); + else + pComp = new (std::nothrow) PktProc(); + return pComp; + } + + virtual TraceComponent *createPktDecode(const bool useInstID, const int instID) + { + TraceComponent *pComp; + if(useInstID) + pComp = new (std::nothrow)PktDcd(instID); + else + pComp = new (std::nothrow)PktDcd(); + return pComp; + } + + virtual CSConfig *createConfig(const void *pDataStruct) + { + return new (std::nothrow) Pc((PcSt *)pDataStruct); + } +}; + +/****************************************************************************************************/ +/* Packet processor only, templated base for creating decoder objects */ +/****************************************************************************************************/ + +template< class P, // Packet class. + class Pt, // Packet enum type ID. + class Pc, // Processor config class. + class PcSt, // Processor config struct type + class PktProc> // Packet processor class. +class DecodeMngrPktProc : public DecoderMngrBase +{ +public: + DecodeMngrPktProc (const std::string &name, ocsd_trace_protocol_t builtInProtocol) + : DecoderMngrBase(name,builtInProtocol) {}; + + virtual ~DecodeMngrPktProc() {}; + + virtual TraceComponent *createPktProc(const bool useInstID, const int instID) + { + TraceComponent *pComp; + if(useInstID) + pComp = new (std::nothrow) PktProc(instID); + else + pComp = new (std::nothrow) PktProc(); + return pComp; + } + + virtual CSConfig *createConfig(const void *pDataStruct) + { + return new (std::nothrow) Pc((PcSt *)pDataStruct); + } +}; + + + +#endif // ARM_OCSD_DCD_MNGR_H_INCLUDED + +/* End of File ocsd_dcd_mngr.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr_i.h b/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr_i.h new file mode 100644 index 000000000000..5ecbe31401a8 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr_i.h @@ -0,0 +1,98 @@ +/* + * \file ocsd_dcd_mngr_i.h + * \brief OpenCSD : Decoder manager interface. + * + * \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_DCD_MNGR_I_H_INCLUDED +#define ARM_OCSD_DCD_MNGR_I_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" +#include "common/trc_cs_config.h" +#include "common/trc_component.h" + +#include "interfaces/trc_error_log_i.h" +#include "interfaces/trc_data_raw_in_i.h" +#include "interfaces/trc_instr_decode_i.h" +#include "interfaces/trc_tgt_mem_access_i.h" +#include "interfaces/trc_gen_elem_in_i.h" +#include "interfaces/trc_abs_typed_base_i.h" + +class IDecoderMngr +{ +public: + IDecoderMngr() {}; + virtual ~IDecoderMngr() {}; + +// create and destroy decoders + virtual ocsd_err_t createDecoder(const int create_flags, const int instID, const CSConfig *p_config, TraceComponent **ppComponent) = 0; + virtual ocsd_err_t destroyDecoder(TraceComponent *pComponent) = 0; + + //! Get the built in protocol type ID managed by this instance - extern for custom decoders + virtual const ocsd_trace_protocol_t getProtocolType() const = 0; + +// connect decoders to other components - (replace current / 0 pointer value to detach ); +// compatible with all decoders + //!attach error logger to ptk-processor, or both of pkt processor and pkt decoder pair + virtual ocsd_err_t attachErrorLogger(TraceComponent *pComponent, ITraceErrorLog *pIErrorLog) = 0; + +// pkt decoder only + //! attach instruction decoder to pkt decoder + virtual ocsd_err_t attachInstrDecoder(TraceComponent *pComponent, IInstrDecode *pIInstrDec) = 0; + + //! attach memory accessor to pkt decoder + virtual ocsd_err_t attachMemAccessor(TraceComponent *pComponent, ITargetMemAccess *pMemAccessor) = 0; + + //! attach generic output interface to pkt decoder + virtual ocsd_err_t attachOutputSink(TraceComponent *pComponent, ITrcGenElemIn *pOutSink) = 0; + +// pkt processor only + //! attach a raw packet monitor to pkt processor (solo pkt processor, or pkt processor part of pair) + virtual ocsd_err_t attachPktMonitor(TraceComponent *pComponent, ITrcTypedBase *pPktRawDataMon) = 0; + + //! attach a packet indexer to pkt processor (solo pkt processor, or pkt processor part of pair) + virtual ocsd_err_t attachPktIndexer(TraceComponent *pComponent, ITrcTypedBase *pPktIndexer) = 0; + + //! attach a packet data sink to pkt processor output (solo pkt processor only - instead of decoder when pkt processor only created.) + virtual ocsd_err_t attachPktSink(TraceComponent *pComponent, ITrcTypedBase *pPktDataInSink) = 0; + +// data input connection interface + //! get raw data input interface from packet processor + virtual ocsd_err_t getDataInputI(TraceComponent *pComponent, ITrcDataIn **ppDataIn) = 0; + +// create configuration from data structure + virtual ocsd_err_t createConfigFromDataStruct(CSConfig **pConfigBase, const void *pDataStruct) = 0; + +}; + +#endif // ARM_OCSD_DCD_MNGR_I_H_INCLUDED + +/* End of File ocsd_dcd_mngr.h */ \ No newline at end of file diff --git a/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h b/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h new file mode 100644 index 000000000000..496f8e5d72e0 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h @@ -0,0 +1,406 @@ +/*! + * \file ocsd_dcd_tree.h + * \brief OpenCSD : Trace Decode Tree. + * + * \copyright Copyright (c) 2015, 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_DCD_TREE_H_INCLUDED +#define ARM_OCSD_DCD_TREE_H_INCLUDED + +#include +#include + +#include "opencsd.h" +#include "ocsd_dcd_tree_elem.h" + +/** @defgroup dcd_tree OpenCSD Library : Trace Decode Tree. + @brief Create a multi source decode tree for a single trace capture buffer. + + Use to create a connected set of decoder objects to decode a trace buffer. + There may be multiple trace sources within the capture buffer. + +@{*/ + +/*! + * @class DecodeTree + * @brief Class to manage the decoding of data from a single trace sink . + * + * Provides functionality to build a tree of decode objects capable of decoding + * multiple trace sources within a single trace sink (capture buffer). + * + */ +class DecodeTree : public ITrcDataIn +{ +public: +/** @name Creation and Destruction +@{*/ + DecodeTree(); //!< default constructor + ~DecodeTree(); //!< default destructor + + /*! + * @brief Create a decode tree. + * Automatically creates a trace frame deformatter if required and a default error log component. + * + * @param src_type : Data stream source type, can be CoreSight frame formatted trace, or single demuxed trace data stream, + * @param formatterCfgFlags : Configuration flags for trace de-formatter. + * + * @return DecodeTree * : pointer to the decode tree, 0 if creation failed. + */ + static DecodeTree *CreateDecodeTree(const ocsd_dcd_tree_src_t src_type, const uint32_t formatterCfgFlags); + + /** @brief Destroy a decode tree */ + static void DestroyDecodeTree(DecodeTree *p_dcd_tree); + +/** @}*/ + + +/** @name Error and element Logging +@{*/ + /** @brief The library default error logger */ + static ocsdDefaultErrorLogger* getDefaultErrorLogger() { return &s_error_logger; }; + + /** the current error logging interface in use */ + static ITraceErrorLog *getCurrentErrorLogI() { return s_i_error_logger; }; + + /** set an alternate error logging interface. */ + static void setAlternateErrorLogger(ITraceErrorLog *p_error_logger); + + /** get the list of packet printers for this decode tree */ + std::vector &getPrinterList() { return m_printer_list; }; + + /** add a protocol packet printer */ + ocsd_err_t addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter **ppPrinter); + + /** add a raw frame printer */ + ocsd_err_t addRawFramePrinter(RawFramePrinter **ppPrinter, uint32_t flags); + + /** add a generic element output printer */ + ocsd_err_t addGenElemPrinter(TrcGenericElementPrinter **ppPrinter); + + + +/** @}*/ + + +/** @name Trace Data Path +@{*/ + /** @brief Trace Data input interface (ITrcDataIn) + + Decode tree implements the data in interface : ITrcDataIn . + Captured raw trace data is passed into the deformatter and decoders via this method. + */ + virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + + /*! + * @brief Decoded Trace output. + * + * Client trace analysis program attaches a generic trace element interface to + * receive the output from the trace decode operations. + * + * @param *i_gen_trace_elem : Pointer to the interface. + */ + void setGenTraceElemOutI(ITrcGenElemIn *i_gen_trace_elem); + + /*! @brief Return the connected generic element interface */ + ITrcGenElemIn *getGenTraceElemOutI() const { return m_i_gen_elem_out; }; + +/** @}*/ + +/** @name Decoder Management +@{*/ + + /*! + * Creates a decoder that is registered with the library under the supplied name. + * createFlags determine if a full packet processor / packet decoder pair or + * packet processor only is created. + * Uses the supplied configuration structure. + * + * @param &decoderName : registered name of decoder + * @param createFlags : Decoder creation options. + * @param *pConfig : Pointer to a valid configuration structure for the named decoder. + * + * @return ocsd_err_t : Library error code or OCSD_OK if successful. + */ + ocsd_err_t createDecoder(const std::string &decoderName, const int createFlags, const CSConfig *pConfig); + + /* */ + /*! + * Remove a decoder / packet processor attached to an Trace ID output on the frame de-mux. + * + * Once removed another decoder can be created that has a CSConfig using that ID. + * + * @param CSID : Trace ID to remove. + * + * @return ocsd_err_t : Library error code or OCSD_OK if successful. + */ + ocsd_err_t removeDecoder(const uint8_t CSID); + + +/* get decoder elements currently in use */ + + /*! + * Find a decode tree element associated with a specific CoreSight trace ID. * + */ + DecodeTreeElement *getDecoderElement(const uint8_t CSID) const; + /* iterate decoder elements */ + + /*! + * Decode tree iteration. Return the first tree element 0 if no elements avaiable. + * + * @param &elemID : CoreSight Trace ID associated with this element + */ + DecodeTreeElement *getFirstElement(uint8_t &elemID); + /*! + * Return the next tree element - or 0 if no futher elements avaiable. + * + * @param &elemID : CoreSight Trace ID associated with this element + */ + DecodeTreeElement *getNextElement(uint8_t &elemID); + +/* set key interfaces - attach / replace on any existing tree components */ + + /*! + * Set an ARM instruction opcode decoder. + * + * @param *i_instr_decode : Pointer to the interface. + */ + void setInstrDecoder(IInstrDecode *i_instr_decode); + /*! + * Set a target memory access interface - used to access program image memory for instruction + * trace decode. + * + * @param *i_mem_access : Pointer to the interface. + */ + void setMemAccessI(ITargetMemAccess *i_mem_access); + + +/** @}*/ + +/** @name Memory Access Mapper + + A memory mapper is used to organise a collection of memory accessor objects that contain the + memory images for different areas of traced instruction memory. These areas could be the executed + program and a set of loaded .so libraries for example - each of which would have code sections in + different memory locations. + + A memory accessor represents a snapshot of an area of memory as it appeared during trace capture, + for a given memory space. Memory spaces are described by the ocsd_mem_space_acc_t enum. The most + general memory space is OCSD_MEM_SPACE_ANY. This represents memory that can be secure or none-secure, + available at any exception level. + + The memory mapper will not allow two accessors to overlap in the same memory space. + + The trace decdoer will access memory with a memory space parameter that represents the current core + state - the mapper will find the closest memory space match for the address. + + e.g. if the core is accessing secure EL3, then the most specialised matching space will be accessed. + If an EL3 space matches that will be used, otherwise the any secure, and finally _ANY. + + It is no necessary for clients to register memory accessors for all spaces - _ANY will be sufficient + in many cases. + + +@{*/ + + /* */ + /*! + * This creates a memory mapper within the decode tree. + * + * @param type : defaults to MEMACC_MAP_GLOBAL (only type available at present) + * + * @return ocsd_err_t : Library error code or OCSD_OK if successful. + */ + ocsd_err_t createMemAccMapper(memacc_mapper_t type = MEMACC_MAP_GLOBAL); + + /*! + * Get a pointer to the memory mapper. Allows a client to add memory accessors directly to the mapper. + * @return TrcMemAccMapper : Pointer to the mapper. + */ + TrcMemAccMapper *getMemAccMapper() const { return m_default_mapper; }; + + /*! + * Set an external mapper rather than create a mapper in the decode tree. + * Setting this will also destroy any internal mapper that was previously created. + * + * @param pMapper : pointer to the mapper to add. + */ + void setExternMemAccMapper(TrcMemAccMapper * pMapper); + + /*! + * Return true if a mapper has been set (internal or external + */ + const bool hasMemAccMapper() const { return (bool)(m_default_mapper != 0); }; + + void logMappedRanges(); //!< Log the mapped memory ranges to the default message logger. + +/** @}*/ + +/** @name Memory Accessors + A memory accessor represents a snapshot of an area of memory as it appeared during trace capture. + + Memory spaces represent either common global memory, or Secure / none-secure and EL specific spaces. + +@{*/ + + /*! + * Creates a memory accessor for a memory block in the supplied buffer and adds to the current mapper. + * + * @param address : Start address for the memory block in the memory map. + * @param mem_space : Memory space + * @param *p_mem_buffer : start of the buffer. + * @param mem_length : length of the buffer. + * + * @return ocsd_err_t : Library error code or OCSD_OK if successful. + */ + ocsd_err_t addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length); + + /*! + * Creates a memory accessor for a memory block supplied as a contiguous binary data file, and adds to the current mapper. + * + * @param address : Start address for the memory block in the memory map. + * @param mem_space : Memory space + * @param &filepath : Path to the binary data file + * + * @return ocsd_err_t : Library error code or OCSD_OK if successful. + */ + ocsd_err_t addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath); + + /*! + * Creates a memory accessor for a memory block supplied as a one or more memory regions in a binary file. + * Region structures are created that describe the memory start address, the offset within the binary file + * for that address, and the length of the region. This accessor can be used to point to the code section + * in a program file for example. + * + * @param *region_array : array of valid memory regions in the file. + * @param num_regions : number of regions + * @param mem_space : Memory space + * @param &filepath : Path to the binary data file + * + * @return ocsd_err_t : Library error code or OCSD_OK if successful. + */ + ocsd_err_t addBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath); + + /*! + * This memory accessor allows the client to supply a callback function for the region + * defined by the start and end addresses. This can be used to supply a custom memory accessor, + * or to directly access memory if the decode is running live on a target system. + * + * @param st_address : start address of region. + * @param en_address : end address of region. + * @param mem_space : Memory space + * @param p_cb_func : Callback function + * @param *p_context : client supplied context information + * + * @return ocsd_err_t : Library error code or OCSD_OK if successful. + */ + ocsd_err_t addCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context); + + /*! + * Remove the memory accessor from the map, that begins at the given address, for the memory space provided. + * + * @param address : Start address of the memory accessor. + * @param mem_space : Memory space for the memory accessor. + * + * @return ocsd_err_t : Library error code or OCSD_OK if successful. + */ + ocsd_err_t removeMemAccByAddress(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space); + +/** @}*/ + +/** @name CoreSight Trace Frame De-mux +@{*/ + + //! Get the Trace Frame de-mux. + TraceFormatterFrameDecoder *getFrameDeformatter() const { return m_frame_deformatter_root; }; + + + /*! @brief ID filtering - sets the output filter on the trace deformatter. + + Only supplied IDs will be decoded. + + No effect if no decoder attached for the ID + + @param ids : Vector of CS Trace IDs + */ + ocsd_err_t setIDFilter(std::vector &ids); // only supplied IDs will be decoded + + ocsd_err_t clearIDFilter(); //!< remove filter, all IDs will be decoded + +/** @}*/ + +private: + bool initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCfgFlags); + const bool usingFormatter() const { return (bool)(m_dcd_tree_type == OCSD_TRC_SRC_FRAME_FORMATTED); }; + void setSingleRoot(TrcPktProcI *pComp); + ocsd_err_t createDecodeElement(const uint8_t CSID); + void destroyDecodeElement(const uint8_t CSID); + void destroyMemAccMapper(); + + ocsd_dcd_tree_src_t m_dcd_tree_type; + + IInstrDecode *m_i_instr_decode; + ITargetMemAccess *m_i_mem_access; + ITrcGenElemIn *m_i_gen_elem_out; //!< Output interface for generic elements from decoder. + + ITrcDataIn* m_i_decoder_root; /*!< root decoder object interface - either deformatter or single packet processor */ + + TraceFormatterFrameDecoder *m_frame_deformatter_root; + + DecodeTreeElement *m_decode_elements[0x80]; + + uint8_t m_decode_elem_iter; + + TrcMemAccMapper *m_default_mapper; //!< the mem acc mapper to use + bool m_created_mapper; //!< true if created by decode tree object + + std::vector m_printer_list; //!< list of packet printers. + + /* global error logger - all sources */ + static ITraceErrorLog *s_i_error_logger; + static std::list s_trace_dcd_trees; + + /**! default error logger */ + static ocsdDefaultErrorLogger s_error_logger; + + /**! default instruction decoder */ + static TrcIDecode s_instruction_decoder; +}; + +/** @}*/ + +#endif // ARM_OCSD_DCD_TREE_H_INCLUDED + +/* End of File ocsd_dcd_tree.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_dcd_tree_elem.h b/contrib/opencsd/decoder/include/common/ocsd_dcd_tree_elem.h new file mode 100644 index 000000000000..2b609fbf04f8 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_dcd_tree_elem.h @@ -0,0 +1,112 @@ +/*! + * \file ocsd_dcd_tree_elem.h + * \brief OpenCSD : Decode tree element. + * + * \copyright Copyright (c) 2015, 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_DCD_TREE_ELEM_H_INCLUDED +#define ARM_OCSD_DCD_TREE_ELEM_H_INCLUDED + +#include "common/ocsd_dcd_mngr_i.h" +#include "common/trc_component.h" + +/** @addtogroup dcd_tree +@{*/ + +/*! @struct _decoder_elements + * @brief Decode tree element base structure. + * + * Element describes the protocol supported for this element and + * contains pointers to the decoder manager interface and component handle. + */ +typedef struct _decoder_elements +{ + std::string dcd_name; //!< Registered name of the decoder + TraceComponent *dcd_handle; //!< handle to the decoder object + IDecoderMngr *dcd_mngr; //!< pointer to the decoder manager interface for the decodcer + ocsd_trace_protocol_t protocol;//!< protocol type + bool created; /**< decode tree created this element (destroy it on tree destruction) */ +} decoder_element; + +/*! + * @class DecodeTreeElement + * @brief Decode tree element + * + * Decoder tree elements are references to individual decoders in the tree. + * These allow iteration of all decoders in the tree to perform common operations. + * + * The DecodeTree contains a list of elements. + */ +class DecodeTreeElement : protected decoder_element +{ +public: + DecodeTreeElement(); + ~DecodeTreeElement() {}; + + void SetDecoderElement(const std::string &name, IDecoderMngr *dcdMngr, TraceComponent *pHandle, bool bCreated); + void DestroyElem(); + + const std::string &getDecoderTypeName() { return dcd_name; }; + IDecoderMngr *getDecoderMngr() { return dcd_mngr; }; + ocsd_trace_protocol_t getProtocol() const { return protocol; }; + TraceComponent *getDecoderHandle() { return dcd_handle; }; +}; + +inline DecodeTreeElement::DecodeTreeElement() +{ + dcd_name = "unknown"; + dcd_mngr = 0; + dcd_handle = 0; + protocol = OCSD_PROTOCOL_END; + created = false; +} + +inline void DecodeTreeElement::SetDecoderElement(const std::string &name, IDecoderMngr *dcdMngr, TraceComponent *pHandle, bool bCreated) +{ + dcd_name = name; + dcd_mngr = dcdMngr; + dcd_handle = pHandle; + protocol = OCSD_PROTOCOL_UNKNOWN; + if(dcd_mngr) + protocol = dcd_mngr->getProtocolType(); + created = bCreated; +} + +inline void DecodeTreeElement::DestroyElem() +{ + if(created && (dcd_mngr != 0) && (dcd_handle != 0)) + dcd_mngr->destroyDecoder(dcd_handle); +} + +/** @}*/ +#endif // ARM_OCSD_DCD_TREE_ELEM_H_INCLUDED + +/* End of File ocsd_dcd_tree_elem.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_error.h b/contrib/opencsd/decoder/include/common/ocsd_error.h new file mode 100644 index 000000000000..e547f4878033 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_error.h @@ -0,0 +1,116 @@ +/*! + * \file ocsd_error.h + * \brief OpenCSD : Library Error class + * + * \copyright Copyright (c) 2015, 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_ERROR_H_INCLUDED +#define ARM_OCSD_ERROR_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" +#include +/** @ingroup ocsd_infrastructure +@{*/ + +/*! + * @class ocsdError + * + * This class is the error object for the Ocsd. + * + * Errors are created with a severity (ocsd_err_severity_t) and a standard ocsd_err_t error code. + * Errors can optionally be created with a trace index (offset from start of capture buffer), and + * trace CoreSight source channel ID. + * + * A custom error message can be appended to the error. + * + * The ocsdError class contains a static function to output a formatted string representation of an error. + * + */ +class ocsdError { +public: + ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code); /**< Default error constructor with severity and error code. */ + ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx); /**< Constructor with optional trace index. */ + ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const uint8_t chan_id); /**< Constructor with optional trace index and channel ID. */ + ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const std::string &msg); /**< Default error constructor with severity and error code - plus message. */ + ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const std::string &msg); /**< Constructor with optional trace index - plus message. */ + ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const uint8_t chan_id, const std::string &msg); /**< Constructor with optional trace index and channel ID - plus message. */ + + ocsdError(const ocsdError *pError); /**< Copy constructor */ + ocsdError(const ocsdError &Error); /**< Copy constructor */ + ~ocsdError(); /**< Destructor */ + + ocsdError& operator=(const ocsdError *p_err); + ocsdError& operator=(const ocsdError &err); + + void setMessage(const std::string &msg) { m_err_message = msg; }; /**< Set custom error message */ + const std::string &getMessage() const { return m_err_message; }; /**< Get custom error message */ + + const ocsd_err_t getErrorCode() const { return m_error_code; }; /**< Get error code. */ + const ocsd_err_severity_t getErrorSeverity() const { return m_sev; }; /**< Get error severity. */ + const ocsd_trc_index_t getErrorIndex() const { return m_idx; }; /**< Get trace index associated with the error. */ + const uint8_t getErrorChanID() const { return m_chan_ID; }; /**< Get the trace source channel ID associated with the error. */ + + static const std::string getErrorString(const ocsdError &error); /**< Generate a formatted error string for the supplied error. */ + +private: + static void appendErrorDetails(std::string &errStr, const ocsdError &error); /**< build the error string. */ + ocsdError(); /**< Make no parameter default constructor inaccessible. */ + + ocsd_err_t m_error_code; /**< Error code for this error */ + ocsd_err_severity_t m_sev; /**< severity for this error */ + ocsd_trc_index_t m_idx; /**< Trace buffer index associated with this error (optional) */ + uint8_t m_chan_ID; /**< trace source ID associated with this error (optional) */ + + std::string m_err_message; /**< Additional text associated with this error (optional) */ +}; + +inline ocsdError& ocsdError::operator=(const ocsdError *p_err) +{ + this->m_error_code = p_err->getErrorCode(); + this->m_sev = p_err->getErrorSeverity(); + this->m_idx = p_err->getErrorIndex(); + this->m_chan_ID = p_err->getErrorChanID(); + this->m_err_message = p_err->getMessage(); + return *this; +} + +inline ocsdError& ocsdError::operator=(const ocsdError &err) +{ + return (*this = &err); +} + + +/** @}*/ + +#endif // ARM_OCSD_ERROR_H_INCLUDED + +/* End of File ocsd_error.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_error_logger.h b/contrib/opencsd/decoder/include/common/ocsd_error_logger.h new file mode 100644 index 000000000000..d60139726efb --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_error_logger.h @@ -0,0 +1,89 @@ +/*! + * \file ocsd_error_logger.h + * \brief OpenCSD : Library error logger. + * + * \copyright Copyright (c) 2015, 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_ERROR_LOGGER_H_INCLUDED +#define ARM_OCSD_ERROR_LOGGER_H_INCLUDED + +#include +#include +#include + +#include "interfaces/trc_error_log_i.h" +#include "ocsd_error.h" +#include "ocsd_msg_logger.h" + +class ocsdDefaultErrorLogger : public ITraceErrorLog +{ +public: + ocsdDefaultErrorLogger(); + virtual ~ocsdDefaultErrorLogger(); + + bool initErrorLogger(const ocsd_err_severity_t verbosity, bool bCreateOutputLogger = false); + + virtual ocsdMsgLogger *getOutputLogger() { return m_output_logger; }; + virtual void setOutputLogger(ocsdMsgLogger *pLogger); + + virtual const ocsd_hndl_err_log_t RegisterErrorSource(const std::string &component_name); + + virtual void LogError(const ocsd_hndl_err_log_t handle, const ocsdError *Error); + virtual void LogMessage(const ocsd_hndl_err_log_t handle, const ocsd_err_severity_t filter_level, const std::string &msg ); + + virtual const ocsd_err_severity_t GetErrorLogVerbosity() const { return m_Verbosity; }; + + virtual ocsdError *GetLastError() { return m_lastErr; }; + virtual ocsdError *GetLastIDError(const uint8_t chan_id) + { + if(OCSD_IS_VALID_CS_SRC_ID(chan_id)) + return m_lastErrID[chan_id]; + return 0; + }; + +private: + void CreateErrorObj(ocsdError **ppErr, const ocsdError *p_from); + + ocsdError *m_lastErr; + ocsdError *m_lastErrID[0x80]; + + ocsd_err_severity_t m_Verbosity; + + ocsdMsgLogger *m_output_logger; // pointer to a standard message output logger; + bool m_created_output_logger; // true if this class created it's own logger; + + std::vector m_error_sources; +}; + + +#endif // ARM_OCSD_ERROR_LOGGER_H_INCLUDED + +/* End of File ocsd_error_logger.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_gen_elem_list.h b/contrib/opencsd/decoder/include/common/ocsd_gen_elem_list.h new file mode 100644 index 000000000000..0ff1bd59cbbe --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_gen_elem_list.h @@ -0,0 +1,153 @@ +/* + * \file ocsd_gen_elem_stack.h + * \brief OpenCSD : Generic element output stack. + * + * \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. + */ + +#include +#include "trc_gen_elem.h" +#include "comp_attach_pt_t.h" +#include "interfaces/trc_gen_elem_in_i.h" + +/*! + * @class OcsdGenElemList + * @brief Maintain a list of elements to be output + * + * Each incoming packet can result in multiple output elements. + * These are stacked in this class prior to entering the output phase of processing. + * + * This should remove some of the requirement on the packet processing to be re-enterant, + * simplifying this code. + * + * Last element(s) on this stack can be marked pending to allow for later cancellation. + * (This required for cancel element in ETMv3 exeception branch). + * + * The "list" is actually a ring buffer - maintaining pointers to indicate current valid elements. + * This buffer can increase on demand, but will only be released at the end of a decode session. + */ +class OcsdGenElemList +{ +public: + OcsdGenElemList(); + ~OcsdGenElemList(); + + void initSendIf(componentAttachPt *pGenElemIf); + void initCSID(const uint8_t CSID) { m_CSID = CSID; }; + + void reset(); //!< reset the element list. + + OcsdTraceElement *getNextElem(const ocsd_trc_index_t trc_pkt_idx); //!< get next free element on the stack (add one to the output) + const int getNumElem() const; //!< return the total number of elements on the stack (inlcuding any pended ones). + + const ocsd_gen_trc_elem_t getElemType(const int entryN) const; //!< get the type for the nth element in the stack (0 indexed) + + void pendLastNElem(int numPend); //!< Last element to be pended prior to cancel/commit decision. + void commitAllPendElem(); //!< commit all pended elements. + void cancelPendElem(); //!< cancel the last pended element on the stack. + const int numPendElem() const; //!< return the number of pended elements. + + /*! Send all of the none pended elements + Stop sending when all sent or _CONT response. + */ + ocsd_datapath_resp_t sendElements(); + const bool elemToSend() const; //!< true if any none-pending elements left to send. + +private: + + void growArray(); + const int getAdjustedIdx(int idxIn) const; //!< get adjusted index into circular buffer. + + + // list element contains pointer and byte index in trace stream + typedef struct _elemPtr { + OcsdTraceElement *pElem; //!< pointer to the listed trace element + ocsd_trc_index_t trc_pkt_idx; //!< packet index in the trace stream + } elemPtr_t; + + elemPtr_t *m_pElemArray; //!< an array of pointers to elements. + int m_elemArraySize; //!< number of element pointers in the array + + int m_firstElemIdx; //!< internal index in array of first element in use. + int m_numUsed; //!< number of elements in use + int m_numPend; //!< internal count of pended elements. + + uint8_t m_CSID; + + componentAttachPt *m_sendIf; //!< element send interface. +}; + +inline const int OcsdGenElemList::getAdjustedIdx(int idxIn) const +{ + if(idxIn >= m_elemArraySize) + idxIn -= m_elemArraySize; + return idxIn; +} + +inline const int OcsdGenElemList::getNumElem() const +{ + return m_numUsed; +} + +inline const int OcsdGenElemList::numPendElem() const +{ + return m_numPend; +} + +inline void OcsdGenElemList::pendLastNElem(int numPend) +{ + if(numPend >= getNumElem()) + m_numPend = numPend; +} + +inline void OcsdGenElemList::commitAllPendElem() +{ + m_numPend = 0; +} + +inline void OcsdGenElemList::cancelPendElem() +{ + if(m_numPend > 0) + { + m_numUsed -= m_numPend; + } +} + +inline const bool OcsdGenElemList::elemToSend() const +{ + return ((getNumElem() - m_numPend) > 0); +} + +inline void OcsdGenElemList::initSendIf(componentAttachPt *pGenElemIf) +{ + m_sendIf = pGenElemIf; +} + +/* End of File ocsd_gen_elem_stack.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_lib_dcd_register.h b/contrib/opencsd/decoder/include/common/ocsd_lib_dcd_register.h new file mode 100644 index 000000000000..6ba4cf82240a --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_lib_dcd_register.h @@ -0,0 +1,131 @@ +/* + * \file ocsd_lib_dcd_register.h + * \brief OpenCSD : Library decoder registration and management. + * + * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. + */ + +#ifndef ARM_OCSD_LIB_DCD_REGISTER_H_INCLUDED +#define ARM_OCSD_LIB_DCD_REGISTER_H_INCLUDED + + +/* + * 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. + */ + +#include + +#include "opencsd/ocsd_if_types.h" +#include "common/ocsd_dcd_mngr_i.h" + +/*! + * @class OcsdLibDcdRegister : Registers decoders with the library + * + * library decoder register class allows decoders to be registered by name, and the register allows clients to access + * the list of names of registerd decoders. + * + * The decoders in the library are accessed through the decoder manager interface. This provides a set of functions to allow + * the creation, manipulation and destruction of registered decoders + * + */ +class OcsdLibDcdRegister +{ +public: + static OcsdLibDcdRegister *getDecoderRegister(); + + static void deregisterAllDecoders(); //!< library cleanup - deregisters decoder managers and destroys the register object. + static const ocsd_trace_protocol_t getNextCustomProtocolID(); + static void releaseLastCustomProtocolID(); + + const ocsd_err_t registerDecoderTypeByName(const std::string &name, IDecoderMngr *p_decoder_fact); //!< register a decoder manager interface + const ocsd_err_t getDecoderMngrByName(const std::string &name, IDecoderMngr **p_decoder_mngr); + const ocsd_err_t getDecoderMngrByType(const ocsd_trace_protocol_t decoderType, IDecoderMngr **p_decoder_mngr); + + const bool isRegisteredDecoder(const std::string &name); + const bool getFirstNamedDecoder(std::string &name); + const bool getNextNamedDecoder(std::string &name); + + const bool isRegisteredDecoderType(const ocsd_trace_protocol_t decoderType); + +private: + void registerBuiltInDecoders(); //!< register the list of build in decoder managers on first access of getDecoderMngrByName. + void deRegisterCustomDecoders(); //!< delete all custom decoders registered with the library. + + std::map m_decoder_mngrs; //!< map linking names to decoder manager interfaces. + std::map::const_iterator m_iter; //!< iterator for name search. + + std::map m_typed_decoder_mngrs; //!< map linking decoder managers to protocol type ID + + // cache last found by type to speed up repeated quries on same object. + IDecoderMngr *m_pLastTypedDecoderMngr; //!< last manager we found by type + + + + // singleton pattern - need just one of these in the library - ensure all default constructors are private. + OcsdLibDcdRegister(); + OcsdLibDcdRegister(OcsdLibDcdRegister const &) {}; + OcsdLibDcdRegister& operator=(OcsdLibDcdRegister const &){ return *this; }; + ~OcsdLibDcdRegister(); + + static OcsdLibDcdRegister *m_p_libMngr; + static bool m_b_registeredBuiltins; + static ocsd_trace_protocol_t m_nextCustomProtocolID; +}; + +/*! + * Typedef of function signature to create a decoder manager. + * + * @param *name : Registered name of the decoder. + */ +typedef IDecoderMngr *(*CreateMngr)(const std::string &name); + +/*! + * Template function to create a specific decoder manager class object. + * + * @param &name : Registered name of the decoder. + * + * @return IDecoderMngr * : pointer to the decoder manager base class interface. + */ +template IDecoderMngr *createManagerInst(const std::string &name) +{ + return new (std::nothrow)T(name); +} + +/*! Structure to contain the information needed to create and register a builtin decoder + * manager with the library + */ +typedef struct built_in_decoder_info { + IDecoderMngr *pMngr; //!< pointer to created decoder manager + CreateMngr PFn; //!< function to create the decoder manager. + const char *name; //!< registered name of the decoder. +} built_in_decoder_info_t; + +//! Define to use to fill in an array of built_in_decoder_info_t structures. +#define CREATE_BUILTIN_ENTRY(C,N) { 0, createManagerInst, N } + +#endif // ARM_OCSD_LIB_DCD_REGISTER_H_INCLUDED + +/* End of File ocsd_lib_dcd_register.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_msg_logger.h b/contrib/opencsd/decoder/include/common/ocsd_msg_logger.h new file mode 100644 index 000000000000..c40af9189aa7 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_msg_logger.h @@ -0,0 +1,84 @@ +/*! + * \file ocsd_msg_logger.h + * \brief OpenCSD : Generic Message logger / printer + * + * \copyright Copyright (c) 2015, 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_MSG_LOGGER_H_INCLUDED +#define ARM_OCSD_MSG_LOGGER_H_INCLUDED + +#include +#include + +class ocsdMsgLogStrOutI +{ +public: + ocsdMsgLogStrOutI() {}; + virtual ~ocsdMsgLogStrOutI() {}; + + virtual void printOutStr(const std::string &outStr) = 0; +}; + +class ocsdMsgLogger +{ +public: + ocsdMsgLogger(); + ~ocsdMsgLogger(); + + typedef enum { + OUT_NONE = 0, + OUT_FILE = 1, + OUT_STDERR = 2, + OUT_STDOUT = 4, + OUT_STR_CB = 8 /* output to external string callback interface */ + } output_dest; + + void setLogOpts(int logOpts); + const int getLogOpts() const { return m_outFlags; }; + + void setLogFileName(const char *fileName); + void setStrOutFn(ocsdMsgLogStrOutI *p_IstrOut); + + void LogMsg(const std::string &msg); + + const bool isLogging() const; + +private: + int m_outFlags; + + std::string m_logFileName; + std::fstream m_out_file; + ocsdMsgLogStrOutI *m_pOutStrI; +}; + +#endif // ARM_OCSD_MSG_LOGGER_H_INCLUDED + +/* End of File ocsd_msg_logger.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_pe_context.h b/contrib/opencsd/decoder/include/common/ocsd_pe_context.h new file mode 100644 index 000000000000..797881cf6985 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_pe_context.h @@ -0,0 +1,116 @@ +/* + * \file ocsd_pe_context.h + * \brief OpenCSD : Wrapper class for PE context + * + * \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_PE_CONTEXT_H_INCLUDED +#define ARM_OCSD_PE_CONTEXT_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" + +/*! @class OcsdPeContext + * @brief Handler for the ocsd_pe_context structure. + * + * Reads and writes structure values, enforcing interaction rules between values + * and flags. + */ +class OcsdPeContext +{ +public: + OcsdPeContext(); + OcsdPeContext(const ocsd_pe_context *context); + ~OcsdPeContext() {}; + + OcsdPeContext &operator =(const OcsdPeContext &ctxt); + OcsdPeContext &operator =(const ocsd_pe_context *context); + + void resetCtxt(); + + void setSecLevel(const ocsd_sec_level sl) { m_context.security_level = sl; }; + void setEL(const ocsd_ex_level el) { m_context.exception_level = el; m_context.el_valid = el > ocsd_EL_unknown ? 1 : 0; }; + void setCtxtID(const uint32_t id) { m_context.context_id = id; m_context.ctxt_id_valid = 1; }; + void setVMID(const uint32_t id) { m_context.vmid = id; m_context.vmid_valid = 1; }; + void set64bit(const bool is64bit) { m_context.bits64 = is64bit ? 1 : 0; }; + + const ocsd_sec_level getSecLevel() const { return m_context.security_level; }; + const ocsd_ex_level getEL() const { return m_context.exception_level; }; + const bool ELvalid() const { return (m_context.el_valid == 1); }; + const uint32_t getCtxtID() const { return (m_context.ctxt_id_valid == 1) ? m_context.context_id : 0; }; + const bool ctxtIDvalid() const { return (m_context.ctxt_id_valid == 1); }; + const uint32_t getVMID() const { return (m_context.vmid_valid == 1) ? m_context.vmid : 0; }; + const bool VMIDvalid() const { return (m_context.vmid_valid == 1); }; + + // only allow an immutable copy of the structure out to C-API land. + operator const ocsd_pe_context &() const { return m_context; }; + +private: + ocsd_pe_context m_context; +}; + +inline OcsdPeContext::OcsdPeContext() +{ + resetCtxt(); +} + +inline OcsdPeContext::OcsdPeContext(const ocsd_pe_context *context) +{ + m_context = *context; +} + +inline void OcsdPeContext::resetCtxt() +{ + // initialise the context + m_context.bits64 = 0; + m_context.context_id = 0; + m_context.ctxt_id_valid = 0; + m_context.el_valid = 0; + m_context.exception_level = ocsd_EL_unknown; + m_context.security_level = ocsd_sec_secure; + m_context.vmid = 0; + m_context.vmid_valid = 0; +} + +inline OcsdPeContext & OcsdPeContext::operator =(const OcsdPeContext &ctxt) +{ + m_context = ctxt; + return *this; +} + +inline OcsdPeContext & OcsdPeContext::operator =(const ocsd_pe_context *context) +{ + m_context = *context; + return *this; +} + + +#endif // ARM_OCSD_PE_CONTEXT_H_INCLUDED + +/* End of File ocsd_pe_context.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_version.h b/contrib/opencsd/decoder/include/common/ocsd_version.h new file mode 100644 index 000000000000..b68c85f43022 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/ocsd_version.h @@ -0,0 +1,46 @@ +/* + * \file ocsd_version.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_VERSION_H_INCLUDED +#define ARM_OCSD_VERSION_H_INCLUDED + +class ocsdVersion +{ +public: + static const uint32_t vers_num(); + static const char *vers_str(); +}; + +#endif // ARM_OCSD_VERSION_H_INCLUDED + +/* End of File ocsd_version.h */ diff --git a/contrib/opencsd/decoder/include/common/trc_component.h b/contrib/opencsd/decoder/include/common/trc_component.h new file mode 100644 index 000000000000..6096ac70f6f0 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_component.h @@ -0,0 +1,149 @@ +/*! + * \file trc_component.h + * \brief OpenCSD : Base trace decode component. + * + * \copyright Copyright (c) 2015, 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_TRC_COMPONENT_H_INCLUDED +#define ARM_TRC_COMPONENT_H_INCLUDED + +#include +#include "comp_attach_pt_t.h" +#include "interfaces/trc_error_log_i.h" +#include "ocsd_error.h" + +class errLogAttachMonitor; + +/** @addtogroup ocsd_infrastructure +@{*/ + +/*! + * @class TraceComponent + * @brief Base class for all decode components in the library. + * + * Provides error logging attachment point and component type and instance naming + * Interface for handling of component operational mode. + */ +class TraceComponent +{ +public: + TraceComponent(const std::string &name); + TraceComponent(const std::string &name, int instIDNum); + virtual ~TraceComponent(); /**< Default Destructor */ + + const std::string &getComponentName() const { return m_name; }; + void setComponentName(const std::string &name) { m_name = name; }; + + /** Error logger attachment point.*/ + componentAttachPt *getErrorLogAttachPt() { return &m_error_logger; }; + + /*! + * Set the operational mode for the component. + * This controls the way the component behaves under error conditions etc. + * These flags may also control output formats or data. + * Operation mode flags used are component specific and defined by derived classes. + * + * @param op_flags : Set of operation mode flags. + * + * @return ocsd_err_t : OCSD_OK if flags supported by this component, error if unsuppored + */ + ocsd_err_t setComponentOpMode(uint32_t op_flags); + + /*! + * Return the current operational mode flags values + * + * @return const uint32_t : Op Mode flags. + */ + const uint32_t getComponentOpMode() const { return m_op_flags; }; + + /*! + * Get the supported operational mode flags for this component. + * Base class will return nothing supported. + * Derived class must set the value correctly for the component. + * + * @return const uint32_t : Supported flags values. + */ + const uint32_t getSupportedOpModes() const { return m_supported_op_flags; }; + + /*! + * Set associated trace component - used by generic code to track + * packet processor / packet decoder pairs. + * + * @param *assocComp : pointer to the associated component + */ + void setAssocComponent(TraceComponent *assocComp) { m_assocComp = assocComp; }; + + + /*! + * get associated trace component pointer + * + * @return TraceComponent *: associated component. + */ + TraceComponent *getAssocComponent() { return m_assocComp; }; + + /*! + * Log a message at the default severity on this component. + */ + void LogDefMessage(const std::string &msg) + { + LogMessage(m_errVerbosity, msg); + } + +protected: + friend class errLogAttachMonitor; + + void LogError(const ocsdError &Error); + void LogMessage(const ocsd_err_severity_t filter_level, const std::string &msg); + const ocsd_err_severity_t getErrorLogLevel() const { return m_errVerbosity; }; + const bool isLoggingErrorLevel(const ocsd_err_severity_t level) const { return level <= m_errVerbosity; }; + void updateErrorLogLevel(); + + void do_attach_notify(const int num_attached); + void Init(const std::string &name); + + uint32_t m_op_flags; //!< current component operational mode flags. + uint32_t m_supported_op_flags; //!< supported component operational mode flags - derived class to intialise. + +private: + componentAttachPt m_error_logger; + ocsd_hndl_err_log_t m_errLogHandle; + ocsd_err_severity_t m_errVerbosity; + errLogAttachMonitor *m_pErrAttachMon; + + std::string m_name; + + TraceComponent *m_assocComp; //!< associated component -> if this is a pkt decoder, associated pkt processor. +}; +/** @}*/ +#endif // ARM_TRC_COMPONENT_H_INCLUDED + +/* End of File trc_component.h */ diff --git a/contrib/opencsd/decoder/include/common/trc_core_arch_map.h b/contrib/opencsd/decoder/include/common/trc_core_arch_map.h new file mode 100644 index 000000000000..5a24149180fc --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_core_arch_map.h @@ -0,0 +1,68 @@ +/*! + * \file trc_core_arch_map.h + * \brief OpenCSD : Map core name strings to architecture profile constants. + * + * \copyright Copyright (c) 2015, 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_TRC_CORE_ARCH_MAP_H_INCLUDED +#define ARM_TRC_CORE_ARCH_MAP_H_INCLUDED + +#include +#include +#include "opencsd/ocsd_if_types.h" + +class CoreArchProfileMap +{ +public: + CoreArchProfileMap(); + ~CoreArchProfileMap() {}; + + ocsd_arch_profile_t getArchProfile(const std::string &coreName); + +private: + + std::map core_profiles; +}; + +inline ocsd_arch_profile_t CoreArchProfileMap::getArchProfile(const std::string &coreName) +{ + ocsd_arch_profile_t ap = { ARCH_UNKNOWN, profile_Unknown }; + + std::map::const_iterator it; + it = core_profiles.find(coreName); + if(it != core_profiles.end()) + ap = it->second; + return ap; +} + +#endif // ARM_TRC_CORE_ARCH_MAP_H_INCLUDED + +/* End of File trc_core_arch_map.h */ diff --git a/contrib/opencsd/decoder/include/common/trc_cs_config.h b/contrib/opencsd/decoder/include/common/trc_cs_config.h new file mode 100644 index 000000000000..9b2c13012f99 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_cs_config.h @@ -0,0 +1,62 @@ +/* + * \file trc_cs_config.h + * \brief OpenCSD : Trace component config base class. + * + * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. + */ +#ifndef ARM_TRC_CS_CONFIG_H_INCLUDED +#define ARM_TRC_CS_CONFIG_H_INCLUDED + + +/* + * 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. + */ + +/** @addtogroup ocsd_protocol_cfg +@{*/ + +/*! + * @class CSConfig + * @brief Base class for configuration data on CoreSight trace component. + * + * Defines common access functionality, common to all components. + * (e.g. trace ID). + * + */ +class CSConfig +{ +public: + CSConfig() {}; + virtual ~CSConfig() {}; + + virtual const uint8_t getTraceID() const = 0; //!< CoreSight Trace ID for this device. +}; + +/** @}*/ + +#endif // ARM_TRC_CS_CONFIG_H_INCLUDED + +/* End of File trc_cs_config.h */ \ No newline at end of file diff --git a/contrib/opencsd/decoder/include/common/trc_frame_deformatter.h b/contrib/opencsd/decoder/include/common/trc_frame_deformatter.h new file mode 100644 index 000000000000..e4297a41e8fd --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_frame_deformatter.h @@ -0,0 +1,97 @@ +/*! + * \file trc_frame_deformatter.h + * \brief OpenCSD : De-format CoreSight formatted trace frame. + * + * \copyright Copyright (c) 2015, 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_TRC_FRAME_DEFORMATTER_H_INCLUDED +#define ARM_TRC_FRAME_DEFORMATTER_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" + +#include "interfaces/trc_data_raw_in_i.h" +#include "comp_attach_pt_t.h" + +class ITrcRawFrameIn; +class ITrcDataMixIDIn; +class ITrcSrcIndexCreator; +class ITraceErrorLog; +class TraceFmtDcdImpl; + +/** @defgroup ocsd_deformatter OpenCSD Library : Trace Frame Deformatter + @brief CoreSight Formatted Trace Frame - deformatting functionality. +@{*/ + +class TraceFormatterFrameDecoder : public ITrcDataIn +{ +public: + TraceFormatterFrameDecoder(); + TraceFormatterFrameDecoder(int instNum); + virtual ~TraceFormatterFrameDecoder(); + + /* the data input interface from the reader */ + virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + + /* attach a data processor to a stream ID output */ + componentAttachPt *getIDStreamAttachPt(uint8_t ID); + + /* attach a data processor to the raw frame output */ + componentAttachPt *getTrcRawFrameAttachPt(); + + componentAttachPt *getTrcSrcIndexAttachPt(); + + componentAttachPt *getErrLogAttachPt(); + + /* configuration - set operational mode for incoming stream (has FSYNCS etc) */ + ocsd_err_t Configure(uint32_t cfg_flags); + const uint32_t getConfigFlags() const; + + /* enable / disable ID streams - default as all enabled */ + ocsd_err_t OutputFilterIDs(std::vector &id_list, bool bEnable); + ocsd_err_t OutputFilterAllIDs(bool bEnable); + + /* decode control */ + ocsd_datapath_resp_t Reset(); /* reset the decode to the start state, drop partial data - propogate to attached components */ + ocsd_datapath_resp_t Flush(); /* flush existing data if possible, retain state - propogate to attached components */ + +private: + TraceFmtDcdImpl *m_pDecoder; + int m_instNum; +}; + +/** @}*/ + +#endif // ARM_TRC_FRAME_DEFORMATTER_H_INCLUDED + +/* End of File trc_frame_deformatter.h */ \ No newline at end of file diff --git a/contrib/opencsd/decoder/include/common/trc_gen_elem.h b/contrib/opencsd/decoder/include/common/trc_gen_elem.h new file mode 100644 index 000000000000..00081b556904 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_gen_elem.h @@ -0,0 +1,206 @@ +/*! + * \file trc_gen_elem.h + * \brief OpenCSD : Decoder Generic trace element output class. + * + * \copyright Copyright (c) 2015, 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_TRC_GEN_ELEM_H_INCLUDED +#define ARM_TRC_GEN_ELEM_H_INCLUDED + +#include "opencsd/trc_gen_elem_types.h" +#include "trc_printable_elem.h" +#include "ocsd_pe_context.h" + +/** @addtogroup gen_trc_elem +@{*/ + +/*! + * @class OcsdTraceElement + * @brief Generic trace element class + * + */ +class OcsdTraceElement : public trcPrintableElem, public ocsd_generic_trace_elem +{ +public: + OcsdTraceElement(); + OcsdTraceElement(ocsd_gen_trc_elem_t type); + virtual ~OcsdTraceElement() {}; + + void init(); + +// set elements API + + void setType(const ocsd_gen_trc_elem_t type); //!< set type and init flags + void updateType(const ocsd_gen_trc_elem_t type); //!< change type only - no init + + void setContext(const ocsd_pe_context &new_context) { context = new_context; }; + void setISA(const ocsd_isa isa_update); + + void setCycleCount(const uint32_t cycleCount); + void setEvent(const event_t ev_type, const uint16_t number); + void setTS(const uint64_t ts, const bool freqChange = false); + + void setExcepMarker() { excep_data_marker = 1; }; + void setExceptionNum(uint32_t excepNum) { exception_number = excepNum; }; + + + void setTraceOnReason(const trace_on_reason_t reason); + + void setAddrRange(const ocsd_vaddr_t st_addr, const ocsd_vaddr_t en_addr); + void setLastInstrInfo(const bool exec, const ocsd_instr_type last_i_type, const ocsd_instr_subtype last_i_subtype); + void setAddrStart(const ocsd_vaddr_t st_addr) { this->st_addr = st_addr; }; + + void setSWTInfo(const ocsd_swt_info_t swt_info) { sw_trace_info = swt_info; }; + void setExtendedDataPtr(const void *data_ptr); + +// stringize the element + + virtual void toString(std::string &str) const; + +// get elements API + + OcsdTraceElement &operator =(const ocsd_generic_trace_elem* p_elem); + + const ocsd_gen_trc_elem_t getType() const { return elem_type; }; + + // return current context + const ocsd_pe_context &getContext() const { return context; }; + + +private: + void printSWInfoPkt(std::ostringstream &oss) const; + void clearPerPktData(); //!< clear flags that indicate validity / have values on a per packet basis + +}; + +inline OcsdTraceElement::OcsdTraceElement(ocsd_gen_trc_elem_t type) +{ + elem_type = type; +} + +inline OcsdTraceElement::OcsdTraceElement() +{ + elem_type = OCSD_GEN_TRC_ELEM_UNKNOWN; +} + +inline void OcsdTraceElement::setCycleCount(const uint32_t cycleCount) +{ + cycle_count = cycleCount; + has_cc = 1; +} + +inline void OcsdTraceElement::setEvent(const event_t ev_type, const uint16_t number) +{ + trace_event.ev_type = (uint16_t)ev_type; + trace_event.ev_number = ev_type == EVENT_NUMBERED ? number : 0; +} + +inline void OcsdTraceElement::setAddrRange(const ocsd_vaddr_t st_addr, const ocsd_vaddr_t en_addr) +{ + this->st_addr = st_addr; + this->en_addr = en_addr; +} + +inline void OcsdTraceElement::setLastInstrInfo(const bool exec, const ocsd_instr_type last_i_type, const ocsd_instr_subtype last_i_subtype) +{ + last_instr_exec = exec ? 1 : 0; + this->last_i_type = last_i_type; + this->last_i_subtype = last_i_subtype; +} + +inline void OcsdTraceElement::setType(const ocsd_gen_trc_elem_t type) +{ + // set the type and clear down the per element flags + elem_type = type; + + clearPerPktData(); +} + +inline void OcsdTraceElement::updateType(const ocsd_gen_trc_elem_t type) +{ + elem_type = type; +} + +inline void OcsdTraceElement::init() +{ + st_addr = en_addr = (ocsd_vaddr_t)-1; + isa = ocsd_isa_unknown; + + cycle_count = 0; + timestamp = 0; + + context.ctxt_id_valid = 0; + context.vmid_valid = 0; + context.el_valid = 0; + + last_i_type = OCSD_INSTR_OTHER; + last_i_subtype = OCSD_S_INSTR_NONE; + + clearPerPktData(); +} + +inline void OcsdTraceElement::clearPerPktData() +{ + flag_bits = 0; // union with trace_on_reason / trace_event + + ptr_extended_data = 0; // extended data pointer +} + +inline void OcsdTraceElement::setTraceOnReason(const trace_on_reason_t reason) +{ + trace_on_reason = reason; +} + +inline void OcsdTraceElement::setISA(const ocsd_isa isa_update) +{ + isa = isa_update; + if(isa > ocsd_isa_unknown) + isa = ocsd_isa_unknown; +} + +inline void OcsdTraceElement::setTS(const uint64_t ts, const bool freqChange /*= false*/) +{ + timestamp = ts; + cpu_freq_change = freqChange ? 1 : 0; + has_ts = 1; +} + +inline void OcsdTraceElement::setExtendedDataPtr(const void *data_ptr) +{ + extended_data = 1; + ptr_extended_data = data_ptr; +} + + +/** @}*/ + +#endif // ARM_TRC_GEN_ELEM_H_INCLUDED + +/* End of File trc_gen_elem.h */ diff --git a/contrib/opencsd/decoder/include/common/trc_pkt_decode_base.h b/contrib/opencsd/decoder/include/common/trc_pkt_decode_base.h new file mode 100644 index 000000000000..2bbf5e51d878 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_pkt_decode_base.h @@ -0,0 +1,303 @@ +/*! + * \file trc_pkt_decode_base.h + * \brief OpenCSD : Trace Packet decoder base class. + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_DECODE_BASE_H_INCLUDED +#define ARM_TRC_PKT_DECODE_BASE_H_INCLUDED + +#include "trc_component.h" +#include "comp_attach_pt_t.h" + +#include "interfaces/trc_pkt_in_i.h" +#include "interfaces/trc_gen_elem_in_i.h" +#include "interfaces/trc_tgt_mem_access_i.h" +#include "interfaces/trc_instr_decode_i.h" + +/** @defgroup ocsd_pkt_decode OpenCSD Library : Packet Decoders. + + @brief Classes providing Protocol Packet Decoding capability. + + Packet decoders convert incoming protocol packets from a packet processor, + into generic trace elements to be output to an analysis program. + + Packet decoders can be:- + - PE decoders - converting ETM or PTM packets into instruction and data trace elements + - SW stimulus decoder - converting STM or ITM packets into software generated trace elements. + - Bus decoders - converting HTM packets into bus transaction elements. + +@{*/ + + +class TrcPktDecodeI : public TraceComponent +{ +public: + TrcPktDecodeI(const char *component_name); + TrcPktDecodeI(const char *component_name, int instIDNum); + virtual ~TrcPktDecodeI() {}; + + componentAttachPt *getTraceElemOutAttachPt() { return &m_trace_elem_out; }; + componentAttachPt *getMemoryAccessAttachPt() { return &m_mem_access; }; + componentAttachPt *getInstrDecodeAttachPt() { return &m_instr_decode; }; + + void setUsesMemAccess(bool bUsesMemaccess) { m_uses_memaccess = bUsesMemaccess; }; + const bool getUsesMemAccess() const { return m_uses_memaccess; }; + + void setUsesIDecode(bool bUsesIDecode) { m_uses_idecode = bUsesIDecode; }; + const bool getUsesIDecode() const { return m_uses_idecode; }; + +protected: + + /* implementation packet decoding interface */ + virtual ocsd_datapath_resp_t processPacket() = 0; + virtual ocsd_datapath_resp_t onEOT() = 0; + virtual ocsd_datapath_resp_t onReset() = 0; + virtual ocsd_datapath_resp_t onFlush() = 0; + virtual ocsd_err_t onProtocolConfig() = 0; + virtual const uint8_t getCoreSightTraceID() = 0; + + const bool checkInit(); + + /* data output */ + ocsd_datapath_resp_t outputTraceElement(const OcsdTraceElement &elem); // use current index + ocsd_datapath_resp_t outputTraceElementIdx(ocsd_trc_index_t idx, const OcsdTraceElement &elem); // use supplied index (where decoder caches elements) + + /* target access */ + ocsd_err_t accessMemory(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, uint32_t *num_bytes, uint8_t *p_buffer); + + /* instruction decode */ + ocsd_err_t instrDecode(ocsd_instr_info *instr_info); + + componentAttachPt m_trace_elem_out; + componentAttachPt m_mem_access; + componentAttachPt m_instr_decode; + + ocsd_trc_index_t m_index_curr_pkt; + + bool m_decode_init_ok; //!< set true if all attachments in place for decode. (remove checks in main throughput paths) + bool m_config_init_ok; //!< set true if config set. + + std::string init_err_msg; //!< error message for init error + + bool m_uses_memaccess; + bool m_uses_idecode; + +}; + +inline TrcPktDecodeI::TrcPktDecodeI(const char *component_name) : + TraceComponent(component_name), + m_index_curr_pkt(0), + m_decode_init_ok(false), + m_config_init_ok(false), + m_uses_memaccess(true), + m_uses_idecode(true) +{ +} + +inline TrcPktDecodeI::TrcPktDecodeI(const char *component_name, int instIDNum) : + TraceComponent(component_name, instIDNum), + m_index_curr_pkt(0), + m_decode_init_ok(false), + m_config_init_ok(false), + m_uses_memaccess(true), + m_uses_idecode(true) +{ +} + +inline const bool TrcPktDecodeI::checkInit() +{ + if(!m_decode_init_ok) + { + if(!m_config_init_ok) + init_err_msg = "No decoder configuration information"; + else if(!m_trace_elem_out.hasAttachedAndEnabled()) + init_err_msg = "No element output interface attached and enabled"; + else if(m_uses_memaccess && !m_mem_access.hasAttachedAndEnabled()) + init_err_msg = "No memory access interface attached and enabled"; + else if(m_uses_idecode && !m_instr_decode.hasAttachedAndEnabled()) + init_err_msg = "No instruction decoder interface attached and enabled"; + else + m_decode_init_ok = true; + } + return m_decode_init_ok; +} + +inline ocsd_datapath_resp_t TrcPktDecodeI::outputTraceElement(const OcsdTraceElement &elem) +{ + return m_trace_elem_out.first()->TraceElemIn(m_index_curr_pkt,getCoreSightTraceID(), elem); +} + +inline ocsd_datapath_resp_t TrcPktDecodeI::outputTraceElementIdx(ocsd_trc_index_t idx, const OcsdTraceElement &elem) +{ + return m_trace_elem_out.first()->TraceElemIn(idx, getCoreSightTraceID(), elem); +} + +inline ocsd_err_t TrcPktDecodeI::instrDecode(ocsd_instr_info *instr_info) +{ + if(m_uses_idecode) + return m_instr_decode.first()->DecodeInstruction(instr_info); + return OCSD_ERR_DCD_INTERFACE_UNUSED; +} + +inline ocsd_err_t TrcPktDecodeI::accessMemory(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, uint32_t *num_bytes, uint8_t *p_buffer) +{ + if(m_uses_memaccess) + return m_mem_access.first()->ReadTargetMemory(address,getCoreSightTraceID(),mem_space, num_bytes,p_buffer); + return OCSD_ERR_DCD_INTERFACE_UNUSED; +} + +/**********************************************************************/ +template +class TrcPktDecodeBase : public TrcPktDecodeI, public IPktDataIn

+{ +public: + TrcPktDecodeBase(const char *component_name); + TrcPktDecodeBase(const char *component_name, int instIDNum); + virtual ~TrcPktDecodeBase(); + + virtual ocsd_datapath_resp_t PacketDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const P *p_packet_in); + + + /* protocol configuration */ + ocsd_err_t setProtocolConfig(const Pc *config); + const Pc * getProtocolConfig() const { return m_config; }; + +protected: + void ClearConfigObj(); + + /* the protocol configuration */ + Pc * m_config; + /* the current input packet */ + const P * m_curr_packet_in; + +}; + + +template TrcPktDecodeBase::TrcPktDecodeBase(const char *component_name) : + TrcPktDecodeI(component_name), + m_config(0) +{ +} + +template TrcPktDecodeBase::TrcPktDecodeBase(const char *component_name, int instIDNum) : + TrcPktDecodeI(component_name,instIDNum), + m_config(0) +{ +} + +template TrcPktDecodeBase::~TrcPktDecodeBase() +{ + ClearConfigObj(); +} + +template ocsd_datapath_resp_t TrcPktDecodeBase::PacketDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const P *p_packet_in) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + if(!checkInit()) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_NOT_INIT,init_err_msg)); + return OCSD_RESP_FATAL_NOT_INIT; + } + + switch(op) + { + case OCSD_OP_DATA: + if(p_packet_in == 0) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL)); + resp = OCSD_RESP_FATAL_INVALID_PARAM; + } + else + { + m_curr_packet_in = p_packet_in; + m_index_curr_pkt = index_sop; + resp = processPacket(); + } + break; + + case OCSD_OP_EOT: + resp = onEOT(); + break; + + case OCSD_OP_FLUSH: + resp = onFlush(); + break; + + case OCSD_OP_RESET: + resp = onReset(); + break; + + default: + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL)); + resp = OCSD_RESP_FATAL_INVALID_OP; + break; + } + return resp; +} + + /* protocol configuration */ +template ocsd_err_t TrcPktDecodeBase::setProtocolConfig(const Pc *config) +{ + ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL; + if(config != 0) + { + ClearConfigObj(); // remove any current config + m_config = new (std::nothrow) Pc(*config); // make a copy of the config - don't rely on the object passed in being valid outside the context of the call. + if(m_config != 0) + { + err = onProtocolConfig(); + if(err == OCSD_OK) + m_config_init_ok = true; + } + else + err = OCSD_ERR_MEM; + } + return err; +} + +template void TrcPktDecodeBase::ClearConfigObj() +{ + if(m_config) + { + delete m_config; + m_config = 0; + } +} + +/** @}*/ +#endif // ARM_TRC_PKT_DECODE_BASE_H_INCLUDED + +/* End of File trc_pkt_decode_base.h */ diff --git a/contrib/opencsd/decoder/include/common/trc_pkt_elem_base.h b/contrib/opencsd/decoder/include/common/trc_pkt_elem_base.h new file mode 100644 index 000000000000..07604a664210 --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_pkt_elem_base.h @@ -0,0 +1,49 @@ +/* + * \file trc_pkt_elem_base.h + * \brief Reference CoreSight Trace Decoder : + * + * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. + */ +#ifndef ARM_TRC_PKT_ELEM_BASE_H_INCLUDED +#define ARM_TRC_PKT_ELEM_BASE_H_INCLUDED + +/* + * 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. + */ + +class TrcPacketBase +{ +public: + TrcPacketBase() {}; + virtual ~TrcPacketBase() {} + + //! return the underlying C API packet structure + virtual const void *c_pkt() const = 0; +}; + +#endif // ARM_TRC_PKT_ELEM_BASE_H_INCLUDED + +/* End of File trc_pkt_elem_base.h */ \ No newline at end of file diff --git a/contrib/opencsd/decoder/include/common/trc_pkt_proc_base.h b/contrib/opencsd/decoder/include/common/trc_pkt_proc_base.h new file mode 100644 index 000000000000..3098a3d0c0ea --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_pkt_proc_base.h @@ -0,0 +1,412 @@ +/*! + * \file trc_pkt_proc_base.h + * \brief OpenCSD : Trace packet processor base class. + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PROC_BASE_H_INCLUDED +#define ARM_TRC_PKT_PROC_BASE_H_INCLUDED + +#include "interfaces/trc_data_raw_in_i.h" +#include "interfaces/trc_pkt_in_i.h" +#include "interfaces/trc_pkt_raw_in_i.h" +#include "interfaces/trc_indexer_pkt_i.h" + +#include "trc_component.h" +#include "comp_attach_pt_t.h" + +/** @defgroup ocsd_pkt_proc OpenCSD Library : Packet Processors. + @brief Classes providing Protocol Packet Processing capability. + + Packet processors take an incoming byte stream and convert into discrete packets for the + required trace protocol. +@{*/ + + + +/*! + * @class TrcPktProcI + * @brief Base Packet processing interface + * + * Defines the packet processing methods that protocol specific processors must + * implement. + * + */ +class TrcPktProcI : public TraceComponent, public ITrcDataIn +{ +public: + TrcPktProcI(const char *component_name); + TrcPktProcI(const char *component_name, int instIDNum); + virtual ~TrcPktProcI() {}; + + /** Trace byte data input interface - from ITrcDataIn. + */ + virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) = 0; + +protected: + + /* implementation packet processing interface */ + + /*! @brief Implementation function for the OCSD_OP_DATA operation */ + virtual ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) = 0; + + virtual ocsd_datapath_resp_t onEOT() = 0; //!< Implementation function for the OCSD_OP_EOT operation + virtual ocsd_datapath_resp_t onReset() = 0; //!< Implementation function for the OCSD_OP_RESET operation + virtual ocsd_datapath_resp_t onFlush() = 0; //!< Implementation function for the OCSD_OP_FLUSH operation + virtual ocsd_err_t onProtocolConfig() = 0; //!< Called when the configuration object is passed to the decoder. + virtual const bool isBadPacket() const = 0; //!< check if the current packet is an error / bad packet +}; + +inline TrcPktProcI::TrcPktProcI(const char *component_name) : + TraceComponent(component_name) +{ +} + +inline TrcPktProcI::TrcPktProcI(const char *component_name, int instIDNum) : + TraceComponent(component_name,instIDNum) +{ +} + +/*! + * @class TrcPktProcBase + * @brief Packet Processor base class. Provides common infrastructure and interconnections for packet processors. + * + * The class is a templated base class. + * - P - this is the packet object class. + * - Pt - this is the packet type class. + * - Pc - this is the packet configuration class. + * + * implementations will provide concrete classes for each of these to operate under the common infrastructures. + * The base provides the trace data in (ITrcDataIn) interface and operates on the incoming operation type. + * + * Implementions override the 'onFn()' and data process functions defined in TrcPktProcI, + * with the base class ensuring consistent ordering of operations. + * + */ +template +class TrcPktProcBase : public TrcPktProcI +{ +public: + TrcPktProcBase(const char *component_name); + TrcPktProcBase(const char *component_name, int instIDNum); + virtual ~TrcPktProcBase(); + + /** Byte trace data input interface defined in ITrcDataIn + + The base class implementation processes the operation to call the + interface functions on TrcPktProcI. + */ + virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + + +/* component attachment points */ + + //! Attachement point for the protocol packet output + componentAttachPt> *getPacketOutAttachPt() { return &m_pkt_out_i; }; + //! Attachment point for the protocol packet monitor + componentAttachPt> *getRawPacketMonAttachPt() { return &m_pkt_raw_mon_i; }; + + //! Attachment point for a packet indexer + componentAttachPt> *getTraceIDIndexerAttachPt() { return &m_pkt_indexer_i; }; + +/* protocol configuration */ + //!< Set the protocol specific configuration for the decoder. + virtual ocsd_err_t setProtocolConfig(const Pc *config); + //!< Get the configuration for the decoder. + virtual const Pc *getProtocolConfig() const { return m_config; }; + +protected: + + /* data output functions */ + ocsd_datapath_resp_t outputDecodedPacket(const ocsd_trc_index_t index_sop, const P *pkt); + + void outputRawPacketToMonitor( const ocsd_trc_index_t index_sop, + const P *pkt, + const uint32_t size, + const uint8_t *p_data); + + void indexPacket(const ocsd_trc_index_t index_sop, const Pt *packet_type); + + ocsd_datapath_resp_t outputOnAllInterfaces(const ocsd_trc_index_t index_sop, const P *pkt, const Pt *pkt_type, std::vector &pktdata); + + ocsd_datapath_resp_t outputOnAllInterfaces(const ocsd_trc_index_t index_sop, const P *pkt, const Pt *pkt_type, const uint8_t *pktdata, uint32_t pktlen); + + /*! Let the derived class figure out if it needs to collate and send raw data. + can improve wait for sync performance if we do not need to save and send unsynced data. + */ + const bool hasRawMon() const; + + /* the protocol configuration */ + const Pc *m_config; + + void ClearConfigObj(); // remove our copy of the config + + const bool checkInit(); // return true if init (configured and at least one output sink attached), false otherwise. + +private: + /* decode control */ + ocsd_datapath_resp_t Reset(const ocsd_trc_index_t index); + ocsd_datapath_resp_t Flush(); + ocsd_datapath_resp_t EOT(); + + componentAttachPt> m_pkt_out_i; + componentAttachPt> m_pkt_raw_mon_i; + + componentAttachPt> m_pkt_indexer_i; + + bool m_b_is_init; +}; + +template TrcPktProcBase::TrcPktProcBase(const char *component_name) : + TrcPktProcI(component_name), + m_config(0), + m_b_is_init(false) +{ +} + +template TrcPktProcBase::TrcPktProcBase(const char *component_name, int instIDNum) : + TrcPktProcI(component_name, instIDNum), + m_config(0), + m_b_is_init(false) +{ +} + +template TrcPktProcBase::~TrcPktProcBase() +{ + ClearConfigObj(); +} + +template ocsd_datapath_resp_t TrcPktProcBase::TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + switch(op) + { + case OCSD_OP_DATA: + if((dataBlockSize == 0) || (pDataBlock == 0) || (numBytesProcessed == 0)) + { + if(numBytesProcessed) + *numBytesProcessed = 0; // ensure processed bytes value set to 0. + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL,"Packet Processor: Zero length data block or NULL pointer error\n")); + resp = OCSD_RESP_FATAL_INVALID_PARAM; + } + else + resp = processData(index,dataBlockSize,pDataBlock,numBytesProcessed); + break; + + case OCSD_OP_EOT: + resp = EOT(); + break; + + case OCSD_OP_FLUSH: + resp = Flush(); + break; + + case OCSD_OP_RESET: + resp = Reset(index); + break; + + default: + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL,"Packet Processor : Unknown Datapath operation\n")); + resp = OCSD_RESP_FATAL_INVALID_OP; + break; + } + return resp; +} + + +template ocsd_datapath_resp_t TrcPktProcBase::Reset(const ocsd_trc_index_t index) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // reset the trace decoder attachment on main data path. + if(m_pkt_out_i.hasAttachedAndEnabled()) + resp = m_pkt_out_i.first()->PacketDataIn(OCSD_OP_RESET,index,0); + + // reset the packet processor implmentation + if(!OCSD_DATA_RESP_IS_FATAL(resp)) + resp = onReset(); + + // packet monitor + if(m_pkt_raw_mon_i.hasAttachedAndEnabled()) + m_pkt_raw_mon_i.first()->RawPacketDataMon(OCSD_OP_RESET,index,0,0,0); + + return resp; +} + +template ocsd_datapath_resp_t TrcPktProcBase::Flush() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + ocsd_datapath_resp_t resplocal = OCSD_RESP_CONT; + + // the trace decoder attachment on main data path. + if(m_pkt_out_i.hasAttachedAndEnabled()) + resp = m_pkt_out_i.first()->PacketDataIn(OCSD_OP_FLUSH,0,0); // flush up the data path first. + + // if the connected components are flushed, not flush this one. + if(OCSD_DATA_RESP_IS_CONT(resp)) + resplocal = onFlush(); // local flush + + return (resplocal > resp) ? resplocal : resp; +} + +template ocsd_datapath_resp_t TrcPktProcBase::EOT() +{ + ocsd_datapath_resp_t resp = onEOT(); // local EOT - mark any part packet as incomplete type and prepare to send + + // the trace decoder attachment on main data path. + if(m_pkt_out_i.hasAttachedAndEnabled() && !OCSD_DATA_RESP_IS_FATAL(resp)) + resp = m_pkt_out_i.first()->PacketDataIn(OCSD_OP_EOT,0,0); + + // packet monitor + if(m_pkt_raw_mon_i.hasAttachedAndEnabled()) + m_pkt_raw_mon_i.first()->RawPacketDataMon(OCSD_OP_EOT,0,0,0,0); + + return resp; +} + +template ocsd_datapath_resp_t TrcPktProcBase::outputDecodedPacket(const ocsd_trc_index_t index, const P *pkt) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // bad packet filter. + if((getComponentOpMode() & OCSD_OPFLG_PKTPROC_NOFWD_BAD_PKTS) && isBadPacket()) + return resp; + + // send a complete packet over the primary data path + if(m_pkt_out_i.hasAttachedAndEnabled()) + resp = m_pkt_out_i.first()->PacketDataIn(OCSD_OP_DATA,index,pkt); + return resp; +} + +template void TrcPktProcBase::outputRawPacketToMonitor( + const ocsd_trc_index_t index_sop, + const P *pkt, + const uint32_t size, + const uint8_t *p_data) +{ + // never output 0 sized packets. + if(size == 0) + return; + + // bad packet filter. + if((getComponentOpMode() & OCSD_OPFLG_PKTPROC_NOMON_BAD_PKTS) && isBadPacket()) + return; + + // packet monitor - this cannot return CONT / WAIT, but does get the raw packet data. + if(m_pkt_raw_mon_i.hasAttachedAndEnabled()) + m_pkt_raw_mon_i.first()->RawPacketDataMon(OCSD_OP_DATA,index_sop,pkt,size,p_data); +} + +template const bool TrcPktProcBase::hasRawMon() const +{ + return m_pkt_raw_mon_i.hasAttachedAndEnabled(); +} + +template void TrcPktProcBase::indexPacket(const ocsd_trc_index_t index_sop, const Pt *packet_type) +{ + // packet indexer - cannot return CONT / WAIT, just gets the current index and type. + if(m_pkt_indexer_i.hasAttachedAndEnabled()) + m_pkt_indexer_i.first()->TracePktIndex(index_sop,packet_type); +} + +template ocsd_datapath_resp_t TrcPktProcBase::outputOnAllInterfaces(const ocsd_trc_index_t index_sop, const P *pkt, const Pt *pkt_type, std::vector &pktdata) +{ + indexPacket(index_sop,pkt_type); + if(pktdata.size() > 0) // prevent out of range errors for 0 length vector. + outputRawPacketToMonitor(index_sop,pkt,(uint32_t)pktdata.size(),&pktdata[0]); + return outputDecodedPacket(index_sop,pkt); +} + +template ocsd_datapath_resp_t TrcPktProcBase::outputOnAllInterfaces(const ocsd_trc_index_t index_sop, const P *pkt, const Pt *pkt_type, const uint8_t *pktdata, uint32_t pktlen) +{ + indexPacket(index_sop,pkt_type); + outputRawPacketToMonitor(index_sop,pkt,pktlen,pktdata); + return outputDecodedPacket(index_sop,pkt); +} + +template ocsd_err_t TrcPktProcBase::setProtocolConfig(const Pc *config) +{ + ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL; + if(config != 0) + { + ClearConfigObj(); + m_config = new (std::nothrow) Pc(*config); + if(m_config != 0) + err = onProtocolConfig(); + else + err = OCSD_ERR_MEM; + } + return err; +} + +template void TrcPktProcBase::ClearConfigObj() +{ + if(m_config) + { + delete m_config; + m_config = 0; + } +} + +template const bool TrcPktProcBase::checkInit() +{ + if(!m_b_is_init) + { + if( (m_config != 0) && + (m_pkt_out_i.hasAttached() || m_pkt_raw_mon_i.hasAttached()) + ) + m_b_is_init = true; + } + return m_b_is_init; +} + +/** @}*/ + +#endif // ARM_TRC_PKT_PROC_BASE_H_INCLUDED + +/* End of File trc_pkt_proc_base.h */ diff --git a/contrib/opencsd/decoder/include/common/trc_printable_elem.h b/contrib/opencsd/decoder/include/common/trc_printable_elem.h new file mode 100644 index 000000000000..92a47e882b1a --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_printable_elem.h @@ -0,0 +1,91 @@ +/*! + * \file trc_printable_elem.h + * \brief OpenCSD : Standard printable element base class. + * + * \copyright Copyright (c) 2015, 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_TRC_PRINTABLE_ELEM_H_INCLUDED +#define ARM_TRC_PRINTABLE_ELEM_H_INCLUDED + +#include +#include + +/** @addtogroup ocsd_infrastructure +@{*/ + +/*! + * @class trcPrintableElem + * @brief Class to provide trace element strings for printing + * + * Provide a standard interface to the trace packet classes to allow the packets + * to be printed in logging or tools. + * + * Provides some standard formatting functionality + * + */ +class trcPrintableElem +{ +public: + trcPrintableElem() {}; + virtual ~trcPrintableElem() {}; + virtual void toString(std::string &str) const; + virtual void toStringFmt(const uint32_t fmtFlags, std::string &str) const; + + // print formatting utilities + static void getValStr(std::string &valStr, const int valTotalBitSize, const int valValidBits, const uint64_t value, const bool asHex = true, const int updateBits = 0); + +}; + +inline void trcPrintableElem::toString(std::string &str) const +{ + str = "Trace Element : print not implemented"; +} + +inline void trcPrintableElem::toStringFmt(const uint32_t /*fmtFlags*/, std::string &str) const +{ + toString(str); +} + +/** static template string function - used in "C" API to provide generic printing */ +template +void trcPrintElemToString(const void *p_pkt, std::string &str) +{ + Pc pktClass; + pktClass = static_cast(p_pkt); + pktClass.toString(str); +} + +/** @}*/ + +#endif // ARM_TRC_PRINTABLE_ELEM_H_INCLUDED + +/* End of File trc_printable_elem.h */ diff --git a/contrib/opencsd/decoder/include/common/trc_ret_stack.h b/contrib/opencsd/decoder/include/common/trc_ret_stack.h new file mode 100644 index 000000000000..a7f53d1cbaeb --- /dev/null +++ b/contrib/opencsd/decoder/include/common/trc_ret_stack.h @@ -0,0 +1,114 @@ +/* +* \file trc_ret_stack.h +* \brief OpenCSD : trace decoder return stack feature. +* +* \copyright Copyright (c) 2017, 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_TRC_RET_STACK_H_INCLUDED +#define ARM_TRC_RET_STACK_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" + +// uncomment below for return stack logging +// #define TRC_RET_STACK_DEBUG + +#ifdef TRC_RET_STACK_DEBUG +class TraceComponent; +#endif + +typedef struct _retStackElement +{ + ocsd_vaddr_t ret_addr; + ocsd_isa ret_isa; +} retStackElement; + +class TrcAddrReturnStack +{ +public: + TrcAddrReturnStack(); + ~TrcAddrReturnStack() {}; + + void set_active(bool active) + { + m_active = active; + }; + + bool is_active() const + { + return m_active; + }; + + void push(const ocsd_vaddr_t addr, const ocsd_isa isa); + ocsd_vaddr_t pop(ocsd_isa &isa); + void flush(); + + bool overflow() const + { + return (bool)(num_entries < 0); + }; + + void set_pop_pending() + { + if (m_active) + m_pop_pending = true; + } + + void clear_pop_pending() + { + m_pop_pending = false; + } + + bool pop_pending() const + { + return m_pop_pending; + }; + +private: + bool m_active; + bool m_pop_pending; // flag for decoder to indicate a pop might be needed depending on the next packet (ETMv4) + + int head_idx; + int num_entries; + retStackElement m_stack[16]; + +#ifdef TRC_RET_STACK_DEBUG +public: + void set_dbg_logger(TraceComponent *pLogger) { m_p_debug_logger = pLogger; }; +private: + void LogOp(const char *pszOpString, ocsd_vaddr_t addr, int head_off, ocsd_isa isa); + + TraceComponent *m_p_debug_logger; +#endif // TRC_RET_STACK_DEBUG +}; + +#endif // ARM_TRC_RET_STACK_H_INCLUDED + +/* End of File trc_ret_stack.h */ diff --git a/contrib/opencsd/decoder/include/i_dec/trc_i_decode.h b/contrib/opencsd/decoder/include/i_dec/trc_i_decode.h new file mode 100644 index 000000000000..ac31a79ded63 --- /dev/null +++ b/contrib/opencsd/decoder/include/i_dec/trc_i_decode.h @@ -0,0 +1,56 @@ +/* + * \file trc_i_decode.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_I_DECODE_H_INCLUDED +#define ARM_TRC_I_DECODE_H_INCLUDED + +#include "interfaces/trc_instr_decode_i.h" +#include "opencsd/ocsd_if_types.h" + +class TrcIDecode : public IInstrDecode +{ +public: + TrcIDecode() {}; + virtual ~TrcIDecode() {}; + + virtual ocsd_err_t DecodeInstruction(ocsd_instr_info *instr_info); + +private: + ocsd_err_t DecodeA32(ocsd_instr_info *instr_info); + ocsd_err_t DecodeA64(ocsd_instr_info *instr_info); + ocsd_err_t DecodeT32(ocsd_instr_info *instr_info); +}; + +#endif // ARM_TRC_I_DECODE_H_INCLUDED + +/* End of File trc_i_decode.h */ diff --git a/contrib/opencsd/decoder/include/i_dec/trc_idec_arminst.h b/contrib/opencsd/decoder/include/i_dec/trc_idec_arminst.h new file mode 100644 index 000000000000..b15984948d29 --- /dev/null +++ b/contrib/opencsd/decoder/include/i_dec/trc_idec_arminst.h @@ -0,0 +1,130 @@ +/* + * \file trc_idec_arminst.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_IDEC_ARMINST_H_INCLUDED +#define ARM_TRC_IDEC_ARMINST_H_INCLUDED + +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS 1 +#endif + +#include "opencsd/ocsd_if_types.h" +#include + +/* +For Thumb2, test if a halfword is the first half of a 32-bit instruction, +as opposed to a complete 16-bit instruction. +*/ +inline int is_wide_thumb(uint16_t insthw) +{ + return (insthw & 0xF800) >= 0xE800; +} + +/* +In the following queries, 16-bit Thumb2 instructions should be +passed in as the high halfword, e.g. xxxx0000. +*/ + +/* +Test whether an instruction is a branch (software change of the PC). +This includes branch instructions and all loads and data-processing +instructions that write to the PC. It does not include exception +instructions such as SVC, HVC and SMC. +(Performance event 0x0C includes these.) +*/ +int inst_ARM_is_branch(uint32_t inst); +int inst_Thumb_is_branch(uint32_t inst); +int inst_A64_is_branch(uint32_t inst); + +/* +Test whether an instruction is a direct (aka immediate) branch. +Performance event 0x0D counts these. +*/ +int inst_ARM_is_direct_branch(uint32_t inst); +int inst_Thumb_is_direct_branch(uint32_t inst); +int inst_A64_is_direct_branch(uint32_t inst); + +/* +Get branch destination for a direct branch. +*/ +int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc); +int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc); +int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc); + +int inst_ARM_is_indirect_branch(uint32_t inst); +int inst_Thumb_is_indirect_branch(uint32_t inst); +int inst_A64_is_indirect_branch(uint32_t inst); + +int inst_ARM_is_branch_and_link(uint32_t inst); +int inst_Thumb_is_branch_and_link(uint32_t inst); +int inst_A64_is_branch_and_link(uint32_t inst); + +int inst_ARM_is_conditional(uint32_t inst); +int inst_Thumb_is_conditional(uint32_t inst); +int inst_A64_is_conditional(uint32_t inst); + +/* For an IT instruction, return the number of instructions conditionalized + (from 1 to 4). For other instructions, return zero. */ +unsigned int inst_Thumb_is_IT(uint32_t inst); + +typedef enum { + ARM_BARRIER_NONE, + ARM_BARRIER_ISB, + ARM_BARRIER_DMB, + ARM_BARRIER_DSB +} arm_barrier_t; + +arm_barrier_t inst_ARM_barrier(uint32_t inst); +arm_barrier_t inst_Thumb_barrier(uint32_t inst); +arm_barrier_t inst_A64_barrier(uint32_t inst); + +/* +Test whether an instruction is definitely undefined, e.g. because +allocated to a "permanently UNDEFINED" space (UDF mnemonic). +Other instructions besides the ones indicated, may always or +sometimes cause an undefined instruction trap. This call is +intended to be helpful in 'runaway decode' prevention. +*/ +int inst_ARM_is_UDF(uint32_t inst); +int inst_Thumb_is_UDF(uint32_t inst); +int inst_A64_is_UDF(uint32_t inst); + + +/* access sub-type information */ +ocsd_instr_subtype get_instr_subtype(); +void clear_instr_subtype(); + +#endif // ARM_TRC_IDEC_ARMINST_H_INCLUDED + +/* End of File trc_idec_arminst.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_abs_typed_base_i.h b/contrib/opencsd/decoder/include/interfaces/trc_abs_typed_base_i.h new file mode 100644 index 000000000000..0db60770844a --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_abs_typed_base_i.h @@ -0,0 +1,58 @@ +/* + * \file trc_abs_typed_base_i.h + * \brief OpenCSD : + * + * \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_TRC_ABS_TYPED_BASE_I_H_INCLUDED +#define ARM_TRC_ABS_TYPED_BASE_I_H_INCLUDED + +/*! + * @class ITrcTypedBase + * @brief Abstract base class to for interfaces templated types. + * + * This class is used as an abstract base for any interfaces that are specialised using + * template<> types. + * + * Designed to allow interface objects to be passed through generic interfaces into type + * specific templated implmentation handlers and converted/checked using RTTI. + */ +class ITrcTypedBase +{ +public: + ITrcTypedBase() {}; + virtual ~ITrcTypedBase() {}; +}; + +#endif // ARM_TRC_ABS_TYPED_BASE_I_H_INCLUDED + +/* End of File trc_abs_typed_base_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_data_raw_in_i.h b/contrib/opencsd/decoder/include/interfaces/trc_data_raw_in_i.h new file mode 100644 index 000000000000..bf020d706df8 --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_data_raw_in_i.h @@ -0,0 +1,84 @@ +/* + * \file trc_data_raw_in_i.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRCDATA_RAW_IN_I_H_INCLUDED +#define ARM_TRCDATA_RAW_IN_I_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" + +/** @class ITrcDataIn + * + * @brief Interface to either trace data frame deformatter or packet processor. + * + * @ingroup ocsd_interfaces + * + * Interface class to a processor that can consume raw formatted trace byte stream from a trace reader + * or raw source buffer into a deformatter object. + * + * Also used to interface a single trace source ID data stream into a packet processor. + * + */ +class ITrcDataIn { +public: + ITrcDataIn() {}; /**< Default constructor. */ + virtual ~ITrcDataIn() {}; /**< Default destructor. */ + + /*! + * Data input method for a component on the Trace decode datapath. + * Datapath operations passed to the component, which responds with data path response codes. + * + * This API is for raw trace data, which can be:- + * - CoreSight formatted frame data for input to the frame deformatter. + * - Single binary source data for input to a packet decoder. + * + * @param op : Data path operation. + * @param index : Byte index of start of pDataBlock data as offset from start of captured data. May be zero for none-data operation + * @param dataBlockSize : Size of data block. Zero for none-data operation. + * @param *pDataBlock : pointer to data block. Null for none-data operation + * @param *numBytesProcessed : Pointer to count of data used by processor. Set by processor on data operation. Null for none-data operation + * + * @return ocsd_datapath_resp_t : Standard data path response code. + */ + virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) = 0; + +}; + +#endif // ARM_TRCDATA_RAW_IN_I_H_INCLUDED + + +/* End of File trc_data_raw_in_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_data_rawframe_in_i.h b/contrib/opencsd/decoder/include/interfaces/trc_data_rawframe_in_i.h new file mode 100644 index 000000000000..9fc35319b86e --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_data_rawframe_in_i.h @@ -0,0 +1,81 @@ +/* + * \file trc_data_rawframe_in_i.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRCDATA_RAWFRAME_IN_I_H_INCLUDED +#define ARM_TRCDATA_RAWFRAME_IN_I_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" + +/*! + * @class ITrcRawFrameIn + * + * @brief Interface to monitor the raw frame decode progress.. + * + * @ingroup ocsd_interfaces + * + * This interface allows a program to monitor the contents of the CoreSight frames passing through the + * frame deformatter. + * + * + */ +class ITrcRawFrameIn { +public: + ITrcRawFrameIn() {}; /**< Default constructor. */ + virtual ~ITrcRawFrameIn() {}; /**< Default destructor. */ + + /*! + * Interface to monitor CoreSight frame data. Output as blocks of data. + * + * @param op : Data path operation. + * @param index : Byte index of start of pDataBlock data as offset from start of captured data. May be zero for none-data operation + * @param frame_element : Type of frame element being output. + * @param dataBlockSize : size of frame element. + * @param *pDataBlock : pointer to frame data. + * @param traceID : Trace ID when element type ID data. + * + * @return ocsd_err_t : Standard library erroc code. Monitor only, not on data path. + */ + virtual ocsd_err_t TraceRawFrameIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const ocsd_rawframe_elem_t frame_element, + const int dataBlockSize, + const uint8_t *pDataBlock, + const uint8_t traceID) = 0; +}; + + +#endif // ARM_TRCDATA_RAWFRAME_IN_I_H_INCLUDED + +/* End of File trc_data_rawframe_in_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_error_log_i.h b/contrib/opencsd/decoder/include/interfaces/trc_error_log_i.h new file mode 100644 index 000000000000..2fc796f72457 --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_error_log_i.h @@ -0,0 +1,134 @@ +/*! + * \file trc_error_log_i.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_ERROR_LOG_I_H_INCLUDED +#define ARM_TRC_ERROR_LOG_I_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" +#include + +class ocsdError; +class ocsdMsgLogger; + +/*! + * @class ITraceErrorLog + * @brief Error logging interface. + * @ingroup ocsd_interfaces + * + * This class provides a standard interface to the decoder error logger for all trace decode and + * reader components. + * + * Implementation will determine if and how the errors and messages are logged. + * + */ +class ITraceErrorLog +{ +public: + ITraceErrorLog() {}; /**< default constructor */ + virtual ~ITraceErrorLog() {}; /**< default destructor */ + + /*! + * Register a named component error source. Allows the logger to associate errors with components. + * returned handle to be used with subsequent error log calls. + * + * @param &component_name : name of the component. + * + * @return virtual const : Handle associated with the component. + */ + virtual const ocsd_hndl_err_log_t RegisterErrorSource(const std::string &component_name) = 0; + + /*! + * Return the verbosity level of the logger. Errors of the returned ocsd_err_severity_t severity + * or lower will be logged, others are ignored. + * + * @return ocsd_err_severity_t : Current logging severity level. + */ + virtual const ocsd_err_severity_t GetErrorLogVerbosity() const = 0; + + /*! + * Log an error. + * Pass an error object and the component or generic handle to associate with the error. + * Error will be saved for access by GetLastError(). + * + * If logger implementation has output print logging enabled then this may be printed to file or screen. + * + * @param handle : Component handle or standard generic handle + * @param *Error : Pointer to an error object. + */ + virtual void LogError(const ocsd_hndl_err_log_t handle, const ocsdError *Error) = 0; + + /*! + * Log a general message. Associated with component or use generic handle. + * Message logged to same output as errors if output enabled, but not saved for GetLastError() + * + * @param handle : Component handle or standard generic handle. + * @param filter_level : Verbosity filter. + * @param msg : Pointer to an error object. + */ + virtual void LogMessage(const ocsd_hndl_err_log_t handle, const ocsd_err_severity_t filter_level, const std::string &msg ) = 0; + + /*! + * Get a pointer to the last logged error. + * Returns 0 if no errors have been logged. + * + * @return ocsdError *: last error pointer. + */ + virtual ocsdError *GetLastError() = 0; + + /*! + * Get the last error associated with the given Trace source channel ID. + * returns a pointer to the error or 0 if no errors associated with the ID. + * + * @param chan_id : ID. + * + * @return ocsdError *: last error pointer for ID or 0. + */ + virtual ocsdError *GetLastIDError(const uint8_t chan_id) = 0; + + virtual ocsdMsgLogger *getOutputLogger() = 0; + virtual void setOutputLogger(ocsdMsgLogger *pLogger) = 0; + + enum generic_handles { + HANDLE_GEN_ERR = 0, + HANDLE_GEN_WARN, + HANDLE_GEN_INFO, + /* last value in list */ + HANDLE_FIRST_REGISTERED_COMPONENT /**< 1st valid handle value for components registered with logger */ + }; +}; + +#endif // ARM_TRC_ERROR_LOG_I_H_INCLUDED + +/* End of File trc_error_log_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_gen_elem_in_i.h b/contrib/opencsd/decoder/include/interfaces/trc_gen_elem_in_i.h new file mode 100644 index 000000000000..5bad293ff13d --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_gen_elem_in_i.h @@ -0,0 +1,77 @@ +/* + * \file trc_gen_elem_in_i.h + * \brief OpenCSD : Generic Trace Element interface. + * + * \copyright Copyright (c) 2015, 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_TRC_GEN_ELEM_IN_I_H_INCLUDED +#define ARM_TRC_GEN_ELEM_IN_I_H_INCLUDED + +class OcsdTraceElement; + +/*! + * @class ITrcGenElemIn + + * @brief Interface for the input of generic trace elements. + * + * @ingroup ocsd_interfaces + * + * This interface is the principal output attachment point for the trace packet decoders. + * + */ +class ITrcGenElemIn +{ +public: + ITrcGenElemIn() {}; /**< Default constructor. */ + virtual ~ITrcGenElemIn() {}; /**< Default destructor. */ + + + /*! + * Interface for analysis blocks that take generic trace elements as their input. + * Final interface on the decode data path. The index provided is that for the generating + * trace packet. Multiple generic elements may be produced from a single packet so they will + * all have the same start index. + * + * @param index_sop : Trace index for start of packet generating this element. + * @param trc_chan_id : CoreSight Trace ID for this source. + * @param &elem : Generic trace element generated from the deocde data path + * + * @return ocsd_datapath_resp_t : Standard data path response. + */ + virtual ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const OcsdTraceElement &elem) = 0; +}; + +#endif // ARM_TRC_GEN_ELEM_IN_I_H_INCLUDED + +/* End of File trc_gen_elem_in_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_indexer_pkt_i.h b/contrib/opencsd/decoder/include/interfaces/trc_indexer_pkt_i.h new file mode 100644 index 000000000000..02aecda8b039 --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_indexer_pkt_i.h @@ -0,0 +1,77 @@ +/* + * \file trc_indexer_pkt_i.h + * \brief OpenCSD : Trace packet indexer + * + * \copyright Copyright (c) 2015, 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_TRC_INDEXER_PKT_I_H_INCLUDED +#define ARM_TRC_INDEXER_PKT_I_H_INCLUDED + +#include "trc_abs_typed_base_i.h" + +/*! + * @class ITrcPktIndexer + + * @brief Templated interface class to index packet types. + * + * @ingroup ocsd_interfaces + * + * Each protocol version will have an associated indexer that will index significant + * packets such as synchronisation points, timestamps, trigger events. + * + * Creating an index is optional at runtime, but will allow any analysis program to synchronise the + * different trace streams. + * + * Indexes need to be created only once and can be saved for re-use. + * + * Packet processors should be created to support the attachment of an indexer. + * + */ +template +class ITrcPktIndexer : public ITrcTypedBase +{ +public: + ITrcPktIndexer() {}; /**< Default constructor. */ + virtual ~ITrcPktIndexer() {}; /**< Default destructor. */ + + /*! + * Interface method for trace packet indexing. Implementated by a channel packet indexer. + * + * @param index_sop : trace index at the start of the packet. + * @param *packet_type : The packet type being indexed. + */ + virtual void TracePktIndex(const ocsd_trc_index_t index_sop, const Pt *packet_type) = 0; +}; + +#endif // ARM_TRC_INDEXER_PKT_I_H_INCLUDED + +/* End of File trc_indexer_pkt_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_indexer_src_i.h b/contrib/opencsd/decoder/include/interfaces/trc_indexer_src_i.h new file mode 100644 index 000000000000..078efa515253 --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_indexer_src_i.h @@ -0,0 +1,124 @@ +/* + * \file trc_indexer_src_i.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_INDEXER_SRC_I_H_INCLUDED +#define ARM_TRC_INDEXER_SRC_I_H_INCLUDED + +#include +#include "opencsd/ocsd_if_types.h" + +/*! + * @class ITrcSrcIndexCreator + * + * @brief Interface class to index the frame formatted trace stream + * + * @ingroup ocsd_interfaces + * + * This indexer creates an index of trace IDs present in the frame formatted trace stream. + * It will also index any trigger point markers indicated in the frame format. + * + * Indexing is optional at runtime. Indexes can be saved and re-used. + */ +class ITrcSrcIndexCreator +{ +public: + ITrcSrcIndexCreator() {}; /**< Default constructor. */ + virtual ~ITrcSrcIndexCreator() {}; /**< Default destructor. */ + + /*! + * The size of block that the indexer will split trace into - this is effectively the + * index granularity. The indexing will indicate if an indexed element - e.g. a source + * ID - is present in the block. Smaller granularity will mean a larger index but more + * resolution in IDs and event positions. + * + * Block sizes will be power of 2 aligned, not less 256 bytes (16 frames). + * Indexer will choose block size based on total trace size and desired granularity. + * + * @return uint32_t : Size of indexing block. + */ + virtual const uint32_t IndexBlockSize() const; + + /*! + * Index a single ID + * + * @param src_idx : trace index of source ID + * @param ID : The source ID. + * + * @return virtual ocsd_err_t : OCSD_OK if successful. + */ + virtual ocsd_err_t TrcIDIndex(const ocsd_trc_index_t src_idx, const uint8_t ID) = 0; + + /*! + * Index a set of IDs in a block. + * Block is assumed to be one of size IndexBlockSize() + * + * May be used by the deformatter to collate IDs and reduce indexing calls. + * May be used by hardware capture source that has its own index of IDs, to transfer + * indexing information into the decoder indexer. + * + * @param src_idx_start : Index of start of block. + * @param IDs : IDs within the block. + * + * @return virtual ocsd_err_t : OCSD_OK if successful. + */ + virtual ocsd_err_t TrcIDBlockMap(const ocsd_trc_index_t src_idx_start, const std::vector IDs) = 0; + + /*! + * The CoreSight frame format can use a reserved ID to indicate trigger or other + * events programmed into the trace protocol generator. + * This call indexes these events. + * + * @param src_idx : trace index of the event. + * @param event_type : type of event. + * + * @return ocsd_err_t : OCSD_OK if indexed correctly, OCSD_ERR_INVALID_PARAM_VAL if incorrect value used. + */ + virtual ocsd_err_t TrcEventIndex(const ocsd_trc_index_t src_idx, const int event_type) = 0; + + + /*! + * When the frame formatter is using frame syncs (typically TPIU output captured on off chip capture + * device), this index call notes the position of these elements. + * + * @param src_idx : trace index of sync point. + */ + virtual void TrcSyncIndex(const ocsd_trc_index_t src_idx); + +}; + +#endif // ARM_TRC_INDEXER_SRC_I_H_INCLUDED + +/* End of File trc_indexer_src_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_instr_decode_i.h b/contrib/opencsd/decoder/include/interfaces/trc_instr_decode_i.h new file mode 100644 index 000000000000..75af19ff796a --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_instr_decode_i.h @@ -0,0 +1,66 @@ +/* + * \file trc_instr_decode_i.h + * \brief OpenCSD : Interface for instruction decode. + * + * \copyright Copyright (c) 2015, 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_TRC_INSTR_DECODE_I_H_INCLUDED +#define ARM_TRC_INSTR_DECODE_I_H_INCLUDED + +/*! + * @class IInstrDecode + * @ingroup ocsd_interfaces + * @brief Interface class to an instruction opcode decoder. + * + * The opcode decoder needs to be capable of limited decode required for trace + * execution flow determination. + * + */ +class IInstrDecode +{ +public: + IInstrDecode() {}; /**< Default constructor. */ + virtual ~IInstrDecode() {}; /**< Default destructor. */ + + /*! + * Instruction opcode decode for the packet trace decoder to follow the + * instruction execution flow. + * + * @param *instr_info : Structure to pass current opcode, and receive required decode information. + * + * @return ocsd_err_t : OCSD_OK if successful. + */ + virtual ocsd_err_t DecodeInstruction(ocsd_instr_info *instr_info) = 0; +}; + +#endif // ARM_TRC_INSTR_DECODE_I_H_INCLUDED + +/* End of File trc_instr_decode_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_pkt_in_i.h b/contrib/opencsd/decoder/include/interfaces/trc_pkt_in_i.h new file mode 100644 index 000000000000..8f6c5eff6db5 --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_pkt_in_i.h @@ -0,0 +1,80 @@ +/* + * \file trc_pkt_in_i.h + * \brief OpenCSD : Interface for trace protocol packet input + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_IN_I_H_INCLUDED +#define ARM_TRC_PKT_IN_I_H_INCLUDED + +#include "trc_abs_typed_base_i.h" + +/*! + * @class IPktDataIn + * @ingroup ocsd_interfaces + * @brief Interface class providing an input for discrete protocol packets. + * + * Implemented by trace protocol packet decoders to convert packets into + * generic trace elements. + * + * Packet class used will contain information on the latest packet, + * and any intra-packet state. + * + */ +template +class IPktDataIn : public ITrcTypedBase +{ +public: + IPktDataIn() {}; /**< Default constructor. */ + virtual ~IPktDataIn() {}; /**< Default destructor. */ + + /*! + * Interface function to process a single protocol packet. + * Pass a trace index for the start of packet and a pointer to a packet when the + * datapath operation is OCSD_OP_DATA. + * + * @param op : Datapath operation. + * @param index_sop : Trace index for the start of the packet, 0 if not OCSD_OP_DATA. + * @param *p_packet_in : Protocol Packet - when data path operation is OCSD_OP_DATA. null otherwise. + * + * @return ocsd_datapath_resp_t : Standard data path response. + */ + virtual ocsd_datapath_resp_t PacketDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const P *p_packet_in) = 0; + + +}; + +#endif // ARM_TRC_PKT_IN_I_H_INCLUDED + +/* End of File trc_proc_pkt_in_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_pkt_raw_in_i.h b/contrib/opencsd/decoder/include/interfaces/trc_pkt_raw_in_i.h new file mode 100644 index 000000000000..6f7b21383024 --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_pkt_raw_in_i.h @@ -0,0 +1,83 @@ +/* + * \file trc_pkt_raw_in_i.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_RAW_IN_I_H_INCLUDED +#define ARM_TRC_PKT_RAW_IN_I_H_INCLUDED + +#include "trc_abs_typed_base_i.h" + +/*! + * @class IPktRawDataMon + * + * @brief Interface class for packet processor monitor. + * + * @addtogroup ocsd_interfaces + * + * This interface provides a monitor point for the packet processor block. + * The templated interface is called with a complete packet of the given + * type, plus the raw packet bytes. Use for tools which need to display compplete + * packets or require additional processing on raw packet data. + * + * This interface is not part of the data decode path and cannot provide feedback. + * + */ +template +class IPktRawDataMon : public ITrcTypedBase +{ +public: + IPktRawDataMon() {}; /**< Default constructor. */ + virtual ~IPktRawDataMon() {}; /**< Default destructor. */ + + /*! + * Interface monitor function called with a complete packet, or other + * data path operation. + * + * @param op : Datapath operation + * @param index_sop : start of packet index + * @param *pkt : The expanded packet + * @param size : size of packet data bytes + * @param *p_data : the packet data bytes. + * + */ + virtual void RawPacketDataMon( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const P *pkt, + const uint32_t size, + const uint8_t *p_data) = 0; +}; + +#endif // ARM_TRC_PKT_RAW_IN_I_H_INCLUDED + +/* End of File trc_pkt_raw_in_i.h */ diff --git a/contrib/opencsd/decoder/include/interfaces/trc_tgt_mem_access_i.h b/contrib/opencsd/decoder/include/interfaces/trc_tgt_mem_access_i.h new file mode 100644 index 000000000000..effc9b5e161e --- /dev/null +++ b/contrib/opencsd/decoder/include/interfaces/trc_tgt_mem_access_i.h @@ -0,0 +1,91 @@ +/* + * \file trc_tgt_mem_access_i.h + * \brief OpenCSD : Target memory read interface. + * + * \copyright Copyright (c) 2015, 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_TRC_TGT_MEM_ACCESS_I_H_INCLUDED +#define ARM_TRC_TGT_MEM_ACCESS_I_H_INCLUDED + +/*! + * @class ITargetMemAccess + * + * @brief Interface to target memory access. + * + * @ingroup ocsd_interfaces + * + * Read Target memory call is used by the decoder to access the memory location in the + * target memory space for the next instruction(s) to be traced. + * + * Memory data returned is to be little-endian. + * + * The implementator of this interface could either use file(s) containing dumps of memory + * locations from the target, be an elf file reader extracting code, or a live target + * connection, depending on the tool execution context. + * + * + */ +class ITargetMemAccess +{ +public: + ITargetMemAccess() {}; /**< default interface constructor */ + virtual ~ITargetMemAccess() {}; /**< default interface destructor */ + + /*! + * Read a block of target memory into supplied buffer. + * + * Bytes read set less than bytes required, along with a success return code indicates full memory + * location not accessible. Function will return all accessible bytes from the address up to the point + * where the first inaccessible location appears. + * + * The cs_trace_id associates a memory read with a core. Different cores may have different memory spaces, + * the memory access may take this into account. Access will first look in the registered memory areas + * associated with the ID, failing that will look into any global memory spaces. + * + * @param address : Address to access. + * @param cs_trace_id : protocol source trace ID. + * @param mem_space : Memory space to access, (secure, non-secure, optionally with EL, or any). + * @param num_bytes : [in] Number of bytes required. [out] Number of bytes actually read. + * @param *p_buffer : Buffer to fill with the bytes. + * + * @return ocsd_err_t : OCSD_OK on successful access (including memory not available) + */ + virtual ocsd_err_t ReadTargetMemory( const ocsd_vaddr_t address, + const uint8_t cs_trace_id, + const ocsd_mem_space_acc_t mem_space, + uint32_t *num_bytes, + uint8_t *p_buffer) = 0; +}; + + +#endif // ARM_TRC_TGT_MEM_ACCESS_I_H_INCLUDED + +/* End of File trc_tgt_mem_access_i.h */ diff --git a/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc.h b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc.h new file mode 100644 index 000000000000..66f91229da21 --- /dev/null +++ b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc.h @@ -0,0 +1,47 @@ +/* + * \file trc_mem_acc.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_MEM_ACC_H_INCLUDED +#define ARM_TRC_MEM_ACC_H_INCLUDED + +#include "trc_mem_acc_base.h" +#include "trc_mem_acc_bufptr.h" +#include "trc_mem_acc_file.h" +#include "trc_mem_acc_mapper.h" +#include "trc_mem_acc_cb.h" + + +#endif // ARM_TRC_MEM_ACC_H_INCLUDED + +/* End of File trc_mem_acc.h */ diff --git a/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_base.h b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_base.h new file mode 100644 index 000000000000..71b6a816edad --- /dev/null +++ b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_base.h @@ -0,0 +1,244 @@ +/*! + * \file trc_mem_acc_base.h + * \brief OpenCSD : Memory accessor base class. + * + * \copyright Copyright (c) 2015, 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_TRC_MEM_ACC_BASE_H_INCLUDED +#define ARM_TRC_MEM_ACC_BASE_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" +#include + +/*! + * @class TrcMemAccessorBase + * @brief Memory range to access by trace decoder. + * + * Represents a memory access range for the trace decoder. + * Range inclusive from m_startAddress to m_endAddress. + * e.g. a 1k range from 0x1000 has start of 0x1000 and end of 0x13FF + * + * Derived classes provide specific access types such as binary files and memory buffers. + * + */ +class TrcMemAccessorBase +{ +public: + + /** Describes the storage type of the underlying memory accessor */ + enum MemAccTypes { + MEMACC_UNKNOWN, + MEMACC_FILE, //= m_startAddress) && (s_address <= m_endAddress); +} + +inline const bool TrcMemAccessorBase::addrStartOfRange(const ocsd_vaddr_t s_address) const +{ + return (s_address == m_startAddress); +} + + +inline const uint32_t TrcMemAccessorBase::bytesInRange(const ocsd_vaddr_t s_address, const uint32_t reqBytes) const +{ + ocsd_vaddr_t bytesInRange = 0; + if(addrInRange(s_address)) // start not in range, return 0. + { + // bytes available till end address. + bytesInRange = m_endAddress - s_address + 1; + if(bytesInRange > reqBytes) + bytesInRange = reqBytes; + } + return (uint32_t)bytesInRange; +} + +inline const bool TrcMemAccessorBase::overLapRange(const TrcMemAccessorBase *p_test_acc) const +{ + if( addrInRange(p_test_acc->m_startAddress) || + addrInRange(p_test_acc->m_endAddress) + ) + return true; + return false; +} + +inline const bool TrcMemAccessorBase::validateRange() +{ + if(m_startAddress & 0x1) // at least hword aligned for thumb + return false; + if((m_endAddress + 1) & 0x1) + return false; + if(m_startAddress == m_endAddress) // zero length range. + return false; + if(m_startAddress > m_endAddress) // values bakcwards / invalid + return false; + return true; +} + + +class TrcMemAccFactory +{ +public: + /** Accessor Creation */ + static ocsd_err_t CreateBufferAccessor(TrcMemAccessorBase **pAccessor, const ocsd_vaddr_t s_address, const uint8_t *p_buffer, const uint32_t size); + static ocsd_err_t CreateFileAccessor(TrcMemAccessorBase **pAccessor, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset = 0, size_t size = 0); + static ocsd_err_t CreateCBAccessor(TrcMemAccessorBase **pAccessor, const ocsd_vaddr_t s_address, const ocsd_vaddr_t e_address, const ocsd_mem_space_acc_t mem_space); + + /** Accessor Destruction */ + static void DestroyAccessor(TrcMemAccessorBase *pAccessor); +private: + TrcMemAccFactory() {}; + ~TrcMemAccFactory() {}; +}; + +#endif // ARM_TRC_MEM_ACC_BASE_H_INCLUDED + +/* End of File trc_mem_acc_base.h */ diff --git a/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_bufptr.h b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_bufptr.h new file mode 100644 index 000000000000..61ec345abe68 --- /dev/null +++ b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_bufptr.h @@ -0,0 +1,76 @@ +/* + * \file trc_mem_acc_bufptr.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_MEM_ACC_BUFPTR_H_INCLUDED +#define ARM_TRC_MEM_ACC_BUFPTR_H_INCLUDED + +#include "mem_acc/trc_mem_acc_base.h" + +/*! + * @class TrcMemAccBufPtr: + * @brief Trace memory accessor for a memory buffer. + * + * Wraps a memory buffer in an memory range accessor object. + * Takes a copy of the buffer pointer which must remain valid + * for the lifetime of the object. + * + */ +class TrcMemAccBufPtr: public TrcMemAccessorBase +{ +public: + /*! + * Construct the accessor. + * uses the start address as the start of range and calculates the end address + * according to the buffer size + * + * @param s_address : Start address in memory map represented by the data in the buffer. + * @param *p_buffer : pointer to a buffer of binary data. + * @param size : size of the buffer. + * + */ + TrcMemAccBufPtr(const ocsd_vaddr_t s_address, const uint8_t *p_buffer, const uint32_t size); + + virtual ~TrcMemAccBufPtr() {}; /**< default destructor */ + + /** Memory access override - allow decoder to read bytes from the buffer. */ + virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer); + +private: + const uint8_t *m_p_buffer; /**< pointer to the memory buffer */ + const uint32_t m_size; /**< size of the memory buffer. */ +}; + +#endif // ARM_TRC_MEM_ACC_BUFPTR_H_INCLUDED + +/* End of File trc_mem_acc_bufptr.h */ diff --git a/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cb.h b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cb.h new file mode 100644 index 000000000000..df6f9930e4fc --- /dev/null +++ b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cb.h @@ -0,0 +1,81 @@ +/*! + * \file trc_mem_acc_cb.h + * \brief OpenCSD : Callback trace memory accessor. + * + * \copyright Copyright (c) 2015, 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_TRC_MEM_ACC_CB_H_INCLUDED +#define ARM_TRC_MEM_ACC_CB_H_INCLUDED + +#include "mem_acc/trc_mem_acc_base.h" +#include "mem_acc/trc_mem_acc_cb_if.h" + +class TrcMemAccCB : public TrcMemAccessorBase +{ +public: + TrcMemAccCB(const ocsd_vaddr_t s_address, + const ocsd_vaddr_t e_address, + const ocsd_mem_space_acc_t mem_space); + + + virtual ~TrcMemAccCB() {}; + + /** Memory access override - allow decoder to read bytes from the buffer. */ + virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer); + + void setCBIfClass(TrcMemAccCBIF *p_if); + void setCBIfFn(Fn_MemAcc_CB p_fn, const void *p_context); + +private: + TrcMemAccCBIF *m_p_CBclass; // +#include +#include +#include + +#include "opencsd/ocsd_if_types.h" +#include "mem_acc/trc_mem_acc_base.h" + +// an add-on region to a file - allows setting of a region at a none-zero offset for a file. +class FileRegionMemAccessor : public TrcMemAccessorBase +{ +public: + FileRegionMemAccessor() : TrcMemAccessorBase(MEMACC_FILE) {}; + virtual ~FileRegionMemAccessor() {}; + + void setOffset(const size_t offset) { m_file_offset = offset; }; + const size_t getOffset() const { return m_file_offset; }; + + bool operator<(const FileRegionMemAccessor& rhs) { return this->m_startAddress < rhs.m_startAddress; }; + + // not going to use these objects to read bytes - defer to the file class for that. + virtual const uint32_t readBytes(const ocsd_vaddr_t s_address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer) { return 0; }; + + const ocsd_vaddr_t regionStartAddress() const { return m_startAddress; }; + +private: + size_t m_file_offset; +}; + +/*! + * @class TrcMemAccessorFile + * @brief Memory accessor for a binary file. + * + * Memory accessor based on a binary file snapshot of some memory. + * + * Static creation code to allow reference counted accessor usable for + * multiple access maps attached to multiple source trees for the same system. + */ +class TrcMemAccessorFile : public TrcMemAccessorBase +{ +public: + /** read bytes override - reads from file */ + virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer); + +protected: + TrcMemAccessorFile(); /**< protected default constructor */ + virtual ~ TrcMemAccessorFile(); /**< protected default destructor */ + + /** increment reference counter */ + void IncRefCount() { m_ref_count++; }; + + /** decrement reference counter */ + void DecRefCount() { m_ref_count--; }; + + /** get current reference count */ + const int getRefCount() const { return m_ref_count; }; + + /*! + * Initialise accessor with file name and path, and start address. + * File opened and length calculated to determine end address for the range. + * + * @param &pathToFile : Binary file path and name + * @param startAddr : system memory address associated with start of binary datain file. + * + * @return bool : true if set up successfully, false if file could not be opened. + */ + ocsd_err_t initAccessor(const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset, size_t size); + + /** get the file path */ + const std::string &getFilePath() const { return m_file_path; }; + + /** get an offset region if extant for the address */ + FileRegionMemAccessor *getRegionForAddress(const ocsd_vaddr_t startAddr) const; + + /* validate ranges */ + virtual const bool validateRange(); + +public: + + /*! + * File may contain multiple none-overlapping ranges in a single file. + * + * @param startAddr : Address for beginning of byte data. + * @param size : size of range in bytes. + * @param offset : offset into file for that data. + * + * @return bool : true if set successfully. + */ + bool AddOffsetRange(const ocsd_vaddr_t startAddr, const size_t size, const size_t offset); + + /*! + * Override in case we have multiple regions in the file. + * + * @param s_address : Address to test. + * + * @return const bool : true if the address is in range. + */ + virtual const bool addrInRange(const ocsd_vaddr_t s_address) const; + + /*! + * test if an address is the start of range for this accessor + * + * @param s_address : Address to test. + * + * @return const bool : true if the address is start of range. + */ + virtual const bool addrStartOfRange(const ocsd_vaddr_t s_address) const; + + /*! + * Test number of bytes available from the start address, up to the number of requested bytes. + * Tests if all the requested bytes are available from the supplied start address. + * Returns the number available up to full requested amount. + * + * @param s_address : Start address within the range. + * @param reqBytes : Number of bytes needed from the start address. + * + * @return const uint32_t : Bytes available, up to reqBytes. 0 is s_address not in range. + */ + virtual const uint32_t bytesInRange(const ocsd_vaddr_t s_address, const uint32_t reqBytes) const; + + /*! + * test is supplied range accessor overlaps this range. + * + * @param *p_test_acc : Accessor to test for overlap. + * + * @return bool : true if overlap, false if not. + */ + virtual const bool overLapRange(const TrcMemAccessorBase *p_test_acc) const; + + /*! Override to handle ranges and offset accessors plus add in file name. */ + virtual void getMemAccString(std::string &accStr) const; + + + /*! + * Create a file accessor based on the supplied path and address. + * Keeps a list of file accessors created. + * + * File will be checked to ensure valid accessor can be created. + * + * If an accessor using the supplied file is currently in use then a reference to that + * accessor will be returned and the accessor reference counter updated. + * + * @param &pathToFile : Path to binary file + * @param startAddr : Start address of data represented by file. + * + * @return TrcMemAccessorFile * : pointer to accessor if successful, 0 if it could not be created. + */ + static ocsd_err_t createFileAccessor(TrcMemAccessorFile **p_acc, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset = 0, size_t size = 0); + + /*! + * Destroy supplied accessor. + * + * Reference counter decremented and checked and accessor destroyed if no longer in use. + * + * @param *p_accessor : File Accessor to destroy. + */ + static void destroyFileAccessor(TrcMemAccessorFile *p_accessor); + + /*! + * Test if any accessor is currently using the supplied file path + * + * @param &pathToFile : Path to test. + * + * @return bool : true if an accessor exists with this file path. + */ + static const bool isExistingFileAccessor(const std::string &pathToFile); + + /*! + * Get the accessor using the supplied file path + * Use after createFileAccessor if additional memory ranges need + * adding to an exiting file accessor. + * + * @param &pathToFile : Path to test. + * + * @return TrcMemAccessorFile * : none 0 if an accessor exists with this file path. + */ + static TrcMemAccessorFile * getExistingFileAccessor(const std::string &pathToFile); + + + + +private: + static std::map s_FileAccessorMap; /**< map of file accessors in use. */ + +private: + std::ifstream m_mem_file; /**< input binary file stream */ + ocsd_vaddr_t m_file_size; /**< size of the file */ + int m_ref_count; /**< accessor reference count */ + std::string m_file_path; /**< path to input file */ + std::list m_access_regions; /**< additional regions in the file at non-zero offsets */ + bool m_base_range_set; /**< true when offset 0 set */ + bool m_has_access_regions; /**< true if single file contains multiple regions */ +}; + +#endif // ARM_TRC_MEM_ACC_FILE_H_INCLUDED + +/* End of File trc_mem_acc_file.h */ diff --git a/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h new file mode 100644 index 000000000000..07d044ead81c --- /dev/null +++ b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h @@ -0,0 +1,128 @@ +/* + * \file trc_mem_acc_mapper.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_MEM_ACC_MAPPER_H_INCLUDED +#define ARM_TRC_MEM_ACC_MAPPER_H_INCLUDED + +#include + +#include "opencsd/ocsd_if_types.h" +#include "interfaces/trc_tgt_mem_access_i.h" +#include "interfaces/trc_error_log_i.h" +#include "mem_acc/trc_mem_acc_base.h" + +typedef enum _memacc_mapper_t { + MEMACC_MAP_GLOBAL, +} memacc_mapper_t; + +class TrcMemAccMapper : public ITargetMemAccess +{ +public: + TrcMemAccMapper(); + TrcMemAccMapper(bool using_trace_id); + virtual ~TrcMemAccMapper(); + +// decoder memory access interface + virtual ocsd_err_t ReadTargetMemory( const ocsd_vaddr_t address, + const uint8_t cs_trace_id, + const ocsd_mem_space_acc_t mem_space, + uint32_t *num_bytes, + uint8_t *p_buffer); + +// mapper memory area configuration interface + + // add an accessor to this map + virtual ocsd_err_t AddAccessor(TrcMemAccessorBase *p_accessor, const uint8_t cs_trace_id) = 0; + + // remove a specific accessor + virtual ocsd_err_t RemoveAccessor(const TrcMemAccessorBase *p_accessor) = 0; + + + // clear all attached accessors from the map + void RemoveAllAccessors(); + + // remove a single accessor based on address. + ocsd_err_t RemoveAccessorByAddress(const ocsd_vaddr_t st_address, const ocsd_mem_space_acc_t mem_space, const uint8_t cs_trace_id = 0); + + // set the error log. + void setErrorLog(ITraceErrorLog *err_log_i) { m_err_log = err_log_i; }; + + // print out the ranges in this mapper. + virtual void logMappedRanges() = 0; + +protected: + virtual bool findAccessor(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t cs_trace_id) = 0; // set m_acc_curr if found valid range, leave unchanged if not. + virtual bool readFromCurrent(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t cs_trace_id) = 0; + virtual TrcMemAccessorBase *getFirstAccessor() = 0; + virtual TrcMemAccessorBase *getNextAccessor() = 0; + virtual void clearAccessorList() = 0; + + void LogMessage(const std::string &msg); + + TrcMemAccessorBase *m_acc_curr; // most recently used - try this first. + uint8_t m_trace_id_curr; // trace ID for the current accessor + const bool m_using_trace_id; // true if we are using separate memory spaces by TraceID. + ITraceErrorLog *m_err_log; // error log to print out mappings on request. +}; + + +// address spaces common to all sources using this mapper. +// trace id unused. +class TrcMemAccMapGlobalSpace : public TrcMemAccMapper +{ +public: + TrcMemAccMapGlobalSpace(); + virtual ~TrcMemAccMapGlobalSpace(); + + // mapper creation interface - prevent overlaps + virtual ocsd_err_t AddAccessor(TrcMemAccessorBase *p_accessor, const uint8_t cs_trace_id); + + // print out the ranges in this mapper. + virtual void logMappedRanges(); + +protected: + virtual bool findAccessor(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t cs_trace_id); + virtual bool readFromCurrent(const ocsd_vaddr_t address,const ocsd_mem_space_acc_t mem_space, const uint8_t cs_trace_id); + virtual TrcMemAccessorBase *getFirstAccessor(); + virtual TrcMemAccessorBase *getNextAccessor(); + virtual void clearAccessorList(); + virtual ocsd_err_t RemoveAccessor(const TrcMemAccessorBase *p_accessor); + + std::vector m_acc_global; + std::vector::iterator m_acc_it; +}; + +#endif // ARM_TRC_MEM_ACC_MAPPER_H_INCLUDED + +/* End of File trc_mem_acc_mapper.h */ diff --git a/contrib/opencsd/decoder/include/ocsd_if_version.h b/contrib/opencsd/decoder/include/ocsd_if_version.h new file mode 100644 index 000000000000..7d51ba27bdf2 --- /dev/null +++ b/contrib/opencsd/decoder/include/ocsd_if_version.h @@ -0,0 +1,65 @@ +/* + * \file ocsd_if_version.h + * \brief OpenCSD : Library API versioning + * + * \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_IF_VERSION_H_INCLUDED +#define ARM_OCSD_IF_VERSION_H_INCLUDED + +#include + +/** @addtogroup ocsd_interfaces +@{*/ + +/** @name Library Versioning +@{*/ +#define OCSD_VER_MAJOR 0x0 /**< Library Major Version */ +#define OCSD_VER_MINOR 0x8 /**< Library Minor Version */ +#define OCSD_VER_PATCH 0x2 /**< Library Patch Version */ + +/** Library version number - MMMMnnpp format. + MMMM = major version, + nn = minor version, + pp = patch version +*/ +#define OCSD_VER_NUM (((uint32_t)OCSD_VER_MAJOR << 16) | ((uint32_t)OCSD_VER_MINOR << 8) | ((uint32_t)OCSD_VER_PATCH)) + +#define OCSD_VER_STRING "0.8.2" /**< Library Version string */ +#define OCSD_LIB_NAME "OpenCSD Library" /**< Library name string */ +#define OCSD_LIB_SHORT_NAME "OCSD" /**< Library Short name string */ +/** @}*/ + +/** @}*/ + +#endif // ARM_OCSD_IF_VERSION_H_INCLUDED + +/* End of File ocsd_if_version.h */ diff --git a/contrib/opencsd/decoder/include/opencsd.h b/contrib/opencsd/decoder/include/opencsd.h new file mode 100644 index 000000000000..615bbcafa2d9 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd.h @@ -0,0 +1,84 @@ +/*! + * \file opencsd.h + * \brief OpenCSD: Open CoreSight Trace Decoder -Master include file for C++ library + * + * \copyright Copyright (c) 2015, 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_OPENCSD_H_INCLUDED +#define ARM_OPENCSD_H_INCLUDED + +/** C interface types */ +#include "opencsd/ocsd_if_types.h" +#include "opencsd/trc_pkt_types.h" +#include "opencsd/trc_gen_elem_types.h" + +/* C++ abstract interfaces */ +#include "interfaces/trc_data_raw_in_i.h" +#include "interfaces/trc_data_rawframe_in_i.h" +#include "interfaces/trc_error_log_i.h" +#include "interfaces/trc_gen_elem_in_i.h" +#include "interfaces/trc_instr_decode_i.h" +#include "interfaces/trc_pkt_in_i.h" +#include "interfaces/trc_pkt_raw_in_i.h" +#include "interfaces/trc_tgt_mem_access_i.h" + +/* protocol base classes and generic elements */ +#include "common/ocsd_version.h" +#include "common/ocsd_error.h" +#include "common/trc_gen_elem.h" +#include "common/trc_core_arch_map.h" + +/** Implemented Protocol decoders */ +#include "common/trc_frame_deformatter.h" + +#include "opencsd/etmv3/etmv3_decoder.h" +#include "opencsd/etmv4/etmv4_decoder.h" +#include "opencsd/ptm/ptm_decoder.h" +#include "opencsd/stm/stm_decoder.h" + +/** C++ library object types */ +#include "common/ocsd_error_logger.h" +#include "common/ocsd_msg_logger.h" +#include "i_dec/trc_i_decode.h" +#include "mem_acc/trc_mem_acc.h" + +/* printers for builtin packet elements */ +#include "pkt_printers/trc_pkt_printers.h" +#include "pkt_printers/trc_print_fact.h" + +/** The decode tree and decoder register*/ +#include "common/ocsd_lib_dcd_register.h" +#include "common/ocsd_dcd_tree.h" + + +#endif // ARM_OPENCSD_H_INCLUDED + +/* End of File opencsd.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_cust_fact.h b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_cust_fact.h new file mode 100644 index 000000000000..f9e6a95104cc --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_cust_fact.h @@ -0,0 +1,54 @@ +/* +* \file ocsd_c_api_cust_fact.h +* \brief OpenCSD : Custom decoder factory API functions +* +* \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_C_API_CUST_FACT_H_INCLUDED +#define ARM_OCSD_C_API_CUST_FACT_H_INCLUDED + +#include "ocsd_c_api_types.h" +#include "ocsd_c_api_custom.h" + +/* Declarations for the functions implemented in the custom decoder factory. */ + +/** Required function to create a decoder instance - fills in the decoder struct supplied. */ +ocsd_err_t CreateCustomDecoder(const int create_flags, const void *decoder_cfg, ocsd_extern_dcd_inst_t *p_decoder_inst); + +/** Required Function to destroy a decoder instance - indicated by decoder handle */ +ocsd_err_t DestroyCustomDecoder(const void *decoder_handle); + +/** Required Function to extract the CoreSight Trace ID from the configuration structure */ +ocsd_err_t GetCSIDFromConfig(const void *decoder_cfg, unsigned char *p_csid); + +/** Optional Function to convert a protocol specific trace packet to human readable string */ +ocsd_err_t PacketToString(const void *trc_pkt, char *buffer, const int buflen); + +#endif /* ARM_OCSD_C_API_CUST_FACT_H_INCLUDED */ diff --git a/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_cust_impl.h b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_cust_impl.h new file mode 100644 index 000000000000..245ce162752e --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_cust_impl.h @@ -0,0 +1,158 @@ +/* +* \file ocsd_c_api_cust_impl.h +* \brief OpenCSD : Custom decoder implementation common API definitions +* +* \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_C_API_CUST_IMPL_H_INCLUDED +#define ARM_OCSD_C_API_CUST_IMPL_H_INCLUDED + +#include "opencsd/c_api/ocsd_c_api_types.h" +#include "opencsd/c_api/ocsd_c_api_custom.h" + +/** @addtogroup ocsd_ext_dcd +@{*/ + +/**@name External decoder - Inline utility functions. + @brief inline functions used in decoders to call the various library callback functionality. + + Functions manipulate and use the ocsd_extern_dcd_cb_fns structure to call into the library, + with appropriate checking for initialisation and usage flags. + +@{*/ + +static inline ocsd_datapath_resp_t lib_cb_GenElemOp(const ocsd_extern_dcd_cb_fns *callbacks, + const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const ocsd_generic_trace_elem *elem) +{ + if (callbacks->fn_gen_elem_out) + return callbacks->fn_gen_elem_out(callbacks->lib_context, index_sop, trc_chan_id, elem); + return OCSD_RESP_FATAL_NOT_INIT; +} + +static inline ocsd_err_t lib_cb_LogError(const ocsd_extern_dcd_cb_fns *callbacks, + const ocsd_err_severity_t filter_level, + const ocsd_err_t code, + const ocsd_trc_index_t idx, + const uint8_t chan_id, + const char *pMsg) +{ + if (callbacks->fn_log_error) + { + callbacks->fn_log_error(callbacks->lib_context, filter_level, code, idx, chan_id, pMsg); + return OCSD_OK; + } + return OCSD_ERR_NOT_INIT; +} + +static inline ocsd_err_t lib_cb_LogMsg(const ocsd_extern_dcd_cb_fns *callbacks, + const ocsd_err_severity_t filter_level, + const char *pMsg) +{ + if (callbacks->fn_log_msg) + { + callbacks->fn_log_msg(callbacks->lib_context, filter_level, pMsg); + return OCSD_OK; + } + return OCSD_ERR_NOT_INIT; +} + +static inline ocsd_err_t lib_cb_DecodeArmInst(const ocsd_extern_dcd_cb_fns *callbacks, + ocsd_instr_info *instr_info) +{ + if (callbacks->fn_arm_instruction_decode) + return callbacks->fn_arm_instruction_decode(callbacks->lib_context, instr_info); + return OCSD_ERR_NOT_INIT; +} + +static inline ocsd_err_t lib_cb_MemAccess(const ocsd_extern_dcd_cb_fns *callbacks, + const ocsd_vaddr_t address, + const uint8_t cs_trace_id, + const ocsd_mem_space_acc_t mem_space, + uint32_t *num_bytes, + uint8_t *p_buffer) +{ + if (callbacks->fn_memory_access) + return callbacks->fn_memory_access(callbacks->lib_context, address, cs_trace_id, mem_space, num_bytes, p_buffer); + return OCSD_ERR_NOT_INIT; +} + +static inline void lib_cb_PktMon(const ocsd_extern_dcd_cb_fns *callbacks, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *pkt, + const uint32_t size, + const uint8_t *p_data) +{ + if (callbacks->packetCBFlags & OCSD_CUST_DCD_PKT_CB_USE_MON) + { + if (callbacks->fn_packet_mon) + callbacks->fn_packet_mon(callbacks->lib_context, op, index_sop, pkt, size, p_data); + } +} + +static inline int lib_cb_usePktMon(const ocsd_extern_dcd_cb_fns *callbacks) +{ + return (callbacks->packetCBFlags & OCSD_CUST_DCD_PKT_CB_USE_MON); +} + +/* callback function to connect to the packet sink interface, on the main decode +data path - used if decoder created as packet processor only */ +static inline ocsd_datapath_resp_t lib_cb_PktDataSink(const ocsd_extern_dcd_cb_fns *callbacks, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *pkt) +{ + if (callbacks->packetCBFlags & OCSD_CUST_DCD_PKT_CB_USE_SINK) + { + if (callbacks->fn_packet_data_sink) + return callbacks->fn_packet_data_sink(callbacks->lib_context, op, index_sop, pkt); + else + return OCSD_RESP_FATAL_NOT_INIT; + } + return OCSD_RESP_CONT; +} + +static inline int lib_cb_usePktSink(const ocsd_extern_dcd_cb_fns *callbacks) +{ + return (callbacks->packetCBFlags & OCSD_CUST_DCD_PKT_CB_USE_SINK); +} + +static inline void lib_cb_updatePktCBFlags(ocsd_extern_dcd_cb_fns *callbacks, const int newFlags) +{ + callbacks->packetCBFlags = newFlags; +} + +/** @}*/ + +/** @}*/ + +#endif /* ARM_OCSD_C_API_CUST_IMPL_H_INCLUDED */ diff --git a/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_custom.h b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_custom.h new file mode 100644 index 000000000000..ada0a68cb3db --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_custom.h @@ -0,0 +1,253 @@ +/* + * \file ocsd_c_api_custom.h + * \brief OpenCSD : Custom decoder interface types and structures + * + * \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_C_API_CUSTOM_H_INCLUDED +#define ARM_OCSD_C_API_CUSTOM_H_INCLUDED + +#include "ocsd_c_api_types.h" + + + /** @defgroup ocsd_ext_dcd OpenCSD Library : Custom External Decoder C-API + @brief Set of types, structures and interfaces for attaching custom decoders via the C-API + + These types, functions and structures define the required API between a custom external decoder + and the library, which will allow the decoder to interact with the library and use library + resources in the same way as the built-in decoders. + + The external decoder must implement:- + - A set of factory functions that allow the creation and destruction of decoder instances. + - A set of call-in and call-back functions plus data structures allowing interaction with the library. + + @{*/ + + +/**@name External decoder - Input Interfaces +@{*/ + +/* Custom decoder C-API interface types. */ + +/** Raw trace data input function - a decoder must have one of these + Implements ITrcDataIn with the addition of a decoder handle to provide context in the decoder. + */ +typedef ocsd_datapath_resp_t (* fnTraceDataIn)( const void *decoder_handle, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + +/** Function to update the in-use flags for the packet sinks + + Defines if the fnPktMonCB or fnPktDataSinkCB callbacks are in use by the library. + If so then it is expected that the decoder should call them when trace protocol packets are generated. + + This function must be implemented in the decoder. + + @param decoder_handle : handle for decoder accessed by this call. + @param flags: Values indicating interfaces in use / not in use. [ OCSD_CUST_DCD_PKT_CB_USE_MON or OCSD_CUST_DCD_PKT_CB_USE_SINK] +*/ +typedef void (* fnUpdatePktMonFlags)(const void *decoder_handle, const int flags); + + + +/** Flag to indicate the the packet monitor (fnPktMonCB) is in use in the library */ +#define OCSD_CUST_DCD_PKT_CB_USE_MON 0x1 + +/** Flag to indicate the the packet sink (fnPktDataSinkCB) is in use in the library - only if trace packet processing only mode. */ +#define OCSD_CUST_DCD_PKT_CB_USE_SINK 0x2 + +/** Owned by the library instance object, this structure is filled in by the ocsd_extern_dcd_fact_t createDecoder() function. */ +typedef struct _ocsd_extern_dcd_inst { + /* Mandatory decoder call back functions - library initialisation will fail without these. */ + fnTraceDataIn fn_data_in; /**< raw trace data input function to decoder */ + fnUpdatePktMonFlags fn_update_pkt_mon; /**< update the packet monitor / sink usage flags */ + + /* Decoder instance data */ + void *decoder_handle; /**< Instance handle for the decoder - used by library to call the decoder call in functions */ + char *p_decoder_name; /**< type name of the decoder - may be used in logging */ + uint8_t cs_id; /**< Coresight ID for the instance - extracted from the config on creation. */ + +} ocsd_extern_dcd_inst_t; + +/** @}*/ + + +/**@name External decoder - Callback Interfaces +@{*/ + + +/** callback function to connect into the generic element output point + Implements ITrcGenElemIn::TraceElemIn with addition of library context pointer. + */ +typedef ocsd_datapath_resp_t (* fnGenElemOpCB)( const void *lib_context, + const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const ocsd_generic_trace_elem *elem); + +/** callback functions to connect into the library error logging mechanism + Implements ITraceErrorLog::LogError with addition of library context pointer. +*/ +typedef void (* fnLogErrorCB)( const void *lib_context, + const ocsd_err_severity_t filter_level, + const ocsd_err_t code, + const ocsd_trc_index_t idx, + const uint8_t chan_id, + const char *pMsg); + +/** callback functions to connect into the library error logging mechanism + Implements ITraceErrorLog::LogMessage with addition of library context pointer. +*/ +typedef void (* fnLogMsgCB)(const void *lib_context, const ocsd_err_severity_t filter_level, const char *msg); + +/** callback function to connect an ARM instruction decoder + Implements IInstrDecode::DecodeInstruction with addition of library context pointer. +*/ +typedef ocsd_err_t (* fnDecodeArmInstCB)(const void *lib_context, ocsd_instr_info *instr_info); + +/** callback function to connect the memory accessor interface + Implements ITargetMemAccess::ReadTargetMemory with addition of library context pointer. +*/ +typedef ocsd_err_t (* fnMemAccessCB)(const void *lib_context, + const ocsd_vaddr_t address, + const uint8_t cs_trace_id, + const ocsd_mem_space_acc_t mem_space, + uint32_t *num_bytes, + uint8_t *p_buffer); + +/** callback function to connect to the packet monitor interface of the packet processor + Implements IPktRawDataMon::RawPacketDataMon with addition of library context pointer. +*/ +typedef void (* fnPktMonCB)( const void *lib_context, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *pkt, + const uint32_t size, + const uint8_t *p_data); + +/** callback function to connect to the packet sink interface, on the main decode + data path - use if decoder created as packet processor only + + Implements IPktDataIn::PacketDataIn with addition of library context pointer. +*/ +typedef ocsd_datapath_resp_t (* fnPktDataSinkCB)( const void *lib_context, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *pkt); + +/** an instance of this is owned by the decoder, filled in by the library - allows the CB fns in the library decode tree to be called. */ +typedef struct _ocsd_extern_dcd_cb_fns { +/* Callback functions */ + fnGenElemOpCB fn_gen_elem_out; /**< Callback to output a generic element. */ + fnLogErrorCB fn_log_error; /**< Callback to output an error. */ + fnLogMsgCB fn_log_msg; /**< Callback to output a message. */ + fnDecodeArmInstCB fn_arm_instruction_decode; /**< Callback to decode an ARM instruction. */ + fnMemAccessCB fn_memory_access; /**< Callback to access memory images related to the trace capture. */ + fnPktMonCB fn_packet_mon; /**< Callback to output trace packet to packet monitor. */ + fnPktDataSinkCB fn_packet_data_sink; /**< Callback to output trace packet to packet sink - if in pack processing only mode. */ +/* CB in use flags. */ + int packetCBFlags; /**< Flags to indicate if the packet sink / packet monitor callbacks are in use. ( OCSD_CUST_DCD_PKT_CB_USE_MON / OCSD_CUST_DCD_PKT_CB_USE_SINK) */ +/* library context */ + const void *lib_context; /**< library context pointer - use in callbacks to allow the library to load the correct context data. */ +} ocsd_extern_dcd_cb_fns; + +/** @}*/ + +/**@name External decoder - Decoder Factory +@{*/ + +/** Function to create a decoder instance + + Create a decoder instance according to the create_flags parameter and the supplied decoder_cfg structure. + Fill in the p_decoder_inst structure, copy the p_lib_callbacks information for use in the decoder instance. + + Create flags can be: + - OCSD_CREATE_FLG_PACKET_PROC: decoder will split the incoming trace into trace protocol packets and not further decode them. fnPktDataSinkCB likely to be in use. + - OCSD_CREATE_FLG_FULL_DECODER: decoder will split the incoming trace into trace protocol packets and further decode them to recreate program flow or other generic trace output. + + @param create_flags : Sets the decoder operating mode. + @param *decoder_cfg : Hardware specific configuration for this trace element. + @param *p_lib_callbacks : Library callbacks plus context pointer. + @param *p_decoder_inst : Structure representing the new decoder instance being created. Filled in by create function to contain handle and call-in functions for the library. + + @return ocsd_err_t : Library error code - RCDTL_OK if successful +*/ +typedef ocsd_err_t (* fnCreateCustomDecoder)(const int create_flags, const void *decoder_cfg, const ocsd_extern_dcd_cb_fns *p_lib_callbacks, ocsd_extern_dcd_inst_t *p_decoder_inst); + +/** Function to destroy a decoder instance indicated by decoder handle. + + @param decoder_handle : Instance handle for decoder. + + @return ocsd_err_t : Library error code - RCDTL_OK if successful +*/ +typedef ocsd_err_t (* fnDestroyCustomDecoder)(const void *decoder_handle); + +/** Function to extract the CoreSight Trace ID from the configuration structure. + + @param *decoder_cfg : Hardware specific configuration for this trace element. + @parma *p_csid : location to write CoreSight Trace ID value. + + @return ocsd_err_t : Library error code - RCDTL_OK if successful +*/ +typedef ocsd_err_t (* fnGetCSIDFromConfig)(const void *decoder_cfg, unsigned char *p_csid); + +/** Function to convert a protocol specific trace packet to human readable string + + @param *trc_pkt : protocol specific packet structure. + @param *buffer : buffer to fill with string. + @param buflen : length of string buffer. + + @return ocsd_err_t : Library error code - RCDTL_OK if successful +*/ +typedef ocsd_err_t (* fnPacketToString)(const void *trc_pkt, char *buffer, const int buflen); + +/** set of functions and callbacks to create an extern custom decoder in the library + via the C API interface. This structure is registered with the library by name and + then decoders of the type can be created on the decode tree. +*/ +typedef struct _ocsd_extern_dcd_fact { + fnCreateCustomDecoder createDecoder; /**< Function pointer to create a decoder instance. */ + fnDestroyCustomDecoder destroyDecoder; /**< Function pointer to destroy a decoder instance. */ + fnGetCSIDFromConfig csidFromConfig; /**< Function pointer to extract the CSID from a config structure */ + fnPacketToString pktToString; /**< Function pointer to print a trace protocol packet in this decoder */ + + ocsd_trace_protocol_t protocol_id; /**< protocol ID assigned during registration. */ +} ocsd_extern_dcd_fact_t; + +/** @}*/ + +/** @}*/ + + +#endif // ARM_OCSD_C_API_CUSTOM_H_INCLUDED + +/* End of File ocsd_c_api_custom.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_types.h b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_types.h new file mode 100644 index 000000000000..ca61e0aaed32 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_types.h @@ -0,0 +1,105 @@ +/*! + * \file ocsd_c_api_types.h + * \brief OpenCSD : Trace Decoder "C" API types. + * + * \copyright Copyright (c) 2015, 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_C_API_TYPES_H_INCLUDED +#define ARM_OCSD_C_API_TYPES_H_INCLUDED + +/* select the library types that are C compatible - the interface data types */ +#include "opencsd/ocsd_if_types.h" +#include "opencsd/trc_gen_elem_types.h" +#include "opencsd/trc_pkt_types.h" + +/* pull in the protocol decoder types. */ +#include "opencsd/etmv3/trc_pkt_types_etmv3.h" +#include "opencsd/etmv4/trc_pkt_types_etmv4.h" +#include "opencsd/ptm/trc_pkt_types_ptm.h" +#include "opencsd/stm/trc_pkt_types_stm.h" + +/** @ingroup lib_c_api +@{*/ + + +/* Specific C-API only types */ + +/** Handle to decode tree */ +typedef void * dcd_tree_handle_t; + +/** define invalid handle value for decode tree handle */ +#define C_API_INVALID_TREE_HANDLE (dcd_tree_handle_t)0 + +/** Logger output printer - no output. */ +#define C_API_MSGLOGOUT_FLG_NONE 0x0 +/** Logger output printer - output to file. */ +#define C_API_MSGLOGOUT_FLG_FILE 0x1 +/** Logger output printer - output to stderr. */ +#define C_API_MSGLOGOUT_FLG_STDERR 0x2 +/** Logger output printer - output to stdout. */ +#define C_API_MSGLOGOUT_FLG_STDOUT 0x4 +/** Logger output printer - mask of valid flags. */ +#define C_API_MSGLOGOUT_MASK 0x7 + +/** function pointer type for decoder outputs. all protocols, generic data element input */ +typedef ocsd_datapath_resp_t (* FnTraceElemIn)( const void *p_context, + const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const ocsd_generic_trace_elem *elem); + +/** function pointer type for packet processor packet output sink, packet analyser/decoder input - generic declaration */ +typedef ocsd_datapath_resp_t (* FnDefPktDataIn)(const void *p_context, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *p_packet_in); + +/** function pointer type for packet processor packet monitor sink, raw packet monitor / display input - generic declaration */ +typedef void (* FnDefPktDataMon)(const void *p_context, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *p_packet_in, + const uint32_t size, + const uint8_t *p_data); + +/** function pointer tyee for library default logger output to allow client to print zero terminated output string */ +typedef void (* FnDefLoggerPrintStrCB)(const void *p_context, const char *psz_msg_str, const int str_len); + +/** Callback interface type when attaching monitor/sink to packet processor */ +typedef enum _ocsd_c_api_cb_types { + OCSD_C_API_CB_PKT_SINK, /** Attach to the packet processor primary packet output (CB fn is FnDefPktDataIn) */ + OCSD_C_API_CB_PKT_MON, /** Attach to the packet processor packet monitor output (CB fn is FnDefPktDataMon) */ +} ocsd_c_api_cb_types; + +/** @}*/ + +#endif // ARM_OCSD_C_API_TYPES_H_INCLUDED + +/* End of File ocsd_c_api_types.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/c_api/opencsd_c_api.h b/contrib/opencsd/decoder/include/opencsd/c_api/opencsd_c_api.h new file mode 100644 index 000000000000..f9f4ed4b8613 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/c_api/opencsd_c_api.h @@ -0,0 +1,485 @@ +/*! + * \file opencsd_c_api.h + * \brief OpenCSD : "C" API + * + * \copyright Copyright (c) 2015, 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_OPENCSD_C_API_H_INCLUDED +#define ARM_OPENCSD_C_API_H_INCLUDED + +/** @defgroup lib_c_api OpenCSD Library : Library "C" API. + @brief "C" API for the OpenCSD Library + + Set of "C" wrapper functions for the OpenCSD library. + + Defines API, functions and callback types. +@{*/ + +/* ensure C bindings */ + +#if defined(WIN32) /* windows bindings */ + /** Building the C-API DLL **/ + #ifdef _OCSD_C_API_DLL_EXPORT + #ifdef __cplusplus + #define OCSD_C_API extern "C" __declspec(dllexport) + #else + #define OCSD_C_API __declspec(dllexport) + #endif + #else + /** building or using the static C-API library **/ + #if defined(_LIB) || defined(OCSD_USE_STATIC_C_API) + #ifdef __cplusplus + #define OCSD_C_API extern "C" + #else + #define OCSD_C_API + #endif + #else + /** using the C-API DLL **/ + #ifdef __cplusplus + #define OCSD_C_API extern "C" __declspec(dllimport) + #else + #define OCSD_C_API __declspec(dllimport) + #endif + #endif + #endif +#else /* linux bindings */ + #ifdef __cplusplus + #define OCSD_C_API extern "C" + #else + #define OCSD_C_API + #endif +#endif + +#include "ocsd_c_api_types.h" +#include "ocsd_c_api_custom.h" + +/** @name Library Version API + +@{*/ +/** Get Library version. Return a 32 bit version in form MMMMnnpp - MMMM = major verison, nn = minor version, pp = patch version */ +OCSD_C_API uint32_t ocsd_get_version(void); + +/** Get library version string */ +OCSD_C_API const char * ocsd_get_version_str(void); +/** @}*/ + +/*---------------------- Trace Decode Tree ----------------------------------------------------------------------------------*/ + +/** @name Library Decode Tree API +@{*/ + +/*! + * Create a decode tree. + * + * @param src_type : Type of tree - formatted input, or single source input + * @param deformatterCfgFlags : Formatter flags - determine presence of frame syncs etc. + * + * @return dcd_tree_handle_t : Handle to the decode tree. Handle value set to 0 if creation failed. + */ +OCSD_C_API dcd_tree_handle_t ocsd_create_dcd_tree(const ocsd_dcd_tree_src_t src_type, const uint32_t deformatterCfgFlags); + +/*! + * Destroy a decode tree. + * + * Also destroys all the associated processors and decoders for the tree. + * + * @param handle : Handle for decode tree to destroy. + */ +OCSD_C_API void ocsd_destroy_dcd_tree(const dcd_tree_handle_t handle); + +/*! + * Input trace data into the decoder. + * + * Large trace source buffers can be broken down into smaller fragments. + * + * @param handle : Handle to decode tree. + * @param op : Datapath operation. + * @param index : Trace buffer byte index for the start of the supplied data block. + * @param dataBlockSize : Size of data block. + * @param *pDataBlock : Pointer to data block. + * @param *numBytesProcessed : Number of bytes actually processed by the decoder. + * + * @return ocsd_datapath_resp_t : Datapath response code (CONT/WAIT/FATAL) + */ +OCSD_C_API ocsd_datapath_resp_t ocsd_dt_process_data(const dcd_tree_handle_t handle, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + + +/*---------------------- Generic Trace Element Output --------------------------------------------------------------*/ + +/*! + * Set the trace element output callback function. + * + * This function will be called for each decoded generic trace element generated by + * any full trace decoder in the decode tree. + * + * A single function is used for all trace source IDs in the decode tree. + * + * @param handle : Handle to decode tree. + * @param pFn : Pointer to the callback function. + * @param p_context : opaque context pointer value used in callback function. + * + * @return ocsd_err_t : Library error code - OCSD_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_set_gen_elem_outfn(const dcd_tree_handle_t handle, FnTraceElemIn pFn, const void *p_context); + +/*---------------------- Trace Decoders ----------------------------------------------------------------------------------*/ +/*! +* Creates a decoder that is registered with the library under the supplied name. +* Flags determine if a full packet processor / packet decoder pair or +* packet processor only is created. +* Uses the supplied configuration structure. +* +* @param handle : Handle to decode tree. +* @param *decoder_name : Registered name of the decoder to create. +* @param create_flags : Decoder creation options. +* @param *decoder_cfg : Pointer to a valid configuration structure for the named decoder. +* @param *pCSID : Pointer to location to return the configured CoreSight trace ID for the decoder. +* +* @return ocsd_err_t : Library error code - OCSD_OK if successful. +*/ +OCSD_C_API ocsd_err_t ocsd_dt_create_decoder(const dcd_tree_handle_t handle, + const char *decoder_name, + const int create_flags, + const void *decoder_cfg, + unsigned char *pCSID + ); + +/*! +* Remove a decoder from the tree and destroy it. +* +* @param handle : Handle to decode tree. +* @param CSID : Configured CoreSight trace ID for the decoder. +* +* @return ocsd_err_t : Library error code - OCSD_OK if successful. +*/ +OCSD_C_API ocsd_err_t ocsd_dt_remove_decoder( const dcd_tree_handle_t handle, + const unsigned char CSID); + + +/*! +* Attach a callback function to the packet processor. +* +* The callback_type defines the attachment point, either the main packet output +* (only if no decoder attached), or the packet monitor. +* +* @param handle : Handle to decode tree. +* @param CSID : Configured CoreSight trace ID for the decoder. +* @param callback_type : Attachment point +* @param p_fn_pkt_data_in : Pointer to the callback function. +* @param p_context : Opaque context pointer value used in callback function. +* +* @return ocsd_err_t : Library error code - OCSD_OK if successful. +*/ +OCSD_C_API ocsd_err_t ocsd_dt_attach_packet_callback( const dcd_tree_handle_t handle, + const unsigned char CSID, + const ocsd_c_api_cb_types callback_type, + void *p_fn_callback_data, + const void *p_context); + + + + + + +/** @}*/ +/*---------------------- Memory Access for traced opcodes ----------------------------------------------------------------------------------*/ +/** @name Library Memory Accessor configuration on decode tree. + @brief Configure the memory regions available for decode. + + Full decode requires memory regions set up to allow access to the traced + opcodes. Add memory buffers or binary file regions to a map of regions. + +@{*/ + +/*! + * Add a binary file based memory range accessor to the decode tree. + * + * Adds the entire binary file as a memory space to be accessed + * + * @param handle : Handle to decode tree. + * @param address : Start address of memory area. + * @param mem_space : Associated memory space. + * @param *filepath : Path to binary data file. + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_add_binfile_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const char *filepath); + +/*! + * Add a binary file based memory range accessor to the decode tree. + * + * Add a binary file that contains multiple regions of memory with differing + * offsets wihtin the file. + * + * A linked list of file_mem_region_t structures is supplied. Each structure contains an + * offset into the binary file, the start address for this offset and the size of the region. + * + * @param handle : Handle to decode tree. + * @param region_list : Array of memory regions in the file. + * @param num_regions : Size of region array + * @param mem_space : Associated memory space. + * @param *filepath : Path to binary data file. + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_add_binfile_region_mem_acc(const dcd_tree_handle_t handle, const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const char *filepath); + +/*! + * Add a memory buffer based memory range accessor to the decode tree. + * + * @param handle : Handle to decode tree. + * @param address : Start address of memory area. + * @param mem_space : Associated memory space. + * @param *p_mem_buffer : pointer to memory buffer. + * @param mem_length : Size of memory buffer. + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_add_buffer_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length); + + +/*! + * Add a memory access callback function. The decoder will call the function for opcode addresses in the + * address range supplied for the memory spaces covered. + * + * @param handle : Handle to decode tree. + * @param st_address : Start address of memory area covered by the callback. + * @param en_address : End address of the memory area covered by the callback. (inclusive) + * @param mem_space : Memory space(s) covered by the callback. + * @param p_cb_func : Callback function + * @param p_context : opaque context pointer value used in callback function. + * + * @return OCSD_C_API ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_add_callback_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context); + +/*! + * Remove a memory accessor by address and memory space. + * + * @param handle : Handle to decode tree. + * @param st_address : Start address of memory accessor. + * @param mem_space : Memory space(s) covered by the accessor. + * + * @return OCSD_C_API ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_remove_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t st_address, const ocsd_mem_space_acc_t mem_space); + +/* + * Print the mapped memory accessor ranges to the configured logger. + * + * @param handle : Handle to decode tree. + */ +OCSD_C_API void ocsd_tl_log_mapped_mem_ranges(const dcd_tree_handle_t handle); + +/** @}*/ + +/** @name Library Default Error Log Object API + @brief Configure the default error logging object in the library. + + Objects created by the decode trees will use this error logger. Configure for + desired error severity, and to enable print or logfile output. + +@{*/ + +/*---------------------- Library Logging and debug ----------------------------------------------------------------------------------*/ +/*! + * Initialise the library error logger. + * + * Choose severity of errors logger, and if the errors will be logged to screen and / or logfile. + * + * @param verbosity : Severity of errors that will be logged. + * @param create_output_logger : Set to none-zero to create an output printer. + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_def_errlog_init(const ocsd_err_severity_t verbosity, const int create_output_logger); + +/*! + * Configure the output logger. Choose STDOUT, STDERR and/or log to file. + * Optionally provide a log file name. + * + * @param output_flags : OR combination of required C_API_MSGLOGOUT_FLG_* flags. + * @param *log_file_name : optional filename if logging to file. Set to NULL if not needed. + * + * @return OCSD_C_API ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_def_errlog_config_output(const int output_flags, const char *log_file_name); + +/*! + * Configure the library default error logger to send all strings it is outputting back to the client + * to allow printing within the client application. This is in additional to any other log destinations + * set in ocsd_def_errlog_init(). + * + * @param *p_context : opaque context pointer + * @param p_str_print_cb : client callback function to "print" logstring. + */ +OCSD_C_API ocsd_err_t ocsd_def_errlog_set_strprint_cb(const dcd_tree_handle_t handle, void *p_context, FnDefLoggerPrintStrCB p_str_print_cb); + +/*! + * Print a message via the library output printer - if enabled. + * + * @param *msg : Message to output. + * + */ +OCSD_C_API void ocsd_def_errlog_msgout(const char *msg); + + +/** @}*/ + +/** @name Packet to string interface + +@{*/ + +/*! + * Take a packet structure and render a string representation of the packet data. + * + * Returns a '0' terminated string of (buffer_size - 1) length or less. + * + * @param pkt_protocol : Packet protocol type - used to interpret the packet pointer + * @param *p_pkt : pointer to a valid packet structure of protocol type. cast to void *. + * @param *buffer : character buffer for string. + * @param buffer_size : size of character buffer. + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_pkt_str(const ocsd_trace_protocol_t pkt_protocol, const void *p_pkt, char *buffer, const int buffer_size); + +/*! + * Get a string representation of the generic trace element. + * + * @param *p_pkt : pointer to valid generic element structure. + * @param *buffer : character buffer for string. + * @param buffer_size : size of character buffer. + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_gen_elem_str(const ocsd_generic_trace_elem *p_pkt, char *buffer, const int buffer_size); + + +/*! + * Init a generic element with type, clearing any flags etc. + */ +OCSD_C_API void ocsd_gen_elem_init(ocsd_generic_trace_elem *p_pkt, const ocsd_gen_trc_elem_t elem_type); + +/** @}*/ + +/** @name Library packet and data printer control API + @brief Allows client to use libraries packet and data printers to log packets etc rather than attach callbacks + to packet output and use packet to string calls. +@{*/ + +/*! + * Set a raw frame printer on the trace frame demuxer. Allows inspection of raw trace data frames for debug. + * Prints via the library default error logging mechanisms. + * + * The flags input determines the data printed. OR combination of one or both of: + * OCSD_DFRMTR_PACKED_RAW_OUT : Output the undemuxed raw data frames. + * OCSD_DFRMTR_UNPACKED_RAW_OUT : Output the raw data by trace ID after unpacking the frame. + * + * @param handle : Handle to decode tree. + * @param flags : indicates type of raw frames to print. + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_set_raw_frame_printer(const dcd_tree_handle_t handle, int flags); + +/*! + * Set a library printer on the generic element output of a full decoder. + * + * @param handle : Handle to decode tree. + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_set_gen_elem_printer(const dcd_tree_handle_t handle); + +/*! + * Attach a library printer to the packet processor. May be attached to the main packet output, or the monitor + * output if the main packet output is to be attached to a packet decoder in the datapath. + * + * @param handle : Handle to decode tree. + * @param cs_id : Coresight trace ID for stream to print. + * @param monitor: 0 to attach printer directly to datapath packet output, 1 to attach to packet monitor output + * + * @return ocsd_err_t : Library error code - RCDTL_OK if successful. + */ +OCSD_C_API ocsd_err_t ocsd_dt_set_pkt_protocol_printer(const dcd_tree_handle_t handle, uint8_t cs_id, int monitor); + +/** @}*/ + + +/** @name Custom Decoder API functions + +@{*/ + +/** Register a custom decoder with the library + + @param *name : Name under which to register the decoder. + @param *p_dcd_fact : Custom decoder factory structure. + + @return ocsd_err_t : Library error code - RCDTL_OK if successful. +*/ +OCSD_C_API ocsd_err_t ocsd_register_custom_decoder(const char *name, ocsd_extern_dcd_fact_t *p_dcd_fact); + +/** Clear all registered decoders - library cleanup + + @return ocsd_err_t : Library error code - RCDTL_OK if successful. +*/ +OCSD_C_API ocsd_err_t ocsd_deregister_decoders(void); + +/** Get a string representation of a custom protocol packet. + + Specific function to extract the packet string for a custom protocol ID only. Custom IDs are allocated to decoder factories + during the ocsd_register_custom_decoder() process. + + This function is called by ocsd_pkt_str() when the incoming protocol is a custom ID. + + @param pkt_protocol : Packet protocol type - must be in the custom ID range ( >= OCSD_PROTOCOL_CUSTOM_0, < OCSD_PROTOCOL_END) + @param *p_pkt : pointer to a valid packet structure of protocol type. cast to void *. + @param *buffer : character buffer for string. + @param buffer_size : size of character buffer. + + @return ocsd_err_t : Library error code - RCDTL_OK if successful, OCSD_ERR_NO_PROTOCOL if input ID not in custom range or not in use. +*/ +OCSD_C_API ocsd_err_t ocsd_cust_protocol_to_str(const ocsd_trace_protocol_t pkt_protocol, const void *trc_pkt, char *buffer, const int buflen); + +/** @}*/ + + +/** @}*/ + +#endif // ARM_OPENCSD_C_API_H_INCLUDED + +/* End of File opencsd_c_api.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv3/etmv3_decoder.h b/contrib/opencsd/decoder/include/opencsd/etmv3/etmv3_decoder.h new file mode 100644 index 000000000000..2d5b7281aed6 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv3/etmv3_decoder.h @@ -0,0 +1,47 @@ +/* + * \file etmv3_decoder.h + * \brief OpenCSD : Top level header file for ETMv3 decoder + * + * \copyright Copyright (c) 2015, 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_ETMV3_DECODER_H_INCLUDED +#define ARM_ETMV3_DECODER_H_INCLUDED + +#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h" +#include "opencsd/etmv3/trc_pkt_elem_etmv3.h" +#include "opencsd/etmv3/trc_pkt_proc_etmv3.h" +#include "opencsd/etmv3/trc_pkt_types_etmv3.h" +#include "opencsd/etmv3/trc_pkt_decode_etmv3.h" + +#endif // ARM_ETMV3_DECODER_H_INCLUDED + +/* End of File etmv3_decoder.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv3/trc_cmp_cfg_etmv3.h b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_cmp_cfg_etmv3.h new file mode 100644 index 000000000000..509de204a4e6 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_cmp_cfg_etmv3.h @@ -0,0 +1,235 @@ +/* + * \file trc_cmp_cfg_etmv3.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_CMP_CFG_ETMV3_H_INCLUDED +#define ARM_TRC_CMP_CFG_ETMV3_H_INCLUDED + +#include "trc_pkt_types_etmv3.h" +#include "common/trc_cs_config.h" + + +/** @addtogroup ocsd_protocol_cfg +@{*/ + +/** @name ETMV3 configuration +@{*/ + + +/*! + * @class EtmV3Config + * @brief Interpreter class for etm v3 config structure. + * + * Provides quick value interpretation methods for the ETMv3 config register values. + * Primarily inlined for efficient code. + * + */ +class EtmV3Config : public CSConfig +{ +public: + EtmV3Config(); /**< Default constructor */ + EtmV3Config(const ocsd_etmv3_cfg *cfg_regs); + ~EtmV3Config() {}; /**< Default destructor */ + + /* register bit constants. */ + static const uint32_t CTRL_DATAVAL = 0x4; + static const uint32_t CTRL_DATAADDR = 0x8; + static const uint32_t CTRL_CYCLEACC = 0x1000; + static const uint32_t CTRL_DATAONLY = 0x100000; + static const uint32_t CTRL_TS_ENA = (0x1 << 28); + static const uint32_t CTRL_VMID_ENA = (0x1 << 30); + + static const uint32_t CCER_HAS_TS = (0x1 << 22); + static const uint32_t CCER_VIRTEXT = (0x1 << 26); + static const uint32_t CCER_TS64BIT = (0x1 << 29); + + static const uint32_t IDR_ALTBRANCH = 0x100000; + +// operations to convert to and from C-API structure + + //! copy assignment operator for C-API base structure into class. + EtmV3Config & operator=(const ocsd_etmv3_cfg *p_cfg); + + //! cast operator returning struct const reference + operator const ocsd_etmv3_cfg &() const { return m_cfg; }; + //! cast operator returning struct const pointer + operator const ocsd_etmv3_cfg *() const { return &m_cfg; }; + + //! combination enum to describe trace mode. + enum EtmTraceMode { + TM_INSTR_ONLY, //!< instruction only trace + TM_I_DATA_VAL, //!< instruction + data value + TM_I_DATA_ADDR, //!< instruction + data address + TM_I_DATA_VAL_ADDR, //!< instr + data value + data address + TM_DATAONLY_VAL, //!< data value trace + TM_DATAONLY_ADDR, //!< data address trace + TM_DATAONLY_VAL_ADDR //!< data value + address trace + }; + + EtmTraceMode const GetTraceMode() const; //!< return trace mode + + const bool isInstrTrace() const; //!< instruction trace present. + const bool isDataValTrace() const; //!< data value trace present. + const bool isDataAddrTrace() const; //!< data address trace present. + const bool isDataTrace() const; //!< either or both data trace types present. + + const bool isCycleAcc() const; //!< return true if cycle accurate tracing enabled. + + const int MinorRev() const; //!< return X revision in 3.X + + const bool isV7MArch() const; //!< source is V7M architecture + const bool isAltBranch() const; //!< Alternate branch packet encoding used. + + const int CtxtIDBytes() const; //!< number of context ID bytes traced 1,2,4; + const bool hasVirtExt() const; //!< processor has virtualisation extensions. + const bool isVMIDTrace() const; //!< VMID tracing enabled. + + const bool hasTS() const; //!< Timestamps implemented in trace. + const bool isTSEnabled() const; //!< Timestamp trace is enabled. + const bool TSPkt64() const; //!< timestamp packet is 64 bits in size. + + virtual const uint8_t getTraceID() const; //!< CoreSight Trace ID for this device. + + const ocsd_arch_version_t getArchVersion() const; //!< architecture version + const ocsd_core_profile_t getCoreProfile() const; //!< core profile. + +private: + ocsd_etmv3_cfg m_cfg; + +}; + + +/* inlines for the bit interpretations */ + +inline EtmV3Config & EtmV3Config::operator=(const ocsd_etmv3_cfg *p_cfg) +{ + m_cfg = *p_cfg; + return *this; +} + +inline const bool EtmV3Config::isCycleAcc() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_CYCLEACC) != 0); +} + +//! return X revision in 3.X +inline const int EtmV3Config::MinorRev() const +{ + return ((int)m_cfg.reg_idr & 0xF0) >> 4; +} + +inline const bool EtmV3Config::isInstrTrace() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_DATAONLY) == 0); +} + +inline const bool EtmV3Config::isDataValTrace() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_DATAVAL) != 0); +} + +inline const bool EtmV3Config::isDataAddrTrace() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_DATAADDR) != 0); +} + +//! either or both data trace present +inline const bool EtmV3Config::isDataTrace() const +{ + return (bool)((m_cfg.reg_ctrl & (CTRL_DATAADDR | CTRL_DATAVAL)) != 0); +} + +inline const bool EtmV3Config::isV7MArch() const +{ + return (bool)((m_cfg.arch_ver == ARCH_V7) && (m_cfg.core_prof == profile_CortexM)); +} + +//! has alternate branch encoding +inline const bool EtmV3Config::isAltBranch() const +{ + return (bool)(((m_cfg.reg_idr & IDR_ALTBRANCH) != 0) && (MinorRev() >= 4)); +} + +//! processor implements virtualisation extensions. +inline const bool EtmV3Config::hasVirtExt() const +{ + return (bool)((m_cfg.reg_ccer & CCER_VIRTEXT) != 0); +} + +//! TS packet is 64 bit. +inline const bool EtmV3Config::TSPkt64() const +{ + return (bool)((m_cfg.reg_ccer & CCER_TS64BIT) != 0); +} + +//! TS implemented. +inline const bool EtmV3Config::hasTS() const +{ + return (bool)((m_cfg.reg_ccer & CCER_HAS_TS) != 0); +} + +//! TS is enabled in the trace +inline const bool EtmV3Config::isTSEnabled() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_TS_ENA) != 0); +} + +//! tracing VMID +inline const bool EtmV3Config::isVMIDTrace() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_VMID_ENA) != 0); +} + +inline const uint8_t EtmV3Config::getTraceID() const +{ + return (uint8_t)(m_cfg.reg_trc_id & 0x7F); +} + +inline const ocsd_arch_version_t EtmV3Config::getArchVersion() const +{ + return m_cfg.arch_ver; +} + +inline const ocsd_core_profile_t EtmV3Config::getCoreProfile() const +{ + return m_cfg.core_prof; +} + +/** @}*/ + +/** @}*/ + +#endif // ARM_TRC_CMP_CFG_ETMV3_H_INCLUDED + +/* End of File trc_cmp_cfg_etmv3.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv3/trc_dcd_mngr_etmv3.h b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_dcd_mngr_etmv3.h new file mode 100644 index 000000000000..c3a96ffcb5ee --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_dcd_mngr_etmv3.h @@ -0,0 +1,57 @@ +/* + * \file trc_dcd_mngr_etmv3.h + * \brief OpenCSD : ETMv3 decoder manager / handler specialisation + * + * \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_TRC_DCD_MNGR_ETMV3_H_INCLUDED +#define ARM_TRC_DCD_MNGR_ETMV3_H_INCLUDED + +#include "common/ocsd_dcd_mngr.h" +#include "trc_pkt_decode_etmv3.h" +#include "trc_pkt_proc_etmv3.h" +#include "trc_cmp_cfg_etmv3.h" +#include "trc_pkt_types_etmv3.h" + +class DecoderMngrEtmV3 : public DecodeMngrFullDcd< EtmV3TrcPacket, + ocsd_etmv3_pkt_type, + EtmV3Config, + ocsd_etmv3_cfg, + TrcPktProcEtmV3, + TrcPktDecodeEtmV3> +{ +public: + DecoderMngrEtmV3(const std::string &name) : DecodeMngrFullDcd(name,OCSD_PROTOCOL_ETMV3) {}; + virtual ~DecoderMngrEtmV3() {}; +}; + +#endif // ARM_TRC_DCD_MNGR_ETMV3_H_INCLUDED + +/* End of File trc_dcd_mngr_etmv3.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_decode_etmv3.h b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_decode_etmv3.h new file mode 100644 index 000000000000..b2139c0d9e68 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_decode_etmv3.h @@ -0,0 +1,274 @@ +/*! + * \file trc_pkt_decode_etmv3.h + * \brief OpenCSD : ETMv3 decode + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_DECODE_ETMV3_H_INCLUDED +#define ARM_TRC_PKT_DECODE_ETMV3_H_INCLUDED + +#include "common/trc_pkt_decode_base.h" +#include "common/trc_gen_elem.h" +#include "common/ocsd_pe_context.h" +#include "common/ocsd_code_follower.h" +#include "common/ocsd_gen_elem_list.h" + +#include "opencsd/etmv3/trc_pkt_elem_etmv3.h" +#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h" + +/**************** Atom handling class **************************************/ +class Etmv3Atoms +{ +public: + Etmv3Atoms(const bool isCycleAcc); + ~Etmv3Atoms() {}; + + //! initialise the atom and index values + void initAtomPkt(const EtmV3TrcPacket *in_pkt, const ocsd_trc_index_t &root_index); + + const ocsd_atm_val getCurrAtomVal() const; + const int numAtoms() const; //!< number of atoms + const ocsd_trc_index_t pktIndex() const; //!< originating packet index + + const bool hasAtomCC() const; //!< cycle count for current atom? + const uint32_t getAtomCC() const; //!< cycle count for current atom + const uint32_t getRemainCC() const; //!< get residual cycle count for remaining atoms + + void clearAtom(); //!< clear the current atom, set the next. + void clearAll(); //!< clear all + +private: + + // Atom PHDR packet formats from ETMv3 spec - defines content of header. + enum { + ATOM_PHDR_FMT_1 = 1, + ATOM_PHDR_FMT_2, + ATOM_PHDR_FMT_3, + ATOM_PHDR_FMT_4, + }; + + + + ocsd_pkt_atom m_atom; /**< atom elements - non zero number indicates valid atom count */ + uint8_t m_p_hdr_fmt; /**< if atom elements, associated phdr format */ + uint32_t m_cycle_count; + ocsd_trc_index_t m_root_index; //!< root index for the atom packet + bool m_isCCPacket; +}; + + +inline Etmv3Atoms::Etmv3Atoms(const bool isCycleAcc) +{ + m_isCCPacket = isCycleAcc; +} + +//! initialise the atom and index values +inline void Etmv3Atoms::initAtomPkt(const EtmV3TrcPacket *in_pkt, const ocsd_trc_index_t &root_index) +{ + m_atom = in_pkt->getAtom(); + m_p_hdr_fmt = in_pkt->getPHdrFmt(); + m_cycle_count = in_pkt->getCycleCount(); +} + +inline const ocsd_atm_val Etmv3Atoms::getCurrAtomVal() const +{ + return (m_atom.En_bits & 0x1) ? ATOM_E : ATOM_N; +} + +inline const int Etmv3Atoms::numAtoms() const +{ + return m_atom.num; +} + +inline const ocsd_trc_index_t Etmv3Atoms::pktIndex() const +{ + return m_root_index; +} + +inline const bool Etmv3Atoms::hasAtomCC() const +{ + bool hasCC = false; + if(!m_isCCPacket) + return hasCC; + + switch(m_p_hdr_fmt) + { + case ATOM_PHDR_FMT_4: + default: + break; + + case ATOM_PHDR_FMT_3: + case ATOM_PHDR_FMT_1: + hasCC = true; + break; + + case ATOM_PHDR_FMT_2: + hasCC = (m_atom.num > 1); // first of 2 has W state + break; + } + return hasCC; +} + +inline const uint32_t Etmv3Atoms::getAtomCC() const +{ + uint32_t CC = 0; + if(!m_isCCPacket) + return CC; + + switch(m_p_hdr_fmt) + { + case ATOM_PHDR_FMT_4: // no CC in format 4 + default: + break; + + case ATOM_PHDR_FMT_3: // single CC with optional E atom + CC = m_cycle_count; + break; + + case ATOM_PHDR_FMT_2: // single W on first of 2 atoms + CC = (m_atom.num > 1) ? 1: 0; + break; + + case ATOM_PHDR_FMT_1: // each atom has 1 CC. + CC = 1; + break; + } + return CC; +} + +inline const uint32_t Etmv3Atoms::getRemainCC() const +{ + uint32_t CC = 0; + if(!m_isCCPacket) + return CC; + + switch(m_p_hdr_fmt) + { + case ATOM_PHDR_FMT_4: // no CC in format 4 + default: + break; + + case ATOM_PHDR_FMT_3: + CC = m_cycle_count; + break; + + case ATOM_PHDR_FMT_2: + CC = (m_atom.num > 1) ? 1: 0; + break; + + case ATOM_PHDR_FMT_1: + CC = m_atom.num; + break; + } + return CC; +} + +inline void Etmv3Atoms::clearAtom() +{ + m_atom.En_bits >>=1; + if(m_atom.num) + m_atom.num--; +} + +inline void Etmv3Atoms::clearAll() +{ + m_atom.num = 0; +} + +/********** Main decode class ****************************************************/ +class TrcPktDecodeEtmV3 : public TrcPktDecodeBase +{ +public: + TrcPktDecodeEtmV3(); + TrcPktDecodeEtmV3(int instIDNum); + virtual ~TrcPktDecodeEtmV3(); + +protected: + /* implementation packet decoding interface */ + virtual ocsd_datapath_resp_t processPacket(); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const uint8_t getCoreSightTraceID() { return m_CSID; }; + + /* local decode methods */ + void initDecoder(); //!< initial state on creation (zeros all config) + void resetDecoder(); //!< reset state to start of decode. (moves state, retains config) + + ocsd_datapath_resp_t decodePacket(bool &pktDone); //!< decode a packet + + ocsd_datapath_resp_t processISync(const bool withCC, const bool firstSync = false); + ocsd_datapath_resp_t processBranchAddr(); + ocsd_datapath_resp_t processPHdr(); + + ocsd_datapath_resp_t sendUnsyncPacket(); //!< send an initial unsync packet when decoder starts + + OcsdTraceElement *GetNextOpElem(ocsd_datapath_resp_t &resp); //!< get the next element from the element list. + +private: + void setNeedAddr(bool bNeedAddr); + void pendExceptionReturn(); + bool preISyncValid(ocsd_etmv3_pkt_type pkt_type); +//** intra packet state; + + OcsdCodeFollower m_code_follower; //!< code follower for instruction trace + + ocsd_vaddr_t m_IAddr; //!< next instruction address + bool m_bNeedAddr; //!< true if an address is needed (current out of date / invalid) + bool m_bSentUnknown; //!< true if we have sent an unknown address packet for this phase of needing an address. + bool m_bWaitISync; //!< true if waiting for first ISync packet + + OcsdPeContext m_PeContext; //!< save context data before sending in output packet + + OcsdGenElemList m_outputElemList; //!< list of output elements + + +//** Other packet decoder state; + + // trace decode FSM + typedef enum { + NO_SYNC, //!< pre start trace - init state or after reset or overflow, loss of sync. + WAIT_ASYNC, //!< waiting for a-sync packet. + WAIT_ISYNC, //!< waiting for i-sync packet. + DECODE_PKTS, //!< processing a packet + SEND_PKTS, //!< sending packets. + } processor_state_t; + + processor_state_t m_curr_state; + + uint8_t m_CSID; //!< Coresight trace ID for this decoder. +}; + + +#endif // ARM_TRC_PKT_DECODE_ETMV3_H_INCLUDED + +/* End of File trc_pkt_decode_etmv3.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_elem_etmv3.h b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_elem_etmv3.h new file mode 100644 index 000000000000..a874ea30c861 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_elem_etmv3.h @@ -0,0 +1,261 @@ +/* + * \file trc_pkt_elem_etmv3.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_ELEM_ETMV3_H_INCLUDED +#define ARM_TRC_PKT_ELEM_ETMV3_H_INCLUDED + +#include "trc_pkt_types_etmv3.h" +#include "common/trc_printable_elem.h" +#include "common/trc_pkt_elem_base.h" + +/** @addtogroup trc_pkts +@{*/ + +/*! + * @class EtmV3TrcPacket + * @brief ETMv3 Trace Protocol Packet. + * + * This class represents a single ETMv3 trace packet, along with intra packet state. + * + */ +class EtmV3TrcPacket : public TrcPacketBase, public trcPrintableElem +{ +public: + EtmV3TrcPacket(); + ~EtmV3TrcPacket(); + +// conversions between C-API struct and C++ object types + // assign from C-API struct + EtmV3TrcPacket &operator =(const ocsd_etmv3_pkt* p_pkt); + + // allow const cast to C-API struct to pass C++ object + operator const ocsd_etmv3_pkt*() const { return &m_pkt_data; }; + operator const ocsd_etmv3_pkt&() const { return m_pkt_data; }; + + // override c_pkt to pass out the packet data struct. + virtual const void *c_pkt() const { return &m_pkt_data; }; + +// update interface - set packet values + void Clear(); //!< clear update data in packet ready for new one. + void ResetState(); //!< reset intra packet state data -on full decoder reset. + + void SetType(const ocsd_etmv3_pkt_type p_type); + void SetErrType(const ocsd_etmv3_pkt_type e_type); + void UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits); + void SetException( const ocsd_armv7_exception type, + const uint16_t number, + const bool cancel, + const bool cm_type, + const int irq_n = 0, + const int resume = 0); + void UpdateNS(const int NS); + void UpdateAltISA(const int AltISA); + void UpdateHyp(const int Hyp); + void UpdateISA(const ocsd_isa isa); + void UpdateContextID(const uint32_t contextID); + void UpdateVMID(const uint8_t VMID); + void UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits); + + bool UpdateAtomFromPHdr(const uint8_t pHdr, const bool cycleAccurate); //!< Interpret P Hdr, return true if valid, false if not. + + void SetDataOOOTag(const uint8_t tag); + void SetDataValue(const uint32_t value); + void UpdateDataAddress(const uint32_t value, const uint8_t valid_bits); + void UpdateDataEndian(const uint8_t BE_Val); + void SetCycleCount(const uint32_t cycleCount); + void SetISyncReason(const ocsd_iSync_reason reason); + void SetISyncHasCC(); + void SetISyncIsLSiP(); + void SetISyncNoAddr(); + +// packet status interface - get packet info. + const ocsd_etmv3_pkt_type getType() const { return m_pkt_data.type; }; + const bool isBadPacket() const; + + const int AltISA() const { return m_pkt_data.context.curr_alt_isa; }; + const ocsd_isa ISA() const { return m_pkt_data.curr_isa; }; + const bool changedISA() const { return m_pkt_data.curr_isa != m_pkt_data.prev_isa; }; + + // any of the context elements updated? + const bool isCtxtUpdated() const; + const bool isCtxtFlagsUpdated() const { return (m_pkt_data.context.updated == 1); }; + const bool isNS() const { return m_pkt_data.context.curr_NS; }; + const bool isHyp() const { return m_pkt_data.context.curr_Hyp; }; + + const bool isCtxtIDUpdated() const { return (m_pkt_data.context.updated_c == 1); } + const uint32_t getCtxtID() const { return m_pkt_data.context.ctxtID; }; + const bool isVMIDUpdated() const { return (m_pkt_data.context.updated_v == 1); } + const uint32_t getVMID() const { return m_pkt_data.context.VMID; }; + + const uint32_t getCycleCount() const { return m_pkt_data.cycle_count; }; + const uint64_t getTS() const { return m_pkt_data.timestamp; }; + + const bool isExcepPkt() const { return (m_pkt_data.exception.bits.present == 1); }; + const ocsd_armv7_exception excepType() const { return m_pkt_data.exception.type; }; + const uint16_t excepNum() const { return m_pkt_data.exception.number; }; + const bool isExcepCancel() const { return (m_pkt_data.exception.bits.present == 1) && (m_pkt_data.exception.bits.cancel == 1); }; + + const ocsd_iSync_reason getISyncReason() const { return m_pkt_data.isync_info.reason; }; + const bool getISyncHasCC() const { return m_pkt_data.isync_info.has_cycle_count; }; + const bool getISyncIsLSiPAddr() const { return m_pkt_data.isync_info.has_LSipAddress; }; + const bool getISyncNoAddr() const { return m_pkt_data.isync_info.no_address; }; + + const ocsd_vaddr_t getAddr() const { return m_pkt_data.addr.val; }; + const ocsd_vaddr_t getDataAddr() const { return m_pkt_data.data.addr.val; }; + + const ocsd_pkt_atom &getAtom() const { return m_pkt_data.atom; }; + const uint8_t getPHdrFmt() const { return m_pkt_data.p_hdr_fmt; }; + + +// printing + virtual void toString(std::string &str) const; + virtual void toStringFmt(const uint32_t fmtFlags, std::string &str) const; + +private: + const char *packetTypeName(const ocsd_etmv3_pkt_type type, const char **ppDesc) const; + void getBranchAddressStr(std::string &valStr) const; + void getAtomStr(std::string &valStr) const; + void getISyncStr(std::string &valStr) const; + void getISAStr(std::string &isaStr) const; + void getExcepStr(std::string &excepStr) const; + + ocsd_etmv3_pkt m_pkt_data; +}; + +inline void EtmV3TrcPacket::UpdateNS(const int NS) +{ + m_pkt_data.context.curr_NS = NS; + m_pkt_data.context.updated = 1; +}; + +inline void EtmV3TrcPacket::UpdateAltISA(const int AltISA) +{ + m_pkt_data.context.curr_alt_isa = AltISA; + m_pkt_data.context.updated = 1; +} + +inline void EtmV3TrcPacket::UpdateHyp(const int Hyp) +{ + m_pkt_data.context.curr_Hyp = Hyp; + m_pkt_data.context.updated = 1; +} + +inline void EtmV3TrcPacket::UpdateISA(const ocsd_isa isa) +{ + m_pkt_data.prev_isa = m_pkt_data.curr_isa; + m_pkt_data.curr_isa = isa; +} + +inline void EtmV3TrcPacket::SetType(const ocsd_etmv3_pkt_type p_type) +{ + m_pkt_data.type = p_type; +} + +inline void EtmV3TrcPacket::SetErrType(const ocsd_etmv3_pkt_type e_type) +{ + m_pkt_data.err_type = m_pkt_data.type; + m_pkt_data.type = e_type; +} + +inline const bool EtmV3TrcPacket::isBadPacket() const +{ + return (m_pkt_data.type >= ETM3_PKT_BAD_SEQUENCE); +} + +inline void EtmV3TrcPacket::SetDataOOOTag(const uint8_t tag) +{ + m_pkt_data.data.ooo_tag = tag; +} + +inline void EtmV3TrcPacket::SetDataValue(const uint32_t value) +{ + m_pkt_data.data.value = value; + m_pkt_data.data.update_dval = 1; +} + +inline void EtmV3TrcPacket::UpdateContextID(const uint32_t contextID) +{ + m_pkt_data.context.updated_c = 1; + m_pkt_data.context.ctxtID = contextID; +} + +inline void EtmV3TrcPacket::UpdateVMID(const uint8_t VMID) +{ + m_pkt_data.context.updated_v = 1; + m_pkt_data.context.VMID = VMID; +} + +inline void EtmV3TrcPacket::UpdateDataEndian(const uint8_t BE_Val) +{ + m_pkt_data.data.be = BE_Val; + m_pkt_data.data.update_be = 1; +} + +inline void EtmV3TrcPacket::SetCycleCount(const uint32_t cycleCount) +{ + m_pkt_data.cycle_count = cycleCount; +} + +inline void EtmV3TrcPacket::SetISyncReason(const ocsd_iSync_reason reason) +{ + m_pkt_data.isync_info.reason = reason; +} + +inline void EtmV3TrcPacket::SetISyncHasCC() +{ + m_pkt_data.isync_info.has_cycle_count = 1; +} + +inline void EtmV3TrcPacket::SetISyncIsLSiP() +{ + m_pkt_data.isync_info.has_LSipAddress = 1; +} + +inline void EtmV3TrcPacket::SetISyncNoAddr() +{ + m_pkt_data.isync_info.no_address = 1; +} + +inline const bool EtmV3TrcPacket::isCtxtUpdated() const +{ + return (m_pkt_data.context.updated_v == 1) || + (m_pkt_data.context.updated == 1) || + (m_pkt_data.context.updated_c == 1); +} + +/** @}*/ +#endif // ARM_TRC_PKT_ELEM_ETMV3_H_INCLUDED + +/* End of File trc_pkt_elem_etmv3.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_proc_etmv3.h b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_proc_etmv3.h new file mode 100644 index 000000000000..5a7f959df4aa --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_proc_etmv3.h @@ -0,0 +1,81 @@ +/* + * \file trc_pkt_proc_etmv3.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PROC_ETMV3_H_INCLUDED +#define ARM_TRC_PKT_PROC_ETMV3_H_INCLUDED + +#include "trc_pkt_types_etmv3.h" +#include "common/trc_pkt_proc_base.h" + +class EtmV3PktProcImpl; +class EtmV3TrcPacket; +class EtmV3Config; + +/** @addtogroup ocsd_pkt_proc +@{*/ + + +class TrcPktProcEtmV3 : public TrcPktProcBase< EtmV3TrcPacket, ocsd_etmv3_pkt_type, EtmV3Config> +{ +public: + TrcPktProcEtmV3(); + TrcPktProcEtmV3(int instIDNum); + virtual ~TrcPktProcEtmV3(); + +protected: + /* implementation packet processing interface */ + virtual ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const bool isBadPacket() const; + + friend class EtmV3PktProcImpl; + + EtmV3PktProcImpl *m_pProcessor; +}; + + +#define ETMV3_OPFLG_UNFORMATTED_SOURCE 0x00010000 /**< Single ETM source from bypassed formatter - need to check for EOT markers */ + +/** @}*/ + +#endif // ARM_TRC_PKT_PROC_ETMV3_H_INCLUDED + +/* End of File trc_pkt_proc_etm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_types_etmv3.h b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_types_etmv3.h new file mode 100644 index 000000000000..c2e01147995d --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv3/trc_pkt_types_etmv3.h @@ -0,0 +1,178 @@ +/* + * \file trc_pkt_types_etmv3.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_ETM3_PKT_TYPES_ETMV3_H_INCLUDED +#define ARM_TRC_ETM3_PKT_TYPES_ETMV3_H_INCLUDED + +#include "opencsd/trc_pkt_types.h" + +/** @addtogroup trc_pkts +@{*/ + +/** @name ETMv3 Packet Types +@{*/ + +typedef enum _ocsd_etmv3_pkt_type +{ + +// markers for unknown packets + ETM3_PKT_NOERROR, //!< no error in packet - supplimentary data. + ETM3_PKT_NOTSYNC, //!< no sync found yet + ETM3_PKT_INCOMPLETE_EOT, //!< flushing incomplete/empty packet at end of trace. + +// markers for valid packets + ETM3_PKT_BRANCH_ADDRESS, + ETM3_PKT_A_SYNC, + ETM3_PKT_CYCLE_COUNT, + ETM3_PKT_I_SYNC, + ETM3_PKT_I_SYNC_CYCLE, + ETM3_PKT_TRIGGER, + ETM3_PKT_P_HDR, + ETM3_PKT_STORE_FAIL, + ETM3_PKT_OOO_DATA, + ETM3_PKT_OOO_ADDR_PLC, + ETM3_PKT_NORM_DATA, + ETM3_PKT_DATA_SUPPRESSED, + ETM3_PKT_VAL_NOT_TRACED, + ETM3_PKT_IGNORE, + ETM3_PKT_CONTEXT_ID, + ETM3_PKT_VMID, + ETM3_PKT_EXCEPTION_ENTRY, + ETM3_PKT_EXCEPTION_EXIT, + ETM3_PKT_TIMESTAMP, + +// internal processing types + ETM3_PKT_BRANCH_OR_BYPASS_EOT, + +// packet errors + ETM3_PKT_BAD_SEQUENCE, //!< invalid sequence for packet type + ETM3_PKT_BAD_TRACEMODE, //!< invalid packet type for this trace mode. + ETM3_PKT_RESERVED //!< packet type reserved. + +} ocsd_etmv3_pkt_type; + +typedef struct _ocsd_etmv3_excep { + ocsd_armv7_exception type; /**< exception type. */ + uint16_t number; /**< exception as number */ + struct { + uint32_t present:1; /**< exception present in packet */ + uint32_t cancel:1; /**< exception cancels prev instruction traced. */ + uint32_t cm_type:1; + uint32_t cm_resume:4; /**< M class resume code */ + uint32_t cm_irq_n:9; /**< M class IRQ n */ + } bits; +} ocsd_etmv3_excep; + +typedef struct _etmv3_context_t { + struct { + uint32_t curr_alt_isa:1; /**< current Alt ISA flag for Tee / T32 (used if not in present packet) */ + uint32_t curr_NS:1; /**< current NS flag (used if not in present packet) */ + uint32_t curr_Hyp:1; /**< current Hyp flag (used if not in present packet) */ + uint32_t updated:1; /**< context updated */ + uint32_t updated_c:1; /**< updated CtxtID */ + uint32_t updated_v:1; /**< updated VMID */ + }; + uint32_t ctxtID; /**< Context ID */ + uint8_t VMID; /**< VMID */ +} etmv3_context_t; + + +typedef struct _etmv3_data_t { + + uint32_t value; /**< Data value */ + ocsd_pkt_vaddr addr; /**< current data address */ + + struct { + uint32_t ooo_tag:2; /**< Out of order data tag. */ + uint32_t be:1; /**< data transfers big-endian */ + uint32_t update_be:1; /**< updated Be flag */ + uint32_t update_addr:1; /**< updated address */ + uint32_t update_dval:1; /**< updated data value */ + }; +} etmv3_data_t; + +typedef struct _etmv3_isync_t { + ocsd_iSync_reason reason; + struct { + uint32_t has_cycle_count:1; /**< updated cycle count */ + uint32_t has_LSipAddress:1; /**< main address is load-store instuction, data address is overlapping instruction @ start of trace */ + uint32_t no_address:1; /**< data only ISync */ + }; +} etmv3_isync_t; + +typedef struct _ocsd_etmv3_pkt +{ + ocsd_etmv3_pkt_type type; /**< Primary packet type. */ + + ocsd_isa curr_isa; /**< current ISA */ + ocsd_isa prev_isa; /**< ISA in previous packet */ + + etmv3_context_t context; /**< current context */ + ocsd_pkt_vaddr addr; /**< current Addr */ + + etmv3_isync_t isync_info; + + ocsd_etmv3_excep exception; + + ocsd_pkt_atom atom; /**< atom elements - non zerom number indicates valid atom count */ + uint8_t p_hdr_fmt; /**< if atom elements, associated phdr format */ + uint32_t cycle_count; /**< cycle count associated with this packet (ETMv3 has counts in atom packets and as individual packets */ + + uint64_t timestamp; /**< current timestamp value */ + uint8_t ts_update_bits; /**< bits of ts updated this packet (if TS packet) */ + + etmv3_data_t data; /**< data transfer values */ + + ocsd_etmv3_pkt_type err_type; /**< Basic packet type if primary type indicates error or incomplete. (header type) */ + +} ocsd_etmv3_pkt; + +typedef struct _ocsd_etmv3_cfg +{ + uint32_t reg_idr; /**< ID register */ + uint32_t reg_ctrl; /**< Control Register */ + uint32_t reg_ccer; /**< CCER register */ + uint32_t reg_trc_id; /**< Trace Stream ID register */ + ocsd_arch_version_t arch_ver; /**< Architecture version */ + ocsd_core_profile_t core_prof; /**< Core Profile */ +} ocsd_etmv3_cfg; + + +#define DATA_ADDR_EXPECTED_FLAG 0x20 /**< Bit set for data trace headers if data address packets follow */ + +/** @}*/ +/** @}*/ +#endif // ARM_TRC_ETM3_PKT_TYPES_ETMV3_H_INCLUDED + +/* End of File trc_pkt_types_etmv3.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/etmv4_decoder.h b/contrib/opencsd/decoder/include/opencsd/etmv4/etmv4_decoder.h new file mode 100644 index 000000000000..05bdd44d683e --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/etmv4_decoder.h @@ -0,0 +1,48 @@ +/* + * \file etmv4_decoder.h + * \brief OpenCSD : Top level header file for ETMv4 decoders + * + * \copyright Copyright (c) 2015, 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_ETMV4_DECODER_H_INCLUDED +#define ARM_ETMV4_DECODER_H_INCLUDED + +#include "trc_cmp_cfg_etmv4.h" +#include "trc_pkt_elem_etmv4i.h" +#include "trc_pkt_elem_etmv4d.h" +#include "trc_pkt_proc_etmv4.h" +#include "trc_pkt_types_etmv4.h" +#include "trc_pkt_decode_etmv4i.h" + +#endif // ARM_ETMV4_DECODER_H_INCLUDED + +/* End of File etmv4_decoder.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h new file mode 100644 index 000000000000..a3f883540a30 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h @@ -0,0 +1,449 @@ +/* + * \file trc_cmp_cfg_etmv4.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_CMP_CFG_ETMV4_H_INCLUDED +#define ARM_TRC_CMP_CFG_ETMV4_H_INCLUDED + +#include "trc_pkt_types_etmv4.h" +#include "common/trc_cs_config.h" + + +/** @addtogroup ocsd_protocol_cfg +@{*/ + +/** @name ETMv4 configuration +@{*/ + +/*! + * @class EtmV4Config + * @brief Interpreter class for etm v4 config structure. + * + * Provides quick value interpretation methods for the ETMv4 config register values. + * Primarily inlined for efficient code. + */ +class EtmV4Config : public CSConfig // public ocsd_etmv4_cfg +{ +public: + EtmV4Config(); /**< Default constructor */ + EtmV4Config(const ocsd_etmv4_cfg *cfg_regs); + ~EtmV4Config() {}; /**< Default destructor */ + +// operations to convert to and from C-API structure + + //! copy assignment operator for base structure into class. + EtmV4Config & operator=(const ocsd_etmv4_cfg *p_cfg); + + //! cast operator returning struct const reference + operator const ocsd_etmv4_cfg &() const { return m_cfg; }; + //! cast operator returning struct const pointer + operator const ocsd_etmv4_cfg *() const { return &m_cfg; }; + + const ocsd_core_profile_t &coreProfile() const { return m_cfg.core_prof; }; + const ocsd_arch_version_t &archVersion() const { return m_cfg.arch_ver; }; + + /* idr 0 */ + const bool LSasInstP0() const; + const bool hasDataTrace() const; + const bool hasBranchBroadcast() const; + const bool hasCondTrace() const; + const bool hasCycleCountI() const; + const bool hasRetStack() const; + const uint8_t numEvents() const; + + typedef enum _condType { + COND_PASS_FAIL, + COND_HAS_ASPR + } condType; + + const condType hasCondType() const; + + typedef enum _QSuppType { + Q_NONE, + Q_ICOUNT_ONLY, + Q_NO_ICOUNT_ONLY, + Q_FULL + } QSuppType; + + const QSuppType getQSuppType(); + const bool hasQElem(); + const bool hasQFilter(); + + const bool hasTrcExcpData() const; + const uint32_t TimeStampSize() const; + + const bool commitOpt1() const; + + /* idr 1 */ + const uint8_t MajVersion() const; + const uint8_t MinVersion() const; + + /* idr 2 */ + const uint32_t iaSizeMax() const; + const uint32_t cidSize() const; + const uint32_t vmidSize(); + const uint32_t daSize() const; + const uint32_t dvSize() const; + const uint32_t ccSize() const; + const bool vmidOpt() const; + + /* id regs 8-13*/ + const uint32_t MaxSpecDepth() const; + const uint32_t P0_Key_Max() const; + const uint32_t P1_Key_Max() const; + const uint32_t P1_Spcl_Key_Max() const; + const uint32_t CondKeyMax() const; + const uint32_t CondSpecKeyMax() const; + const uint32_t CondKeyMaxIncr() const; + + /* trace idr */ + virtual const uint8_t getTraceID() const; //!< CoreSight Trace ID for this device. + + /* config R */ + const bool enabledDVTrace() const; + const bool enabledDATrace() const; + const bool enabledDataTrace() const; + + typedef enum { + LSP0_NONE, + LSP0_L, + LSP0_S, + LSP0_LS + } LSP0_t; + + const bool enabledLSP0Trace() const; + const LSP0_t LSP0Type() const; + + const bool enabledBrBroad() const; + const bool enabledCCI() const; + const bool enabledCID() const; + const bool enabledVMID() const; + + typedef enum { + COND_TR_DIS, + COND_TR_LD, + COND_TR_ST, + COND_TR_LDST, + COND_TR_ALL + } CondITrace_t; + + const CondITrace_t enabledCondITrace(); + + const bool enabledTS() const; + const bool enabledRetStack() const; + + const bool enabledQE() const; + +private: + void PrivateInit(); + void CalcQSupp(); + void CalcVMIDSize(); + + bool m_QSuppCalc; + bool m_QSuppFilter; + QSuppType m_QSuppType; + + bool m_VMIDSzCalc; + uint32_t m_VMIDSize; + + bool m_condTraceCalc; + CondITrace_t m_CondTrace; + + ocsd_etmv4_cfg m_cfg; +}; + +/* idr 0 */ +inline const bool EtmV4Config::LSasInstP0() const +{ + return (bool)((m_cfg.reg_idr0 & 0x6) == 0x6); +} + +inline const bool EtmV4Config::hasDataTrace() const +{ + return (bool)((m_cfg.reg_idr0 & 0x18) == 0x18); +} + +inline const bool EtmV4Config::hasBranchBroadcast() const +{ + return (bool)((m_cfg.reg_idr0 & 0x20) == 0x20); +} + +inline const bool EtmV4Config::hasCondTrace() const +{ + return (bool)((m_cfg.reg_idr0 & 0x40) == 0x40); +} + +inline const bool EtmV4Config::hasCycleCountI() const +{ + return (bool)((m_cfg.reg_idr0 & 0x80) == 0x80); +} + +inline const bool EtmV4Config::hasRetStack() const +{ + return (bool)((m_cfg.reg_idr0 & 0x200) == 0x200); +} + +inline const uint8_t EtmV4Config::numEvents() const +{ + return ((m_cfg.reg_idr0 >> 10) & 0x3) + 1; +} + +inline const EtmV4Config::condType EtmV4Config::hasCondType() const +{ + return ((m_cfg.reg_idr0 & 0x3000) == 0x1000) ? EtmV4Config::COND_HAS_ASPR : EtmV4Config::COND_PASS_FAIL; +} + +inline const EtmV4Config::QSuppType EtmV4Config::getQSuppType() +{ + if(!m_QSuppCalc) CalcQSupp(); + return m_QSuppType; +} + +inline const bool EtmV4Config::hasQElem() +{ + if(!m_QSuppCalc) CalcQSupp(); + return (bool)(m_QSuppType != Q_NONE); +} + +inline const bool EtmV4Config::hasQFilter() +{ + if(!m_QSuppCalc) CalcQSupp(); + return m_QSuppFilter; +} + +inline const bool EtmV4Config::hasTrcExcpData() const +{ + return (bool)((m_cfg.reg_idr0 & 0x20000) == 0x20000); +} + +inline const uint32_t EtmV4Config::TimeStampSize() const +{ + uint32_t tsSizeF = (m_cfg.reg_idr0 >> 24) & 0x1F; + if(tsSizeF == 0x6) + return 48; + if(tsSizeF == 0x8) + return 64; + return 0; +} + +inline const bool EtmV4Config::commitOpt1() const +{ + return (bool)((m_cfg.reg_idr0 & 0x20000000) == 0x20000000) && hasCycleCountI(); +} + + /* idr 1 */ +inline const uint8_t EtmV4Config::MajVersion() const +{ + return (uint8_t)((m_cfg.reg_idr1 >> 8) & 0xF); +} + +inline const uint8_t EtmV4Config::MinVersion() const +{ + return (uint8_t)((m_cfg.reg_idr1 >> 4) & 0xF); +} + + +/* idr 2 */ +inline const uint32_t EtmV4Config::iaSizeMax() const +{ + return ((m_cfg.reg_idr2 & 0x1F) == 0x8) ? 64 : 32; +} + +inline const uint32_t EtmV4Config::cidSize() const +{ + return (((m_cfg.reg_idr2 >> 5) & 0x1F) == 0x4) ? 32 : 0; +} + +inline const uint32_t EtmV4Config::vmidSize() +{ + if(!m_VMIDSzCalc) + { + CalcVMIDSize(); + } + return m_VMIDSize; +} + +inline const uint32_t EtmV4Config::daSize() const +{ + uint32_t daSizeF = ((m_cfg.reg_idr2 >> 15) & 0x1F); + if(daSizeF) + return (((m_cfg.reg_idr2 >> 15) & 0x1F) == 0x8) ? 64 : 32; + return 0; +} + +inline const uint32_t EtmV4Config::dvSize() const +{ + uint32_t dvSizeF = ((m_cfg.reg_idr2 >> 20) & 0x1F); + if(dvSizeF) + return (((m_cfg.reg_idr2 >> 20) & 0x1F) == 0x8) ? 64 : 32; + return 0; +} + +inline const uint32_t EtmV4Config::ccSize() const +{ + return ((m_cfg.reg_idr2 >> 25) & 0xF) + 12; +} + +inline const bool EtmV4Config::vmidOpt() const +{ + return (bool)((m_cfg.reg_idr2 & 0x20000000) == 0x20000000) && (MinVersion() > 0); +} + +/* id regs 8-13*/ + +inline const uint32_t EtmV4Config::MaxSpecDepth() const +{ + return m_cfg.reg_idr8; +} + +inline const uint32_t EtmV4Config::P0_Key_Max() const +{ + return (m_cfg.reg_idr9 == 0) ? 1 : m_cfg.reg_idr9; +} + +inline const uint32_t EtmV4Config::P1_Key_Max() const +{ + return m_cfg.reg_idr10; +} + +inline const uint32_t EtmV4Config::P1_Spcl_Key_Max() const +{ + return m_cfg.reg_idr11; +} + +inline const uint32_t EtmV4Config::CondKeyMax() const +{ + return m_cfg.reg_idr12; +} + +inline const uint32_t EtmV4Config::CondSpecKeyMax() const +{ + return m_cfg.reg_idr13; +} + +inline const uint32_t EtmV4Config::CondKeyMaxIncr() const +{ + return m_cfg.reg_idr12 - m_cfg.reg_idr13; +} + +inline const uint8_t EtmV4Config::getTraceID() const +{ + return (uint8_t)(m_cfg.reg_traceidr & 0x7F); +} + + /* config R */ +inline const bool EtmV4Config::enabledDVTrace() const +{ + return hasDataTrace() && enabledLSP0Trace() && ((m_cfg.reg_configr & (0x1 << 17)) != 0); +} + +inline const bool EtmV4Config::enabledDATrace() const +{ + return hasDataTrace() && enabledLSP0Trace() && ((m_cfg.reg_configr & (0x1 << 16)) != 0); +} + +inline const bool EtmV4Config::enabledDataTrace() const +{ + return enabledDATrace() || enabledDVTrace(); +} + +inline const bool EtmV4Config::enabledLSP0Trace() const +{ + return ((m_cfg.reg_configr & 0x6) != 0); +} + +inline const EtmV4Config::LSP0_t EtmV4Config::LSP0Type() const +{ + return (LSP0_t)((m_cfg.reg_configr & 0x6) >> 1); +} + +inline const bool EtmV4Config::enabledBrBroad() const +{ + return ((m_cfg.reg_configr & (0x1 << 3)) != 0); +} + +inline const bool EtmV4Config::enabledCCI() const +{ + return ((m_cfg.reg_configr & (0x1 << 4)) != 0); +} + +inline const bool EtmV4Config::enabledCID() const +{ + return ((m_cfg.reg_configr & (0x1 << 6)) != 0); +} + +inline const bool EtmV4Config::enabledVMID() const +{ + return ((m_cfg.reg_configr & (0x1 << 7)) != 0); +} + +inline const EtmV4Config::CondITrace_t EtmV4Config::enabledCondITrace() +{ + if(!m_condTraceCalc) + { + switch((m_cfg.reg_configr >> 8) & 0x7) + { + default: + case 0: m_CondTrace = COND_TR_DIS; break; + case 1: m_CondTrace = COND_TR_LD; break; + case 2: m_CondTrace = COND_TR_ST; break; + case 3: m_CondTrace = COND_TR_LDST; break; + case 7: m_CondTrace = COND_TR_ALL; break; + } + m_condTraceCalc = true; + } + return m_CondTrace; +} + +inline const bool EtmV4Config::enabledTS() const +{ + return ((m_cfg.reg_configr & (0x1 << 11)) != 0); +} + +inline const bool EtmV4Config::enabledRetStack() const +{ + return ((m_cfg.reg_configr & (0x1 << 12)) != 0); +} + +inline const bool EtmV4Config::enabledQE() const +{ + return ((m_cfg.reg_configr & (0x3 << 13)) != 0); +} + +/** @}*/ +/** @}*/ + +#endif // ARM_TRC_CMP_CFG_ETMV4_H_INCLUDED + +/* End of File trc_cmp_cfg_etmv4.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_dcd_mngr_etmv4i.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_dcd_mngr_etmv4i.h new file mode 100644 index 000000000000..a5b25404fcf3 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_dcd_mngr_etmv4i.h @@ -0,0 +1,31 @@ +/* + * \file trc_dcd_mngr_etmv4i.h + * \brief Reference CoreSight Trace Decoder : + * + * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. + */ + +#ifndef ARM_TRC_DCD_MNGR_ETMV4I_H_INCLUDED +#define ARM_TRC_DCD_MNGR_ETMV4I_H_INCLUDED + +#include "common/ocsd_dcd_mngr.h" +#include "trc_pkt_decode_etmv4i.h" +#include "trc_pkt_proc_etmv4.h" +#include "trc_cmp_cfg_etmv4.h" +#include "trc_pkt_types_etmv4.h" + +class DecoderMngrEtmV4I : public DecodeMngrFullDcd< EtmV4ITrcPacket, + ocsd_etmv4_i_pkt_type, + EtmV4Config, + ocsd_etmv4_cfg, + TrcPktProcEtmV4I, + TrcPktDecodeEtmV4I> +{ +public: + DecoderMngrEtmV4I(const std::string &name) : DecodeMngrFullDcd(name,OCSD_PROTOCOL_ETMV4I) {}; + virtual ~DecoderMngrEtmV4I() {}; +}; + +#endif // ARM_TRC_DCD_MNGR_ETMV4I_H_INCLUDED + +/* End of File trc_dcd_mngr_etmv4i.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h new file mode 100644 index 000000000000..8bf0fb0c0478 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h @@ -0,0 +1,338 @@ +/* + * \file trc_etmv4_stack_elem.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_ETMV4_STACK_ELEM_H_INCLUDED +#define ARM_TRC_ETMV4_STACK_ELEM_H_INCLUDED + +#include "opencsd/etmv4/trc_pkt_types_etmv4.h" + +#include +#include + +/* ETMv4 I trace stack elements + Speculation requires that we stack certain elements till they are committed or + cancelled. (P0 elements + other associated parts.) +*/ + +typedef enum _p0_elem_t +{ + P0_UNKNOWN, + P0_ATOM, + P0_ADDR, + P0_CTXT, + P0_TRC_ON, + P0_EXCEP, + P0_EXCEP_RET, + P0_EVENT, + P0_TS, + P0_CC, + P0_TS_CC, + P0_OVERFLOW +} p0_elem_t; + + +/************************************************************/ +/***Trace stack element base class - + record originating packet type and index in buffer*/ + +class TrcStackElem { +public: + TrcStackElem(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + virtual ~TrcStackElem() {}; + + const p0_elem_t getP0Type() const { return m_P0_type; }; + const ocsd_etmv4_i_pkt_type getRootPkt() const { return m_root_pkt; }; + const ocsd_trc_index_t getRootIndex() const { return m_root_idx; }; + const bool isP0() const { return m_is_P0; }; + +private: + ocsd_etmv4_i_pkt_type m_root_pkt; + ocsd_trc_index_t m_root_idx; + p0_elem_t m_P0_type; + +protected: + bool m_is_P0; // true if genuine P0 - commit / cancellable, false otherwise + +}; + +inline TrcStackElem::TrcStackElem(p0_elem_t p0_type, const bool isP0, ocsd_etmv4_i_pkt_type root_pkt, ocsd_trc_index_t root_index) : + m_root_pkt(root_pkt), + m_root_idx(root_index), + m_P0_type(p0_type), + m_is_P0(isP0) +{ +} + +/************************************************************/ +/** Address element */ + +class TrcStackElemAddr : public TrcStackElem +{ +protected: + TrcStackElemAddr(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + virtual ~TrcStackElemAddr() {}; + + friend class EtmV4P0Stack; + +public: + void setAddr(const etmv4_addr_val_t &addr_val) { m_addr_val = addr_val; }; + const etmv4_addr_val_t &getAddr() const { return m_addr_val; }; + +private: + etmv4_addr_val_t m_addr_val; +}; + +inline TrcStackElemAddr::TrcStackElemAddr(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : + TrcStackElem(P0_ADDR, false, root_pkt,root_index) +{ + m_addr_val.val = 0; + m_addr_val.isa = 0; +} + +/************************************************************/ +/** Context element */ + +class TrcStackElemCtxt : public TrcStackElem +{ +protected: + TrcStackElemCtxt(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + virtual ~TrcStackElemCtxt() {}; + + friend class EtmV4P0Stack; + +public: + void setContext(const etmv4_context_t &ctxt) { m_context = ctxt; }; + const etmv4_context_t &getContext() const { return m_context; }; + +private: + etmv4_context_t m_context; +}; + +inline TrcStackElemCtxt::TrcStackElemCtxt(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : + TrcStackElem(P0_CTXT, false, root_pkt,root_index) +{ +} + +/************************************************************/ +/** Exception element */ + +class TrcStackElemExcept : public TrcStackElem +{ +protected: + TrcStackElemExcept(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + virtual ~TrcStackElemExcept() {}; + + friend class EtmV4P0Stack; + +public: + void setPrevSame(bool bSame) { m_prev_addr_same = bSame; }; + const bool getPrevSame() const { return m_prev_addr_same; }; + + void setExcepNum(const uint16_t num) { m_excep_num = num; }; + const uint16_t getExcepNum() const { return m_excep_num; }; + +private: + bool m_prev_addr_same; + uint16_t m_excep_num; +}; + +inline TrcStackElemExcept::TrcStackElemExcept(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : + TrcStackElem(P0_EXCEP, true, root_pkt,root_index), + m_prev_addr_same(false) +{ +} + +/************************************************************/ +/** Atom element */ + +class TrcStackElemAtom : public TrcStackElem +{ +protected: + TrcStackElemAtom(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + virtual ~TrcStackElemAtom() {}; + + friend class EtmV4P0Stack; + +public: + void setAtom(const ocsd_pkt_atom &atom) { m_atom = atom; }; + + const ocsd_atm_val commitOldest(); + int cancelNewest(const int nCancel); + const bool isEmpty() const { return (m_atom.num == 0); }; + +private: + ocsd_pkt_atom m_atom; +}; + +inline TrcStackElemAtom::TrcStackElemAtom(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : + TrcStackElem(P0_ATOM, true, root_pkt,root_index) +{ + m_atom.num = 0; +} + +// commit oldest - get value and remove it from pattern +inline const ocsd_atm_val TrcStackElemAtom::commitOldest() +{ + ocsd_atm_val val = (m_atom.En_bits & 0x1) ? ATOM_E : ATOM_N; + m_atom.num--; + m_atom.En_bits >>= 1; + return val; +} + +// cancel newest - just reduce the atom count. +inline int TrcStackElemAtom::cancelNewest(const int nCancel) +{ + int nRemove = (nCancel <= m_atom.num) ? nCancel : m_atom.num; + m_atom.num -= nRemove; + return nRemove; +} + +/************************************************************/ +/** Generic param element */ + +class TrcStackElemParam : public TrcStackElem +{ +protected: + TrcStackElemParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + virtual ~TrcStackElemParam() {}; + + friend class EtmV4P0Stack; + +public: + void setParam(const uint32_t param, const int nParamNum) { m_param[(nParamNum & 0x3)] = param; }; + const uint32_t &getParam(const int nParamNum) const { return m_param[(nParamNum & 0x3)]; }; + +private: + uint32_t m_param[4]; +}; + +inline TrcStackElemParam::TrcStackElemParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : + TrcStackElem(p0_type, isP0, root_pkt,root_index) +{ +} + +/************************************************************/ +/* P0 element stack that allows push of elements, and deletion of elements when done. +*/ +class EtmV4P0Stack +{ +public: + EtmV4P0Stack() {}; + ~EtmV4P0Stack(); + + void push_front(TrcStackElem *pElem); + void pop_back(); + TrcStackElem *back(); + size_t size(); + + void delete_all(); + void delete_back(); + void delete_popped(); + + // creation functions - create and push if successful. + TrcStackElemParam *createParamElem(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const std::vector ¶ms); + TrcStackElemParam *createParamElemNoParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + TrcStackElemAtom *createAtomElem (const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const ocsd_pkt_atom &atom); + TrcStackElemExcept *createExceptElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const bool bSame, const uint16_t excepNum); + TrcStackElemCtxt *createContextElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_context_t &context); + TrcStackElemAddr *createAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val); + +private: + std::deque m_P0_stack; //!< P0 decode element stack + std::vector m_popped_elem; //!< save list of popped but not deleted elements. + +}; + +inline EtmV4P0Stack::~EtmV4P0Stack() +{ + delete_all(); + delete_popped(); +} + +// put an element on the front of the stack +inline void EtmV4P0Stack::push_front(TrcStackElem *pElem) +{ + m_P0_stack.push_front(pElem); +} + +// pop last element pointer off the stack and stash it for later deletion +inline void EtmV4P0Stack::pop_back() +{ + m_popped_elem.push_back(m_P0_stack.back()); + m_P0_stack.pop_back(); +} + +// pop last element pointer off the stack and delete immediately +inline void EtmV4P0Stack::delete_back() +{ + if (m_P0_stack.size() > 0) + { + TrcStackElem* pElem = m_P0_stack.back(); + delete pElem; + m_P0_stack.pop_back(); + } +} + +// get a pointer to the last element on the stack +inline TrcStackElem *EtmV4P0Stack::back() +{ + return m_P0_stack.back(); +} + +// remove and delete all the elements left on the stack +inline void EtmV4P0Stack::delete_all() +{ + while (m_P0_stack.size() > 0) + delete_back(); + m_P0_stack.clear(); +} + +// delete list of popped elements. +inline void EtmV4P0Stack::delete_popped() +{ + while (m_popped_elem.size() > 0) + { + delete m_popped_elem.back(); + m_popped_elem.pop_back(); + } + m_popped_elem.clear(); +} + +// get current number of elements on the stack +inline size_t EtmV4P0Stack::size() +{ + return m_P0_stack.size(); +} + +#endif // ARM_TRC_ETMV4_STACK_ELEM_H_INCLUDED + +/* End of File trc_etmv4_stack_elem.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h new file mode 100644 index 000000000000..f27bb45d9fa8 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h @@ -0,0 +1,183 @@ +/* + * \file trc_pkt_decode_etmv4i.h + * \brief OpenCSD : ETMv4 instruction decoder + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_DECODE_ETMV4I_H_INCLUDED +#define ARM_TRC_PKT_DECODE_ETMV4I_H_INCLUDED + +#include "common/trc_pkt_decode_base.h" +#include "opencsd/etmv4/trc_pkt_elem_etmv4i.h" +#include "opencsd/etmv4/trc_cmp_cfg_etmv4.h" +#include "common/trc_gen_elem.h" +#include "common/trc_ret_stack.h" +#include "opencsd/etmv4/trc_etmv4_stack_elem.h" + +class TrcStackElem; +class TrcStackElemParam; +class TrcStackElemCtxt; + +class TrcPktDecodeEtmV4I : public TrcPktDecodeBase +{ +public: + TrcPktDecodeEtmV4I(); + TrcPktDecodeEtmV4I(int instIDNum); + virtual ~TrcPktDecodeEtmV4I(); + +protected: + /* implementation packet decoding interface */ + virtual ocsd_datapath_resp_t processPacket(); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const uint8_t getCoreSightTraceID() { return m_CSID; }; + + /* local decode methods */ + void initDecoder(); // initial state on creation (zeros all config) + void resetDecoder(); // reset state to start of decode. (moves state, retains config) + + ocsd_datapath_resp_t decodePacket(bool &Complete); // return true to indicate decode complete - can change FSM to commit state - return is false. + ocsd_datapath_resp_t commitElements(bool &Complete); // commit elements - may get wait response, or flag completion. + ocsd_datapath_resp_t flushEOT(); + + void doTraceInfoPacket(); + void updateContext(TrcStackElemCtxt *pCtxtElem); + + // process atom will output instruction trace, or no memory access trace elements. + ocsd_datapath_resp_t processAtom(const ocsd_atm_val, bool &bCont); + + // process an exception element - output instruction trace + exception generic type. + ocsd_datapath_resp_t processException(); + + // process a bad packet + ocsd_datapath_resp_t handleBadPacket(const char *reason); + + ocsd_datapath_resp_t outputCC(TrcStackElemParam *pParamElem); + ocsd_datapath_resp_t outputTS(TrcStackElemParam *pParamElem, bool withCC); + ocsd_datapath_resp_t outputEvent(TrcStackElemParam *pParamElem); + +private: + void SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa); + + ocsd_err_t traceInstrToWP(bool &bWPFound, const bool traceToAddrNext = false, const ocsd_vaddr_t nextAddrMatch = 0); //!< follow instructions from the current address to a WP. true if good, false if memory cannot be accessed. + + ocsd_datapath_resp_t returnStackPop(); // pop return stack and update instruction address. + +//** intra packet state (see ETMv4 spec 6.2.1); + + // timestamping + uint64_t m_timestamp; // last broadcast global Timestamp. + + // state and context + uint32_t m_context_id; // most recent context ID + uint32_t m_vmid_id; // most recent VMID + bool m_is_secure; // true if Secure + bool m_is_64bit; // true if 64 bit + + // cycle counts + int m_cc_threshold; + + // speculative trace (unsupported at present in the decoder). + int m_curr_spec_depth; + int m_max_spec_depth; + + // data trace associative elements (unsupported at present in the decoder). + int m_p0_key; + int m_p0_key_max; + + // conditional non-branch trace - when data trace active (unsupported at present in the decoder) + int m_cond_c_key; + int m_cond_r_key; + int m_cond_key_max_incr; + + uint8_t m_CSID; //!< Coresight trace ID for this decoder. + + bool m_IASize64; //!< True if 64 bit instruction addresses supported. + +//** Other processor state; + + // trace decode FSM + typedef enum { + NO_SYNC, //!< pre start trace - init state or after reset or overflow, loss of sync. + WAIT_SYNC, //!< waiting for sync packet. + WAIT_TINFO, //!< waiting for trace info packet. + DECODE_PKTS, //!< processing packets - creating decode elements on stack + COMMIT_ELEM, //!< commit elements for execution - create generic trace elements and pass on. + } processor_state_t; + + processor_state_t m_curr_state; + +//** P0 element stack + EtmV4P0Stack m_P0_stack; //!< P0 decode element stack + + int m_P0_commit; //!< number of elements to commit + + // packet decode state + bool m_need_ctxt; //!< need context to continue + bool m_need_addr; //!< need an address to continue + bool m_except_pending_addr; //!< next address packet is part of exception. + + // exception packet processing state (may need excep elem only, range+excep, range+ + typedef enum { + EXCEP_POP, // start of processing read exception packets off the stack and analyze + EXCEP_RANGE, // output a range element + EXCEP_NACC, // output a nacc element + EXCEP_EXCEP, // output an ecxeption element. + } excep_proc_state_t; + + excep_proc_state_t m_excep_proc; //!< state of exception processing + etmv4_addr_val_t m_excep_addr; //!< excepiton return address. + ocsd_trc_index_t m_excep_index; //!< trace index for exception element + + ocsd_instr_info m_instr_info; //!< instruction info for code follower - in address is the next to be decoded. + + bool m_mem_nacc_pending; //!< need to output a memory access failure packet + ocsd_vaddr_t m_nacc_addr; //!< record unaccessible address + + ocsd_pe_context m_pe_context; //!< current context information + etmv4_trace_info_t m_trace_info; //!< trace info for this trace run. + + bool m_prev_overflow; + + bool m_flush_EOT; //!< true if doing an end of trace flush - cleans up lingering events / TS / CC + + TrcAddrReturnStack m_return_stack; + +//** output element + OcsdTraceElement m_output_elem; + +}; + +#endif // ARM_TRC_PKT_DECODE_ETMV4I_H_INCLUDED + +/* End of File trc_pkt_decode_etmv4i.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4d.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4d.h new file mode 100644 index 000000000000..bb6a0029c0c0 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4d.h @@ -0,0 +1,73 @@ +/* + * \file trc_pkt_elem_etmv4d.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_ELEM_ETMV4D_H_INCLUDED +#define ARM_TRC_PKT_ELEM_ETMV4D_H_INCLUDED + +#include "trc_pkt_types_etmv4.h" +#include "common/trc_printable_elem.h" +#include "common/trc_pkt_elem_base.h" + +/** @addtogroup trc_pkts +@{*/ +/*! + * @class EtmV4DTrcPacket + * @brief ETMv4 Data Trace Protocol Packet . + * + * This class represents a single ETMv4 instruction trace packet, along with intra packet state. + * + */ +class EtmV4DTrcPacket : public TrcPacketBase, public ocsd_etmv4_d_pkt, trcPrintableElem +{ +public: + EtmV4DTrcPacket(); + ~EtmV4DTrcPacket(); + + // update interface - set packet values + + + + // packet status interface - get packet info. + + + // printing + virtual void toString(std::string &str) const; + virtual void toStringFmt(const uint32_t fmtFlags, std::string &str) const; +}; + +/** @}*/ + +#endif // ARM_TRC_PKT_ELEM_ETMV4D_H_INCLUDED + +/* End of File trc_pkt_elem_etmv4d.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h new file mode 100644 index 000000000000..e0343c76260c --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h @@ -0,0 +1,520 @@ +/* + * \file trc_pkt_elem_etmv4i.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_ELEM_ETMV4I_H_INCLUDED +#define ARM_TRC_PKT_ELEM_ETMV4I_H_INCLUDED + +#include "trc_pkt_types_etmv4.h" +#include "common/trc_printable_elem.h" +#include "common/trc_pkt_elem_base.h" + +/** @addtogroup trc_pkts +@{*/ + +/*! +* @class Etmv4PktAddrStack +* @brief ETMv4 Address packet values stack +* @ingroup trc_pkts +* +* This class represents a stack of recent broadcast address values - +* used to fulfil the ExactMatch address type where no address is output. +* +*/ +class Etmv4PktAddrStack +{ +public: + Etmv4PktAddrStack() + { + for (int i = 0; i < 3; i++) + { + m_v_addr[i].pkt_bits = 0; + m_v_addr[i].size = VA_64BIT; + m_v_addr[i].val = 0; + m_v_addr[i].valid_bits = 0; + m_v_addr_ISA[i] = 0; + } + } + ~Etmv4PktAddrStack() {}; + + void push(const ocsd_pkt_vaddr vaddr, const uint8_t isa) + { + m_v_addr[2] = m_v_addr[1]; + m_v_addr[1] = m_v_addr[0]; + m_v_addr[0] = vaddr; + m_v_addr_ISA[2] = m_v_addr_ISA[1]; + m_v_addr_ISA[1] = m_v_addr_ISA[0]; + m_v_addr_ISA[0] = isa; + } + + void get_idx(const uint8_t idx, ocsd_pkt_vaddr &vaddr, uint8_t &isa) + { + if (idx < 3) + { + vaddr = m_v_addr[idx]; + isa = m_v_addr_ISA[idx]; + } + } + +private: + ocsd_pkt_vaddr m_v_addr[3]; //!< most recently broadcast address packet + uint8_t m_v_addr_ISA[3]; +}; + +/*! + * @class EtmV4ITrcPacket + * @brief ETMv4 Instuction Trace Protocol Packet. + * @ingroup trc_pkts + * + * This class represents a single ETMv4 data trace packet, along with intra packet state. + * + */ +class EtmV4ITrcPacket : public TrcPacketBase, public ocsd_etmv4_i_pkt, public trcPrintableElem +{ +public: + EtmV4ITrcPacket(); + ~EtmV4ITrcPacket(); + + EtmV4ITrcPacket &operator =(const ocsd_etmv4_i_pkt* p_pkt); + + virtual const void *c_pkt() const { return (const ocsd_etmv4_i_pkt *)this; }; + + // update interface - set packet values + void initStartState(); //!< Set to initial state - no intra packet state valid. Use on start of trace / discontinuities. + void initNextPacket(); //!< clear any single packet only flags / state. + + void setType(const ocsd_etmv4_i_pkt_type pkt_type) { type = pkt_type; }; + void updateErrType(const ocsd_etmv4_i_pkt_type err_pkt_type); + + void clearTraceInfo(); //!< clear all the trace info data prior to setting for new trace info packet. + void setTraceInfo(const uint32_t infoVal); + void setTraceInfoKey(const uint32_t keyVal); + void setTraceInfoSpec(const uint32_t specVal); + void setTraceInfoCyct(const uint32_t cyctVal); + + void setTS(const uint64_t value, const uint8_t bits); + void setCycleCount(const uint32_t value); + void setCommitElements(const uint32_t commit_elem); + void setCancelElements(const uint32_t cancel_elem); + void setAtomPacket(const ocsd_pkt_atm_type type, const uint32_t En_bits, const uint8_t num); + + void setCondIF1(uint32_t const cond_key); + void setCondIF2(uint8_t const c_elem_idx); + void setCondIF3(uint8_t const num_c_elem, const bool finalElem); + + void setCondRF1(const uint32_t key[2], const uint8_t res[2], const uint8_t CI[2], const bool set2Keys); + void setCondRF2(const uint8_t key_incr, const uint8_t token); + void setCondRF3(const uint16_t tokens); + void setCondRF4(const uint8_t token); + + void setContextInfo(const bool update, const uint8_t EL = 0, const uint8_t NS = 0, const uint8_t SF = 0); + void setContextVMID(const uint32_t VMID); + void setContextCID(const uint32_t CID); + + void setExceptionInfo(const uint16_t excep_type, const uint8_t addr_interp, const uint8_t m_fault_pending, const uint8_t m_type); + + void set64BitAddress(const uint64_t addr, const uint8_t IS); + void set32BitAddress(const uint32_t addr, const uint8_t IS); + void updateShortAddress(const uint32_t addr, const uint8_t IS, const uint8_t update_bits); + void setAddressExactMatch(const uint8_t idx); + + void setDataSyncMarker(const uint8_t dsm_val); + void setEvent(const uint8_t event_val); + + void setQType(const bool has_count, const uint32_t count, const bool has_addr, const bool addr_match, const uint8_t type); + + // packet status interface - get packet info. + const ocsd_etmv4_i_pkt_type getType() const { return type; }; + const ocsd_etmv4_i_pkt_type getErrType() const { return err_type; }; + + //! return true if this packet has set the commit packet count. + const bool hasCommitElementsCount() const + { + return pkt_valid.bits.commit_elem_valid ? true : false; + }; + + // trace info + const etmv4_trace_info_t &getTraceInfo() const { return trace_info; }; + const uint32_t getCCThreshold() const; + const uint32_t getP0Key() const; + const uint32_t getCurrSpecDepth() const; + + // atom + const ocsd_pkt_atom &getAtom() const { return atom; }; + + // context + const etmv4_context_t &getContext() const { return context; }; + + // address + const uint8_t &getAddrMatch() const { return addr_exact_match_idx; }; + const ocsd_vaddr_t &getAddrVal() const { return v_addr.val; }; + const uint8_t &getAddrIS() const { return v_addr_ISA; }; + const bool getAddr64Bit() const { return v_addr.size == VA_64BIT; }; + + // ts + const uint64_t getTS() const { return pkt_valid.bits.ts_valid ? ts.timestamp : 0; }; + + // cc + const uint32_t getCC() const { return pkt_valid.bits.cc_valid ? cycle_count : 0; }; + + // packet type + const bool isBadPacket() const; + + // printing + virtual void toString(std::string &str) const; + virtual void toStringFmt(const uint32_t fmtFlags, std::string &str) const; + +private: + const char *packetTypeName(const ocsd_etmv4_i_pkt_type type, const char **pDesc) const; + void contextStr(std::string &ctxtStr) const; + void atomSeq(std::string &valStr) const; + void addrMatchIdx(std::string &valStr) const; + void exceptionInfo(std::string &valStr) const; + + void push_vaddr(); + void pop_vaddr_idx(const uint8_t idx); + + Etmv4PktAddrStack m_addr_stack; +}; + +inline void EtmV4ITrcPacket::updateErrType(const ocsd_etmv4_i_pkt_type err_pkt_type) +{ + // set primary type to incoming error type, set packet err type to previous primary type. + err_type = type; + type = err_pkt_type; +} + +inline void EtmV4ITrcPacket::clearTraceInfo() +{ + pkt_valid.bits.ts_valid = 0; + pkt_valid.bits.trace_info_valid = 0; + pkt_valid.bits.p0_key_valid = 0; + pkt_valid.bits.spec_depth_valid = 0; + pkt_valid.bits.cc_thresh_valid = 0; + + pkt_valid.bits.ts_valid = 0; // mark TS as invalid - must be re-updated after trace info. +} + +inline void EtmV4ITrcPacket::setTraceInfo(const uint32_t infoVal) +{ + trace_info.val = infoVal; + pkt_valid.bits.trace_info_valid = 1; +} + +inline void EtmV4ITrcPacket::setTraceInfoKey(const uint32_t keyVal) +{ + p0_key = keyVal; + pkt_valid.bits.p0_key_valid = 1; +} + +inline void EtmV4ITrcPacket::setTraceInfoSpec(const uint32_t specVal) +{ + curr_spec_depth = specVal; + pkt_valid.bits.spec_depth_valid = 1; +} + +inline void EtmV4ITrcPacket::setTraceInfoCyct(const uint32_t cyctVal) +{ + cc_threshold = cyctVal; + pkt_valid.bits.cc_thresh_valid = 1; +} + +inline void EtmV4ITrcPacket::setTS(const uint64_t value, const uint8_t bits) +{ + uint64_t mask = (uint64_t)-1LL; + if(bits < 64) mask = (1ULL << bits) - 1; + ts.timestamp = (ts.timestamp & ~mask) | (value & mask); + ts.bits_changed = bits; + pkt_valid.bits.ts_valid = 1; +} + +inline void EtmV4ITrcPacket::setCycleCount(const uint32_t value) +{ + pkt_valid.bits.cc_valid = 1; + cycle_count = value; +} + +inline void EtmV4ITrcPacket::setCommitElements(const uint32_t commit_elem) +{ + pkt_valid.bits.commit_elem_valid = 1; + commit_elements = commit_elem; +} + +inline const uint32_t EtmV4ITrcPacket::getCCThreshold() const +{ + if(pkt_valid.bits.cc_thresh_valid) + return cc_threshold; + return 0; +} + +inline const uint32_t EtmV4ITrcPacket::getP0Key() const +{ + if(pkt_valid.bits.p0_key_valid) + return p0_key; + return 0; +} + +inline const uint32_t EtmV4ITrcPacket::getCurrSpecDepth() const +{ + if(pkt_valid.bits.spec_depth_valid) + return curr_spec_depth; + return 0; +} + +inline void EtmV4ITrcPacket::setCancelElements(const uint32_t cancel_elem) +{ + cancel_elements = cancel_elem; +} + +inline void EtmV4ITrcPacket::setAtomPacket(const ocsd_pkt_atm_type type, const uint32_t En_bits, const uint8_t num) +{ + if(type == ATOM_REPEAT) + { + uint32_t bit_patt = En_bits & 0x1; + if(bit_patt) + { + // none zero - all 1s + bit_patt = (bit_patt << num) - 1; + } + atom.En_bits = bit_patt; + } + else + atom.En_bits = En_bits; + atom.num = num; +} + +inline void EtmV4ITrcPacket::setCondIF1(const uint32_t cond_key) +{ + cond_instr.cond_key_set = 1; + cond_instr.f3_final_elem = 0; + cond_instr.f2_cond_incr = 0; + cond_instr.num_c_elem = 1; + cond_instr.cond_c_key = cond_key; +} + +inline void EtmV4ITrcPacket::setCondIF2(const uint8_t c_elem_idx) +{ + cond_instr.cond_key_set = 0; + cond_instr.f3_final_elem = 0; + switch(c_elem_idx & 0x3) + { + case 0: + cond_instr.f2_cond_incr = 1; + cond_instr.num_c_elem = 1; + break; + + case 1: + cond_instr.f2_cond_incr = 0; + cond_instr.num_c_elem = 1; + break; + + case 2: + cond_instr.f2_cond_incr = 1; + cond_instr.num_c_elem = 2; + break; + } +} + +inline void EtmV4ITrcPacket::setCondIF3(const uint8_t num_c_elem, const bool finalElem) +{ + cond_instr.cond_key_set = 0; + cond_instr.f3_final_elem = finalElem ? 1: 0; + cond_instr.f2_cond_incr = 0; + cond_instr.num_c_elem = num_c_elem; +} + +inline void EtmV4ITrcPacket::setCondRF1(const uint32_t key[2], const uint8_t res[2], const uint8_t CI[2],const bool set2Keys) +{ + cond_result.key_res_0_set = 1; + cond_result.cond_r_key_0 = key[0]; + cond_result.res_0 = res[0]; + cond_result.ci_0 = CI[0]; + + if(set2Keys) + { + cond_result.key_res_1_set = 1; + cond_result.cond_r_key_1 = key[1]; + cond_result.res_1 = res[1]; + cond_result.ci_1 = CI[1]; + } +} + + +inline void EtmV4ITrcPacket::setCondRF2(const uint8_t key_incr, const uint8_t token) +{ + cond_result.key_res_0_set = 0; + cond_result.key_res_1_set = 0; + cond_result.f2_key_incr = key_incr; + cond_result.f2f4_token = token; +} + +inline void EtmV4ITrcPacket::setCondRF3(const uint16_t tokens) +{ + cond_result.key_res_0_set = 0; + cond_result.key_res_1_set = 0; + cond_result.f3_tokens = tokens; +} + +inline void EtmV4ITrcPacket::setCondRF4(const uint8_t token) +{ + cond_result.key_res_0_set = 0; + cond_result.key_res_1_set = 0; + cond_result.f2f4_token = token; +} + +inline void EtmV4ITrcPacket::setContextInfo(const bool update, const uint8_t EL, const uint8_t NS, const uint8_t SF) +{ + pkt_valid.bits.context_valid = 1; + if(update) + { + context.updated = 1; + context.EL = EL; + context.NS = NS; + context.SF = SF; + } +} + +inline void EtmV4ITrcPacket::setContextVMID(const uint32_t VMID) +{ + pkt_valid.bits.context_valid = 1; + context.updated = 1; + context.VMID = VMID; + context.updated_v = 1; +} + +inline void EtmV4ITrcPacket::setContextCID(const uint32_t CID) +{ + pkt_valid.bits.context_valid = 1; + context.updated = 1; + context.ctxtID = CID; + context.updated_c = 1; +} + +inline void EtmV4ITrcPacket::setExceptionInfo(const uint16_t excep_type, const uint8_t addr_interp, const uint8_t m_fault_pending, const uint8_t m_type) +{ + exception_info.exceptionType = excep_type; + exception_info.addr_interp = addr_interp; + exception_info.m_fault_pending = m_fault_pending; + exception_info.m_type = m_type; +} + +inline void EtmV4ITrcPacket::set64BitAddress(const uint64_t addr, const uint8_t IS) +{ + v_addr.pkt_bits = 64; + v_addr.valid_bits = 64; + v_addr.size = VA_64BIT; + v_addr.val = addr; + v_addr_ISA = IS; + push_vaddr(); +} + +inline void EtmV4ITrcPacket::set32BitAddress(const uint32_t addr, const uint8_t IS) +{ + uint64_t mask = OCSD_BIT_MASK(32); + v_addr.pkt_bits = 32; + + if (pkt_valid.bits.context_valid && context.SF) + v_addr.size = VA_64BIT; + else + { + v_addr.val &= 0xFFFFFFFF; // ensure vaddr is only 32 bits if not 64 bit + v_addr.size = VA_32BIT; + } + + if (v_addr.valid_bits < 32) // may be 64 bit address so only set 32 if less + v_addr.valid_bits = 32; + + v_addr.val = (v_addr.val & ~mask) | (addr & mask); + v_addr_ISA = IS; + push_vaddr(); +} + +inline void EtmV4ITrcPacket::updateShortAddress(const uint32_t addr, const uint8_t IS, const uint8_t update_bits) +{ + ocsd_vaddr_t update_mask = OCSD_BIT_MASK(update_bits); + v_addr.pkt_bits = update_bits; + if(v_addr.valid_bits < update_bits) + v_addr.valid_bits = update_bits; + + v_addr.val = (v_addr.val & ~update_mask) | (addr & update_mask); + v_addr_ISA = IS; + push_vaddr(); +} + +inline void EtmV4ITrcPacket::setAddressExactMatch(const uint8_t idx) +{ + addr_exact_match_idx = idx; + pop_vaddr_idx(idx); + push_vaddr(); +} + +inline void EtmV4ITrcPacket::setDataSyncMarker(const uint8_t dsm_value) +{ + dsm_val = dsm_value; +} + +inline void EtmV4ITrcPacket::setEvent(const uint8_t event_value) +{ + event_val = event_value; +} + +inline void EtmV4ITrcPacket::setQType(const bool has_count, const uint32_t count, const bool has_addr, const bool addr_match, const uint8_t type) +{ + Q_pkt.q_count = count; + Q_pkt.q_type = type; + Q_pkt.count_present = has_count ? 1 : 0; + Q_pkt.addr_present = has_addr ? 1: 0; + Q_pkt.addr_match = addr_match ? 1 :0; +} + +inline const bool EtmV4ITrcPacket::isBadPacket() const +{ + return (type >= ETM4_PKT_I_BAD_SEQUENCE); +} + +inline void EtmV4ITrcPacket::push_vaddr() +{ + m_addr_stack.push(v_addr, v_addr_ISA); +} + +inline void EtmV4ITrcPacket::pop_vaddr_idx(const uint8_t idx) +{ + m_addr_stack.get_idx(idx, v_addr, v_addr_ISA); +} + +/** @}*/ + +#endif // ARM_TRC_PKT_ELEM_ETMV4I_H_INCLUDED + +/* End of File trc_pkt_elem_etmv4i.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_proc_etmv4.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_proc_etmv4.h new file mode 100644 index 000000000000..0d9ccea2be54 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_proc_etmv4.h @@ -0,0 +1,104 @@ +/* + * \file trc_pkt_proc_etmv4.h + * \brief OpenCSD : ETMv4 packet processor interface classes. + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PROC_ETMV4_H_INCLUDED +#define ARM_TRC_PKT_PROC_ETMV4_H_INCLUDED + + +#include "trc_pkt_types_etmv4.h" +#include "common/trc_pkt_proc_base.h" + +class EtmV4IPktProcImpl; /**< ETMv4 I channel packet processor */ +class EtmV4DPktProcImpl; /**< ETMv4 D channel packet processor */ +class EtmV4ITrcPacket; +class EtmV4DTrcPacket; +class EtmV4Config; + +/** @addtogroup ocsd_pkt_proc +@{*/ + +class TrcPktProcEtmV4I : public TrcPktProcBase< EtmV4ITrcPacket, ocsd_etmv4_i_pkt_type, EtmV4Config> +{ +public: + TrcPktProcEtmV4I(); + TrcPktProcEtmV4I(int instIDNum); + virtual ~TrcPktProcEtmV4I(); + +protected: + /* implementation packet processing interface */ + virtual ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const bool isBadPacket() const; + + friend class EtmV4IPktProcImpl; + + EtmV4IPktProcImpl *m_pProcessor; +}; + + +class TrcPktProcEtmV4D : public TrcPktProcBase< EtmV4DTrcPacket, ocsd_etmv4_d_pkt_type, EtmV4Config> +{ +public: + TrcPktProcEtmV4D(); + TrcPktProcEtmV4D(int instIDNum); + virtual ~TrcPktProcEtmV4D(); + +protected: + /* implementation packet processing interface */ + virtual ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const bool isBadPacket() const; + + friend class EtmV4DPktProcImpl; + + EtmV4DPktProcImpl *m_pProcessor; +}; + +/** @}*/ + +#endif // ARM_TRC_PKT_PROC_ETMV4_H_INCLUDED + +/* End of File trc_pkt_proc_etmv4.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h new file mode 100644 index 000000000000..b22a2b939719 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h @@ -0,0 +1,350 @@ +/* + * \file trc_pkt_types_etmv4.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_TYPES_ETMV4_H_INCLUDED +#define ARM_TRC_PKT_TYPES_ETMV4_H_INCLUDED + +#include "opencsd/trc_pkt_types.h" + +/** @addtogroup trc_pkts +@{*/ + +/** @name ETMv4 Packet Types +@{*/ + +/** I stream packets. */ +typedef enum _ocsd_etmv4_i_pkt_type +{ +/* state of decode markers */ + ETM4_PKT_I_NOTSYNC = 0x200, /*!< no sync found yet. */ + ETM4_PKT_I_INCOMPLETE_EOT, /*!< flushing incomplete/empty packet at end of trace.*/ + ETM4_PKT_I_NO_ERR_TYPE, /*!< error type not set for packet. */ + +/* markers for unknown/bad packets */ + ETM4_PKT_I_BAD_SEQUENCE = 0x300, /*!< invalid sequence for packet type. */ + ETM4_PKT_I_BAD_TRACEMODE, /*!< invalid packet type for this trace mode. */ + ETM4_PKT_I_RESERVED, /*!< packet type reserved. */ + +/* I stream packet types. */ + /* extension header. */ + ETM4_PKT_I_EXTENSION = 0x00, /*!< b00000000 */ + + /* address amd context */ + ETM4_PKT_I_ADDR_CTXT_L_32IS0 = 0x82, /*!< b10000010 */ + ETM4_PKT_I_ADDR_CTXT_L_32IS1, /*!< b10000011 */ + /* unused encoding b10000100 */ + ETM4_PKT_I_ADDR_CTXT_L_64IS0 = 0x85, /*!< b10000101 */ + ETM4_PKT_I_ADDR_CTXT_L_64IS1, /*!< b10000110 */ + /* unused encoding b10000111 */ + ETM4_PKT_I_CTXT = 0x80, /*!< b1000000x */ + ETM4_PKT_I_ADDR_MATCH = 0x90, /*!< b10010000 to b10010010 */ + ETM4_PKT_I_ADDR_L_32IS0 = 0x9A, /*!< b10011010 */ + ETM4_PKT_I_ADDR_L_32IS1, /*!< b10011011 */ + /* unused encoding b10011100 */ + ETM4_PKT_I_ADDR_L_64IS0 = 0x9D, /*!< b10011101 */ + ETM4_PKT_I_ADDR_L_64IS1, /*!< b10011110 */ + /* unused encoding b10011111 */ + ETM4_PKT_I_ADDR_S_IS0 = 0x95, /*!< b10010101 */ + ETM4_PKT_I_ADDR_S_IS1, /*!< b10010110 */ + /* unused encoding b10010111 + unused encoding b10011000 + unused encoding b10011001 */ + + /* Q packets */ + ETM4_PKT_I_Q = 0xA0, /*!< b1010xxxx */ + + /* Atom packets */ + ETM4_PKT_I_ATOM_F1 = 0xF6, /*!< b1111011x */ + ETM4_PKT_I_ATOM_F2 = 0xD8, /*!< b110110xx */ + ETM4_PKT_I_ATOM_F3 = 0xF8, //!< b11111xxx + ETM4_PKT_I_ATOM_F4 = 0xDC, //!< b110111xx + ETM4_PKT_I_ATOM_F5 = 0xD5, //!< b11010101 - b11010111, b11110101 + ETM4_PKT_I_ATOM_F6 = 0xC0, //!< b11000000 - b11010100, b11100000 - b11110100 + + /* conditional instruction tracing */ + ETM4_PKT_I_COND_FLUSH = 0x43, //!< b01000011 + ETM4_PKT_I_COND_I_F1 = 0x6C, //!< b01101100 + ETM4_PKT_I_COND_I_F2 = 0x40, //!< b01000000 - b01000010 + ETM4_PKT_I_COND_I_F3 = 0x6D, //!< b01101101 + ETM4_PKT_I_COND_RES_F1 = 0x68, //!< b0110111x, b011010xx + ETM4_PKT_I_COND_RES_F2 = 0x48, //!< b0100100x, b01001010, b0100110x, b01001110 + ETM4_PKT_I_COND_RES_F3 = 0x50, //!< b0101xxxx + ETM4_PKT_I_COND_RES_F4 = 0x44, //!< b0100010x, b01000110 + + /* cycle count packets */ + ETM4_PKT_I_CCNT_F1 = 0x0E, //!< b0000111x + ETM4_PKT_I_CCNT_F2 = 0x0C, //!< b0000110x + ETM4_PKT_I_CCNT_F3 = 0x10, //!< b0001xxxx + // data synchronisation markers + ETM4_PKT_I_NUM_DS_MKR = 0x20, //!< b00100xxx + ETM4_PKT_I_UNNUM_DS_MKR = 0x28, //!< b00101000 - b00101100 + // event trace + ETM4_PKT_I_EVENT = 0x70, //!< b0111xxxx + // Exceptions + ETM4_PKT_I_EXCEPT = 0x06, //!< b00000110 + ETM4_PKT_I_EXCEPT_RTN = 0x07, //!< b00000111 + // timestamp + ETM4_PKT_I_TIMESTAMP = 0x02, //!< b0000001x + // speculation + ETM4_PKT_I_CANCEL_F1 = 0x2E, //!< b0010111x + ETM4_PKT_I_CANCEL_F2 = 0x34, //!< b001101xx + ETM4_PKT_I_CANCEL_F3 = 0x38, //!< b00111xxx + ETM4_PKT_I_COMMIT = 0x2D, //!< b00101101 + ETM4_PKT_I_MISPREDICT = 0x30, //!< b001100xx + // Sync + ETM4_PKT_I_TRACE_INFO = 0x01, //!< b00000001 + ETM4_PKT_I_TRACE_ON = 0x04, //!< b00000100 + // extension packets - follow 0x00 header + ETM4_PKT_I_ASYNC = 0x100, //!< b00000000 + ETM4_PKT_I_DISCARD = 0x103, //!< b00000011 + ETM4_PKT_I_OVERFLOW = 0x105 //!< b00000101 + +} ocsd_etmv4_i_pkt_type; + +typedef union _etmv4_trace_info_t { + uint32_t val; //!< trace info full value. + struct { + uint32_t cc_enabled:1; //!< 1 if cycle count enabled + uint32_t cond_enabled:3; //!< conditional trace enabeld type + uint32_t p0_load:1; //!< 1 if tracing with P0 load elements (for data trace) + uint32_t p0_store:1; //1< 1 if tracing with P0 store elements (for data trace) + } bits; //!< bitfields for trace info value. +} etmv4_trace_info_t; + +typedef struct _etmv4_context_t { + struct { + uint32_t EL:2; //!< exception level. + uint32_t SF:1; //!< sixty four bit + uint32_t NS:1; //!< none secure + uint32_t updated:1; //!< updated this context packet (otherwise same as last time) + uint32_t updated_c:1; //!< updated CtxtID + uint32_t updated_v:1; //!< updated VMID + }; + uint32_t ctxtID; //!< Current ctxtID + uint32_t VMID; //!< current VMID +} etmv4_context_t; + +/** a broadcast address value. */ +typedef struct _etmv4_addr_val_t { + ocsd_vaddr_t val; //!< Address value. + uint8_t isa; //!< instruction set. +} etmv4_addr_val_t; + +typedef struct _ocsd_etmv4_i_pkt +{ + ocsd_etmv4_i_pkt_type type; /**< Trace packet type derived from header byte */ + + //** intra-packet data - valid across packets. + + ocsd_pkt_vaddr v_addr; //!< most recently broadcast address packet + uint8_t v_addr_ISA; //!< ISA for the address packet. (0 = IS0 / 1 = IS1) + + etmv4_context_t context; //!< current context for PE + + struct { + uint64_t timestamp; //!< current timestamp value + uint8_t bits_changed; //!< bits updated in this timestamp packet. + } ts; + + uint32_t cc_threshold; //!< cycle count threshold - from trace info. + + // single packet data - only valid for specific packet types on packet instance. + ocsd_pkt_atom atom; //!< atom elements - number of atoms indicates validity of packet + uint32_t cycle_count; //!< cycle count + + uint32_t curr_spec_depth; //!< current speculation depth + uint32_t p0_key; //!< current P0 key value for data packet synchronisation + + uint32_t commit_elements; // data value, timestamp value, event value */ + + ocsd_etmv4_d_pkt_type err_type; + +} ocsd_etmv4_d_pkt; + +typedef struct _ocsd_etmv4_cfg +{ + uint32_t reg_idr0; /**< ID0 register */ + uint32_t reg_idr1; /**< ID1 register */ + uint32_t reg_idr2; /**< ID2 register */ + uint32_t reg_idr8; + uint32_t reg_idr9; + uint32_t reg_idr10; + uint32_t reg_idr11; + uint32_t reg_idr12; + uint32_t reg_idr13; + uint32_t reg_configr; /**< Config Register */ + uint32_t reg_traceidr; /**< Trace Stream ID register */ + ocsd_arch_version_t arch_ver; /**< Architecture version */ + ocsd_core_profile_t core_prof; /**< Core Profile */ +} ocsd_etmv4_cfg; + +/** @}*/ +/** @}*/ +#endif // ARM_TRC_PKT_TYPES_ETMV4_H_INCLUDED + +/* End of File trc_pkt_types_etmv4.h */ + diff --git a/contrib/opencsd/decoder/include/opencsd/ocsd_if_types.h b/contrib/opencsd/decoder/include/opencsd/ocsd_if_types.h new file mode 100644 index 000000000000..def16575f2b2 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ocsd_if_types.h @@ -0,0 +1,592 @@ +/*! + * \file opencsd/ocsd_if_types.h + * \brief OpenCSD : Standard Types used in the library interfaces. + * + * \copyright Copyright (c) 2015, 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_IF_TYPES_H_INCLUDED +#define ARM_OCSD_IF_TYPES_H_INCLUDED + +#include +#include +#if defined(_MSC_VER) && (_MSC_VER < 1900) +/** VS2010 does not support inttypes - remove when VS2010 support is dropped */ +#define __PRI64_PREFIX "ll" +#define PRIX64 __PRI64_PREFIX "X" +#define PRIu64 __PRI64_PREFIX "u" +#define PRIu32 "u" +#else +#include +#endif + + +/** @defgroup ocsd_interfaces OpenCSD Library : Interfaces + @brief Set of types, structures and virtual interface classes making up the primary API + + Set of component interfaces that connect various source reader and decode components into a + decode tree to allow trace decode for the trace data being output by the source reader. + +@{*/ + + + +/** @name Trace Indexing and Channel IDs +@{*/ +#ifdef ENABLE_LARGE_TRACE_SOURCES +typedef uint64_t ocsd_trc_index_t; /**< Trace source index type - 64 bit size */ +#define OCSD_TRC_IDX_STR PRIu64 +#else +typedef uint32_t ocsd_trc_index_t; /**< Trace source index type - 32 bit size */ +#define OCSD_TRC_IDX_STR PRIu32 +#endif + +/** Invalid trace index value */ +#define OCSD_BAD_TRC_INDEX ((ocsd_trc_index_t)-1) +/** Invalid trace source ID value */ +#define OCSD_BAD_CS_SRC_ID ((uint8_t)-1) +/** macro returing true if trace source ID is in valid range (0x0 < ID < 0x70) */ +#define OCSD_IS_VALID_CS_SRC_ID(id) ((id > 0) && (id < 0x70)) +/** macro returing true if trace source ID is in reserved range (ID == 0x0 || 0x70 <= ID <= 0x7F) */ +#define OCSD_IS_RESERVED_CS_SRC_ID(id) ((id == 0) || ((id >= 0x70) && (id <= 0x7F)) +/** @}*/ + +/** @name General Library Return and Error Codes +@{*/ + +/** Library Error return type */ +typedef enum _ocsd_err_t { + + /* general return errors */ + OCSD_OK = 0, /**< No Error. */ + OCSD_ERR_FAIL, /**< General systemic failure. */ + OCSD_ERR_MEM, /**< Internal memory allocation error. */ + OCSD_ERR_NOT_INIT, /**< Component not initialised or initialisation failure. */ + OCSD_ERR_INVALID_ID, /**< Invalid CoreSight Trace Source ID. */ + OCSD_ERR_BAD_HANDLE, /**< Invalid handle passed to component. */ + OCSD_ERR_INVALID_PARAM_VAL, /**< Invalid value parameter passed to component. */ + OCSD_ERR_INVALID_PARAM_TYPE, /**< Type mismatch on abstract interface */ + OCSD_ERR_FILE_ERROR, /**< File access error */ + OCSD_ERR_NO_PROTOCOL, /**< Trace protocol unsupported */ + /* attachment point errors */ + OCSD_ERR_ATTACH_TOO_MANY, /**< Cannot attach - attach device limit reached. */ + OCSD_ERR_ATTACH_INVALID_PARAM, /**< Cannot attach - invalid parameter. */ + OCSD_ERR_ATTACH_COMP_NOT_FOUND,/**< Cannot detach - component not found. */ + /* source reader errors */ + OCSD_ERR_RDR_FILE_NOT_FOUND, /**< source reader - file not found. */ + OCSD_ERR_RDR_INVALID_INIT, /**< source reader - invalid initialisation parameter. */ + OCSD_ERR_RDR_NO_DECODER, /**< source reader - not trace decoder set. */ + /* data path errors */ + OCSD_ERR_DATA_DECODE_FATAL, /**< A decoder in the data path has returned a fatal error. */ + /* frame deformatter errors */ + OCSD_ERR_DFMTR_NOTCONTTRACE, /**< Trace input to deformatter none-continuous */ + /* packet processor errors - protocol issues etc */ + OCSD_ERR_BAD_PACKET_SEQ, /**< Bad packet sequence */ + OCSD_ERR_INVALID_PCKT_HDR, /**< Invalid packet header */ + OCSD_ERR_PKT_INTERP_FAIL, /**< Interpreter failed - cannot recover - bad data or sequence */ + /* packet decoder errors */ + OCSD_ERR_UNSUPPORTED_ISA, /**< ISA not supported in decoder. */ + OCSD_ERR_HW_CFG_UNSUPP, /**< Programmed trace configuration not supported by decoder.*/ + OCSD_ERR_UNSUPP_DECODE_PKT, /**< Packet not supported in decoder */ + OCSD_ERR_BAD_DECODE_PKT, /**< reserved or unknown packet in decoder. */ + OCSD_ERR_COMMIT_PKT_OVERRUN, /**< overrun in commit packet stack - tried to commit more than available */ + OCSD_ERR_MEM_NACC, /**< unable to access required memory address */ + OCSD_ERR_RET_STACK_OVERFLOW, /**< internal return stack overflow checks failed - popped more than we pushed. */ + /* decode tree errors */ + OCSD_ERR_DCDT_NO_FORMATTER, /**< No formatter in use - operation not valid. */ + /* target memory access errors */ + OCSD_ERR_MEM_ACC_OVERLAP, /**< Attempted to set an overlapping range in memory access map */ + OCSD_ERR_MEM_ACC_FILE_NOT_FOUND, /**< Memory access file could not be opened */ + OCSD_ERR_MEM_ACC_FILE_DIFF_RANGE, /**< Attempt to re-use the same memory access file for a different address range */ + OCSD_ERR_MEM_ACC_RANGE_INVALID, /**< Address range in accessor set to invalid values */ + /* test errors - errors generated only by the test code, not the library */ + OCSD_ERR_TEST_SNAPSHOT_PARSE, /**< test snapshot file parse error */ + OCSD_ERR_TEST_SNAPSHOT_PARSE_INFO, /**< test snapshot file parse information */ + OCSD_ERR_TEST_SNAPSHOT_READ, /**< test snapshot reader error */ + OCSD_ERR_TEST_SS_TO_DECODER, /**< test snapshot to decode tree conversion error */ + /* decoder registration */ + OCSD_ERR_DCDREG_NAME_REPEAT, /**< attempted to register a decoder with the same name as another one */ + OCSD_ERR_DCDREG_NAME_UNKNOWN, /**< attempted to find a decoder with a name that is not known in the library */ + OCSD_ERR_DCDREG_TYPE_UNKNOWN, /**< attempted to find a decoder with a type that is not known in the library */ + OCSD_ERR_DCDREG_TOOMANY, /**< attempted to register too many custom decoders */ + /* decoder config */ + OCSD_ERR_DCD_INTERFACE_UNUSED, /**< Attempt to connect or use and inteface not supported by this decoder. */ + /* end marker*/ + OCSD_ERR_LAST +} ocsd_err_t; + +/* component handle types */ +typedef unsigned int ocsd_hndl_rdr_t; /**< reader control handle */ +typedef unsigned int ocsd_hndl_err_log_t; /**< error logger connection handle */ + +/* common invalid handle type */ +#define OCSD_INVALID_HANDLE (unsigned int)-1 /**< Global invalid handle value */ + +/*! Error Severity Type + * + * Used to indicate the severity of an error, and also as the + * error log verbosity level in the error logger. + * + * The logger will ignore errors with a severity value higher than the + * current verbosity level. + * + * The value OCSD_ERR_SEV_NONE can only be used as a verbosity level to switch off logging, + * not as a severity value on an error. The other values can be used as both error severity and + * logger verbosity values. + */ +typedef enum _ocsd_err_severity_t { + OCSD_ERR_SEV_NONE, /**< No error logging. */ + OCSD_ERR_SEV_ERROR, /**< Most severe error - perhaps fatal. */ + OCSD_ERR_SEV_WARN, /**< Warning level. Inconsistent or incorrect data seen but can carry on decode processing */ + OCSD_ERR_SEV_INFO, /**< Information only message. Use for debugging code or suspect input data. */ +} ocsd_err_severity_t; + +/** @}*/ + +/** @name Trace Datapath +@{*/ + +/** Trace Datapath operations. + */ +typedef enum _ocsd_datapath_op_t { + OCSD_OP_DATA = 0, /**< Standard index + data packet */ + OCSD_OP_EOT, /**< End of available trace data. No data packet. */ + OCSD_OP_FLUSH, /**< Flush existing data where possible, retain decode state. No data packet. */ + OCSD_OP_RESET, /**< Reset decode state - drop any existing partial data. No data packet. */ +} ocsd_datapath_op_t; + +/** + * Trace Datapath responses + */ +typedef enum _ocsd_datapath_resp_t { + OCSD_RESP_CONT, /**< Continue processing */ + OCSD_RESP_WARN_CONT, /**< Continue processing : a component logged a warning. */ + OCSD_RESP_ERR_CONT, /**< Continue processing : a component logged an error.*/ + OCSD_RESP_WAIT, /**< Pause processing */ + OCSD_RESP_WARN_WAIT, /**< Pause processing : a component logged a warning. */ + OCSD_RESP_ERR_WAIT, /**< Pause processing : a component logged an error. */ + OCSD_RESP_FATAL_NOT_INIT, /**< Processing Fatal Error : component unintialised. */ + OCSD_RESP_FATAL_INVALID_OP, /**< Processing Fatal Error : invalid data path operation. */ + OCSD_RESP_FATAL_INVALID_PARAM, /**< Processing Fatal Error : invalid parameter in datapath call. */ + OCSD_RESP_FATAL_INVALID_DATA, /**< Processing Fatal Error : invalid trace data */ + OCSD_RESP_FATAL_SYS_ERR, /**< Processing Fatal Error : internal system error. */ +} ocsd_datapath_resp_t; + +/*! Macro returning true if datapath response value is FATAL. */ +#define OCSD_DATA_RESP_IS_FATAL(x) (x >= OCSD_RESP_FATAL_NOT_INIT) +/*! Macro returning true if datapath response value indicates WARNING logged. */ +#define OCSD_DATA_RESP_IS_WARN(x) ((x == OCSD_RESP_WARN_CONT) || (x == OCSD_RESP_WARN_WAIT)) +/*! Macro returning true if datapath response value indicates ERROR logged. */ +#define OCSD_DATA_RESP_IS_ERR(x) ((x == OCSD_RESP_ERR_CONT) || (x == OCSD_RESP_ERR_WAIT)) +/*! Macro returning true if datapath response value indicates WARNING or ERROR logged. */ +#define OCSD_DATA_RESP_IS_WARN_OR_ERR(x) (OCSD_DATA_RESP_IS_ERR(x) || OCSD_DATA_RESP_IS_WARN(x)) +/*! Macro returning true if datapath response value is CONT. */ +#define OCSD_DATA_RESP_IS_CONT(x) (x < OCSD_RESP_WAIT) +/*! Macro returning true if datapath response value is WAIT. */ +#define OCSD_DATA_RESP_IS_WAIT(x) ((x >= OCSD_RESP_WAIT) && (x < OCSD_RESP_FATAL_NOT_INIT)) + +/** @}*/ + +/** @name Trace Decode component types +@{*/ + + +/** Raw frame element data types + Data blocks types output from ITrcRawFrameIn. +*/ +typedef enum _rcdtl_rawframe_elem_t { + OCSD_FRM_NONE, /**< None data operation on data path. (EOT etc.) */ + OCSD_FRM_PACKED, /**< Raw packed frame data */ + OCSD_FRM_HSYNC, /**< HSYNC data */ + OCSD_FRM_FSYNC, /**< Frame Sync Data */ + OCSD_FRM_ID_DATA, /**< unpacked data for ID */ +} ocsd_rawframe_elem_t; + + +/** Indicates if the trace source will be frame formatted or a single protocol source. + Used in decode tree creation and configuration code. +*/ +typedef enum _ocsd_dcd_tree_src_t { + OCSD_TRC_SRC_FRAME_FORMATTED, /**< input source is frame formatted. */ + OCSD_TRC_SRC_SINGLE, /**< input source is from a single protocol generator. */ +} ocsd_dcd_tree_src_t; + +#define OCSD_DFRMTR_HAS_FSYNCS 0x01 /**< Deformatter Config : formatted data has fsyncs - input data 4 byte aligned */ +#define OCSD_DFRMTR_HAS_HSYNCS 0x02 /**< Deformatter Config : formatted data has hsyncs - input data 2 byte aligned */ +#define OCSD_DFRMTR_FRAME_MEM_ALIGN 0x04 /**< Deformatter Config : formatted frames are memory aligned, no syncs. Input data 16 byte frame aligned. */ +#define OCSD_DFRMTR_PACKED_RAW_OUT 0x08 /**< Deformatter Config : output raw packed frame data if raw monitor attached. */ +#define OCSD_DFRMTR_UNPACKED_RAW_OUT 0x10 /**< Deformatter Config : output raw unpacked frame data if raw monitor attached. */ +#define OCSD_DFRMTR_RESET_ON_4X_FSYNC 0x20 /**< Deformatter Config : reset downstream decoders if frame aligned 4x consecutive fsyncs spotted. (perf workaround) */ +#define OCSD_DFRMTR_VALID_MASK 0x3F /**< Deformatter Config : valid mask for deformatter configuration */ + +#define OCSD_DFRMTR_FRAME_SIZE 0x10 /**< CoreSight frame formatter frame size constant in bytes. */ + +/** @}*/ + +/** @name Trace Decode Component Name Prefixes + * + * Set of standard prefixes to be used for component names +@{*/ + +/** Component name prefix for trace source reader components */ +#define OCSD_CMPNAME_PREFIX_SOURCE_READER "SRDR" +/** Component name prefix for trace frame deformatter component */ +#define OCSD_CMPNAME_PREFIX_FRAMEDEFORMATTER "DFMT" +/** Component name prefix for trace packet processor. */ +#define OCSD_CMPNAME_PREFIX_PKTPROC "PKTP" +/** Component name prefix for trace packet decoder. */ +#define OCSD_CMPNAME_PREFIX_PKTDEC "PDEC" + +/** @}*/ + +/** @name Trace Decode Arch and Profile +@{*/ + +/** Core Architecture Version */ +typedef enum _ocsd_arch_version { + ARCH_UNKNOWN, /**< unknown architecture */ + ARCH_V7, /**< V7 architecture */ + ARCH_V8, /**< V8 architecture */ + ARCH_CUSTOM, /**< None ARM, custom architecture */ +} ocsd_arch_version_t; + +/** Core Profile */ +typedef enum _ocsd_core_profile { + profile_Unknown, /**< Unknown profile */ + profile_CortexM, /**< Cortex-M profile */ + profile_CortexR, /**< Cortex-R profile */ + profile_CortexA, /**< Cortex-A profile */ + profile_Custom, /**< None ARM, custom arch profile */ +} ocsd_core_profile_t; + +/** Combined architecture and profile descriptor for a core */ +typedef struct _ocsd_arch_profile_t { + ocsd_arch_version_t arch; /**< core architecture */ + ocsd_core_profile_t profile; /**< core profile */ +} ocsd_arch_profile_t; + +/* may want to use a 32 bit v-addr when running on 32 bit only ARM platforms. */ +#ifdef USE_32BIT_V_ADDR +typedef uint32_t ocsd_vaddr_t; /**< 32 bit virtual addressing in library - use if compiling on 32 bit platforms */ +#define OCSD_MAX_VA_BITSIZE 32 /**< 32 bit Virtual address bitsize macro */ +#define OCSD_VA_MASK ~0UL /**< 32 bit Virtual address bitsize mask */ +#else +typedef uint64_t ocsd_vaddr_t; /**< 64 bit virtual addressing in library */ +#define OCSD_MAX_VA_BITSIZE 64 /**< 64 bit Virtual address bitsize macro */ +#define OCSD_VA_MASK ~0ULL /**< 64 bit Virtual address bitsize mask */ +#endif + +/** A bit mask for the first 'bits' consecutive bits of an address */ +#define OCSD_BIT_MASK(bits) (bits == OCSD_MAX_VA_BITSIZE) ? OCSD_VA_MASK : ((ocsd_vaddr_t)1 << bits) - 1 + +/** @}*/ + +/** @name Instruction Decode Information +@{*/ + +/** Instruction Set Architecture type + * + */ +typedef enum _ocsd_isa +{ + ocsd_isa_arm, /**< V7 ARM 32, V8 AArch32 */ + ocsd_isa_thumb2, /**< Thumb2 -> 16/32 bit instructions */ + ocsd_isa_aarch64, /**< V8 AArch64 */ + ocsd_isa_tee, /**< Thumb EE - unsupported */ + ocsd_isa_jazelle, /**< Jazelle - unsupported in trace */ + ocsd_isa_custom, /**< Instruction set - custom arch decoder */ + ocsd_isa_unknown /**< ISA not yet known */ +} ocsd_isa; + +/** Security level type +*/ +typedef enum _ocsd_sec_level +{ + ocsd_sec_secure, /**< Core is in secure state */ + ocsd_sec_nonsecure /**< Core is in non-secure state */ +} ocsd_sec_level ; + +/** Exception level type +*/ +typedef enum _ocsd_ex_level +{ + ocsd_EL_unknown = -1, /**< EL unknown / unsupported in trace */ + ocsd_EL0 = 0, /**< EL0 */ + ocsd_EL1, /**< EL1 */ + ocsd_EL2, /**< EL2 */ + ocsd_EL3, /**< EL3 */ +} ocsd_ex_level; + + +/** instruction types - significant for waypoint calculaitons */ +typedef enum _ocsd_instr_type { + OCSD_INSTR_OTHER, /**< Other instruction - not significant for waypoints. */ + OCSD_INSTR_BR, /**< Immediate Branch instruction */ + OCSD_INSTR_BR_INDIRECT, /**< Indirect Branch instruction */ + OCSD_INSTR_ISB, /**< Barrier : ISB instruction */ + OCSD_INSTR_DSB_DMB /**< Barrier : DSB or DMB instruction */ +} ocsd_instr_type; + +/** instruction sub types - addiitonal information passed to the output packets + for trace analysis tools. + */ +typedef enum _ocsd_instr_subtype { + OCSD_S_INSTR_NONE, /**< no subtype set */ + OCSD_S_INSTR_BR_LINK, /**< branch with link */ + OCSD_S_INSTR_V8_RET, /**< v8 ret instruction - subtype of BR_INDIRECT */ + OCSD_S_INSTR_V8_ERET, /**< v8 eret instruction - subtype of BR_INDIRECT */ +} ocsd_instr_subtype; + +/** Instruction decode request structure. + * + * Used in IInstrDecode interface. + * + * Caller fills in the input: information, callee then fills in the decoder: information. + */ +typedef struct _ocsd_instr_info { + /* input information */ + ocsd_arch_profile_t pe_type; /**< input: Core Arch and profile */ + ocsd_isa isa; /**< Input: Current ISA. */ + ocsd_vaddr_t instr_addr; /**< Input: Instruction address. */ + uint32_t opcode; /**< Input: Opcode at address. 16 bit opcodes will use MS 16bits of parameter. */ + uint8_t dsb_dmb_waypoints; /**< Input: DMB and DSB are waypoints */ + + /* instruction decode info */ + ocsd_instr_type type; /**< Decoder: Current instruction type. */ + ocsd_vaddr_t branch_addr; /**< Decoder: Calculated address of branch instrcution (direct branches only) */ + ocsd_isa next_isa; /**< Decoder: ISA for next intruction. */ + uint8_t instr_size; /**< Decoder : size of the decoded instruction */ + uint8_t is_conditional; /**< Decoder : set to 1 if this instruction is conditional */ + uint8_t is_link; /**< Decoder : is a branch with link instruction */ + uint8_t thumb_it_conditions; /**< Decoder : return number of following instructions set with conditions by this Thumb IT instruction */ + ocsd_instr_subtype sub_type; /**< Decoder : current instruction sub-type if known */ +} ocsd_instr_info; + + +/** Core(PE) context structure + records current security state, exception level, VMID and ContextID for core. +*/ +typedef struct _ocsd_pe_context { + ocsd_sec_level security_level; /**< security state */ + ocsd_ex_level exception_level; /**< exception level */ + uint32_t context_id; /**< context ID */ + uint32_t vmid; /**< VMID */ + struct { + uint32_t bits64:1; /**< 1 if 64 bit operation */ + uint32_t ctxt_id_valid:1; /**< 1 if context ID value valid */ + uint32_t vmid_valid:1; /**< 1 if VMID value is valid */ + uint32_t el_valid:1; /**< 1 if EL value is valid (ETMv4 traces EL, other protocols do not) */ + }; +} ocsd_pe_context; + + +/** @}*/ + +/** @name Opcode Memory Access + Types used when accessing memory storage for traced opcodes.. +@{*/ + +/** memory space bitfield enum for available security states and exception levels used + when accessing memory. */ +typedef enum _ocsd_mem_space_acc_t { + OCSD_MEM_SPACE_EL1S = 0x1, /**< S EL1/0 */ + OCSD_MEM_SPACE_EL1N = 0x2, /**< NS EL1/0 */ + OCSD_MEM_SPACE_EL2 = 0x4, /**< NS EL2 */ + OCSD_MEM_SPACE_EL3 = 0x8, /**< S EL3 */ + OCSD_MEM_SPACE_S = 0x9, /**< Any S */ + OCSD_MEM_SPACE_N = 0x6, /**< Any NS */ + OCSD_MEM_SPACE_ANY = 0xF, /**< Any sec level / EL - live system use current EL + sec state */ +} ocsd_mem_space_acc_t; + +/** + * Callback function definition for callback function memory accessor type. + * + * When using callback memory accessor, the decoder will call this function to obtain the + * memory at the address for the current opcodes. The memory space will represent the current + * exception level and security context of the traced code. + * + * Return the number of bytes read, which can be less than the amount requested if this would take the + * access address outside the range of addresses defined when this callback was registered with the decoder. + * + * Return 0 bytes if start address out of covered range, or memory space is not one of those defined as supported + * when the callback was registered. + * + * @param p_context : opaque context pointer set by callback client. + * @param address : start address of memory to be accessed + * @param mem_space : memory space of accessed memory (current EL & security state) + * @param reqBytes : number of bytes required + * @param *byteBuffer : buffer for data. + * + * @return uint32_t : Number of bytes actually read, or 0 for access error. + */ +typedef uint32_t (* Fn_MemAcc_CB)(const void *p_context, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer); + + +/** memory region type for adding multi-region binary files to memory access interface */ +typedef struct _ocsd_file_mem_region { + size_t file_offset; /**< Offset from start of file for memory region */ + ocsd_vaddr_t start_address; /**< Start address of memory region */ + size_t region_size; /**< size in bytes of memory region */ +} ocsd_file_mem_region_t; + +/** @}*/ + +/** @name Packet Processor Operation Control Flags + common operational flags - bottom 16 bits, + component specific - top 16 bits. +@{*/ + +#define OCSD_OPFLG_PKTPROC_NOFWD_BAD_PKTS 0x00000001 /**< don't forward bad packets up data path */ +#define OCSD_OPFLG_PKTPROC_NOMON_BAD_PKTS 0x00000002 /**< don't forward bad packets to monitor interface */ +#define OCSD_OPFLG_PKTPROC_ERR_BAD_PKTS 0x00000004 /**< throw error for bad packets - halt decoding. */ +#define OCSD_OPFLG_PKTPROC_UNSYNC_ON_BAD_PKTS 0x00000008 /**< switch to unsynced state on bad packets - wait for next sync point */ + +/** mask to combine all common packet processor operational control flags */ +#define OCSD_OPFLG_PKTPROC_COMMON (OCSD_OPFLG_PKTPROC_NOFWD_BAD_PKTS | \ + OCSD_OPFLG_PKTPROC_NOMON_BAD_PKTS | \ + OCSD_OPFLG_PKTPROC_ERR_BAD_PKTS | \ + OCSD_OPFLG_PKTPROC_UNSYNC_ON_BAD_PKTS ) + +/** @}*/ + +/** @name Packet Decoder Operation Control Flags + common operational flags - bottom 16 bits, + component specific - top 16 bits. +@{*/ + +#define OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS 0x00000001 /**< throw error on bad packets input (default is to unsync and wait) */ + +/** mask to combine all common packet processor operational control flags */ +#define OCSD_OPFLG_PKTDEC_COMMON (OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) + +/** @}*/ + +/** @name Decoder creation information + + Flags to use when creating decoders by name + + Builtin decoder names. + + Protocol type enum. +@{*/ + +#define OCSD_CREATE_FLG_PACKET_PROC 0x01 /**< Create packet processor only. */ +#define OCSD_CREATE_FLG_FULL_DECODER 0x02 /**< Create packet processor + decoder pair */ +#define OCSD_CREATE_FLG_INST_ID 0x04 /**< Use instance ID in decoder instance name */ + +#define OCSD_BUILTIN_DCD_STM "STM" /**< STM decoder */ +#define OCSD_BUILTIN_DCD_ETMV3 "ETMV3" /**< ETMv3 decoder */ +#define OCSD_BUILTIN_DCD_ETMV4I "ETMV4I" /**< ETMv4 instruction decoder */ +#define OCSD_BUILTIN_DCD_ETMV4D "ETMV4D" /**< ETMv4 data decoder */ +#define OCSD_BUILTIN_DCD_PTM "PTM" /**< PTM decoder */ + +/*! Trace Protocol Builtin Types + extern + */ +typedef enum _ocsd_trace_protocol_t { + OCSD_PROTOCOL_UNKNOWN = 0, /**< Protocol unknown */ + +/* Built in library decoders */ + OCSD_PROTOCOL_ETMV3, /**< ETMV3 instruction and data trace protocol decoder. */ + OCSD_PROTOCOL_ETMV4I, /**< ETMV4 instruction trace protocol decoder. */ + OCSD_PROTOCOL_ETMV4D, /**< ETMV4 data trace protocol decoder. */ + OCSD_PROTOCOL_PTM, /**< PTM program flow instruction trace protocol decoder. */ + OCSD_PROTOCOL_STM, /**< STM system trace protocol decoder. */ + +/* others to be added here */ + OCSD_PROTOCOL_BUILTIN_END, /**< Invalid protocol - built-in protocol types end marker */ + +/* Custom / external decoders */ + OCSD_PROTOCOL_CUSTOM_0 = 100, /**< Values from this onwards are assigned to external registered decoders */ + OCSD_PROTOCOL_CUSTOM_1, + OCSD_PROTOCOL_CUSTOM_2, + OCSD_PROTOCOL_CUSTOM_3, + OCSD_PROTOCOL_CUSTOM_4, + OCSD_PROTOCOL_CUSTOM_5, + OCSD_PROTOCOL_CUSTOM_6, + OCSD_PROTOCOL_CUSTOM_7, + OCSD_PROTOCOL_CUSTOM_8, + OCSD_PROTOCOL_CUSTOM_9, + + OCSD_PROTOCOL_END /**< Invalid protocol - protocol types end marker */ +} ocsd_trace_protocol_t; + +/** Test if protocol type is a library built-in decoder */ +#define OCSD_PROTOCOL_IS_BUILTIN(P) ((P > OCSD_PROTOCOL_UNKNOWN) && (P < OCSD_PROTOCOL_BUILTIN_END)) + +/** Test if protocol type is a custom external registered decoder */ +#define OCSD_PROTOCOL_IS_CUSTOM(P) ((P >= OCSD_PROTOCOL_CUSTOM_0) && (P < OCSD_PROTOCOL_END )) + +/** @}*/ + + +/** @name Software Trace Packets Info + + Contains the information for the generic software trace output packet. + + Software trace packet master and channel data. + Payload info: + size - packet payload size in bits; + marker - if this packet has a marker/flag + timestamp - if this packet has a timestamp associated + number of packets - packet processor can optionally correlate identically + sized packets on the same master / channel to be output as a single generic packet + + Payload output as separate LE buffer, of sufficient bytes to hold all the packets. +@{*/ + +typedef struct _ocsd_swt_info { + uint16_t swt_master_id; + uint16_t swt_channel_id; + union { + struct { + uint32_t swt_payload_pkt_bitsize:8; /**< [bits 0:7 ] Packet size in bits of the payload packets */ + uint32_t swt_payload_num_packets:8; /**< [bits 8:15 ] number of consecutive packets of this type in the payload data */ + uint32_t swt_marker_packet:1; /**< [bit 16 ] packet is marker / flag packet */ + uint32_t swt_has_timestamp:1; /**< [bit 17 ] packet has timestamp. */ + uint32_t swt_marker_first:1; /**< [bit 18 ] for multiple packet payloads, this indicates if any marker is on first or last packet */ + uint32_t swt_master_err:1; /**< [bit 19 ] current master has error - payload is error code */ + uint32_t swt_global_err:1; /**< [bit 20 ] global error - payload is error code - master and channel ID not valid */ + uint32_t swt_trigger_event:1; /**< [bit 21 ] trigger event packet - payload is event number */ + uint32_t swt_frequency:1; /**< [bit 22 ] frequency packet - payload is frequency */ + uint32_t swt_id_valid:1; /**< [bit 23 ] master & channel ID has been set by input stream */ + }; + uint32_t swt_flag_bits; + }; +} ocsd_swt_info_t; + +/** mask for the swt_id_valid flag - need to retain between packets */ +#define SWT_ID_VALID_MASK (0x1 << 23) + +/** @}*/ + +/** @}*/ +#endif // ARM_OCSD_IF_TYPES_H_INCLUDED + +/* End of File opencsd/ocsd_if_types.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ptm/ptm_decoder.h b/contrib/opencsd/decoder/include/opencsd/ptm/ptm_decoder.h new file mode 100644 index 000000000000..80086d2ea54f --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ptm/ptm_decoder.h @@ -0,0 +1,46 @@ +/* + * \file ptm_decoder.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_PTM_DECODER_H_INCLUDED +#define ARM_PTM_DECODER_H_INCLUDED + +#include "trc_cmp_cfg_ptm.h" +#include "trc_pkt_elem_ptm.h" +#include "trc_pkt_proc_ptm.h" +#include "trc_pkt_types_ptm.h" +#include "trc_pkt_decode_ptm.h" + +#endif // ARM_PTM_DECODER_H_INCLUDED + +/* End of File ptm_decoder.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ptm/trc_cmp_cfg_ptm.h b/contrib/opencsd/decoder/include/opencsd/ptm/trc_cmp_cfg_ptm.h new file mode 100644 index 000000000000..e086aae8e446 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ptm/trc_cmp_cfg_ptm.h @@ -0,0 +1,210 @@ +/* + * \file trc_cmp_cfg_ptm.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_CMP_CFG_PTM_H_INCLUDED +#define ARM_TRC_CMP_CFG_PTM_H_INCLUDED + +#include "trc_pkt_types_ptm.h" +#include "common/trc_cs_config.h" + +/** @defgroup ocsd_protocol_cfg OpenCSD Library : Trace Source Protocol Configuration. + + @brief Classes describing the trace capture time configuration of the trace source hardware. + + Protocol configuration represents the trace capture time settings for the CoreSight hardware + component generating the trace. The packet processors and packet decoders require this configuration + information to correctly interpret packets and decode trace. + +@{*/ + +/** @name PTM configuration +@{*/ + +/*! + * @class PtmConfig + * @brief Interpreter class for PTM Hardware configuration. + * + * Provides quick value interpretation methods for the PTM config register values. + * Primarily inlined for efficient code. + */ +class PtmConfig : public CSConfig // public ocsd_ptm_cfg +{ +public: + PtmConfig(); /**< Default constructor */ + PtmConfig(const ocsd_ptm_cfg *cfg_regs); + ~PtmConfig() {}; /**< Default destructor */ + + /* register bit constants. */ + static const uint32_t CTRL_BRANCH_BCAST = (0x1 << 8); + static const uint32_t CTRL_CYCLEACC = (0x1 << 12); + static const uint32_t CTRL_TS_ENA = (0x1 << 28); + static const uint32_t CTRL_RETSTACK_ENA = (0x1 << 29); + static const uint32_t CTRL_VMID_ENA = (0x1 << 30); + + static const uint32_t CCER_TS_IMPL = (0x1 << 22); + static const uint32_t CCER_RESTACK_IMPL = (0x1 << 23); + static const uint32_t CCER_DMSB_WPT = (0x1 << 24); + static const uint32_t CCER_TS_DMSB = (0x1 << 25); + static const uint32_t CCER_VIRTEXT = (0x1 << 26); + static const uint32_t CCER_TS_ENC_NAT = (0x1 << 28); + static const uint32_t CCER_TS_64BIT = (0x1 << 29); + +// operations to convert to and from C-API structure + + //! copy assignment operator for base structure into class. + PtmConfig & operator=(const ocsd_ptm_cfg *p_cfg); + + //! cast operator returning struct const reference + operator const ocsd_ptm_cfg &() const { return m_cfg; }; + //! cast operator returning struct const pointer + operator const ocsd_ptm_cfg *() const { return &m_cfg; }; + +// access functions + + const bool enaBranchBCast() const; //!< Branch broadcast enabled. + const bool enaCycleAcc() const; //!< cycle accurate tracing enabled. + + const bool enaRetStack() const; //!< return stack enabled. + const bool hasRetStack() const; //!< return stack implemented. + + const int MinorRev() const; //!< return X revision in 1.X + + const bool hasTS() const; //!< Timestamps implemented in trace. + const bool enaTS() const; //!< Timestamp trace is enabled. + const bool TSPkt64() const; //!< timestamp packet is 64 bits in size. + const bool TSBinEnc() const; //!< Timestamp encoded as natural binary number. + + const int CtxtIDBytes() const; //!< number of context ID bytes traced 1,2,4; + const bool hasVirtExt() const; //!< processor has virtualisation extensions. + const bool enaVMID() const; //!< VMID tracing enabled. + + const bool dmsbGenTS() const; //!< TS generated for DMB and DSB + const bool dmsbWayPt() const; //!< DMB and DSB are waypoint instructions. + + virtual const uint8_t getTraceID() const; //!< CoreSight Trace ID for this device. + + const ocsd_core_profile_t &coreProfile() const { return m_cfg.core_prof; }; + const ocsd_arch_version_t &archVersion() const { return m_cfg.arch_ver; }; + +private: + ocsd_ptm_cfg m_cfg; +}; + +/* inlines */ + +inline PtmConfig & PtmConfig::operator=(const ocsd_ptm_cfg *p_cfg) +{ + // object of base class ocsd_ptm_cfg + m_cfg = *p_cfg; + return *this; +} + +inline const bool PtmConfig::enaBranchBCast() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_BRANCH_BCAST) != 0); +} + +inline const bool PtmConfig::enaCycleAcc() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_CYCLEACC) != 0); +} + +inline const bool PtmConfig::enaRetStack() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_RETSTACK_ENA) != 0); +} + +inline const bool PtmConfig::hasRetStack() const +{ + return (bool)((m_cfg.reg_ccer & CCER_RESTACK_IMPL) != 0); +} + +inline const int PtmConfig::MinorRev() const +{ + return ((int)m_cfg.reg_idr & 0xF0) >> 4; +} + +inline const bool PtmConfig::hasTS() const +{ + return (bool)((m_cfg.reg_ccer & CCER_TS_IMPL) != 0); +} + +inline const bool PtmConfig::enaTS() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_TS_ENA) != 0); +} + +inline const bool PtmConfig::TSPkt64() const +{ + if(MinorRev() == 0) return false; + return (bool)((m_cfg.reg_ccer & CCER_TS_64BIT) != 0); +} + +inline const bool PtmConfig::TSBinEnc() const +{ + if(MinorRev() == 0) return false; + return (bool)((m_cfg.reg_ccer & CCER_TS_ENC_NAT) != 0); +} + +inline const bool PtmConfig::hasVirtExt() const +{ + return (bool)((m_cfg.reg_ccer & CCER_VIRTEXT) != 0); +} + +inline const bool PtmConfig::enaVMID() const +{ + return (bool)((m_cfg.reg_ctrl & CTRL_VMID_ENA) != 0); +} + +inline const bool PtmConfig::dmsbGenTS() const +{ + return (bool)((m_cfg.reg_ccer & CCER_TS_DMSB) != 0); +} + +inline const bool PtmConfig::dmsbWayPt() const +{ + return (bool)((m_cfg.reg_ccer & CCER_DMSB_WPT) != 0); +} + +inline const uint8_t PtmConfig::getTraceID() const +{ + return (uint8_t)(m_cfg.reg_trc_id & 0x7F); +} + +/** @}*/ +/** @}*/ +#endif // ARM_TRC_CMP_CFG_PTM_H_INCLUDED + +/* End of File trc_cmp_cfg_ptm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ptm/trc_dcd_mngr_ptm.h b/contrib/opencsd/decoder/include/opencsd/ptm/trc_dcd_mngr_ptm.h new file mode 100644 index 000000000000..0defb0d2a590 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ptm/trc_dcd_mngr_ptm.h @@ -0,0 +1,57 @@ +/* + * \file trc_dcd_mngr_ptm.h + * \brief OpenCSD : PTM decoder manager / handler specialisation + * + * \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_TRC_DCD_MNGR_PTM_H_INCLUDED +#define ARM_TRC_DCD_MNGR_PTM_H_INCLUDED + +#include "common/ocsd_dcd_mngr.h" +#include "trc_pkt_decode_ptm.h" +#include "trc_pkt_proc_ptm.h" +#include "trc_cmp_cfg_ptm.h" +#include "trc_pkt_types_ptm.h" + +class DecoderMngrPtm : public DecodeMngrFullDcd< PtmTrcPacket, + ocsd_ptm_pkt_type, + PtmConfig, + ocsd_ptm_cfg, + TrcPktProcPtm, + TrcPktDecodePtm> +{ +public: + DecoderMngrPtm(const std::string &name) : DecodeMngrFullDcd(name,OCSD_PROTOCOL_PTM) {}; + virtual ~DecoderMngrPtm() {}; +}; + +#endif // ARM_TRC_DCD_MNGR_PTM_H_INCLUDED + +/* End of File trc_dcd_mngr_ptm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_decode_ptm.h b/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_decode_ptm.h new file mode 100644 index 000000000000..395b316cda06 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_decode_ptm.h @@ -0,0 +1,197 @@ +/* + * \file trc_pkt_decode_ptm.h + * \brief OpenCSD : PTM packet decoder. + * + * \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_TRC_PKT_DECODE_PTM_H_INCLUDED +#define ARM_TRC_PKT_DECODE_PTM_H_INCLUDED + +#include "common/trc_pkt_decode_base.h" +#include "opencsd/ptm/trc_pkt_elem_ptm.h" +#include "opencsd/ptm/trc_cmp_cfg_ptm.h" +#include "common/trc_gen_elem.h" +#include "common/trc_ret_stack.h" + +/**************** Atom handling class **************************************/ +class PtmAtoms +{ +public: + PtmAtoms() {}; + ~PtmAtoms() {}; + + //! initialise the atom and index values + void initAtomPkt(const ocsd_pkt_atom &atom, const ocsd_trc_index_t &root_index); + + const ocsd_atm_val getCurrAtomVal() const; + const int numAtoms() const; //!< number of atoms + const ocsd_trc_index_t pktIndex() const; //!< originating packet index + + void clearAtom(); //!< clear the current atom, set the next. + void clearAll(); //!< clear all + +private: + ocsd_pkt_atom m_atom; + ocsd_trc_index_t m_root_index; //!< root index for the atom packet +}; + +inline void PtmAtoms::initAtomPkt(const ocsd_pkt_atom &atom, const ocsd_trc_index_t &root_index) +{ + m_atom = atom; + m_root_index = root_index; +} + +inline const ocsd_atm_val PtmAtoms::getCurrAtomVal() const +{ + return (m_atom.En_bits & 0x1) ? ATOM_E : ATOM_N; +} + +inline const int PtmAtoms::numAtoms() const +{ + return m_atom.num; +} + +inline const ocsd_trc_index_t PtmAtoms::pktIndex() const +{ + return m_root_index; +} + +inline void PtmAtoms::clearAtom() +{ + if(m_atom.num) + { + m_atom.num--; + m_atom.En_bits >>=1; + } +} + +inline void PtmAtoms::clearAll() +{ + m_atom.num = 0; +} + +/********** Main decode class ****************************************************/ +class TrcPktDecodePtm : public TrcPktDecodeBase +{ +public: + TrcPktDecodePtm(); + TrcPktDecodePtm(int instIDNum); + virtual ~TrcPktDecodePtm(); + +protected: + /* implementation packet decoding interface */ + virtual ocsd_datapath_resp_t processPacket(); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const uint8_t getCoreSightTraceID() { return m_CSID; }; + + /* local decode methods */ + +private: + /** operation for the trace instruction follower */ + typedef enum { + TRACE_WAYPOINT, //!< standard operation - trace to waypoint - default op + TRACE_TO_ADDR_EXCL, //!< trace to supplied address - address is 1st instuction not executed. + TRACE_TO_ADDR_INCL //!< trace to supplied address - address is last instruction executed. + } waypoint_trace_t; + + void initDecoder(); + void resetDecoder(); + + ocsd_datapath_resp_t decodePacket(); + ocsd_datapath_resp_t contProcess(); + ocsd_datapath_resp_t processIsync(); + ocsd_datapath_resp_t processBranch(); + ocsd_datapath_resp_t processWPUpdate(); + ocsd_datapath_resp_t processAtom(); + ocsd_err_t traceInstrToWP(bool &bWPFound, const waypoint_trace_t traceWPOp = TRACE_WAYPOINT, const ocsd_vaddr_t nextAddrMatch = 0); //!< follow instructions from the current address to a WP. true if good, false if memory cannot be accessed. + ocsd_datapath_resp_t processAtomRange(const ocsd_atm_val A, const char *pkt_msg, const waypoint_trace_t traceWPOp = TRACE_WAYPOINT, const ocsd_vaddr_t nextAddrMatch = 0); + void checkPendingNacc(ocsd_datapath_resp_t &resp); + + uint8_t m_CSID; //!< Coresight trace ID for this decoder. + +//** Other processor state; + + // trace decode FSM + typedef enum { + NO_SYNC, //!< pre start trace - init state or after reset or overflow, loss of sync. + WAIT_SYNC, //!< waiting for sync packet. + WAIT_ISYNC, //!< waiting for isync packet after 1st ASYNC. + DECODE_PKTS, //!< processing input packet + CONT_ISYNC, //!< continue processing isync packet after WAIT. + CONT_ATOM, //!< continue processing atom packet after WAIT. + CONT_WPUP, //!< continue processing WP update packet after WAIT. + CONT_BRANCH, //!< continue processing Branch packet after WAIT. + } processor_state_t; + + processor_state_t m_curr_state; + + const bool processStateIsCont() const; + + // PE decode state - address and isa + + //! Structure to contain the PE addr and ISA state. + typedef struct _ptm_pe_addr_state { + ocsd_isa isa; //!< current isa. + ocsd_vaddr_t instr_addr; //!< current address. + bool valid; //!< address valid - false if we need an address to continue decode. + } ptm_pe_addr_state; + + ptm_pe_addr_state m_curr_pe_state; //!< current instruction state for PTM decode. + ocsd_pe_context m_pe_context; //!< current context information + + // packet decode state + bool m_need_isync; //!< need context to continue + + ocsd_instr_info m_instr_info; //!< instruction info for code follower - in address is the next to be decoded. + + bool m_mem_nacc_pending; //!< need to output a memory access failure packet + ocsd_vaddr_t m_nacc_addr; //!< address of memory access failure + + bool m_i_sync_pe_ctxt; //!< isync has pe context. + + PtmAtoms m_atoms; //!< atoms to process in an atom packet + + TrcAddrReturnStack m_return_stack; //!< trace return stack. + +//** output element + OcsdTraceElement m_output_elem; +}; + +inline const bool TrcPktDecodePtm::processStateIsCont() const +{ + return (bool)(m_curr_state >= CONT_ISYNC); +} + +#endif // ARM_TRC_PKT_DECODE_PTM_H_INCLUDED + +/* End of File trc_pkt_decode_ptm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_elem_ptm.h b/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_elem_ptm.h new file mode 100644 index 000000000000..266bd2b692a0 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_elem_ptm.h @@ -0,0 +1,221 @@ +/* + * \file trc_pkt_elem_ptm.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_ELEM_PTM_H_INCLUDED +#define ARM_TRC_PKT_ELEM_PTM_H_INCLUDED + +#include "trc_pkt_types_ptm.h" +#include "common/trc_printable_elem.h" +#include "common/trc_pkt_elem_base.h" + +/** @addtogroup trc_pkts +@{*/ + + +class PtmTrcPacket : public TrcPacketBase, public ocsd_ptm_pkt, trcPrintableElem +{ +public: + PtmTrcPacket(); + ~PtmTrcPacket(); + + PtmTrcPacket &operator =(const ocsd_ptm_pkt* p_pkt); + + virtual const void *c_pkt() const { return (const ocsd_ptm_pkt *)this; }; + + // update interface - set packet values + + void Clear(); //!< clear update data in packet ready for new one. + void ResetState(); //!< reset intra packet state data - on full decoder reset. + + void SetType(const ocsd_ptm_pkt_type p_type); + void SetErrType(const ocsd_ptm_pkt_type e_type); + + void SetException( const ocsd_armv7_exception type, + const uint16_t number); + void SetISyncReason(const ocsd_iSync_reason reason); + void SetCycleCount(const uint32_t cycleCount); + void SetAtomFromPHdr(const uint8_t pHdr); + void SetCycleAccAtomFromPHdr(const uint8_t pHdr); + + void UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits); + void UpdateNS(const int NS); + void UpdateAltISA(const int AltISA); + void UpdateHyp(const int Hyp); + void UpdateISA(const ocsd_isa isa); + void UpdateContextID(const uint32_t contextID); + void UpdateVMID(const uint8_t VMID); + void UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits); + + // packet status interface + + // get packet info. + const bool isBadPacket() const; + const ocsd_ptm_pkt_type getType() const; + + // isa + const ocsd_isa getISA() const; + const bool ISAChanged() const { return (bool)(curr_isa != prev_isa); }; + const uint8_t getAltISA() const { return context.curr_alt_isa; }; + const uint8_t getNS() const { return context.curr_NS; }; + const uint8_t getHyp() const { return context.curr_Hyp; }; + + // address + const ocsd_vaddr_t getAddrVal() const { return addr.val; }; + + // pe context information + const bool CtxtIDUpdated() const { return (bool)(context.updated_c == 1); }; + const bool VMIDUpdated() const { return (bool)(context.updated_v == 1); }; + const uint32_t getCtxtID() const { return context.ctxtID; }; + const uint8_t getVMID() const { return context.VMID; }; + const bool PEContextUpdated() const { return context.updated; }; + + // atom info + const ocsd_pkt_atom &getAtom() const { return atom; }; + + // branch address info + const bool isBranchExcepPacket() const { return (exception.bits.present == 1); }; + const ocsd_armv7_exception excepType() const { return exception.type; }; + const uint16_t excepNum() const { return exception.number; }; + + // isync + const ocsd_iSync_reason iSyncReason() const { return i_sync_reason; }; + + // cycle count + const bool hasCC() const { return (cc_valid == 1); }; + const uint32_t getCCVal() const { return cycle_count; }; + + // printing + virtual void toString(std::string &str) const; + virtual void toStringFmt(const uint32_t fmtFlags, std::string &str) const; + +private: + void packetTypeName(const ocsd_ptm_pkt_type pkt_type, std::string &name, std::string &desc) const; + void getAtomStr(std::string &valStr) const; + void getBranchAddressStr(std::string &valStr) const; + void getExcepStr(std::string &excepStr) const; + void getISAStr(std::string &isaStr) const; + void getCycleCountStr(std::string &subStr) const; + void getISyncStr(std::string &valStr) const; + void getTSStr(std::string &valStr) const; +}; + + +//*** update interface - set packet values +inline void PtmTrcPacket::SetType(const ocsd_ptm_pkt_type p_type) +{ + type = p_type; +} + +inline void PtmTrcPacket::SetErrType(const ocsd_ptm_pkt_type e_type) +{ + err_type = type; + type = e_type; +} + +inline void PtmTrcPacket::UpdateNS(const int NS) +{ + context.curr_NS = NS; + context.updated = 1; +}; + +inline void PtmTrcPacket::UpdateAltISA(const int AltISA) +{ + context.curr_alt_isa = AltISA; + context.updated = 1; +} + +inline void PtmTrcPacket::UpdateHyp(const int Hyp) +{ + context.curr_Hyp = Hyp; + context.updated = 1; +} + +inline void PtmTrcPacket::UpdateISA(const ocsd_isa isa) +{ + prev_isa = curr_isa; + curr_isa = isa; +} + +inline void PtmTrcPacket::UpdateContextID(const uint32_t contextID) +{ + context.ctxtID = contextID; + context.updated_c = 1; +} + +inline void PtmTrcPacket::UpdateVMID(const uint8_t VMID) +{ + context.VMID = VMID; + context.updated_v = 1; +} + +inline void PtmTrcPacket::SetException( const ocsd_armv7_exception type, const uint16_t number) +{ + exception.bits.present = 1; + exception.number = number; + exception.type = type; +} + +inline void PtmTrcPacket::SetISyncReason(const ocsd_iSync_reason reason) +{ + i_sync_reason = reason; +} + +inline void PtmTrcPacket::SetCycleCount(const uint32_t cycleCount) +{ + cycle_count = cycleCount; + cc_valid = 1; +} + +//*** packet status interface - get packet info. +inline const bool PtmTrcPacket::isBadPacket() const +{ + return (bool)(type >= PTM_PKT_BAD_SEQUENCE); +} + +inline const ocsd_ptm_pkt_type PtmTrcPacket::getType() const +{ + return type; +} + +inline const ocsd_isa PtmTrcPacket::getISA() const +{ + return curr_isa; +} + +/** @}*/ +#endif // ARM_TRC_PKT_ELEM_PTM_H_INCLUDED + +/* End of File trc_pkt_elem_ptm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_proc_ptm.h b/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_proc_ptm.h new file mode 100644 index 000000000000..87e933a3225d --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_proc_ptm.h @@ -0,0 +1,215 @@ +/* + * \file trc_pkt_proc_ptm.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PROC_PTM_H_INCLUDED +#define ARM_TRC_PKT_PROC_PTM_H_INCLUDED + +#include "trc_pkt_types_ptm.h" +#include "common/trc_pkt_proc_base.h" +#include "trc_pkt_elem_ptm.h" +#include "trc_cmp_cfg_ptm.h" + +class PtmTrcPacket; +class PtmConfig; + +/** @addtogroup ocsd_pkt_proc +@{*/ + + + +class TrcPktProcPtm : public TrcPktProcBase< PtmTrcPacket, ocsd_ptm_pkt_type, PtmConfig> +{ +public: + TrcPktProcPtm(); + TrcPktProcPtm(int instIDNum); + virtual ~TrcPktProcPtm(); + +protected: + /* implementation packet processing interface */ + virtual ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const bool isBadPacket() const; + + void InitPacketState(); // clear current packet state. + void InitProcessorState(); // clear all previous process state + + ocsd_datapath_resp_t outputPacket(); + + typedef enum _process_state { + WAIT_SYNC, + PROC_HDR, + PROC_DATA, + SEND_PKT, + } process_state; + + process_state m_process_state; // process algorithm state. + + std::vector m_currPacketData; // raw data + uint32_t m_currPktIdx; // index into packet when expanding + PtmTrcPacket m_curr_packet; // expanded packet + ocsd_trc_index_t m_curr_pkt_index; // trace index at start of packet. + + const bool readByte(uint8_t &currByte); + const bool readByte(); // just read into buffer, don't need the value + void unReadByte(); // remove last byte from the buffer. + + uint8_t m_chanIDCopy; + + // current data block being processed. + const uint8_t *m_pDataIn; + uint32_t m_dataInLen; + uint32_t m_dataInProcessed; + ocsd_trc_index_t m_block_idx; // index start for current block + + // processor synchronisation + const bool isSync() const; + ocsd_datapath_resp_t waitASync(); //!< look for first synchronisation point in the packet stream + bool m_waitASyncSOPkt; + bool m_bAsyncRawOp; + bool m_bOPNotSyncPkt; //!< true if output not sync packet when waiting for ASYNC + + // ** packet processing functions. + void pktASync(); + void pktISync(); + void pktTrigger(); + void pktWPointUpdate(); + void pktIgnore(); + void pktCtxtID(); + void pktVMID(); + void pktAtom(); + void pktTimeStamp(); + void pktExceptionRet(); + void pktBranchAddr(); + void pktReserved(); + + // async finder + typedef enum _async_result { + ASYNC, //!< pattern confirmed async 0x00 x 5, 0x80 + NOT_ASYNC, //!< pattern confirmed not async + ASYNC_EXTRA_0, //!< pattern confirmed 0x00 x N + ASYNC + THROW_0, //!< long pattern of 0x00 - throw some away. + ASYNC_INCOMPLETE, //!< not enough input data. + } async_result_t; + + async_result_t findAsync(); + + int m_async_0; // number of current consecutive async 0s + + bool m_part_async; + + // number of extra 0s before we throw 0 on async detect. + #define ASYNC_PAD_0_LIMIT 11 + // number of 0s minimum to form an async + #define ASYNC_REQ_0 5 + + // extraction sub-routines + void extractCtxtID(int idx, uint32_t &ctxtID); + void extractCycleCount(int idx, uint32_t &cycleCount); + int extractTS(uint64_t &tsVal, uint8_t &tsUpdateBits); + uint32_t extractAddress(const int offset,uint8_t &total_bits); + + // number of bytes required for a complete packet - used in some multi byte packets + int m_numPktBytesReq; + + // packet processing state + bool m_needCycleCount; + bool m_gotCycleCount; + int m_gotCCBytes; // number of CC bytes read so far + + int m_numCtxtIDBytes; + int m_gotCtxtIDBytes; + + bool m_gotTSBytes; //!< got all TS bytes + int m_tsByteMax; //!< max size for TS portion of TS packet. + + // branch address state + bool m_gotAddrBytes; //!< got all Addr bytes in branch packet + int m_numAddrBytes; //!< number of address bytes + bool m_gotExcepBytes; //!< got all needed exception bytes + int m_numExcepBytes; //!< got 1st exception byte + ocsd_isa m_addrPktIsa; //!< ISA of the branch address packet + int m_excepAltISA; //!< Alt ISA bit iff exception bytes + + // bad packets + void throwMalformedPacketErr(const char *pszErrMsg); + void throwPacketHeaderErr(const char *pszErrMsg); + + + // packet processing function table + typedef void (TrcPktProcPtm::*PPKTFN)(void); + PPKTFN m_pIPktFn; + + struct _pkt_i_table_t { + ocsd_ptm_pkt_type pkt_type; + PPKTFN pptkFn; + } m_i_table[256]; + + void BuildIPacketTable(); + +}; + +inline const bool TrcPktProcPtm::isSync() const +{ + return (bool)(m_curr_packet.getType() == PTM_PKT_NOTSYNC); +} + +inline void TrcPktProcPtm::throwMalformedPacketErr(const char *pszErrMsg) +{ + m_curr_packet.SetErrType(PTM_PKT_BAD_SEQUENCE); + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_curr_pkt_index,m_chanIDCopy,pszErrMsg); +} + +inline void TrcPktProcPtm::throwPacketHeaderErr(const char *pszErrMsg) +{ + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PCKT_HDR,m_curr_pkt_index,m_chanIDCopy,pszErrMsg); +} + +inline const bool TrcPktProcPtm::readByte() +{ + uint8_t currByte; + return readByte(currByte); +} + +/** @}*/ + +#endif // ARM_TRC_PKT_PROC_PTM_H_INCLUDED + +/* End of File trc_pkt_proc_ptm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_types_ptm.h b/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_types_ptm.h new file mode 100644 index 000000000000..45d994d59b50 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ptm/trc_pkt_types_ptm.h @@ -0,0 +1,137 @@ +/* + * \file trc_pkt_ptm_types.h + * \brief OpenCSD : PTM specific types + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PTM_TYPES_H_INCLUDED +#define ARM_TRC_PKT_PTM_TYPES_H_INCLUDED + +#include "opencsd/trc_pkt_types.h" + +/** @addtogroup trc_pkts +@{*/ + +/** @name PTM Packet Types +@{*/ + +typedef enum _ocsd_ptm_pkt_type +{ +// markers for unknown packets + PTM_PKT_NOTSYNC, //!< no sync found yet + PTM_PKT_INCOMPLETE_EOT, //!< flushing incomplete packet at end of trace. + PTM_PKT_NOERROR, //!< no error base type packet. + +// markers for valid packets + PTM_PKT_BRANCH_ADDRESS, //!< Branch address with optional exception. + PTM_PKT_A_SYNC, //!< Alignment Synchronisation. + PTM_PKT_I_SYNC, //!< Instruction sync with address. + PTM_PKT_TRIGGER, //!< trigger packet + PTM_PKT_WPOINT_UPDATE, //!< Waypoint update. + PTM_PKT_IGNORE, //!< ignore packet. + PTM_PKT_CONTEXT_ID, //!< context id packet. + PTM_PKT_VMID, //!< VMID packet + PTM_PKT_ATOM, //!< atom waypoint packet. + PTM_PKT_TIMESTAMP, //!< timestamp packet. + PTM_PKT_EXCEPTION_RET, //!< exception return. + PTM_PKT_BRANCH_OR_BYPASS_EOT, // interpreter FSM 'state' : unsure if branch 0 packet or bypass flush end of trace + PTM_PKT_TPIU_PAD_EOB, // pad end of a buffer - no valid trace at this point + +// markers for bad packets + PTM_PKT_BAD_SEQUENCE, //!< invalid sequence for packet type + PTM_PKT_RESERVED, //!< Reserved packet encoding + +} ocsd_ptm_pkt_type; + +typedef struct _ptm_context_t { + struct { + uint32_t curr_alt_isa:1; /**< current Alt ISA flag for Tee / T32 (used if not in present packet) */ + uint32_t curr_NS:1; /**< current NS flag (used if not in present packet) */ + uint32_t curr_Hyp:1; /**< current Hyp flag (used if not in present packet) */ + uint32_t updated:1; /**< context updated */ + uint32_t updated_c:1; /**< updated CtxtID */ + uint32_t updated_v:1; /**< updated VMID */ + }; + uint32_t ctxtID; /**< Context ID */ + uint8_t VMID; /**< VMID */ +} ptm_context_t; + +typedef struct _ocsd_ptm_excep { + ocsd_armv7_exception type; /**< exception type. */ + uint16_t number; /**< exception as number */ + struct { + uint32_t present:1; /**< exception present in packet */ + } bits; +} ocsd_ptm_excep; + + +typedef struct _ocsd_ptm_pkt +{ + ocsd_ptm_pkt_type type; /**< Primary packet type. */ + + ocsd_isa curr_isa; /**< current ISA. */ + ocsd_isa prev_isa; /**< previous ISA */ + + ocsd_pkt_vaddr addr; /**< current address. */ + ptm_context_t context; /**< current context. */ + ocsd_pkt_atom atom; + + ocsd_iSync_reason i_sync_reason; /**< reason for ISync Packet. */ + + uint32_t cycle_count; /**< cycle count value associated with this packet. */ + uint8_t cc_valid; /**< cycle count value valid. */ + + uint64_t timestamp; /**< timestamp value. */ + uint8_t ts_update_bits; /**< bits of ts updated this packet. (if TS packet) */ + + ocsd_ptm_excep exception; /**< exception information in packet */ + + ocsd_ptm_pkt_type err_type; /**< Basic packet type if primary type indicates error or incomplete. */ + +} ocsd_ptm_pkt; + +typedef struct _ocsd_ptm_cfg +{ + uint32_t reg_idr; /**< PTM ID register */ + uint32_t reg_ctrl; /**< Control Register */ + uint32_t reg_ccer; /**< Condition code extension register */ + uint32_t reg_trc_id; /**< CoreSight Trace ID register */ + ocsd_arch_version_t arch_ver; /**< Architecture version */ + ocsd_core_profile_t core_prof; /**< Core Profile */ +} ocsd_ptm_cfg; + +/** @}*/ + + +/** @}*/ +#endif // ARM_TRC_PKT_PTM_TYPES_H_INCLUDED + +/* End of File trc_pkt_ptm_types.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/stm/stm_decoder.h b/contrib/opencsd/decoder/include/opencsd/stm/stm_decoder.h new file mode 100644 index 000000000000..1367cad5d159 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/stm/stm_decoder.h @@ -0,0 +1,45 @@ +/* + * \file stm_decoder.h + * \brief OpenCSD : STM decoder + * + * \copyright Copyright (c) 2015, 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_STM_DECODER_H_INCLUDED +#define ARM_STM_DECODER_H_INCLUDED + +#include "trc_pkt_types_stm.h" +#include "trc_pkt_elem_stm.h" +#include "trc_pkt_proc_stm.h" + + +#endif // ARM_STM_DECODER_H_INCLUDED + +/* End of File stm_decoder.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/stm/trc_cmp_cfg_stm.h b/contrib/opencsd/decoder/include/opencsd/stm/trc_cmp_cfg_stm.h new file mode 100644 index 000000000000..41003ece3d91 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/stm/trc_cmp_cfg_stm.h @@ -0,0 +1,161 @@ +/* + * \file trc_cmp_cfg_stm.h + * \brief OpenCSD : STM compnent configuration. + * + * \copyright Copyright (c) 2015, 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_TRC_CMP_CFG_STM_H_INCLUDED +#define ARM_TRC_CMP_CFG_STM_H_INCLUDED + +#include "trc_pkt_types_stm.h" +#include "common/trc_cs_config.h" + +/** @addtogroup ocsd_protocol_cfg +@{*/ + +/** @name STM configuration +@{*/ + +/*! + * @class STMConfig + * @brief STM hardware configuration data. + * + * Represents the programmed and hardware configured state of an STM device. + * Creates default values for most RO register values to effect a default STM + * with values of 256 masters, 65536 channels, HW event trace not present / disabled. + * + * If this default is sufficient a single call to setTraceID() will be all that is + * required to decode the STM protocol. + * + * Can also be initialised with a fully populated ocsd_stm_cfg structure. + */ +class STMConfig : public CSConfig // public ocsd_stm_cfg +{ +public: + STMConfig(); //!< Constructor - creates a default configuration + STMConfig(const ocsd_stm_cfg *cfg_regs); + ~STMConfig() {}; + +// operations to convert to and from C-API structure + + STMConfig & operator=(const ocsd_stm_cfg *p_cfg); //!< set from full configuration structure. + //! cast operator returning struct const reference + operator const ocsd_stm_cfg &() const { return m_cfg; }; + //! cast operator returning struct const pointer + operator const ocsd_stm_cfg *() const { return &m_cfg; }; + +// access functions + void setTraceID(const uint8_t traceID); //!< Set the CoreSight trace ID. + void setHWTraceFeat(const hw_event_feat_t hw_feat); //!< set usage of STM HW event trace. + + virtual const uint8_t getTraceID() const; //!< Get the CoreSight trace ID. + const uint8_t getMaxMasterIdx() const; //!< Get the maximum master index + const uint16_t getMaxChannelIdx() const; //!< Get the maximum channel index. + const uint16_t getHWTraceMasterIdx() const; //!< Get the master used for HW event trace. + bool getHWTraceEn() const; //!< return true if HW trace is present and enabled. + +private: + bool m_bHWTraceEn; + ocsd_stm_cfg m_cfg; +}; + +inline STMConfig::STMConfig() +{ + m_cfg.reg_tcsr = 0; + m_cfg.reg_devid = 0xFF; // default to 256 masters. + m_cfg.reg_feat3r = 0x10000; // default to 65536 channels. + m_cfg.reg_feat1r = 0x0; + m_cfg.reg_hwev_mast = 0; // default hwtrace master = 0; + m_cfg.hw_event = HwEvent_Unknown_Disabled; // default to not present / disabled. + m_bHWTraceEn = false; +} + +inline STMConfig::STMConfig(const ocsd_stm_cfg *cfg_regs) +{ + m_cfg = *cfg_regs; + setHWTraceFeat(m_cfg.hw_event); +} + +inline STMConfig & STMConfig::operator=(const ocsd_stm_cfg *p_cfg) +{ + m_cfg = *p_cfg; + setHWTraceFeat(p_cfg->hw_event); + return *this; +} + +inline void STMConfig::setTraceID(const uint8_t traceID) +{ + uint32_t IDmask = 0x007F0000; + m_cfg.reg_tcsr &= ~IDmask; + m_cfg.reg_tcsr |= (((uint32_t)traceID) << 16) & IDmask; +} + +inline void STMConfig::setHWTraceFeat(const hw_event_feat_t hw_feat) +{ + m_cfg.hw_event = hw_feat; + m_bHWTraceEn = (m_cfg.hw_event == HwEvent_Enabled); + if(m_cfg.hw_event == HwEvent_UseRegisters) + m_bHWTraceEn = (((m_cfg.reg_feat1r & 0xC0000) == 0x80000) && ((m_cfg.reg_tcsr & 0x8) == 0x8)); +} + +inline const uint8_t STMConfig::getTraceID() const +{ + return (uint8_t)((m_cfg.reg_tcsr >> 16) & 0x7F); +} + +inline const uint8_t STMConfig::getMaxMasterIdx() const +{ + return (uint8_t)(m_cfg.reg_devid & 0xFF); +} + +inline const uint16_t STMConfig::getMaxChannelIdx() const +{ + return (uint16_t)(m_cfg.reg_feat3r - 1); +} + +inline const uint16_t STMConfig::getHWTraceMasterIdx() const +{ + return (uint16_t)(m_cfg.reg_hwev_mast & 0xFFFF); +} + +inline bool STMConfig::getHWTraceEn() const +{ + return m_bHWTraceEn; +} + + +/** @}*/ + +/** @}*/ + +#endif // ARM_TRC_CMP_CFG_STM_H_INCLUDED + +/* End of File trc_cmp_cfg_stm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/stm/trc_dcd_mngr_stm.h b/contrib/opencsd/decoder/include/opencsd/stm/trc_dcd_mngr_stm.h new file mode 100644 index 000000000000..33632c6d65a7 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/stm/trc_dcd_mngr_stm.h @@ -0,0 +1,57 @@ +/* + * \file trc_dcd_mngr_stm.h + * \brief OpenCSD : STM decoder manager / handler specialisation + * + * \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_TRC_DCD_MNGR_STM_H_INCLUDED +#define ARM_TRC_DCD_MNGR_STM_H_INCLUDED + +#include "common/ocsd_dcd_mngr.h" +#include "trc_pkt_decode_stm.h" +#include "trc_pkt_proc_stm.h" +#include "trc_cmp_cfg_stm.h" +#include "trc_pkt_types_stm.h" + +class DecoderMngrStm : public DecodeMngrFullDcd< StmTrcPacket, + ocsd_stm_pkt_type, + STMConfig, + ocsd_stm_cfg, + TrcPktProcStm, + TrcPktDecodeStm> +{ +public: + DecoderMngrStm(const std::string &name) : DecodeMngrFullDcd(name,OCSD_PROTOCOL_STM) {}; + virtual ~DecoderMngrStm() {}; +}; + +#endif // ARM_TRC_DCD_MNGR_STM_H_INCLUDED + +/* End of File trc_dcd_mngr_stm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_decode_stm.h b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_decode_stm.h new file mode 100644 index 000000000000..a4807207eb1e --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_decode_stm.h @@ -0,0 +1,103 @@ +/* + * \file trc_pkt_decode_stm.h + * \brief OpenCSD : STM packet decoder + * + * Convert the incoming indidvidual STM packets to + * + * \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_TRC_PKT_DECODE_STM_H_INCLUDED +#define ARM_TRC_PKT_DECODE_STM_H_INCLUDED + + +#include "common/trc_pkt_decode_base.h" +#include "opencsd/stm/trc_pkt_elem_stm.h" +#include "opencsd/stm/trc_cmp_cfg_stm.h" +#include "common/trc_gen_elem.h" + +class TrcPktDecodeStm : public TrcPktDecodeBase +{ +public: + TrcPktDecodeStm(); + TrcPktDecodeStm(int instIDNum); + virtual ~TrcPktDecodeStm(); + +protected: + /* implementation packet decoding interface */ + virtual ocsd_datapath_resp_t processPacket(); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const uint8_t getCoreSightTraceID() { return m_CSID; }; + + /* local decode methods */ + +private: + void initDecoder(); + void resetDecoder(); + void initPayloadBuffer(); + bool isInit() { return (bool)((m_config != 0) && (m_payload_buffer != 0)); }; + ocsd_datapath_resp_t decodePacket(bool &bPktDone); //!< decode the current incoming packet + void clearSWTPerPcktInfo(); + void updatePayload(bool &bSendPacket); + + typedef enum { + NO_SYNC, //!< pre start trace - init state or after reset or overflow, loss of sync. + WAIT_SYNC, //!< waiting for sync packet. + DECODE_PKTS //!< processing input packet. + } processor_state_t; + + processor_state_t m_curr_state; + + ocsd_swt_info_t m_swt_packet_info; + + uint8_t *m_payload_buffer; //!< payload buffer - allocated for one or multiple packets according to config + int m_payload_size; //!< payload buffer total size in bytes. + int m_payload_used; //!< payload buffer used in bytes - current payload size. + bool m_payload_odd_nibble; //!< last used byte in payload contains a single 4 bit packet. + int m_num_pkt_correlation; //!< number of identical payload packets to buffer up before output. - fixed at 1 till later update + + uint8_t m_CSID; //!< Coresight trace ID for this decoder. + + bool m_decode_pass1; //!< flag to indicate 1st pass of packet decode. + + + +//** output element + OcsdTraceElement m_output_elem; //!< output packet +}; + +#endif // ARM_TRC_PKT_DECODE_STM_H_INCLUDED + +/* End of File trc_pkt_decode_stm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_elem_stm.h b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_elem_stm.h new file mode 100644 index 000000000000..738e4522a9c2 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_elem_stm.h @@ -0,0 +1,238 @@ +/*! + * \file trc_pkt_elem_stm.h + * \brief OpenCSD : STM packet class. + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_ELEM_STM_H_INCLUDED +#define ARM_TRC_PKT_ELEM_STM_H_INCLUDED + +#include "trc_pkt_types_stm.h" +#include "common/trc_printable_elem.h" +#include "common/trc_pkt_elem_base.h" + +/*! + * @class StmTrcPacket + * @brief STM trace packet with packet printing functionality + * + * This class allows for the update and access of the current STM trace + * packet, implementing the STM protocol rules as appropriate. Maintains + * the intra packet state as well as updates on a per packet basis. + * + * Based on data structure ocsd_stm_pkt. + * + */ +class StmTrcPacket : public TrcPacketBase, public ocsd_stm_pkt, public trcPrintableElem +{ +public: + StmTrcPacket(); + ~StmTrcPacket() {}; + + StmTrcPacket &operator =(const ocsd_stm_pkt *p_pkt); + + virtual const void *c_pkt() const { return (const ocsd_stm_pkt *)this; }; + + void initStartState(); //!< Initialise packet state at start of decoder. + void initNextPacket(); //!< Initialise state for next packet. + + void setPacketType(const ocsd_stm_pkt_type type, const bool bMarker); + void updateErrType(const ocsd_stm_pkt_type err_type); + void setMaster(const uint8_t master); + void setChannel(const uint16_t channel, const bool b8Bit); + void setTS(const uint64_t ts_val, const uint8_t updatedBits); + void onVersionPkt(const ocsd_stm_ts_type type); + + void setD4Payload(const uint8_t value); + void setD8Payload(const uint8_t value); + void setD16Payload(const uint16_t value); + void setD32Payload(const uint32_t value); + void setD64Payload(const uint64_t value); + + const bool isMarkerPkt() const; + const bool isTSPkt() const; + + const ocsd_stm_pkt_type getPktType() const; + const ocsd_stm_pkt_type getPktErrType() const; + const uint8_t getMaster() const; + const uint16_t getChannel() const; + const ocsd_stm_ts_type getTSType() const; + const uint64_t getTSVal() const; + + const uint8_t getD4Val() const; + const uint8_t getD8Val() const; + const uint16_t getD16Val() const; + const uint32_t getD32Val() const; + const uint64_t getD64Val() const; + + const bool isBadPacket() const; + + // printing + virtual void toString(std::string &str) const; + virtual void toStringFmt(const uint32_t fmtFlags, std::string &str) const; + + +private: + void pktTypeName(const ocsd_stm_pkt_type pkt_type, std::string &name, std::string &desc) const; +}; + +inline void StmTrcPacket::setPacketType(const ocsd_stm_pkt_type type, const bool bMarker) +{ + this->type = type; + if(bMarker) + pkt_has_marker = 1; +} + +inline void StmTrcPacket::updateErrType(const ocsd_stm_pkt_type err_type) +{ + this->err_type = this->type; // original type is the err type; + this->type = err_type; // mark main type as an error. +} + +inline void StmTrcPacket::setMaster(const uint8_t master) +{ + this->master = master; + channel = 0; // M8 forces current channel to 0. +} + +inline void StmTrcPacket::setChannel(const uint16_t channel, const bool b8Bit) +{ + if(b8Bit) + this->channel = (this->channel & 0xFF00) | (channel & 0xFF); + else + this->channel = channel; +} + +inline void StmTrcPacket::onVersionPkt(const ocsd_stm_ts_type type) +{ + this->ts_type = type; + master = 0; + channel = 0; +} + +inline void StmTrcPacket::setD4Payload(const uint8_t value) +{ + payload.D8 = value & 0xF; +} + +inline void StmTrcPacket::setD8Payload(const uint8_t value) +{ + payload.D8 = value; +} + +inline void StmTrcPacket::setD16Payload(const uint16_t value) +{ + payload.D16 = value; +} + +inline void StmTrcPacket::setD32Payload(const uint32_t value) +{ + payload.D32 = value; +} + +inline void StmTrcPacket::setD64Payload(const uint64_t value) +{ + payload.D64 = value; +} + +inline const bool StmTrcPacket::isMarkerPkt() const +{ + return (pkt_has_marker != 0); +} + +inline const bool StmTrcPacket::isTSPkt() const +{ + return (pkt_has_ts != 0); +} + +inline const ocsd_stm_pkt_type StmTrcPacket::getPktType() const +{ + return type; +} + +inline const ocsd_stm_pkt_type StmTrcPacket::getPktErrType() const +{ + return err_type; +} + +inline const uint8_t StmTrcPacket::getMaster() const +{ + return master; +} + +inline const uint16_t StmTrcPacket::getChannel() const +{ + return channel; +} + +inline const ocsd_stm_ts_type StmTrcPacket::getTSType() const +{ + return ts_type; +} + +inline const uint64_t StmTrcPacket::getTSVal() const +{ + return timestamp; +} + +inline const uint8_t StmTrcPacket::getD4Val() const +{ + return payload.D8; +} + +inline const uint8_t StmTrcPacket::getD8Val() const +{ + return payload.D8; +} + +inline const uint16_t StmTrcPacket::getD16Val() const +{ + return payload.D16; +} + +inline const uint32_t StmTrcPacket::getD32Val() const +{ + return payload.D32; +} + +inline const uint64_t StmTrcPacket::getD64Val() const +{ + return payload.D64; +} + +inline const bool StmTrcPacket::isBadPacket() const +{ + return (bool)(type >= STM_PKT_BAD_SEQUENCE); +} + + +#endif // ARM_TRC_PKT_ELEM_STM_H_INCLUDED + +/* End of File trc_pkt_elem_stm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_proc_stm.h b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_proc_stm.h new file mode 100644 index 000000000000..909ac0cb0566 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_proc_stm.h @@ -0,0 +1,289 @@ +/* + * \file trc_pkt_proc_stm.h + * \brief OpenCSD : STM packet processing + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PROC_STM_H_INCLUDED +#define ARM_TRC_PKT_PROC_STM_H_INCLUDED + +#include + +#include "trc_pkt_types_stm.h" +#include "common/trc_pkt_proc_base.h" +#include "trc_pkt_elem_stm.h" +#include "trc_cmp_cfg_stm.h" + +/** @addtogroup ocsd_pkt_proc +@{*/ + +class TrcPktProcStm : public TrcPktProcBase +{ +public: + TrcPktProcStm(); + TrcPktProcStm(int instIDNum); + virtual ~TrcPktProcStm(); + +protected: + /* implementation packet processing interface */ + virtual ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + virtual ocsd_datapath_resp_t onEOT(); + virtual ocsd_datapath_resp_t onReset(); + virtual ocsd_datapath_resp_t onFlush(); + virtual ocsd_err_t onProtocolConfig(); + virtual const bool isBadPacket() const; + + + typedef enum _process_state { + WAIT_SYNC, + PROC_HDR, + PROC_DATA, + SEND_PKT + } process_state; + + process_state m_proc_state; + +private: + + void initObj(); + void initProcessorState(); + void initNextPacket(); + void waitForSync(const ocsd_trc_index_t blk_st_index); + + ocsd_datapath_resp_t outputPacket(); //!< send packet on output + void sendPacket(); //!< mark packet for send. + void setProcUnsynced(); //!< set processor state to unsynced + void throwBadSequenceError(const char *pszMessage = ""); + void throwReservedHdrError(const char *pszMessage = ""); + + // packet processing routines + // 1 nibble opcodes + void stmPktReserved(); + void stmPktNull(); + void stmPktM8(); + void stmPktMERR(); + void stmPktC8(); + void stmPktD4(); + void stmPktD8(); + void stmPktD16(); + void stmPktD32(); + void stmPktD64(); + void stmPktD4MTS(); + void stmPktD8MTS(); + void stmPktD16MTS(); + void stmPktD32MTS(); + void stmPktD64MTS(); + void stmPktFlagTS(); + void stmPktFExt(); + + // 2 nibble opcodes 0xFn + void stmPktReservedFn(); + void stmPktF0Ext(); + void stmPktGERR(); + void stmPktC16(); + void stmPktD4TS(); + void stmPktD8TS(); + void stmPktD16TS(); + void stmPktD32TS(); + void stmPktD64TS(); + void stmPktD4M(); + void stmPktD8M(); + void stmPktD16M(); + void stmPktD32M(); + void stmPktD64M(); + void stmPktFlag(); + void stmPktASync(); + + // 3 nibble opcodes 0xF0n + void stmPktReservedF0n(); + void stmPktVersion(); + void stmPktNullTS(); + void stmPktTrigger(); + void stmPktTriggerTS(); + void stmPktFreq(); + + void stmExtractTS(); // extract a TS in packets that require it. + void stmExtractVal8(uint8_t nibbles_to_val); + void stmExtractVal16(uint8_t nibbles_to_val); + void stmExtractVal32(uint8_t nibbles_to_val); + void stmExtractVal64(uint8_t nibbles_to_val); + + uint64_t bin_to_gray(uint64_t bin_value); + uint64_t gray_to_bin(uint64_t gray_value); + void pktNeedsTS(); // init the TS extraction routines + + // data processing op function tables + void buildOpTables(); + + typedef void (TrcPktProcStm::*PPKTFN)(void); + PPKTFN m_pCurrPktFn; // current active processing function. + + PPKTFN m_1N_ops[0x10]; + PPKTFN m_2N_ops[0x10]; + PPKTFN m_3N_ops[0x10]; + + // read a nibble from the input data - may read a byte and set spare or return spare. + // handles setting up packet data block and end of input + bool readNibble(); + + const bool dataToProcess() const; //!< true if data to process, or packet to send + + void savePacketByte(const uint8_t val); //!< save data to packet buffer if we need it for monitor. + + // packet data + StmTrcPacket m_curr_packet; //!< current packet. + bool m_bNeedsTS; //!< packet requires a TS + bool m_bIsMarker; + + + bool m_bStreamSync; //!< packet stream is synced + + // input data handling + uint8_t m_num_nibbles; //!< number of nibbles in the current packet + uint8_t m_nibble; //!< current nibble being processed. + uint8_t m_nibble_2nd; //!< 2nd unused nibble from a processed byte. + bool m_nibble_2nd_valid; //!< 2nd nibble is valid; + uint8_t m_num_data_nibbles; //!< number of nibbles needed to acheive payload. + + const uint8_t *m_p_data_in; //!< pointer to input data. + uint32_t m_data_in_size; //!< amount of data in. + uint32_t m_data_in_used; //!< amount of data processed. + ocsd_trc_index_t m_packet_index; //!< byte index for start of current packet + + std::vector m_packet_data; //!< current packet data (bytes) - only saved if needed to output to monitor. + bool m_bWaitSyncSaveSuppressed; //!< don't save byte at a time when waitsync + + // payload data + uint8_t m_val8; //!< 8 bit payload. + uint16_t m_val16; //!< 16 bit payload + uint32_t m_val32; //!< 32 bit payload + uint64_t m_val64; //!< 64 bit payload + + // timestamp handling + uint8_t m_req_ts_nibbles; + uint8_t m_curr_ts_nibbles; + uint64_t m_ts_update_value; + bool m_ts_req_set; + + + // sync handling - need to spot sync mid other packet in case of wrap / discontinuity + uint8_t m_num_F_nibbles; //!< count consecutive F nibbles. + bool m_sync_start; //!< possible start of sync + bool m_is_sync; //!< true if found sync at current nibble + ocsd_trc_index_t m_sync_index; //!< index of start of possible sync packet + + void checkSyncNibble(); //!< check current nibble as part of sync. + void clearSyncCount(); //!< valid packet, so clear sync counters (i.e. a trailing ffff is not part of sync). + + class monAttachNotify : public IComponentAttachNotifier + { + public: + monAttachNotify() { m_bInUse = false; }; + virtual ~monAttachNotify() {}; + virtual void attachNotify(const int num_attached) { m_bInUse = (num_attached > 0); }; + + const bool usingMonitor() const { return m_bInUse; }; + + private: + bool m_bInUse; + } mon_in_use; +}; + +inline const bool TrcPktProcStm::dataToProcess() const +{ + // data to process if + // 1) not processed all the input bytes + // 2) there is still a nibble available from the last byte. + // 3) bytes processed, but there is a full packet to send + return (m_data_in_used < m_data_in_size) || m_nibble_2nd_valid || (m_proc_state == SEND_PKT); +} + + +inline void TrcPktProcStm::checkSyncNibble() +{ + if(m_nibble != 0xF) + { + if(!m_sync_start) + return; + + if((m_nibble == 0) && (m_num_F_nibbles >= 21)) + { + m_is_sync = true; //this nibble marks a sync sequence - keep the F nibble count + } + else + { + clearSyncCount(); // clear all sync counters + } + return; + } + + m_num_F_nibbles++; + if(!m_sync_start) + { + m_sync_start = true; + m_sync_index = m_packet_index + ((m_num_nibbles - 1) / 2); + } +} + +inline void TrcPktProcStm::clearSyncCount() +{ + m_num_F_nibbles = 0; + m_sync_start = false; + m_is_sync = false; +} + +inline void TrcPktProcStm::sendPacket() +{ + m_proc_state = SEND_PKT; +} + +inline void TrcPktProcStm::setProcUnsynced() +{ + m_proc_state = WAIT_SYNC; + m_bStreamSync = false; +} + + +inline void TrcPktProcStm::savePacketByte(const uint8_t val) +{ + // save packet data if using monitor and synchronised. + if(mon_in_use.usingMonitor() && !m_bWaitSyncSaveSuppressed) + m_packet_data.push_back(val); +} + +/** @}*/ + +#endif // ARM_TRC_PKT_PROC_STM_H_INCLUDED + +/* End of File trc_pkt_proc_stm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_types_stm.h b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_types_stm.h new file mode 100644 index 000000000000..fd44cea939b4 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_types_stm.h @@ -0,0 +1,158 @@ +/* + * \file trc_pkt_types_stm.h + * \brief OpenCSD : STM decoder + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_TYPES_STM_H_INCLUDED +#define ARM_TRC_PKT_TYPES_STM_H_INCLUDED + +#include "opencsd/trc_pkt_types.h" + +/** @addtogroup trc_pkts +@{*/ + +/** @name STM Packet Types +@{*/ + +/** STM protocol packet types. + Contains both protocol packet types and markers for unsynced processor + state and bad packet sequences. +*/ +typedef enum _ocsd_stm_pkt_type +{ +/* markers for unknown packets / state*/ + STM_PKT_NOTSYNC, /**< Not synchronised */ + STM_PKT_INCOMPLETE_EOT, /**< Incomplete packet flushed at end of trace. */ + STM_PKT_NO_ERR_TYPE, /**< No error in error packet marker. */ + +/* markers for valid packets*/ + STM_PKT_ASYNC, /**< Alignment synchronisation packet */ + STM_PKT_VERSION, /**< Version packet */ + STM_PKT_FREQ, /**< Frequency packet */ + STM_PKT_NULL, /**< Null packet */ + STM_PKT_TRIG, /**< Trigger event packet. */ + + STM_PKT_GERR, /**< Global error packet - protocol error but unknown which master had error */ + STM_PKT_MERR, /**< Master error packet - current master detected an error (e.g. dropped trace) */ + + STM_PKT_M8, /**< Set current master */ + STM_PKT_C8, /**< Set lower 8 bits of current channel */ + STM_PKT_C16, /**< Set current channel */ + + STM_PKT_FLAG, /**< Flag packet */ + + STM_PKT_D4, /**< 4 bit data payload packet */ + STM_PKT_D8, /**< 8 bit data payload packet */ + STM_PKT_D16, /**< 16 bit data payload packet */ + STM_PKT_D32, /**< 32 bit data payload packet */ + STM_PKT_D64, /**< 64 bit data payload packet */ + +/* packet errors.*/ + STM_PKT_BAD_SEQUENCE, /**< Incorrect protocol sequence */ + STM_PKT_RESERVED, /**< Reserved packet header / not supported by CS-STM */ + +} ocsd_stm_pkt_type; + +/** STM timestamp encoding type. + Extracted from STM version packet. + CS-STM supports Natural binary and grey encodings. +*/ +typedef enum _ocsd_stm_ts_type +{ + STM_TS_UNKNOWN, /**< TS encoding unknown at present. */ + STM_TS_NATBINARY, /**< TS encoding natural binary */ + STM_TS_GREY /**< TS encoding grey coded. */ +} ocsd_stm_ts_type; + +/** STM trace packet + + Structure containing the packet data for a single STM packet, plus + data persisting between packets (master, channel, last timestamp). +*/ +typedef struct _ocsd_stm_pkt +{ + ocsd_stm_pkt_type type; /**< STM packet type */ + + uint8_t master; /**< current master */ + uint16_t channel; /**< current channel */ + + uint64_t timestamp; /**< latest timestamp value -> as binary - packet processor does grey decoding */ + uint8_t pkt_ts_bits; /**< timestamp bits updated this packet */ + uint8_t pkt_has_ts; /**< current packet has associated timestamp (ts bits can be 0 if same value as last time) */ + + ocsd_stm_ts_type ts_type; /**< timestamp encoding type */ + + uint8_t pkt_has_marker; /**< flag to indicate current packet has marker */ + + union { + uint8_t D8; /**< payload for D8 or D4 data packet, or parameter value for other packets with 8 bit value [VERSION, TRIG, xERR] */ + uint16_t D16; /**< payload for D16 data packet, or reserved opcode in bad packet header (1-3 nibbles) */ + uint32_t D32; /**< payload for D32 data packet, or parameter value for other packets with 32 bit value [FREQ] */ + uint64_t D64; /**< payload for D64 data packet */ + } payload; + + ocsd_stm_pkt_type err_type; /**< Initial type of packet if type indicates bad sequence. */ + +} ocsd_stm_pkt; + +/** HW Event trace feature + Defines if the STM supports or has enabled the HW event trace feature. + This may not always be able to be determined by the registers, or the feature + values can override if HW event trace is to be ignored. +*/ +typedef enum _hw_event_feat { + HwEvent_Unknown_Disabled, /*!< status of HW event features not known - assume not present or disabled */ + HwEvent_Enabled, /*!< HW event present and enabled - ignore Feat regs, assume hwev_mast value valid */ + HwEvent_UseRegisters /*!< Feature Register values and enable bits used to determine HW event trace status */ +} hw_event_feat_t; + + +/** STM hardware configuration. + Contains hardware register values at time of trace capture and HW event feature + field to enable and control decode of STM trace stream. +*/ +typedef struct _ocsd_stm_cfg +{ + uint32_t reg_tcsr; /**< Contains CoreSight trace ID, HWTEN */ + uint32_t reg_feat3r; /**< defines number of masters */ + uint32_t reg_devid; /**< defines number of channels per master */ + + uint32_t reg_feat1r; /**< defines HW trace features */ + uint32_t reg_hwev_mast; /**< master ID for HW event trace */ + hw_event_feat_t hw_event; /**< status of HW event trace */ +} ocsd_stm_cfg; + +/** @}*/ +/** @}*/ + +#endif // ARM_TRC_PKT_TYPES_STM_H_INCLUDED + +/* End of File trc_pkt_types_stm.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h b/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h new file mode 100644 index 000000000000..3766785dbd6d --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h @@ -0,0 +1,126 @@ +/*! + * \file opencsd/trc_gen_elem_types.h + * \brief OpenCSD : Decoder Output Generic Element types. + * + * \copyright Copyright (c) 2015, 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_TRC_GEN_ELEM_TYPES_H_INCLUDED +#define ARM_TRC_GEN_ELEM_TYPES_H_INCLUDED + +/** @defgroup gen_trc_elem OpenCSD Library : Generic Trace Elements + * @brief Generic trace elements output by the PE trace decode and SW stim decode stages. + * + * +@{*/ + +#include "opencsd/ocsd_if_types.h" + +/** Enum for generic element types */ +typedef enum _ocsd_gen_trc_elem_t +{ + OCSD_GEN_TRC_ELEM_UNKNOWN = 0, /*!< Unknown trace element - default value or indicate error in stream to client */ + OCSD_GEN_TRC_ELEM_NO_SYNC, /*!< Waiting for sync - either at start of decode, or after overflow / bad packet */ + OCSD_GEN_TRC_ELEM_TRACE_ON, /*!< Start of trace - beginning of elements or restart after discontinuity (overflow, trace filtering). */ + OCSD_GEN_TRC_ELEM_EO_TRACE, /*!< end of the available trace in the buffer. */ + OCSD_GEN_TRC_ELEM_PE_CONTEXT, /*!< PE status update / change (arch, ctxtid, vmid etc). */ + OCSD_GEN_TRC_ELEM_INSTR_RANGE, /*!< traced N consecutive instructions from addr (no intervening events or data elements), may have data assoc key */ + OCSD_GEN_TRC_ELEM_ADDR_NACC, /*!< tracing in inaccessible memory area */ + OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN, /*!< address currently unknown - need address packet update */ + OCSD_GEN_TRC_ELEM_EXCEPTION, /*!< exception - start address may be exception target, end address may be preferred ret addr. */ + OCSD_GEN_TRC_ELEM_EXCEPTION_RET, /*!< expection return */ + OCSD_GEN_TRC_ELEM_TIMESTAMP, /*!< Timestamp - preceding elements happeded before this time. */ + OCSD_GEN_TRC_ELEM_CYCLE_COUNT, /*!< Cycle count - cycles since last cycle count value - associated with a preceding instruction range. */ + OCSD_GEN_TRC_ELEM_EVENT, /*!< Event - trigger, (TBC - perhaps have a set of event types - cut down additional processing?) */ + OCSD_GEN_TRC_ELEM_SWTRACE, /*!< Software trace packet - may contain data payload. */ + OCSD_GEN_TRC_ELEM_CUSTOM, /*!< Fully custom packet type - used by none-ARM architecture decoders */ +} ocsd_gen_trc_elem_t; + + +typedef enum _trace_on_reason_t { + TRACE_ON_NORMAL = 0, /**< Trace on at start of trace or filtering discontinuity */ + TRACE_ON_OVERFLOW, /**< Trace on due to prior trace overflow discontinuity */ + TRACE_ON_EX_DEBUG, /**< Trace restarted due to debug exit */ +} trace_on_reason_t; + +typedef struct _trace_event_t { + uint16_t ev_type; /**< event type - unknown (0) trigger (1), numbered event (2)*/ + uint16_t ev_number; /**< event number if numbered event type */ +} trace_event_t; + +typedef struct _ocsd_generic_trace_elem { + ocsd_gen_trc_elem_t elem_type; /**< Element type - remaining data interpreted according to this value */ + ocsd_isa isa; /**< instruction set for executed instructions */ + ocsd_vaddr_t st_addr; /**< start address for instruction execution range / inaccessible code address / data address */ + ocsd_vaddr_t en_addr; /**< end address (exclusive) for instruction execution range. */ + ocsd_pe_context context; /**< PE Context */ + uint64_t timestamp; /**< timestamp value for TS element type */ + uint32_t cycle_count; /**< cycle count for explicit cycle count element, or count for element with associated cycle count */ + ocsd_instr_type last_i_type; /**< Last instruction type if instruction execution range */ + ocsd_instr_subtype last_i_subtype; /**< sub type for last instruction in range */ + + //! per element flags + union { + struct { + uint32_t last_instr_exec:1; /**< 1 if last instruction in range was executed; */ + uint32_t has_cc:1; /**< 1 if this packet has a valid cycle count included (e.g. cycle count included as part of instruction range packet, always 1 for pure cycle count packet.*/ + uint32_t cpu_freq_change:1; /**< 1 if this packet indicates a change in CPU frequency */ + uint32_t excep_ret_addr:1; /**< 1 if en_addr is the preferred exception return address on exception packet type */ + uint32_t excep_data_marker:1; /**< 1 if the exception entry packet is a data push marker only, with no address information (used typically in v7M trace for marking data pushed onto stack) */ + uint32_t extended_data:1; /**< 1 if the packet extended data pointer is valid. Allows packet extensions for custom decoders, or additional data payloads for data trace. */ + uint32_t has_ts:1; /**< 1 if the packet has an associated timestamp - e.g. SW/STM trace TS+Payload as a single packet */ + }; + uint32_t flag_bits; + }; + + //! packet specific payloads + union { + uint32_t exception_number; /**< exception number for exception type packets */ + trace_event_t trace_event; /**< Trace event - trigger etc */ + trace_on_reason_t trace_on_reason; /**< reason for the trace on packet */ + ocsd_swt_info_t sw_trace_info; /**< software trace packet info */ + }; + + const void *ptr_extended_data; /**< pointer to extended data buffer (data trace, sw trace payload) / custom structure */ + +} ocsd_generic_trace_elem; + + +typedef enum _event_t { + EVENT_UNKNOWN = 0, + EVENT_TRIGGER, + EVENT_NUMBERED +} event_t; + + +/** @}*/ +#endif // ARM_TRC_GEN_ELEM_TYPES_H_INCLUDED + +/* End of File opencsd/trc_gen_elem_types.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/trc_pkt_types.h b/contrib/opencsd/decoder/include/opencsd/trc_pkt_types.h new file mode 100644 index 000000000000..2eb353a1761a --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/trc_pkt_types.h @@ -0,0 +1,137 @@ +/*! + * \file opencsd/trc_pkt_types.h + * \brief OpenCSD: Common "C" types for trace packets. + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_TYPES_H_INCLUDED +#define ARM_TRC_PKT_TYPES_H_INCLUDED + +#include +#include "opencsd/ocsd_if_types.h" + +/** @defgroup trc_pkts OpenCSD Library : Trace Packet Types + + @brief Types used in trace packet description structures. + +@{*/ + + +/** @name Common Packet Types +@{*/ + +typedef enum _ocsd_pkt_va_size +{ + VA_32BIT, + VA_64BIT +} ocsd_pkt_va_size; + +typedef struct _ocsd_pkt_vaddr +{ + ocsd_pkt_va_size size; /**< Virtual address size. */ + ocsd_vaddr_t val; /**< Current value */ + uint8_t pkt_bits; /**< Bits updated this packet */ + uint8_t valid_bits; /**< Currently valid bits */ +} ocsd_pkt_vaddr; + +typedef struct _ocsd_pkt_byte_sz_val +{ + uint32_t val; + uint8_t size_bytes; + uint8_t valid_bytes; +} ocsd_pkt_byte_sz_val; + +typedef enum _ocsd_pkt_atm_type +{ + ATOM_PATTERN, /**< set atom packet using pattern supplied */ + ATOM_REPEAT /**< set atom packet using repeat value (convert to pattern) */ +} ocsd_pkt_atm_type; + +typedef enum _ocsd_atm_val { + ATOM_N, + ATOM_E +} ocsd_atm_val; + +typedef struct _ocsd_pkt_atom +{ + /** pattern across num bits. + Bit sequence:- ls bit = oldest atom (1st instruction executed), ms bit = newest (last instruction executed), + Bit values :- 1'b1 = E atom, 1'b0 = N atom. + */ + uint32_t En_bits; + uint8_t num; /**< number of atoms represented */ +} ocsd_pkt_atom; + +/** Isync Reason - common to PTM and ETMv3 **/ +typedef enum _ocsd_iSync_reason { + iSync_Periodic = 0, + iSync_TraceEnable, + iSync_TraceRestartAfterOverflow, + iSync_DebugExit +} ocsd_iSync_reason; + + +typedef enum _ocsd_armv7_exception { + Excp_Reserved, + Excp_NoException, + Excp_Reset, + Excp_IRQ, + Excp_FIQ, + Excp_AsyncDAbort, + Excp_DebugHalt, + Excp_Jazelle, + Excp_SVC, + Excp_SMC, + Excp_Hyp, + Excp_Undef, + Excp_PrefAbort, + Excp_Generic, + Excp_SyncDataAbort, + Excp_CMUsageFault, + Excp_CMNMI, + Excp_CMDebugMonitor, + Excp_CMMemManage, + Excp_CMPendSV, + Excp_CMSysTick, + Excp_CMBusFault, + Excp_CMHardFault, + Excp_CMIRQn, + Excp_ThumbEECheckFail, +} ocsd_armv7_exception; + +/** @}*/ + +/** @}*/ + +#endif // ARM_TRC_PKT_TYPES_H_INCLUDED + +/* End of File opencsd/trc_pkt_types.h */ diff --git a/contrib/opencsd/decoder/include/pkt_printers/gen_elem_printer.h b/contrib/opencsd/decoder/include/pkt_printers/gen_elem_printer.h new file mode 100644 index 000000000000..ba3138a67f6e --- /dev/null +++ b/contrib/opencsd/decoder/include/pkt_printers/gen_elem_printer.h @@ -0,0 +1,95 @@ +/* + * \file gen_elem_printer.h + * \brief OpenCSD : Generic element printer class. + * + * \copyright Copyright (c) 2015, 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_GEN_ELEM_PRINTER_H_INCLUDED +#define ARM_GEN_ELEM_PRINTER_H_INCLUDED + +#include "opencsd.h" + +class TrcGenericElementPrinter : public ItemPrinter, public ITrcGenElemIn +{ +public: + TrcGenericElementPrinter(); + virtual ~TrcGenericElementPrinter() {}; + + virtual ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const OcsdTraceElement &elem); + + // funtionality to test wait / flush mechanism + void ackWait() { m_needWaitAck = false; }; + const bool needAckWait() const { return m_needWaitAck; }; + +protected: + bool m_needWaitAck; +}; + + +inline TrcGenericElementPrinter::TrcGenericElementPrinter() : + m_needWaitAck(false) +{ +} + +inline ocsd_datapath_resp_t TrcGenericElementPrinter::TraceElemIn(const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const OcsdTraceElement &elem) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + std::string elemStr; + std::ostringstream oss; + oss << "Idx:" << index_sop << "; ID:"<< std::hex << (uint32_t)trc_chan_id << "; "; + elem.toString(elemStr); + oss << elemStr << std::endl; + itemPrintLine(oss.str()); + + // funtionality to test wait / flush mechanism + if(m_needWaitAck) + { + oss.str(""); + oss << "WARNING: Generic Element Printer; New element without previous _WAIT acknowledged\n"; + itemPrintLine(oss.str()); + m_needWaitAck = false; + } + + if(getTestWaits()) + { + resp = OCSD_RESP_WAIT; // return _WAIT for the 1st N packets. + decTestWaits(); + m_needWaitAck = true; + } + return resp; +} + +#endif // ARM_GEN_ELEM_PRINTER_H_INCLUDED + +/* End of File gen_elem_printer.h */ diff --git a/contrib/opencsd/decoder/include/pkt_printers/item_printer.h b/contrib/opencsd/decoder/include/pkt_printers/item_printer.h new file mode 100644 index 000000000000..cc3ec37c291e --- /dev/null +++ b/contrib/opencsd/decoder/include/pkt_printers/item_printer.h @@ -0,0 +1,94 @@ +/* + * \file item_printer.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_ITEM_PRINTER_H_INCLUDED +#define ARM_ITEM_PRINTER_H_INCLUDED + +#include "opencsd.h" +#include + +class ItemPrinter +{ +public: + ItemPrinter(); + virtual ~ItemPrinter(); + + void setMessageLogger(ocsdMsgLogger *pMsgLogger) { m_pMsgLogger = pMsgLogger; }; + void itemPrintLine(const std::string &msg); + + // return wait for the first N packets - test the wait mechanism. + void setTestWaits(const int num_waits); + const int getTestWaits() const; + void decTestWaits(); + +protected: + ocsdMsgLogger *m_pMsgLogger; + int m_test_waits; +}; + +inline ItemPrinter::ItemPrinter() : + m_pMsgLogger(0), + m_test_waits(0) +{ +} + +inline ItemPrinter::~ItemPrinter() +{ + m_pMsgLogger = 0; +} + +inline void ItemPrinter::itemPrintLine(const std::string &msg) +{ + if(m_pMsgLogger) + m_pMsgLogger->LogMsg(msg); +} + +inline void ItemPrinter::setTestWaits(const int num_waits) +{ + m_test_waits = num_waits; +} + +inline const int ItemPrinter::getTestWaits() const +{ + return m_test_waits; +} + +inline void ItemPrinter::decTestWaits() +{ + m_test_waits--; +} + +#endif // ARM_ITEM_PRINTER_H_INCLUDED + +/* End of File item_printer.h */ diff --git a/contrib/opencsd/decoder/include/pkt_printers/pkt_printer_t.h b/contrib/opencsd/decoder/include/pkt_printers/pkt_printer_t.h new file mode 100644 index 000000000000..fc3ad2a78e57 --- /dev/null +++ b/contrib/opencsd/decoder/include/pkt_printers/pkt_printer_t.h @@ -0,0 +1,189 @@ +/* + * \file pkt_printer_t.h + * \brief OpenCSD : Test packet printer. + * + * \copyright Copyright (c) 2015, 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_PKT_PRINTER_T_H_INCLUDED +#define ARM_PKT_PRINTER_T_H_INCLUDED + +#include "opencsd.h" + +#include +#include +#include +#include + +template +class PacketPrinter : public IPktDataIn

, public IPktRawDataMon

, public ItemPrinter +{ +public: + PacketPrinter(const uint8_t trcID); + PacketPrinter(const uint8_t trcID, ocsdMsgLogger *pMsgLogger); + virtual ~PacketPrinter(); + + + virtual ocsd_datapath_resp_t PacketDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const P *p_packet_in); + + virtual void RawPacketDataMon( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const P *pkt, + const uint32_t size, + const uint8_t *p_data); + + +private: + void printIdx_ID(const ocsd_trc_index_t index_sop); + + uint8_t m_trcID; + bool m_bRawPrint; + std::ostringstream m_oss; + ocsd_datapath_resp_t m_last_resp; + +}; + +template PacketPrinter

::PacketPrinter(uint8_t trcID) : + m_trcID(trcID), + m_bRawPrint(false), + m_last_resp(OCSD_RESP_CONT) +{ +} + +template PacketPrinter

::PacketPrinter(const uint8_t trcID, ocsdMsgLogger *pMsgLogger) : + m_trcID(trcID), + m_bRawPrint(false), + m_last_resp(OCSD_RESP_CONT) +{ + setMessageLogger(pMsgLogger); +} + +template PacketPrinter

::~PacketPrinter() +{ +} + +template ocsd_datapath_resp_t PacketPrinter

::PacketDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const P *p_packet_in) +{ + std::string pktstr; + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // wait / flush test verification + if(!m_bRawPrint && (m_last_resp == OCSD_RESP_WAIT)) + { + // expect a flush or a complete reset after a wait. + if((op != OCSD_OP_FLUSH) || (op != OCSD_OP_RESET)) + { + m_oss <<"ID:"<< std::hex << (uint32_t)m_trcID << "\tERROR: FLUSH operation expected after wait on trace decode path\n"; + itemPrintLine(m_oss.str()); + m_oss.str(""); + return OCSD_RESP_FATAL_INVALID_OP; + } + } + + switch(op) + { + case OCSD_OP_DATA: + p_packet_in->toString(pktstr); + if(!m_bRawPrint) + printIdx_ID(index_sop); + m_oss << ";\t" << pktstr << std::endl; + + // test the wait/flush response mechnism + if(getTestWaits() && !m_bRawPrint) + { + decTestWaits(); + resp = OCSD_RESP_WAIT; + } + break; + + case OCSD_OP_EOT: + m_oss <<"ID:"<< std::hex << (uint32_t)m_trcID << "\tEND OF TRACE DATA\n"; + break; + + case OCSD_OP_FLUSH: + m_oss <<"ID:"<< std::hex << (uint32_t)m_trcID << "\tFLUSH operation on trace decode path\n"; + break; + + case OCSD_OP_RESET: + m_oss <<"ID:"<< std::hex << (uint32_t)m_trcID << "\tRESET operation on trace decode path\n"; + break; + } + + m_last_resp = resp; + itemPrintLine(m_oss.str()); + m_oss.str(""); + return resp; +} + +template void PacketPrinter

::RawPacketDataMon( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const P *pkt, + const uint32_t size, + const uint8_t *p_data) +{ + switch(op) + { + case OCSD_OP_DATA: + printIdx_ID(index_sop); + m_oss << "; ["; + if((size > 0) && (p_data != 0)) + { + uint32_t data = 0; + for(uint32_t i = 0; i < size; i++) + { + data = (uint32_t)(p_data[i] & 0xFF); + m_oss << "0x" << std::hex << std::setw(2) << std::setfill('0') << data << " "; + } + } + m_oss << "]"; + m_bRawPrint = true; + PacketDataIn(op,index_sop,pkt); + m_bRawPrint = false; + break; + + default: + PacketDataIn(op,index_sop,pkt); + break; + } + +} + +template void PacketPrinter

::printIdx_ID(const ocsd_trc_index_t index_sop) +{ + m_oss << "Idx:" << std::dec << index_sop << "; ID:"<< std::hex << (uint32_t)m_trcID; +} + +#endif // ARM_PKT_PRINTER_T_H_INCLUDED + +/* End of File pkt_printer_t.h */ diff --git a/contrib/opencsd/decoder/include/pkt_printers/raw_frame_printer.h b/contrib/opencsd/decoder/include/pkt_printers/raw_frame_printer.h new file mode 100644 index 000000000000..50caeb89ee00 --- /dev/null +++ b/contrib/opencsd/decoder/include/pkt_printers/raw_frame_printer.h @@ -0,0 +1,69 @@ +/* + * \file raw_frame_printer.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_RAW_FRAME_PRINTER_H_INCLUDED +#define ARM_RAW_FRAME_PRINTER_H_INCLUDED + +#include "opencsd.h" + +#include +#include + +class RawFramePrinter : public ITrcRawFrameIn, public ItemPrinter +{ +public: + RawFramePrinter() {}; + RawFramePrinter(ocsdMsgLogger *pMsgLogger); + virtual ~RawFramePrinter() {}; + + virtual ocsd_err_t TraceRawFrameIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const ocsd_rawframe_elem_t frame_element, + const int dataBlockSize, + const uint8_t *pDataBlock, + const uint8_t traceID); + +private: + void createDataString(const int dataSize, const uint8_t *pData, int bytesPerLine, std::string &dataStr); + +}; + +inline RawFramePrinter::RawFramePrinter(ocsdMsgLogger *pMsgLogger) +{ + setMessageLogger(pMsgLogger); +} + +#endif // ARM_RAW_FRAME_PRINTER_H_INCLUDED + +/* End of File raw_frame_printer.h */ diff --git a/contrib/opencsd/decoder/include/pkt_printers/trc_pkt_printers.h b/contrib/opencsd/decoder/include/pkt_printers/trc_pkt_printers.h new file mode 100644 index 000000000000..439701aea59e --- /dev/null +++ b/contrib/opencsd/decoder/include/pkt_printers/trc_pkt_printers.h @@ -0,0 +1,43 @@ +/* +* \file trc_pkt_printers.h +* \brief OpenCSD : Known protocol packet printers. +* +* \copyright Copyright (c) 2015, 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_TRC_PKT_PRINTERS_H_INCLUDED +#define ARM_TRC_PKT_PRINTERS_H_INCLUDED + +#include "pkt_printers/item_printer.h" +#include "pkt_printers/pkt_printer_t.h" +#include "pkt_printers/gen_elem_printer.h" +#include "pkt_printers/raw_frame_printer.h" + +#endif // ARM_TRC_PKT_PRINTERS_H_INCLUDED diff --git a/contrib/opencsd/decoder/include/pkt_printers/trc_print_fact.h b/contrib/opencsd/decoder/include/pkt_printers/trc_print_fact.h new file mode 100644 index 000000000000..73dd9dc29118 --- /dev/null +++ b/contrib/opencsd/decoder/include/pkt_printers/trc_print_fact.h @@ -0,0 +1,60 @@ +/* +* \file trc_print_fact.h +* \brief OpenCSD : Factory for protocol packet printers. +* +* \copyright Copyright (c) 2015, 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_TRC_PRINT_FACT_H_INCLUDED +#define ARM_TRC_PRINT_FACT_H_INCLUDED + +#include "opencsd.h" + +class PktPrinterFact +{ +public: + static ItemPrinter *createProtocolPrinter(std::vector &printer_list, ocsd_trace_protocol_t protocol, uint8_t elemID, ocsdMsgLogger *pMsgLogger = 0); + static RawFramePrinter *createRawFramePrinter(std::vector &printer_list, ocsdMsgLogger *pMsgLogger = 0); + static TrcGenericElementPrinter *createGenElemPrinter(std::vector &printer_list, ocsdMsgLogger *pMsgLogger = 0); + + static void destroyPrinter(std::vector &printer_list, ItemPrinter *pPrinter); + static void destroyAllPrinters(std::vector &printer_list); + static const int numPrinters(std::vector &printer_list); + +private: + static void SavePrinter(std::vector &printer_list, ItemPrinter *pPrinter, ocsdMsgLogger *pMsgLogger); + + PktPrinterFact() {}; + ~PktPrinterFact() {}; +}; + +#endif // ARM_TRC_PRINT_FACT_H_INCLUDED + +/* end of file trc_print_fact.h */ diff --git a/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp b/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp new file mode 100644 index 000000000000..1a2a74f899bc --- /dev/null +++ b/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp @@ -0,0 +1,572 @@ +/* + * \file ocsd_c_api.cpp + * \brief OpenCSD : "C" API libary implementation. + * + * \copyright Copyright (c) 2015, 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. + */ + +#include + +/* pull in the C++ decode library */ +#include "opencsd.h" + +/* C-API and wrapper objects */ +#include "opencsd/c_api/opencsd_c_api.h" +#include "ocsd_c_api_obj.h" + +/** MSVC2010 unwanted export workaround */ +#ifdef WIN32 +#if (_MSC_VER == 1600) +#include +namespace std { const nothrow_t nothrow = nothrow_t(); } +#endif +#endif + +/*******************************************************************************/ +/* C API internal helper function declarations */ +/*******************************************************************************/ + +static ocsd_err_t ocsd_create_pkt_sink_cb(ocsd_trace_protocol_t protocol, FnDefPktDataIn pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ); +static ocsd_err_t ocsd_create_pkt_mon_cb(ocsd_trace_protocol_t protocol, FnDefPktDataMon pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ); +static ocsd_err_t ocsd_check_and_add_mem_acc_mapper(const dcd_tree_handle_t handle, DecodeTree **ppDT); + +/*******************************************************************************/ +/* C library data - additional data on top of the C++ library objects */ +/*******************************************************************************/ + +/* keep a list of interface objects for a decode tree for later disposal */ +typedef struct _lib_dt_data_list { + std::vector cb_objs; + DefLogStrCBObj s_def_log_str_cb; +} lib_dt_data_list; + +/* map lists to handles */ +static std::map s_data_map; + +/*******************************************************************************/ +/* C API functions */ +/*******************************************************************************/ + +/** Get Library version. Return a 32 bit version in form MMMMnnpp - MMMM = major verison, nn = minor version, pp = patch version */ +OCSD_C_API uint32_t ocsd_get_version(void) +{ + return ocsdVersion::vers_num(); +} + +/** Get library version string */ +OCSD_C_API const char * ocsd_get_version_str(void) +{ + return ocsdVersion::vers_str(); +} + + +/*** Decode tree creation etc. */ + +OCSD_C_API dcd_tree_handle_t ocsd_create_dcd_tree(const ocsd_dcd_tree_src_t src_type, const uint32_t deformatterCfgFlags) +{ + dcd_tree_handle_t handle = C_API_INVALID_TREE_HANDLE; + handle = (dcd_tree_handle_t)DecodeTree::CreateDecodeTree(src_type,deformatterCfgFlags); + if(handle != C_API_INVALID_TREE_HANDLE) + { + lib_dt_data_list *pList = new (std::nothrow) lib_dt_data_list; + if(pList != 0) + { + s_data_map.insert(std::pair(handle,pList)); + } + else + { + ocsd_destroy_dcd_tree(handle); + handle = C_API_INVALID_TREE_HANDLE; + } + } + return handle; +} + +OCSD_C_API void ocsd_destroy_dcd_tree(const dcd_tree_handle_t handle) +{ + if(handle != C_API_INVALID_TREE_HANDLE) + { + GenTraceElemCBObj * pIf = (GenTraceElemCBObj *)(((DecodeTree *)handle)->getGenTraceElemOutI()); + if(pIf != 0) + delete pIf; + + /* need to clear any associated callback data. */ + std::map::iterator it; + it = s_data_map.find(handle); + if(it != s_data_map.end()) + { + std::vector::iterator itcb; + itcb = it->second->cb_objs.begin(); + while(itcb != it->second->cb_objs.end()) + { + delete *itcb; + itcb++; + } + it->second->cb_objs.clear(); + delete it->second; + s_data_map.erase(it); + } + DecodeTree::DestroyDecodeTree((DecodeTree *)handle); + } +} + +/*** Decode tree process data */ + +OCSD_C_API ocsd_datapath_resp_t ocsd_dt_process_data(const dcd_tree_handle_t handle, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_FATAL_NOT_INIT; + if(handle != C_API_INVALID_TREE_HANDLE) + resp = ((DecodeTree *)handle)->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed); + return resp; +} + +/*** Decode tree - decoder management */ + +OCSD_C_API ocsd_err_t ocsd_dt_create_decoder(const dcd_tree_handle_t handle, + const char *decoder_name, + const int create_flags, + const void *decoder_cfg, + unsigned char *pCSID + ) +{ + ocsd_err_t err = OCSD_OK; + DecodeTree *dt = (DecodeTree *)handle; + std::string dName = decoder_name; + IDecoderMngr *pDcdMngr; + err = OcsdLibDcdRegister::getDecoderRegister()->getDecoderMngrByName(dName,&pDcdMngr); + if(err != OCSD_OK) + return err; + + CSConfig *pConfig = 0; + err = pDcdMngr->createConfigFromDataStruct(&pConfig,decoder_cfg); + if(err != OCSD_OK) + return err; + + err = dt->createDecoder(dName,create_flags,pConfig); + if(err == OCSD_OK) + *pCSID = pConfig->getTraceID(); + delete pConfig; + return err; +} + +OCSD_C_API ocsd_err_t ocsd_dt_remove_decoder( const dcd_tree_handle_t handle, + const unsigned char CSID) +{ + return ((DecodeTree *)handle)->removeDecoder(CSID); +} + +OCSD_C_API ocsd_err_t ocsd_dt_attach_packet_callback( const dcd_tree_handle_t handle, + const unsigned char CSID, + const ocsd_c_api_cb_types callback_type, + void *p_fn_callback_data, + const void *p_context) +{ + ocsd_err_t err = OCSD_OK; + DecodeTree *pDT = static_cast(handle); + DecodeTreeElement *pElem = pDT->getDecoderElement(CSID); + if(pElem == 0) + return OCSD_ERR_INVALID_ID; // cannot find entry for that CSID + + ITrcTypedBase *pDataInSink = 0; // pointer to a sink callback object + switch(callback_type) + { + case OCSD_C_API_CB_PKT_SINK: + err = ocsd_create_pkt_sink_cb(pElem->getProtocol(),(FnDefPktDataIn)p_fn_callback_data,p_context,&pDataInSink); + if(err == OCSD_OK) + err = pElem->getDecoderMngr()->attachPktSink(pElem->getDecoderHandle(), pDataInSink); + break; + + case OCSD_C_API_CB_PKT_MON: + err = ocsd_create_pkt_mon_cb(pElem->getProtocol(),(FnDefPktDataMon)p_fn_callback_data,p_context,&pDataInSink); + if (err == OCSD_OK) + err = pElem->getDecoderMngr()->attachPktMonitor(pElem->getDecoderHandle(), pDataInSink); + break; + + default: + err = OCSD_ERR_INVALID_PARAM_VAL; + } + + if(err == OCSD_OK) + { + if (err == OCSD_OK) + { + // save object pointer for destruction later. + std::map::iterator it; + it = s_data_map.find(handle); + if (it != s_data_map.end()) + it->second->cb_objs.push_back(pDataInSink); + } + else + delete pDataInSink; + } + return err; +} + +/*** Decode tree set element output */ + +OCSD_C_API ocsd_err_t ocsd_dt_set_gen_elem_outfn(const dcd_tree_handle_t handle, FnTraceElemIn pFn, const void *p_context) +{ + + GenTraceElemCBObj * pCBObj = new (std::nothrow)GenTraceElemCBObj(pFn, p_context); + if(pCBObj) + { + ((DecodeTree *)handle)->setGenTraceElemOutI(pCBObj); + return OCSD_OK; + } + return OCSD_ERR_MEM; +} + + +/*** Default error logging */ + +OCSD_C_API ocsd_err_t ocsd_def_errlog_init(const ocsd_err_severity_t verbosity, const int create_output_logger) +{ + if(DecodeTree::getDefaultErrorLogger()->initErrorLogger(verbosity,(bool)(create_output_logger != 0))) + return OCSD_OK; + return OCSD_ERR_NOT_INIT; +} + +OCSD_C_API ocsd_err_t ocsd_def_errlog_config_output(const int output_flags, const char *log_file_name) +{ + ocsdMsgLogger *pLogger = DecodeTree::getDefaultErrorLogger()->getOutputLogger(); + if(pLogger) + { + pLogger->setLogOpts(output_flags & C_API_MSGLOGOUT_MASK); + if(log_file_name != NULL) + { + pLogger->setLogFileName(log_file_name); + } + return OCSD_OK; + } + return OCSD_ERR_NOT_INIT; +} + + +OCSD_C_API ocsd_err_t ocsd_def_errlog_set_strprint_cb(const dcd_tree_handle_t handle, void *p_context, FnDefLoggerPrintStrCB p_str_print_cb) +{ + ocsdMsgLogger *pLogger = DecodeTree::getDefaultErrorLogger()->getOutputLogger(); + if (pLogger) + { + std::map::iterator it; + it = s_data_map.find(handle); + if (it != s_data_map.end()) + { + DefLogStrCBObj *pCBObj = &(it->second->s_def_log_str_cb); + pCBObj->setCBFn(p_context, p_str_print_cb); + pLogger->setStrOutFn(pCBObj); + int logOpts = pLogger->getLogOpts(); + logOpts |= (int)(ocsdMsgLogger::OUT_STR_CB); + pLogger->setLogOpts(logOpts); + return OCSD_OK; + } + } + return OCSD_ERR_NOT_INIT; +} + +OCSD_C_API void ocsd_def_errlog_msgout(const char *msg) +{ + ocsdMsgLogger *pLogger = DecodeTree::getDefaultErrorLogger()->getOutputLogger(); + if(pLogger) + pLogger->LogMsg(msg); +} + +/*** Convert packet to string */ + +OCSD_C_API ocsd_err_t ocsd_pkt_str(const ocsd_trace_protocol_t pkt_protocol, const void *p_pkt, char *buffer, const int buffer_size) +{ + ocsd_err_t err = OCSD_OK; + if((buffer == NULL) || (buffer_size < 2)) + return OCSD_ERR_INVALID_PARAM_VAL; + + std::string pktStr = ""; + buffer[0] = 0; + + switch(pkt_protocol) + { + case OCSD_PROTOCOL_ETMV4I: + trcPrintElemToString(p_pkt, pktStr); + break; + + case OCSD_PROTOCOL_ETMV3: + trcPrintElemToString(p_pkt, pktStr); + break; + + case OCSD_PROTOCOL_STM: + trcPrintElemToString(p_pkt, pktStr); + break; + + case OCSD_PROTOCOL_PTM: + trcPrintElemToString(p_pkt, pktStr); + break; + + default: + if (OCSD_PROTOCOL_IS_CUSTOM(pkt_protocol)) + err = ocsd_cust_protocol_to_str(pkt_protocol, p_pkt, buffer, buffer_size); + else + err = OCSD_ERR_NO_PROTOCOL; + break; + } + + if(pktStr.size() > 0) + { + strncpy(buffer,pktStr.c_str(),buffer_size-1); + buffer[buffer_size-1] = 0; + } + return err; +} + +OCSD_C_API ocsd_err_t ocsd_gen_elem_str(const ocsd_generic_trace_elem *p_pkt, char *buffer, const int buffer_size) +{ + ocsd_err_t err = OCSD_OK; + if((buffer == NULL) || (buffer_size < 2)) + return OCSD_ERR_INVALID_PARAM_VAL; + std::string str; + trcPrintElemToString(p_pkt,str); + if(str.size() > 0) + { + strncpy(buffer,str.c_str(),buffer_size -1); + buffer[buffer_size-1] = 0; + } + return err; +} + +/*** Decode tree -- memory accessor control */ + +OCSD_C_API ocsd_err_t ocsd_dt_add_binfile_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const char *filepath) +{ + ocsd_err_t err = OCSD_OK; + DecodeTree *pDT; + err = ocsd_check_and_add_mem_acc_mapper(handle,&pDT); + if(err == OCSD_OK) + err = pDT->addBinFileMemAcc(address,mem_space,filepath); + return err; +} + +OCSD_C_API ocsd_err_t ocsd_dt_add_binfile_region_mem_acc(const dcd_tree_handle_t handle, const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const char *filepath) +{ + ocsd_err_t err = OCSD_OK; + DecodeTree *pDT; + err = ocsd_check_and_add_mem_acc_mapper(handle,&pDT); + if(err == OCSD_OK) + err = pDT->addBinFileRegionMemAcc(region_array,num_regions,mem_space,filepath); + return err; +} + +OCSD_C_API ocsd_err_t ocsd_dt_add_buffer_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length) +{ + ocsd_err_t err = OCSD_OK; + DecodeTree *pDT; + err = ocsd_check_and_add_mem_acc_mapper(handle,&pDT); + if(err == OCSD_OK) + err = pDT->addBufferMemAcc(address,mem_space,p_mem_buffer,mem_length); + return err; +} + +OCSD_C_API ocsd_err_t ocsd_dt_add_callback_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context) +{ + ocsd_err_t err = OCSD_OK; + DecodeTree *pDT; + err = ocsd_check_and_add_mem_acc_mapper(handle,&pDT); + if(err == OCSD_OK) + err = pDT->addCallbackMemAcc(st_address,en_address,mem_space,p_cb_func,p_context); + return err; +} + +OCSD_C_API ocsd_err_t ocsd_dt_remove_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t st_address, const ocsd_mem_space_acc_t mem_space) +{ + ocsd_err_t err = OCSD_OK; + + if(handle != C_API_INVALID_TREE_HANDLE) + { + DecodeTree *pDT = static_cast(handle); + err = pDT->removeMemAccByAddress(st_address,mem_space); + } + else + err = OCSD_ERR_INVALID_PARAM_VAL; + return err; +} + +OCSD_C_API void ocsd_tl_log_mapped_mem_ranges(const dcd_tree_handle_t handle) +{ + if(handle != C_API_INVALID_TREE_HANDLE) + { + DecodeTree *pDT = static_cast(handle); + pDT->logMappedRanges(); + } +} + +OCSD_C_API void ocsd_gen_elem_init(ocsd_generic_trace_elem *p_pkt, const ocsd_gen_trc_elem_t elem_type) +{ + p_pkt->elem_type = elem_type; + p_pkt->flag_bits = 0; + p_pkt->ptr_extended_data = 0; +} + +OCSD_C_API ocsd_err_t ocsd_dt_set_raw_frame_printer(const dcd_tree_handle_t handle, int flags) +{ + if (handle != C_API_INVALID_TREE_HANDLE) + return ((DecodeTree *)handle)->addRawFramePrinter(0, (uint32_t)flags); + return OCSD_ERR_NOT_INIT; +} + +OCSD_C_API ocsd_err_t ocsd_dt_set_gen_elem_printer(const dcd_tree_handle_t handle) +{ + if (handle != C_API_INVALID_TREE_HANDLE) + return ((DecodeTree *)handle)->addGenElemPrinter(0); + return OCSD_ERR_NOT_INIT; +} + +OCSD_C_API ocsd_err_t ocsd_dt_set_pkt_protocol_printer(const dcd_tree_handle_t handle, uint8_t cs_id, int monitor) +{ + ocsd_err_t err = OCSD_ERR_NOT_INIT; + if (handle != C_API_INVALID_TREE_HANDLE) + { + DecodeTree *p_tree = (DecodeTree *)handle; + err = p_tree->addPacketPrinter(cs_id, (bool)(monitor != 0), 0); + } + return err; +} + +/*******************************************************************************/ +/* C API local fns */ +/*******************************************************************************/ +static ocsd_err_t ocsd_create_pkt_sink_cb(ocsd_trace_protocol_t protocol, FnDefPktDataIn pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ) +{ + ocsd_err_t err = OCSD_OK; + *ppCBObj = 0; + + switch(protocol) + { + case OCSD_PROTOCOL_ETMV4I: + *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn,p_context); + break; + + case OCSD_PROTOCOL_ETMV3: + *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn,p_context); + break; + + case OCSD_PROTOCOL_PTM: + *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn,p_context); + break; + + case OCSD_PROTOCOL_STM: + *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn,p_context); + break; + + default: + if ((protocol >= OCSD_PROTOCOL_CUSTOM_0) && (protocol < OCSD_PROTOCOL_END)) + { + *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn, p_context); + } + else + err = OCSD_ERR_NO_PROTOCOL; + break; + } + + if((*ppCBObj == 0) && (err == OCSD_OK)) + err = OCSD_ERR_MEM; + + return err; +} + +static ocsd_err_t ocsd_create_pkt_mon_cb(ocsd_trace_protocol_t protocol, FnDefPktDataMon pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ) +{ + ocsd_err_t err = OCSD_OK; + *ppCBObj = 0; + + switch(protocol) + { + case OCSD_PROTOCOL_ETMV4I: + *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn,p_context); + break; + + case OCSD_PROTOCOL_ETMV3: + *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn,p_context); + break; + + case OCSD_PROTOCOL_PTM: + *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn,p_context); + break; + + case OCSD_PROTOCOL_STM: + *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn,p_context); + break; + + default: + if ((protocol >= OCSD_PROTOCOL_CUSTOM_0) && (protocol < OCSD_PROTOCOL_END)) + { + *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn, p_context); + } + else + err = OCSD_ERR_NO_PROTOCOL; + break; + } + + if((*ppCBObj == 0) && (err == OCSD_OK)) + err = OCSD_ERR_MEM; + + return err; +} + +static ocsd_err_t ocsd_check_and_add_mem_acc_mapper(const dcd_tree_handle_t handle, DecodeTree **ppDT) +{ + *ppDT = 0; + if(handle == C_API_INVALID_TREE_HANDLE) + return OCSD_ERR_INVALID_PARAM_VAL; + *ppDT = static_cast(handle); + if(!(*ppDT)->hasMemAccMapper()) + return (*ppDT)->createMemAccMapper(); + return OCSD_OK; +} + +/*******************************************************************************/ +/* C API Helper objects */ +/*******************************************************************************/ + +/****************** Generic trace element output callback function ************/ +GenTraceElemCBObj::GenTraceElemCBObj(FnTraceElemIn pCBFn, const void *p_context) : + m_c_api_cb_fn(pCBFn), + m_p_cb_context(p_context) +{ +} + +ocsd_datapath_resp_t GenTraceElemCBObj::TraceElemIn(const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const OcsdTraceElement &elem) +{ + return m_c_api_cb_fn(m_p_cb_context, index_sop, trc_chan_id, &elem); +} + +/* End of File ocsd_c_api.cpp */ diff --git a/contrib/opencsd/decoder/source/c_api/ocsd_c_api_custom_obj.cpp b/contrib/opencsd/decoder/source/c_api/ocsd_c_api_custom_obj.cpp new file mode 100644 index 000000000000..dbd0bd107698 --- /dev/null +++ b/contrib/opencsd/decoder/source/c_api/ocsd_c_api_custom_obj.cpp @@ -0,0 +1,431 @@ +/* + * \file ocsd_c_api_custom_obj.cpp + * \brief OpenCSD : + * + * \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. + */ + +/* pull in the C++ decode library */ +#include "opencsd.h" + +#include "opencsd/c_api/opencsd_c_api.h" +#include "ocsd_c_api_custom_obj.h" +#include "common/ocsd_lib_dcd_register.h" + +/***************** C-API functions ********************************/ + +/** register a custom decoder with the library */ +OCSD_C_API ocsd_err_t ocsd_register_custom_decoder(const char *name, ocsd_extern_dcd_fact_t *p_dcd_fact) +{ + ocsd_err_t err = OCSD_OK; + OcsdLibDcdRegister *pRegister = OcsdLibDcdRegister::getDecoderRegister(); + + // check not already registered + if(pRegister->isRegisteredDecoder(name)) + return OCSD_ERR_DCDREG_NAME_REPEAT; + + // validate the factory interface structure + if((p_dcd_fact->createDecoder == 0) || + (p_dcd_fact->destroyDecoder == 0) || + (p_dcd_fact->csidFromConfig == 0) + ) + return OCSD_ERR_INVALID_PARAM_VAL; + + // create a wrapper. + CustomDcdMngrWrapper *pWrapper = new (std::nothrow) CustomDcdMngrWrapper(); + if(pRegister == 0) + return OCSD_ERR_MEM; + + p_dcd_fact->protocol_id = OcsdLibDcdRegister::getNextCustomProtocolID(); + if(p_dcd_fact->protocol_id < OCSD_PROTOCOL_END) + { + // fill out the wrapper and register it + pWrapper->setAPIDcdFact(p_dcd_fact); + err = pRegister->registerDecoderTypeByName(name,pWrapper); + if(err != OCSD_OK) + OcsdLibDcdRegister::releaseLastCustomProtocolID(); + } + else + err = OCSD_ERR_DCDREG_TOOMANY; // too many decoders + + if(err != OCSD_OK) + delete pWrapper; + + return err; +} + +OCSD_C_API ocsd_err_t ocsd_deregister_decoders() +{ + // destroys all builtin and custom decoders & library registration object. + OcsdLibDcdRegister::deregisterAllDecoders(); + return OCSD_OK; +} + +OCSD_C_API ocsd_err_t ocsd_cust_protocol_to_str(const ocsd_trace_protocol_t pkt_protocol, const void *trc_pkt, char *buffer, const int buflen) +{ + OcsdLibDcdRegister *pRegister = OcsdLibDcdRegister::getDecoderRegister(); + IDecoderMngr *p_mngr = 0; + if (OCSD_PROTOCOL_IS_CUSTOM(pkt_protocol) && (pRegister->getDecoderMngrByType(pkt_protocol, &p_mngr) == OCSD_OK)) + { + CustomDcdMngrWrapper *pWrapper = static_cast(p_mngr); + pWrapper->pktToString(trc_pkt, buffer, buflen); + return OCSD_OK; + } + return OCSD_ERR_NO_PROTOCOL; +} + +/***************** Decode Manager Wrapper *****************************/ + +CustomDcdMngrWrapper::CustomDcdMngrWrapper() +{ + m_dcd_fact.protocol_id = OCSD_PROTOCOL_END; +} + + + // set the C-API decoder factory interface +void CustomDcdMngrWrapper::setAPIDcdFact(ocsd_extern_dcd_fact_t *p_dcd_fact) +{ + m_dcd_fact = *p_dcd_fact; +} + +// create and destroy decoders +ocsd_err_t CustomDcdMngrWrapper::createDecoder(const int create_flags, const int instID, const CSConfig *p_config, TraceComponent **ppComponent) +{ + ocsd_err_t err = OCSD_OK; + if(m_dcd_fact.protocol_id == OCSD_PROTOCOL_END) + return OCSD_ERR_NOT_INIT; + + CustomDecoderWrapper *pComp = new (std::nothrow) CustomDecoderWrapper(); + *ppComponent = pComp; + if (pComp == 0) + return OCSD_ERR_MEM; + + ocsd_extern_dcd_cb_fns lib_callbacks; + CustomDecoderWrapper::SetCallbacks(lib_callbacks); + lib_callbacks.lib_context = pComp; + lib_callbacks.packetCBFlags = 0; + + ocsd_extern_dcd_inst_t *pDecodeInst = pComp->getDecoderInstInfo(); + + err = m_dcd_fact.createDecoder( create_flags, + ((CustomConfigWrapper *)p_config)->getConfig(), + &lib_callbacks, + pDecodeInst); + + if (err == OCSD_OK) + { + // validate the decoder + if ((pDecodeInst->fn_data_in == 0) || + (pDecodeInst->fn_update_pkt_mon == 0) || + (pDecodeInst->cs_id == 0) || + (pDecodeInst->decoder_handle == 0) || + (pDecodeInst->p_decoder_name == 0) + ) + { + err = OCSD_ERR_INVALID_PARAM_VAL; + } + } + + if (err != OCSD_OK) + delete pComp; + else + pComp->updateNameFromDcdInst(); + return err; +} + +ocsd_err_t CustomDcdMngrWrapper::destroyDecoder(TraceComponent *pComponent) +{ + CustomDecoderWrapper *pCustWrap = dynamic_cast(pComponent); + if(m_dcd_fact.protocol_id != OCSD_PROTOCOL_END) + m_dcd_fact.destroyDecoder(pCustWrap->getDecoderInstInfo()->decoder_handle); + delete pCustWrap; + return OCSD_OK; +} + +const ocsd_trace_protocol_t CustomDcdMngrWrapper::getProtocolType() const +{ + return m_dcd_fact.protocol_id; +} + +ocsd_err_t CustomDcdMngrWrapper::createConfigFromDataStruct(CSConfig **pConfigBase, const void *pDataStruct) +{ + ocsd_err_t err = OCSD_OK; + CustomConfigWrapper *pConfig = new (std::nothrow) CustomConfigWrapper(pDataStruct); + if(!pConfig) + return OCSD_ERR_MEM; + + if(m_dcd_fact.csidFromConfig == 0) + return OCSD_ERR_NOT_INIT; + + unsigned char csid; + err = m_dcd_fact.csidFromConfig(pDataStruct,&csid); + if(err == OCSD_OK) + { + pConfig->setCSID(csid); + *pConfigBase = pConfig; + } + return err; +} + +ocsd_err_t CustomDcdMngrWrapper::getDataInputI(TraceComponent *pComponent, ITrcDataIn **ppDataIn) +{ + CustomDecoderWrapper *pDecoder = dynamic_cast(pComponent); + if(pDecoder == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + + *ppDataIn = pDecoder; + return OCSD_OK; +} + +// component connections +// all +ocsd_err_t CustomDcdMngrWrapper::attachErrorLogger(TraceComponent *pComponent, ITraceErrorLog *pIErrorLog) +{ + CustomDecoderWrapper *pDecoder = dynamic_cast(pComponent); + if (pDecoder == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + pDecoder->getErrorLogAttachPt()->replace_first(pIErrorLog); + return OCSD_OK; +} + +// full decoder +ocsd_err_t CustomDcdMngrWrapper::attachInstrDecoder(TraceComponent *pComponent, IInstrDecode *pIInstrDec) +{ + CustomDecoderWrapper *pDecoder = dynamic_cast(pComponent); + if(pDecoder == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + pDecoder->attachInstrDecI(pIInstrDec); + return OCSD_OK; +} + +ocsd_err_t CustomDcdMngrWrapper::attachMemAccessor(TraceComponent *pComponent, ITargetMemAccess *pMemAccessor) +{ + CustomDecoderWrapper *pDecoder = dynamic_cast(pComponent); + if(pDecoder == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + pDecoder->attachMemAccI(pMemAccessor); + return OCSD_OK; +} + +ocsd_err_t CustomDcdMngrWrapper::attachOutputSink(TraceComponent *pComponent, ITrcGenElemIn *pOutSink) +{ + CustomDecoderWrapper *pDecoder = dynamic_cast(pComponent); + if(pDecoder == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + pDecoder->attachGenElemI(pOutSink); + return OCSD_OK; +} + +// pkt processor only +ocsd_err_t CustomDcdMngrWrapper::attachPktMonitor(TraceComponent *pComponent, ITrcTypedBase *pPktRawDataMon) +{ + CustomDecoderWrapper *pDecoder = dynamic_cast(pComponent); + if(pDecoder == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + IPktRawDataMon *pIF = 0; + if (pPktRawDataMon) + { + pIF = dynamic_cast *>(pPktRawDataMon); + if (!pIF) + return OCSD_ERR_INVALID_PARAM_TYPE; + } + pDecoder->attachPtkMonI(pIF); + return OCSD_OK; +} + +ocsd_err_t CustomDcdMngrWrapper::attachPktIndexer(TraceComponent *pComponent, ITrcTypedBase *pPktIndexer) +{ + // indexers for external custom will also be external and custom. + return OCSD_ERR_DCD_INTERFACE_UNUSED; +} + +ocsd_err_t CustomDcdMngrWrapper::attachPktSink(TraceComponent *pComponent, ITrcTypedBase *pPktDataInSink) +{ + CustomDecoderWrapper *pDecoder = dynamic_cast(pComponent); + if(pDecoder == 0) + return OCSD_ERR_INVALID_PARAM_TYPE; + IPktDataIn *pIF = 0; + if (pPktDataInSink) + { + pIF = dynamic_cast *>(pPktDataInSink); + if(!pIF) + return OCSD_ERR_INVALID_PARAM_TYPE; + } + pDecoder->attachPtkSinkI(pIF); + return OCSD_OK; +} + +void CustomDcdMngrWrapper::pktToString(const void *pkt, char *pStrBuffer, int bufSize) +{ + if (m_dcd_fact.pktToString) + m_dcd_fact.pktToString(pkt, pStrBuffer, bufSize); + else + snprintf(pStrBuffer, bufSize, "CUSTOM_PKT[]: print unsupported; protocol(%d).",m_dcd_fact.protocol_id); +} + +/************************** Decoder instance wrapper **************************************/ + +/* callback functions */ +ocsd_datapath_resp_t GenElemOpCB( const void *lib_context, + const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const ocsd_generic_trace_elem *elem) +{ + if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pGenElemIn) + return ((CustomDecoderWrapper *)lib_context)->m_pGenElemIn->TraceElemIn(index_sop,trc_chan_id,*(OcsdTraceElement *)elem); + return OCSD_RESP_FATAL_NOT_INIT; +} + +void LogErrorCB(const void *lib_context, const ocsd_err_severity_t filter_level, const ocsd_err_t code, const ocsd_trc_index_t idx, const uint8_t chan_id, const char *pMsg) +{ + if (lib_context) + { + if(pMsg) + ((CustomDecoderWrapper *)lib_context)->LogError(ocsdError(filter_level, code, idx, chan_id, std::string(pMsg))); + else + ((CustomDecoderWrapper *)lib_context)->LogError(ocsdError(filter_level, code, idx, chan_id)); + } +} + +void LogMsgCB(const void *lib_context, const ocsd_err_severity_t filter_level, const char *msg) +{ + if (lib_context && msg) + ((CustomDecoderWrapper *)lib_context)->LogMessage(filter_level, std::string(msg)); +} + +ocsd_err_t DecodeArmInstCB(const void *lib_context, ocsd_instr_info *instr_info) +{ + if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pIInstrDec) + return ((CustomDecoderWrapper *)lib_context)->m_pIInstrDec->DecodeInstruction(instr_info); + return OCSD_ERR_ATTACH_INVALID_PARAM; +} + +ocsd_err_t MemAccessCB(const void *lib_context, + const ocsd_vaddr_t address, + const uint8_t cs_trace_id, + const ocsd_mem_space_acc_t mem_space, + uint32_t *num_bytes, + uint8_t *p_buffer) +{ + if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pMemAccessor) + return ((CustomDecoderWrapper *)lib_context)->m_pMemAccessor->ReadTargetMemory(address, cs_trace_id, mem_space, num_bytes, p_buffer); + return OCSD_ERR_INVALID_PARAM_VAL; +} + +void PktMonCB(const void *lib_context, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *pkt, + const uint32_t size, + const uint8_t *p_data) +{ + if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pPktMon) + ((CustomDecoderWrapper *)lib_context)->m_pPktMon->RawPacketDataMon(op, index_sop, pkt, size, p_data); +} + +ocsd_datapath_resp_t PktDataSinkCB(const void *lib_context, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *pkt) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pPktIn) + resp = ((CustomDecoderWrapper *)lib_context)->m_pPktIn->PacketDataIn(op, index_sop, pkt); + return resp; +} + + + +/** decoder instance object */ +CustomDecoderWrapper::CustomDecoderWrapper() : TraceComponent("extern_wrapper"), + m_pGenElemIn(0), + m_pIInstrDec(0), + m_pMemAccessor(0), + m_pPktMon(0), + m_pPktIn(0) +{ +} + +CustomDecoderWrapper::~CustomDecoderWrapper() +{ +} + +ocsd_datapath_resp_t CustomDecoderWrapper::TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + if(m_decoder_inst.fn_data_in) + return m_decoder_inst.fn_data_in( m_decoder_inst.decoder_handle, + op, + index, + dataBlockSize, + pDataBlock, + numBytesProcessed); + return OCSD_RESP_FATAL_NOT_INIT; +} + +void CustomDecoderWrapper::attachPtkMonI(IPktRawDataMon* pIF) +{ + m_pPktMon = pIF; + int flags = (m_pPktMon ? OCSD_CUST_DCD_PKT_CB_USE_MON : 0) | (m_pPktIn ? OCSD_CUST_DCD_PKT_CB_USE_SINK : 0); + m_decoder_inst.fn_update_pkt_mon(m_decoder_inst.decoder_handle, flags); +} + +void CustomDecoderWrapper::attachPtkSinkI(IPktDataIn* pIF) +{ + m_pPktIn = pIF; + int flags = (m_pPktMon ? OCSD_CUST_DCD_PKT_CB_USE_MON : 0) | (m_pPktIn ? OCSD_CUST_DCD_PKT_CB_USE_SINK : 0); + m_decoder_inst.fn_update_pkt_mon(m_decoder_inst.decoder_handle, flags); +} + +void CustomDecoderWrapper::updateNameFromDcdInst() +{ + // create a unique component name from the decoder name + cs-id. + std::string name_combined = m_decoder_inst.p_decoder_name; + char num_buffer[32]; + sprintf(num_buffer, "_%04d", m_decoder_inst.cs_id); + name_combined += (std::string)num_buffer; + setComponentName(name_combined); +} + +void CustomDecoderWrapper::SetCallbacks(ocsd_extern_dcd_cb_fns & callbacks) +{ + callbacks.fn_arm_instruction_decode = DecodeArmInstCB; + callbacks.fn_gen_elem_out = GenElemOpCB; + callbacks.fn_log_error = LogErrorCB; + callbacks.fn_log_msg = LogMsgCB; + callbacks.fn_memory_access = MemAccessCB; + callbacks.fn_packet_data_sink = PktDataSinkCB; + callbacks.fn_packet_mon = PktMonCB; +} + +/* End of File ocsd_c_api_custom_obj.cpp */ diff --git a/contrib/opencsd/decoder/source/c_api/ocsd_c_api_custom_obj.h b/contrib/opencsd/decoder/source/c_api/ocsd_c_api_custom_obj.h new file mode 100644 index 000000000000..d4845bdf709d --- /dev/null +++ b/contrib/opencsd/decoder/source/c_api/ocsd_c_api_custom_obj.h @@ -0,0 +1,189 @@ +/* + * \file ocsd_c_api_custom_obj.h + * \brief OpenCSD : + * + * \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_C_API_CUSTOM_OBJ_H_INCLUDED +#define ARM_OCSD_C_API_CUSTOM_OBJ_H_INCLUDED + +#include "opencsd/c_api/ocsd_c_api_custom.h" +#include "common/ocsd_dcd_mngr_i.h" + +/***** Decoder manager interface ******************************/ +class CustomDcdMngrWrapper : public IDecoderMngr +{ +public: + CustomDcdMngrWrapper(); + virtual ~CustomDcdMngrWrapper() {}; + + // set the C-API decoder factory interface. + void setAPIDcdFact(ocsd_extern_dcd_fact_t *p_dcd_fact); + +// create and destroy decoders + virtual ocsd_err_t createDecoder(const int create_flags, const int instID, const CSConfig *p_config, TraceComponent **ppComponent); + virtual ocsd_err_t destroyDecoder(TraceComponent *pComponent); + + //! Get the built in protocol type ID managed by this instance - extern for custom decoders + virtual const ocsd_trace_protocol_t getProtocolType() const; + +// connect decoders to other components - (replace current / 0 pointer value to detach ); +// compatible with all decoders + //!attach error logger to ptk-processor, or both of pkt processor and pkt decoder pair + virtual ocsd_err_t attachErrorLogger(TraceComponent *pComponent, ITraceErrorLog *pIErrorLog); + +// pkt decoder only + //! attach instruction decoder to pkt decoder + virtual ocsd_err_t attachInstrDecoder(TraceComponent *pComponent, IInstrDecode *pIInstrDec); + + //! attach memory accessor to pkt decoder + virtual ocsd_err_t attachMemAccessor(TraceComponent *pComponent, ITargetMemAccess *pMemAccessor); + + //! attach generic output interface to pkt decoder + virtual ocsd_err_t attachOutputSink(TraceComponent *pComponent, ITrcGenElemIn *pOutSink); + +// pkt processor only + //! attach a raw packet monitor to pkt processor (solo pkt processor, or pkt processor part of pair) + virtual ocsd_err_t attachPktMonitor(TraceComponent *pComponent, ITrcTypedBase *pPktRawDataMon); + + //! attach a packet indexer to pkt processor (solo pkt processor, or pkt processor part of pair) + virtual ocsd_err_t attachPktIndexer(TraceComponent *pComponent, ITrcTypedBase *pPktIndexer); + + //! attach a packet data sink to pkt processor output (solo pkt processor only - instead of decoder when pkt processor only created.) + virtual ocsd_err_t attachPktSink(TraceComponent *pComponent, ITrcTypedBase *pPktDataInSink); + +// data input connection interface + //! get raw data input interface from packet processor + virtual ocsd_err_t getDataInputI(TraceComponent *pComponent, ITrcDataIn **ppDataIn); + +// create configuration from data structure + virtual ocsd_err_t createConfigFromDataStruct(CSConfig **pConfigBase, const void *pDataStruct); + +// custom packet to string interface. + void pktToString(const void *pkt, char *pStrBuffer, int bufSize); + +private: + + ocsd_extern_dcd_fact_t m_dcd_fact; +}; + +/**** Decoder instance wrapper */ +class CustomDecoderWrapper : public TraceComponent, public ITrcDataIn +{ +public: + CustomDecoderWrapper(); + virtual ~CustomDecoderWrapper(); + ocsd_extern_dcd_inst_t *getDecoderInstInfo() { return &m_decoder_inst; } + + virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + + void attachGenElemI(ITrcGenElemIn *pIF) { m_pGenElemIn = pIF; }; + void attachInstrDecI(IInstrDecode *pIF) { m_pIInstrDec = pIF; }; + void attachMemAccI(ITargetMemAccess *pIF) { m_pMemAccessor = pIF; }; + + void attachPtkMonI(IPktRawDataMon *pIF); + void attachPtkSinkI(IPktDataIn *pIF); + + void updateNameFromDcdInst(); + + static void SetCallbacks(ocsd_extern_dcd_cb_fns &callbacks); + +private: + // declare the callback functions as friend functions. + friend ocsd_datapath_resp_t GenElemOpCB( const void *lib_context, + const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const ocsd_generic_trace_elem *elem); + + friend void LogErrorCB( const void *lib_context, + const ocsd_err_severity_t filter_level, + const ocsd_err_t code, + const ocsd_trc_index_t idx, + const uint8_t chan_id, + const char *pMsg); + + friend void LogMsgCB(const void *lib_context, + const ocsd_err_severity_t filter_level, + const char *msg); + + friend ocsd_err_t DecodeArmInstCB(const void *lib_context, ocsd_instr_info *instr_info); + + friend ocsd_err_t MemAccessCB(const void *lib_context, + const ocsd_vaddr_t address, + const uint8_t cs_trace_id, + const ocsd_mem_space_acc_t mem_space, + uint32_t *num_bytes, + uint8_t *p_buffer); + + friend void PktMonCB(const void *lib_context, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *pkt, + const uint32_t size, + const uint8_t *p_data); + + friend ocsd_datapath_resp_t PktDataSinkCB(const void *lib_context, + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *pkt); + +private: + ITrcGenElemIn *m_pGenElemIn; //!< generic element sink interface - output from decoder fed to common sink. + IInstrDecode *m_pIInstrDec; //!< arm instruction decode interface - decoder may want to use this. + ITargetMemAccess *m_pMemAccessor; //!< system memory accessor insterface - decoder may want to use this. + IPktRawDataMon *m_pPktMon; //!< interface to packet monitor (full or packet only decode). + IPktDataIn *m_pPktIn; //!< interface to packet sink (decode packets only). + + ocsd_extern_dcd_inst_t m_decoder_inst; +}; + +/**** Decoder configuration wrapper - implements CSConfig base class interface ***/ +class CustomConfigWrapper : public CSConfig +{ +public: + CustomConfigWrapper(const void *p_config) : m_p_config(p_config), m_CSID(0) {}; + virtual ~CustomConfigWrapper() {}; + virtual const uint8_t getTraceID() const { return m_CSID; }; + void setCSID(const uint8_t CSID) { m_CSID = CSID; }; + const void *getConfig() { return m_p_config; }; +private: + const void *m_p_config; + uint8_t m_CSID; +}; + +#endif // ARM_OCSD_C_API_CUSTOM_OBJ_H_INCLUDED + +/* End of File ocsd_c_api_custom_obj.h */ diff --git a/contrib/opencsd/decoder/source/c_api/ocsd_c_api_obj.h b/contrib/opencsd/decoder/source/c_api/ocsd_c_api_obj.h new file mode 100644 index 000000000000..0476ac67177c --- /dev/null +++ b/contrib/opencsd/decoder/source/c_api/ocsd_c_api_obj.h @@ -0,0 +1,182 @@ +/* + * \file ocsd_c_api_obj.h + * \brief OpenCSD : C API callback objects. + * + * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + */ + +#ifndef ARM_OCSD_C_API_OBJ_H_INCLUDED +#define ARM_OCSD_C_API_OBJ_H_INCLUDED + +#include "opencsd/c_api/ocsd_c_api_types.h" +#include "interfaces/trc_gen_elem_in_i.h" +#include "common/ocsd_msg_logger.h" + +class TraceElemCBBase +{ +public: + TraceElemCBBase() {}; + virtual ~TraceElemCBBase() {}; +}; + +class GenTraceElemCBObj : public ITrcGenElemIn, public TraceElemCBBase +{ +public: + GenTraceElemCBObj(FnTraceElemIn pCBFn, const void *p_context); + virtual ~GenTraceElemCBObj() {}; + + virtual ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop, + const uint8_t trc_chan_id, + const OcsdTraceElement &elem); + +private: + FnTraceElemIn m_c_api_cb_fn; + const void *m_p_cb_context; +}; + + + +template +class PktCBObj : public IPktDataIn +{ +public: + PktCBObj( FnDefPktDataIn pCBFunc, const void *p_context) + { + m_c_api_cb_fn = pCBFunc; + m_p_context = p_context; + }; + + virtual ~PktCBObj() {}; + + virtual ocsd_datapath_resp_t PacketDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const TrcPkt *p_packet_in) + { + const void *c_pkt_struct = 0; + if(op == OCSD_OP_DATA) + c_pkt_struct = p_packet_in->c_pkt(); // always output the c struct packet + return m_c_api_cb_fn(m_p_context,op,index_sop,c_pkt_struct); + }; + +private: + FnDefPktDataIn m_c_api_cb_fn; + const void *m_p_context; +}; + +// void specialisation for custom decoders that pass packets as const void * pointers +template<> +class PktCBObj : public IPktDataIn +{ +public: + PktCBObj(FnDefPktDataIn pCBFunc, const void *p_context) + { + m_c_api_cb_fn = pCBFunc; + m_p_context = p_context; + }; + + virtual ~PktCBObj() {}; + + virtual ocsd_datapath_resp_t PacketDataIn(const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *p_packet_in) + { + return m_c_api_cb_fn(m_p_context, op, index_sop, p_packet_in); + }; + +private: + FnDefPktDataIn m_c_api_cb_fn; + const void *m_p_context; +}; + + +template +class PktMonCBObj : public IPktRawDataMon +{ +public: + PktMonCBObj( FnDefPktDataMon pCBFunc, const void *p_context) + { + m_c_api_cb_fn = pCBFunc; + m_p_context = p_context; + }; + + virtual ~PktMonCBObj() {}; + + virtual void RawPacketDataMon( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const TrcPkt *p_packet_in, + const uint32_t size, + const uint8_t *p_data) + { + const void *c_pkt_struct = 0; + if(op == OCSD_OP_DATA) + c_pkt_struct = p_packet_in->c_pkt(); // always output the c struct packet + m_c_api_cb_fn(m_p_context,op,index_sop,c_pkt_struct,size,p_data); + }; + +private: + FnDefPktDataMon m_c_api_cb_fn; + const void *m_p_context; +}; + +// void specialisation for custom decoders that pass packets as const void * pointers +template<> +class PktMonCBObj : public IPktRawDataMon +{ +public: + PktMonCBObj(FnDefPktDataMon pCBFunc, const void *p_context) + { + m_c_api_cb_fn = pCBFunc; + m_p_context = p_context; + }; + + virtual ~PktMonCBObj() {}; + virtual void RawPacketDataMon(const ocsd_datapath_op_t op, + const ocsd_trc_index_t index_sop, + const void *p_packet_in, + const uint32_t size, + const uint8_t *p_data) + { + m_c_api_cb_fn(m_p_context, op, index_sop, p_packet_in, size, p_data); + }; + +private: + FnDefPktDataMon m_c_api_cb_fn; + const void *m_p_context; +}; + +/* handler for default string print CB object */ +class DefLogStrCBObj : public ocsdMsgLogStrOutI +{ +public: + DefLogStrCBObj() + { + m_c_api_cb_fn = 0; + m_p_context = 0; + }; + + virtual ~DefLogStrCBObj() + { + m_c_api_cb_fn = 0; + m_p_context = 0; + }; + + void setCBFn(const void *p_context, FnDefLoggerPrintStrCB pCBFn) + { + m_c_api_cb_fn = pCBFn; + m_p_context = p_context; + }; + + virtual void printOutStr(const std::string &outStr) + { + if(m_c_api_cb_fn) + m_c_api_cb_fn(m_p_context, outStr.c_str(), outStr.length()); + } + +private: + FnDefLoggerPrintStrCB m_c_api_cb_fn; + const void *m_p_context; +}; + +#endif // ARM_OCSD_C_API_OBJ_H_INCLUDED + +/* End of File ocsd_c_api_obj.h */ diff --git a/contrib/opencsd/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp b/contrib/opencsd/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp new file mode 100644 index 000000000000..f2556e4dfef4 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp @@ -0,0 +1,65 @@ +/* + * \file trc_cmp_cfg_etmv3.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h" + +EtmV3Config::EtmV3Config() +{ + // defaults set ETMv3.4, V7A, instruction only. + m_cfg.arch_ver = ARCH_V7; + m_cfg.core_prof = profile_CortexA; + m_cfg.reg_ccer = 0; + m_cfg.reg_idr = 0x4100F240; // default trace IDR value + m_cfg.reg_ctrl = 0; +} + +EtmV3Config::EtmV3Config(const ocsd_etmv3_cfg *cfg_regs) +{ + m_cfg = *cfg_regs; +} + +EtmV3Config::EtmTraceMode const EtmV3Config::GetTraceMode() const +{ + int mode = 0 + ( isDataValTrace() ? 1 : 0 ) + (isDataAddrTrace() ? 2 : 0) + (isInstrTrace() ? 0 : 3); + return (EtmTraceMode)mode; +} + +const int EtmV3Config::CtxtIDBytes() const +{ + int ctxtIdsizes[] = { 0, 1, 2, 4 }; + return ctxtIdsizes[(m_cfg.reg_ctrl >> 14) & 0x3]; +} + +/* End of File trc_cmp_cfg_etmv3.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp b/contrib/opencsd/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp new file mode 100644 index 000000000000..bd7cb60b5b63 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp @@ -0,0 +1,670 @@ +/*! + * \file trc_pkt_decode_etmv3.cpp + * \brief OpenCSD : ETMv3 trace packet decode. + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/etmv3/trc_pkt_decode_etmv3.h" + +#define DCD_NAME "DCD_ETMV3" + +TrcPktDecodeEtmV3::TrcPktDecodeEtmV3() : + TrcPktDecodeBase(DCD_NAME) +{ + initDecoder(); +} + +TrcPktDecodeEtmV3::TrcPktDecodeEtmV3(int instIDNum) : + TrcPktDecodeBase(DCD_NAME, instIDNum) +{ + initDecoder(); +} + +TrcPktDecodeEtmV3::~TrcPktDecodeEtmV3() +{ +} + + +/* implementation packet decoding interface */ +ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bPktDone = false; + + if(!m_config) + return OCSD_RESP_FATAL_NOT_INIT; + + // iterate round the state machine, waiting for sync, then decoding packets. + while(!bPktDone) + { + switch(m_curr_state) + { + case NO_SYNC: + // output the initial not synced packet to the sink + resp = sendUnsyncPacket(); + m_curr_state = WAIT_ASYNC; // immediate wait for ASync and actually check out the packet + break; + + case WAIT_ASYNC: + // if async, wait for ISync, but this packet done. + if(m_curr_packet_in->getType() == ETM3_PKT_A_SYNC) + m_curr_state = WAIT_ISYNC; + bPktDone = true; + break; + + case WAIT_ISYNC: + m_bWaitISync = true; // we are waiting for ISync + if((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC) || + (m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE)) + { + // process the ISync immediately as the first ISync seen. + resp = processISync((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE),true); + m_curr_state = SEND_PKTS; + m_bWaitISync = false; + } + // something like TS, CC, PHDR+CC, which after ASYNC may be valid prior to ISync + else if(preISyncValid(m_curr_packet_in->getType())) + { + // decode anything that might be valid - send will be set automatically + resp = decodePacket(bPktDone); + } + else + bPktDone = true; + break; + + case DECODE_PKTS: + resp = decodePacket(bPktDone); + break; + + case SEND_PKTS: + resp = m_outputElemList.sendElements(); + if(OCSD_DATA_RESP_IS_CONT(resp)) + m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS; + bPktDone = true; + break; + + default: + bPktDone = true; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,"Unknown Decoder State")); + resetDecoder(); // mark decoder as unsynced - dump any current state. + resp = OCSD_RESP_FATAL_SYS_ERR; + break; + } + } + + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + OcsdTraceElement *pElem = 0; + try { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EO_TRACE); + m_outputElemList.commitAllPendElem(); + m_curr_state = SEND_PKTS; + resp = m_outputElemList.sendElements(); + if(OCSD_DATA_RESP_IS_CONT(resp)) + m_curr_state = DECODE_PKTS; + } + catch(ocsdError &err) + { + LogError(err); + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::onReset() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + resetDecoder(); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::onFlush() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + if(m_curr_state == SEND_PKTS) + { + resp = m_outputElemList.sendElements(); + if(OCSD_DATA_RESP_IS_CONT(resp)) + m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS; + } + return resp; +} + +ocsd_err_t TrcPktDecodeEtmV3::onProtocolConfig() +{ + ocsd_err_t err = OCSD_OK; + if(m_config) + { + // set some static config elements + m_CSID = m_config->getTraceID(); + + // check config compatible with current decoder support level. + // at present no data trace; + if(m_config->GetTraceMode() != EtmV3Config::TM_INSTR_ONLY) + { + err = OCSD_ERR_HW_CFG_UNSUPP; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv3 trace decoder : data trace decode not yet supported")); + } + + // need to set up core profile info in follower + ocsd_arch_profile_t arch_profile; + arch_profile.arch = m_config->getArchVersion(); + arch_profile.profile = m_config->getCoreProfile(); + m_code_follower.setArchProfile(arch_profile); + m_code_follower.setMemSpaceCSID(m_CSID); + m_outputElemList.initCSID(m_CSID); + } + else + err = OCSD_ERR_NOT_INIT; + return err; +} + +/* local decode methods */ + +// initialise on creation +void TrcPktDecodeEtmV3::initDecoder() +{ + m_CSID = 0; + resetDecoder(); + m_code_follower.initInterfaces(getMemoryAccessAttachPt(),getInstrDecodeAttachPt()); + m_outputElemList.initSendIf(getTraceElemOutAttachPt()); +} + +// reset for first use / re-use. +void TrcPktDecodeEtmV3::resetDecoder() +{ + m_curr_state = NO_SYNC; // mark as not synced + m_bNeedAddr = true; + m_bSentUnknown = false; + m_bWaitISync = false; + m_outputElemList.reset(); +} + +OcsdTraceElement *TrcPktDecodeEtmV3::GetNextOpElem(ocsd_datapath_resp_t &resp) +{ + OcsdTraceElement *pElem = m_outputElemList.getNextElem(m_index_curr_pkt); + if(pElem == 0) + { + resp = OCSD_RESP_FATAL_NOT_INIT; + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_MEM,m_index_curr_pkt,m_CSID,"Memory Allocation Error - fatal"); + } + return pElem; +} + +bool TrcPktDecodeEtmV3::preISyncValid(ocsd_etmv3_pkt_type pkt_type) +{ + bool bValid = false; + // its a timestamp + if((pkt_type == ETM3_PKT_TIMESTAMP) || + // or we are cycleacc and its a packet that can have CC in it + (m_config->isCycleAcc() && ((pkt_type == ETM3_PKT_CYCLE_COUNT) || (pkt_type == ETM3_PKT_P_HDR))) + ) + bValid = true; + return bValid; +} + +// simple packet transforms handled here, more complex processing passed on to specific routines. +ocsd_datapath_resp_t TrcPktDecodeEtmV3::decodePacket(bool &pktDone) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bISyncHasCC = false; + OcsdTraceElement *pElem = 0; + pktDone = false; + + // there may be pended packets that can now be committed. + // only the branch address with exception and cancel element can cancel + // if not one of those, commit immediately, otherwise defer to branch address handler. + if(m_curr_packet_in->getType() != ETM3_PKT_BRANCH_ADDRESS) + m_outputElemList.commitAllPendElem(); + + try { + + switch(m_curr_packet_in->getType()) + { + + case ETM3_PKT_NOTSYNC: + // mark as not synced - must have lost sync in the packet processor somehow + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Trace Packet Synchronisation Lost"); + break; + + // no action for these packets - ignore and continue + case ETM3_PKT_INCOMPLETE_EOT: + case ETM3_PKT_A_SYNC: + case ETM3_PKT_IGNORE: + break; + + // markers for valid packets + case ETM3_PKT_CYCLE_COUNT: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); + pElem->setCycleCount(m_curr_packet_in->getCycleCount()); + break; + + case ETM3_PKT_TRIGGER: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EVENT); + pElem->setEvent(EVENT_TRIGGER,0); + break; + + case ETM3_PKT_BRANCH_ADDRESS: + resp = processBranchAddr(); + break; + + case ETM3_PKT_I_SYNC_CYCLE: + bISyncHasCC = true; + case ETM3_PKT_I_SYNC: + resp = processISync(bISyncHasCC); + break; + + case ETM3_PKT_P_HDR: + resp = processPHdr(); + break; + + case ETM3_PKT_CONTEXT_ID: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID()); + pElem->setContext(m_PeContext); + break; + + case ETM3_PKT_VMID: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_PeContext.setVMID(m_curr_packet_in->getVMID()); + pElem->setContext(m_PeContext); + break; + + case ETM3_PKT_EXCEPTION_ENTRY: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION); + pElem->setExcepMarker(); // exception entries are always v7M data markers in ETMv3 trace. + break; + + case ETM3_PKT_EXCEPTION_EXIT: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); + pendExceptionReturn(); + break; + + case ETM3_PKT_TIMESTAMP: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); + pElem->setTS(m_curr_packet_in->getTS()); + break; + + // data packets - data trace not supported at present + case ETM3_PKT_STORE_FAIL: + case ETM3_PKT_OOO_DATA: + case ETM3_PKT_OOO_ADDR_PLC: + case ETM3_PKT_NORM_DATA: + case ETM3_PKT_DATA_SUPPRESSED: + case ETM3_PKT_VAL_NOT_TRACED: + case ETM3_PKT_BAD_TRACEMODE: + resp = OCSD_RESP_FATAL_INVALID_DATA; + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_index_curr_pkt,m_CSID,"Invalid packet type : Data Tracing decode not supported."); + break; + + // packet errors + case ETM3_PKT_BAD_SEQUENCE: + resp = OCSD_RESP_FATAL_INVALID_DATA; + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Bad Packet sequence."); + break; + + default: + case ETM3_PKT_RESERVED: + resp = OCSD_RESP_FATAL_INVALID_DATA; + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Reserved or unknown packet ID."); + break; + } + m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; + pktDone = !m_outputElemList.elemToSend(); + } + catch(ocsdError &err) + { + LogError(err); + resetDecoder(); // mark decoder as unsynced - dump any current state. + pktDone = true; + } + catch(...) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,m_CSID,"Bad Packet sequence.")); + resp = OCSD_RESP_FATAL_SYS_ERR; + resetDecoder(); // mark decoder as unsynced - dump any current state. + pktDone = true; + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::sendUnsyncPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + OcsdTraceElement *pElem = 0; + try { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_NO_SYNC); + resp = m_outputElemList.sendElements(); + } + catch(ocsdError &err) + { + LogError(err); + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + return resp; +} + +void TrcPktDecodeEtmV3::setNeedAddr(bool bNeedAddr) +{ + m_bNeedAddr = bNeedAddr; + m_bSentUnknown = false; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::processISync(const bool withCC, const bool firstSync /* = false */) +{ + // map ISync reason to generic reason codes. + static trace_on_reason_t on_map[] = { TRACE_ON_NORMAL, TRACE_ON_NORMAL, + TRACE_ON_OVERFLOW, TRACE_ON_EX_DEBUG }; + + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool ctxtUpdate = m_curr_packet_in->isCtxtUpdated(); + OcsdTraceElement *pElem = 0; + + try { + + pElem = GetNextOpElem(resp); + + if(firstSync || (m_curr_packet_in->getISyncReason() != iSync_Periodic)) + { + pElem->setType(OCSD_GEN_TRC_ELEM_TRACE_ON); + pElem->setTraceOnReason(on_map[(int)m_curr_packet_in->getISyncReason()]); + pElem = GetNextOpElem(resp); + } + + // look for context changes.... + if(ctxtUpdate || firstSync) + { + // if not first time out, read existing context in output element, + // otherwise we are setting it new. + if(firstSync) + m_PeContext.resetCtxt(); + + if(m_curr_packet_in->isCtxtIDUpdated()) + m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID()); + if(m_curr_packet_in->isVMIDUpdated()) + m_PeContext.setVMID(m_curr_packet_in->getVMID()); + if(m_curr_packet_in->isCtxtFlagsUpdated()) + { + m_PeContext.setEL(m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown); + m_PeContext.setSecLevel(m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure); + } + + // prepare the context packet + pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + pElem->setContext(m_PeContext); + pElem->setISA(m_curr_packet_in->ISA()); + + // with cycle count... + if(m_curr_packet_in->getISyncHasCC()) + pElem->setCycleCount(m_curr_packet_in->getCycleCount()); + + } + + // set ISync address - if it is a valid I address + if(!m_curr_packet_in->getISyncNoAddr()) + { + if(m_curr_packet_in->getISyncIsLSiPAddr()) + { + // TBD: handle extra data processing instruction for data trace + // need to output E atom relating to the data instruction + // rare - on start-up case. + + // main instruction address saved in data address for this packet type. + m_IAddr = m_curr_packet_in->getDataAddr(); + } + else + { + m_IAddr = m_curr_packet_in->getAddr(); + } + setNeedAddr(false); // ready to process atoms. + } + m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; + } + catch(ocsdError &err) + { + LogError(err); + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::processBranchAddr() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + OcsdTraceElement *pElem = 0; + bool bUpdatePEContext = false; + + // might need to cancel something ... if the last output was an instruction range or excep return + if(m_curr_packet_in->isExcepCancel()) + m_outputElemList.cancelPendElem(); + else + m_outputElemList.commitAllPendElem(); // otherwise commit any pending elements. + + // record the address + m_IAddr = m_curr_packet_in->getAddr(); + setNeedAddr(false); // no longer need an address. + + // exception packet - may need additional output + if(m_curr_packet_in->isExcepPkt()) + { + // exeception packet may have exception, context change, or both. + // check for context change + if(m_curr_packet_in->isCtxtUpdated()) + { + + ocsd_sec_level sec = m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure; + if(sec != m_PeContext.getSecLevel()) + { + m_PeContext.setSecLevel(sec); + bUpdatePEContext = true; + } + ocsd_ex_level pkt_el = m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown; + if(pkt_el != m_PeContext.getEL()) + { + m_PeContext.setEL(pkt_el); + bUpdatePEContext = true; + } + } + + // now decide if we need to send any packets out. + try { + + if(bUpdatePEContext) + { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + pElem->setContext(m_PeContext); + } + + // check for exception + if(m_curr_packet_in->excepNum() != 0) + { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION); + pElem->setExceptionNum(m_curr_packet_in->excepNum()); + } + + // finally - do we have anything to send yet? + m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; + } + catch(ocsdError &err) + { + LogError(err); + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + } + return resp; +} + + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPHdr() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + OcsdTraceElement *pElem = 0; + ocsd_isa isa; + Etmv3Atoms atoms(m_config->isCycleAcc()); + + atoms.initAtomPkt(m_curr_packet_in,m_index_curr_pkt); + isa = m_curr_packet_in->ISA(); + m_code_follower.setMemSpaceAccess((m_PeContext.getSecLevel() == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N); + + try + { + do + { + // if we do not have a valid address then send any cycle count elements + // and stop processing + if(m_bNeedAddr) + { + // output unknown address packet or a cycle count packet + if(!m_bSentUnknown || m_config->isCycleAcc()) + { + pElem = GetNextOpElem(resp); + if(m_bSentUnknown || !atoms.numAtoms()) + pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); + else + pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN); + if(m_config->isCycleAcc()) + pElem->setCycleCount(atoms.getRemainCC()); + m_bSentUnknown = true; + } + atoms.clearAll(); // skip remaining atoms + } + else // have an address, can process atoms + { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + + // cycle accurate may have a cycle count to use + if(m_config->isCycleAcc()) + { + // note: it is possible to have a CC only atom packet. + if(!atoms.numAtoms()) // override type if CC only + pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); + // set cycle count + pElem->setCycleCount(atoms.getAtomCC()); + } + + // now process the atom + if(atoms.numAtoms()) + { + m_code_follower.setISA(isa); + m_code_follower.followSingleAtom(m_IAddr,atoms.getCurrAtomVal()); + + // valid code range + if(m_code_follower.hasRange()) + { + pElem->setAddrRange(m_IAddr,m_code_follower.getRangeEn()); + pElem->setLastInstrInfo(atoms.getCurrAtomVal() == ATOM_E, + m_code_follower.getInstrType(), + m_code_follower.getInstrSubType()); + pElem->setISA(isa); + if(m_code_follower.hasNextAddr()) + m_IAddr = m_code_follower.getNextAddr(); + else + setNeedAddr(true); + } + + // next address has new ISA? + if(m_code_follower.ISAChanged()) + isa = m_code_follower.nextISA(); + + // there is a nacc + if(m_code_follower.isNacc()) + { + if(m_code_follower.hasRange()) + { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + } + else + pElem->updateType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + pElem->setAddrStart(m_code_follower.getNaccAddr()); + setNeedAddr(true); + m_code_follower.clearNacc(); // we have generated some code for the nacc. + } + } + + atoms.clearAtom(); // next atom + } + } + while(atoms.numAtoms()); + + // is tha last element an atom? + int numElem = m_outputElemList.getNumElem(); + if(numElem >= 1) + { + // if the last thing is an instruction range, pend it - could be cancelled later. + if(m_outputElemList.getElemType(numElem-1) == OCSD_GEN_TRC_ELEM_INSTR_RANGE) + m_outputElemList.pendLastNElem(1); + } + + // finally - do we have anything to send yet? + m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; + } + catch(ocsdError &err) + { + LogError(err); + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + return resp; +} + +// if v7M -> pend only ERET, if V7A/R pend ERET and prev instr. +void TrcPktDecodeEtmV3::pendExceptionReturn() +{ + int pendElem = 1; + if(m_config->getCoreProfile() != profile_CortexM) + { + int nElem = m_outputElemList.getNumElem(); + if(nElem > 1) + { + if(m_outputElemList.getElemType(nElem - 2) == OCSD_GEN_TRC_ELEM_INSTR_RANGE) + pendElem = 2; // need to pend instr+eret for A/R + } + } + m_outputElemList.pendLastNElem(pendElem); +} + +/* End of File trc_pkt_decode_etmv3.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp b/contrib/opencsd/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp new file mode 100644 index 000000000000..f1e411f72423 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp @@ -0,0 +1,688 @@ +/* + * \file trc_pkt_elem_etmv3.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include +#include +#include + +#include "opencsd/etmv3/trc_pkt_elem_etmv3.h" + +EtmV3TrcPacket::EtmV3TrcPacket() +{ + m_pkt_data.addr.size = VA_32BIT; // etm v3 only handles 32 bit addresses. +} + +EtmV3TrcPacket::~EtmV3TrcPacket() +{ +} + +// update interface - set packet values + +// clear this packet info +void EtmV3TrcPacket::Clear() +{ + // clear structure flags and counter elements etc, that work per packet. + // leave intra packet data unchanged + m_pkt_data.addr.pkt_bits = 0; + m_pkt_data.prev_isa = m_pkt_data.curr_isa; // mark ISA as not changed + m_pkt_data.exception.bits.present = 0; + m_pkt_data.atom.num = 0; + m_pkt_data.cycle_count = 0; + m_pkt_data.context.updated = 0; + m_pkt_data.context.updated_c = 0; + m_pkt_data.context.updated_v = 0; + m_pkt_data.data.ooo_tag = 0; + m_pkt_data.data.value = 0; + m_pkt_data.data.update_addr = 0; + m_pkt_data.data.update_be = 0; + m_pkt_data.data.update_dval = 0; + m_pkt_data.ts_update_bits = 0; + m_pkt_data.isync_info.has_cycle_count = 0; + m_pkt_data.isync_info.has_LSipAddress = 0; + m_pkt_data.isync_info.no_address = 0; +} + +// reset all state including intra packet +void EtmV3TrcPacket::ResetState() +{ + memset(&m_pkt_data,0,sizeof(ocsd_etmv3_pkt)); + m_pkt_data.curr_isa = m_pkt_data.prev_isa = ocsd_isa_unknown; +} + +void EtmV3TrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits) +{ + ocsd_vaddr_t validMask = OCSD_VA_MASK; + validMask >>= OCSD_MAX_VA_BITSIZE-updateBits; + m_pkt_data.addr.pkt_bits = updateBits; + m_pkt_data.addr.val &= ~validMask; + m_pkt_data.addr.val |= (partAddrVal & validMask); + if(updateBits > m_pkt_data.addr.valid_bits) + m_pkt_data.addr.valid_bits = updateBits; +} + +void EtmV3TrcPacket::UpdateDataAddress(const uint32_t value, const uint8_t valid_bits) +{ + // ETMv3 data addresses 32 bits. + uint32_t validMask = 0xFFFFFFFF; + validMask >>= 32-valid_bits; + m_pkt_data.addr.pkt_bits = valid_bits; + m_pkt_data.addr.val &= ~validMask; + m_pkt_data.addr.val |= (value & validMask); + if(valid_bits > m_pkt_data.addr.valid_bits) + m_pkt_data.addr.valid_bits = valid_bits; + m_pkt_data.data.update_addr = 1; +} + +void EtmV3TrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits) +{ + uint64_t validMask = ~0ULL; + validMask >>= 64-updateBits; + m_pkt_data.timestamp &= ~validMask; + m_pkt_data.timestamp |= (tsVal & validMask); + m_pkt_data.ts_update_bits = updateBits; +} + + + +void EtmV3TrcPacket::SetException( const ocsd_armv7_exception type, + const uint16_t number, + const bool cancel, + const bool cm_type, + const int irq_n /*= 0*/, + const int resume /* = 0*/) +{ + // initial data + m_pkt_data.exception.bits.cancel = cancel ? 1 : 0; + m_pkt_data.exception.bits.cm_irq_n = irq_n; + m_pkt_data.exception.bits.cm_resume = resume; + m_pkt_data.exception.bits.cm_type = cm_type ? 1 : 0; + m_pkt_data.exception.number = number; + m_pkt_data.exception.type = type; + + // mark as valid in this packet + m_pkt_data.exception.bits.present = 1; +} + +bool EtmV3TrcPacket::UpdateAtomFromPHdr(const uint8_t pHdr, const bool cycleAccurate) +{ + bool bValid = true; + uint8_t E = 0, N = 0; + if(!cycleAccurate) + { + if((pHdr & 0x3) == 0x0) + { + E = ((pHdr >> 2) & 0xF); + N = (pHdr & 0x40) ? 1 : 0; + m_pkt_data.atom.num = E+N; + m_pkt_data.atom.En_bits = (((uint32_t)0x1) << E) - 1; + m_pkt_data.p_hdr_fmt = 1; + } + else if((pHdr & 0x3) == 0x2) + { + m_pkt_data.atom.num = 2; + m_pkt_data.p_hdr_fmt = 2; + m_pkt_data.atom.En_bits = (pHdr & 0x8 ? 0 : 1) | (pHdr & 0x4 ? 0 : 0x2); + } + else + bValid = false; + } + else + { + uint8_t pHdr_code = pHdr & 0xA3; + switch(pHdr_code) + { + case 0x80: + m_pkt_data.p_hdr_fmt = 1; + E = ((pHdr >> 2) & 0x7); + N = (pHdr & 0x40) ? 1 : 0; + m_pkt_data.atom.num = E+N; + if(m_pkt_data.atom.num) + { + m_pkt_data.atom.En_bits = (((uint32_t)0x1) << E) - 1; + m_pkt_data.cycle_count = E+N; + } + else + bValid = false; // deprecated 8b'10000000 code + + break; + + case 0x82: + m_pkt_data.p_hdr_fmt = 2; + if(pHdr & 0x10) + { + m_pkt_data.p_hdr_fmt = 4; + m_pkt_data.atom.num = 1; + m_pkt_data.cycle_count = 0; + m_pkt_data.atom.En_bits = pHdr & 0x04 ? 0 : 1; + } + else + { + m_pkt_data.atom.num = 2; + m_pkt_data.cycle_count = 1; + m_pkt_data.atom.En_bits = (pHdr & 0x8 ? 0 : 1) | (pHdr & 0x4 ? 0 : 0x2); + } + break; + + case 0xA0: + m_pkt_data.p_hdr_fmt = 3; + m_pkt_data.cycle_count = ((pHdr >> 2) & 7) + 1; + E = pHdr & 0x40 ? 1 : 0; + m_pkt_data.atom.num = E; + m_pkt_data.atom.En_bits = E; + break; + + default: + bValid = false; + break; + + } + } + return bValid; +} + +EtmV3TrcPacket &EtmV3TrcPacket::operator =(const ocsd_etmv3_pkt* p_pkt) +{ + m_pkt_data = *p_pkt; + return *this; +} + + // printing +void EtmV3TrcPacket::toString(std::string &str) const +{ + const char *name; + const char *desc; + std::string valStr, ctxtStr = ""; + + name = packetTypeName(m_pkt_data.type, &desc); + str = name + (std::string)" : " + desc; + + switch(m_pkt_data.type) + { + // print the original header type for the bad sequences. + case ETM3_PKT_BAD_SEQUENCE: + case ETM3_PKT_BAD_TRACEMODE: + name = packetTypeName(m_pkt_data.err_type,0); + str += "[" + (std::string)name + "]"; + break; + + case ETM3_PKT_BRANCH_ADDRESS: + getBranchAddressStr(valStr); + str += "; " + valStr; + break; + + case ETM3_PKT_I_SYNC_CYCLE: + case ETM3_PKT_I_SYNC: + getISyncStr(valStr); + str += "; " + valStr; + break; + + case ETM3_PKT_P_HDR: + getAtomStr(valStr); + str += "; " + valStr; + break; + + case ETM3_PKT_CYCLE_COUNT: + { + std::ostringstream oss; + oss << "; Cycles=" << m_pkt_data.cycle_count; + str += oss.str(); + } + break; + + case ETM3_PKT_CONTEXT_ID: + { + std::ostringstream oss; + oss << "; CtxtID=" << std::hex << "0x" << m_pkt_data.context.ctxtID; + str += oss.str(); + } + break; + + case ETM3_PKT_VMID: + { + std::ostringstream oss; + oss << "; VMID=" << std::hex << "0x" << m_pkt_data.context.VMID; + str += oss.str(); + } + break; + + case ETM3_PKT_TIMESTAMP: + { + std::ostringstream oss; + oss << "; TS=" << std::hex << "0x" << m_pkt_data.timestamp << " (" << std::dec << m_pkt_data.timestamp << ") "; + str += oss.str(); + } + break; + + case ETM3_PKT_OOO_DATA: + { + std::ostringstream oss; + oss << "; Val=" << std::hex << "0x" << m_pkt_data.data.value; + oss << "; OO_Tag=" << std::hex << "0x" << m_pkt_data.data.ooo_tag; + str += oss.str(); + } + break; + + case ETM3_PKT_VAL_NOT_TRACED: + if(m_pkt_data.data.update_addr) + { + trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits, + m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits); + str += "; Addr=" + valStr; + } + break; + + case ETM3_PKT_OOO_ADDR_PLC: + if(m_pkt_data.data.update_addr) + { + trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits, + m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits); + str += "; Addr=" + valStr; + } + { + std::ostringstream oss; + oss << "; OO_Tag=" << std::hex << "0x" << m_pkt_data.data.ooo_tag; + str += oss.str(); + } + break; + + case ETM3_PKT_NORM_DATA: + if(m_pkt_data.data.update_addr) + { + trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits, + m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits); + str += "; Addr=" + valStr; + } + if(m_pkt_data.data.update_dval) + { + std::ostringstream oss; + oss << "; Val=" << std::hex << "0x" << m_pkt_data.data.value; + str += oss.str(); + } + break; + } +} + +void EtmV3TrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const +{ + // no formatting implemented at present. + toString(str); +} + +const char *EtmV3TrcPacket::packetTypeName(const ocsd_etmv3_pkt_type type, const char **ppDesc) const +{ + const char *pName = "I_RESERVED"; + const char *pDesc = "Reserved Packet Header"; + + switch(type) + { +// markers for unknown packets + // case ETM3_PKT_NOERROR:, //!< no error in packet - supplimentary data. + case ETM3_PKT_NOTSYNC: //!< no sync found yet + pName = "NOTSYNC"; + pDesc = "Trace Stream not synchronised"; + break; + + case ETM3_PKT_INCOMPLETE_EOT: //!< flushing incomplete/empty packet at end of trace. + pName = "INCOMPLETE_EOT."; + pDesc = "Incomplete packet at end of trace data."; + break; + +// markers for valid packets + case ETM3_PKT_BRANCH_ADDRESS: + pName = "BRANCH_ADDRESS"; + pDesc = "Branch address."; + break; + + case ETM3_PKT_A_SYNC: + pName = "A_SYNC"; + pDesc = "Alignment Synchronisation."; + break; + + case ETM3_PKT_CYCLE_COUNT: + pName = "CYCLE_COUNT"; + pDesc = "Cycle Count."; + break; + + case ETM3_PKT_I_SYNC: + pName = "I_SYNC"; + pDesc = "Instruction Packet synchronisation."; + break; + + case ETM3_PKT_I_SYNC_CYCLE: + pName = "I_SYNC_CYCLE"; + pDesc = "Instruction Packet synchronisation with cycle count."; + break; + + case ETM3_PKT_TRIGGER: + pName = "TRIGGER"; + pDesc = "Trace Trigger Event."; + break; + + case ETM3_PKT_P_HDR: + pName = "P_HDR"; + pDesc = "Atom P-header."; + break; + + case ETM3_PKT_STORE_FAIL: + pName = "STORE_FAIL"; + pDesc = "Data Store Failed."; + break; + + case ETM3_PKT_OOO_DATA: + pName = "OOO_DATA"; + pDesc = "Out of Order data value packet."; + break; + + case ETM3_PKT_OOO_ADDR_PLC: + pName = "OOO_ADDR_PLC"; + pDesc = "Out of Order data address placeholder."; + break; + + case ETM3_PKT_NORM_DATA: + pName = "NORM_DATA"; + pDesc = "Data trace packet."; + break; + + case ETM3_PKT_DATA_SUPPRESSED: + pName = "DATA_SUPPRESSED"; + pDesc = "Data trace suppressed."; + break; + + case ETM3_PKT_VAL_NOT_TRACED: + pName = "VAL_NOT_TRACED"; + pDesc = "Data trace value not traced."; + break; + + case ETM3_PKT_IGNORE: + pName = "IGNORE"; + pDesc = "Packet ignored."; + break; + + case ETM3_PKT_CONTEXT_ID: + pName = "CONTEXT_ID"; + pDesc = "Context ID change."; + break; + + case ETM3_PKT_VMID: + pName = "VMID"; + pDesc = "VMID change."; + break; + + case ETM3_PKT_EXCEPTION_ENTRY: + pName = "EXCEPTION_ENTRY"; + pDesc = "Exception entry data marker."; + break; + + case ETM3_PKT_EXCEPTION_EXIT: + pName = "EXCEPTION_EXIT"; + pDesc = "Exception return."; + break; + + case ETM3_PKT_TIMESTAMP: + pName = "TIMESTAMP"; + pDesc = "Timestamp Value."; + break; + +// internal processing types + // case ETM3_PKT_BRANCH_OR_BYPASS_EOT: not externalised + +// packet errors + case ETM3_PKT_BAD_SEQUENCE: + pName = "BAD_SEQUENCE"; + pDesc = "Invalid sequence for packet type."; + break; + + case ETM3_PKT_BAD_TRACEMODE: + pName = "BAD_TRACEMODE"; + pDesc = "Invalid packet type for this trace mode."; + break; + + // leave thest unchanged. + case ETM3_PKT_RESERVED: + default: + break; + + } + + if(ppDesc) *ppDesc = pDesc; + return pName; +} + +void EtmV3TrcPacket::getBranchAddressStr(std::string &valStr) const +{ + std::ostringstream oss; + std::string subStr; + + // print address. + trcPrintableElem::getValStr(subStr,32,m_pkt_data.addr.valid_bits, + m_pkt_data.addr.val,true,m_pkt_data.addr.pkt_bits); + oss << "Addr=" << subStr << "; "; + + // current ISA if changed. + if(m_pkt_data.curr_isa != m_pkt_data.prev_isa) + { + getISAStr(subStr); + oss << subStr; + } + + // S / NS etc if changed. + if(m_pkt_data.context.updated) + { + oss << (m_pkt_data.context.curr_NS ? "NS; " : "S; "); + oss << (m_pkt_data.context.curr_Hyp ? "Hyp; " : ""); + } + + // exception? + if(m_pkt_data.exception.bits.present) + { + getExcepStr(subStr); + oss << subStr; + } + valStr = oss.str(); +} + +void EtmV3TrcPacket::getAtomStr(std::string &valStr) const +{ + std::ostringstream oss; + uint32_t bitpattern = m_pkt_data.atom.En_bits; // arranged LSBit oldest, MSbit newest + + if(!m_pkt_data.cycle_count) + { + for(int i = 0; i < m_pkt_data.atom.num; i++) + { + oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest + bitpattern >>= 1; + } + } + else + { + switch(m_pkt_data.p_hdr_fmt) + { + case 1: + for(int i = 0; i < m_pkt_data.atom.num; i++) + { + oss << ((bitpattern & 0x1) ? "WE" : "WN"); // in spec read L->R, oldest->newest + bitpattern >>= 1; + } + break; + + case 2: + oss << "W"; + for(int i = 0; i < m_pkt_data.atom.num; i++) + { + oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest + bitpattern >>= 1; + } + break; + + case 3: + for(uint32_t i = 0; i < m_pkt_data.cycle_count; i++) + oss << "W"; + if(m_pkt_data.atom.num) + oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest + break; + } + oss << "; Cycles=" << m_pkt_data.cycle_count; + } + valStr = oss.str(); +} + +void EtmV3TrcPacket::getISyncStr(std::string &valStr) const +{ + std::ostringstream oss; + static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" }; + + // reason. + oss << "(" << reason[(int)m_pkt_data.isync_info.reason] << "); "; + + // full address. + if(!m_pkt_data.isync_info.no_address) + { + if(m_pkt_data.isync_info.has_LSipAddress) + oss << "Data Instr Addr=0x"; + else + oss << "Addr=0x"; + oss << std::hex << std::setfill('0') << std::setw(8) << m_pkt_data.addr.val << "; "; + } + + oss << (m_pkt_data.context.curr_NS ? "NS; " : "S; "); + oss << (m_pkt_data.context.curr_Hyp ? "Hyp; " : " "); + + if(m_pkt_data.context.updated_c) + { + oss << "CtxtID=" << std::hex << m_pkt_data.context.ctxtID << "; "; + } + + if(m_pkt_data.isync_info.no_address) + { + valStr = oss.str(); + return; // bail out at this point if a data only ISYNC + } + + std::string isaStr; + getISAStr(isaStr); + oss << isaStr; + + if(m_pkt_data.isync_info.has_cycle_count) + { + oss << "Cycles=" << std::dec << m_pkt_data.cycle_count << "; "; + } + + if(m_pkt_data.isync_info.has_LSipAddress) + { + std::string addrStr; + + // extract address updata. + trcPrintableElem::getValStr(addrStr,32,m_pkt_data.data.addr.valid_bits, + m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits); + oss << "Curr Instr Addr=" << addrStr << ";"; + } + valStr = oss.str(); +} + +void EtmV3TrcPacket::getISAStr(std::string &isaStr) const +{ + std::ostringstream oss; + oss << "ISA="; + switch(m_pkt_data.curr_isa) + { + case ocsd_isa_arm: + oss << "ARM(32); "; + break; + + case ocsd_isa_thumb2: + oss << "Thumb2; "; + break; + + case ocsd_isa_aarch64: + oss << "AArch64; "; + break; + + case ocsd_isa_tee: + oss << "ThumbEE; "; + break; + + case ocsd_isa_jazelle: + oss << "Jazelle; "; + break; + + default: + case ocsd_isa_unknown: + oss << "Unknown; "; + break; + } + isaStr = oss.str(); +} + +void EtmV3TrcPacket::getExcepStr(std::string &excepStr) const +{ + static const char *ARv7Excep[] = { + "No Exception", "Debug Halt", "SMC", "Hyp", + "Async Data Abort", "Jazelle", "Reserved", "Reserved", + "PE Reset", "Undefined Instr", "SVC", "Prefetch Abort", + "Data Fault", "Generic", "IRQ", "FIQ" + }; + + static const char *MExcep[] = { + "No Exception", "IRQ1", "IRQ2", "IRQ3", + "IRQ4", "IRQ5", "IRQ6", "IRQ7", + "IRQ0","usage Fault","NMI","SVC", + "DebugMonitor", "Mem Manage","PendSV","SysTick", + "Reserved","PE Reset","Reserved","HardFault" + "Reserved","BusFault","Reserved","Reserved" + }; + + std::ostringstream oss; + oss << "Exception="; + + if(m_pkt_data.exception.bits.cm_type) + { + if(m_pkt_data.exception.number < 0x18) + oss << MExcep[m_pkt_data.exception.number]; + else + oss << "IRQ" << std::dec << (m_pkt_data.exception.number - 0x10); + if(m_pkt_data.exception.bits.cm_resume) + oss << "; Resume=" << m_pkt_data.exception.bits.cm_resume; + if(m_pkt_data.exception.bits.cancel) + oss << "; Cancel prev instr"; + } + else + { + oss << ARv7Excep[m_pkt_data.exception.number] << "; "; + if(m_pkt_data.exception.bits.cancel) + oss << "; Cancel prev instr"; + } + excepStr = oss.str(); +} +/* End of File trc_pkt_elem_etmv3.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp b/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp new file mode 100644 index 000000000000..7871619fe55f --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp @@ -0,0 +1,122 @@ +/* + * \file trc_pkt_proc_etmv3.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/etmv3/trc_pkt_proc_etmv3.h" +#include "trc_pkt_proc_etmv3_impl.h" +#include "common/ocsd_error.h" + +#ifdef __GNUC__ +// G++ doesn't like the ## pasting +#define ETMV3_PKTS_NAME "PKTP_ETMV3" +#else +#define ETMV3_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_"##OCSD_BUILTIN_DCD_ETMV3 +#endif + +static const uint32_t ETMV3_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON | + ETMV3_OPFLG_UNFORMATTED_SOURCE; + +TrcPktProcEtmV3::TrcPktProcEtmV3() : TrcPktProcBase(ETMV3_PKTS_NAME), + m_pProcessor(0) +{ + m_supported_op_flags = ETMV3_SUPPORTED_OP_FLAGS; +} + +TrcPktProcEtmV3::TrcPktProcEtmV3(int instIDNum) : TrcPktProcBase(ETMV3_PKTS_NAME, instIDNum), + m_pProcessor(0) +{ + m_supported_op_flags = ETMV3_SUPPORTED_OP_FLAGS; +} + +TrcPktProcEtmV3::~TrcPktProcEtmV3() +{ + if(m_pProcessor) + delete m_pProcessor; + m_pProcessor = 0; +} + +ocsd_err_t TrcPktProcEtmV3::onProtocolConfig() +{ + if(m_pProcessor == 0) + { + m_pProcessor = new (std::nothrow) EtmV3PktProcImpl(); + if(m_pProcessor == 0) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM)); + return OCSD_ERR_MEM; + } + m_pProcessor->Initialise(this); + } + return m_pProcessor->Configure(m_config); +} + +ocsd_datapath_resp_t TrcPktProcEtmV3::processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + if(m_pProcessor) + return m_pProcessor->processData(index,dataBlockSize,pDataBlock,numBytesProcessed); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV3::onEOT() +{ + if(m_pProcessor) + return m_pProcessor->onEOT(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV3::onReset() +{ + if(m_pProcessor) + return m_pProcessor->onReset(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV3::onFlush() +{ + if(m_pProcessor) + return m_pProcessor->onFlush(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +const bool TrcPktProcEtmV3::isBadPacket() const +{ + if(m_pProcessor) + return m_pProcessor->isBadPacket(); + return false; +} + +/* End of File trc_pkt_proc_etmv3.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp b/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp new file mode 100644 index 000000000000..fc39a5eda7d3 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp @@ -0,0 +1,1224 @@ +/* + * \file trc_pkt_proc_etmv3_impl.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "trc_pkt_proc_etmv3_impl.h" + +EtmV3PktProcImpl::EtmV3PktProcImpl() : + m_isInit(false), + m_interface(0) +{ +} + +EtmV3PktProcImpl::~EtmV3PktProcImpl() +{ +} + +ocsd_err_t EtmV3PktProcImpl::Configure(const EtmV3Config *p_config) +{ + ocsd_err_t err = OCSD_OK; + if(p_config != 0) + { + m_config = *p_config; + m_chanIDCopy = m_config.getTraceID(); + } + else + { + err = OCSD_ERR_INVALID_PARAM_VAL; + if(m_isInit) + m_interface->LogError(ocsdError(OCSD_ERR_SEV_ERROR,err)); + } + return err; +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::processData(const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + m_bytesProcessed = 0; + + while( ( (m_bytesProcessed < dataBlockSize) || + ((m_bytesProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) ) + && OCSD_DATA_RESP_IS_CONT(resp)) + { + try + { + switch(m_process_state) + { + case WAIT_SYNC: + if(!m_bStartOfSync) + m_packet_index = index + m_bytesProcessed; + m_bytesProcessed += waitForSync(dataBlockSize-m_bytesProcessed,pDataBlock+m_bytesProcessed); + break; + + case PROC_HDR: + m_packet_index = index + m_bytesProcessed; + processHeaderByte(pDataBlock[m_bytesProcessed++]); + break; + + case PROC_DATA: + processPayloadByte(pDataBlock [m_bytesProcessed++]); + break; + + case SEND_PKT: + resp = outputPacket(); + break; + } + } + catch(ocsdError &err) + { + m_interface->LogError(err); + if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) || + (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)) + { + // send invalid packets up the pipe to let the next stage decide what to do. + m_process_state = SEND_PKT; + } + else + { + // bail out on any other error. + resp = OCSD_RESP_FATAL_INVALID_DATA; + } + } + catch(...) + { + /// vv bad at this point. + resp = OCSD_RESP_FATAL_SYS_ERR; + ocsdError fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_chanIDCopy); + fatal.setMessage("Unknown System Error decoding trace."); + m_interface->LogError(fatal); + } + } + + *numBytesProcessed = m_bytesProcessed; + return resp; +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + // if we have a partial packet then send to attached sinks + if(m_currPacketData.size() != 0) + { + // TBD: m_curr_packet.updateErrType(ETM4_ETM3_PKT_I_INCOMPLETE_EOT); + resp = outputPacket(); + InitPacketState(); + } + return resp; +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::onReset() +{ + InitProcessorState(); + return OCSD_RESP_CONT; +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::onFlush() +{ + // packet processor never holds on to flushable data (may have partial packet, + // but any full packets are immediately sent) + return OCSD_RESP_CONT; +} + +void EtmV3PktProcImpl::Initialise(TrcPktProcEtmV3 *p_interface) +{ + if(p_interface) + { + m_interface = p_interface; + m_isInit = true; + + } + InitProcessorState(); + /* not using pattern matcher for sync at present + static const uint8_t a_sync[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }; + m_syncMatch.setPattern(a_sync, sizeof(a_sync));*/ +} + +void EtmV3PktProcImpl::InitProcessorState() +{ + m_bStreamSync = false; // not synced + m_process_state = WAIT_SYNC; // waiting for sync + m_bStartOfSync = false; // not seen start of sync packet + m_curr_packet.ResetState(); // reset intra packet state + InitPacketState(); // set curr packet state + m_bSendPartPkt = false; +} + +void EtmV3PktProcImpl::InitPacketState() +{ + m_bytesExpectedThisPkt = 0; + m_BranchPktNeedsException = false; + m_bIsync_got_cycle_cnt = false; + m_bIsync_get_LSiP_addr = false; + m_IsyncInfoIdx = false; + m_bExpectingDataAddress = false; + m_bFoundDataAddress = false; + m_currPacketData.clear(); + m_currPktIdx = 0; // index into processed bytes in current packet + m_curr_packet.Clear(); + +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::outputPacket() +{ + ocsd_datapath_resp_t dp_resp = OCSD_RESP_FATAL_NOT_INIT; + if(m_isInit) + { + ocsd_etmv3_pkt_type type = m_curr_packet.getType(); + if(!m_bSendPartPkt) + { + dp_resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&type,m_currPacketData); + m_process_state = m_bStreamSync ? PROC_HDR : WAIT_SYNC; // need a header next time, or still waiting to sync. + m_currPacketData.clear(); + } + else + { + // sending part packet, still some data in the main packet + dp_resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&type,m_partPktData); + m_process_state = m_post_part_pkt_state; + m_packet_index += m_partPktData.size(); + m_bSendPartPkt = false; + m_curr_packet.SetType(m_post_part_pkt_type); + } + } + return dp_resp; +} + +void EtmV3PktProcImpl::setBytesPartPkt(int numBytes, process_state nextState, const ocsd_etmv3_pkt_type nextType) +{ + m_partPktData.clear(); + for(int i=0; i < numBytes; i++) + { + m_partPktData.push_back(m_currPacketData[i]); + } + m_currPacketData.erase(m_currPacketData.begin(), m_currPacketData.begin()+numBytes); + m_bSendPartPkt = true; + m_post_part_pkt_state = nextState; + m_post_part_pkt_type = nextType; +} + +uint32_t EtmV3PktProcImpl::waitForSync(const uint32_t dataBlockSize, const uint8_t *pDataBlock) +{ + uint8_t currByte; + uint32_t bytesProcessed = 0; + bool bSendBlock = false; + + // need to wait for the first sync packet + while(!bSendBlock && (bytesProcessed < dataBlockSize)) + { + currByte = pDataBlock[bytesProcessed++]; + // TBD: forced sync point + + if(m_bStartOfSync) + { + // need to handle consecutive 0 bytes followed by genuine A-SYNC. + + m_currPacketData.push_back(currByte); + if((currByte == 0x80) && (m_currPacketData.size() >= 6)) + { + // it is a sync packet possibly with leading zeros + bSendBlock = true; + if(m_currPacketData.size() > 6) + { + m_currPacketData.pop_back(); + bytesProcessed--; // return 0x80 to the input buffer to re-process next pass after stripping 0's + setBytesPartPkt(m_currPacketData.size()-5,WAIT_SYNC,ETM3_PKT_NOTSYNC); + } + else + { + m_bStreamSync = true; + m_curr_packet.SetType(ETM3_PKT_A_SYNC); + } + } + else if(currByte != 0x00) + { + m_bStartOfSync = false; // not a sync packet + } + else if(m_currPacketData.size() >= 13) // 13 0's, strip 8 of them... + { + setBytesPartPkt(8,WAIT_SYNC,ETM3_PKT_NOTSYNC); + bSendBlock = true; + } + } + else // not seen a start of sync candidate yet + { + if(currByte == 0x00) // could be the start of a-sync + { + if(m_currPacketData.size() == 0) + { + m_currPacketData.push_back(currByte); + m_bStartOfSync = true; + } + else + { + bytesProcessed--; + bSendBlock = true; // send none sync packet data, re-process this byte next time. + m_curr_packet.SetType(ETM3_PKT_NOTSYNC); // send unsynced data packet. + } + } + else + { + //save a byte - not start of a-sync + m_currPacketData.push_back(currByte); + + // done all data in this block, or got 16 unsynced bytes + if((bytesProcessed == dataBlockSize) || (m_currPacketData.size() == 16)) + { + bSendBlock = true; // send none sync packet block + m_curr_packet.SetType(ETM3_PKT_NOTSYNC); // send unsynced data packet. + } + } + } + } + if(bSendBlock) + SendPacket(); + return bytesProcessed; +} + +ocsd_err_t EtmV3PktProcImpl::processHeaderByte(uint8_t by) +{ + InitPacketState(); // new packet, clear old single packet state (retains intra packet state). + + // save byte + m_currPacketData.push_back(by); + + m_process_state = PROC_DATA; // assume next is data packet + + // check for branch address 0bCxxxxxxx1 + if((by & 0x01) == 0x01 ) { + m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS); + m_BranchPktNeedsException = false; + if((by & 0x80) != 0x80) { + // no continuation - 1 byte branch same in alt and std... + if((by == 0x01) && (m_interface->getComponentOpMode() & ETMV3_OPFLG_UNFORMATTED_SOURCE)) + { + // TBD: need to fix up for handling bypassed ETM stream at some point. + throwUnsupportedErr("Bypassed ETM stream not supported in this version of the decoder."); + // could be EOTrace marker from bypassed formatter + m_curr_packet.SetType(ETM3_PKT_BRANCH_OR_BYPASS_EOT); + } + else + { + OnBranchAddress(); + SendPacket(); // mark ready to send. + } + } + } + // check for p-header - 0b1xxxxxx0 + else if((by & 0x81) == 0x80) { + m_curr_packet.SetType(ETM3_PKT_P_HDR); + if(m_curr_packet.UpdateAtomFromPHdr(by,m_config.isCycleAcc())) + SendPacket(); + else + throwPacketHeaderErr("Invalid P-Header."); + } + // check 0b0000xx00 group + else if((by & 0xF3) == 0x00) { + + // A-Sync + if(by == 0x00) { + m_curr_packet.SetType(ETM3_PKT_A_SYNC); + } + // cycle count + else if(by == 0x04) { + m_curr_packet.SetType(ETM3_PKT_CYCLE_COUNT); + } + // I-Sync + else if(by == 0x08) { + m_curr_packet.SetType(ETM3_PKT_I_SYNC); + m_bIsync_got_cycle_cnt = false; + m_bIsync_get_LSiP_addr = false; + } + // trigger + else if(by == 0x0C) { + m_curr_packet.SetType(ETM3_PKT_TRIGGER); + // no payload - just send it. + SendPacket(); + } + } + // check remaining 0bxxxxxx00 codes + else if((by & 0x03 )== 0x00) { + // OoO data 0b0xx0xx00 + if((by & 0x93 )== 0x00) { + if(!m_config.isDataValTrace()) { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (out of order data) - not tracing data values."); + } + m_curr_packet.SetType(ETM3_PKT_OOO_DATA); + uint8_t size = ((by & 0x0C) >> 2); + // header contains a count of the data to follow + // size 3 == 4 bytes, other sizes == size bytes + if(size == 0) + { + m_curr_packet.SetDataOOOTag((by >> 5) & 0x3); + m_curr_packet.SetDataValue(0); + SendPacket(); + } + else + m_bytesExpectedThisPkt = (short)(1 + ((size == 3) ? 4 : size)); + } + // I-Sync + cycle count + else if(by == 0x70) { + m_curr_packet.SetType(ETM3_PKT_I_SYNC_CYCLE); + m_bIsync_got_cycle_cnt = false; + m_bIsync_get_LSiP_addr = false; + } + // store failed + else if(by == 0x50) { + if(!m_config.isDataValTrace()) + { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (store failed) - not tracing data values."); + } + m_curr_packet.SetType(ETM3_PKT_STORE_FAIL); + SendPacket(); + } + // OoO placeholder 0b01x1xx00 + else if((by & 0xD3 )== 0x50) { + m_curr_packet.SetType(ETM3_PKT_OOO_ADDR_PLC); + if(!m_config.isDataTrace()) + { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (out of order placeholder) - not tracing data."); + } + // expecting data address if flagged and address tracing enabled (flag can be set even if address tracing disabled) + m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace(); + m_bFoundDataAddress = false; + m_curr_packet.SetDataOOOTag((by >> 2) & 0x3); + if(!m_bExpectingDataAddress) { + SendPacket(); + } + } + // vmid 0b00111100 + else if(by == 0x3c) { + m_curr_packet.SetType(ETM3_PKT_VMID); + } + else + { + m_curr_packet.SetErrType(ETM3_PKT_RESERVED); + throwPacketHeaderErr("Packet header reserved encoding"); + } + } + // normal data 0b00x0xx10 + else if((by & 0xD3 )== 0x02) { + uint8_t size = ((by & 0x0C) >> 2); + if(!m_config.isDataTrace()) { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (normal data) - not tracing data."); + } + m_curr_packet.SetType(ETM3_PKT_NORM_DATA); + m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace(); + m_bFoundDataAddress = false; + + // set this with the data bytes expected this packet, plus the header byte. + m_bytesExpectedThisPkt = (short)( 1 + ((size == 3) ? 4 : size)); + if(!m_bExpectingDataAddress && (m_bytesExpectedThisPkt == 1)) { + // single byte data packet, value = 0; + m_curr_packet.SetDataValue(0); + SendPacket(); + } + + } + // data suppressed 0b01100010 + else if(by == 0x62) { + if(!m_config.isDataTrace()) + { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (data suppressed) - not tracing data."); + } + m_curr_packet.SetType(ETM3_PKT_DATA_SUPPRESSED); + SendPacket(); + } + // value not traced 0b011x1010 + else if((by & 0xEF )== 0x6A) { + if(!m_config.isDataTrace()) { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (value not traced) - not tracing data."); + } + m_curr_packet.SetType(ETM3_PKT_VAL_NOT_TRACED); + m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace(); + m_bFoundDataAddress = false; + if(!m_bExpectingDataAddress) { + SendPacket(); + } + } + // ignore 0b01100110 + else if(by == 0x66) { + m_curr_packet.SetType(ETM3_PKT_IGNORE); + SendPacket(); + } + // context ID 0b01101110 + else if(by == 0x6E) { + m_curr_packet.SetType(ETM3_PKT_CONTEXT_ID); + m_bytesExpectedThisPkt = (short)(1 + m_config.CtxtIDBytes()); + } + // exception return 0b01110110 + else if(by == 0x76) { + m_curr_packet.SetType(ETM3_PKT_EXCEPTION_EXIT); + SendPacket(); + } + // exception entry 0b01111110 + else if(by == 0x7E) { + m_curr_packet.SetType(ETM3_PKT_EXCEPTION_ENTRY); + SendPacket(); + } + // timestamp packet 0b01000x10 + else if((by & 0xFB )== 0x42) + { + m_curr_packet.SetType(ETM3_PKT_TIMESTAMP); + } + else + { + m_curr_packet.SetErrType(ETM3_PKT_RESERVED); + throwPacketHeaderErr("Packet header reserved encoding."); + } + return OCSD_OK; +} + +ocsd_err_t EtmV3PktProcImpl::processPayloadByte(uint8_t by) +{ + bool bTopBitSet = false; + bool packetDone = false; + + // pop byte into buffer + m_currPacketData.push_back(by); + + switch(m_curr_packet.getType()) { + default: + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_PKT_INTERP_FAIL,m_packet_index,m_chanIDCopy,"Interpreter failed - cannot process payload for unexpected or unsupported packet."); + break; + + case ETM3_PKT_BRANCH_ADDRESS: + bTopBitSet = (bool)((by & 0x80) == 0x80); + if(m_config.isAltBranch()) // etm implements the alternative branch encoding + { + if(!bTopBitSet) // no continuation + { + if(!m_BranchPktNeedsException) + { + if((by & 0xC0) == 0x40) + m_BranchPktNeedsException = true; + else + packetDone = true; + } + else + packetDone = true; + } + } + else + { + // standard encoding < 5 bytes cannot be exception branch + // 5 byte packet + if(m_currPacketData.size() == 5) { + if((by & 0xC0) == 0x40) + // expecting follow up byte(s) + m_BranchPktNeedsException = true; + else + packetDone = true; + } + // waiting for exception packet + else if(m_BranchPktNeedsException){ + if(!bTopBitSet) + packetDone = true; + } + else { + // not exception - end of packets + if(!bTopBitSet) + packetDone = true; + } + } + + if(packetDone) + { + OnBranchAddress(); + SendPacket(); + } + break; + + case ETM3_PKT_BRANCH_OR_BYPASS_EOT: + /* + if((by != 0x00) || ( m_currPacketData.size() == ETM3_PKT_BUFF_SIZE)) { + if(by == 0x80 && ( m_currPacketData.size() == 7)) { + // branch 0 followed by A-sync! + m_currPacketData.size() = 1; + m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS; + SendPacket(); + memcpy(m_currPacketData, &m_currPacketData[1],6); + m_currPacketData.size() = 6; + m_curr_packet.SetType(ETM3_PKT_A_SYNC; + SendPacket(); + } + else if( m_currPacketData.size() == 2) { + // branch followed by another byte + m_currPacketData.size() = 1; + m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS; + SendPacket(); + ProcessHeaderByte(by); + } + else if(by == 0x00) { + // end of buffer...output something - incomplete / unknown. + SendPacket(); + } + else if(by == 0x01) { + // 0x01 - 0x00 x N - 0x1 + // end of buffer...output something + m_currPacketData.size()--; + SendPacket(); + ProcessHeaderByte(by); + } + else { + // branch followed by unknown sequence + int oldidx = m_currPacketData.size(); + m_currPacketData.size() = 1; + m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS; + SendPacket(); + oldidx--; + memcpy(m_currPacketData, &m_currPacketData[1],oldidx); + m_currPacketData.size() = oldidx; + SendBadPacket("ERROR : unknown sequence"); + } + }*/ + // just ignore zeros + break; + + + + case ETM3_PKT_A_SYNC: + if(by == 0x00) { + if( m_currPacketData.size() > 5) { + // extra 0, need to lose one + + // set error type + m_curr_packet.SetErrType(ETM3_PKT_BAD_SEQUENCE); + // mark extra 0 for sending, retain remaining, restart in A-SYNC processing mode. + setBytesPartPkt(1,PROC_DATA,ETM3_PKT_A_SYNC); + throwMalformedPacketErr("A-Sync ?: Extra 0x00 in sequence"); + } + } + else if((by == 0x80) && ( m_currPacketData.size() == 6)) { + SendPacket(); + m_bStreamSync = true; + } + else + { + m_curr_packet.SetErrType(ETM3_PKT_BAD_SEQUENCE); + m_bytesProcessed--; // remove the last byte from the number processed to re-try + m_currPacketData.pop_back(); // remove the last byte processed from the packet + throwMalformedPacketErr("A-Sync ? : Unexpected byte in sequence"); + } + break; + + case ETM3_PKT_CYCLE_COUNT: + bTopBitSet = ((by & 0x80) == 0x80); + if(!bTopBitSet || ( m_currPacketData.size() >= 6)) { + m_currPktIdx = 1; + m_curr_packet.SetCycleCount(extractCycleCount()); + SendPacket(); + } + break; + + case ETM3_PKT_I_SYNC_CYCLE: + if(!m_bIsync_got_cycle_cnt) { + if(((by & 0x80) != 0x80) || ( m_currPacketData.size() >= 6)) { + m_bIsync_got_cycle_cnt = true; + } + break; + } + // fall through when we have the first non-cycle count byte + case ETM3_PKT_I_SYNC: + if(m_bytesExpectedThisPkt == 0) { + int cycCountBytes = m_currPacketData.size() - 2; + int ctxtIDBytes = m_config.CtxtIDBytes(); + // bytes expected = header + n x ctxt id + info byte + 4 x addr; + if(m_config.isInstrTrace()) + m_bytesExpectedThisPkt = cycCountBytes + 6 + ctxtIDBytes; + else + m_bytesExpectedThisPkt = 2 + ctxtIDBytes; + m_IsyncInfoIdx = 1 + cycCountBytes + ctxtIDBytes; + } + if(( m_currPacketData.size() - 1) == (unsigned)m_IsyncInfoIdx) { + m_bIsync_get_LSiP_addr = ((m_currPacketData[m_IsyncInfoIdx] & 0x80) == 0x80); + } + + // if bytes collected >= bytes expected + if( m_currPacketData.size() >= m_bytesExpectedThisPkt) { + // if we still need the LSip Addr, then this is not part of the expected + // count as we have no idea how long it is + if(m_bIsync_get_LSiP_addr) { + if((by & 0x80) != 0x80) { + OnISyncPacket(); + } + } + else { + // otherwise, output now + OnISyncPacket(); + } + } + break; + + case ETM3_PKT_NORM_DATA: + if(m_bExpectingDataAddress && !m_bFoundDataAddress) { + // look for end of continuation bits + if((by & 0x80) != 0x80) { + m_bFoundDataAddress = true; + // add on the bytes we have found for the address to the expected data bytes + m_bytesExpectedThisPkt += ( m_currPacketData.size() - 1); + } + else + break; + } + // found any data address we were expecting + else if(m_bytesExpectedThisPkt == m_currPacketData.size()) { + m_currPktIdx = 1; + if(m_bExpectingDataAddress) + { + uint8_t bits = 0, beVal = 0; + bool updateBE = false; + uint32_t dataAddress = extractDataAddress(bits,updateBE,beVal); + m_curr_packet.UpdateDataAddress(dataAddress, bits); + if(updateBE) + m_curr_packet.UpdateDataEndian(beVal); + } + m_curr_packet.SetDataValue(extractDataValue((m_currPacketData[0] >> 2) & 0x3)); + SendPacket(); + } + break; + + case ETM3_PKT_OOO_DATA: + if(m_bytesExpectedThisPkt == m_currPacketData.size()) + { + m_currPktIdx = 1; + m_curr_packet.SetDataValue(extractDataValue((m_currPacketData[0] >> 2) & 0x3)); + m_curr_packet.SetDataOOOTag((m_currPacketData[0] >> 5) & 0x3); + SendPacket(); + } + if(m_bytesExpectedThisPkt < m_currPacketData.size()) + throwMalformedPacketErr("Malformed out of order data packet."); + break; + + // both these expect an address only. + case ETM3_PKT_VAL_NOT_TRACED: + case ETM3_PKT_OOO_ADDR_PLC: // we set the tag earlier. + if(m_bExpectingDataAddress) { + // look for end of continuation bits + if((by & 0x80) != 0x80) { + uint8_t bits = 0, beVal = 0; + bool updateBE = false; + m_currPktIdx = 1; + uint32_t dataAddress = extractDataAddress(bits,updateBE,beVal); + m_curr_packet.UpdateDataAddress(dataAddress, bits); + if(updateBE) + m_curr_packet.UpdateDataEndian(beVal); + SendPacket(); + } + } + break; + + case ETM3_PKT_CONTEXT_ID: + if(m_bytesExpectedThisPkt == m_currPacketData.size()) { + m_currPktIdx = 1; + m_curr_packet.UpdateContextID(extractCtxtID()); + SendPacket(); + } + if(m_bytesExpectedThisPkt < m_currPacketData.size()) + throwMalformedPacketErr("Malformed context id packet."); + break; + + case ETM3_PKT_TIMESTAMP: + if((by & 0x80) != 0x80) { + uint8_t tsBits = 0; + m_currPktIdx = 1; + uint64_t tsVal = extractTimestamp(tsBits); + m_curr_packet.UpdateTimestamp(tsVal,tsBits); + SendPacket(); + } + break; + + case ETM3_PKT_VMID: + // single byte payload + m_curr_packet.UpdateVMID(by); + SendPacket(); + break; + } + + return OCSD_OK; +} + +// extract branch address packet at current location in packet data. +void EtmV3PktProcImpl::OnBranchAddress() +{ + int validBits = 0; + ocsd_vaddr_t partAddr = 0; + + partAddr = extractBrAddrPkt(validBits); + m_curr_packet.UpdateAddress(partAddr,validBits); +} + +uint32_t EtmV3PktProcImpl::extractBrAddrPkt(int &nBitsOut) +{ + static int addrshift[] = { + 2, // ARM_ISA + 1, // thumb + 1, // thumb EE + 0 // jazelle + }; + + static uint8_t addrMask[] = { // byte 5 masks + 0x7, // ARM_ISA + 0xF, // thumb + 0xF, // thumb EE + 0x1F // jazelle + }; + + static int addrBits[] = { // address bits in byte 5 + 3, // ARM_ISA + 4, // thumb + 4, // thumb EE + 5 // jazelle + }; + + static ocsd_armv7_exception exceptionTypeARMdeprecated[] = { + Excp_Reset, + Excp_IRQ, + Excp_Reserved, + Excp_Reserved, + Excp_Jazelle, + Excp_FIQ, + Excp_AsyncDAbort, + Excp_DebugHalt + }; + + bool CBit = true; + int bytecount = 0; + int bitcount = 0; + int shift = 0; + int isa_idx = 0; + uint32_t value = 0; + uint8_t addrbyte; + bool byte5AddrUpdate = false; + + while(CBit && bytecount < 4) + { + checkPktLimits(); + addrbyte = m_currPacketData[m_currPktIdx++]; + CBit = (bool)((addrbyte & 0x80) != 0); + shift = bitcount; + if(bytecount == 0) + { + addrbyte &= ~0x81; + bitcount+=6; + addrbyte >>= 1; + } + else + { + // bytes 2-4, no continuation, alt format uses bit 6 to indicate following exception bytes + if(m_config.isAltBranch() && !CBit) + { + // last compressed address byte with exception + if((addrbyte & 0x40) == 0x40) + extractExceptionData(); + addrbyte &= 0x3F; + bitcount+=6; + } + else + { + addrbyte &= 0x7F; + bitcount+=7; + } + } + value |= ((uint32_t)addrbyte) << shift; + bytecount++; + } + + // byte 5 - indicates following exception bytes (or not!) + if(CBit) + { + checkPktLimits(); + addrbyte = m_currPacketData[m_currPktIdx++]; + + // deprecated original byte 5 encoding - ARM state exception only + if(addrbyte & 0x80) + { + uint8_t excep_num = (addrbyte >> 3) & 0x7; + m_curr_packet.UpdateISA(ocsd_isa_arm); + m_curr_packet.SetException(exceptionTypeARMdeprecated[excep_num], excep_num, (addrbyte & 0x40) ? true : false,m_config.isV7MArch()); + } + else + // normal 5 byte branch, or uses exception bytes. + { + // go grab the exception bits to correctly interpret the ISA state + if((addrbyte & 0x40) == 0x40) + extractExceptionData(); + + if((addrbyte & 0xB8) == 0x08) + m_curr_packet.UpdateISA(ocsd_isa_arm); + else if ((addrbyte & 0xB0) == 0x10) + m_curr_packet.UpdateISA(m_curr_packet.AltISA() ? ocsd_isa_tee : ocsd_isa_thumb2); + else if ((addrbyte & 0xA0) == 0x20) + m_curr_packet.UpdateISA(ocsd_isa_jazelle); + else + throwMalformedPacketErr("Malformed Packet - Unknown ISA."); + } + + byte5AddrUpdate = true; // need to update the address value from byte 5 + } + + // figure out the correct ISA shifts for the address bits + switch(m_curr_packet.ISA()) + { + case ocsd_isa_thumb2: isa_idx = 1; break; + case ocsd_isa_tee: isa_idx = 2; break; + case ocsd_isa_jazelle: isa_idx = 3; break; + default: break; + } + + if(byte5AddrUpdate) + { + value |= ((uint32_t)(addrbyte & addrMask[isa_idx])) << bitcount; + bitcount += addrBits[isa_idx]; + } + + // finally align according to ISA + shift = addrshift[isa_idx]; + value <<= shift; + bitcount += shift; + + nBitsOut = bitcount; + return value; +} + +// extract exception data from bytes after address. +void EtmV3PktProcImpl::extractExceptionData() +{ + static const ocsd_armv7_exception exceptionTypesStd[] = { + Excp_NoException, Excp_DebugHalt, Excp_SMC, Excp_Hyp, + Excp_AsyncDAbort, Excp_Jazelle, Excp_Reserved, Excp_Reserved, + Excp_Reset, Excp_Undef, Excp_SVC, Excp_PrefAbort, + Excp_SyncDataAbort, Excp_Generic, Excp_IRQ, Excp_FIQ + }; + + static const ocsd_armv7_exception exceptionTypesCM[] = { + Excp_NoException, Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn, + Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn, + Excp_CMIRQn, Excp_CMUsageFault, Excp_CMNMI, Excp_SVC, + Excp_CMDebugMonitor, Excp_CMMemManage, Excp_CMPendSV, Excp_CMSysTick, + Excp_Reserved, Excp_Reset, Excp_Reserved, Excp_CMHardFault, + Excp_Reserved, Excp_CMBusFault, Excp_Reserved, Excp_Reserved + }; + + uint16_t exceptionNum = 0; + ocsd_armv7_exception excep_type = Excp_Reserved; + int resume = 0; + int irq_n = 0; + bool cancel_prev_instr = 0; + bool Byte2 = false; + + checkPktLimits(); + + //**** exception info Byte 0 + uint8_t dataByte = m_currPacketData[m_currPktIdx++]; + + m_curr_packet.UpdateNS(dataByte & 0x1); + exceptionNum |= (dataByte >> 1) & 0xF; + cancel_prev_instr = (dataByte & 0x20) ? true : false; + m_curr_packet.UpdateAltISA(((dataByte & 0x40) != 0) ? 1 : 0); + + //** another byte? + if(dataByte & 0x80) + { + checkPktLimits(); + dataByte = m_currPacketData[m_currPktIdx++]; + + if(dataByte & 0x40) + Byte2 = true; //** immediate info byte 2, skipping 1 + else + { + //**** exception info Byte 1 + if(m_config.isV7MArch()) + { + exceptionNum |= ((uint16_t)(dataByte & 0x1F)) << 4; + } + m_curr_packet.UpdateHyp(dataByte & 0x20 ? 1 : 0); + + if(dataByte & 0x80) + { + checkPktLimits(); + dataByte = m_currPacketData[m_currPktIdx++]; + Byte2 = true; + } + } + //**** exception info Byte 2 + if(Byte2) + { + resume = dataByte & 0xF; + } + } + + // set the exception type - according to the number and core profile + if(m_config.isV7MArch()) + { + exceptionNum &= 0x1FF; + if(exceptionNum < 0x018) + excep_type= exceptionTypesCM[exceptionNum]; + else + excep_type = Excp_CMIRQn; + + if(excep_type == Excp_CMIRQn) + { + if(exceptionNum > 0x018) + irq_n = exceptionNum - 0x10; + else if(exceptionNum == 0x008) + irq_n = 0; + else + irq_n = exceptionNum; + } + } + else + { + exceptionNum &= 0xF; + excep_type = exceptionTypesStd[exceptionNum]; + } + m_curr_packet.SetException(excep_type, exceptionNum, cancel_prev_instr,m_config.isV7MArch(), irq_n,resume); +} + +void EtmV3PktProcImpl::checkPktLimits() +{ + // index running off the end of the packet means a malformed packet. + if(m_currPktIdx >= m_currPacketData.size()) + throwMalformedPacketErr("Malformed Packet - oversized packet."); +} + +uint32_t EtmV3PktProcImpl::extractCtxtID() +{ + uint32_t ctxtID = 0; + int size = m_config.CtxtIDBytes(); + + // check we have enough data + if((m_currPktIdx + size) > m_currPacketData.size()) + throwMalformedPacketErr("Too few bytes to extract context ID."); + + switch(size) + { + case 1: + ctxtID = (uint32_t)m_currPacketData[m_currPktIdx]; + m_currPktIdx++; + break; + + case 2: + ctxtID = (uint32_t)m_currPacketData[m_currPktIdx] + | ((uint32_t)m_currPacketData[m_currPktIdx+1]) << 8; + m_currPktIdx+=2; + break; + + case 4: + ctxtID = (uint32_t)m_currPacketData[m_currPktIdx] + | ((uint32_t)m_currPacketData[m_currPktIdx+1]) << 8 + | ((uint32_t)m_currPacketData[m_currPktIdx+2]) << 16 + | ((uint32_t)m_currPacketData[m_currPktIdx+3]) << 24; + m_currPktIdx+=4; + break; + } + return ctxtID; +} + +uint64_t EtmV3PktProcImpl::extractTimestamp(uint8_t &tsBits) +{ + uint64_t ts = 0; + unsigned tsMaxBytes = m_config.TSPkt64() ? 9 : 7; + unsigned tsCurrBytes = 0; + bool bCont = true; + uint8_t mask = 0x7F; + uint8_t last_mask = m_config.TSPkt64() ? 0xFF : 0x3F; + uint8_t ts_iter_bits = 7; + uint8_t ts_last_iter_bits = m_config.TSPkt64() ? 8 : 6; + uint8_t currByte; + tsBits = 0; + + while((tsCurrBytes < tsMaxBytes) && bCont) + { + if(m_currPacketData.size() < (m_currPktIdx + tsCurrBytes + 1)) + throwMalformedPacketErr("Insufficient bytes to extract timestamp."); + + currByte = m_currPacketData[m_currPktIdx+tsCurrBytes]; + ts |= ((uint64_t)(currByte & mask)) << (7 * tsCurrBytes); + tsCurrBytes++; + tsBits += ts_iter_bits; + bCont = ((0x80 & currByte) == 0x80); + if(tsCurrBytes == (tsMaxBytes - 1)) + { + mask = last_mask; + ts_iter_bits = ts_last_iter_bits; + } + } + m_currPktIdx += tsCurrBytes; + return ts; +} + + +uint32_t EtmV3PktProcImpl::extractDataAddress(uint8_t &bits, bool &updateBE, uint8_t &beVal) +{ + uint32_t dataAddr = 0; + int bytesIdx = 0; + bool bCont = true; + uint8_t currByte = 0; + + updateBE = false; + bits = 0; + + while(bCont) + { + checkPktLimits(); + currByte = m_currPacketData[m_currPktIdx++] & ((bytesIdx == 4) ? 0x0F : 0x7F); + dataAddr |= (((uint32_t)currByte) << (bytesIdx * 7)); + bCont = ((currByte & 0x80) == 0x80); + if(bytesIdx == 4) + { + bits += 4; + updateBE = true; + beVal = ((currByte >> 4) & 0x1); + bCont = false; + } + else + bits+=7; + bytesIdx++; + } + return dataAddr; +} + +uint32_t EtmV3PktProcImpl::extractDataValue(const int dataByteSize) +{ + static int bytesReqTable[] = { 0,1,2,4 }; + + uint32_t dataVal = 0; + int bytesUsed = 0; + int bytesReq = bytesReqTable[dataByteSize & 0x3]; + while(bytesUsed < bytesReq) + { + checkPktLimits(); + dataVal |= (((uint32_t)m_currPacketData[m_currPktIdx++]) << (bytesUsed * 8)); + bytesUsed++; + } + return dataVal; +} + + +uint32_t EtmV3PktProcImpl::extractCycleCount() +{ + uint32_t cycleCount = 0; + int byteIdx = 0; + uint8_t mask = 0x7F; + bool bCond = true; + uint8_t currByte = 0; + + while(bCond) + { + checkPktLimits(); + currByte = m_currPacketData[m_currPktIdx++]; + cycleCount |= ((uint32_t)(currByte & mask)) << (7 * byteIdx); + bCond = ((currByte & 0x80) == 0x80); + byteIdx++; + + if(byteIdx == 4) + mask = 0x0F; + + if(byteIdx == 5) + bCond = false; + } + return cycleCount; +} + +void EtmV3PktProcImpl::OnISyncPacket() +{ + uint8_t iSyncInfoByte = 0; + uint32_t instrAddr = 0, LSiPAddr = 0; + int LSiPBits = 0; + uint8_t T = 0, J = 0, AltISA = 0; + + m_currPktIdx = 1; + if(m_bIsync_got_cycle_cnt) + { + m_curr_packet.SetCycleCount(extractCycleCount()); + m_curr_packet.SetISyncHasCC(); + } + + if(m_config.CtxtIDBytes() != 0) + { + m_curr_packet.UpdateContextID(extractCtxtID()); + } + + // extract context info + iSyncInfoByte = m_currPacketData[m_currPktIdx++]; + m_curr_packet.SetISyncReason((ocsd_iSync_reason)((iSyncInfoByte >> 5) & 0x3)); + J = (iSyncInfoByte >> 4) & 0x1; + AltISA = m_config.MinorRev() >= 3 ? (iSyncInfoByte >> 2) & 0x1 : 0; + m_curr_packet.UpdateNS((iSyncInfoByte >> 3) & 0x1); + if(m_config.hasVirtExt()) + m_curr_packet.UpdateHyp((iSyncInfoByte >> 1) & 0x1); + + // main address value - full 32 bit address value + if(m_config.isInstrTrace()) + { + for(int i = 0; i < 4; i++) + instrAddr |= ((uint32_t)m_currPacketData[m_currPktIdx++]) << (8*i); + T = instrAddr & 0x1; // get the T bit. + instrAddr &= ~0x1; // remove from address. + m_curr_packet.UpdateAddress(instrAddr,32); + + // enough data now to set the instruction set. + ocsd_isa currISA = ocsd_isa_arm; + if(J) + currISA = ocsd_isa_jazelle; + else if(T) + currISA = AltISA ? ocsd_isa_tee : ocsd_isa_thumb2; + m_curr_packet.UpdateISA(currISA); + + // possible follow up address value - rarely uses unless trace enabled during + // load and store instruction executing on top of other instruction. + if(m_bIsync_get_LSiP_addr) + { + LSiPAddr = extractBrAddrPkt(LSiPBits); + // follow up address value is compressed relative to the main value + // we store this in the data address value temporarily. + m_curr_packet.UpdateDataAddress(instrAddr,32); + m_curr_packet.UpdateDataAddress(LSiPAddr,LSiPBits); + } + } + else + m_curr_packet.SetISyncNoAddr(); + + SendPacket(); // mark ready to send +} + +/* End of File trc_pkt_proc_etmv3_impl.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h b/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h new file mode 100644 index 000000000000..a8e4fd1b5373 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h @@ -0,0 +1,175 @@ +/* + * \file trc_pkt_proc_etmv3_impl.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED +#define ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED + +#include "opencsd/etmv3/trc_pkt_proc_etmv3.h" +#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h" +#include "opencsd/etmv3/trc_pkt_elem_etmv3.h" + +#define MAX_PACKET_SIZE 32 +#define ASYNC_SIZE 6 + +class EtmV3PktProcImpl +{ +public: + EtmV3PktProcImpl(); + ~EtmV3PktProcImpl(); + + void Initialise(TrcPktProcEtmV3 *p_interface); + + ocsd_err_t Configure(const EtmV3Config *p_config); + + + ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + ocsd_datapath_resp_t onEOT(); + ocsd_datapath_resp_t onReset(); + ocsd_datapath_resp_t onFlush(); + const bool isBadPacket() const; + +protected: + typedef enum _process_state { + WAIT_SYNC, + PROC_HDR, + PROC_DATA, + SEND_PKT, + PROC_ERR, + } process_state; + + process_state m_process_state; + + + void InitPacketState(); // clear current packet state. + void InitProcessorState(); // clear all previous process state + + // byte processing + + uint32_t waitForSync(const uint32_t dataBlockSize, const uint8_t *pDataBlock); //!< look for sync, return none-sync bytes processed. + ocsd_err_t processHeaderByte(uint8_t by); + ocsd_err_t processPayloadByte(uint8_t by); + + // packet handling - main routines + void OnBranchAddress(); + void OnISyncPacket(); + uint32_t extractCtxtID(); + uint64_t extractTimestamp(uint8_t &tsBits); + uint32_t extractDataAddress(uint8_t &bits, bool &updateBE, uint8_t &beVal); + uint32_t extractDataValue(const int dataByteSize); + uint32_t extractCycleCount(); + + // packet handling - helper routines + uint32_t extractBrAddrPkt(int &nBitsOut); + void extractExceptionData(); + void checkPktLimits(); + void setBytesPartPkt(const int numBytes, const process_state nextState, const ocsd_etmv3_pkt_type nextType); // set first n bytes from current packet to be sent via alt packet. + + // packet output + void SendPacket(); // mark state for packet output + ocsd_datapath_resp_t outputPacket(); // output a packet + + // bad packets + void throwMalformedPacketErr(const char *pszErrMsg); + void throwPacketHeaderErr(const char *pszErrMsg); + void throwUnsupportedErr(const char *pszErrMsg); + + uint32_t m_bytesProcessed; // bytes processed by the process data routine (index into input buffer) + std::vector m_currPacketData; // raw data + uint32_t m_currPktIdx; // index into packet when expanding + EtmV3TrcPacket m_curr_packet; // expanded packet + + std::vector m_partPktData; // raw data when we need to split a packet. + bool m_bSendPartPkt; // mark the part packet as the one we send. + process_state m_post_part_pkt_state; // state to set after part packet set + ocsd_etmv3_pkt_type m_post_part_pkt_type; // reset the packet type. + + // process state + bool m_bStreamSync; //!< true if we have synced this stream + bool m_bStartOfSync; //!< true if we have a start of sync. + + // packet state + uint32_t m_bytesExpectedThisPkt; // used by some of the variable packet length types. + bool m_BranchPktNeedsException; + bool m_bIsync_got_cycle_cnt; + bool m_bIsync_get_LSiP_addr; + int m_IsyncInfoIdx; + bool m_bExpectingDataAddress; + bool m_bFoundDataAddress; + + ocsd_trc_index_t m_packet_index; // index of the start of the current packet + ocsd_trc_index_t m_packet_curr_byte_index; // index of the current byte. + + bool m_isInit; + TrcPktProcEtmV3 *m_interface; /**< The interface to the other decode components */ + + EtmV3Config m_config; + + uint8_t m_chanIDCopy; +}; + + +inline void EtmV3PktProcImpl::SendPacket() +{ + m_process_state = SEND_PKT; +} + +inline void EtmV3PktProcImpl::throwMalformedPacketErr(const char *pszErrMsg) +{ + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,m_chanIDCopy,pszErrMsg); +} + +inline void EtmV3PktProcImpl::throwPacketHeaderErr(const char *pszErrMsg) +{ + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,m_chanIDCopy,pszErrMsg); +} + +inline void EtmV3PktProcImpl::throwUnsupportedErr(const char *pszErrMsg) +{ + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_packet_index,m_chanIDCopy,pszErrMsg); +} + + +inline const bool EtmV3PktProcImpl::isBadPacket() const +{ + return m_curr_packet.isBadPacket(); +} + + +#endif // ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED + +/* End of File trc_pkt_proc_etmv3_impl.h */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp b/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp new file mode 100644 index 000000000000..7db0fa61f963 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp @@ -0,0 +1,109 @@ +/* + * \file trc_cmp_cfg_etmv4.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/etmv4/trc_cmp_cfg_etmv4.h" + +EtmV4Config::EtmV4Config() +{ + m_cfg.reg_idr0 = 0x28000EA1; + m_cfg.reg_idr1 = 0x4100F403; + m_cfg.reg_idr2 = 0x00000488; + m_cfg.reg_idr8 = 0; + m_cfg.reg_idr9 = 0; + m_cfg.reg_idr10 = 0; + m_cfg.reg_idr11 = 0; + m_cfg.reg_idr12 = 0; + m_cfg.reg_idr13 = 0; + m_cfg.reg_configr = 0xC1; + m_cfg.reg_traceidr = 0; + m_cfg.arch_ver = ARCH_V7; + m_cfg.core_prof = profile_CortexA; + + PrivateInit(); +} + +EtmV4Config::EtmV4Config(const ocsd_etmv4_cfg *cfg_regs) +{ + m_cfg = *cfg_regs; + PrivateInit(); +} + +EtmV4Config & EtmV4Config::operator=(const ocsd_etmv4_cfg *p_cfg) +{ + m_cfg = *p_cfg; + PrivateInit(); + return *this; +} + +void EtmV4Config::PrivateInit() +{ + m_QSuppCalc = false; + m_QSuppFilter = false; + m_QSuppType = Q_NONE; + m_VMIDSzCalc = false; + m_VMIDSize = 0; + m_condTraceCalc = false; + m_CondTrace = COND_TR_DIS; +} + +void EtmV4Config::CalcQSupp() +{ + QSuppType qtypes[] = { + Q_NONE, + Q_ICOUNT_ONLY, + Q_NO_ICOUNT_ONLY, + Q_FULL + }; + uint8_t Qsupp = (m_cfg.reg_idr0 >> 15) & 0x3; + m_QSuppType = qtypes[Qsupp]; + m_QSuppFilter = (bool)((m_cfg.reg_idr0 & 0x4000) == 0x4000) && (m_QSuppType != Q_NONE); + m_QSuppCalc = true; +} + +void EtmV4Config::CalcVMIDSize() +{ + uint32_t vmidszF = (m_cfg.reg_idr2 >> 10) & 0x1F; + if(vmidszF == 1) + m_VMIDSize = 8; + else if(MinVersion() > 0) + { + if(vmidszF == 2) + m_VMIDSize = 16; + else if(vmidszF == 4) + m_VMIDSize = 32; + } + m_VMIDSzCalc = true; +} + +/* End of File trc_cmp_cfg_etmv4.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_etmv4_stack_elem.cpp b/contrib/opencsd/decoder/source/etmv4/trc_etmv4_stack_elem.cpp new file mode 100644 index 000000000000..ace0ac932b76 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_etmv4_stack_elem.cpp @@ -0,0 +1,110 @@ +/* +* \file trc_etmv4_stack_elem.cpp +* \brief OpenCSD : ETMv4 decoder +* +* \copyright Copyright (c) 2017, 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. +*/ + +#include "opencsd/etmv4/trc_etmv4_stack_elem.h" + +/* implementation of P0 element stack in ETM v4 trace*/ +TrcStackElemParam *EtmV4P0Stack::createParamElemNoParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) +{ + std::vector params; + params.clear(); + return createParamElem(p0_type, isP0, root_pkt, root_index, params); +} + +TrcStackElemParam *EtmV4P0Stack::createParamElem(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const std::vector ¶ms) +{ + TrcStackElemParam *pElem = new (std::nothrow) TrcStackElemParam(p0_type, isP0, root_pkt, root_index); + if (pElem) + { + int param_idx = 0; + int params_to_fill = params.size(); + while ((param_idx < 4) && params_to_fill) + { + pElem->setParam(params[param_idx], param_idx); + param_idx++; + params_to_fill--; + } + push_front(pElem); + } + return pElem; +} + +TrcStackElemAtom *EtmV4P0Stack::createAtomElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const ocsd_pkt_atom &atom) +{ + TrcStackElemAtom *pElem = new (std::nothrow) TrcStackElemAtom(root_pkt, root_index); + if (pElem) + { + pElem->setAtom(atom); + push_front(pElem); + } + return pElem; +} + +TrcStackElemExcept *EtmV4P0Stack::createExceptElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const bool bSame, const uint16_t excepNum) +{ + TrcStackElemExcept *pElem = new (std::nothrow) TrcStackElemExcept(root_pkt, root_index); + if (pElem) + { + pElem->setExcepNum(excepNum); + pElem->setPrevSame(bSame); + push_front(pElem); + } + return pElem; +} + +TrcStackElemCtxt *EtmV4P0Stack::createContextElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_context_t &context) +{ + TrcStackElemCtxt *pElem = new (std::nothrow) TrcStackElemCtxt(root_pkt, root_index); + if (pElem) + { + pElem->setContext(context); + push_front(pElem); + } + return pElem; + +} + +TrcStackElemAddr *EtmV4P0Stack::createAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val) +{ + TrcStackElemAddr *pElem = new (std::nothrow) TrcStackElemAddr(root_pkt, root_index); + if (pElem) + { + pElem->setAddr(addr_val); + push_front(pElem); + } + return pElem; +} + +/* End of file trc_etmv4_stack_elem.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp b/contrib/opencsd/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp new file mode 100644 index 000000000000..865aacbdb2a5 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp @@ -0,0 +1,1121 @@ +/* + * \file trc_pkt_decode_etmv4i.cpp + * \brief OpenCSD : ETMv4 decoder + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/etmv4/trc_pkt_decode_etmv4i.h" + +#include "common/trc_gen_elem.h" + + +#define DCD_NAME "DCD_ETMV4" + +static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS = OCSD_OPFLG_PKTDEC_COMMON; + +TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I() + : TrcPktDecodeBase(DCD_NAME) +{ + initDecoder(); +} + +TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I(int instIDNum) + : TrcPktDecodeBase(DCD_NAME,instIDNum) +{ + initDecoder(); +} + +TrcPktDecodeEtmV4I::~TrcPktDecodeEtmV4I() +{ +} + +/*********************** implementation packet decoding interface */ + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bPktDone = false; + + while(!bPktDone) + { + switch (m_curr_state) + { + case NO_SYNC: + // output the initial not synced packet to the sink + m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); + resp = outputTraceElement(m_output_elem); + m_curr_state = WAIT_SYNC; + // fall through to check if the current packet is the async we are waiting for. + break; + + case WAIT_SYNC: + if(m_curr_packet_in->getType() == ETM4_PKT_I_ASYNC) + m_curr_state = WAIT_TINFO; + bPktDone = true; + break; + + case WAIT_TINFO: + m_need_ctxt = true; + m_need_addr = true; + if(m_curr_packet_in->getType() == ETM4_PKT_I_TRACE_INFO) + { + doTraceInfoPacket(); + m_curr_state = DECODE_PKTS; + m_return_stack.flush(); + } + bPktDone = true; + break; + + case DECODE_PKTS: + resp = decodePacket(bPktDone); // this may change the state to commit elem; + break; + + case COMMIT_ELEM: + resp = commitElements(bPktDone); // this will change the state to DECODE_PKTS once all elem committed. + break; + + } + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + m_flush_EOT = true; + resp = flushEOT(); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onReset() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + resetDecoder(); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onFlush() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // continue exception processing (can't go through processPacket as elements no longer on stack) + if(m_excep_proc != EXCEP_POP) + resp = processException(); + // continue ongoing output operations on comitted elements. + else if(m_curr_state == COMMIT_ELEM) + resp = processPacket(); + // continue flushing at end of trace + else if(m_flush_EOT) + resp = flushEOT(); + return resp; +} + +ocsd_err_t TrcPktDecodeEtmV4I::onProtocolConfig() +{ + ocsd_err_t err = OCSD_OK; + + // set some static config elements + m_CSID = m_config->getTraceID(); + m_max_spec_depth = m_config->MaxSpecDepth(); + m_p0_key_max = m_config->P0_Key_Max(); + m_cond_key_max_incr = m_config->CondKeyMaxIncr(); + + // set up static trace instruction decode elements + m_instr_info.dsb_dmb_waypoints = 0; + m_instr_info.pe_type.arch = m_config->archVersion(); + m_instr_info.pe_type.profile = m_config->coreProfile(); + + m_IASize64 = (m_config->iaSizeMax() == 64); + + if (m_config->enabledRetStack()) + { + m_return_stack.set_active(true); +#ifdef TRC_RET_STACK_DEBUG + m_return_stack.set_dbg_logger(this); +#endif + } + + // check config compatible with current decoder support level. + // at present no data trace, no spec depth, no return stack, no QE + // Remove these checks as support is added. + if(m_max_spec_depth != 0) + { + err = OCSD_ERR_HW_CFG_UNSUPP; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : None-zero speculation depth not supported")); + } + else if(m_config->enabledDataTrace()) + { + err = OCSD_ERR_HW_CFG_UNSUPP; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Data trace elements not supported")); + } + else if(m_config->enabledLSP0Trace()) + { + err = OCSD_ERR_HW_CFG_UNSUPP; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : LSP0 elements not supported.")); + } + else if(m_config->enabledCondITrace() != EtmV4Config::COND_TR_DIS) + { + err = OCSD_ERR_HW_CFG_UNSUPP; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace on conditional non-branch elements not supported.")); + } + else if(m_config->enabledQE()) + { + err = OCSD_ERR_HW_CFG_UNSUPP; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace using Q elements not supported.")); + } + return err; +} + + +/************* local decode methods */ +void TrcPktDecodeEtmV4I::initDecoder() +{ + // set the operational modes supported. + m_supported_op_flags = ETMV4_SUPPORTED_DECODE_OP_FLAGS; + + /* init elements that get set by config */ + m_max_spec_depth = 0; + m_p0_key_max = 0; + m_CSID = 0; + m_cond_key_max_incr = 0; + m_IASize64 = false; + + // reset decoder state to unsynced + resetDecoder(); +} + +void TrcPktDecodeEtmV4I::resetDecoder() +{ + m_curr_state = NO_SYNC; + m_timestamp = 0; + m_context_id = 0; + m_vmid_id = 0; + m_is_secure = true; + m_is_64bit = false; + m_cc_threshold = 0; + m_curr_spec_depth = 0; + m_p0_key = 0; + m_cond_c_key = 0; + m_cond_r_key = 0; + m_need_ctxt = true; + m_need_addr = true; + m_except_pending_addr = false; + m_mem_nacc_pending = false; + m_prev_overflow = false; + m_P0_stack.delete_all(); + m_output_elem.init(); + m_excep_proc = EXCEP_POP; + m_flush_EOT = false; +} + +// this function can output an immediate generic element if this covers the complete packet decode, +// or stack P0 and other elements for later processing on commit or cancel. +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::decodePacket(bool &Complete) +{ + bool bAllocErr = false; + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + Complete = true; + bool is_addr = false; + bool is_except = false; + + switch(m_curr_packet_in->getType()) + { + case ETM4_PKT_I_ASYNC: // nothing to do with this packet. + break; + + case ETM4_PKT_I_TRACE_INFO: + // skip subsequent TInfo packets. + m_return_stack.flush(); + break; + + case ETM4_PKT_I_TRACE_ON: + { + if (m_P0_stack.createParamElemNoParam(P0_TRC_ON, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + } + break; + + case ETM4_PKT_I_OVERFLOW: + { + if (m_P0_stack.createParamElemNoParam(P0_OVERFLOW, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + } + break; + + case ETM4_PKT_I_ATOM_F1: + case ETM4_PKT_I_ATOM_F2: + case ETM4_PKT_I_ATOM_F3: + case ETM4_PKT_I_ATOM_F4: + case ETM4_PKT_I_ATOM_F5: + case ETM4_PKT_I_ATOM_F6: + { + if (m_P0_stack.createAtomElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getAtom()) == 0) + bAllocErr = true; + else + m_curr_spec_depth += m_curr_packet_in->getAtom().num; + } + break; + + case ETM4_PKT_I_CTXT: + { + if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext()) == 0) + bAllocErr = true; + } + break; + + case ETM4_PKT_I_ADDR_MATCH: + { + etmv4_addr_val_t addr; + + addr.val = m_curr_packet_in->getAddrVal(); + addr.isa = m_curr_packet_in->getAddrIS(); + if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) + bAllocErr = true; + is_addr = true; + } + break; + + case ETM4_PKT_I_ADDR_CTXT_L_64IS0: + case ETM4_PKT_I_ADDR_CTXT_L_64IS1: + case ETM4_PKT_I_ADDR_CTXT_L_32IS0: + case ETM4_PKT_I_ADDR_CTXT_L_32IS1: + { + if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext()) == 0) + bAllocErr = true; + } + case ETM4_PKT_I_ADDR_L_32IS0: + case ETM4_PKT_I_ADDR_L_32IS1: + case ETM4_PKT_I_ADDR_L_64IS0: + case ETM4_PKT_I_ADDR_L_64IS1: + case ETM4_PKT_I_ADDR_S_IS0: + case ETM4_PKT_I_ADDR_S_IS1: + { + etmv4_addr_val_t addr; + + addr.val = m_curr_packet_in->getAddrVal(); + addr.isa = m_curr_packet_in->getAddrIS(); + if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) + bAllocErr = true; + is_addr = true; + } + break; + + // Exceptions + case ETM4_PKT_I_EXCEPT: + { + if (m_P0_stack.createExceptElem(m_curr_packet_in->getType(), m_index_curr_pkt, + (m_curr_packet_in->exception_info.addr_interp == 0x2), + m_curr_packet_in->exception_info.exceptionType) == 0) + bAllocErr = true; + else + { + m_except_pending_addr = true; // wait for following packets before marking for commit. + is_except = true; + } + } + break; + + case ETM4_PKT_I_EXCEPT_RTN: + { + // P0 element if V7M profile. + bool bV7MProfile = (m_config->archVersion() == ARCH_V7) && (m_config->coreProfile() == profile_CortexM); + if (m_P0_stack.createParamElemNoParam(P0_EXCEP_RET, bV7MProfile, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + } + break; + + // event trace + case ETM4_PKT_I_EVENT: + { + std::vector params = { 0 }; + params[0] = (uint32_t)m_curr_packet_in->event_val; + if (m_P0_stack.createParamElem(P0_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) + bAllocErr = true; + + } + break; + + /* cycle count packets */ + case ETM4_PKT_I_CCNT_F1: + case ETM4_PKT_I_CCNT_F2: + case ETM4_PKT_I_CCNT_F3: + { + std::vector params = { 0 }; + params[0] = m_curr_packet_in->getCC(); + if (m_P0_stack.createParamElem(P0_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) + bAllocErr = true; + + } + break; + + // timestamp + case ETM4_PKT_I_TIMESTAMP: + { + bool bTSwithCC = m_config->enabledCCI(); + uint64_t ts = m_curr_packet_in->getTS(); + std::vector params = { 0, 0, 0 }; + params[0] = (uint32_t)(ts & 0xFFFFFFFF); + params[1] = (uint32_t)((ts >> 32) & 0xFFFFFFFF); + if (bTSwithCC) + params[2] = m_curr_packet_in->getCC(); + if (m_P0_stack.createParamElem(P0_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) + bAllocErr = true; + + } + break; + + case ETM4_PKT_I_BAD_SEQUENCE: + resp = handleBadPacket("Bad byte sequence in packet."); + break; + + case ETM4_PKT_I_BAD_TRACEMODE: + resp = handleBadPacket("Invalid packet type for trace mode."); + break; + + case ETM4_PKT_I_RESERVED: + resp = handleBadPacket("Reserved packet header"); + break; + + /*** presently unsupported packets ***/ + /* conditional instruction tracing */ + case ETM4_PKT_I_COND_FLUSH: + case ETM4_PKT_I_COND_I_F1: + case ETM4_PKT_I_COND_I_F2: + case ETM4_PKT_I_COND_I_F3: + case ETM4_PKT_I_COND_RES_F1: + case ETM4_PKT_I_COND_RES_F2: + case ETM4_PKT_I_COND_RES_F3: + case ETM4_PKT_I_COND_RES_F4: + // speculation + case ETM4_PKT_I_CANCEL_F1: + case ETM4_PKT_I_CANCEL_F2: + case ETM4_PKT_I_CANCEL_F3: + case ETM4_PKT_I_COMMIT: + case ETM4_PKT_I_MISPREDICT: + case ETM4_PKT_I_DISCARD: + // data synchronisation markers + case ETM4_PKT_I_NUM_DS_MKR: + case ETM4_PKT_I_UNNUM_DS_MKR: + /* Q packets */ + case ETM4_PKT_I_Q: + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Unsupported packet type.")); + break; + + default: + // any other packet - bad packet error + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Unknown packet type.")); + break; + + } + + // we need to wait for following address after exception + // - work out if we have seen enough here... + if(m_except_pending_addr && !is_except) + { + m_except_pending_addr = false; //next packet has to be an address + // exception packet sequence complete + if(is_addr) + { + m_curr_spec_depth++; // exceptions are P0 elements so up the spec depth to commit if needed. + } + else + { + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Expected Address packet to follow exception packet.")); + } + } + + if(bAllocErr) + { + resp = OCSD_RESP_FATAL_SYS_ERR; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM,"Memory allocation error.")); + } + else if(m_curr_spec_depth > m_max_spec_depth) + { + // auto commit anything above max spec depth + // (this will auto commit anything if spec depth not supported!) + m_P0_commit = m_curr_spec_depth - m_max_spec_depth; + m_curr_state = COMMIT_ELEM; + Complete = false; // force the processing of the commit elements. + } + return resp; +} + +void TrcPktDecodeEtmV4I::doTraceInfoPacket() +{ + m_trace_info = m_curr_packet_in->getTraceInfo(); + m_cc_threshold = m_curr_packet_in->getCCThreshold(); + m_p0_key = m_curr_packet_in->getP0Key(); + m_curr_spec_depth = m_curr_packet_in->getCurrSpecDepth(); +} + +/* + * Walks through the element stack, processing from oldest element to the newest, + according to the number of P0 elements that need committing. + */ +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::commitElements(bool &Complete) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bPause = false; // pause commit operation + bool bPopElem = true; // do we remove the element from the stack (multi atom elements may need to stay!) + int num_commit_req = m_P0_commit; + + Complete = true; // assume we exit due to completion of commit operation + + TrcStackElem *pElem = 0; // stacked element pointer + + while(m_P0_commit && !bPause) + { + if(m_P0_stack.size() > 0) + { + pElem = m_P0_stack.back(); // get oldest element + + switch(pElem->getP0Type()) + { + // indicates a trace restart - beginning of trace or discontinuiuty + case P0_TRC_ON: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_TRACE_ON); + m_output_elem.trace_on_reason = m_prev_overflow ? TRACE_ON_OVERFLOW : TRACE_ON_NORMAL; + m_prev_overflow = false; + resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); + m_return_stack.flush(); + break; + + case P0_ADDR: + { + TrcStackElemAddr *pAddrElem = dynamic_cast(pElem); + m_return_stack.clear_pop_pending(); // address removes the need to pop the indirect address target from the stack + if(pAddrElem) + { + SetInstrInfoInAddrISA(pAddrElem->getAddr().val, pAddrElem->getAddr().isa); + m_need_addr = false; + } + } + break; + + case P0_CTXT: + { + TrcStackElemCtxt *pCtxtElem = dynamic_cast(pElem); + if(pCtxtElem) + { + etmv4_context_t ctxt = pCtxtElem->getContext(); + // check this is an updated context + if(ctxt.updated) + { + updateContext(pCtxtElem); + + m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); + } + } + } + break; + + case P0_EVENT: + { + TrcStackElemParam *pParamElem = dynamic_cast(pElem); + if(pParamElem) + resp = this->outputEvent(pParamElem); + } + break; + + case P0_TS: + { + TrcStackElemParam *pParamElem = dynamic_cast(pElem); + if(pParamElem) + resp = outputTS(pParamElem,false); + } + break; + + case P0_CC: + { + TrcStackElemParam *pParamElem = dynamic_cast(pElem); + if(pParamElem) + resp = outputCC(pParamElem); + } + break; + + case P0_TS_CC: + { + TrcStackElemParam *pParamElem = dynamic_cast(pElem); + if(pParamElem) + resp = outputTS(pParamElem,true); + } + break; + + case P0_OVERFLOW: + m_prev_overflow = true; + break; + + case P0_ATOM: + { + TrcStackElemAtom *pAtomElem = dynamic_cast(pElem); + + if(pAtomElem) + { + bool bContProcess = true; + while(!pAtomElem->isEmpty() && m_P0_commit && bContProcess) + { + ocsd_atm_val atom = pAtomElem->commitOldest(); + + // check if prev atom left us an indirect address target on the return stack + if ((resp = returnStackPop()) != OCSD_RESP_CONT) + break; + + // if address and context do instruction trace follower. + // otherwise skip atom and reduce committed elements + if(!m_need_ctxt && !m_need_addr) + { + resp = processAtom(atom,bContProcess); + } + m_P0_commit--; // mark committed + } + if(!pAtomElem->isEmpty()) + bPopElem = false; // don't remove if still atoms to process. + } + } + break; + + case P0_EXCEP: + // check if prev atom left us an indirect address target on the return stack + if ((resp = returnStackPop()) != OCSD_RESP_CONT) + break; + + m_excep_proc = EXCEP_POP; // set state in case we need to stop part way through + resp = processException(); // output trace + exception elements. + m_P0_commit--; + break; + + case P0_EXCEP_RET: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); + resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); + if(pElem->isP0()) // are we on a core that counts ERET as P0? + m_P0_commit--; + break; + } + + if(bPopElem) + m_P0_stack.delete_back(); // remove element from stack; + + // if response not continue, then break out of the loop. + if(!OCSD_DATA_RESP_IS_CONT(resp)) + { + bPause = true; + } + } + else + { + // too few elements for commit operation - decode error. + ocsd_trc_index_t err_idx = 0; + if(pElem) + err_idx = pElem->getRootIndex(); + + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_COMMIT_PKT_OVERRUN,err_idx,m_CSID,"Not enough elements to commit")); + bPause = true; + } + } + + // done all elements - need more packets. + if(m_P0_commit == 0) + m_curr_state = DECODE_PKTS; + + // reduce the spec depth by number of comitted elements + m_curr_spec_depth -= (num_commit_req-m_P0_commit); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::returnStackPop() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + ocsd_isa nextISA; + + if (m_return_stack.pop_pending()) + { + ocsd_vaddr_t popAddr = m_return_stack.pop(nextISA); + if (m_return_stack.overflow()) + { + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_RET_STACK_OVERFLOW, "Trace Return Stack Overflow.")); + } + else + { + m_instr_info.instr_addr = popAddr; + m_instr_info.isa = nextISA; + m_need_addr = false; + } + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::flushEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + if(m_flush_EOT) + { + TrcStackElem *pElem = 0; + while(OCSD_DATA_RESP_IS_CONT(resp) && (m_P0_stack.size() > 0)) + { + // scan for outstanding events, TS and CC, before any outstanding + // P0 commit elements. + pElem = m_P0_stack.back(); + + switch(pElem->getP0Type()) + { + // clear stack and stop + case P0_UNKNOWN: + case P0_ATOM: + case P0_TRC_ON: + case P0_EXCEP: + case P0_EXCEP_RET: + case P0_OVERFLOW: + m_P0_stack.delete_all(); + break; + + //skip + case P0_ADDR: + case P0_CTXT: + break; + + // output + case P0_EVENT: + { + TrcStackElemParam *pParamElem = dynamic_cast(pElem); + if(pParamElem) + resp = this->outputEvent(pParamElem); + } + break; + + case P0_TS: + { + TrcStackElemParam *pParamElem = dynamic_cast(pElem); + if(pParamElem) + resp = outputTS(pParamElem,false); + } + break; + + case P0_CC: + { + TrcStackElemParam *pParamElem = dynamic_cast(pElem); + if(pParamElem) + resp = outputCC(pParamElem); + } + break; + + case P0_TS_CC: + { + TrcStackElemParam *pParamElem = dynamic_cast(pElem); + if(pParamElem) + resp = outputTS(pParamElem,true); + } + break; + } + m_P0_stack.delete_back(); + } + + if(OCSD_DATA_RESP_IS_CONT(resp) && (m_P0_stack.size() == 0)) + { + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE); + resp = outputTraceElement(m_output_elem); + m_flush_EOT = false; + } + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputCC(TrcStackElemParam *pParamElem) +{ + m_output_elem.setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); + m_output_elem.cycle_count = pParamElem->getParam(0); + return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputTS(TrcStackElemParam *pParamElem, bool withCC) +{ + m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); + m_output_elem.timestamp = (uint64_t)(pParamElem->getParam(0)) | (((uint64_t)pParamElem->getParam(1)) << 32); + if(withCC) + m_output_elem.setCycleCount(pParamElem->getParam(2)); + return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputEvent(TrcStackElemParam *pParamElem) +{ + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT); + m_output_elem.trace_event.ev_type = EVENT_NUMBERED; + m_output_elem.trace_event.ev_number = pParamElem->getParam(0); + return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom, bool &bCont) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + TrcStackElem *pElem = m_P0_stack.back(); // get the atom element + bool bWPFound = false; + ocsd_err_t err; + bCont = true; + + err = traceInstrToWP(bWPFound); + if(err != OCSD_OK) + { + if(err == OCSD_ERR_UNSUPPORTED_ISA) + { + m_need_addr = true; + m_need_ctxt = true; + LogError(ocsdError(OCSD_ERR_SEV_WARN,err,pElem->getRootIndex(),m_CSID,"Warning: unsupported instruction set processing atom packet.")); + // wait for next context + return resp; + } + else + { + bCont = false; + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet.")); + return resp; + } + } + + if(bWPFound) + { + // save recorded next instuction address + ocsd_vaddr_t nextAddr = m_instr_info.instr_addr; + + // action according to waypoint type and atom value + switch(m_instr_info.type) + { + case OCSD_INSTR_BR: + if (atom == ATOM_E) + { + m_instr_info.instr_addr = m_instr_info.branch_addr; + if (m_instr_info.is_link) + m_return_stack.push(nextAddr, m_instr_info.isa); + + } + break; + + case OCSD_INSTR_BR_INDIRECT: + if (atom == ATOM_E) + { + m_need_addr = true; // indirect branch taken - need new address. + if (m_instr_info.is_link) + m_return_stack.push(nextAddr,m_instr_info.isa); + m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen + } + break; + } + m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + m_output_elem.setLastInstrInfo((atom == ATOM_E),m_instr_info.type, m_instr_info.sub_type); + m_output_elem.setISA(m_instr_info.isa); + resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); + + } + else + { + // no waypoint - likely inaccessible memory range. + m_need_addr = true; // need an address update + + if(m_output_elem.st_addr != m_output_elem.en_addr) + { + // some trace before we were out of memory access range + m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); + m_output_elem.setISA(m_instr_info.isa); + resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); + } + + if(m_mem_nacc_pending && OCSD_DATA_RESP_IS_CONT(resp)) + { + m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + m_output_elem.st_addr = m_nacc_addr; + resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); + m_mem_nacc_pending = false; + } + } + + if(!OCSD_DATA_RESP_IS_CONT(resp)) + bCont = false; + + return resp; +} + +// Exception processor +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processException() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool excep_implied_P0 = false; //!< exception implies P0 + + if(m_excep_proc == EXCEP_POP) + { + TrcStackElemExcept *pExceptElem = dynamic_cast(m_P0_stack.back()); // get the exception element + TrcStackElemAddr *pAddressElem = 0; + TrcStackElemCtxt *pCtxtElem = 0; + TrcStackElem *pElem = 0; + + m_P0_stack.pop_back(); // remove the exception element + pElem = m_P0_stack.back(); // look at next element. + if(pElem->getP0Type() == P0_CTXT) + { + pCtxtElem = dynamic_cast(pElem); + m_P0_stack.pop_back(); // remove the context element + pElem = m_P0_stack.back(); // next one should be an address element + } + + if(pElem->getP0Type() != P0_ADDR) + { + // no following address element - indicate processing error. + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,pExceptElem->getRootIndex(),m_CSID,"Address missing in exception packet.")); + } + else + { + // extract address + pAddressElem = static_cast(pElem); + + m_excep_addr = pAddressElem->getAddr(); + + // if we have context, get that. + if(pCtxtElem) + updateContext(pCtxtElem); + + // record the exception number + m_output_elem.exception_number = pExceptElem->getExcepNum(); + + // see if there is an implied P0 element on the exception. + excep_implied_P0 = pExceptElem->getPrevSame(); + + // save the trace index. + m_excep_index = pExceptElem->getRootIndex(); + + // figure out next move + if(m_excep_addr.val == m_instr_info.instr_addr) + m_excep_proc = EXCEP_EXCEP; + else + m_excep_proc = EXCEP_RANGE; + } + m_P0_stack.delete_popped(); + } + + // output a range element + if(m_excep_proc == EXCEP_RANGE) + { + bool bWPFound = false; + ocsd_err_t err; + + // last instr_info address is the start address + m_output_elem.st_addr = m_instr_info.instr_addr; + + // look for either a WP or match to return address. + err = traceInstrToWP(bWPFound,!excep_implied_P0,m_excep_addr.val); + + if(err != OCSD_OK) + { + if(err == OCSD_ERR_UNSUPPORTED_ISA) + { + m_need_addr = true; + m_need_ctxt = true; + LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_excep_index,m_CSID,"Warning: unsupported instruction set processing exception packet.")); + } + else + { + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_excep_index,m_CSID,"Error processing exception packet.")); + m_excep_proc = EXCEP_POP; // nothing more to do, reset to start of exception handling + } + } + + if(bWPFound) + { + // action according to waypoint type and atom value + if(excep_implied_P0) + { + switch(m_instr_info.type) + { + case OCSD_INSTR_BR: + m_instr_info.instr_addr = m_instr_info.branch_addr; + break; + + case OCSD_INSTR_BR_INDIRECT: + m_instr_info.instr_addr = m_excep_addr.val; + break; + } + } + m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); + m_output_elem.setISA(m_instr_info.isa); + resp = outputTraceElementIdx(m_excep_index, m_output_elem); + m_excep_proc = EXCEP_EXCEP; + } + else + { + // no waypoint - likely inaccessible memory range. + m_need_addr = true; // need an address update + + if(m_output_elem.st_addr != m_output_elem.en_addr) + { + // some trace before we were out of memory access range + m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); + m_output_elem.setISA(m_instr_info.isa); + resp = outputTraceElementIdx(m_excep_index,m_output_elem); + } + + m_excep_proc = m_mem_nacc_pending ? EXCEP_NACC : EXCEP_EXCEP; + } + } + + if((m_excep_proc == EXCEP_NACC) && OCSD_DATA_RESP_IS_CONT(resp)) + { + m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + m_output_elem.st_addr = m_nacc_addr; + resp = outputTraceElementIdx(m_excep_index,m_output_elem); + m_excep_proc = EXCEP_EXCEP; + m_mem_nacc_pending = false; + } + + if((m_excep_proc == EXCEP_EXCEP) && OCSD_DATA_RESP_IS_CONT(resp)) + { + // output element. + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION); + // add end address as preferred return address to end addr in element + m_output_elem.en_addr = m_excep_addr.val; + m_output_elem.excep_ret_addr = 1; + resp = outputTraceElementIdx(m_excep_index,m_output_elem); + m_excep_proc = EXCEP_POP; + } + return resp; +} + +void TrcPktDecodeEtmV4I::SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa) +{ + m_instr_info.instr_addr = addr_val; + if(m_is_64bit) + m_instr_info.isa = ocsd_isa_aarch64; + else + m_instr_info.isa = (isa == 0) ? ocsd_isa_arm : ocsd_isa_thumb2; +} + +// trace an instruction range to a waypoint - and set next address to restart from. +ocsd_err_t TrcPktDecodeEtmV4I::traceInstrToWP(bool &bWPFound, const bool traceToAddrNext /*= false*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/) +{ + uint32_t opcode; + uint32_t bytesReq; + ocsd_err_t err = OCSD_OK; + + // TBD?: update mem space to allow for EL as well. + ocsd_mem_space_acc_t mem_space = m_is_secure ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N; + + m_output_elem.st_addr = m_output_elem.en_addr = m_instr_info.instr_addr; + + bWPFound = false; + + while(!bWPFound && !m_mem_nacc_pending) + { + // start off by reading next opcode; + bytesReq = 4; + err = accessMemory(m_instr_info.instr_addr,mem_space,&bytesReq,(uint8_t *)&opcode); + if(err != OCSD_OK) break; + + if(bytesReq == 4) // got data back + { + m_instr_info.opcode = opcode; + err = instrDecode(&m_instr_info); + if(err != OCSD_OK) break; + + // increment address - may be adjusted by direct branch value later + m_instr_info.instr_addr += m_instr_info.instr_size; + + // update the range decoded address in the output packet. + m_output_elem.en_addr = m_instr_info.instr_addr; + + // either walking to match the next instruction address or a real watchpoint + if(traceToAddrNext) + bWPFound = (m_output_elem.en_addr == nextAddrMatch); + else + bWPFound = (m_instr_info.type != OCSD_INSTR_OTHER); + } + else + { + // not enough memory accessible. + m_mem_nacc_pending = true; + m_nacc_addr = m_instr_info.instr_addr; + } + } + return err; +} + +void TrcPktDecodeEtmV4I::updateContext(TrcStackElemCtxt *pCtxtElem) +{ + etmv4_context_t ctxt = pCtxtElem->getContext(); + // map to output element and local saved state. + m_is_64bit = (ctxt.SF != 0); + m_output_elem.context.bits64 = ctxt.SF; + m_is_secure = (ctxt.NS == 0); + m_output_elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure; + m_output_elem.context.exception_level = (ocsd_ex_level)ctxt.EL; + m_output_elem.context.el_valid = 1; + if(ctxt.updated_c) + { + m_output_elem.context.ctxt_id_valid = 1; + m_context_id = m_output_elem.context.context_id = ctxt.ctxtID; + } + if(ctxt.updated_v) + { + m_output_elem.context.vmid_valid = 1; + m_vmid_id = m_output_elem.context.vmid = ctxt.VMID; + } + m_need_ctxt = false; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + if(getComponentOpMode() && OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) + { + // error out - stop decoding + resp = OCSD_RESP_FATAL_INVALID_DATA; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,reason)); + } + else + { + // switch to unsync - clear decode state + m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); + resp = outputTraceElement(m_output_elem); + resetDecoder(); + m_curr_state = WAIT_SYNC; + } + return resp; +} + +/* End of File trc_pkt_decode_etmv4i.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4d.cpp b/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4d.cpp new file mode 100644 index 000000000000..58343b4117bf --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4d.cpp @@ -0,0 +1,57 @@ +/* + * \file trc_pkt_elem_etmv4d.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/etmv4/trc_pkt_elem_etmv4d.h" + +EtmV4DTrcPacket::EtmV4DTrcPacket() +{ +} + +EtmV4DTrcPacket::~EtmV4DTrcPacket() +{ +} + + // printing +void EtmV4DTrcPacket::toString(std::string &str) const +{ +} + +void EtmV4DTrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const +{ +} + + + +/* End of File trc_pkt_elem_etmv4d.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp b/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp new file mode 100644 index 000000000000..0761f7aa64f4 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp @@ -0,0 +1,560 @@ +/* + * \file trc_pkt_elem_etmv4i.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ +#include +#include + +#include "opencsd/etmv4/trc_pkt_elem_etmv4i.h" + +EtmV4ITrcPacket::EtmV4ITrcPacket() +{ +} + +EtmV4ITrcPacket::~EtmV4ITrcPacket() +{ +} + +void EtmV4ITrcPacket::initStartState() +{ + // clear packet state to start of trace (first sync or post discontinuity) + + // clear all valid bits + pkt_valid.val = 0; + + // virtual address + v_addr.pkt_bits = 0; + v_addr.valid_bits = 0; + v_addr_ISA = 0; + + // timestamp + ts.bits_changed = 0; + ts.timestamp = 0; + + // per packet init + initNextPacket(); +} + +void EtmV4ITrcPacket::initNextPacket() +{ + // clear valid bits for elements that are only valid over a single packet. + pkt_valid.bits.cc_valid = 0; + pkt_valid.bits.commit_elem_valid = 0; + atom.num = 0; + context.updated = 0; + context.updated_v = 0; + context.updated_c = 0; + err_type = ETM4_PKT_I_NO_ERR_TYPE; +} + +// printing +void EtmV4ITrcPacket::toString(std::string &str) const +{ + const char *name; + const char *desc; + std::string valStr, ctxtStr = ""; + + name = packetTypeName(type, &desc); + str = name + (std::string)" : " + desc; + + // extended descriptions + switch (type) + { + case ETM4_PKT_I_BAD_SEQUENCE: + case ETM4_PKT_I_INCOMPLETE_EOT: + name = packetTypeName(err_type, 0); + str += "[" + (std::string)name + "]"; + break; + + case ETM4_PKT_I_ADDR_CTXT_L_32IS0: + case ETM4_PKT_I_ADDR_CTXT_L_32IS1: + contextStr(ctxtStr); + case ETM4_PKT_I_ADDR_L_32IS0: + case ETM4_PKT_I_ADDR_L_32IS1: + trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 32) ? v_addr.pkt_bits : 0); + str += "; Addr=" + valStr + "; " + ctxtStr; + break; + + case ETM4_PKT_I_ADDR_CTXT_L_64IS0: + case ETM4_PKT_I_ADDR_CTXT_L_64IS1: + contextStr(ctxtStr); + case ETM4_PKT_I_ADDR_L_64IS0: + case ETM4_PKT_I_ADDR_L_64IS1: + trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 64) ? v_addr.pkt_bits : 0); + str += "; Addr=" + valStr + "; " + ctxtStr; + break; + + case ETM4_PKT_I_CTXT: + contextStr(ctxtStr); + str += "; " + ctxtStr; + break; + + case ETM4_PKT_I_ADDR_S_IS0: + case ETM4_PKT_I_ADDR_S_IS1: + trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, v_addr.pkt_bits); + str += "; Addr=" + valStr; + break; + + case ETM4_PKT_I_ADDR_MATCH: + addrMatchIdx(valStr); + str += ", " + valStr; + trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true); + str += "; Addr=" + valStr + "; " + ctxtStr; + break; + + case ETM4_PKT_I_ATOM_F1: + case ETM4_PKT_I_ATOM_F2: + case ETM4_PKT_I_ATOM_F3: + case ETM4_PKT_I_ATOM_F4: + case ETM4_PKT_I_ATOM_F5: + case ETM4_PKT_I_ATOM_F6: + atomSeq(valStr); + str += "; " + valStr; + break; + + case ETM4_PKT_I_EXCEPT: + exceptionInfo(valStr); + str += "; " + valStr; + break; + + case ETM4_PKT_I_TIMESTAMP: + { + std::ostringstream oss; + oss << "; Updated val = " << std::hex << "0x" << ts.timestamp; + if (pkt_valid.bits.cc_valid) + oss << "; CC=" << std::hex << "0x" << cycle_count; + str += oss.str(); + } + break; + + case ETM4_PKT_I_TRACE_INFO: + { + std::ostringstream oss; + oss << "; INFO=" << std::hex << "0x" << trace_info.val; + if (trace_info.bits.cc_enabled) + oss << "; CC_THRESHOLD=" << std::hex << "0x" << cc_threshold; + str += oss.str(); + } + break; + + case ETM4_PKT_I_CCNT_F1: + case ETM4_PKT_I_CCNT_F2: + case ETM4_PKT_I_CCNT_F3: + { + std::ostringstream oss; + oss << "; Count=" << std::hex << "0x" << cycle_count; + str += oss.str(); + } + break; + } +} + +void EtmV4ITrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const +{ + toString(str); // TBD add in formatted response. +} + +const char *EtmV4ITrcPacket::packetTypeName(const ocsd_etmv4_i_pkt_type type, const char **ppDesc) const +{ + const char *pName = "I_RESERVED"; + const char *pDesc = "Reserved Packet Header"; + + switch(type) + { + case ETM4_PKT_I_RESERVED: break; // default; + + case ETM4_PKT_I_NOTSYNC: + pName = "I_NOT_SYNC"; + pDesc = "I Stream not synchronised"; + break; + + case ETM4_PKT_I_BAD_SEQUENCE: + pName = "I_BAD_SEQUENCE"; + pDesc = "Invalid Sequence in packet."; + break; + + case ETM4_PKT_I_BAD_TRACEMODE: + pName = "I_BAD_TRACEMODE"; + pDesc = "Invalid Packet for trace mode."; + break; + + case ETM4_PKT_I_INCOMPLETE_EOT: + pName = "I_INCOMPLETE_EOT"; + pDesc = "Incomplete packet at end of trace."; + break; + + case ETM4_PKT_I_NO_ERR_TYPE: + pName = "I_NO_ERR_TYPE"; + pDesc = "No Error Type."; + break; + + case ETM4_PKT_I_EXTENSION: + pName = "I_EXTENSION"; + pDesc = "Extention packet header."; + break; + + case ETM4_PKT_I_ADDR_CTXT_L_32IS0: + pName = "I_ADDR_CTXT_L_32IS0"; + pDesc = "Address & Context, Long, 32 bit, IS0."; + break; + + case ETM4_PKT_I_ADDR_CTXT_L_32IS1: + pName = "I_ADDR_CTXT_L_32IS1"; + pDesc = "Address & Context, Long, 32 bit, IS0."; + break; + + case ETM4_PKT_I_ADDR_CTXT_L_64IS0: + pName = "I_ADDR_CTXT_L_64IS0"; + pDesc = "Address & Context, Long, 64 bit, IS0."; + break; + + case ETM4_PKT_I_ADDR_CTXT_L_64IS1: + pName = "I_ADDR_CTXT_L_64IS1"; + pDesc = "Address & Context, Long, 64 bit, IS1."; + break; + + case ETM4_PKT_I_CTXT: + pName = "I_CTXT"; + pDesc = "Context Packet."; + break; + + case ETM4_PKT_I_ADDR_MATCH: + pName = "I_ADDR_MATCH"; + pDesc = "Exact Address Match."; + break; + + case ETM4_PKT_I_ADDR_L_32IS0: + pName = "I_ADDR_L_32IS0"; + pDesc = "Address, Long, 32 bit, IS0."; + break; + + case ETM4_PKT_I_ADDR_L_32IS1: + pName = "I_ADDR_L_32IS1"; + pDesc = "Address, Long, 32 bit, IS1."; + break; + + case ETM4_PKT_I_ADDR_L_64IS0: + pName = "I_ADDR_L_64IS0"; + pDesc = "Address, Long, 64 bit, IS0."; + break; + + case ETM4_PKT_I_ADDR_L_64IS1: + pName = "I_ADDR_L_64IS1"; + pDesc = "Address, Long, 64 bit, IS1."; + break; + + case ETM4_PKT_I_ADDR_S_IS0: + pName = "I_ADDR_S_IS0"; + pDesc = "Address, Short, IS0."; + break; + + case ETM4_PKT_I_ADDR_S_IS1: + pName = "I_ADDR_S_IS1"; + pDesc = "Address, Short, IS1."; + break; + + case ETM4_PKT_I_Q: + pName = "I_Q"; + pDesc = "Q Packet."; + break; + + case ETM4_PKT_I_ATOM_F1: + pName = "I_ATOM_F1"; + pDesc = "Atom format 1."; + break; + + case ETM4_PKT_I_ATOM_F2: + pName = "I_ATOM_F2"; + pDesc = "Atom format 2."; + break; + + case ETM4_PKT_I_ATOM_F3: + pName = "I_ATOM_F3"; + pDesc = "Atom format 3."; + break; + + case ETM4_PKT_I_ATOM_F4: + pName = "I_ATOM_F4"; + pDesc = "Atom format 4."; + break; + + case ETM4_PKT_I_ATOM_F5: + pName = "I_ATOM_F5"; + pDesc = "Atom format 5."; + break; + + case ETM4_PKT_I_ATOM_F6: + pName = "I_ATOM_F6"; + pDesc = "Atom format 6."; + break; + + case ETM4_PKT_I_COND_FLUSH: + pName = "I_COND_FLUSH"; + pDesc = "Conditional Flush."; + break; + + case ETM4_PKT_I_COND_I_F1: + pName = "I_COND_I_F1"; + pDesc = "Conditional Instruction, format 1."; + break; + + case ETM4_PKT_I_COND_I_F2: + pName = "I_COND_I_F2"; + pDesc = "Conditional Instruction, format 2."; + break; + + case ETM4_PKT_I_COND_I_F3: + pName = "I_COND_I_F3"; + pDesc = "Conditional Instruction, format 3."; + break; + + case ETM4_PKT_I_COND_RES_F1: + pName = "I_COND_RES_F1"; + pDesc = "Conditional Result, format 1."; + break; + + case ETM4_PKT_I_COND_RES_F2: + pName = "I_COND_RES_F2"; + pDesc = "Conditional Result, format 2."; + break; + + case ETM4_PKT_I_COND_RES_F3: + pName = "I_COND_RES_F3"; + pDesc = "Conditional Result, format 3."; + break; + + case ETM4_PKT_I_COND_RES_F4: + pName = "I_COND_RES_F4"; + pDesc = "Conditional Result, format 4."; + break; + + case ETM4_PKT_I_CCNT_F1: + pName = "I_CCNT_F1"; + pDesc = "Cycle Count format 1."; + break; + + case ETM4_PKT_I_CCNT_F2: + pName = "I_CCNT_F2"; + pDesc = "Cycle Count format 2."; + break; + + case ETM4_PKT_I_CCNT_F3: + pName = "I_CCNT_F3"; + pDesc = "Cycle Count format 3."; + break; + + case ETM4_PKT_I_NUM_DS_MKR: + pName = "I_NUM_DS_MKR"; + pDesc = "Data Synchronisation Marker - Numbered."; + break; + + case ETM4_PKT_I_UNNUM_DS_MKR: + pName = "I_UNNUM_DS_MKR"; + pDesc = "Data Synchronisation Marker - Unnumbered."; + break; + + case ETM4_PKT_I_EVENT: + pName = "I_EVENT"; + pDesc = "Trace Event."; + break; + + case ETM4_PKT_I_EXCEPT: + pName = "I_EXCEPT"; + pDesc = "Exception."; + break; + + case ETM4_PKT_I_EXCEPT_RTN: + pName = "I_EXCEPT_RTN"; + pDesc = "Exception Return."; + break; + + case ETM4_PKT_I_TIMESTAMP: + pName = "I_TIMESTAMP"; + pDesc = "Timestamp."; + break; + + case ETM4_PKT_I_CANCEL_F1: + pName = "I_CANCEL_F1"; + pDesc = "Cancel Format 1."; + break; + case ETM4_PKT_I_CANCEL_F2: + pName = "I_CANCEL_F2"; + pDesc = "Cancel Format 2."; + break; + + case ETM4_PKT_I_CANCEL_F3: + pName = "I_CANCEL_F3"; + pDesc = "Cancel Format 3."; + break; + + case ETM4_PKT_I_COMMIT: + pName = "I_COMMIT"; + pDesc = "Commit"; + break; + + case ETM4_PKT_I_MISPREDICT: + pName = "I_MISPREDICT"; + pDesc = "Mispredict."; + break; + + case ETM4_PKT_I_TRACE_INFO: + pName = "I_TRACE_INFO"; + pDesc = "Trace Info."; + break; + + case ETM4_PKT_I_TRACE_ON: + pName = "I_TRACE_ON"; + pDesc = "Trace On."; + break; + + case ETM4_PKT_I_ASYNC: + pName = "I_ASYNC"; + pDesc = "Alignment Synchronisation."; + break; + + case ETM4_PKT_I_DISCARD: + pName = "I_DISCARD"; + pDesc = "Discard."; + break; + + case ETM4_PKT_I_OVERFLOW: + pName = "I_OVERFLOW"; + pDesc = "Overflow."; + break; + } + + if(ppDesc) *ppDesc = pDesc; + return pName; +} + +void EtmV4ITrcPacket::contextStr(std::string &ctxtStr) const +{ + ctxtStr = ""; + if(pkt_valid.bits.context_valid) + { + std::ostringstream oss; + if(context.updated) + { + oss << "Ctxt: " << (context.SF ? "AArch64," : "AArch32, ") << "EL" << context.EL << ", " << (context.NS ? "NS; " : "S; "); + if(context.updated_c) + { + oss << "CID=0x" << std::hex << std::setfill('0') << std::setw(8) << context.ctxtID << "; "; + } + if(context.updated_v) + { + oss << "VMID=0x" << std::hex << std::setfill('0') << std::setw(4) << context.VMID << "; "; + } + } + else + { + oss << "Ctxt: Same"; + } + ctxtStr = oss.str(); + } +} + +void EtmV4ITrcPacket::atomSeq(std::string &valStr) const +{ + std::ostringstream oss; + uint32_t bitpattern = atom.En_bits; + for(int i = 0; i < atom.num; i++) + { + oss << ((bitpattern & 0x1) ? "E" : "N"); + bitpattern >>= 1; + } + valStr = oss.str(); +} + +void EtmV4ITrcPacket::addrMatchIdx(std::string &valStr) const +{ + std::ostringstream oss; + oss << "[" << (uint16_t)addr_exact_match_idx << "]"; + valStr = oss.str(); +} + +void EtmV4ITrcPacket::exceptionInfo(std::string &valStr) const +{ + std::ostringstream oss; + + static const char *ARv8Excep[] = { + "PE Reset", "Debug Halt", "Call", "Trap", + "System Error", "Reserved", "Inst Debug", "Data Debug", + "Reserved", "Reserved", "Alignment", "Inst Fault", + "Data Fault", "Reserved", "IRQ", "FIQ" + }; + + static const char *MExcep[] = { + "Reserved", "PE Reset", "NMI", "HardFault", + "MemManage", "BusFault", "UsageFault", "Reserved", + "Reserved","Reserved","Reserved","SVC", + "DebugMonitor", "Reserved","PendSV","SysTick", + "IRQ0","IRQ1","IRQ2","IRQ3", + "IRQ4","IRQ5","IRQ6","IRQ7", + "DebugHalt", "LazyFP Push", "Lockup", "Reserved", + "Reserved","Reserved","Reserved","Reserved" + }; + + if(exception_info.m_type == 0) + { + if(exception_info.exceptionType < 0x10) + oss << " " << ARv8Excep[exception_info.exceptionType] << ";"; + else + oss << " Reserved;"; + + } + else + { + if(exception_info.exceptionType < 0x20) + oss << " " << MExcep[exception_info.exceptionType] << ";"; + else if((exception_info.exceptionType >= 0x208) && (exception_info.exceptionType <= 0x3EF)) + oss << " IRQ" << (int)(exception_info.exceptionType - 0x200) << ";"; + else + oss << " Reserved;"; + if(exception_info.m_fault_pending) + oss << " Fault Pending;"; + } + + if(exception_info.addr_interp == 0x1) + oss << " Ret Addr Follows;"; + else if(exception_info.addr_interp == 0x2) + oss << " Ret Addr Follows, Match Prev;"; + + valStr = oss.str(); +} + +EtmV4ITrcPacket &EtmV4ITrcPacket::operator =(const ocsd_etmv4_i_pkt* p_pkt) +{ + *dynamic_cast(this) = *p_pkt; + return *this; +} + +/* End of File trc_pkt_elem_etmv4i.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4.cpp b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4.cpp new file mode 100644 index 000000000000..b8c4f819c2d3 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4.cpp @@ -0,0 +1,126 @@ +/* + * \file trc_pkt_proc_etmv4.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/etmv4/trc_pkt_proc_etmv4.h" +#include "trc_pkt_proc_etmv4i_impl.h" +#include "common/ocsd_error.h" + +#ifdef __GNUC__ +// G++ doesn't like the ## pasting +#define ETMV4I_PKTS_NAME "PKTP_ETMV4I" +#else +// VC++ is fine +#define ETMV4I_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_ETMV4I" +#endif + +static const uint32_t ETMV4_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON; + +/***************************************************************************/ +/*******************ETM V4 INSTRUCTION *************************************/ +/***************************************************************************/ + +TrcPktProcEtmV4I::TrcPktProcEtmV4I() : TrcPktProcBase(ETMV4I_PKTS_NAME), + m_pProcessor(0) +{ + m_supported_op_flags = ETMV4_SUPPORTED_OP_FLAGS; +} + +TrcPktProcEtmV4I::TrcPktProcEtmV4I(int instIDNum) : TrcPktProcBase(ETMV4I_PKTS_NAME, instIDNum), + m_pProcessor(0) +{ + m_supported_op_flags = ETMV4_SUPPORTED_OP_FLAGS; +} + +TrcPktProcEtmV4I::~TrcPktProcEtmV4I() +{ + if(m_pProcessor) + delete m_pProcessor; + m_pProcessor = 0; +} + +ocsd_err_t TrcPktProcEtmV4I::onProtocolConfig() +{ + if(m_pProcessor == 0) + { + m_pProcessor = new (std::nothrow) EtmV4IPktProcImpl(); + if(m_pProcessor == 0) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM)); + return OCSD_ERR_MEM; + } + m_pProcessor->Initialise(this); + } + return m_pProcessor->Configure(m_config); +} + +ocsd_datapath_resp_t TrcPktProcEtmV4I::processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + if(m_pProcessor) + return m_pProcessor->processData(index,dataBlockSize,pDataBlock,numBytesProcessed); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV4I::onEOT() +{ + if(m_pProcessor) + return m_pProcessor->onEOT(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV4I::onReset() +{ + if(m_pProcessor) + return m_pProcessor->onReset(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV4I::onFlush() +{ + if(m_pProcessor) + return m_pProcessor->onFlush(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +const bool TrcPktProcEtmV4I::isBadPacket() const +{ + if(m_pProcessor) + return m_pProcessor->isBadPacket(); + return false; +} + +/* End of File trc_pkt_proc_etmv4.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4d_impl.h b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4d_impl.h new file mode 100644 index 000000000000..3be35bd12b55 --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4d_impl.h @@ -0,0 +1,71 @@ +/* + * \file trc_pkt_proc_etmv4d_impl.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PROC_ETMV4D_IMPL_H_INCLUDED +#define ARM_TRC_PKT_PROC_ETMV4D_IMPL_H_INCLUDED + +#include "etmv4/trc_pkt_proc_etmv4.h" +#include "etmv4/trc_cmp_cfg_etmv4.h" + +class EtmV4DPktProcImpl +{ +public: + EtmV4DPktProcImpl(); + ~EtmV4DPktProcImpl(); + + void Initialise(TrcPktProcEtmV4D *p_interface); + + ocsd_err_t Configure(const EtmV4Config *p_config); + + + ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + ocsd_datapath_resp_t onEOT(); + ocsd_datapath_resp_t onReset(); + ocsd_datapath_resp_t onFlush(); + +protected: + + bool m_isInit; + TrcPktProcEtmV4D *m_interface; /**< The interface to the other decode components */ + + EtmV4Config m_config; +}; + + +#endif // ARM_TRC_PKT_PROC_ETMV4D_IMPL_H_INCLUDED + +/* End of File trc_pkt_proc_etmv4d_impl.h */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.cpp b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.cpp new file mode 100644 index 000000000000..8d17d8386eba --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.cpp @@ -0,0 +1,1582 @@ +/* + * \file trc_pkt_proc_etmv4i_impl.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "trc_pkt_proc_etmv4i_impl.h" + +EtmV4IPktProcImpl::EtmV4IPktProcImpl() : + m_isInit(false), + m_interface(0), + m_first_trace_info(false) +{ + BuildIPacketTable(); +} + +EtmV4IPktProcImpl::~EtmV4IPktProcImpl() +{ +} + +void EtmV4IPktProcImpl::Initialise(TrcPktProcEtmV4I *p_interface) +{ + if(p_interface) + { + m_interface = p_interface; + m_isInit = true; + } + InitProcessorState(); +} + +ocsd_err_t EtmV4IPktProcImpl::Configure(const EtmV4Config *p_config) +{ + ocsd_err_t err = OCSD_OK; + if(p_config != 0) + { + m_config = *p_config; + } + else + { + err = OCSD_ERR_INVALID_PARAM_VAL; + if(m_isInit) + m_interface->LogError(ocsdError(OCSD_ERR_SEV_ERROR,err)); + } + return err; +} + +ocsd_datapath_resp_t EtmV4IPktProcImpl::processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + m_blockBytesProcessed = 0; + m_blockIndex = index; + uint8_t currByte; + while( ( (m_blockBytesProcessed < dataBlockSize) || + ((m_blockBytesProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) ) && + OCSD_DATA_RESP_IS_CONT(resp)) + { + currByte = pDataBlock[m_blockBytesProcessed]; + try + { + switch(m_process_state) + { + case PROC_HDR: + m_packet_index = m_blockIndex + m_blockBytesProcessed; + if(m_is_sync) + { + m_pIPktFn = m_i_table[currByte].pptkFn; + m_curr_packet.type = m_i_table[currByte].pkt_type; + } + else + { + // unsynced - process data until we see a sync point + m_pIPktFn = &EtmV4IPktProcImpl::iNotSync; + m_curr_packet.type = ETM4_PKT_I_NOTSYNC; + } + m_process_state = PROC_DATA; + + case PROC_DATA: + m_currPacketData.push_back(pDataBlock[m_blockBytesProcessed]); + m_blockBytesProcessed++; + (this->*m_pIPktFn)(); + break; + + case SEND_PKT: + resp = outputPacket(); + InitPacketState(); + m_process_state = PROC_HDR; + break; + + case SEND_UNSYNCED: + resp = outputUnsyncedRawPacket(); + if(m_update_on_unsync_packet_index != 0) + { + m_packet_index = m_update_on_unsync_packet_index; + m_update_on_unsync_packet_index = 0; + } + m_process_state = PROC_DATA; // after dumping unsynced data, still in data mode. + break; + } + } + catch(ocsdError &err) + { + m_interface->LogError(err); + if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) || + (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)) + { + // send invalid packets up the pipe to let the next stage decide what to do. + m_process_state = SEND_PKT; + } + else + { + // bail out on any other error. + resp = OCSD_RESP_FATAL_INVALID_DATA; + } + } + catch(...) + { + /// vv bad at this point. + resp = OCSD_RESP_FATAL_SYS_ERR; + const ocsdError &fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_config.getTraceID(),"Unknown System Error decoding trace."); + m_interface->LogError(fatal); + } + } + + *numBytesProcessed = m_blockBytesProcessed; + return resp; +} + +ocsd_datapath_resp_t EtmV4IPktProcImpl::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + // if we have a partial packet then send to attached sinks + if(m_currPacketData.size() != 0) + { + m_curr_packet.updateErrType(ETM4_PKT_I_INCOMPLETE_EOT); + resp = outputPacket(); + InitPacketState(); + } + return resp; +} + +ocsd_datapath_resp_t EtmV4IPktProcImpl::onReset() +{ + // prepare for new decoding session + InitProcessorState(); + return OCSD_RESP_CONT; +} + +ocsd_datapath_resp_t EtmV4IPktProcImpl::onFlush() +{ + // packet processor never holds on to flushable data (may have partial packet, + // but any full packets are immediately sent) + return OCSD_RESP_CONT; +} + +void EtmV4IPktProcImpl::InitPacketState() +{ + m_currPacketData.clear(); + m_curr_packet.initNextPacket(); // clear for next packet. + m_update_on_unsync_packet_index = 0; +} + +void EtmV4IPktProcImpl::InitProcessorState() +{ + InitPacketState(); + m_pIPktFn = &EtmV4IPktProcImpl::iNotSync; + m_packet_index = 0; + m_is_sync = false; + m_first_trace_info = false; + m_sent_notsync_packet = false; + m_process_state = PROC_HDR; + m_curr_packet.initStartState(); +} + +ocsd_datapath_resp_t EtmV4IPktProcImpl::outputPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&m_curr_packet.type,m_currPacketData); + return resp; +} + +ocsd_datapath_resp_t EtmV4IPktProcImpl::outputUnsyncedRawPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + + m_interface->outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]); + + if(!m_sent_notsync_packet) + { + resp = m_interface->outputDecodedPacket(m_packet_index,&m_curr_packet); + m_sent_notsync_packet = true; + } + + if(m_currPacketData.size() <= m_dump_unsynced_bytes) + m_currPacketData.clear(); + else + m_currPacketData.erase(m_currPacketData.begin(),m_currPacketData.begin()+m_dump_unsynced_bytes); + + return resp; +} + +void EtmV4IPktProcImpl::iNotSync() +{ + uint8_t lastByte = m_currPacketData.back(); // peek at the byte being processed... + + // is it an extension byte? + if(lastByte == 0x00) // TBD : add check for forced sync in here? + { + if(m_currPacketData.size() > 1) + { + m_dump_unsynced_bytes = m_currPacketData.size() - 1; + m_process_state = SEND_UNSYNCED; + // outputting some data then update packet index after so output indexes accurate + m_update_on_unsync_packet_index = m_blockIndex + m_blockBytesProcessed - 1; + } + else + m_packet_index = m_blockIndex + m_blockBytesProcessed - 1; // set it up now otherwise. + + m_pIPktFn = m_i_table[lastByte].pptkFn; + } + else if(m_currPacketData.size() >= 8) + { + m_dump_unsynced_bytes = m_currPacketData.size(); + m_process_state = SEND_UNSYNCED; + // outputting some data then update packet index after so output indexes accurate + m_update_on_unsync_packet_index = m_blockIndex + m_blockBytesProcessed; + } +} + +void EtmV4IPktProcImpl::iPktNoPayload() +{ + // some expansion may be required... + uint8_t lastByte = m_currPacketData.back(); + switch(m_curr_packet.type) + { + case ETM4_PKT_I_ADDR_MATCH: + m_curr_packet.setAddressExactMatch(lastByte & 0x3); + break; + + case ETM4_PKT_I_EVENT: + m_curr_packet.setEvent(lastByte & 0xF); + break; + + case ETM4_PKT_I_NUM_DS_MKR: + case ETM4_PKT_I_UNNUM_DS_MKR: + m_curr_packet.setDataSyncMarker(lastByte & 0x7); + break; + + // these just need the packet type - no processing required. + case ETM4_PKT_I_COND_FLUSH: + case ETM4_PKT_I_EXCEPT_RTN: + case ETM4_PKT_I_TRACE_ON: + default: break; + } + m_process_state = SEND_PKT; // now just send it.... +} + +void EtmV4IPktProcImpl::iPktReserved() +{ + m_curr_packet.updateErrType(ETM4_PKT_I_RESERVED); // swap type for err type + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,m_config.getTraceID()); +} + +void EtmV4IPktProcImpl::iPktExtension() +{ + uint8_t lastByte = m_currPacketData.back(); + if(m_currPacketData.size() == 2) + { + // not sync and not next by 0x00 - not sync sequence + if(!m_is_sync && (lastByte != 0x00)) + { + m_pIPktFn = &EtmV4IPktProcImpl::iNotSync; + m_curr_packet.type = ETM4_PKT_I_NOTSYNC; + return; + } + + switch(lastByte) + { + case 0x03: // discard packet. + m_curr_packet.type = ETM4_PKT_I_DISCARD; + m_process_state = SEND_PKT; + break; + + case 0x05: + m_curr_packet.type = ETM4_PKT_I_OVERFLOW; + m_process_state = SEND_PKT; + break; + + case 0x00: + m_curr_packet.type = ETM4_PKT_I_ASYNC; + m_pIPktFn = &EtmV4IPktProcImpl::iPktASync; // handle subsequent bytes as async + break; + + default: + m_curr_packet.err_type = m_curr_packet.type; + m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE; + m_process_state = SEND_PKT; + break; + } + } +} + +void EtmV4IPktProcImpl::iPktASync() +{ + uint8_t lastByte = m_currPacketData.back(); + if(lastByte != 0x00) + { + // not sync and not next by 0x00 - not sync sequence if < 12 + if(!m_is_sync && m_currPacketData.size() != 12) + { + m_pIPktFn = &EtmV4IPktProcImpl::iNotSync; + m_curr_packet.type = ETM4_PKT_I_NOTSYNC; + return; + } + + // 12 bytes and not valid sync sequence - not possible even if not synced + m_process_state = SEND_PKT; + if((m_currPacketData.size() != 12) || (lastByte != 0x80)) + { + m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE; + m_curr_packet.err_type = ETM4_PKT_I_ASYNC; + } + else + m_is_sync = true; // found a sync packet, mark decoder as synchronised. + } + else if(m_currPacketData.size() == 12) + { + if(!m_is_sync) + { + // if we are not yet synced then ignore extra leading 0x00. + m_dump_unsynced_bytes = 1; + m_process_state = SEND_UNSYNCED; + } + else + { + // bad periodic ASYNC sequence. + m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE; + m_curr_packet.err_type = ETM4_PKT_I_ASYNC; + m_process_state = SEND_PKT; + } + } +} + +void EtmV4IPktProcImpl::iPktTraceInfo() +{ + uint8_t lastByte = m_currPacketData.back(); + if(m_currPacketData.size() == 1) // header + { + //clear flags + m_tinfo_sections.sectFlags = 0; // mark all sections as incomplete. + m_tinfo_sections.ctrlBytes = 1; // assume only a single control section byte for now + + } + else if(m_currPacketData.size() == 2) // first payload control byte + { + // figure out which sections are absent and set to true - opposite of bitfeild in byte; + m_tinfo_sections.sectFlags = (~lastByte) & TINFO_ALL_SECT; + + // see if there is an extended control section, otherwise this byte is it. + if((lastByte & 0x80) == 0x0) + m_tinfo_sections.sectFlags |= TINFO_CTRL; + + } + else + { + if(!(m_tinfo_sections.sectFlags & TINFO_CTRL)) + { + m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_CTRL; + m_tinfo_sections.ctrlBytes++; + } + else if(!(m_tinfo_sections.sectFlags & TINFO_INFO_SECT)) + m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_INFO_SECT; + else if(!(m_tinfo_sections.sectFlags & TINFO_KEY_SECT)) + m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_KEY_SECT; + else if(!(m_tinfo_sections.sectFlags & TINFO_SPEC_SECT)) + m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_SPEC_SECT; + else if(!(m_tinfo_sections.sectFlags & TINFO_CYCT_SECT)) + m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_CYCT_SECT; + } + + // all sections accounted for? + if(m_tinfo_sections.sectFlags == TINFO_ALL) + { + // index of first section is number of payload control bytes + 1 for header byte + unsigned idx = m_tinfo_sections.ctrlBytes + 1; + uint32_t fieldVal = 0; + uint8_t presSect = m_currPacketData[1] & TINFO_ALL_SECT; // first payload control byte + + m_curr_packet.clearTraceInfo(); + + if((presSect & TINFO_INFO_SECT) && (idx < m_currPacketData.size())) + { + idx += extractContField(m_currPacketData,idx,fieldVal); + m_curr_packet.setTraceInfo(fieldVal); + } + if((presSect & TINFO_KEY_SECT) && (idx < m_currPacketData.size())) + { + idx += extractContField(m_currPacketData,idx,fieldVal); + m_curr_packet.setTraceInfoKey(fieldVal); + } + if((presSect & TINFO_SPEC_SECT) && (idx < m_currPacketData.size())) + { + idx += extractContField(m_currPacketData,idx,fieldVal); + m_curr_packet.setTraceInfoSpec(fieldVal); + } + if((presSect & TINFO_CYCT_SECT) && (idx < m_currPacketData.size())) + { + idx += extractContField(m_currPacketData,idx,fieldVal); + m_curr_packet.setTraceInfoCyct(fieldVal); + } + m_process_state = SEND_PKT; + m_first_trace_info = true; + } + +} + +void EtmV4IPktProcImpl::iPktTimestamp() +{ + // save the latest byte + uint8_t lastByte = m_currPacketData.back(); + + // process the header byte + if(m_currPacketData.size() == 1) + { + m_ccount_done = (bool)((lastByte & 0x1) == 0); // 0 = not present + m_ts_done = false; + m_ts_bytes = 0; + } + else + { + if(!m_ts_done) + { + m_ts_bytes++; + m_ts_done = (m_ts_bytes == 9) || ((lastByte & 0x80) == 0); + } + else if(!m_ccount_done) + { + m_ccount_done = (bool)((lastByte & 0x80) == 0); + // TBD: check for oorange ccount - bad packet. + } + } + + if(m_ts_done && m_ccount_done) + { + int idx = 1; + uint64_t tsVal; + int ts_bytes = extractContField64(m_currPacketData, idx, tsVal); + int ts_bits = ts_bytes < 7 ? ts_bytes * 7 : 64; + + if(!m_curr_packet.pkt_valid.bits.ts_valid && m_first_trace_info) + ts_bits = 64; // after trace info, missing bits are all 0. + + m_curr_packet.setTS(tsVal,(uint8_t)ts_bits); + + if((m_currPacketData[0] & 0x1) == 0x1) + { + uint32_t countVal, countMask; + + idx += ts_bytes; + extractContField(m_currPacketData, idx, countVal, 3); // only 3 possible count bytes. + countMask = (((uint32_t)1UL << m_config.ccSize()) - 1); // mask of the CC size + countVal &= countMask; + m_curr_packet.setCycleCount(countVal); + } + + m_process_state = SEND_PKT; + } +} + +void EtmV4IPktProcImpl::iPktException() +{ + uint8_t lastByte = m_currPacketData.back(); + + switch(m_currPacketData.size()) + { + case 1: m_excep_size = 3; break; + case 2: if((lastByte & 0x80) == 0x00) + m_excep_size = 2; + break; + } + + if(m_currPacketData.size() == (unsigned)m_excep_size) + { + uint16_t excep_type = (m_currPacketData[1] >> 1) & 0x1F; + uint8_t addr_interp = (m_currPacketData[1] & 0x40) >> 5 | (m_currPacketData[1] & 0x1); + uint8_t m_fault_pending = 0; + uint8_t m_type = (m_config.coreProfile() == profile_CortexM) ? 1 : 0; + + // extended exception packet (probably M class); + if(m_currPacketData[1] & 0x80) + { + excep_type |= ((uint16_t)m_currPacketData[2] & 0x1F) << 5; + m_fault_pending = (m_currPacketData[2] >> 5) & 0x1; + } + m_curr_packet.setExceptionInfo(excep_type,addr_interp,m_fault_pending, m_type); + m_process_state = SEND_PKT; + + // allow the standard address packet handlers to process the address packet field for the exception. + } +} + +void EtmV4IPktProcImpl::iPktCycleCntF123() +{ + ocsd_etmv4_i_pkt_type format = m_curr_packet.type; + + uint8_t lastByte = m_currPacketData.back(); + if( m_currPacketData.size() == 1) + { + m_count_done = m_commit_done = false; + m_has_count = true; + + if(format == ETM4_PKT_I_CCNT_F3) + { + // no commit section for TRCIDR0.COMMOPT == 1 + if(!m_config.commitOpt1()) + { + m_curr_packet.setCommitElements(((lastByte >> 2) & 0x3) + 1); + } + // TBD: warning of non-valid CC threshold here? + m_curr_packet.setCycleCount(m_curr_packet.getCCThreshold() + (lastByte & 0x3)); + m_process_state = SEND_PKT; + } + else if(format == ETM4_PKT_I_CCNT_F1) + { + if((lastByte & 0x1) == 0x1) + { + m_has_count = false; + m_count_done = true; + } + + // no commit section for TRCIDR0.COMMOPT == 1 + if(m_config.commitOpt1()) + m_commit_done = true; + } + } + else if((format == ETM4_PKT_I_CCNT_F2) && ( m_currPacketData.size() == 2)) + { + int commit_offset = ((lastByte & 0x1) == 0x1) ? ((int)m_config.MaxSpecDepth() - 15) : 1; + int commit_elements = ((lastByte >> 4) & 0xF); + commit_elements += commit_offset; + + // TBD: warning if commit elements < 0? + + m_curr_packet.setCycleCount(m_curr_packet.getCCThreshold() + (lastByte & 0xF)); + m_curr_packet.setCommitElements(commit_elements); + m_process_state = SEND_PKT; + } + else + { + // F1 and size 2 or more + if(!m_commit_done) + m_commit_done = ((lastByte & 0x80) == 0x00); + else if(!m_count_done) + m_count_done = ((lastByte & 0x80) == 0x00); + } + + if((format == ETM4_PKT_I_CCNT_F1) && m_commit_done && m_count_done) + { + int idx = 1; // index into buffer for payload data. + uint32_t field_value = 0; + // no commit section for TRCIDR0.COMMOPT == 1 + if(!m_config.commitOpt1()) + { + idx += extractContField(m_currPacketData,idx,field_value); + m_curr_packet.setCommitElements(field_value); + } + if (m_has_count) + { + extractContField(m_currPacketData, idx, field_value, 3); + m_curr_packet.setCycleCount(field_value + m_curr_packet.getCCThreshold()); + } + else + m_curr_packet.setCycleCount(0); /* unknown CC marked as 0 after overflow */ + m_process_state = SEND_PKT; + } +} + +void EtmV4IPktProcImpl::iPktSpeclRes() +{ + uint8_t lastByte = m_currPacketData.back(); + if(m_currPacketData.size() == 1) + { + switch(m_curr_packet.getType()) + { + case ETM4_PKT_I_MISPREDICT: + case ETM4_PKT_I_CANCEL_F2: + switch(lastByte & 0x3) + { + case 0x1: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x1, 1); break; // E + case 0x2: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x3, 2); break; // EE + case 0x3: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x0, 1); break; // N + } + if(m_curr_packet.getType() == ETM4_PKT_I_CANCEL_F2) + m_curr_packet.setCancelElements(1); + m_process_state = SEND_PKT; + break; + + case ETM4_PKT_I_CANCEL_F3: + if(lastByte & 0x1) + m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x1, 1); // E + m_curr_packet.setCancelElements(((lastByte >> 1) & 0x3) + 2); + m_process_state = SEND_PKT; + break; + } + } + else + { + if((lastByte & 0x80) == 0x00) + { + uint32_t field_val = 0; + extractContField(m_currPacketData,1,field_val); + if(m_curr_packet.getType() == ETM4_PKT_I_COMMIT) + m_curr_packet.setCommitElements(field_val); + else + m_curr_packet.setCancelElements(field_val); + // TBD: sanity check with max spec depth here? + m_process_state = SEND_PKT; + } + } +} + +void EtmV4IPktProcImpl::iPktCondInstr() +{ + uint8_t lastByte = m_currPacketData.back(); + bool bF1Done = false; + + if(m_currPacketData.size() == 1) + { + if(m_curr_packet.getType() == ETM4_PKT_I_COND_I_F2) + { + m_curr_packet.setCondIF2(lastByte & 0x3); + m_process_state = SEND_PKT; + } + + } + else if(m_currPacketData.size() == 2) + { + if(m_curr_packet.getType() == ETM4_PKT_I_COND_I_F3) // f3 two bytes long + { + uint8_t num_c_elem = ((lastByte >> 1) & 0x3F) + (lastByte & 0x1); + m_curr_packet.setCondIF3(num_c_elem,(bool)((lastByte & 0x1) == 0x1)); + // TBD: check for 0 num_c_elem in here. + m_process_state = SEND_PKT; + } + else + { + bF1Done = ((lastByte & 0x80) == 0x00); + } + } + else + { + bF1Done = ((lastByte & 0x80) == 0x00); + } + + if(bF1Done) + { + uint32_t cond_key = 0; + extractContField(m_currPacketData, 1, cond_key); + m_process_state = SEND_PKT; + } +} + +void EtmV4IPktProcImpl::iPktCondResult() +{ + //static ocsd_etmv4_i_pkt_type format = ETM4_PKT_I_COND_RES_F1; // conditional result formats F1-F4 + uint8_t lastByte = m_currPacketData.back(); + if(m_currPacketData.size() == 1) + { + m_F1P1_done = false; // F1 payload 1 done + m_F1P2_done = false; // F1 payload 2 done + m_F1has_P2 = false; // F1 has a payload 2 + + switch(m_curr_packet.getType()) + { + case ETM4_PKT_I_COND_RES_F1: + + m_F1has_P2 = true; + if((lastByte & 0xFC) == 0x6C)// only one payload set + { + m_F1P2_done = true; + m_F1has_P2 = false; + } + break; + + case ETM4_PKT_I_COND_RES_F2: + m_curr_packet.setCondRF2((lastByte & 0x4) ? 2 : 1, lastByte & 0x3); + m_process_state = SEND_PKT; + break; + + case ETM4_PKT_I_COND_RES_F3: + break; + + case ETM4_PKT_I_COND_RES_F4: + m_curr_packet.setCondRF4(lastByte & 0x3); + m_process_state = SEND_PKT; + break; + } + } + else if((m_curr_packet.getType() == ETM4_PKT_I_COND_RES_F3) && (m_currPacketData.size() == 2)) + { + // 2nd F3 packet + uint16_t f3_tokens = 0; + f3_tokens = (uint16_t)m_currPacketData[1]; + f3_tokens |= ((uint16_t)m_currPacketData[0] & 0xf) << 8; + m_curr_packet.setCondRF3(f3_tokens); + m_process_state = SEND_PKT; + } + else // !first packet - F1 + { + if(!m_F1P1_done) + m_F1P1_done = ((lastByte & 0x80) == 0x00); + else if(!m_F1P2_done) + m_F1P2_done = ((lastByte & 0x80) == 0x00); + + if(m_F1P1_done && m_F1P2_done) + { + int st_idx = 1; + uint32_t key[2]; + uint8_t result[2]; + uint8_t CI[2]; + + st_idx+= extractCondResult(m_currPacketData,st_idx,key[0],result[0]); + CI[0] = m_currPacketData[0] & 0x1; + if(m_F1has_P2) // 2nd payload? + { + extractCondResult(m_currPacketData,st_idx,key[1],result[1]); + CI[1] = (m_currPacketData[0] >> 1) & 0x1; + } + m_curr_packet.setCondRF1(key,result,CI,m_F1has_P2); + m_process_state = SEND_PKT; + } + } +} + +void EtmV4IPktProcImpl::iPktContext() +{ + bool bSendPacket = false; + uint8_t lastByte = m_currPacketData.back(); + if(m_currPacketData.size() == 1) + { + if((lastByte & 0x1) == 0) + { + m_curr_packet.setContextInfo(false); // no update context packet (ctxt same as last time). + m_process_state = SEND_PKT; + } + } + else if(m_currPacketData.size() == 2) + { + if((lastByte & 0xC0) == 0) // no VMID or CID + { + bSendPacket = true; + } + else + { + m_vmidBytes = ((lastByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0; + m_ctxtidBytes = ((lastByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0; + } + } + else // 3rd byte onwards + { + if(m_vmidBytes > 0) + m_vmidBytes--; + else if(m_ctxtidBytes > 0) + m_ctxtidBytes--; + + if((m_ctxtidBytes == 0) && (m_vmidBytes == 0)) + bSendPacket = true; + } + + if(bSendPacket) + { + extractAndSetContextInfo(m_currPacketData,1); + m_process_state = SEND_PKT; + } +} + +void EtmV4IPktProcImpl::extractAndSetContextInfo(const std::vector &buffer, const int st_idx) +{ + // on input, buffer index points at the info byte - always present + uint8_t infoByte = m_currPacketData[st_idx]; + + m_curr_packet.setContextInfo(true, (infoByte & 0x3), (infoByte >> 5) & 0x1, (infoByte >> 4) & 0x1); + + // see if there are VMID and CID bytes, and how many. + int nVMID_bytes = ((infoByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0; + int nCtxtID_bytes = ((infoByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0; + + // extract any VMID and CID + int payload_idx = st_idx+1; + if(nVMID_bytes) + { + uint32_t VMID = 0; + for(int i = 0; i < nVMID_bytes; i++) + { + VMID |= ((uint32_t)m_currPacketData[i+payload_idx] << i*8); + } + payload_idx += nVMID_bytes; + m_curr_packet.setContextVMID(VMID); + } + + if(nCtxtID_bytes) + { + uint32_t CID = 0; + for(int i = 0; i < nCtxtID_bytes; i++) + { + CID |= ((uint32_t)m_currPacketData[i+payload_idx] << i*8); + } + m_curr_packet.setContextCID(CID); + } +} + +void EtmV4IPktProcImpl::iPktAddrCtxt() +{ + uint8_t lastByte = m_currPacketData.back(); + + if( m_currPacketData.size() == 1) + { + m_addrIS = 0; + m_addrBytes = 4; + m_bAddr64bit = false; + m_vmidBytes = 0; + m_ctxtidBytes = 0; + m_bCtxtInfoDone = false; + + switch(m_curr_packet.type) + { + case ETM4_PKT_I_ADDR_CTXT_L_32IS1: + m_addrIS = 1; + case ETM4_PKT_I_ADDR_CTXT_L_32IS0: + break; + + case ETM4_PKT_I_ADDR_CTXT_L_64IS1: + m_addrIS = 1; + case ETM4_PKT_I_ADDR_CTXT_L_64IS0: + m_addrBytes = 8; + m_bAddr64bit = true; + break; + } + } + else + { + if(m_addrBytes == 0) + { + if(m_bCtxtInfoDone == false) + { + m_bCtxtInfoDone = true; + m_vmidBytes = ((lastByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0; + m_ctxtidBytes = ((lastByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0; + } + else + { + if( m_vmidBytes > 0) + m_vmidBytes--; + else if(m_ctxtidBytes > 0) + m_ctxtidBytes--; + } + } + else + m_addrBytes--; + + if((m_addrBytes == 0) && m_bCtxtInfoDone && (m_vmidBytes == 0) && (m_ctxtidBytes == 0)) + { + int st_idx = 1; + if(m_bAddr64bit) + { + uint64_t val64; + st_idx+=extract64BitLongAddr(m_currPacketData,st_idx,m_addrIS,val64); + m_curr_packet.set64BitAddress(val64,m_addrIS); + } + else + { + uint32_t val32; + st_idx+=extract32BitLongAddr(m_currPacketData,st_idx,m_addrIS,val32); + m_curr_packet.set32BitAddress(val32,m_addrIS); + } + extractAndSetContextInfo(m_currPacketData,st_idx); + m_process_state = SEND_PKT; + } + } +} + +void EtmV4IPktProcImpl::iPktShortAddr() +{ + uint8_t lastByte = m_currPacketData.back(); + if(m_currPacketData.size() == 1) + { + m_addr_done = false; + m_addrIS = (lastByte == ETM4_PKT_I_ADDR_S_IS0) ? 0 : 1; + } + else if(!m_addr_done) + { + m_addr_done = (m_currPacketData.size() == 3) || ((lastByte & 0x80) == 0x00); + } + + if(m_addr_done) + { + uint32_t addr_val = 0; + int bits = 0; + + extractShortAddr(m_currPacketData,1,m_addrIS,addr_val,bits); + m_curr_packet.updateShortAddress(addr_val,m_addrIS,(uint8_t)bits); + m_process_state = SEND_PKT; + } +} + +int EtmV4IPktProcImpl::extractShortAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint32_t &value, int &bits) +{ + int IS_shift = (IS == 0) ? 2 : 1; + int idx = 0; + + bits = 7; // at least 7 bits + value = 0; + value |= ((uint32_t)(buffer[st_idx+idx] & 0x7F)) << IS_shift; + + if(m_currPacketData[st_idx+idx] & 0x80) + { + idx++; + value |= ((uint32_t)m_currPacketData[st_idx+idx]) << (7 + IS_shift); + bits += 8; + } + idx++; + bits += IS_shift; + return idx; +} + +void EtmV4IPktProcImpl::iPktLongAddr() +{ + if(m_currPacketData.size() == 1) + { + // init the intra-byte data + m_addrIS = 0; + m_bAddr64bit = false; + m_addrBytes = 4; + + switch(m_curr_packet.type) + { + case ETM4_PKT_I_ADDR_L_32IS1: + m_addrIS = 1; + case ETM4_PKT_I_ADDR_L_32IS0: + m_addrBytes = 4; + break; + + case ETM4_PKT_I_ADDR_L_64IS1: + m_addrIS = 1; + case ETM4_PKT_I_ADDR_L_64IS0: + m_addrBytes = 8; + m_bAddr64bit = true; + break; + } + } + if(m_currPacketData.size() == (unsigned)(1+m_addrBytes)) + { + int st_idx = 1; + if(m_bAddr64bit) + { + uint64_t val64; + st_idx+=extract64BitLongAddr(m_currPacketData,st_idx,m_addrIS,val64); + m_curr_packet.set64BitAddress(val64,m_addrIS); + } + else + { + uint32_t val32; + st_idx+=extract32BitLongAddr(m_currPacketData,st_idx,m_addrIS,val32); + m_curr_packet.set32BitAddress(val32,m_addrIS); + } + m_process_state = SEND_PKT; + } +} + +void EtmV4IPktProcImpl::iPktQ() +{ + uint8_t lastByte = m_currPacketData.back(); + + if(m_currPacketData.size() == 1) + { + m_Q_type = lastByte & 0xF; + + m_addrBytes = 0; + m_count_done = false; + m_has_addr = false; + m_addr_short = true; + m_addr_match = false; + m_addrIS = 1; + m_QE = 0; + + switch(m_Q_type) + { + // count only - implied address. + case 0x0: + case 0x1: + case 0x2: + m_addr_match = true; + m_has_addr = true; + m_QE = m_Q_type & 0x3; + case 0xC: + break; + + // count + short address + case 0x5: + m_addrIS = 0; + case 0x6: + m_has_addr = true; + m_addrBytes = 2; // short IS0/1 + break; + + // count + long address + case 0xA: + m_addrIS = 0; + case 0xB: + m_has_addr = true; + m_addr_short = false; + m_addrBytes = 4; // long IS0/1 + break; + + // no count, no address + case 0xF: + m_count_done = true; + break; + + // reserved values 0x3, 0x4, 0x7, 0x8, 0x9, 0xD, 0xE + default: + m_curr_packet.err_type = m_curr_packet.type; + m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE; + //SendBadIPacket( PKT_BAD_SEQUENCE, "ERROR: Bad Q packet type", PKT_Q ); + break; + } + } + else + { + if(m_addrBytes > 0) + { + if(m_addr_short && m_addrBytes == 2) // short + { + if((lastByte & 0x80) == 0x00) + m_addrBytes--; // short version can have just single byte. + } + m_addrBytes--; + } + else if(!m_count_done) + { + m_count_done = ((lastByte & 0x80) == 0x00); + } + } + + if(((m_addrBytes == 0) && m_count_done)) + { + int idx = 1; // move past the header + int bits = 0; + uint32_t q_addr; + uint32_t q_count; + + if(m_has_addr) + { + if(m_addr_match) + { + m_curr_packet.setAddressExactMatch(m_QE); + } + else if(m_addr_short) + { + idx+=extractShortAddr(m_currPacketData,idx,m_addrIS,q_addr,bits); + m_curr_packet.updateShortAddress(q_addr,m_addrIS,(uint8_t)bits); + } + else + { + idx+=extract32BitLongAddr(m_currPacketData,idx,m_addrIS,q_addr); + m_curr_packet.set32BitAddress(q_addr,m_addrIS); + } + } + + if(m_Q_type != 0xF) + { + extractContField(m_currPacketData,idx,q_count); + m_curr_packet.setQType(true,q_count,m_has_addr,m_addr_match,m_Q_type); + } + else + { + m_curr_packet.setQType(false,0,false,false,0xF); + } + m_process_state = SEND_PKT; + } + +} + +void EtmV4IPktProcImpl::iAtom() +{ + // patterns lsbit = oldest atom, ms bit = newest. + static const uint32_t f4_patterns[] = { + 0xE, // EEEN + 0x0, // NNNN + 0xA, // ENEN + 0x5 // NENE + }; + + uint8_t lastByte = m_currPacketData.back(); + uint8_t pattIdx = 0, pattCount = 0; + uint32_t pattern; + + // atom packets are single byte, no payload. + switch(m_curr_packet.type) + { + case ETM4_PKT_I_ATOM_F1: + m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x1), 1); // 1xE or N + break; + + case ETM4_PKT_I_ATOM_F2: + m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x3), 2); // 2x (E or N) + break; + + case ETM4_PKT_I_ATOM_F3: + m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x7), 3); // 3x (E or N) + break; + + case ETM4_PKT_I_ATOM_F4: + m_curr_packet.setAtomPacket(ATOM_PATTERN,f4_patterns[(lastByte & 0x3)], 4); // 4 atom pattern + break; + + case ETM4_PKT_I_ATOM_F5: + pattIdx = ((lastByte & 0x20) >> 3) | (lastByte & 0x3); + switch(pattIdx) + { + case 5: // 0b101 + m_curr_packet.setAtomPacket(ATOM_PATTERN,0x1E, 5); // 5 atom pattern EEEEN + break; + + case 1: // 0b001 + m_curr_packet.setAtomPacket(ATOM_PATTERN,0x00, 5); // 5 atom pattern NNNNN + break; + + case 2: //0b010 + m_curr_packet.setAtomPacket(ATOM_PATTERN,0x0A, 5); // 5 atom pattern NENEN + break; + + case 3: //0b011 + m_curr_packet.setAtomPacket(ATOM_PATTERN,0x15, 5); // 5 atom pattern ENENE + break; + + default: + // TBD: warn about invalid pattern in here. + break; + } + break; + + case ETM4_PKT_I_ATOM_F6: + pattCount = (lastByte & 0x1F) + 3; // count of E's + // TBD: check 23 or less at this point? + pattern = ((uint32_t)0x1 << pattCount) - 1; // set pattern to string of E's + if((lastByte & 0x20) == 0x00) // last atom is E? + pattern |= ((uint32_t)0x1 << pattCount); + m_curr_packet.setAtomPacket(ATOM_PATTERN,pattern, pattCount+1); + break; + } + + m_process_state = SEND_PKT; +} + +// header byte processing is table driven. +void EtmV4IPktProcImpl::BuildIPacketTable() +{ + // initialise everything as reserved. + for(int i = 0; i < 256; i++) + { + m_i_table[i].pkt_type = ETM4_PKT_I_RESERVED; + m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iPktReserved; + } + + // 0x00 - extension + m_i_table[0x00].pkt_type = ETM4_PKT_I_EXTENSION; + m_i_table[0x00].pptkFn = &EtmV4IPktProcImpl::iPktExtension; + + // 0x01 - Trace info + m_i_table[0x01].pkt_type = ETM4_PKT_I_TRACE_INFO; + m_i_table[0x01].pptkFn = &EtmV4IPktProcImpl::iPktTraceInfo; + + // b0000001x - timestamp + m_i_table[0x02].pkt_type = ETM4_PKT_I_TIMESTAMP; + m_i_table[0x02].pptkFn = &EtmV4IPktProcImpl::iPktTimestamp; + m_i_table[0x03].pkt_type = ETM4_PKT_I_TIMESTAMP; + m_i_table[0x03].pptkFn = &EtmV4IPktProcImpl::iPktTimestamp; + + // b0000 0100 - trace on + m_i_table[0x04].pkt_type = ETM4_PKT_I_TRACE_ON; + m_i_table[0x04].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + + // b0000 0110 - exception + m_i_table[0x06].pkt_type = ETM4_PKT_I_EXCEPT; + m_i_table[0x06].pptkFn = &EtmV4IPktProcImpl::iPktException; + + // b0000 0111 - exception return + m_i_table[0x07].pkt_type = ETM4_PKT_I_EXCEPT_RTN; + m_i_table[0x07].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + + // b0000 110x - cycle count f2 + // b0000 111x - cycle count f1 + for(int i = 0; i < 4; i++) + { + m_i_table[0x0C+i].pkt_type = (i >= 2) ? ETM4_PKT_I_CCNT_F1 : ETM4_PKT_I_CCNT_F2; + m_i_table[0x0C+i].pptkFn = &EtmV4IPktProcImpl::iPktCycleCntF123; + } + + // b0001 xxxx - cycle count f3 + for(int i = 0; i < 16; i++) + { + m_i_table[0x10+i].pkt_type = ETM4_PKT_I_CCNT_F3; + m_i_table[0x10+i].pptkFn = &EtmV4IPktProcImpl::iPktCycleCntF123; + } + + // b0010 0xxx - NDSM + for(int i = 0; i < 8; i++) + { + m_i_table[0x20+i].pkt_type = ETM4_PKT_I_NUM_DS_MKR; + m_i_table[0x20+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + } + + // b0010 10xx, b0010 1100 - UDSM + for(int i = 0; i < 5; i++) + { + m_i_table[0x28+i].pkt_type = ETM4_PKT_I_UNNUM_DS_MKR; + m_i_table[0x28+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + } + + // b0010 1101 - commit + m_i_table[0x2D].pkt_type = ETM4_PKT_I_COMMIT; + m_i_table[0x2D].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; + + + // b0010 111x - cancel f1 + for(int i = 0; i < 2; i++) + { + // G++ doesn't understand [0x2E+i] so... + int idx = i + 0x2E; + m_i_table[idx].pkt_type = ETM4_PKT_I_CANCEL_F1; + m_i_table[idx].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; + } + + // b0011 00xx - mis predict + for(int i = 0; i < 4; i++) + { + m_i_table[0x30+i].pkt_type = ETM4_PKT_I_MISPREDICT; + m_i_table[0x30+i].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; + } + + // b0011 01xx - cancel f2 + for(int i = 0; i < 4; i++) + { + m_i_table[0x34+i].pkt_type = ETM4_PKT_I_CANCEL_F2; + m_i_table[0x34+i].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; + } + + // b0011 1xxx - cancel f3 + for(int i = 0; i < 8; i++) + { + m_i_table[0x38+i].pkt_type = ETM4_PKT_I_CANCEL_F3; + m_i_table[0x38+i].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; + } + + // b0100 000x, b0100 0010 - cond I f2 + for(int i = 0; i < 3; i++) + { + m_i_table[0x40+i].pkt_type = ETM4_PKT_I_COND_I_F2; + m_i_table[0x40+i].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + } + + // b0100 0011 - cond flush + m_i_table[0x43].pkt_type = ETM4_PKT_I_COND_FLUSH; + m_i_table[0x43].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + + // b0100 010x, b0100 0110 - cond res f4 + for(int i = 0; i < 3; i++) + { + m_i_table[0x44+i].pkt_type = ETM4_PKT_I_COND_RES_F4; + m_i_table[0x44+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + } + + // b0100 100x, b0100 0110 - cond res f2 + // b0100 110x, b0100 1110 - cond res f2 + for(int i = 0; i < 3; i++) + { + m_i_table[0x48+i].pkt_type = ETM4_PKT_I_COND_RES_F2; + m_i_table[0x48+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + } + for(int i = 0; i < 3; i++) + { + m_i_table[0x4C+i].pkt_type = ETM4_PKT_I_COND_RES_F2; + m_i_table[0x4C+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + } + + // b0101xxxx - cond res f3 + for(int i = 0; i < 16; i++) + { + m_i_table[0x50+i].pkt_type = ETM4_PKT_I_COND_RES_F3; + m_i_table[0x50+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + } + + // b011010xx - cond res f1 + for(int i = 0; i < 4; i++) + { + m_i_table[0x68+i].pkt_type = ETM4_PKT_I_COND_RES_F1; + m_i_table[0x68+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + } + + // b0110 1100 - cond instr f1 + m_i_table[0x6C].pkt_type = ETM4_PKT_I_COND_I_F1; + m_i_table[0x6C].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + + // b0110 1101 - cond instr f3 + m_i_table[0x6D].pkt_type = ETM4_PKT_I_COND_I_F3; + m_i_table[0x6D].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + + // b0110111x - cond res f1 + for(int i = 0; i < 2; i++) + { + // G++ cannot understand [0x6E+i] so change these round + m_i_table[i+0x6E].pkt_type = ETM4_PKT_I_COND_RES_F1; + m_i_table[i+0x6E].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + } + + // b01110001 - b01111111 - cond res f1 + for(int i = 0; i < 15; i++) + { + m_i_table[0x71+i].pkt_type = ETM4_PKT_I_EVENT; + m_i_table[0x71+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + } + + // 0b1000 000x - context + for(int i = 0; i < 2; i++) + { + m_i_table[0x80+i].pkt_type = ETM4_PKT_I_CTXT; + m_i_table[0x80+i].pptkFn = &EtmV4IPktProcImpl::iPktContext; + } + + // 0b1000 0010 to b1000 0011 - addr with ctxt + // 0b1000 0101 to b1000 0110 - addr with ctxt + for(int i = 0; i < 2; i++) + { + m_i_table[0x82+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_CTXT_L_32IS0 : ETM4_PKT_I_ADDR_CTXT_L_32IS1; + m_i_table[0x82+i].pptkFn = &EtmV4IPktProcImpl::iPktAddrCtxt; + } + + for(int i = 0; i < 2; i++) + { + m_i_table[0x85+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_CTXT_L_64IS0 : ETM4_PKT_I_ADDR_CTXT_L_64IS1; + m_i_table[0x85+i].pptkFn = &EtmV4IPktProcImpl::iPktAddrCtxt; + } + + // 0b1001 0000 to b1001 0010 - exact match addr + for(int i = 0; i < 3; i++) + { + m_i_table[0x90+i].pkt_type = ETM4_PKT_I_ADDR_MATCH; + m_i_table[0x90+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + } + + // b1001 0101 - b1001 0110 - addr short address + for(int i = 0; i < 2; i++) + { + m_i_table[0x95+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_S_IS0 : ETM4_PKT_I_ADDR_S_IS1; + m_i_table[0x95+i].pptkFn = &EtmV4IPktProcImpl::iPktShortAddr; + } + + // b10011010 - b10011011 - addr long address + // b10011101 - b10011110 - addr long address + for(int i = 0; i < 2; i++) + { + m_i_table[0x9A+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_L_32IS0 : ETM4_PKT_I_ADDR_L_32IS1; + m_i_table[0x9A+i].pptkFn = &EtmV4IPktProcImpl::iPktLongAddr; + } + for(int i = 0; i < 2; i++) + { + m_i_table[0x9D+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_L_64IS0 : ETM4_PKT_I_ADDR_L_64IS1; + m_i_table[0x9D+i].pptkFn = &EtmV4IPktProcImpl::iPktLongAddr; + } + + // b1010xxxx - Q packet + for(int i = 0; i < 16; i++) + { + m_i_table[0xA0+i].pkt_type = ETM4_PKT_I_Q; + m_i_table[0xA0+i].pptkFn = &EtmV4IPktProcImpl::iPktQ; + } + + // Atom Packets - all no payload but have specific pattern generation fn + for(int i = 0xC0; i <= 0xD4; i++) // atom f6 + { + m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F6; + m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; + } + for(int i = 0xD5; i <= 0xD7; i++) // atom f5 + { + m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F5; + m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; + } + for(int i = 0xD8; i <= 0xDB; i++) // atom f2 + { + m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F2; + m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; + } + for(int i = 0xDC; i <= 0xDF; i++) // atom f4 + { + m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F4; + m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; + } + for(int i = 0xE0; i <= 0xF4; i++) // atom f6 + { + m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F6; + m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; + } + + // atom f5 + m_i_table[0xF5].pkt_type = ETM4_PKT_I_ATOM_F5; + m_i_table[0xF5].pptkFn = &EtmV4IPktProcImpl::iAtom; + + for(int i = 0xF6; i <= 0xF7; i++) // atom f1 + { + m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F1; + m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; + } + for(int i = 0xF8; i <= 0xFF; i++) // atom f3 + { + m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F3; + m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; + } +} + + unsigned EtmV4IPktProcImpl::extractContField(const std::vector &buffer, const unsigned st_idx, uint32_t &value, const unsigned byte_limit /*= 5*/) +{ + unsigned idx = 0; + bool lastByte = false; + uint8_t byteVal; + value = 0; + while(!lastByte && (idx < byte_limit)) // max 5 bytes for 32 bit value; + { + if(buffer.size() > (st_idx + idx)) + { + // each byte has seven bits + cont bit + byteVal = buffer[(st_idx + idx)]; + lastByte = (byteVal & 0x80) != 0x80; + value |= ((uint32_t)(byteVal & 0x7F)) << (idx * 7); + idx++; + } + else + { + throwBadSequenceError("Invalid 32 bit continuation fields in packet"); + } + } + return idx; +} + +unsigned EtmV4IPktProcImpl::extractContField64(const std::vector &buffer, const unsigned st_idx, uint64_t &value, const unsigned byte_limit /*= 9*/) +{ + unsigned idx = 0; + bool lastByte = false; + uint8_t byteVal; + value = 0; + while(!lastByte && (idx < byte_limit)) // max 9 bytes for 64 bit value; + { + if(buffer.size() > (st_idx + idx)) + { + // each byte has seven bits + cont bit + byteVal = buffer[(st_idx + idx)]; + lastByte = (byteVal & 0x80) != 0x80; + value |= ((uint64_t)(byteVal & 0x7F)) << (idx * 7); + idx++; + } + else + { + throwBadSequenceError("Invalid 64 bit continuation fields in packet"); + } + } + return idx; +} + + unsigned EtmV4IPktProcImpl::extractCondResult(const std::vector &buffer, const unsigned st_idx, uint32_t& key, uint8_t &result) +{ + unsigned idx = 0; + bool lastByte = false; + int incr = 0; + + key = 0; + + while(!lastByte && (idx < 6)) // cannot be more than 6 bytes for res + 32 bit key + { + if(buffer.size() > (st_idx + idx)) + { + if(idx == 0) + { + result = buffer[st_idx+idx]; + key = (buffer[st_idx+idx] >> 4) & 0x7; + incr+=3; + } + else + { + key |= ((uint32_t)(buffer[st_idx+idx] & 0x7F)) << incr; + incr+=7; + } + lastByte = (bool)((buffer[st_idx+idx] & 0x80) == 0); + idx++; + } + else + { + throwBadSequenceError("Invalid continuation fields in packet"); + } + } + return idx; +} + +int EtmV4IPktProcImpl::extract64BitLongAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint64_t &value) +{ + value = 0; + if(IS == 0) + { + value |= ((uint64_t)(buffer[st_idx+0] & 0x7F)) << 2; + value |= ((uint64_t)(buffer[st_idx+1] & 0x7F)) << 9; + } + else + { + value |= ((uint64_t)(buffer[st_idx+0] & 0x7F)) << 1; + value |= ((uint64_t)buffer[st_idx+1]) << 8; + } + value |= ((uint64_t)buffer[st_idx+2]) << 16; + value |= ((uint64_t)buffer[st_idx+3]) << 24; + value |= ((uint64_t)buffer[st_idx+4]) << 32; + value |= ((uint64_t)buffer[st_idx+5]) << 40; + value |= ((uint64_t)buffer[st_idx+6]) << 48; + value |= ((uint64_t)buffer[st_idx+7]) << 56; + return 8; +} + +int EtmV4IPktProcImpl::extract32BitLongAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint32_t &value) +{ + value = 0; + if(IS == 0) + { + value |= ((uint32_t)(buffer[st_idx+0] & 0x7F)) << 2; + value |= ((uint32_t)(buffer[st_idx+1] & 0x7F)) << 9; + } + else + { + value |= ((uint32_t)(buffer[st_idx+0] & 0x7F)) << 1; + value |= ((uint32_t)buffer[st_idx+1]) << 8; + } + value |= ((uint32_t)buffer[st_idx+2]) << 16; + value |= ((uint32_t)buffer[st_idx+3]) << 24; + return 4; +} + +void EtmV4IPktProcImpl::throwBadSequenceError(const char *pszExtMsg) +{ + m_curr_packet.updateErrType(ETM4_PKT_I_BAD_SEQUENCE); // swap type for err type + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,m_config.getTraceID(),pszExtMsg); +} + + +/* End of File trc_pkt_proc_etmv4i_impl.cpp */ diff --git a/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.h b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.h new file mode 100644 index 000000000000..5c79c256967a --- /dev/null +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.h @@ -0,0 +1,204 @@ +/* + * \file trc_pkt_proc_etmv4i_impl.h + * \brief OpenCSD : Implementation of ETMv4 packet processing + * + * \copyright Copyright (c) 2015, 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_TRC_PKT_PROC_ETMV4I_IMPL_H_INCLUDED +#define ARM_TRC_PKT_PROC_ETMV4I_IMPL_H_INCLUDED + +#include "opencsd/etmv4/trc_pkt_proc_etmv4.h" +#include "opencsd/etmv4/trc_cmp_cfg_etmv4.h" +#include "opencsd/etmv4/trc_pkt_elem_etmv4i.h" + +class EtmV4IPktProcImpl +{ +public: + EtmV4IPktProcImpl(); + ~EtmV4IPktProcImpl(); + + void Initialise(TrcPktProcEtmV4I *p_interface); + + ocsd_err_t Configure(const EtmV4Config *p_config); + + + ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + ocsd_datapath_resp_t onEOT(); + ocsd_datapath_resp_t onReset(); + ocsd_datapath_resp_t onFlush(); + const bool isBadPacket() const; + +protected: + typedef enum _process_state { + PROC_HDR, + PROC_DATA, + SEND_PKT, + SEND_UNSYNCED, + PROC_ERR, + } process_state; + + process_state m_process_state; + + void InitPacketState(); // clear current packet state. + void InitProcessorState(); // clear all previous process state + + /** packet processor configuration **/ + bool m_isInit; + TrcPktProcEtmV4I *m_interface; /**< The interface to the other decode components */ + + // etmv4 hardware configuration + EtmV4Config m_config; + + /** packet data **/ + std::vector m_currPacketData; // raw data + int m_currPktIdx; // index into raw packet when expanding + EtmV4ITrcPacket m_curr_packet; // expanded packet + ocsd_trc_index_t m_packet_index; // index of the start of the current packet + uint32_t m_blockBytesProcessed; // number of bytes processed in the current data block + ocsd_trc_index_t m_blockIndex; // index at the start of the current data block being processed + + // searching for sync + bool m_is_sync; //!< seen first sync packet + bool m_first_trace_info; //!< seen first trace info packet after sync + bool m_sent_notsync_packet; //!< send one not sync packet if we see any unsynced data on the channel + unsigned m_dump_unsynced_bytes; //!< number of unsynced bytes to send + ocsd_trc_index_t m_update_on_unsync_packet_index; + + +private: + // current processing state data - counts and flags to determine if a packet is complete. + + // TraceInfo Packet + // flags to indicate processing progress for these sections is complete. + struct _t_info_pkt_prog { + uint8_t sectFlags; + uint8_t ctrlBytes; + } m_tinfo_sections; + + #define TINFO_INFO_SECT 0x01 + #define TINFO_KEY_SECT 0x02 + #define TINFO_SPEC_SECT 0x04 + #define TINFO_CYCT_SECT 0x08 + #define TINFO_CTRL 0x10 + #define TINFO_ALL_SECT 0x0F + #define TINFO_ALL 0x1F + + + // address and context packets + int m_addrBytes; + uint8_t m_addrIS; + bool m_bAddr64bit; + int m_vmidBytes; // bytes still to find + int m_ctxtidBytes; // bytes still to find + bool m_bCtxtInfoDone; + bool m_addr_done; + + // timestamp + bool m_ccount_done; // done or not needed + bool m_ts_done; + int m_ts_bytes; + + // exception + int m_excep_size; + + // cycle count + bool m_has_count; + bool m_count_done; + bool m_commit_done; + + // cond result + bool m_F1P1_done; // F1 payload 1 done + bool m_F1P2_done; // F1 payload 2 done + bool m_F1has_P2; // F1 has a payload 2 + + // Q packets (use some from above too) + bool m_has_addr; + bool m_addr_short; + bool m_addr_match; + uint8_t m_Q_type; + uint8_t m_QE; + + ocsd_datapath_resp_t outputPacket(); + ocsd_datapath_resp_t outputUnsyncedRawPacket(); + + void iNotSync(); // not synced yet + void iPktNoPayload(); // process a single byte packet + void iPktReserved(); // deal with reserved header value + void iPktExtension(); + void iPktASync(); + void iPktTraceInfo(); + void iPktTimestamp(); + void iPktException(); + void iPktCycleCntF123(); + void iPktSpeclRes(); + void iPktCondInstr(); + void iPktCondResult(); + void iPktContext(); + void iPktAddrCtxt(); + void iPktShortAddr(); + void iPktLongAddr(); + void iPktQ(); + void iAtom(); + + unsigned extractContField(const std::vector &buffer, const unsigned st_idx, uint32_t &value, const unsigned byte_limit = 5); + unsigned extractContField64(const std::vector &buffer, const unsigned st_idx, uint64_t &value, const unsigned byte_limit = 9); + unsigned extractCondResult(const std::vector &buffer, const unsigned st_idx, uint32_t& key, uint8_t &result); + void extractAndSetContextInfo(const std::vector &buffer, const int st_idx); + int extract64BitLongAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint64_t &value); + int extract32BitLongAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint32_t &value); + int extractShortAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint32_t &value, int &bits); + + // packet processing is table driven. + typedef void (EtmV4IPktProcImpl::*PPKTFN)(void); + PPKTFN m_pIPktFn; + + struct _pkt_i_table_t { + ocsd_etmv4_i_pkt_type pkt_type; + PPKTFN pptkFn; + } m_i_table[256]; + + void BuildIPacketTable(); + + void throwBadSequenceError(const char *pszExtMsg); +}; + + +inline const bool EtmV4IPktProcImpl::isBadPacket() const +{ + return m_curr_packet.isBadPacket(); +} + +#endif // ARM_TRC_PKT_PROC_ETMV4I_IMPL_H_INCLUDED + +/* End of File trc_pkt_proc_etmv4i_impl.h */ diff --git a/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp b/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp new file mode 100644 index 000000000000..47b4867e6c5c --- /dev/null +++ b/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp @@ -0,0 +1,213 @@ +/* + * \file trc_i_decode.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/ocsd_if_types.h" +#include "i_dec/trc_i_decode.h" +#include "i_dec/trc_idec_arminst.h" + +ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info) +{ + ocsd_err_t err = OCSD_OK; + clear_instr_subtype(); + switch(instr_info->isa) + { + case ocsd_isa_arm: + err = DecodeA32(instr_info); + break; + + case ocsd_isa_thumb2: + err = DecodeT32(instr_info); + break; + + case ocsd_isa_aarch64: + err = DecodeA64(instr_info); + break; + + case ocsd_isa_tee: + case ocsd_isa_jazelle: + default: + // unsupported ISA + err = OCSD_ERR_UNSUPPORTED_ISA; + break; + } + instr_info->sub_type = get_instr_subtype(); + return err; +} + +ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info) +{ + uint32_t branchAddr = 0; + arm_barrier_t barrier; + + instr_info->instr_size = 4; // instruction size A32 + instr_info->type = OCSD_INSTR_OTHER; // default type + instr_info->next_isa = instr_info->isa; // assume same ISA + instr_info->is_link = 0; + + if(inst_ARM_is_indirect_branch(instr_info->opcode)) + { + instr_info->type = OCSD_INSTR_BR_INDIRECT; + instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode); + } + else if(inst_ARM_is_direct_branch(instr_info->opcode)) + { + inst_ARM_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr); + instr_info->type = OCSD_INSTR_BR; + if (branchAddr & 0x1) + { + instr_info->next_isa = ocsd_isa_thumb2; + branchAddr &= ~0x1; + } + instr_info->branch_addr = (ocsd_vaddr_t)branchAddr; + instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode); + } + else if((barrier = inst_ARM_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) + { + switch(barrier) + { + case ARM_BARRIER_ISB: + instr_info->type = OCSD_INSTR_ISB; + break; + + case ARM_BARRIER_DSB: + case ARM_BARRIER_DMB: + if(instr_info->dsb_dmb_waypoints) + instr_info->type = OCSD_INSTR_DSB_DMB; + break; + } + } + + instr_info->is_conditional = inst_ARM_is_conditional(instr_info->opcode); + + return OCSD_OK; +} + +ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info) +{ + uint64_t branchAddr = 0; + arm_barrier_t barrier; + + instr_info->instr_size = 4; // default address update + instr_info->type = OCSD_INSTR_OTHER; // default type + instr_info->next_isa = instr_info->isa; // assume same ISA + instr_info->is_link = 0; + + if(inst_A64_is_indirect_branch(instr_info->opcode)) + { + instr_info->type = OCSD_INSTR_BR_INDIRECT; + instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); + } + else if(inst_A64_is_direct_branch(instr_info->opcode)) + { + inst_A64_branch_destination(instr_info->instr_addr,instr_info->opcode,&branchAddr); + instr_info->type = OCSD_INSTR_BR; + instr_info->branch_addr = (ocsd_vaddr_t)branchAddr; + instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); + } + else if((barrier = inst_A64_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) + { + switch(barrier) + { + case ARM_BARRIER_ISB: + instr_info->type = OCSD_INSTR_ISB; + break; + + case ARM_BARRIER_DSB: + case ARM_BARRIER_DMB: + if(instr_info->dsb_dmb_waypoints) + instr_info->type = OCSD_INSTR_DSB_DMB; + break; + } + } + + instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode); + + return OCSD_OK; +} + +ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info) +{ + uint32_t branchAddr = 0; + arm_barrier_t barrier; + + // need to align the 32 bit opcode as 2 16 bit, with LS 16 as in top 16 bit of + // 32 bit word - T2 routines assume 16 bit in top 16 bit of 32 bit opcode. + uint32_t op_temp = (instr_info->opcode >> 16) & 0xFFFF; + op_temp |= ((instr_info->opcode & 0xFFFF) << 16); + instr_info->opcode = op_temp; + + + instr_info->instr_size = is_wide_thumb((uint16_t)(instr_info->opcode >> 16)) ? 4 : 2; + instr_info->type = OCSD_INSTR_OTHER; // default type + instr_info->next_isa = instr_info->isa; // assume same ISA + instr_info->is_link = 0; + + if(inst_Thumb_is_indirect_branch(instr_info->opcode)) + { + instr_info->type = OCSD_INSTR_BR_INDIRECT; + instr_info->is_link = inst_Thumb_is_branch_and_link(instr_info->opcode); + } + else if(inst_Thumb_is_direct_branch(instr_info->opcode)) + { + inst_Thumb_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr); + instr_info->type = OCSD_INSTR_BR; + instr_info->branch_addr = (ocsd_vaddr_t)(branchAddr & ~0x1); + if((branchAddr & 0x1) == 0) + instr_info->next_isa = ocsd_isa_arm; + instr_info->is_link = inst_Thumb_is_branch_and_link(instr_info->opcode); + } + else if((barrier = inst_Thumb_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) + { + switch(barrier) + { + case ARM_BARRIER_ISB: + instr_info->type = OCSD_INSTR_ISB; + break; + + case ARM_BARRIER_DSB: + case ARM_BARRIER_DMB: + if(instr_info->dsb_dmb_waypoints) + instr_info->type = OCSD_INSTR_DSB_DMB; + break; + } + } + + instr_info->is_conditional = inst_Thumb_is_conditional(instr_info->opcode); + instr_info->thumb_it_conditions = inst_Thumb_is_IT(instr_info->opcode); + + return OCSD_OK; +} + + +/* End of File trc_i_decode.cpp */ diff --git a/contrib/opencsd/decoder/source/i_dec/trc_idec_arminst.cpp b/contrib/opencsd/decoder/source/i_dec/trc_idec_arminst.cpp new file mode 100644 index 000000000000..ed7eb247d3be --- /dev/null +++ b/contrib/opencsd/decoder/source/i_dec/trc_idec_arminst.cpp @@ -0,0 +1,561 @@ +/* + * \file trc_idec_arminst.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +/* +Basic ARM/Thumb/A64 instruction decode, suitable for e.g. basic +block identification and trace decode. +*/ + +#include "i_dec/trc_idec_arminst.h" + + +#include /* for NULL */ +#include + + +static ocsd_instr_subtype instr_sub_type = OCSD_S_INSTR_NONE; + +ocsd_instr_subtype get_instr_subtype() +{ + return instr_sub_type; +} + +void clear_instr_subtype() +{ + instr_sub_type = OCSD_S_INSTR_NONE; +} + +int inst_ARM_is_direct_branch(uint32_t inst) +{ + int is_direct_branch = 1; + if ((inst & 0xf0000000) == 0xf0000000) { + /* NV space */ + if ((inst & 0xfe000000) == 0xfa000000){ + /* BLX (imm) */ + } else { + is_direct_branch = 0; + } + } else if ((inst & 0x0e000000) == 0x0a000000) { + /* B, BL */ + } else { + is_direct_branch = 0; + } + return is_direct_branch; +} + + +int inst_ARM_is_indirect_branch(uint32_t inst) +{ + int is_indirect_branch = 1; + if ((inst & 0xf0000000) == 0xf0000000) { + /* NV space */ + if ((inst & 0xfe500000) == 0xf8100000) { + /* RFE */ + } else { + is_indirect_branch = 0; + } + } else if ((inst & 0x0ff000d0) == 0x01200010) { + /* BLX (register), BX */ + } else if ((inst & 0x0e108000) == 0x08108000) { + /* POP {...,pc} or LDMxx {...,pc} */ + } else if ((inst & 0x0e50f000) == 0x0410f000) { + /* LDR PC,imm... inc. POP {PC} */ + } else if ((inst & 0x0e50f010) == 0x0610f000) { + /* LDR PC,reg */ + } else if ((inst & 0x0fe0f000) == 0x01a0f000) { + /* MOV PC,rx */ + } else if ((inst & 0x0f900080) == 0x01000000) { + /* "Miscellaneous instructions" - in DP space */ + is_indirect_branch = 0; + } else if ((inst & 0x0f9000f0) == 0x01800090) { + /* Some extended loads and stores */ + is_indirect_branch = 0; + } else if ((inst & 0x0fb0f000) == 0x0320f000) { + /* MSR #imm */ + is_indirect_branch = 0; + } else if ((inst & 0x0e00f000) == 0x0200f000) { + /* DP PC,imm shift */ + if ((inst & 0x0f90f000) == 0x0310f000) { + /* TST/CMP */ + is_indirect_branch = 0; + } + } else if ((inst & 0x0e00f000) == 0x0000f000) { + /* DP PC,reg */ + } else { + is_indirect_branch = 0; + } + return is_indirect_branch; +} + + +int inst_Thumb_is_direct_branch(uint32_t inst) +{ + int is_direct_branch = 1; + if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) { + /* B (encoding T1) */ + } else if ((inst & 0xf8000000) == 0xe0000000) { + /* B (encoding T2) */ + } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) { + /* B (encoding T3) */ + } else if ((inst & 0xf8009000) == 0xf0009000) { + /* B (encoding T4); BL (encoding T1) */ + } else if ((inst & 0xf800d001) == 0xf000c000) { + /* BLX (imm) (encoding T2) */ + } else if ((inst & 0xf5000000) == 0xb1000000) { + /* CB(NZ) */ + } else { + is_direct_branch = 0; + } + return is_direct_branch; +} + + +int inst_Thumb_is_indirect_branch(uint32_t inst) +{ + /* See e.g. PFT Table 2-3 and Table 2-5 */ + int is_branch = 1; + if ((inst & 0xff000000) == 0x47000000) { + /* BX, BLX (reg) */ + } else if ((inst & 0xff000000) == 0xbd000000) { + /* POP {pc} */ + } else if ((inst & 0xfd870000) == 0x44870000) { + /* MOV PC,reg or ADD PC,reg */ + } else if ((inst & 0xfff0ffe0) == 0xe8d0f000) { + /* TBB/TBH */ + } else if ((inst & 0xffd00000) == 0xe8100000) { + /* RFE (T1) */ + } else if ((inst & 0xffd00000) == 0xe9900000) { + /* RFE (T2) */ + } else if ((inst & 0xfff0d000) == 0xf3d08000) { + /* SUBS PC,LR,#imm inc.ERET */ + } else if ((inst & 0xfff0f000) == 0xf8d0f000) { + /* LDR PC,imm (T3) */ + } else if ((inst & 0xff7ff000) == 0xf85ff000) { + /* LDR PC,literal (T2) */ + } else if ((inst & 0xfff0f800) == 0xf850f800) { + /* LDR PC,imm (T4) */ + } else if ((inst & 0xfff0ffc0) == 0xf850f000) { + /* LDR PC,reg (T2) */ + } else if ((inst & 0xfe508000) == 0xe8108000) { + /* LDM PC */ + } else { + is_branch = 0; + } + return is_branch; +} + + +int inst_A64_is_direct_branch(uint32_t inst) +{ + int is_direct_branch = 1; + if ((inst & 0x7c000000) == 0x34000000) { + /* CB, TB */ + } else if ((inst & 0xff000010) == 0x54000000) { + /* B */ + } else if ((inst & 0x7c000000) == 0x14000000) { + /* B, BL imm */ + } else { + is_direct_branch = 0; + } + return is_direct_branch; +} + + +int inst_A64_is_indirect_branch(uint32_t inst) +{ + int is_indirect_branch = 1; + if ((inst & 0xffdffc1f) == 0xd61f0000) { + /* BR, BLR */ + } else if ((inst & 0xfffffc1f) == 0xd65f0000) { + instr_sub_type = OCSD_S_INSTR_V8_RET; + /* RET */ + } else if ((inst & 0xffffffff) == 0xd69f03e0) { + /* ERET */ + instr_sub_type = OCSD_S_INSTR_V8_ERET; + } else { + is_indirect_branch = 0; + } + return is_indirect_branch; +} + + +int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc) +{ + uint32_t npc; + int is_direct_branch = 1; + if ((inst & 0x0e000000) == 0x0a000000) { + /* + B: cccc:1010:imm24 + BL: cccc:1011:imm24 + BLX: 1111:101H:imm24 + */ + npc = addr + 8 + ((int32_t)((inst & 0xffffff) << 8) >> 6); + if ((inst & 0xf0000000) == 0xf0000000) { + npc |= 1; /* indicate ISA is now Thumb */ + npc |= ((inst >> 23) & 2); /* apply the H bit */ + } + } else { + is_direct_branch = 0; + } + if (is_direct_branch && pnpc != NULL) { + *pnpc = npc; + } + return is_direct_branch; +} + + +int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc) +{ + uint32_t npc; + int is_direct_branch = 1; + if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) { + /* B (encoding T1) */ + npc = addr + 4 + ((int32_t)((inst & 0x00ff0000) << 8) >> 23); + npc |= 1; + } else if ((inst & 0xf8000000) == 0xe0000000) { + /* B (encoding T2) */ + npc = addr + 4 + ((int32_t)((inst & 0x07ff0000) << 5) >> 20); + npc |= 1; + } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) { + /* B (encoding T3) */ + npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) | + ((inst & 0x0800) << 19) | + ((inst & 0x2000) << 16) | + ((inst & 0x003f0000) << 7) | + ((inst & 0x000007ff) << 12)) >> 11); + npc |= 1; + } else if ((inst & 0xf8009000) == 0xf0009000) { + /* B (encoding T4); BL (encoding T1) */ + uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */ + npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) | + (((inst^S) & 0x2000) << 17) | + (((inst^S) & 0x0800) << 18) | + ((inst & 0x03ff0000) << 3) | + ((inst & 0x000007ff) << 8)) >> 7); + npc |= 1; + } else if ((inst & 0xf800d001) == 0xf000c000) { + /* BLX (encoding T2) */ + uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */ + addr &= 0xfffffffc; /* Align(PC,4) */ + npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) | + (((inst^S) & 0x2000) << 17) | + (((inst^S) & 0x0800) << 18) | + ((inst & 0x03ff0000) << 3) | + ((inst & 0x000007fe) << 8)) >> 7); + /* don't set the Thumb bit, as we're transferring to ARM */ + } else if ((inst & 0xf5000000) == 0xb1000000) { + /* CB(NZ) */ + /* Note that it's zero-extended - always a forward branch */ + npc = addr + 4 + ((((inst & 0x02000000) << 6) | + ((inst & 0x00f80000) << 7)) >> 25); + npc |= 1; + } else { + is_direct_branch = 0; + } + if (is_direct_branch && pnpc != NULL) { + *pnpc = npc; + } + return is_direct_branch; +} + + +int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc) +{ + uint64_t npc; + int is_direct_branch = 1; + if ((inst & 0xff000010) == 0x54000000) { + /* B */ + npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11); + } else if ((inst & 0x7c000000) == 0x14000000) { + /* B, BL imm */ + npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4); + } else if ((inst & 0x7e000000) == 0x34000000) { + /* CB */ + npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11); + } else if ((inst & 0x7e000000) == 0x36000000) { + /* TB */ + npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16); + } else { + is_direct_branch = 0; + } + if (is_direct_branch && pnpc != NULL) { + *pnpc = npc; + } + return is_direct_branch; +} + +int inst_ARM_is_branch(uint32_t inst) +{ + return inst_ARM_is_indirect_branch(inst) || + inst_ARM_is_direct_branch(inst); +} + + +int inst_Thumb_is_branch(uint32_t inst) +{ + return inst_Thumb_is_indirect_branch(inst) || + inst_Thumb_is_direct_branch(inst); +} + + +int inst_A64_is_branch(uint32_t inst) +{ + return inst_A64_is_indirect_branch(inst) || + inst_A64_is_direct_branch(inst); +} + + +int inst_ARM_is_branch_and_link(uint32_t inst) +{ + int is_branch = 1; + if ((inst & 0xf0000000) == 0xf0000000) { + if ((inst & 0xfe000000) == 0xfa000000){ + instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BLX (imm) */ + } else { + is_branch = 0; + } + } else if ((inst & 0x0f000000) == 0x0b000000) { + instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BL */ + } else if ((inst & 0x0ff000f0) == 0x01200030) { + instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BLX (reg) */ + } else { + is_branch = 0; + } + return is_branch; +} + + +int inst_Thumb_is_branch_and_link(uint32_t inst) +{ + int is_branch = 1; + if ((inst & 0xff800000) == 0x47800000) { + instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BLX (reg) */ + } else if ((inst & 0xf800c000) == 0xf000c000) { + instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BL, BLX (imm) */ + } else { + is_branch = 0; + } + return is_branch; +} + + +int inst_A64_is_branch_and_link(uint32_t inst) +{ + int is_branch = 1; + if ((inst & 0xfffffc1f) == 0xd63f0000) { + /* BLR */ + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else if ((inst & 0xfc000000) == 0x94000000) { + /* BL */ + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else { + is_branch = 0; + } + return is_branch; +} + + +int inst_ARM_is_conditional(uint32_t inst) +{ + return (inst & 0xe0000000) != 0xe0000000; +} + + +int inst_Thumb_is_conditional(uint32_t inst) +{ + if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) { + /* B (encoding T1) */ + return 1; + } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) { + /* B (encoding T3) */ + return 1; + } else if ((inst & 0xf5000000) == 0xb1000000) { + /* CB(N)Z */ + return 1; + } + return 0; +} + + +unsigned int inst_Thumb_is_IT(uint32_t inst) +{ + if ((inst & 0xff000000) == 0xbf000000 && + (inst & 0x000f0000) != 0x00000000) { + if (inst & 0x00010000) { + return 4; + } else if (inst & 0x00020000) { + return 3; + } else if (inst & 0x00040000) { + return 2; + } else { + assert(inst & 0x00080000); + return 1; + } + } else { + return 0; + } +} + + +/* +Test whether an A64 instruction is conditional. + +Instructions like CSEL, CSINV, CCMP are not classed as conditional. +They use the condition code but do one of two things with it, +neither a NOP. The "intruction categories" section of ETMv4 +lists no (non branch) conditional instructions for A64. +*/ +int inst_A64_is_conditional(uint32_t inst) +{ + if ((inst & 0x7c000000) == 0x34000000) { + /* CB, TB */ + return 1; + } else if ((inst & 0xff000010) == 0x54000000) { + /* B.cond */ + return 1; + } + return 0; +} + + +arm_barrier_t inst_ARM_barrier(uint32_t inst) +{ + if ((inst & 0xfff00000) == 0xf5700000) { + switch (inst & 0xf0) { + case 0x40: + return ARM_BARRIER_DSB; + case 0x50: + return ARM_BARRIER_DMB; + case 0x60: + return ARM_BARRIER_ISB; + default: + return ARM_BARRIER_NONE; + } + } else if ((inst & 0x0fff0f00) == 0x0e070f00) { + switch (inst & 0xff) { + case 0x9a: + return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */ + case 0xba: + return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */ + case 0x95: + return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */ + default: + return ARM_BARRIER_NONE; + } + } else { + return ARM_BARRIER_NONE; + } +} + + +arm_barrier_t inst_Thumb_barrier(uint32_t inst) +{ + if ((inst & 0xffffff00) == 0xf3bf8f00) { + switch (inst & 0xf0) { + case 0x40: + return ARM_BARRIER_DSB; + case 0x50: + return ARM_BARRIER_DMB; + case 0x60: + return ARM_BARRIER_ISB; + default: + return ARM_BARRIER_NONE; + } + } else if ((inst & 0xffff0f00) == 0xee070f00) { + /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */ + switch (inst & 0xff) { + case 0x9a: + return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */ + case 0xba: + return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */ + case 0x95: + return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */ + default: + return ARM_BARRIER_NONE; + } + return ARM_BARRIER_NONE; + } else { + return ARM_BARRIER_NONE; + } +} + + +arm_barrier_t inst_A64_barrier(uint32_t inst) +{ + if ((inst & 0xfffff09f) == 0xd503309f) { + switch (inst & 0x60) { + case 0x0: + return ARM_BARRIER_DSB; + case 0x20: + return ARM_BARRIER_DMB; + case 0x40: + return ARM_BARRIER_ISB; + default: + return ARM_BARRIER_NONE; + } + } else { + return ARM_BARRIER_NONE; + } +} + + +int inst_ARM_is_UDF(uint32_t inst) +{ + return (inst & 0xfff000f0) == 0xe7f000f0; +} + + +int inst_Thumb_is_UDF(uint32_t inst) +{ + return (inst & 0xff000000) == 0xde000000 || /* T1 */ + (inst & 0xfff0f000) == 0xf7f0a000; /* T2 */ +} + + +int inst_A64_is_UDF(uint32_t inst) +{ + /* No A64 encodings are formally allocated as permanently undefined, + but it is intended not to allocate any instructions in the 21-bit + regions at the bottom or top of the range. */ + return (inst & 0xffe00000) == 0x00000000 || + (inst & 0xffe00000) == 0xffe00000; +} + +/* End of File trc_idec_arminst.cpp */ diff --git a/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_base.cpp b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_base.cpp new file mode 100644 index 000000000000..1250bdc42d93 --- /dev/null +++ b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_base.cpp @@ -0,0 +1,148 @@ +/*! + * \file trc_mem_acc_base.cpp + * \brief OpenCSD : Trace memory accessor base class. + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "mem_acc/trc_mem_acc_base.h" +#include "mem_acc/trc_mem_acc_file.h" +#include "mem_acc/trc_mem_acc_cb.h" +#include "mem_acc/trc_mem_acc_bufptr.h" + +#include +#include + + /** Accessor Creation */ +ocsd_err_t TrcMemAccFactory::CreateBufferAccessor(TrcMemAccessorBase **pAccessor, const ocsd_vaddr_t s_address, const uint8_t *p_buffer, const uint32_t size) +{ + ocsd_err_t err = OCSD_OK; + TrcMemAccessorBase *pAcc = 0; + pAcc = new (std::nothrow) TrcMemAccBufPtr(s_address,p_buffer,size); + if(pAcc == 0) + err = OCSD_ERR_MEM; + *pAccessor = pAcc; + return err; +} + +ocsd_err_t TrcMemAccFactory::CreateFileAccessor(TrcMemAccessorBase **pAccessor, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset /*= 0*/, size_t size /*= 0*/) +{ + ocsd_err_t err = OCSD_OK; + TrcMemAccessorFile *pFileAccessor = 0; + err = TrcMemAccessorFile::createFileAccessor(&pFileAccessor, pathToFile, startAddr, offset,size); + *pAccessor = pFileAccessor; + return err; +} + +ocsd_err_t TrcMemAccFactory::CreateCBAccessor(TrcMemAccessorBase **pAccessor, const ocsd_vaddr_t s_address, const ocsd_vaddr_t e_address, const ocsd_mem_space_acc_t mem_space) +{ + ocsd_err_t err = OCSD_OK; + TrcMemAccessorBase *pAcc = 0; + pAcc = new (std::nothrow) TrcMemAccCB(s_address,e_address,mem_space); + if(pAcc == 0) + err = OCSD_ERR_MEM; + *pAccessor = pAcc; + return err; +} + +/** Accessor Destruction */ +void TrcMemAccFactory::DestroyAccessor(TrcMemAccessorBase *pAccessor) +{ + switch(pAccessor->getType()) + { + case TrcMemAccessorBase::MEMACC_FILE: + TrcMemAccessorFile::destroyFileAccessor(dynamic_cast(pAccessor)); + break; + + case TrcMemAccessorBase::MEMACC_CB_IF: + case TrcMemAccessorBase::MEMACC_BUFPTR: + delete pAccessor; + break; + + default: + break; + } +} + + +/* memory access info logging */ +void TrcMemAccessorBase::getMemAccString(std::string &accStr) const +{ + std::ostringstream oss; + + switch(m_type) + { + case MEMACC_FILE: + oss << "FileAcc; Range::0x"; + break; + + case MEMACC_BUFPTR: + oss << "BuffAcc; Range::0x"; + break; + + case MEMACC_CB_IF: + oss << "CB Acc; Range::0x"; + break; + + default: + oss << "UnknAcc; Range::0x"; + break; + } + oss << std::hex << std::setw(2) << std::setfill('0') << m_startAddress << ":" << m_endAddress; + oss << "; Mem Space::"; + switch(m_mem_space) + { + case OCSD_MEM_SPACE_EL1S: oss << "EL1S"; break; + case OCSD_MEM_SPACE_EL1N: oss << "EL1N"; break; + case OCSD_MEM_SPACE_EL2: oss << "EL2"; break; + case OCSD_MEM_SPACE_EL3: oss << "EL3"; break; + case OCSD_MEM_SPACE_S: oss << "Any S"; break; + case OCSD_MEM_SPACE_N: oss << "Any NS"; break; + case OCSD_MEM_SPACE_ANY: oss << "Any"; break; + + default: + { + uint8_t MSBits = (uint8_t)m_mem_space; + if(MSBits & (uint8_t)OCSD_MEM_SPACE_EL1S) + oss << "EL1S,"; + if(MSBits & (uint8_t)OCSD_MEM_SPACE_EL1N) + oss << "EL1N,"; + if(MSBits & (uint8_t)OCSD_MEM_SPACE_EL2) + oss << "EL2,"; + if(MSBits & (uint8_t)OCSD_MEM_SPACE_EL3) + oss << "EL3,"; + } + break; + } + accStr = oss.str(); +} + +/* End of File trc_mem_acc_base.cpp */ diff --git a/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp new file mode 100644 index 000000000000..fee663b30d06 --- /dev/null +++ b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp @@ -0,0 +1,54 @@ +/* + * \file trc_mem_acc_bufptr.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ +#include + +#include "mem_acc/trc_mem_acc_bufptr.h" + +TrcMemAccBufPtr::TrcMemAccBufPtr(const ocsd_vaddr_t s_address, const uint8_t *p_buffer, const uint32_t size) : + TrcMemAccessorBase(MEMACC_BUFPTR, s_address, s_address+size-1), + m_p_buffer(p_buffer), + m_size(size) +{ +} + +const uint32_t TrcMemAccBufPtr::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer) +{ + // mapper wlll filter memory spaces. + uint32_t bytesRead = bytesInRange(address,reqBytes); // check bytes available + if(bytesRead) + memcpy(byteBuffer,m_p_buffer+address-m_startAddress,bytesRead); + return bytesRead; +} + +/* End of File trc_mem_acc_bufptr.cpp */ diff --git a/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cb.cpp b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cb.cpp new file mode 100644 index 000000000000..28dedcb0fba6 --- /dev/null +++ b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cb.cpp @@ -0,0 +1,32 @@ +/*! + * \file trc_mem_acc_cb.cpp + * \brief OpenCSD : Trace Mem accessor - callback function + * + * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + */ + +#include "mem_acc/trc_mem_acc_cb.h" + +TrcMemAccCB::TrcMemAccCB(const ocsd_vaddr_t s_address, + const ocsd_vaddr_t e_address, + const ocsd_mem_space_acc_t mem_space) : + TrcMemAccessorBase(MEMACC_CB_IF, s_address, e_address), + m_p_CBclass(0), + m_p_CBfn(0), + m_p_cbfn_context(0) +{ + setMemSpace(mem_space); +} + +/** Memory access override - allow decoder to read bytes from the buffer. */ +const uint32_t TrcMemAccCB::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer) +{ + // if we have a callback object, use it to call back. + if(m_p_CBclass) + return m_p_CBclass->readBytes(address,memSpace,reqBytes,byteBuffer); + if(m_p_CBfn) + return m_p_CBfn(m_p_cbfn_context, address,memSpace,reqBytes,byteBuffer); + return 0; +} + +/* End of File trc_mem_acc_cb.cpp */ diff --git a/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_file.cpp b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_file.cpp new file mode 100644 index 000000000000..87901c83dcee --- /dev/null +++ b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_file.cpp @@ -0,0 +1,391 @@ +/* + * \file trc_mem_acc_file.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "mem_acc/trc_mem_acc_file.h" + +#include +#include + +/***************************************************/ +/* protected construction and reference counting */ +/***************************************************/ + +TrcMemAccessorFile::TrcMemAccessorFile() : TrcMemAccessorBase(MEMACC_FILE) +{ + m_ref_count = 0; + m_base_range_set = false; + m_has_access_regions = false; + m_file_size = 0; +} + +TrcMemAccessorFile::~TrcMemAccessorFile() +{ + if(m_mem_file.is_open()) + m_mem_file.close(); + if(m_access_regions.size()) + { + std::list::iterator it; + it = m_access_regions.begin(); + while(it != m_access_regions.end()) + { + delete (*it); + it++; + } + m_access_regions.clear(); + } +} + +ocsd_err_t TrcMemAccessorFile::initAccessor(const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset, size_t size) +{ + ocsd_err_t err = OCSD_OK; + bool init = false; + + m_mem_file.open(pathToFile.c_str(), std::ifstream::binary | std::ifstream::ate); + if(m_mem_file.is_open()) + { + m_file_size = (ocsd_vaddr_t)m_mem_file.tellg() & ((ocsd_vaddr_t)~0x1); + m_mem_file.seekg(0, m_mem_file.beg); + // adding an offset of 0, sets the base range. + if((offset == 0) && (size == 0)) + { + init = AddOffsetRange(startAddr, ((size_t)m_file_size)-offset, offset); + } + else if((offset + size) <= m_file_size) + { + // if offset != 0, size must by != 0 + init = AddOffsetRange(startAddr, size, offset); + } + m_file_path = pathToFile; + } + else + err = OCSD_ERR_MEM_ACC_FILE_NOT_FOUND; + if(!init) + err = OCSD_ERR_NOT_INIT; + return err; +} + + +FileRegionMemAccessor *TrcMemAccessorFile::getRegionForAddress(const ocsd_vaddr_t startAddr) const +{ + FileRegionMemAccessor *p_region = 0; + if(m_has_access_regions) + { + std::list::const_iterator it; + it = m_access_regions.begin(); + while((it != m_access_regions.end()) && (p_region == 0)) + { + if((*it)->addrInRange(startAddr)) + p_region = *it; + it++; + } + } + return p_region; +} + + +/***************************************************/ +/* static object creation */ +/***************************************************/ + +std::map TrcMemAccessorFile::s_FileAccessorMap; + +// return existing or create new accessor +ocsd_err_t TrcMemAccessorFile::createFileAccessor(TrcMemAccessorFile **p_acc, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset /*= 0*/, size_t size /*= 0*/) +{ + ocsd_err_t err = OCSD_OK; + TrcMemAccessorFile * acc = 0; + std::map::iterator it = s_FileAccessorMap.find(pathToFile); + if(it != s_FileAccessorMap.end()) + { + acc = it->second; + if(acc->addrStartOfRange(startAddr)) + acc->IncRefCount(); + else + { + err = OCSD_ERR_MEM_ACC_FILE_DIFF_RANGE; + acc = 0; + } + } + else + { + acc = new (std::nothrow) TrcMemAccessorFile(); + if(acc != 0) + { + if((err = acc->initAccessor(pathToFile,startAddr, offset,size)) == OCSD_OK) + { + acc->IncRefCount(); + s_FileAccessorMap.insert(std::pair(pathToFile,acc)); + } + else + { + delete acc; + acc = 0; + } + } + else + err = OCSD_ERR_MEM; + } + *p_acc = acc; + return err; +} + +void TrcMemAccessorFile::destroyFileAccessor(TrcMemAccessorFile *p_accessor) +{ + if(p_accessor != 0) + { + p_accessor->DecRefCount(); + if(p_accessor->getRefCount() == 0) + { + std::map::iterator it = s_FileAccessorMap.find(p_accessor->getFilePath()); + if(it != s_FileAccessorMap.end()) + { + s_FileAccessorMap.erase(it); + } + delete p_accessor; + } + } +} + +const bool TrcMemAccessorFile::isExistingFileAccessor(const std::string &pathToFile) +{ + bool bExists = false; + std::map::const_iterator it = s_FileAccessorMap.find(pathToFile); + if(it != s_FileAccessorMap.end()) + bExists = true; + return bExists; +} + +TrcMemAccessorFile * TrcMemAccessorFile::getExistingFileAccessor(const std::string &pathToFile) +{ + TrcMemAccessorFile * p_acc = 0; + std::map::iterator it = s_FileAccessorMap.find(pathToFile); + if(it != s_FileAccessorMap.end()) + p_acc = it->second; + return p_acc; +} + + + +/***************************************************/ +/* accessor instance functions */ +/***************************************************/ +const uint32_t TrcMemAccessorFile::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer) +{ + if(!m_mem_file.is_open()) + return 0; + uint32_t bytesRead = 0; + + if(m_base_range_set) + { + bytesRead = TrcMemAccessorBase::bytesInRange(address,reqBytes); // get avialable bytes in range. + if(bytesRead) + { + ocsd_vaddr_t addr_pos = (ocsd_vaddr_t)m_mem_file.tellg(); + if((address - m_startAddress) != addr_pos) + m_mem_file.seekg(address - m_startAddress); + m_mem_file.read((char *)byteBuffer,bytesRead); + } + } + + if((bytesRead == 0) && m_has_access_regions) + { + bytesRead = bytesInRange(address,reqBytes); + if(bytesRead) + { + FileRegionMemAccessor *p_region = getRegionForAddress(address); + ocsd_vaddr_t addr_pos = (ocsd_vaddr_t)m_mem_file.tellg(); + if((address - p_region->regionStartAddress() + p_region->getOffset()) != addr_pos) + m_mem_file.seekg(address - p_region->regionStartAddress() + p_region->getOffset()); + m_mem_file.read((char *)byteBuffer,bytesRead); + } + } + return bytesRead; +} + +bool TrcMemAccessorFile::AddOffsetRange(const ocsd_vaddr_t startAddr, const size_t size, const size_t offset) +{ + bool addOK = false; + if(m_file_size == 0) // must have set the file size + return false; + if(addrInRange(startAddr) || addrInRange(startAddr+size-1)) // cannot be overlapping + return false; + + // now either set the base range or an offset range + if(offset == 0) + { + if(!m_base_range_set) + { + setRange(startAddr, startAddr+size-1); + m_base_range_set = true; + addOK = true; + } + } + else + { + if((offset + size) <= m_file_size) + { + FileRegionMemAccessor *frmacc = new (std::nothrow) FileRegionMemAccessor(); + if(frmacc) + { + frmacc->setOffset(offset); + frmacc->setRange(startAddr,startAddr+size-1); + m_access_regions.push_back(frmacc); + m_access_regions.sort(); + // may need to trim the 0 offset base range... + if(m_base_range_set) + { + std::list::iterator it; + it = m_access_regions.begin(); + size_t first_range_offset = (*it)->getOffset(); + if((m_startAddress + first_range_offset - 1) > m_endAddress) + m_endAddress = m_startAddress + first_range_offset - 1; + } + addOK = true; + m_has_access_regions = true; + } + } + } + return addOK; +} + +const bool TrcMemAccessorFile::addrInRange(const ocsd_vaddr_t s_address) const +{ + bool bInRange = false; + if(m_base_range_set) + bInRange = TrcMemAccessorBase::addrInRange(s_address); + + if(!bInRange && m_has_access_regions) + { + if(getRegionForAddress(s_address) != 0) + bInRange = true; + } + return bInRange; +} + +const bool TrcMemAccessorFile::addrStartOfRange(const ocsd_vaddr_t s_address) const +{ + bool bInRange = false; + if(m_base_range_set) + bInRange = TrcMemAccessorBase::addrStartOfRange(s_address); + if(!bInRange && m_has_access_regions) + { + FileRegionMemAccessor *pRegion = getRegionForAddress(s_address); + if(pRegion) + bInRange = (pRegion->regionStartAddress() == s_address); + } + return bInRange; +} + + + /* validate ranges */ +const bool TrcMemAccessorFile::validateRange() +{ + bool bRangeValid = true; + if(m_base_range_set) + bRangeValid = TrcMemAccessorBase::validateRange(); + + if(m_has_access_regions && bRangeValid) + { + std::list::const_iterator it; + it = m_access_regions.begin(); + while((it != m_access_regions.end()) && bRangeValid) + { + bRangeValid = (*it)->validateRange(); + it++; + } + } + return bRangeValid; +} + +const uint32_t TrcMemAccessorFile::bytesInRange(const ocsd_vaddr_t s_address, const uint32_t reqBytes) const +{ + uint32_t bytesInRange = 0; + if(m_base_range_set) + bytesInRange = TrcMemAccessorBase::bytesInRange(s_address,reqBytes); + + if((bytesInRange == 0) && (m_has_access_regions)) + { + FileRegionMemAccessor *p_region = getRegionForAddress(s_address); + bytesInRange = p_region->bytesInRange(s_address,reqBytes); + } + + return bytesInRange; +} + +const bool TrcMemAccessorFile::overLapRange(const TrcMemAccessorBase *p_test_acc) const +{ + bool bOverLapRange = false; + if(m_base_range_set) + bOverLapRange = TrcMemAccessorBase::overLapRange(p_test_acc); + + if(!bOverLapRange && (m_has_access_regions)) + { + std::list::const_iterator it; + it = m_access_regions.begin(); + while((it != m_access_regions.end()) && !bOverLapRange) + { + bOverLapRange = (*it)->overLapRange(p_test_acc); + it++; + } + } + return bOverLapRange; +} + + /*! Override to handle ranges and offset accessors plus add in file name. */ +void TrcMemAccessorFile::getMemAccString(std::string &accStr) const +{ + std::ostringstream oss; + accStr = ""; + if(m_base_range_set) + { + TrcMemAccessorBase::getMemAccString(accStr); + } + + if(m_has_access_regions) + { + std::string addStr; + std::list::const_iterator it; + it = m_access_regions.begin(); + while(it != m_access_regions.end()) + { + (*it)->getMemAccString(addStr); + if(accStr.length()) + accStr += "\n"; + accStr += addStr; + it++; + } + } + accStr += (std::string)"\nFilename=" + m_file_path; +} + +/* End of File trc_mem_acc_file.cpp */ diff --git a/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp new file mode 100644 index 000000000000..6d4f085c6fa0 --- /dev/null +++ b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp @@ -0,0 +1,238 @@ +/* + * \file trc_mem_acc_mapper.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "mem_acc/trc_mem_acc_mapper.h" +#include "mem_acc/trc_mem_acc_file.h" + +/************************************************************************************/ +/* mappers base class */ +/************************************************************************************/ + +TrcMemAccMapper::TrcMemAccMapper() : + m_acc_curr(0), + m_trace_id_curr(0), + m_using_trace_id(false), + m_err_log(0) +{ +} + +TrcMemAccMapper::TrcMemAccMapper(bool using_trace_id) : + m_acc_curr(0), + m_trace_id_curr(0), + m_using_trace_id(using_trace_id), + m_err_log(0) +{ +} + +TrcMemAccMapper::~TrcMemAccMapper() +{ +} + +// memory access interface +ocsd_err_t TrcMemAccMapper::ReadTargetMemory(const ocsd_vaddr_t address, const uint8_t cs_trace_id, const ocsd_mem_space_acc_t mem_space, uint32_t *num_bytes, uint8_t *p_buffer) +{ + bool bReadFromCurr = true; + + /* see if the address is in any range we know */ + if(!readFromCurrent(address, mem_space, cs_trace_id)) + bReadFromCurr = findAccessor(address, mem_space, cs_trace_id); + + /* if bReadFromCurr then we know m_acc_curr is set */ + if(bReadFromCurr) + *num_bytes = m_acc_curr->readBytes(address, mem_space, *num_bytes,p_buffer); + else + *num_bytes = 0; + return OCSD_OK; +} + +void TrcMemAccMapper::RemoveAllAccessors() +{ + TrcMemAccessorBase *pAcc = 0; + pAcc = getFirstAccessor(); + while(pAcc != 0) + { + TrcMemAccFactory::DestroyAccessor(pAcc); + pAcc = getNextAccessor(); + } + clearAccessorList(); +} + +ocsd_err_t TrcMemAccMapper::RemoveAccessorByAddress(const ocsd_vaddr_t st_address, const ocsd_mem_space_acc_t mem_space, const uint8_t cs_trace_id /* = 0 */) +{ + ocsd_err_t err = OCSD_OK; + if(findAccessor(st_address,mem_space,cs_trace_id)) + { + err = RemoveAccessor(m_acc_curr); + m_acc_curr = 0; + } + else + err = OCSD_ERR_INVALID_PARAM_VAL; + return err; +} + +void TrcMemAccMapper::LogMessage(const std::string &msg) +{ + if(m_err_log) + m_err_log->LogMessage(ITraceErrorLog::HANDLE_GEN_INFO,OCSD_ERR_SEV_INFO,msg); +} + +/************************************************************************************/ +/* mappers global address space class - no differentiation in core trace IDs */ +/************************************************************************************/ +TrcMemAccMapGlobalSpace::TrcMemAccMapGlobalSpace() : TrcMemAccMapper() +{ +} + +TrcMemAccMapGlobalSpace::~TrcMemAccMapGlobalSpace() +{ +} + +ocsd_err_t TrcMemAccMapGlobalSpace::AddAccessor(TrcMemAccessorBase *p_accessor, const uint8_t /*cs_trace_id*/) +{ + ocsd_err_t err = OCSD_OK; + bool bOverLap = false; + + if(!p_accessor->validateRange()) + return OCSD_ERR_MEM_ACC_RANGE_INVALID; + + std::vector::const_iterator it = m_acc_global.begin(); + while((it != m_acc_global.end()) && !bOverLap) + { + // if overlap and memory space match + if( ((*it)->overLapRange(p_accessor)) && + ((*it)->inMemSpace(p_accessor->getMemSpace())) + ) + { + bOverLap = true; + err = OCSD_ERR_MEM_ACC_OVERLAP; + } + it++; + } + + // no overlap - add to the list of ranges. + if(!bOverLap) + m_acc_global.push_back(p_accessor); + + return err; +} + +bool TrcMemAccMapGlobalSpace::findAccessor(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t /*cs_trace_id*/) +{ + bool bFound = false; + std::vector::const_iterator it = m_acc_global.begin(); + while((it != m_acc_global.end()) && !bFound) + { + if( (*it)->addrInRange(address) && + (*it)->inMemSpace(mem_space)) + { + bFound = true; + m_acc_curr = *it; + } + it++; + } + return bFound; +} + +bool TrcMemAccMapGlobalSpace::readFromCurrent(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t /*cs_trace_id*/) +{ + bool readFromCurr = false; + if(m_acc_curr) + readFromCurr = (m_acc_curr->addrInRange(address) && m_acc_curr->inMemSpace(mem_space)); + return readFromCurr; +} + + +TrcMemAccessorBase * TrcMemAccMapGlobalSpace::getFirstAccessor() +{ + TrcMemAccessorBase *p_acc = 0; + m_acc_it = m_acc_global.begin(); + if(m_acc_it != m_acc_global.end()) + { + p_acc = *m_acc_it; + } + return p_acc; +} + +TrcMemAccessorBase *TrcMemAccMapGlobalSpace::getNextAccessor() +{ + TrcMemAccessorBase *p_acc = 0; + m_acc_it++; + if(m_acc_it != m_acc_global.end()) + { + p_acc = *m_acc_it; + } + return p_acc; +} + +void TrcMemAccMapGlobalSpace::clearAccessorList() +{ + m_acc_global.clear(); +} + +ocsd_err_t TrcMemAccMapGlobalSpace::RemoveAccessor(const TrcMemAccessorBase *p_accessor) +{ + bool bFound = false; + TrcMemAccessorBase *p_acc = getFirstAccessor(); + while(p_acc != 0) + { + if(p_acc == p_accessor) + { + m_acc_global.erase(m_acc_it); + TrcMemAccFactory::DestroyAccessor(p_acc); + p_acc = 0; + bFound = true; + } + else + p_acc = getNextAccessor(); + } + return bFound ? OCSD_OK : OCSD_ERR_INVALID_PARAM_VAL; +} + + +void TrcMemAccMapGlobalSpace::logMappedRanges() +{ + std::string accStr; + TrcMemAccessorBase *pAccessor = getFirstAccessor(); + LogMessage("Mapped Memory Accessors\n"); + while(pAccessor != 0) + { + pAccessor->getMemAccString(accStr); + accStr += "\n"; + LogMessage(accStr); + pAccessor = getNextAccessor(); + } + LogMessage("========================\n"); +} + +/* End of File trc_mem_acc_mapper.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_code_follower.cpp b/contrib/opencsd/decoder/source/ocsd_code_follower.cpp new file mode 100644 index 000000000000..229859e4733a --- /dev/null +++ b/contrib/opencsd/decoder/source/ocsd_code_follower.cpp @@ -0,0 +1,161 @@ +/* + * \file ocsd_code_follower.cpp + * \brief OpenCSD : Instruction Code path follower. + * + * \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. + */ + +#include "common/ocsd_code_follower.h" + +OcsdCodeFollower::OcsdCodeFollower() +{ + m_instr_info.pe_type.arch = ARCH_UNKNOWN; + m_instr_info.pe_type.profile = profile_Unknown; + m_instr_info.isa = ocsd_isa_unknown; + m_instr_info.dsb_dmb_waypoints = 0; + m_instr_info.instr_addr = 0; + m_instr_info.opcode = 0; + m_pMemAccess = 0; + m_pIDecode = 0; + m_mem_space_csid = 0; + m_st_range_addr = m_en_range_addr = m_next_addr = 0; + m_b_next_valid = false; + m_b_nacc_err = false; +} + +OcsdCodeFollower::~OcsdCodeFollower() +{ +} + +void OcsdCodeFollower::initInterfaces(componentAttachPt *pMemAccess, componentAttachPt *pIDecode) +{ + m_pMemAccess = pMemAccess; + m_pIDecode = pIDecode; +} + +bool OcsdCodeFollower::initFollowerState() +{ + bool initDone = false; + + // reset per follow flags + m_b_next_valid = false; + m_b_nacc_err = false; + + // set range addresses + m_en_range_addr = m_next_addr = m_st_range_addr; + +// check initialisation is valid. + + // must have attached memory access and i-decode objects + if(m_pMemAccess && m_pIDecode) + { + initDone = (m_pMemAccess->hasAttachedAndEnabled() && m_pIDecode->hasAttachedAndEnabled()); + } + return initDone; +} + +/*! + * Decodes an instruction at a single location, calculates the next address + * if possible according to the instruction type and atom. + * + * @param addrStart : Address of the instruction + * @param A : Atom value - E or N + * + * @return ocsd_err_t : OCSD_OK - decode correct, check flags for next address + * : OCSD_ERR_MEM_NACC - unable to access memory area @ address - need new address in trace packet stream. + * : OCSD_ERR_NOT_INIT - not initialised - fatal. + * : OCSD_ - other error occured - fatal. + */ +ocsd_err_t OcsdCodeFollower::followSingleAtom(const ocsd_vaddr_t addrStart, const ocsd_atm_val A) +{ + ocsd_err_t err = OCSD_ERR_NOT_INIT; + + if(!initFollowerState()) + return err; + + m_en_range_addr = m_st_range_addr = m_instr_info.instr_addr = addrStart; + err = decodeSingleOpCode(); + + if(err != OCSD_OK) + return err; + + // set end range - always after the instruction executed. + m_en_range_addr = m_instr_info.instr_addr + m_instr_info.instr_size; + + // assume next addr is the instruction after + m_next_addr = m_en_range_addr; + m_b_next_valid = true; + + // case when next address is different + switch(m_instr_info.type) + { + case OCSD_INSTR_BR: + if(A == ATOM_E) // executed the direct branch + m_next_addr = m_instr_info.branch_addr; + break; + + case OCSD_INSTR_BR_INDIRECT: + if(A == ATOM_E) // executed indirect branch + m_b_next_valid = false; + break; + } + return err; +} + +ocsd_err_t OcsdCodeFollower::decodeSingleOpCode() +{ + ocsd_err_t err = OCSD_OK; + // request 4 bytes for the opcode - even for Thumb which may be T32 + uint32_t bytesReq = 4; + uint32_t opcode; // buffer for opcode + + // read memory location for opcode + err = m_pMemAccess->first()->ReadTargetMemory(m_instr_info.instr_addr,m_mem_space_csid,m_mem_acc_rule,&bytesReq,(uint8_t *)&opcode); + + // operational error (not access problem - that is indicated by 0 bytes returned) + if(err != OCSD_OK) + return err; + + if(bytesReq == 4) // check that we got all memory requested. + { + m_instr_info.opcode = opcode; + err = m_pIDecode->first()->DecodeInstruction(&m_instr_info); + } + else // otherwise memory unavailable. + { + m_b_nacc_err = true; + m_nacc_address = m_instr_info.instr_addr; + err = OCSD_ERR_MEM_NACC; + } + return err; +} + +/* End of File ocsd_code_follower.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp b/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp new file mode 100644 index 000000000000..0cce1340c759 --- /dev/null +++ b/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp @@ -0,0 +1,671 @@ +/* + * \file ocsd_dcd_tree.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "common/ocsd_dcd_tree.h" +#include "common/ocsd_lib_dcd_register.h" +#include "mem_acc/trc_mem_acc_mapper.h" + +/***************************************************************/ +ITraceErrorLog *DecodeTree::s_i_error_logger = &DecodeTree::s_error_logger; +std::list DecodeTree::s_trace_dcd_trees; /**< list of pointers to decode tree objects */ +ocsdDefaultErrorLogger DecodeTree::s_error_logger; /**< The library default error logger */ +TrcIDecode DecodeTree::s_instruction_decoder; /**< default instruction decode library */ + +DecodeTree *DecodeTree::CreateDecodeTree(const ocsd_dcd_tree_src_t src_type, uint32_t formatterCfgFlags) +{ + DecodeTree *dcd_tree = new (std::nothrow) DecodeTree(); + if(dcd_tree != 0) + { + if(dcd_tree->initialise(src_type, formatterCfgFlags)) + { + s_trace_dcd_trees.push_back(dcd_tree); + } + else + { + delete dcd_tree; + dcd_tree = 0; + } + } + return dcd_tree; +} + +void DecodeTree::DestroyDecodeTree(DecodeTree *p_dcd_tree) +{ + std::list::iterator it; + bool bDestroyed = false; + it = s_trace_dcd_trees.begin(); + while(!bDestroyed && (it != s_trace_dcd_trees.end())) + { + if(*it == p_dcd_tree) + { + s_trace_dcd_trees.erase(it); + delete p_dcd_tree; + bDestroyed = true; + } + else + it++; + } +} + +void DecodeTree::setAlternateErrorLogger(ITraceErrorLog *p_error_logger) +{ + if(p_error_logger) + s_i_error_logger = p_error_logger; + else + s_i_error_logger = &s_error_logger; +} + +/***************************************************************/ + +DecodeTree::DecodeTree() : + m_i_instr_decode(&s_instruction_decoder), + m_i_mem_access(0), + m_i_gen_elem_out(0), + m_i_decoder_root(0), + m_frame_deformatter_root(0), + m_decode_elem_iter(0), + m_default_mapper(0), + m_created_mapper(false) +{ + for(int i = 0; i < 0x80; i++) + m_decode_elements[i] = 0; +} + +DecodeTree::~DecodeTree() +{ + for(uint8_t i = 0; i < 0x80; i++) + { + destroyDecodeElement(i); + } + PktPrinterFact::destroyAllPrinters(m_printer_list); +} + + + +ocsd_datapath_resp_t DecodeTree::TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + if(m_i_decoder_root) + return m_i_decoder_root->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed); + *numBytesProcessed = 0; + return OCSD_RESP_FATAL_NOT_INIT; +} + +/* set key interfaces - attach / replace on any existing tree components */ +void DecodeTree::setInstrDecoder(IInstrDecode *i_instr_decode) +{ + uint8_t elemID; + DecodeTreeElement *pElem = 0; + + pElem = getFirstElement(elemID); + while(pElem != 0) + { + pElem->getDecoderMngr()->attachInstrDecoder(pElem->getDecoderHandle(),i_instr_decode); + pElem = getNextElement(elemID); + } +} + +void DecodeTree::setMemAccessI(ITargetMemAccess *i_mem_access) +{ + uint8_t elemID; + DecodeTreeElement *pElem = 0; + + pElem = getFirstElement(elemID); + while(pElem != 0) + { + pElem->getDecoderMngr()->attachMemAccessor(pElem->getDecoderHandle(),i_mem_access); + pElem = getNextElement(elemID); + } + m_i_mem_access = i_mem_access; +} + +void DecodeTree::setGenTraceElemOutI(ITrcGenElemIn *i_gen_trace_elem) +{ + uint8_t elemID; + DecodeTreeElement *pElem = 0; + + pElem = getFirstElement(elemID); + while(pElem != 0) + { + pElem->getDecoderMngr()->attachOutputSink(pElem->getDecoderHandle(),i_gen_trace_elem); + pElem = getNextElement(elemID); + } +} + +ocsd_err_t DecodeTree::createMemAccMapper(memacc_mapper_t type /* = MEMACC_MAP_GLOBAL*/ ) +{ + // clean up any old one + destroyMemAccMapper(); + + // make a new one + switch(type) + { + default: + case MEMACC_MAP_GLOBAL: + m_default_mapper = new (std::nothrow) TrcMemAccMapGlobalSpace(); + break; + } + + // set the access interface + if(m_default_mapper) + { + m_created_mapper = true; + setMemAccessI(m_default_mapper); + m_default_mapper->setErrorLog(s_i_error_logger); + } + + return (m_default_mapper != 0) ? OCSD_OK : OCSD_ERR_MEM; +} + +void DecodeTree::setExternMemAccMapper(TrcMemAccMapper* pMapper) +{ + destroyMemAccMapper(); // destroy any existing mapper - if decode tree created it. + m_default_mapper = pMapper; +} + +void DecodeTree::destroyMemAccMapper() +{ + if(m_default_mapper && m_created_mapper) + { + m_default_mapper->RemoveAllAccessors(); + delete m_default_mapper; + m_default_mapper = 0; + m_created_mapper = false; + } +} + +void DecodeTree::logMappedRanges() +{ + if(m_default_mapper) + m_default_mapper->logMappedRanges(); +} + +/* Memory accessor creation - all on default mem accessor using the 0 CSID for global core space. */ +ocsd_err_t DecodeTree::addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length) +{ + if(!hasMemAccMapper()) + return OCSD_ERR_NOT_INIT; + + // need a valid memory buffer, and a least enough bytes for one opcode. + if((p_mem_buffer == 0) || (mem_length < 4)) + return OCSD_ERR_INVALID_PARAM_VAL; + + TrcMemAccessorBase *p_accessor; + ocsd_err_t err = TrcMemAccFactory::CreateBufferAccessor(&p_accessor, address, p_mem_buffer, mem_length); + if(err == OCSD_OK) + { + TrcMemAccBufPtr *pMBuffAcc = dynamic_cast(p_accessor); + if(pMBuffAcc) + { + pMBuffAcc->setMemSpace(mem_space); + err = m_default_mapper->AddAccessor(p_accessor,0); + } + else + err = OCSD_ERR_MEM; // wrong type of object - treat as mem error + + if(err != OCSD_OK) + TrcMemAccFactory::DestroyAccessor(p_accessor); + } + return err; +} + +ocsd_err_t DecodeTree::addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath) +{ + if(!hasMemAccMapper()) + return OCSD_ERR_NOT_INIT; + + if(filepath.length() == 0) + return OCSD_ERR_INVALID_PARAM_VAL; + + TrcMemAccessorBase *p_accessor; + ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,address); + + if(err == OCSD_OK) + { + TrcMemAccessorFile *pAcc = dynamic_cast(p_accessor); + if(pAcc) + { + pAcc->setMemSpace(mem_space); + err = m_default_mapper->AddAccessor(pAcc,0); + } + else + err = OCSD_ERR_MEM; // wrong type of object - treat as mem error + + if(err != OCSD_OK) + TrcMemAccFactory::DestroyAccessor(p_accessor); + } + return err; + +} + +ocsd_err_t DecodeTree::addBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath) +{ + if(!hasMemAccMapper()) + return OCSD_ERR_NOT_INIT; + + if((region_array == 0) || (num_regions == 0) || (filepath.length() == 0)) + return OCSD_ERR_INVALID_PARAM_VAL; + + TrcMemAccessorBase *p_accessor; + int curr_region_idx = 0; + + // add first region during the creation of the file accessor. + ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,region_array[curr_region_idx].start_address,region_array[curr_region_idx].file_offset, region_array[curr_region_idx].region_size); + if(err == OCSD_OK) + { + TrcMemAccessorFile *pAcc = dynamic_cast(p_accessor); + if(pAcc) + { + // add additional regions to the file accessor. + curr_region_idx++; + while(curr_region_idx < num_regions) + { + pAcc->AddOffsetRange(region_array[curr_region_idx].start_address, + region_array[curr_region_idx].region_size, + region_array[curr_region_idx].file_offset); + curr_region_idx++; + } + pAcc->setMemSpace(mem_space); + + // add the accessor to the map. + err = m_default_mapper->AddAccessor(pAcc,0); + } + else + err = OCSD_ERR_MEM; // wrong type of object - treat as mem error + + if(err != OCSD_OK) + TrcMemAccFactory::DestroyAccessor(p_accessor); + } + return err; +} + +ocsd_err_t DecodeTree::addCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context) +{ + if(!hasMemAccMapper()) + return OCSD_ERR_NOT_INIT; + + if(p_cb_func == 0) + return OCSD_ERR_INVALID_PARAM_VAL; + + TrcMemAccessorBase *p_accessor; + ocsd_err_t err = TrcMemAccFactory::CreateCBAccessor(&p_accessor, st_address, en_address, mem_space); + if(err == OCSD_OK) + { + TrcMemAccCB *pCBAcc = dynamic_cast(p_accessor); + if(pCBAcc) + { + pCBAcc->setCBIfFn(p_cb_func, p_context); + err = m_default_mapper->AddAccessor(p_accessor,0); + } + else + err = OCSD_ERR_MEM; // wrong type of object - treat as mem error + + if(err != OCSD_OK) + TrcMemAccFactory::DestroyAccessor(p_accessor); + } + return err; +} + +ocsd_err_t DecodeTree::removeMemAccByAddress(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space) +{ + if(!hasMemAccMapper()) + return OCSD_ERR_NOT_INIT; + return m_default_mapper->RemoveAccessorByAddress(address,mem_space,0); +} + +ocsd_err_t DecodeTree::createDecoder(const std::string &decoderName, const int createFlags, const CSConfig *pConfig) +{ + ocsd_err_t err = OCSD_OK; + IDecoderMngr *pDecoderMngr = 0; + TraceComponent *pTraceComp = 0; + int crtFlags = createFlags; + + uint8_t CSID = 0; // default for single stream decoder (no deformatter) - we ignore the ID + if(usingFormatter()) + { + CSID = pConfig->getTraceID(); + crtFlags |= OCSD_CREATE_FLG_INST_ID; + } + + // create the decode element to attach to the channel. + if((err = createDecodeElement(CSID)) != OCSD_OK) + return err; + + // get the libary decoder register. + OcsdLibDcdRegister * lib_reg = OcsdLibDcdRegister::getDecoderRegister(); + if(lib_reg == 0) + return OCSD_ERR_NOT_INIT; + + // find the named decoder + if((err = lib_reg->getDecoderMngrByName(decoderName,&pDecoderMngr)) != OCSD_OK) + return err; + + // got the decoder... + if((err = pDecoderMngr->createDecoder(crtFlags,(int)CSID,pConfig,&pTraceComp)) != OCSD_OK) + return err; + + m_decode_elements[CSID]->SetDecoderElement(decoderName, pDecoderMngr, pTraceComp, true); + + // always attach an error logger + if(err == OCSD_OK) + err = pDecoderMngr->attachErrorLogger(pTraceComp,DecodeTree::s_i_error_logger); + + // if we created a packet decoder it may need additional components. + if(crtFlags & OCSD_CREATE_FLG_FULL_DECODER) + { + if(m_i_instr_decode && (err == OCSD_OK)) + err = pDecoderMngr->attachInstrDecoder(pTraceComp,m_i_instr_decode); + + if(err == OCSD_ERR_DCD_INTERFACE_UNUSED) // ignore if instruction decoder refused + err = OCSD_OK; + + if(m_i_mem_access && (err == OCSD_OK)) + err = pDecoderMngr->attachMemAccessor(pTraceComp,m_i_mem_access); + + if(err == OCSD_ERR_DCD_INTERFACE_UNUSED) // ignore if mem accessor refused + err = OCSD_OK; + + if( m_i_gen_elem_out && (err == OCSD_OK)) + err = pDecoderMngr->attachOutputSink(pTraceComp,m_i_gen_elem_out); + } + + // finally attach the packet processor input to the demux output channel + if(err == OCSD_OK) + { + ITrcDataIn *pDataIn = 0; + if((err = pDecoderMngr->getDataInputI(pTraceComp,&pDataIn)) == OCSD_OK) + { + // got the interface -> attach to demux, or direct to input of decode tree + if(usingFormatter()) + err = m_frame_deformatter_root->getIDStreamAttachPt(CSID)->attach(pDataIn); + else + m_i_decoder_root = pDataIn; + } + } + + if(err != OCSD_OK) + { + destroyDecodeElement(CSID); // will destroy decoder as well. + } + return err; +} + +ocsd_err_t DecodeTree::removeDecoder(const uint8_t CSID) +{ + ocsd_err_t err = OCSD_OK; + uint8_t localID = CSID; + if(!usingFormatter()) + localID = 0; + + if(usingFormatter() && !OCSD_IS_VALID_CS_SRC_ID(CSID)) + err = OCSD_ERR_INVALID_ID; + else + { + destroyDecodeElement(localID); + } + return err; +} + +DecodeTreeElement * DecodeTree::getDecoderElement(const uint8_t CSID) const +{ + DecodeTreeElement *ret_elem = 0; + if(usingFormatter() && OCSD_IS_VALID_CS_SRC_ID(CSID)) + { + ret_elem = m_decode_elements[CSID]; + } + else + ret_elem = m_decode_elements[0]; // ID 0 is used if single leaf tree. + return ret_elem; +} + +DecodeTreeElement *DecodeTree::getFirstElement(uint8_t &elemID) +{ + m_decode_elem_iter = 0; + return getNextElement(elemID); +} + +DecodeTreeElement *DecodeTree::getNextElement(uint8_t &elemID) +{ + DecodeTreeElement *ret_elem = 0; + + if(m_decode_elem_iter < 0x80) + { + // find a none zero entry or end of range + while((m_decode_elements[m_decode_elem_iter] == 0) && (m_decode_elem_iter < 0x80)) + m_decode_elem_iter++; + + // return entry unless end of range + if(m_decode_elem_iter < 0x80) + { + ret_elem = m_decode_elements[m_decode_elem_iter]; + elemID = m_decode_elem_iter; + m_decode_elem_iter++; + } + } + return ret_elem; +} + +bool DecodeTree::initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCfgFlags) +{ + bool initOK = true; + m_dcd_tree_type = type; + if(type == OCSD_TRC_SRC_FRAME_FORMATTED) + { + // frame formatted - we want to create the deformatter and hook it up + m_frame_deformatter_root = new (std::nothrow) TraceFormatterFrameDecoder(); + if(m_frame_deformatter_root) + { + m_frame_deformatter_root->Configure(formatterCfgFlags); + m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger); + m_i_decoder_root = dynamic_cast(m_frame_deformatter_root); + } + else + initOK = false; + } + return initOK; +} + +void DecodeTree::setSingleRoot(TrcPktProcI *pComp) +{ + m_i_decoder_root = static_cast(pComp); +} + +ocsd_err_t DecodeTree::createDecodeElement(const uint8_t CSID) +{ + ocsd_err_t err = OCSD_ERR_INVALID_ID; + if(CSID < 0x80) + { + if(m_decode_elements[CSID] == 0) + { + m_decode_elements[CSID] = new (std::nothrow) DecodeTreeElement(); + if(m_decode_elements[CSID] == 0) + err = OCSD_ERR_MEM; + else + err = OCSD_OK; + } + else + err = OCSD_ERR_ATTACH_TOO_MANY; + } + return err; +} + +void DecodeTree::destroyDecodeElement(const uint8_t CSID) +{ + if(CSID < 0x80) + { + if(m_decode_elements[CSID] != 0) + { + m_decode_elements[CSID]->DestroyElem(); + delete m_decode_elements[CSID]; + m_decode_elements[CSID] = 0; + } + } +} + +ocsd_err_t DecodeTree::setIDFilter(std::vector &ids) +{ + ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER; + if(usingFormatter()) + { + err = m_frame_deformatter_root->OutputFilterAllIDs(false); + if(err == OCSD_OK) + err = m_frame_deformatter_root->OutputFilterIDs(ids,true); + } + return err; +} + +ocsd_err_t DecodeTree::clearIDFilter() +{ + ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER; + if(usingFormatter()) + { + err = m_frame_deformatter_root->OutputFilterAllIDs(true); + } + return err; +} + +/** add a protocol packet printer */ +ocsd_err_t DecodeTree::addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter **ppPrinter) +{ + ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL; + DecodeTreeElement *pElement = getDecoderElement(CSID); + if (pElement) + { + ocsd_trace_protocol_t protocol = pElement->getProtocol(); + ItemPrinter *pPrinter; + + pPrinter = PktPrinterFact::createProtocolPrinter(getPrinterList(), protocol, CSID); + if (pPrinter) + { + pPrinter->setMessageLogger(getCurrentErrorLogI()->getOutputLogger()); + switch (protocol) + { + case OCSD_PROTOCOL_ETMV4I: + { + PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); + if (bMonitor) + err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); + else + err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); + } + break; + + case OCSD_PROTOCOL_ETMV3: + { + PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); + if (bMonitor) + err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); + else + err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); + } + break; + + case OCSD_PROTOCOL_PTM: + { + PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); + if (bMonitor) + err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); + else + err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); + } + break; + + case OCSD_PROTOCOL_STM: + { + PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); + if (bMonitor) + err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); + else + err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); + } + break; + + default: + err = OCSD_ERR_NO_PROTOCOL; + break; + } + + if (err == OCSD_OK) + { + if (ppPrinter) + *ppPrinter = pPrinter; + } + else + PktPrinterFact::destroyPrinter(getPrinterList(), pPrinter); + } + } + return err; +} + +/** add a raw frame printer */ +ocsd_err_t DecodeTree::addRawFramePrinter(RawFramePrinter **ppPrinter, uint32_t flags) +{ + ocsd_err_t err = OCSD_ERR_MEM; + RawFramePrinter *pPrinter = PktPrinterFact::createRawFramePrinter(getPrinterList()); + if (pPrinter) + { + pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger())); + TraceFormatterFrameDecoder *pFrameDecoder = getFrameDeformatter(); + uint32_t cfgFlags = pFrameDecoder->getConfigFlags(); + cfgFlags |= ((uint32_t)flags & (OCSD_DFRMTR_PACKED_RAW_OUT | OCSD_DFRMTR_UNPACKED_RAW_OUT)); + pFrameDecoder->Configure(cfgFlags); + err = pFrameDecoder->getTrcRawFrameAttachPt()->attach(pPrinter); + if (ppPrinter && (err==OCSD_OK)) + *ppPrinter = pPrinter; + } + return err; +} + +/** add a generic element output printer */ +ocsd_err_t DecodeTree::addGenElemPrinter(TrcGenericElementPrinter **ppPrinter) +{ + ocsd_err_t err = OCSD_ERR_MEM; + TrcGenericElementPrinter *pPrinter = PktPrinterFact::createGenElemPrinter(getPrinterList()); + if (pPrinter) + { + pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger())); + setGenTraceElemOutI(pPrinter); + err = OCSD_OK; + if (ppPrinter) + *ppPrinter = pPrinter; + } + return err; + +} + +/* End of File ocsd_dcd_tree.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_error.cpp b/contrib/opencsd/decoder/source/ocsd_error.cpp new file mode 100644 index 000000000000..cd417a2212c9 --- /dev/null +++ b/contrib/opencsd/decoder/source/ocsd_error.cpp @@ -0,0 +1,230 @@ +/* + * \file ocsd_error.cpp + * \brief OpenCSD : Library error class. + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "common/ocsd_error.h" +#include +#include + +static const char *s_errorCodeDescs[][2] = { + /* general return errors */ + {"OCSD_OK", "No Error."}, + {"OCSD_ERR_FAIL","General failure."}, + {"OCSD_ERR_MEM","Internal memory allocation error."}, + {"OCSD_ERR_NOT_INIT","Component not initialised."}, + {"OCSD_ERR_INVALID_ID","Invalid CoreSight Trace Source ID."}, + {"OCSD_ERR_BAD_HANDLE","Invalid handle passed to component."}, + {"OCSD_ERR_INVALID_PARAM_VAL","Invalid value parameter passed to component."}, + {"OCSD_ERR_INVALID_PARAM_TYPE","Type mismatch on abstract interface."}, + {"OCSD_ERR_FILE_ERROR","File access error"}, + {"OCSD_ERR_NO_PROTOCOL","Trace protocol unsupported"}, + /* attachment point errors */ + {"OCSD_ERR_ATTACH_TOO_MANY","Cannot attach - attach device limit reached."}, + {"OCSD_ERR_ATTACH_INVALID_PARAM"," Cannot attach - invalid parameter."}, + {"OCSD_ERR_ATTACH_COMP_NOT_FOUND","Cannot detach - component not found."}, + /* source reader errors */ + {"OCSD_ERR_RDR_FILE_NOT_FOUND","source reader - file not found."}, + {"OCSD_ERR_RDR_INVALID_INIT", "source reader - invalid initialisation parameter."}, + {"OCSD_ERR_RDR_NO_DECODER", "source reader - not trace decoder set."}, + /* data path errors */ + {"OCSD_ERR_DATA_DECODE_FATAL", "A decoder in the data path has returned a fatal error."}, + /* frame deformatter errors */ + {"OCSD_ERR_DFMTR_NOTCONTTRACE", "Trace input to deformatter none-continuous"}, + /* packet processor errors - protocol issues etc */ + {"OCSD_ERR_BAD_PACKET_SEQ","Bad packet sequence"}, + {"OCSD_ERR_INVALID_PCKT_HDR","Invalid packet header"}, + {"OCSD_ERR_PKT_INTERP_FAIL","Interpreter failed - cannot recover - bad data or sequence"}, + /* packet decoder errors */ + {"OCSD_ERR_UNSUPPORTED_ISA","ISA not supported in decoder"}, + {"OCSD_ERR_HW_CFG_UNSUPP","Programmed trace configuration not supported by decodUer."}, + {"OCSD_ERR_UNSUPP_DECODE_PKT","Packet not supported in decoder"}, + {"OCSD_ERR_BAD_DECODE_PKT","Reserved or unknown packet in decoder."}, + {"OCSD_ERR_COMMIT_PKT_OVERRUN","Overrun in commit packet stack - tried to commit more than available"}, + {"OCSD_ERR_MEM_NACC","Unable to access required memory address."}, + {"OCSD_ERR_RET_STACK_OVERFLOW","Internal return stack overflow checks failed - popped more than we pushed."}, + /* decode tree errors */ + {"OCSD_ERR_DCDT_NO_FORMATTER","No formatter in use - operation not valid."}, + /* target memory access errors */ + {"OCSD_ERR_MEM_ACC_OVERLAP","Attempted to set an overlapping range in memory access map."}, + {"OCSD_ERR_MEM_ACC_FILE_NOT_FOUND","Memory access file could not be opened."}, + {"OCSD_ERR_MEM_ACC_FILE_DIFF_RANGE","Attempt to re-use the same memory access file for a different address range."}, + {"OCSD_ERR_MEM_ACC_RANGE_INVALID","Address range in accessor set to invalid values."}, + /* test errors - errors generated only by the test code, not the library */ + {"OCSD_ERR_TEST_SNAPSHOT_PARSE", "Test snapshot file parse error"}, + {"OCSD_ERR_TEST_SNAPSHOT_PARSE_INFO", "Test snapshot file parse information"}, + {"OCSD_ERR_TEST_SNAPSHOT_READ","test snapshot reader error"}, + {"OCSD_ERR_TEST_SS_TO_DECODER","test snapshot to decode tree conversion error"}, + /* decoder registration */ + {"OCSD_ERR_DCDREG_NAME_REPEAT","Attempted to register a decoder with the same name as another one."}, + {"OCSD_ERR_DCDREG_NAME_UNKNOWN","Attempted to find a decoder with a name that is not known in the library."}, + {"OCSD_ERR_DCDREG_TYPE_UNKNOWN","Attempted to find a decoder with a type that is not known in the library."}, + /* decoder config */ + {"OCSD_ERR_DCD_INTERFACE_UNUSED","Attempt to connect or use and inteface not supported by this decoder."}, + /* end marker*/ + {"OCSD_ERR_LAST", "No error - error code end marker"} +}; + +ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code) : + m_error_code(code), + m_sev(sev_type), + m_idx(OCSD_BAD_TRC_INDEX), + m_chan_ID(OCSD_BAD_CS_SRC_ID) +{ +} + +ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx) : + m_error_code(code), + m_sev(sev_type), + m_idx(idx), + m_chan_ID(OCSD_BAD_CS_SRC_ID) +{ +} + +ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const uint8_t chan_id) : + m_error_code(code), + m_sev(sev_type), + m_idx(idx), + m_chan_ID(chan_id) +{ +} + +ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const std::string &msg) : + m_error_code(code), + m_sev(sev_type), + m_idx(OCSD_BAD_TRC_INDEX), + m_chan_ID(OCSD_BAD_CS_SRC_ID), + m_err_message(msg) +{ +} + +ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const std::string &msg) : + m_error_code(code), + m_sev(sev_type), + m_idx(idx), + m_chan_ID(OCSD_BAD_CS_SRC_ID), + m_err_message(msg) +{ +} + +ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const uint8_t chan_id, const std::string &msg) : + m_error_code(code), + m_sev(sev_type), + m_idx(idx), + m_chan_ID(chan_id), + m_err_message(msg) +{ +} + + +ocsdError::ocsdError(const ocsdError *pError) : + m_error_code(pError->getErrorCode()), + m_sev(pError->getErrorSeverity()), + m_idx(pError->getErrorIndex()), + m_chan_ID(pError->getErrorChanID()) +{ + setMessage(pError->getMessage()); +} + +ocsdError::ocsdError(const ocsdError &Error) : + m_error_code(Error.getErrorCode()), + m_sev(Error.getErrorSeverity()), + m_idx(Error.getErrorIndex()), + m_chan_ID(Error.getErrorChanID()) +{ + setMessage(Error.getMessage()); +} + +ocsdError::ocsdError(): + m_error_code(OCSD_ERR_LAST), + m_sev(OCSD_ERR_SEV_NONE), + m_idx(OCSD_BAD_TRC_INDEX), + m_chan_ID(OCSD_BAD_CS_SRC_ID) +{ +} + +ocsdError::~ocsdError() +{ +} + +const std::string ocsdError::getErrorString(const ocsdError &error) +{ + std::string szErrStr = "LIBRARY INTERNAL ERROR: Invalid Error Object"; + const char *sev_type_sz[] = { + "NONE ", + "ERROR:", + "WARN :", + "INFO :" + }; + + switch(error.getErrorSeverity()) + { + default: + case OCSD_ERR_SEV_NONE: + break; + + case OCSD_ERR_SEV_ERROR: + case OCSD_ERR_SEV_WARN: + case OCSD_ERR_SEV_INFO: + szErrStr = sev_type_sz[(int)error.getErrorSeverity()]; + appendErrorDetails(szErrStr,error); + break; + } + return szErrStr; +} + +void ocsdError::appendErrorDetails(std::string &errStr, const ocsdError &error) +{ + int numerrstr = ((sizeof(s_errorCodeDescs) / sizeof(const char *)) / 2); + int code = (int)error.getErrorCode(); + ocsd_trc_index_t idx = error.getErrorIndex(); + uint8_t chan_ID = error.getErrorChanID(); + std::ostringstream oss; + + oss << "0x" << std::hex << std::setfill('0') << std::setw(4) << code; + if(code < numerrstr) + oss << " (" << s_errorCodeDescs[code][0] << ") [" << s_errorCodeDescs[code][1] << "]; "; + else + oss << " (unknown); "; + + if(idx != OCSD_BAD_TRC_INDEX) + oss << "TrcIdx=" << std::dec << idx << "; "; + + if(chan_ID != OCSD_BAD_CS_SRC_ID) + oss << "CS ID=" << std::hex << std::setfill('0') << std::setw(2) << (uint16_t)chan_ID << "; "; + + oss << error.getMessage(); + errStr = oss.str(); +} + +/* End of File ocsd_error.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_error_logger.cpp b/contrib/opencsd/decoder/source/ocsd_error_logger.cpp new file mode 100644 index 000000000000..2b109d605b05 --- /dev/null +++ b/contrib/opencsd/decoder/source/ocsd_error_logger.cpp @@ -0,0 +1,159 @@ +/* + * \file ocsd_error_logger.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "common/ocsd_error_logger.h" + +#include +#include + +ocsdDefaultErrorLogger::ocsdDefaultErrorLogger() : + m_Verbosity(OCSD_ERR_SEV_ERROR), + m_output_logger(0), + m_created_output_logger(false) +{ + m_lastErr = 0; + for(int i = 0; i < 0x80; i++) + m_lastErrID[i] = 0; + m_error_sources.push_back("Gen_Err"); // handle 0 + m_error_sources.push_back("Gen_Warn"); // handle 1 + m_error_sources.push_back("Gen_Info"); // handle 2 +} + +ocsdDefaultErrorLogger::~ocsdDefaultErrorLogger() +{ + if(m_created_output_logger) + delete m_output_logger; + + if(m_lastErr) + delete m_lastErr; + + for(int i = 0; i < 0x80; i++) + if(m_lastErrID[i] != 0) delete m_lastErrID[i]; +} + +bool ocsdDefaultErrorLogger::initErrorLogger(const ocsd_err_severity_t verbosity, bool bCreateOutputLogger /*= false*/) +{ + bool bInit = true; + m_Verbosity = verbosity; + if(bCreateOutputLogger) + { + m_output_logger = new (std::nothrow) ocsdMsgLogger(); + if(m_output_logger) + { + m_created_output_logger = true; + m_output_logger->setLogOpts(ocsdMsgLogger::OUT_STDERR); + } + else + bInit = false; + } + return bInit; +} + +void ocsdDefaultErrorLogger::setOutputLogger(ocsdMsgLogger *pLogger) +{ + // if we created the current logger, delete it. + if(m_output_logger && m_created_output_logger) + delete m_output_logger; + m_created_output_logger = false; + m_output_logger = pLogger; +} + +const ocsd_hndl_err_log_t ocsdDefaultErrorLogger::RegisterErrorSource(const std::string &component_name) +{ + ocsd_hndl_err_log_t handle = m_error_sources.size(); + m_error_sources.push_back(component_name); + return handle; +} + +void ocsdDefaultErrorLogger::LogError(const ocsd_hndl_err_log_t handle, const ocsdError *Error) +{ + // only log errors that match or exceed the current verbosity + if(m_Verbosity >= Error->getErrorSeverity()) + { + // print out only if required + if(m_output_logger) + { + if(m_output_logger->isLogging()) + { + std::string errStr = "unknown"; + if(handle < m_error_sources.size()) + errStr = m_error_sources[handle]; + errStr += " : " + ocsdError::getErrorString(Error); + m_output_logger->LogMsg(errStr); + } + } + + // log last error + if(m_lastErr == 0) + CreateErrorObj(&m_lastErr,Error); + else + *m_lastErr = Error; + + // log last error associated with an ID + if(OCSD_IS_VALID_CS_SRC_ID(Error->getErrorChanID())) + { + if(m_lastErrID[Error->getErrorChanID()] == 0) + CreateErrorObj(&m_lastErrID[Error->getErrorChanID()], Error); + else + *m_lastErrID[Error->getErrorChanID()] = Error; + } + } +} + +void ocsdDefaultErrorLogger::LogMessage(const ocsd_hndl_err_log_t handle, const ocsd_err_severity_t filter_level, const std::string &msg ) +{ + // only log errors that match or exceed the current verbosity + if((m_Verbosity >= filter_level)) + { + if(m_output_logger) + { + if(m_output_logger->isLogging()) + { + std::string errStr = "unknown"; + if(handle < m_error_sources.size()) + errStr = m_error_sources[handle]; + errStr += " : " + msg; + m_output_logger->LogMsg(errStr); + } + } + } +} + +void ocsdDefaultErrorLogger::CreateErrorObj(ocsdError **ppErr, const ocsdError *p_from) +{ + *ppErr = new (std::nothrow) ocsdError(p_from); +} + +/* End of File ocsd_error_logger.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_gen_elem_list.cpp b/contrib/opencsd/decoder/source/ocsd_gen_elem_list.cpp new file mode 100644 index 000000000000..1a568ec34775 --- /dev/null +++ b/contrib/opencsd/decoder/source/ocsd_gen_elem_list.cpp @@ -0,0 +1,168 @@ +/* + * \file ocsd_gen_elem_list.cpp + * \brief OpenCSD : List of Generic trace elements for output. + * + * \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. + */ + +#include "common/ocsd_gen_elem_list.h" + +OcsdGenElemList::OcsdGenElemList() +{ + m_firstElemIdx=0; + m_numUsed=0; + m_numPend=0; + + m_elemArraySize = 0; + m_sendIf = 0; + m_CSID = 0; + m_pElemArray = 0; +} + +OcsdGenElemList::~OcsdGenElemList() +{ + for(int i = 0; igetType(); + } + return elem_type; +} + +ocsd_datapath_resp_t OcsdGenElemList::sendElements() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + if((m_elemArraySize == 0) || (m_sendIf == 0)) + return OCSD_RESP_FATAL_NOT_INIT; + + if(!m_sendIf->hasAttachedAndEnabled()) + return OCSD_RESP_FATAL_NOT_INIT; + + while(elemToSend() && OCSD_DATA_RESP_IS_CONT(resp)) + { + resp = m_sendIf->first()->TraceElemIn(m_pElemArray[m_firstElemIdx].trc_pkt_idx, m_CSID, *(m_pElemArray[m_firstElemIdx].pElem)); + m_firstElemIdx++; + if(m_firstElemIdx >= m_elemArraySize) + m_firstElemIdx = 0; + m_numUsed--; + } + return resp; +} + +// this function will enlarge the array, and create extra element objects. +// existing objects will be moved to the front of the array +// called if all elements are in use. (sets indexes accordingly) +void OcsdGenElemList::growArray() +{ + elemPtr_t *p_new_array = 0; + + int increment; + if(m_elemArraySize == 0) + // starting from scratch... + increment = 8; + else + increment = m_elemArraySize / 2; // grow by 50% + + + p_new_array = new (std::nothrow) elemPtr_t[m_elemArraySize+increment]; + + if(p_new_array != 0) + { + // fill the last increment elements with new objects + for(int i=0; i < increment; i++) + { + p_new_array[m_elemArraySize+i].pElem = new (std::nothrow) OcsdTraceElement(); + } + + // copy the existing objects from the old array to the start of the new one + // and adjust the indices. + if(m_elemArraySize > 0) + { + int inIdx = m_firstElemIdx; + for(int i = 0; i < m_elemArraySize; i++) + { + p_new_array[i].pElem = m_pElemArray[inIdx].pElem; + p_new_array[i].trc_pkt_idx = m_pElemArray[inIdx].trc_pkt_idx; + inIdx++; + if(inIdx >= m_elemArraySize) + inIdx = 0; + } + } + + // delete the old pointer array. + delete [] m_pElemArray; + m_elemArraySize += increment; + } + else + m_elemArraySize = 0; + + // update the internal array pointers to the new array + if(m_firstElemIdx >= 0) + m_firstElemIdx = 0; + m_pElemArray = p_new_array; +} + +/* End of File ocsd_gen_elem_list.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_lib_dcd_register.cpp b/contrib/opencsd/decoder/source/ocsd_lib_dcd_register.cpp new file mode 100644 index 000000000000..adb042dcadff --- /dev/null +++ b/contrib/opencsd/decoder/source/ocsd_lib_dcd_register.cpp @@ -0,0 +1,215 @@ +/* + * \file ocsd_lib_dcd_register.cpp + * \brief OpenCSD : Library decoder register object + * + * \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. + */ + +#include "common/ocsd_lib_dcd_register.h" + +// include built-in decode manager headers +#include "opencsd/etmv4/trc_dcd_mngr_etmv4i.h" +#include "opencsd/etmv3/trc_dcd_mngr_etmv3.h" +#include "opencsd/ptm/trc_dcd_mngr_ptm.h" +#include "opencsd/stm/trc_dcd_mngr_stm.h" + +// create array of built-in decoders to register with library +static built_in_decoder_info_t sBuiltInArray[] = { + CREATE_BUILTIN_ENTRY(DecoderMngrEtmV4I,OCSD_BUILTIN_DCD_ETMV4I), + CREATE_BUILTIN_ENTRY(DecoderMngrEtmV3, OCSD_BUILTIN_DCD_ETMV3), + CREATE_BUILTIN_ENTRY(DecoderMngrPtm, OCSD_BUILTIN_DCD_PTM), + CREATE_BUILTIN_ENTRY(DecoderMngrStm, OCSD_BUILTIN_DCD_STM) + //{ 0, 0, 0} +}; + +#define NUM_BUILTINS sizeof(sBuiltInArray) / sizeof(built_in_decoder_info_t) + + +OcsdLibDcdRegister *OcsdLibDcdRegister::m_p_libMngr = 0; +bool OcsdLibDcdRegister::m_b_registeredBuiltins = false; +ocsd_trace_protocol_t OcsdLibDcdRegister::m_nextCustomProtocolID = OCSD_PROTOCOL_CUSTOM_0; + +OcsdLibDcdRegister *OcsdLibDcdRegister::getDecoderRegister() +{ + if(m_p_libMngr == 0) + m_p_libMngr = new (std::nothrow) OcsdLibDcdRegister(); + return m_p_libMngr; +} + +const ocsd_trace_protocol_t OcsdLibDcdRegister::getNextCustomProtocolID() +{ + ocsd_trace_protocol_t ret = m_nextCustomProtocolID; + if(m_nextCustomProtocolID < OCSD_PROTOCOL_END) + m_nextCustomProtocolID = (ocsd_trace_protocol_t)(((int)m_nextCustomProtocolID)+1); + return ret; +} + +void OcsdLibDcdRegister::releaseLastCustomProtocolID() +{ + if(m_nextCustomProtocolID > OCSD_PROTOCOL_CUSTOM_0) + m_nextCustomProtocolID = (ocsd_trace_protocol_t)(((int)m_nextCustomProtocolID)-1); +} + +OcsdLibDcdRegister::OcsdLibDcdRegister() +{ + m_iter = m_decoder_mngrs.begin(); + m_pLastTypedDecoderMngr = 0; +} + +OcsdLibDcdRegister::~OcsdLibDcdRegister() +{ + m_decoder_mngrs.clear(); + m_typed_decoder_mngrs.clear(); + m_pLastTypedDecoderMngr = 0; +} + + +const ocsd_err_t OcsdLibDcdRegister::registerDecoderTypeByName(const std::string &name, IDecoderMngr *p_decoder_fact) +{ + if(isRegisteredDecoder(name)) + return OCSD_ERR_DCDREG_NAME_REPEAT; + m_decoder_mngrs.emplace(std::pair(name,p_decoder_fact)); + m_typed_decoder_mngrs.emplace(std::pair(p_decoder_fact->getProtocolType(),p_decoder_fact)); + return OCSD_OK; +} + +void OcsdLibDcdRegister::registerBuiltInDecoders() +{ + bool memFail = false; + for(unsigned i = 0; i < NUM_BUILTINS; i++) + { + if(sBuiltInArray[i].PFn) + { + sBuiltInArray[i].pMngr = sBuiltInArray[i].PFn( sBuiltInArray[i].name); + if(!sBuiltInArray[i].pMngr) + memFail=true; + } + } + m_b_registeredBuiltins = !memFail; +} + +void OcsdLibDcdRegister::deregisterAllDecoders() +{ + if(m_b_registeredBuiltins) + { + for(unsigned i = 0; i < NUM_BUILTINS; i++) + delete sBuiltInArray[i].pMngr; + m_b_registeredBuiltins = false; + } + + if(m_p_libMngr) + { + m_p_libMngr->deRegisterCustomDecoders(); + delete m_p_libMngr; + m_p_libMngr = 0; + } +} + +void OcsdLibDcdRegister::deRegisterCustomDecoders() +{ + std::map::const_iterator iter = m_typed_decoder_mngrs.begin(); + while(iter != m_typed_decoder_mngrs.end()) + { + IDecoderMngr *pMngr = iter->second; + if(pMngr->getProtocolType() >= OCSD_PROTOCOL_CUSTOM_0) + delete pMngr; + iter++; + } +} + +const ocsd_err_t OcsdLibDcdRegister::getDecoderMngrByName(const std::string &name, IDecoderMngr **p_decoder_mngr) +{ + if(!m_b_registeredBuiltins) + { + registerBuiltInDecoders(); + if(!m_b_registeredBuiltins) + return OCSD_ERR_MEM; + } + + std::map::const_iterator iter = m_decoder_mngrs.find(name); + if(iter == m_decoder_mngrs.end()) + return OCSD_ERR_DCDREG_NAME_UNKNOWN; + *p_decoder_mngr = iter->second; + return OCSD_OK; +} + +const ocsd_err_t OcsdLibDcdRegister::getDecoderMngrByType(const ocsd_trace_protocol_t decoderType, IDecoderMngr **p_decoder_mngr) +{ + if(!m_b_registeredBuiltins) + { + registerBuiltInDecoders(); + if(!m_b_registeredBuiltins) + return OCSD_ERR_MEM; + } + + if (m_pLastTypedDecoderMngr && (m_pLastTypedDecoderMngr->getProtocolType() == decoderType)) + *p_decoder_mngr = m_pLastTypedDecoderMngr; + else + { + std::map::const_iterator iter = m_typed_decoder_mngrs.find(decoderType); + if (iter == m_typed_decoder_mngrs.end()) + return OCSD_ERR_DCDREG_TYPE_UNKNOWN; + *p_decoder_mngr = m_pLastTypedDecoderMngr = iter->second; + } + return OCSD_OK; +} + +const bool OcsdLibDcdRegister::isRegisteredDecoder(const std::string &name) +{ + std::map::const_iterator iter = m_decoder_mngrs.find(name); + if(iter != m_decoder_mngrs.end()) + return true; + return false; +} + +const bool OcsdLibDcdRegister::isRegisteredDecoderType(const ocsd_trace_protocol_t decoderType) +{ + std::map::const_iterator iter = m_typed_decoder_mngrs.find(decoderType); + if(iter != m_typed_decoder_mngrs.end()) + return true; + return false; +} + +const bool OcsdLibDcdRegister::getFirstNamedDecoder(std::string &name) +{ + m_iter = m_decoder_mngrs.begin(); + return getNextNamedDecoder(name); +} + +const bool OcsdLibDcdRegister::getNextNamedDecoder(std::string &name) +{ + if(m_iter == m_decoder_mngrs.end()) + return false; + name = m_iter->first; + m_iter++; + return true; +} + +/* End of File ocsd_lib_dcd_register.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_msg_logger.cpp b/contrib/opencsd/decoder/source/ocsd_msg_logger.cpp new file mode 100644 index 000000000000..287edfa9fe84 --- /dev/null +++ b/contrib/opencsd/decoder/source/ocsd_msg_logger.cpp @@ -0,0 +1,120 @@ +/* + * \file ocsd_msg_logger.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "common/ocsd_msg_logger.h" + +#include +#include + +#define MSGLOG_OUT_MASK (ocsdMsgLogger::OUT_FILE | ocsdMsgLogger::OUT_STDERR | ocsdMsgLogger::OUT_STDOUT | ocsdMsgLogger::OUT_STR_CB) + +ocsdMsgLogger::ocsdMsgLogger() : + m_outFlags(ocsdMsgLogger::OUT_STDOUT), + m_logFileName("ocsd_trace_decode.log"), + m_pOutStrI(0) +{ +} + +ocsdMsgLogger::~ocsdMsgLogger() +{ + m_out_file.close(); +} + +void ocsdMsgLogger::setLogOpts(int logOpts) +{ + m_outFlags = logOpts & (MSGLOG_OUT_MASK); +} + +void ocsdMsgLogger::setLogFileName(const char *fileName) +{ + if (fileName == 0) + m_logFileName = ""; + else + m_logFileName = fileName; + + if(m_out_file.is_open()) + m_out_file.close(); + + if (m_logFileName.length()) + m_outFlags |= (int)ocsdMsgLogger::OUT_FILE; + else + m_outFlags &= ~((int)ocsdMsgLogger::OUT_FILE); +} + +void ocsdMsgLogger::setStrOutFn(ocsdMsgLogStrOutI *p_IstrOut) +{ + m_pOutStrI = p_IstrOut; + if (p_IstrOut) + m_outFlags |= (int)ocsdMsgLogger::OUT_STR_CB; + else + m_outFlags &= ~((int)ocsdMsgLogger::OUT_STR_CB); +} + +void ocsdMsgLogger::LogMsg(const std::string &msg) +{ + if(m_outFlags & OUT_STDOUT) + { + std::cout << msg; + std::cout.flush(); + } + + if(m_outFlags & OUT_STDERR) + { + std::cerr << msg; + std::cerr.flush(); + } + + if(m_outFlags & OUT_FILE) + { + if(!m_out_file.is_open()) + { + m_out_file.open(m_logFileName.c_str(),std::fstream::out | std::fstream::app); + } + m_out_file << msg; + m_out_file.flush(); + } + + if (m_outFlags & OUT_STR_CB) + { + if (m_pOutStrI) + m_pOutStrI->printOutStr(msg); + } +} + +const bool ocsdMsgLogger::isLogging() const +{ + return (bool)((m_outFlags & MSGLOG_OUT_MASK) != 0); +} + +/* End of File ocsd_msg_logger.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_version.cpp b/contrib/opencsd/decoder/source/ocsd_version.cpp new file mode 100644 index 000000000000..33990a02c999 --- /dev/null +++ b/contrib/opencsd/decoder/source/ocsd_version.cpp @@ -0,0 +1,48 @@ +/* + * \file ocsd_version.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "ocsd_if_version.h" +#include "common/ocsd_version.h" + +const uint32_t ocsdVersion::vers_num() +{ + return OCSD_VER_NUM; +} + +const char *ocsdVersion::vers_str() +{ + return OCSD_VER_STRING; +} + +/* End of File ocsd_version.cpp */ diff --git a/contrib/opencsd/decoder/source/pkt_printers/raw_frame_printer.cpp b/contrib/opencsd/decoder/source/pkt_printers/raw_frame_printer.cpp new file mode 100644 index 000000000000..7ac2ddf66334 --- /dev/null +++ b/contrib/opencsd/decoder/source/pkt_printers/raw_frame_printer.cpp @@ -0,0 +1,104 @@ +/* + * \file raw_frame_printer.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include +#include +#include + +#include "opencsd.h" + + +ocsd_err_t RawFramePrinter::TraceRawFrameIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const ocsd_rawframe_elem_t frame_element, + const int dataBlockSize, + const uint8_t *pDataBlock, + const uint8_t traceID) +{ + + if(op == OCSD_OP_DATA) // only interested in actual frame data. + { + std::string strData; + std::ostringstream oss; + int printDataSize = dataBlockSize; + + oss << "Frame Data; Index" << std::setw(7) << index << "; "; + + switch(frame_element) + { + case OCSD_FRM_PACKED: oss << std::setw(15) << "RAW_PACKED; "; break; + case OCSD_FRM_HSYNC: oss << std::setw(15) << "HSYNC; "; break; + case OCSD_FRM_FSYNC: oss << std::setw(15) << "FSYNC; "; break; + case OCSD_FRM_ID_DATA: + oss << std::setw(10) << "ID_DATA["; + if (traceID == OCSD_BAD_CS_SRC_ID) + oss << "????"; + else + oss << "0x" << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)traceID; + oss << "]; "; + break; + default: oss << std::setw(15) << "UNKNOWN; "; break; + } + + if(printDataSize) + { + createDataString(printDataSize,pDataBlock,16,strData); + oss << strData; + } + oss << std::endl; + itemPrintLine(oss.str()); + } + return OCSD_OK; +} + +void RawFramePrinter::createDataString(const int dataSize, const uint8_t *pData, int bytesPerLine, std::string &dataStr) +{ + int lineBytes = 0; + std::ostringstream oss; + + for(int i = 0; i < dataSize; i++) + { + if(lineBytes == bytesPerLine) + { + oss << std::endl; + lineBytes = 0; + } + oss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)pData[i] << " "; + lineBytes ++; + } + dataStr = oss.str(); +} + + +/* End of File raw_frame_printer.cpp */ diff --git a/contrib/opencsd/decoder/source/pkt_printers/trc_print_fact.cpp b/contrib/opencsd/decoder/source/pkt_printers/trc_print_fact.cpp new file mode 100644 index 000000000000..52dcb6b3e1ac --- /dev/null +++ b/contrib/opencsd/decoder/source/pkt_printers/trc_print_fact.cpp @@ -0,0 +1,123 @@ +/* +* \file trc_print_fact.cpp +* \brief OpenCSD : Trace Packet printer factory. +* +* \copyright Copyright (c) 2017, 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. +*/ + +#include "pkt_printers/trc_print_fact.h" + +RawFramePrinter * PktPrinterFact::createRawFramePrinter(std::vector &printer_list, ocsdMsgLogger *pMsgLogger /*= 0*/) +{ + RawFramePrinter *pPrinter = 0; + pPrinter = new (std::nothrow)RawFramePrinter(); + SavePrinter(printer_list, pPrinter, pMsgLogger); + return pPrinter; +} + +TrcGenericElementPrinter *PktPrinterFact::createGenElemPrinter(std::vector &printer_list, ocsdMsgLogger *pMsgLogger /*= 0*/) +{ + TrcGenericElementPrinter *pPrinter = 0; + pPrinter = new (std::nothrow)TrcGenericElementPrinter(); + SavePrinter(printer_list, pPrinter, pMsgLogger); + return pPrinter; +} + +ItemPrinter *PktPrinterFact::createProtocolPrinter(std::vector &printer_list, ocsd_trace_protocol_t protocol, uint8_t CSID, ocsdMsgLogger *pMsgLogger /*= 0*/) +{ + ItemPrinter *pPrinter = 0; + switch (protocol) + { + case OCSD_PROTOCOL_ETMV4I: + pPrinter = new (std::nothrow) PacketPrinter(CSID); + break; + case OCSD_PROTOCOL_ETMV3: + pPrinter = new (std::nothrow) PacketPrinter(CSID); + break; + case OCSD_PROTOCOL_PTM: + pPrinter = new (std::nothrow) PacketPrinter(CSID); + break; + case OCSD_PROTOCOL_STM: + pPrinter = new (std::nothrow) PacketPrinter(CSID); + break; + default: + break; + } + SavePrinter(printer_list, pPrinter, pMsgLogger); + return pPrinter; +} + +const int PktPrinterFact::numPrinters(std::vector &printer_list) +{ + return printer_list.size(); +} + +void PktPrinterFact::SavePrinter(std::vector &printer_list, ItemPrinter *pPrinter, ocsdMsgLogger *pMsgLogger) +{ + if (pPrinter) + { + pPrinter->setMessageLogger(pMsgLogger); + printer_list.push_back((ItemPrinter *)pPrinter); + } +} + +void PktPrinterFact::destroyAllPrinters(std::vector &printer_list) +{ + std::vector::iterator it; + it = printer_list.begin(); + while (it != printer_list.end()) + { + delete *it; + it++; + } + printer_list.clear(); +} + +void PktPrinterFact::destroyPrinter(std::vector &printer_list, ItemPrinter *pPrinter) +{ + std::vector::iterator it; + it = printer_list.begin(); + while (it != printer_list.end()) + { + if (*it == pPrinter) + { + printer_list.erase(it); + delete pPrinter; + return; + } + else + it++; + } +} + + + +/* end of file trc_print_fact.cpp */ diff --git a/contrib/opencsd/decoder/source/ptm/trc_cmp_cfg_ptm.cpp b/contrib/opencsd/decoder/source/ptm/trc_cmp_cfg_ptm.cpp new file mode 100644 index 000000000000..74ded02c2130 --- /dev/null +++ b/contrib/opencsd/decoder/source/ptm/trc_cmp_cfg_ptm.cpp @@ -0,0 +1,59 @@ +/* + * \file trc_cmp_cfg_ptm.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/ptm/trc_cmp_cfg_ptm.h" + +PtmConfig::PtmConfig() +{ + // defaults set ETMv1.1, V7A + m_cfg.arch_ver = ARCH_V7; + m_cfg.core_prof = profile_CortexA; + m_cfg.reg_ccer = 0; + m_cfg.reg_idr = 0x4100F310; + m_cfg.reg_ctrl = 0; +} + +PtmConfig::PtmConfig(const ocsd_ptm_cfg *cfg_regs) +{ + m_cfg = *cfg_regs; +} + +const int PtmConfig::CtxtIDBytes() const +{ + int ctxtIdsizes[] = { 0, 1, 2, 4 }; + return ctxtIdsizes[(m_cfg.reg_ctrl >> 14) & 0x3]; +} + + +/* End of File trc_cmp_cfg_ptm.cpp */ diff --git a/contrib/opencsd/decoder/source/ptm/trc_pkt_decode_ptm.cpp b/contrib/opencsd/decoder/source/ptm/trc_pkt_decode_ptm.cpp new file mode 100644 index 000000000000..aa426889fd52 --- /dev/null +++ b/contrib/opencsd/decoder/source/ptm/trc_pkt_decode_ptm.cpp @@ -0,0 +1,660 @@ +/* + * \file trc_pkt_decode_ptm.cpp + * \brief OpenCSD : PTM packet decoder. + * + * \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. + */ + +#include +#include "opencsd/ptm/trc_pkt_decode_ptm.h" + +#define DCD_NAME "DCD_PTM" + +TrcPktDecodePtm::TrcPktDecodePtm() + : TrcPktDecodeBase(DCD_NAME) +{ + initDecoder(); +} + +TrcPktDecodePtm::TrcPktDecodePtm(int instIDNum) + : TrcPktDecodeBase(DCD_NAME,instIDNum) +{ + initDecoder(); +} + +TrcPktDecodePtm::~TrcPktDecodePtm() +{ +} + +/*********************** implementation packet decoding interface */ + +ocsd_datapath_resp_t TrcPktDecodePtm::processPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bPktDone = false; + + while(!bPktDone) + { + switch(m_curr_state) + { + case NO_SYNC: + // no sync - output a no sync packet then transition to wait sync. + m_output_elem.elem_type = OCSD_GEN_TRC_ELEM_NO_SYNC; + resp = outputTraceElement(m_output_elem); + m_curr_state = (m_curr_packet_in->getType() == PTM_PKT_A_SYNC) ? WAIT_ISYNC : WAIT_SYNC; + bPktDone = true; + break; + + case WAIT_SYNC: + if(m_curr_packet_in->getType() == PTM_PKT_A_SYNC) + m_curr_state = WAIT_ISYNC; + bPktDone = true; + break; + + case WAIT_ISYNC: + if(m_curr_packet_in->getType() == PTM_PKT_I_SYNC) + m_curr_state = DECODE_PKTS; + else + bPktDone = true; + break; + + case DECODE_PKTS: + resp = decodePacket(); + bPktDone = true; + break; + + default: + // should only see these after a _WAIT resp - in flush handler + case CONT_ISYNC: + case CONT_ATOM: + bPktDone = true; + // throw a decoder error + break; + } + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodePtm::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + // shouldn't be any packets left to be processed - flush shoudl have done this. + // just output the end of trace marker + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE); + resp = outputTraceElement(m_output_elem); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodePtm::onReset() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + resetDecoder(); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodePtm::onFlush() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + resp = contProcess(); + return resp; +} + +// atom and isync packets can have multiple ouput packets that can be _WAITed mid stream. +ocsd_datapath_resp_t TrcPktDecodePtm::contProcess() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + switch(m_curr_state) + { + case CONT_ISYNC: + resp = processIsync(); + break; + + case CONT_ATOM: + resp = processAtom(); + break; + + case CONT_WPUP: + resp = processWPUpdate(); + break; + + case CONT_BRANCH: + resp = processBranch(); + break; + + default: break; // not a state that requires further processing + } + + if(OCSD_DATA_RESP_IS_CONT(resp) && processStateIsCont()) + m_curr_state = DECODE_PKTS; // continue packet processing - assuming we have not degraded into an unsynced state. + + return resp; +} + +ocsd_err_t TrcPktDecodePtm::onProtocolConfig() +{ + ocsd_err_t err = OCSD_OK; + if(m_config == 0) + return OCSD_ERR_NOT_INIT; + + // static config - copy of CSID for easy reference + m_CSID = m_config->getTraceID(); + + // handle return stack implementation + if (m_config->hasRetStack()) + { + m_return_stack.set_active(m_config->enaRetStack()); +#ifdef TRC_RET_STACK_DEBUG + m_return_stack.set_dbg_logger(this); +#endif + } + + // config options affecting decode + m_instr_info.pe_type.profile = m_config->coreProfile(); + m_instr_info.pe_type.arch = m_config->archVersion(); + m_instr_info.dsb_dmb_waypoints = m_config->dmsbWayPt() ? 1 : 0; + return err; +} + +/****************** local decoder routines */ + +void TrcPktDecodePtm::initDecoder() +{ + m_CSID = 0; + m_instr_info.pe_type.profile = profile_Unknown; + m_instr_info.pe_type.arch = ARCH_UNKNOWN; + m_instr_info.dsb_dmb_waypoints = 0; + resetDecoder(); +} + +void TrcPktDecodePtm::resetDecoder() +{ + m_curr_state = NO_SYNC; + m_need_isync = true; // need context to start. + + m_instr_info.isa = ocsd_isa_unknown; + m_mem_nacc_pending = false; + + m_pe_context.ctxt_id_valid = 0; + m_pe_context.bits64 = 0; + m_pe_context.vmid_valid = 0; + m_pe_context.exception_level = ocsd_EL_unknown; + m_pe_context.security_level = ocsd_sec_secure; + m_pe_context.el_valid = 0; + + m_curr_pe_state.instr_addr = 0x0; + m_curr_pe_state.isa = ocsd_isa_unknown; + m_curr_pe_state.valid = false; + + m_atoms.clearAll(); + m_output_elem.init(); +} + +ocsd_datapath_resp_t TrcPktDecodePtm::decodePacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + switch(m_curr_packet_in->getType()) + { + // ignore these from trace o/p point of veiw + case PTM_PKT_NOTSYNC: + case PTM_PKT_INCOMPLETE_EOT: + case PTM_PKT_NOERROR: + break; + + // bad / reserved packet - need to wait for next sync point + case PTM_PKT_BAD_SEQUENCE: + case PTM_PKT_RESERVED: + m_curr_state = WAIT_SYNC; + m_need_isync = true; // need context to re-start. + m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); + resp = outputTraceElement(m_output_elem); + break; + + // packets we can ignore if in sync + case PTM_PKT_A_SYNC: + case PTM_PKT_IGNORE: + break; + + // + case PTM_PKT_I_SYNC: + resp = processIsync(); + break; + + case PTM_PKT_BRANCH_ADDRESS: + resp = processBranch(); + break; + + case PTM_PKT_TRIGGER: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT); + m_output_elem.setEvent(EVENT_TRIGGER, 0); + resp = outputTraceElement(m_output_elem); + break; + + case PTM_PKT_WPOINT_UPDATE: + resp = processWPUpdate(); + break; + + case PTM_PKT_CONTEXT_ID: + { + bool bUpdate = true; + // see if this is a change + if((m_pe_context.ctxt_id_valid) && (m_pe_context.context_id == m_curr_packet_in->context.ctxtID)) + bUpdate = false; + if(bUpdate) + { + m_pe_context.context_id = m_curr_packet_in->context.ctxtID; + m_pe_context.ctxt_id_valid = 1; + m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_output_elem.setContext(m_pe_context); + resp = outputTraceElement(m_output_elem); + } + } + break; + + case PTM_PKT_VMID: + { + bool bUpdate = true; + // see if this is a change + if((m_pe_context.vmid_valid) && (m_pe_context.vmid == m_curr_packet_in->context.VMID)) + bUpdate = false; + if(bUpdate) + { + m_pe_context.vmid = m_curr_packet_in->context.VMID; + m_pe_context.vmid_valid = 1; + m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_output_elem.setContext(m_pe_context); + resp = outputTraceElement(m_output_elem); + } + } + break; + + case PTM_PKT_ATOM: + if(m_curr_pe_state.valid) + { + m_atoms.initAtomPkt(m_curr_packet_in->getAtom(),m_index_curr_pkt); + resp = processAtom(); + } + break; + + case PTM_PKT_TIMESTAMP: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); + m_output_elem.timestamp = m_curr_packet_in->timestamp; + if(m_curr_packet_in->cc_valid) + m_output_elem.setCycleCount(m_curr_packet_in->cycle_count); + resp = outputTraceElement(m_output_elem); + break; + + case PTM_PKT_EXCEPTION_RET: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); + resp = outputTraceElement(m_output_elem); + break; + + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodePtm::processIsync() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // extract the I-Sync data if not re-entering after a _WAIT + if(m_curr_state == DECODE_PKTS) + { + m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal(); + m_curr_pe_state.isa = m_curr_packet_in->getISA(); + m_curr_pe_state.valid = true; + + m_i_sync_pe_ctxt = m_curr_packet_in->ISAChanged(); + if(m_curr_packet_in->CtxtIDUpdated()) + { + m_pe_context.context_id = m_curr_packet_in->getCtxtID(); + m_pe_context.ctxt_id_valid = 1; + m_i_sync_pe_ctxt = true; + } + + if(m_curr_packet_in->VMIDUpdated()) + { + m_pe_context.vmid = m_curr_packet_in->getVMID(); + m_pe_context.vmid_valid = 1; + m_i_sync_pe_ctxt = true; + } + m_pe_context.security_level = m_curr_packet_in->getNS() ? ocsd_sec_nonsecure : ocsd_sec_secure; + + if(m_need_isync || (m_curr_packet_in->iSyncReason() != iSync_Periodic)) + { + m_output_elem.setType(OCSD_GEN_TRC_ELEM_TRACE_ON); + m_output_elem.trace_on_reason = TRACE_ON_NORMAL; + if(m_curr_packet_in->iSyncReason() == iSync_TraceRestartAfterOverflow) + m_output_elem.trace_on_reason = TRACE_ON_OVERFLOW; + else if(m_curr_packet_in->iSyncReason() == iSync_DebugExit) + m_output_elem.trace_on_reason = TRACE_ON_EX_DEBUG; + if(m_curr_packet_in->hasCC()) + m_output_elem.setCycleCount(m_curr_packet_in->getCCVal()); + resp = outputTraceElement(m_output_elem); + } + else + { + // periodic - no output + m_i_sync_pe_ctxt = false; + } + m_need_isync = false; // got 1st Isync - can continue to process data. + m_return_stack.flush(); + } + + if(m_i_sync_pe_ctxt && OCSD_DATA_RESP_IS_CONT(resp)) + { + m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_output_elem.setContext(m_pe_context); + m_output_elem.setISA(m_curr_pe_state.isa); + resp = outputTraceElement(m_output_elem); + m_i_sync_pe_ctxt = false; + } + + // if wait and still stuff to process.... + if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_i_sync_pe_ctxt)) + m_curr_state = CONT_ISYNC; + + return resp; +} + +// change of address and/or exception in program flow. +// implies E atom before the branch if none exception. +ocsd_datapath_resp_t TrcPktDecodePtm::processBranch() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // initial pass - decoding packet. + if(m_curr_state == DECODE_PKTS) + { + // specific behviour if this is an exception packet. + if(m_curr_packet_in->isBranchExcepPacket()) + { + // exception - record address and output exception packet. + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION); + m_output_elem.exception_number = m_curr_packet_in->excepNum(); + m_output_elem.excep_ret_addr = 0; + if(m_curr_pe_state.valid) + { + m_output_elem.excep_ret_addr = 1; + m_output_elem.en_addr = m_curr_pe_state.instr_addr; + } + // could be an associated cycle count + if(m_curr_packet_in->hasCC()) + m_output_elem.setCycleCount(m_curr_packet_in->getCCVal()); + + // output the element + resp = outputTraceElement(m_output_elem); + } + else + { + // branch address only - implies E atom - need to output a range element based on the atom. + if(m_curr_pe_state.valid) + resp = processAtomRange(ATOM_E,"BranchAddr"); + } + + // now set the branch address for the next time. + m_curr_pe_state.isa = m_curr_packet_in->getISA(); + m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal(); + m_curr_pe_state.valid = true; + } + + // atom range may return with NACC pending + checkPendingNacc(resp); + + // if wait and still stuff to process.... + if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending)) + m_curr_state = CONT_BRANCH; + + return resp; +} + +// effectively completes a range prior to exception or after many bytes of trace (>4096) +// +ocsd_datapath_resp_t TrcPktDecodePtm::processWPUpdate() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // if we need an address to run from then the WPUpdate will not form a range as + // we do not have a start point - still waiting for branch or other address packet + if(m_curr_pe_state.valid) + { + // WP update implies atom - use E, we cannot be sure if the instruction passed its condition codes + // - though it doesn't really matter as it is not a branch so cannot change flow. + resp = processAtomRange(ATOM_E,"WP update",TRACE_TO_ADDR_INCL,m_curr_packet_in->getAddrVal()); + } + + // atom range may return with NACC pending + checkPendingNacc(resp); + + // if wait and still stuff to process.... + if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending)) + m_curr_state = CONT_WPUP; + + return resp; +} + +// a single atom packet can result in multiple range outputs...need to be re-entrant in case we get a wait response. +// also need to handle nacc response from instruction walking routine +// +ocsd_datapath_resp_t TrcPktDecodePtm::processAtom() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // loop to process all the atoms in the packet + while(m_atoms.numAtoms() && m_curr_pe_state.valid && OCSD_DATA_RESP_IS_CONT(resp)) + { + resp = processAtomRange(m_atoms.getCurrAtomVal(),"atom"); + if(!m_curr_pe_state.valid) + m_atoms.clearAll(); + else + m_atoms.clearAtom(); + } + + // bad address may mean a nacc needs sending + checkPendingNacc(resp); + + // if wait and still stuff to process.... + if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending || m_atoms.numAtoms())) + m_curr_state = CONT_ATOM; + + return resp; +} + + void TrcPktDecodePtm::checkPendingNacc(ocsd_datapath_resp_t &resp) + { + if(m_mem_nacc_pending && OCSD_DATA_RESP_IS_CONT(resp)) + { + m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + m_output_elem.st_addr = m_nacc_addr; + resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem); + m_mem_nacc_pending = false; + } + } + +// given an atom element - walk the code and output a range or mark nacc. +ocsd_datapath_resp_t TrcPktDecodePtm::processAtomRange(const ocsd_atm_val A, const char *pkt_msg, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bWPFound = false; + std::ostringstream oss; + + m_instr_info.instr_addr = m_curr_pe_state.instr_addr; + m_instr_info.isa = m_curr_pe_state.isa; + + ocsd_err_t err = traceInstrToWP(bWPFound,traceWPOp,nextAddrMatch); + if(err != OCSD_OK) + { + if(err == OCSD_ERR_UNSUPPORTED_ISA) + { + m_curr_pe_state.valid = false; // need a new address packet + oss << "Warning: unsupported instruction set processing " << pkt_msg << " packet."; + LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_index_curr_pkt,m_CSID,oss.str())); + // wait for next address + return OCSD_RESP_WARN_CONT; + } + else + { + resp = OCSD_RESP_FATAL_INVALID_DATA; + oss << "Error processing " << pkt_msg << " packet."; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_index_curr_pkt,m_CSID,oss.str())); + return resp; + } + } + + if(bWPFound) + { + // save recorded next instuction address + ocsd_vaddr_t nextAddr = m_instr_info.instr_addr; + + // action according to waypoint type and atom value + switch(m_instr_info.type) + { + case OCSD_INSTR_BR: + if (A == ATOM_E) + { + m_instr_info.instr_addr = m_instr_info.branch_addr; + if (m_instr_info.is_link) + m_return_stack.push(nextAddr,m_instr_info.isa); + } + break; + + // For PTM -> branch addresses imply E atom, N atom does not need address (return stack will require this) + case OCSD_INSTR_BR_INDIRECT: + if (A == ATOM_E) + { + // atom on indirect branch - either implied E from a branch address packet, or return stack if active. + + // indirect branch taken - need new address -if the current packet is a branch address packet this will be sorted. + m_curr_pe_state.valid = false; + + // if return stack and the incoming packet is an atom. + if (m_return_stack.is_active() && (m_curr_packet_in->getType() == PTM_PKT_ATOM)) + { + // we have an E atom packet and return stack value - set address from return stack + m_instr_info.instr_addr = m_return_stack.pop(m_instr_info.next_isa); + + if (m_return_stack.overflow()) + { + resp = OCSD_RESP_FATAL_INVALID_DATA; + oss << "Return stack error processing " << pkt_msg << " packet."; + LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_RET_STACK_OVERFLOW, m_index_curr_pkt, m_CSID, oss.str())); + return resp; + } + else + m_curr_pe_state.valid = true; + } + if(m_instr_info.is_link) + m_return_stack.push(nextAddr, m_instr_info.isa); + } + break; + } + + m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + m_output_elem.setLastInstrInfo((A == ATOM_E),m_instr_info.type, m_instr_info.sub_type); + m_output_elem.setISA(m_curr_pe_state.isa); + if(m_curr_packet_in->hasCC()) + m_output_elem.setCycleCount(m_curr_packet_in->getCCVal()); + resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem); + + m_curr_pe_state.instr_addr = m_instr_info.instr_addr; + m_curr_pe_state.isa = m_instr_info.next_isa; + } + else + { + // no waypoint - likely inaccessible memory range. + m_curr_pe_state.valid = false; // need an address update + + if(m_output_elem.st_addr != m_output_elem.en_addr) + { + // some trace before we were out of memory access range + m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); + m_output_elem.setISA(m_curr_pe_state.isa); + resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem); + } + } + return resp; +} + +ocsd_err_t TrcPktDecodePtm::traceInstrToWP(bool &bWPFound, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/) +{ + uint32_t opcode; + uint32_t bytesReq; + ocsd_err_t err = OCSD_OK; + ocsd_vaddr_t curr_op_address; + + ocsd_mem_space_acc_t mem_space = (m_pe_context.security_level == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N; + + m_output_elem.st_addr = m_output_elem.en_addr = m_instr_info.instr_addr; + + bWPFound = false; + + while(!bWPFound && !m_mem_nacc_pending) + { + // start off by reading next opcode; + bytesReq = 4; + curr_op_address = m_instr_info.instr_addr; // save the start address for the current opcode + err = accessMemory(m_instr_info.instr_addr,mem_space,&bytesReq,(uint8_t *)&opcode); + if(err != OCSD_OK) break; + + if(bytesReq == 4) // got data back + { + m_instr_info.opcode = opcode; + err = instrDecode(&m_instr_info); + if(err != OCSD_OK) break; + + // increment address - may be adjusted by direct branch value later + m_instr_info.instr_addr += m_instr_info.instr_size; + + // update the range decoded address in the output packet. + m_output_elem.en_addr = m_instr_info.instr_addr; + + m_output_elem.last_i_type = m_instr_info.type; + // either walking to match the next instruction address or a real waypoint + if(traceWPOp != TRACE_WAYPOINT) + { + if(traceWPOp == TRACE_TO_ADDR_EXCL) + bWPFound = (m_output_elem.en_addr == nextAddrMatch); + else + bWPFound = (curr_op_address == nextAddrMatch); + } + else + bWPFound = (m_instr_info.type != OCSD_INSTR_OTHER); + } + else + { + // not enough memory accessible. + m_mem_nacc_pending = true; + m_nacc_addr = m_instr_info.instr_addr; + } + } + return err; +} + +/* End of File trc_pkt_decode_ptm.cpp */ diff --git a/contrib/opencsd/decoder/source/ptm/trc_pkt_elem_ptm.cpp b/contrib/opencsd/decoder/source/ptm/trc_pkt_elem_ptm.cpp new file mode 100644 index 000000000000..7c8bcd7ef7f6 --- /dev/null +++ b/contrib/opencsd/decoder/source/ptm/trc_pkt_elem_ptm.cpp @@ -0,0 +1,473 @@ +/* + * \file trc_pkt_elem_ptm.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include +#include + +#include "opencsd/ptm/trc_pkt_elem_ptm.h" + +PtmTrcPacket::PtmTrcPacket() +{ +} + +PtmTrcPacket::~PtmTrcPacket() +{ +} + +PtmTrcPacket &PtmTrcPacket::operator =(const ocsd_ptm_pkt* p_pkt) +{ + *dynamic_cast(this) = *p_pkt; + return *this; +} + +void PtmTrcPacket::Clear() +{ + err_type = PTM_PKT_NOERROR; + cycle_count = 0; + cc_valid = 0; + context.updated = 0; + context.updated_c = 0; + context.updated_v = 0; + ts_update_bits = 0; + atom.En_bits = 0; + exception.bits.present = 0; + prev_isa = curr_isa; // mark ISA as not changed +} + +void PtmTrcPacket::ResetState() +{ + type = PTM_PKT_NOTSYNC; + + context.ctxtID = 0; + context.VMID = 0; + context.curr_alt_isa = 0; + context.curr_Hyp = 0; + context.curr_NS = 0; + + addr.valid_bits = 0; + addr.size = VA_32BIT; + addr.val = 0; + + prev_isa = curr_isa = ocsd_isa_unknown; + + timestamp = 0; + + Clear(); +} + +void PtmTrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits) +{ + ocsd_vaddr_t validMask = OCSD_VA_MASK; + validMask >>= OCSD_MAX_VA_BITSIZE-updateBits; + addr.pkt_bits = updateBits; + addr.val &= ~validMask; + addr.val |= (partAddrVal & validMask); + if(updateBits > addr.valid_bits) + addr.valid_bits = updateBits; +} + +void PtmTrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits) +{ + uint64_t validMask = ~0ULL; + validMask >>= 64-updateBits; + timestamp &= ~validMask; + timestamp |= (tsVal & validMask); + ts_update_bits = updateBits; +} + +void PtmTrcPacket::SetCycleAccAtomFromPHdr(const uint8_t pHdr) +{ + atom.num = 1; + atom.En_bits = (pHdr & 0x2) ? 0x0 : 0x1; +} + +void PtmTrcPacket::SetAtomFromPHdr(const uint8_t pHdr) +{ + // how many atoms + uint8_t atom_fmt_id = pHdr & 0xF0; + if(atom_fmt_id == 0x80) + { + // format 1 or 2 + if((pHdr & 0x08) == 0x08) + atom.num = 2; + else + atom.num = 1; + } + else if(atom_fmt_id == 0x90) + { + atom.num = 3; + } + else + { + if((pHdr & 0xE0) == 0xA0) + atom.num = 4; + else + atom.num = 5; + } + + // extract the E/N bits + uint8_t atom_mask = 0x2; // start @ bit 1 - newest instruction + atom.En_bits = 0; + for(int i = 0; i < atom.num; i++) + { + atom.En_bits <<= 1; + if(!(atom_mask & pHdr)) // 0 bit is an E in PTM -> a one in the standard atom bit type + atom.En_bits |= 0x1; + atom_mask <<= 1; + } +} + + // printing +void PtmTrcPacket::toString(std::string &str) const +{ + std::string temp1, temp2; + std::ostringstream oss; + + packetTypeName(type, temp1,temp2); + oss << temp1 << " : " << temp2 << "; "; + + // some packets require additional data. + switch(type) + { + case PTM_PKT_BAD_SEQUENCE: + packetTypeName(err_type, temp1,temp2); + oss << "[" << temp1 << "]; "; + break; + + case PTM_PKT_ATOM: + getAtomStr(temp1); + oss << temp1; + break; + + case PTM_PKT_CONTEXT_ID: + oss << "CtxtID=0x" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; "; + break; + + case PTM_PKT_VMID: + oss << "VMID=0x" << std::hex << std::setw(2) << std::setfill('0') << context.VMID << "; "; + break; + + case PTM_PKT_WPOINT_UPDATE: + case PTM_PKT_BRANCH_ADDRESS: + getBranchAddressStr(temp1); + oss << temp1; + break; + + case PTM_PKT_I_SYNC: + getISyncStr(temp1); + oss << temp1; + break; + + case PTM_PKT_TIMESTAMP: + getTSStr(temp1); + oss << temp1; + break; + } + + str = oss.str(); +} + +void PtmTrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const +{ + toString(str); +} + +void PtmTrcPacket::getAtomStr(std::string &valStr) const +{ + std::ostringstream oss; + uint32_t bitpattern = atom.En_bits; // arranged LSBit oldest, MSbit newest + + if(cc_valid) // cycle accurate trace - single atom + { + std::string subStr; + oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest + oss << "; "; + getCycleCountStr(subStr); + oss << subStr; + } + else + { + // none cycle count + for(int i = 0; i < atom.num; i++) + { + oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest + bitpattern >>= 1; + } + oss << "; "; + } + valStr = oss.str(); +} + +void PtmTrcPacket::getBranchAddressStr(std::string &valStr) const +{ + std::ostringstream oss; + std::string subStr; + + // print address. + trcPrintableElem::getValStr(subStr,32,addr.valid_bits,addr.val,true,addr.pkt_bits); + oss << "Addr=" << subStr << "; "; + + // current ISA if changed. + if(curr_isa != prev_isa) + { + getISAStr(subStr); + oss << subStr; + } + + // S / NS etc if changed. + if(context.updated) + { + oss << (context.curr_NS ? "NS; " : "S; "); + oss << (context.curr_Hyp ? "Hyp; " : ""); + } + + // exception? + if(exception.bits.present) + { + getExcepStr(subStr); + oss << subStr; + } + + if(cc_valid) + { + getCycleCountStr(subStr); + oss << subStr; + } + valStr = oss.str(); +} + +void PtmTrcPacket::getISAStr(std::string &isaStr) const +{ + std::ostringstream oss; + oss << "ISA="; + switch(curr_isa) + { + case ocsd_isa_arm: + oss << "ARM(32); "; + break; + + case ocsd_isa_thumb2: + oss << "Thumb2; "; + break; + + case ocsd_isa_aarch64: + oss << "AArch64; "; + break; + + case ocsd_isa_tee: + oss << "ThumbEE; "; + break; + + case ocsd_isa_jazelle: + oss << "Jazelle; "; + break; + + default: + case ocsd_isa_unknown: + oss << "Unknown; "; + break; + } + isaStr = oss.str(); +} + +void PtmTrcPacket::getExcepStr(std::string &excepStr) const +{ + static const char *ARv7Excep[] = { + "No Exception", "Debug Halt", "SMC", "Hyp", + "Async Data Abort", "Jazelle", "Reserved", "Reserved", + "PE Reset", "Undefined Instr", "SVC", "Prefetch Abort", + "Data Fault", "Generic", "IRQ", "FIQ" + }; + + std::ostringstream oss; + oss << "Excep="; + if(exception.number < 16) + oss << ARv7Excep[exception.number]; + else + oss << "Unknown"; + oss << " [" << std::hex << std::setw(2) << std::setfill('0') << exception.number << "]; "; + excepStr = oss.str(); +} + +void PtmTrcPacket::getISyncStr(std::string &valStr) const +{ + std::ostringstream oss; + std::string tmpStr; + static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" }; + + // reason. + oss << "(" << reason[(int)i_sync_reason] << "); "; + + // full address. + oss << "Addr=0x" << std::hex << std::setfill('0') << std::setw(8) << (uint32_t)addr.val << "; "; + + oss << (context.curr_NS ? "NS; " : "S; "); + oss << (context.curr_Hyp ? "Hyp; " : " "); + + if(context.updated_c) + { + oss << "CtxtID=" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; "; + } + + getISAStr(tmpStr); + oss << tmpStr; + + if(cc_valid) + { + getCycleCountStr(tmpStr); + oss << tmpStr; + } + valStr = oss.str(); +} + +void PtmTrcPacket::getTSStr(std::string &valStr) const +{ + std::string tmpStr; + std::ostringstream oss; + + trcPrintableElem::getValStr(tmpStr,64,64,timestamp,true,ts_update_bits); + oss << "TS=" << tmpStr + "(" << std::dec << timestamp << "); "; + if(cc_valid) + { + getCycleCountStr(tmpStr); + oss << tmpStr; + } + valStr = oss.str(); +} + + +void PtmTrcPacket::getCycleCountStr(std::string &subStr) const +{ + std::ostringstream oss; + oss << "Cycles=" << std::dec << cycle_count << "; "; + subStr = oss.str(); +} + + +void PtmTrcPacket::packetTypeName(const ocsd_ptm_pkt_type pkt_type, std::string &name, std::string &desc) const +{ + switch(pkt_type) + { + case PTM_PKT_NOTSYNC: //!< no sync found yet + name = "NOTSYNC"; + desc = "PTM Not Synchronised"; + break; + + case PTM_PKT_INCOMPLETE_EOT: + name = "INCOMPLETE_EOT"; + desc = "Incomplete packet flushed at end of trace"; + break; + + case PTM_PKT_NOERROR: + name = "NO_ERROR"; + desc = "Error type not set"; + break; + + case PTM_PKT_BAD_SEQUENCE: + name = "BAD_SEQUENCE"; + desc = "Invalid sequence in packet"; + break; + + case PTM_PKT_RESERVED: + name = "RESERVED"; + desc = "Reserved Packet Header"; + break; + + case PTM_PKT_BRANCH_ADDRESS: + name = "BRANCH_ADDRESS"; + desc = "Branch address packet"; + break; + + case PTM_PKT_A_SYNC: + name = "ASYNC"; + desc = "Alignment Synchronisation Packet"; + break; + + case PTM_PKT_I_SYNC: + name = "ISYNC"; + desc = "Instruction Synchronisation packet"; + break; + + case PTM_PKT_TRIGGER: + name = "TRIGGER"; + desc = "Trigger Event packet"; + break; + + case PTM_PKT_WPOINT_UPDATE: + name = "WP_UPDATE"; + desc = "Waypoint update packet"; + break; + + case PTM_PKT_IGNORE: + name = "IGNORE"; + desc = "Ignore packet"; + break; + + case PTM_PKT_CONTEXT_ID: + name = "CTXTID"; + desc = "Context ID packet"; + break; + + case PTM_PKT_VMID: + name = "VMID"; + desc = "VM ID packet"; + break; + + case PTM_PKT_ATOM: + name = "ATOM"; + desc = "Atom packet"; + break; + + case PTM_PKT_TIMESTAMP: + name = "TIMESTAMP"; + desc = "Timestamp packet"; + break; + + case PTM_PKT_EXCEPTION_RET: + name = "ERET"; + desc = "Exception return packet"; + break; + + default: + name = "UNKNOWN"; + desc = "Unknown packet type"; + break; + + //PTM_PKT_BRANCH_OR_BYPASS_EOT, + //PTM_PKT_TPIU_PAD_EOB, + } +} + +/* End of File trc_pkt_elem_ptm.cpp */ diff --git a/contrib/opencsd/decoder/source/ptm/trc_pkt_proc_ptm.cpp b/contrib/opencsd/decoder/source/ptm/trc_pkt_proc_ptm.cpp new file mode 100644 index 000000000000..7c90b62e6413 --- /dev/null +++ b/contrib/opencsd/decoder/source/ptm/trc_pkt_proc_ptm.cpp @@ -0,0 +1,1215 @@ +/* + * \file trc_pkt_proc_ptm.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/ptm/trc_pkt_proc_ptm.h" +#include "opencsd/ptm/trc_cmp_cfg_ptm.h" +#include "common/ocsd_error.h" + + +#ifdef __GNUC__ +// G++ doesn't like the ## pasting +#define PTM_PKTS_NAME "PKTP_PTM" +#else +// VC++ is OK +#define PTM_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_PTM" +#endif + +TrcPktProcPtm::TrcPktProcPtm() : TrcPktProcBase(PTM_PKTS_NAME) +{ + InitProcessorState(); + BuildIPacketTable(); +} + +TrcPktProcPtm::TrcPktProcPtm(int instIDNum) : TrcPktProcBase(PTM_PKTS_NAME, instIDNum) +{ + InitProcessorState(); + BuildIPacketTable(); +} + +TrcPktProcPtm::~TrcPktProcPtm() +{ + +} + +ocsd_err_t TrcPktProcPtm::onProtocolConfig() +{ + ocsd_err_t err = OCSD_ERR_NOT_INIT; + + if(m_config != 0) + { + m_chanIDCopy = m_config->getTraceID(); + err = OCSD_OK; + } + return err; +} + +ocsd_datapath_resp_t TrcPktProcPtm::processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + uint8_t currByte = 0; + + m_dataInProcessed = 0; + + if(!checkInit()) + { + resp = OCSD_RESP_FATAL_NOT_INIT; + } + else + { + m_pDataIn = pDataBlock; + m_dataInLen = dataBlockSize; + m_block_idx = index; // index start for current block + } + + while( ( ( m_dataInProcessed < dataBlockSize) || + (( m_dataInProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) ) && + OCSD_DATA_RESP_IS_CONT(resp)) + { + try + { + switch(m_process_state) + { + case WAIT_SYNC: + if(!m_waitASyncSOPkt) + { + m_curr_pkt_index = m_block_idx + m_dataInProcessed; + m_curr_packet.type = PTM_PKT_NOTSYNC; + m_bAsyncRawOp = hasRawMon(); + } + resp = waitASync(); + break; + + case PROC_HDR: + m_curr_pkt_index = m_block_idx + m_dataInProcessed; + if(readByte(currByte)) + { + m_pIPktFn = m_i_table[currByte].pptkFn; + m_curr_packet.type = m_i_table[currByte].pkt_type; + } + else + { + // sequencing error - should not get to the point where readByte + // fails and m_DataInProcessed < dataBlockSize + // throw data overflow error + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_PKT_INTERP_FAIL,m_curr_pkt_index,this->m_chanIDCopy,"Data Buffer Overrun"); + } + m_process_state = PROC_DATA; + + case PROC_DATA: + (this->*m_pIPktFn)(); + break; + + case SEND_PKT: + resp = outputPacket(); + InitPacketState(); + m_process_state = PROC_HDR; + break; + } + } + catch(ocsdError &err) + { + LogError(err); + if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) || + (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)) + { + // send invalid packets up the pipe to let the next stage decide what to do. + m_process_state = SEND_PKT; + } + else + { + // bail out on any other error. + resp = OCSD_RESP_FATAL_INVALID_DATA; + } + } + catch(...) + { + /// vv bad at this point. + resp = OCSD_RESP_FATAL_SYS_ERR; + const ocsdError &fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_curr_pkt_index,m_chanIDCopy,"Unknown System Error decoding trace."); + LogError(fatal); + } + + } + *numBytesProcessed = m_dataInProcessed; + return resp; +} + +ocsd_datapath_resp_t TrcPktProcPtm::onEOT() +{ + ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT; + if(checkInit()) + { + err = OCSD_RESP_CONT; + if(m_currPacketData.size() > 0) + { + m_curr_packet.SetErrType(PTM_PKT_INCOMPLETE_EOT); + err = outputPacket(); + } + } + return err; +} + +ocsd_datapath_resp_t TrcPktProcPtm::onReset() +{ + ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT; + if(checkInit()) + { + InitProcessorState(); + err = OCSD_RESP_CONT; + } + return err; +} + +ocsd_datapath_resp_t TrcPktProcPtm::onFlush() +{ + ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT; + if(checkInit()) + { + err = OCSD_RESP_CONT; + } + return err; +} + +const bool TrcPktProcPtm::isBadPacket() const +{ + return m_curr_packet.isBadPacket(); +} + +void TrcPktProcPtm::InitPacketState() +{ + m_curr_packet.Clear(); + +} + +void TrcPktProcPtm::InitProcessorState() +{ + m_curr_packet.SetType(PTM_PKT_NOTSYNC); + m_pIPktFn = &TrcPktProcPtm::pktReserved; + m_process_state = WAIT_SYNC; + m_async_0 = 0; + m_waitASyncSOPkt = false; + m_bAsyncRawOp = false; + m_bOPNotSyncPkt = false; + + m_curr_packet.ResetState(); + InitPacketState(); +} + +const bool TrcPktProcPtm::readByte(uint8_t &currByte) +{ + bool bValidByte = false; + + if(m_dataInProcessed < m_dataInLen) + { + currByte = m_pDataIn[m_dataInProcessed++]; + m_currPacketData.push_back(currByte); + bValidByte = true; + } + return bValidByte; +} + +void TrcPktProcPtm::unReadByte() +{ + m_dataInProcessed--; + m_currPacketData.pop_back(); +} + +ocsd_datapath_resp_t TrcPktProcPtm::outputPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + resp = outputOnAllInterfaces(m_curr_pkt_index,&m_curr_packet,&m_curr_packet.type,m_currPacketData); + m_currPacketData.clear(); + return resp; +} + +/*** sync and packet functions ***/ +ocsd_datapath_resp_t TrcPktProcPtm::waitASync() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + + // looking for possible patterns in input buffer:- + // a) ASYNC @ start : 00 00 00 00 00 80 + // b) unsync then async: xx xx xx xx xx xx xx xx 00 00 00 00 00 80 + // c) unsync (may have 00) xx xx xx xx 00 xx xx 00 00 00 xx xx xx xx + // d) unsync then part async: xx xx xx xx xx xx xx xx xx xx xx 00 00 00 + // e) unsync with prev part async [00 00 00] 00 xx xx xx xx xx xx xx xx [] = byte in previous input buffer + + // bytes to read before throwing an unsynced packet + #define UNSYNC_PKT_MAX 16 + static const uint8_t spare_zeros[] = { 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 }; + + bool doScan = true; + bool bSendUnsyncedData = false; + bool bHaveASync = false; + int unsynced_bytes = 0; + int unsync_scan_block_start = 0; + int pktBytesOnEntry = m_currPacketData.size(); // did we have part of a potential async last time? + + while(doScan && OCSD_DATA_RESP_IS_CONT(resp)) + { + // may have spotted the start of an async + if(m_waitASyncSOPkt == true) + { + switch(findAsync()) + { + case ASYNC: + case ASYNC_EXTRA_0: + m_process_state = SEND_PKT; + m_waitASyncSOPkt = false; + bSendUnsyncedData = true; + bHaveASync = true; + doScan = false; + break; + + case THROW_0: + // remove a bunch of 0s + unsynced_bytes += ASYNC_PAD_0_LIMIT; + m_waitASyncSOPkt = false; + m_currPacketData.erase( m_currPacketData.begin(), m_currPacketData.begin()+ASYNC_PAD_0_LIMIT); + break; + + case NOT_ASYNC: + unsynced_bytes += m_currPacketData.size(); + m_waitASyncSOPkt = false; + m_currPacketData.clear(); + break; + + case ASYNC_INCOMPLETE: + bSendUnsyncedData = true; + doScan = false; + break; + } + } + else + { + if(m_pDataIn[m_dataInProcessed++] == 0x00) + { + m_waitASyncSOPkt = true; + m_currPacketData.push_back(0); + m_async_0 = 1; + } + else + { + unsynced_bytes++; + } + } + + // may need to send some unsynced data here, either if we have enought to make it worthwhile, + // or are at the end of the buffer. + if(unsynced_bytes >= UNSYNC_PKT_MAX) + bSendUnsyncedData = true; + + if(m_dataInProcessed == m_dataInLen) + { + bSendUnsyncedData = true; + doScan = false; // no more data available - stop the scan + } + + // will send any unsynced data + if(bSendUnsyncedData && (unsynced_bytes > 0)) + { + if(m_bAsyncRawOp) + { + // there were some 0's in the packet buyffer from the last pass that are no longer in the raw buffer, + // and these turned out not to be an async + if(pktBytesOnEntry) + { + outputRawPacketToMonitor(m_curr_pkt_index,&m_curr_packet,pktBytesOnEntry,spare_zeros); + m_curr_pkt_index += pktBytesOnEntry; + } + outputRawPacketToMonitor(m_curr_pkt_index,&m_curr_packet,unsynced_bytes,m_pDataIn+unsync_scan_block_start); + } + if (!m_bOPNotSyncPkt) + { + resp = outputDecodedPacket(m_curr_pkt_index, &m_curr_packet); + m_bOPNotSyncPkt = true; + } + unsync_scan_block_start += unsynced_bytes; + m_curr_pkt_index+= unsynced_bytes; + unsynced_bytes = 0; + bSendUnsyncedData = false; + } + + // mark next packet as the ASYNC we are looking for. + if(bHaveASync) + m_curr_packet.SetType(PTM_PKT_A_SYNC); + } + + return resp; +} + +void TrcPktProcPtm::pktASync() +{ + if(m_currPacketData.size() == 1) // header byte + { + m_async_0 = 1; + } + + switch(findAsync()) + { + case ASYNC: + case ASYNC_EXTRA_0: + m_process_state = SEND_PKT; + break; + + case THROW_0: + case NOT_ASYNC: + throwMalformedPacketErr("Bad Async packet"); + break; + + case ASYNC_INCOMPLETE: + break; + + } +} + +TrcPktProcPtm::async_result_t TrcPktProcPtm::findAsync() +{ + async_result_t async_res = NOT_ASYNC; + bool bFound = false; // found non-zero byte in sequence + bool bByteAvail = true; + uint8_t currByte; + + while(!bFound && bByteAvail) + { + if(readByte(currByte)) + { + if(currByte == 0x00) + { + m_async_0++; + if(m_async_0 >= (ASYNC_PAD_0_LIMIT + ASYNC_REQ_0)) + { + bFound = true; + async_res = THROW_0; + } + } + else + { + if(currByte == 0x80) + { + if(m_async_0 == 5) + async_res = ASYNC; + else if(m_async_0 > 5) + async_res = ASYNC_EXTRA_0; + } + bFound = true; + } + } + else + { + bByteAvail = false; + async_res = ASYNC_INCOMPLETE; + } + } + return async_res; +} + +void TrcPktProcPtm::pktISync() +{ + uint8_t currByte = 0; + int pktIndex = m_currPacketData.size() - 1; + bool bGotBytes = false, validByte = true; + + if(pktIndex == 0) + { + m_numCtxtIDBytes = m_config->CtxtIDBytes(); + m_gotCtxtIDBytes = 0; + + // total bytes = 6 + ctxtID; (perhaps more later) + m_numPktBytesReq = 6 + m_numCtxtIDBytes; + } + + while(validByte && !bGotBytes) + { + if(readByte(currByte)) + { + pktIndex = m_currPacketData.size() - 1; + if(pktIndex == 5) + { + // got the info byte + int altISA = (currByte >> 2) & 0x1; + int reason = (currByte >> 5) & 0x3; + m_curr_packet.SetISyncReason((ocsd_iSync_reason)(reason)); + m_curr_packet.UpdateNS((currByte >> 3) & 0x1); + m_curr_packet.UpdateAltISA((currByte >> 2) & 0x1); + m_curr_packet.UpdateHyp((currByte >> 1) & 0x1); + + ocsd_isa isa = ocsd_isa_arm; + if(m_currPacketData[1] & 0x1) + isa = altISA ? ocsd_isa_tee : ocsd_isa_thumb2; + m_curr_packet.UpdateISA(isa); + + // check cycle count required - not if reason == 0; + m_needCycleCount = (reason != 0) ? m_config->enaCycleAcc() : false; + m_gotCycleCount = false; + m_numPktBytesReq += (m_needCycleCount ? 1 : 0); + m_gotCCBytes = 0; + + } + else if(pktIndex > 5) + { + // cycle count appears first if present + if(m_needCycleCount && !m_gotCycleCount) + { + if(pktIndex == 6) + m_gotCycleCount = (bool)((currByte & 0x40) == 0); // no cont bit, got cycle count + else + m_gotCycleCount = ((currByte & 0x80) == 0) || (pktIndex == 10); + + m_gotCCBytes++; // count the cycle count bytes for later use. + if(!m_gotCycleCount) // need more cycle count bytes + m_numPktBytesReq++; + } + // then context ID if present. + else if( m_numCtxtIDBytes > m_gotCtxtIDBytes) + { + m_gotCtxtIDBytes++; + } + } + + // check if we have enough bytes + bGotBytes = (bool)((unsigned)m_numPktBytesReq == m_currPacketData.size()); + } + else + validByte = false; // no byte available, exit. + } + + if(bGotBytes) + { + // extract address value, cycle count and ctxt id. + uint32_t cycleCount = 0; + uint32_t ctxtID = 0; + int optIdx = 6; // start index for optional elements. + + // address is always full fixed 32 bit value + uint32_t address = ((uint32_t)m_currPacketData[1]) & 0xFE; + address |= ((uint32_t)m_currPacketData[2]) << 8; + address |= ((uint32_t)m_currPacketData[3]) << 16; + address |= ((uint32_t)m_currPacketData[4]) << 24; + m_curr_packet.UpdateAddress(address,32); + + if(m_needCycleCount) + { + extractCycleCount(optIdx,cycleCount); + m_curr_packet.SetCycleCount(cycleCount); + optIdx+=m_gotCCBytes; + } + + if(m_numCtxtIDBytes) + { + extractCtxtID(optIdx,ctxtID); + m_curr_packet.UpdateContextID(ctxtID); + } + m_process_state = SEND_PKT; + } +} + +void TrcPktProcPtm::pktTrigger() +{ + m_process_state = SEND_PKT; // no payload +} + +void TrcPktProcPtm::pktWPointUpdate() +{ + bool bDone = false; + bool bBytesAvail = true; + uint8_t currByte = 0; + int byteIdx = 0; + + if(m_currPacketData.size() == 1) + { + m_gotAddrBytes = false; // flag to indicate got all needed address bytes + m_numAddrBytes = 0; // number of address bytes so far - in this case header is not part of the address + + m_gotExcepBytes = false; // mark as not got all required exception bytes thus far + m_numExcepBytes = 0; // 0 read in + + m_addrPktIsa = ocsd_isa_unknown; // not set by this packet as yet + } + + // collect all the bytes needed + while(!bDone && bBytesAvail) + { + if(readByte(currByte)) + { + byteIdx = m_currPacketData.size() - 1; + if(!m_gotAddrBytes) + { + if(byteIdx < 4) + { + // address bytes 1 - 4; + // ISA stays the same + if((currByte & 0x80) == 0x00) + { + // no further bytes + m_gotAddrBytes = true; + bDone = true; + m_gotExcepBytes = true; + } + } + else + { + // 5th address byte - determine ISA from this. + if((currByte & 0x40) == 0x00) + m_gotExcepBytes = true; // no exception bytes - mark as done + m_gotAddrBytes = true; + bDone = m_gotExcepBytes; + + m_addrPktIsa = ocsd_isa_arm; // assume ARM, but then check + if((currByte & 0x20) == 0x20) // bit 5 == 1'b1 - jazelle, bits 4 & 3 part of address. + m_addrPktIsa = ocsd_isa_jazelle; + else if((currByte & 0x30) == 0x10) // bit [5:4] == 2'b01 - thumb, bit 3 part of address. + m_addrPktIsa = ocsd_isa_thumb2; + } + m_numAddrBytes++; + } + else if(!m_gotExcepBytes) + { + // excep byte is actually a WP update byte. + m_excepAltISA = ((currByte & 0x40) == 0x40) ? 1 : 0; + m_gotExcepBytes = true; + m_numExcepBytes++; + bDone = true; + } + } + else + bBytesAvail = false; + } + + // analyse the bytes to create the packet + if(bDone) + { + // ISA for the packet + if(m_addrPktIsa == ocsd_isa_unknown) // unchanged by trace packet + m_addrPktIsa = m_curr_packet.getISA(); // same as prev + + if(m_gotExcepBytes) // may adjust according to alt ISA in exception packet + { + if((m_addrPktIsa == ocsd_isa_tee) && (m_excepAltISA == 0)) + m_addrPktIsa = ocsd_isa_thumb2; + else if((m_addrPktIsa == ocsd_isa_thumb2) && (m_excepAltISA == 1)) + m_addrPktIsa = ocsd_isa_tee; + } + m_curr_packet.UpdateISA(m_addrPktIsa); // mark ISA in packet (update changes current and prev to dectect an ISA change). + + uint8_t total_bits = 0; + uint32_t addr_val = extractAddress(1,total_bits); + m_curr_packet.UpdateAddress(addr_val,total_bits); + m_process_state = SEND_PKT; + } +} + +void TrcPktProcPtm::pktIgnore() +{ + m_process_state = SEND_PKT; // no payload +} + +void TrcPktProcPtm::pktCtxtID() +{ + int pktIndex = m_currPacketData.size() - 1; + + // if at the header, determine how many more bytes we need. + if(pktIndex == 0) + { + m_numCtxtIDBytes = m_config->CtxtIDBytes(); + m_gotCtxtIDBytes = 0; + } + + // read the necessary ctxtID bytes from the stream + bool bGotBytes = false, bytesAvail = true; + uint32_t ctxtID = 0; + + bGotBytes = m_numCtxtIDBytes == m_gotCtxtIDBytes; + while(!bGotBytes & bytesAvail) + { + bytesAvail = readByte(); + if(bytesAvail) + m_gotCtxtIDBytes++; + bGotBytes = m_numCtxtIDBytes == m_gotCtxtIDBytes; + } + + if(bGotBytes) + { + if(m_numCtxtIDBytes) + { + extractCtxtID(1,ctxtID); + } + m_curr_packet.UpdateContextID(ctxtID); + m_process_state = SEND_PKT; + } +} + +void TrcPktProcPtm::pktVMID() +{ + uint8_t currByte; + + // just need a single payload byte... + if(readByte(currByte)) + { + m_curr_packet.UpdateVMID(currByte); + m_process_state = SEND_PKT; + } +} + +void TrcPktProcPtm::pktAtom() +{ + uint8_t pHdr = m_currPacketData[0]; + + if(!m_config->enaCycleAcc()) + { + m_curr_packet.SetAtomFromPHdr(pHdr); + m_process_state = SEND_PKT; + } + else + { + bool bGotAllPktBytes = false, byteAvail = true; + uint8_t currByte = 0; // cycle accurate tracing -> atom + cycle count + + if(!(pHdr & 0x40)) + { + // only the header byte present + bGotAllPktBytes = true; + } + else + { + // up to 4 additional bytes of count data. + while(byteAvail && !bGotAllPktBytes) + { + if(readByte(currByte)) + { + if(!(currByte & 0x80) || (m_currPacketData.size() == 5)) + bGotAllPktBytes = true; + } + else + byteAvail = false; + } + } + + // we have all the bytes for a cycle accurate packet. + if(bGotAllPktBytes) + { + uint32_t cycleCount = 0; + extractCycleCount(0,cycleCount); + m_curr_packet.SetCycleCount(cycleCount); + m_curr_packet.SetCycleAccAtomFromPHdr(pHdr); + m_process_state = SEND_PKT; + } + } +} + +void TrcPktProcPtm::pktTimeStamp() +{ + uint8_t currByte = 0; + int pktIndex = m_currPacketData.size() - 1; + bool bGotBytes = false, byteAvail = true; + + if(pktIndex == 0) + { + m_gotTSBytes = false; + m_needCycleCount = m_config->enaCycleAcc(); + m_gotCCBytes = 0; + + // max byte buffer size for full ts packet + m_tsByteMax = m_config->TSPkt64() ? 10 : 8; + } + + while(byteAvail && !bGotBytes) + { + if(readByte(currByte)) + { + if(!m_gotTSBytes) + { + if(((currByte & 0x80) == 0) || (m_currPacketData.size() == (unsigned)m_tsByteMax)) + { + m_gotTSBytes = true; + if(!m_needCycleCount) + bGotBytes = true; + } + } + else + { + uint8_t cc_cont_mask = 0x80; + // got TS bytes, collect cycle count + if(m_gotCCBytes == 0) + cc_cont_mask = 0x40; + if((currByte & cc_cont_mask) == 0) + bGotBytes = true; + m_gotCCBytes++; + if(m_gotCCBytes == 5) + bGotBytes = true; + } + } + else + byteAvail = false; + } + + if(bGotBytes) + { + uint64_t tsVal = 0; + uint32_t cycleCount = 0; + uint8_t tsUpdateBits = 0; + int ts_end_idx = extractTS(tsVal,tsUpdateBits); + if(m_needCycleCount) + { + extractCycleCount(ts_end_idx,cycleCount); + m_curr_packet.SetCycleCount(cycleCount); + } + m_curr_packet.UpdateTimestamp(tsVal,tsUpdateBits); + m_process_state = SEND_PKT; + } +} + +void TrcPktProcPtm::pktExceptionRet() +{ + m_process_state = SEND_PKT; // no payload +} + +void TrcPktProcPtm::pktBranchAddr() +{ + uint8_t currByte = m_currPacketData[0]; + bool bDone = false; + bool bBytesAvail = true; + int byteIdx = 0; + + if(m_currPacketData.size() == 1) + { + m_gotAddrBytes = false; // flag to indicate got all needed address bytes + m_numAddrBytes = 1; // number of address bytes so far + + m_needCycleCount = m_config->enaCycleAcc(); // check if we have a cycle count + m_gotCCBytes = 0; // number of cc bytes read in so far. + + m_gotExcepBytes = false; // mark as not got all required exception bytes thus far + m_numExcepBytes = 0; // 0 read in + + m_addrPktIsa = ocsd_isa_unknown; // not set by this packet as yet + + // header is also 1st address byte + if((currByte & 0x80) == 0) // could be single byte packet + { + m_gotAddrBytes = true; + if(!m_needCycleCount) + bDone = true; // all done if no cycle count + m_gotExcepBytes = true; // cannot have exception bytes following single byte packet + } + + } + + // collect all the bytes needed + while(!bDone && bBytesAvail) + { + if(readByte(currByte)) + { + byteIdx = m_currPacketData.size() - 1; + if(!m_gotAddrBytes) + { + if(byteIdx < 4) + { + // address bytes 2 - 4; + // ISA stays the same + if((currByte & 0x80) == 0x00) + { + // no further bytes + if((currByte & 0x40) == 0x00) + m_gotExcepBytes = true; // no exception bytes - mark as done + m_gotAddrBytes = true; + bDone = m_gotExcepBytes && !m_needCycleCount; + } + } + else + { + // 5th address byte - determine ISA from this. + if((currByte & 0x40) == 0x00) + m_gotExcepBytes = true; // no exception bytes - mark as done + m_gotAddrBytes = true; + bDone = m_gotExcepBytes && !m_needCycleCount; + + m_addrPktIsa = ocsd_isa_arm; // assume ARM, but then check + if((currByte & 0x20) == 0x20) // bit 5 == 1'b1 - jazelle, bits 4 & 3 part of address. + m_addrPktIsa = ocsd_isa_jazelle; + else if((currByte & 0x30) == 0x10) // bit [5:4] == 2'b01 - thumb, bit 3 part of address. + m_addrPktIsa = ocsd_isa_thumb2; + } + m_numAddrBytes++; + } + else if(!m_gotExcepBytes) + { + // may need exception bytes + if(m_numExcepBytes == 0) + { + if((currByte & 0x80) == 0x00) + m_gotExcepBytes = true; + m_excepAltISA = ((currByte & 0x40) == 0x40) ? 1 : 0; + } + else + m_gotExcepBytes = true; + m_numExcepBytes++; + + if(m_gotExcepBytes && !m_needCycleCount) + bDone = true; + + } + else if(m_needCycleCount) + { + // not done after exception bytes, collect cycle count + if(m_gotCCBytes == 0) + { + bDone = ((currByte & 0x40) == 0x00 ); + } + else + { + // done if no more or 5th byte + bDone = (((currByte & 0x80) == 0x00 ) || (m_gotCCBytes == 4)); + } + m_gotCCBytes++; + } + else + // this should never be reached. + throwMalformedPacketErr("sequencing error analysing branch packet"); + } + else + bBytesAvail = false; + } + + // analyse the bytes to create the packet + if(bDone) + { + // ISA for the packet + if(m_addrPktIsa == ocsd_isa_unknown) // unchanged by trace packet + m_addrPktIsa = m_curr_packet.getISA(); // same as prev + + if(m_gotExcepBytes) // may adjust according to alt ISA in exception packet + { + if((m_addrPktIsa == ocsd_isa_tee) && (m_excepAltISA == 0)) + m_addrPktIsa = ocsd_isa_thumb2; + else if((m_addrPktIsa == ocsd_isa_thumb2) && (m_excepAltISA == 1)) + m_addrPktIsa = ocsd_isa_tee; + } + m_curr_packet.UpdateISA(m_addrPktIsa); // mark ISA in packet (update changes current and prev to dectect an ISA change). + + + + // we know the ISA, we can correctly interpret the address. + uint8_t total_bits = 0; + uint32_t addr_val = extractAddress(0,total_bits); + m_curr_packet.UpdateAddress(addr_val,total_bits); + + if(m_numExcepBytes > 0) + { + uint8_t E1 = m_currPacketData[m_numAddrBytes]; + uint16_t ENum = (E1 >> 1) & 0xF; + ocsd_armv7_exception excep = Excp_Reserved; + + m_curr_packet.UpdateNS(E1 & 0x1); + if(m_numExcepBytes > 1) + { + uint8_t E2 = m_currPacketData[m_numAddrBytes+1]; + m_curr_packet.UpdateHyp((E2 >> 5) & 0x1); + ENum |= ((uint16_t)(E2 & 0x1F) << 4); + } + + if(ENum <= 0xF) + { + static ocsd_armv7_exception v7ARExceptions[16] = { + Excp_NoException, Excp_DebugHalt, Excp_SMC, Excp_Hyp, + Excp_AsyncDAbort, Excp_ThumbEECheckFail, Excp_Reserved, Excp_Reserved, + Excp_Reset, Excp_Undef, Excp_SVC, Excp_PrefAbort, + Excp_SyncDataAbort, Excp_Generic, Excp_IRQ, Excp_FIQ + }; + excep = v7ARExceptions[ENum]; + } + m_curr_packet.SetException(excep,ENum); + } + + if(m_needCycleCount) + { + int countIdx = m_numAddrBytes + m_numExcepBytes; + uint32_t cycleCount = 0; + extractCycleCount(countIdx,cycleCount); + m_curr_packet.SetCycleCount(cycleCount); + } + m_process_state = SEND_PKT; + } +} + +void TrcPktProcPtm::pktReserved() +{ + m_process_state = SEND_PKT; // no payload +} + +void TrcPktProcPtm::extractCtxtID(int idx, uint32_t &ctxtID) +{ + ctxtID = 0; + int shift = 0; + for(int i=0; i < m_numCtxtIDBytes; i++) + { + if((size_t)idx+i >= m_currPacketData.size()) + throwMalformedPacketErr("Insufficient packet bytes for Context ID value."); + ctxtID |= ((uint32_t)m_currPacketData[idx+i]) << shift; + shift+=8; + } +} + +void TrcPktProcPtm::extractCycleCount(int offset, uint32_t &cycleCount) +{ + bool bCont = true; + cycleCount = 0; + int by_idx = 0; + uint8_t currByte; + int shift = 4; + + while(bCont) + { + if((size_t)by_idx+offset >= m_currPacketData.size()) + throwMalformedPacketErr("Insufficient packet bytes for Cycle Count value."); + + currByte = m_currPacketData[offset+by_idx]; + if(by_idx == 0) + { + bCont = (currByte & 0x40) != 0; + cycleCount = (currByte >> 2) & 0xF; + } + else + { + + bCont = (currByte & 0x80) != 0; + if(by_idx == 4) + bCont = false; + cycleCount |= (((uint32_t)(currByte & 0x7F)) << shift); + shift += 7; + } + by_idx++; + } +} + +int TrcPktProcPtm::extractTS(uint64_t &tsVal,uint8_t &tsUpdateBits) +{ + bool bCont = true; + int tsIdx = 1; // start index; + uint8_t byteVal; + bool b64BitVal = m_config->TSPkt64(); + int shift = 0; + + tsVal = 0; + tsUpdateBits = 0; + + while(bCont) + { + if((size_t)tsIdx >= m_currPacketData.size()) + throwMalformedPacketErr("Insufficient packet bytes for Timestamp value."); + + byteVal = m_currPacketData[tsIdx]; + + if(b64BitVal) + { + if(tsIdx < 9) + { + bCont = ((byteVal & 0x80) == 0x80); + byteVal &= 0x7F; + tsUpdateBits += 7; + } + else + { + bCont = false; + tsUpdateBits += 8; + } + } + else + { + if(tsIdx < 7) + { + bCont = ((byteVal & 0x80) == 0x80); + byteVal &= 0x7F; + tsUpdateBits += 7; + } + else + { + byteVal &=0x3F; + bCont = false; + tsUpdateBits += 6; + } + } + tsVal |= (((uint64_t)byteVal) << shift); + tsIdx++; + shift += 7; + } + return tsIdx; // return next byte index in packet. +} + +uint32_t TrcPktProcPtm::extractAddress(const int offset, uint8_t &total_bits) +{ + // we know the ISA, we can correctly interpret the address. + uint32_t addr_val = 0; + uint8_t mask = 0x7E; // first byte mask (always); + uint8_t num_bits = 0x7; // number of bits in the 1st byte (thumb); + int shift = 0; + int next_shift = 0; + + total_bits = 0; + + for(int i = 0; i < m_numAddrBytes; i++) + { + if(i == 4) + { + // 5th byte mask + mask = 0x0f; // thumb mask; + num_bits = 4; + if(m_addrPktIsa == ocsd_isa_jazelle) + { + mask = 0x1F; + num_bits = 5; + } + else if(m_addrPktIsa == ocsd_isa_arm) + { + mask = 0x07; + num_bits = 3; + } + } + else if(i > 0) + { + mask = 0x7F; + num_bits = 7; + // check for last byte but not 1st or 5th byte mask + if(i == m_numAddrBytes-1) + { + mask = 0x3F; + num_bits = 6; + } + } + + // extract data + shift = next_shift; + addr_val |= ((uint32_t)(m_currPacketData[i+offset] & mask) << shift); + total_bits += num_bits; + + // how much we shift the next value + if(i == 0) + { + if(m_addrPktIsa == ocsd_isa_jazelle) + { + addr_val >>= 1; + next_shift = 6; + total_bits--; // adjust bits for jazelle offset + } + else + { + next_shift = 7; + } + } + else + { + next_shift += 7; + } + } + + if(m_addrPktIsa == ocsd_isa_arm) + { + addr_val <<= 1; // shift one extra bit for ARM address alignment. + total_bits++; + } + return addr_val; +} + + +void TrcPktProcPtm::BuildIPacketTable() +{ + // initialise all to branch, atom or reserved packet header + for(unsigned i = 0; i < 256; i++) + { + // branch address packets all end in 8'bxxxxxxx1 + if((i & 0x01) == 0x01) + { + m_i_table[i].pkt_type = PTM_PKT_BRANCH_ADDRESS; + m_i_table[i].pptkFn = &TrcPktProcPtm::pktBranchAddr; + } + // atom packets are 8'b1xxxxxx0 + else if((i & 0x81) == 0x80) + { + m_i_table[i].pkt_type = PTM_PKT_ATOM; + m_i_table[i].pptkFn = &TrcPktProcPtm::pktAtom; + } + else + { + // set all the others to reserved for now + m_i_table[i].pkt_type = PTM_PKT_RESERVED; + m_i_table[i].pptkFn = &TrcPktProcPtm::pktReserved; + } + } + + // pick out the other packet types by individual codes. + + // A-sync 8'b00000000 + m_i_table[0x00].pkt_type = PTM_PKT_A_SYNC; + m_i_table[0x00].pptkFn = &TrcPktProcPtm::pktASync; + + // I-sync 8'b00001000 + m_i_table[0x08].pkt_type = PTM_PKT_I_SYNC; + m_i_table[0x08].pptkFn = &TrcPktProcPtm::pktISync; + + // waypoint update 8'b01110010 + m_i_table[0x72].pkt_type = PTM_PKT_WPOINT_UPDATE; + m_i_table[0x72].pptkFn = &TrcPktProcPtm::pktWPointUpdate; + + // trigger 8'b00001100 + m_i_table[0x0C].pkt_type = PTM_PKT_TRIGGER; + m_i_table[0x0C].pptkFn = &TrcPktProcPtm::pktTrigger; + + // context ID 8'b01101110 + m_i_table[0x6E].pkt_type = PTM_PKT_CONTEXT_ID; + m_i_table[0x6E].pptkFn = &TrcPktProcPtm::pktCtxtID; + + // VMID 8'b00111100 + m_i_table[0x3C].pkt_type = PTM_PKT_VMID; + m_i_table[0x3C].pptkFn = &TrcPktProcPtm::pktVMID; + + // Timestamp 8'b01000x10 + m_i_table[0x42].pkt_type = PTM_PKT_TIMESTAMP; + m_i_table[0x42].pptkFn = &TrcPktProcPtm::pktTimeStamp; + m_i_table[0x46].pkt_type = PTM_PKT_TIMESTAMP; + m_i_table[0x46].pptkFn = &TrcPktProcPtm::pktTimeStamp; + + // Exception return 8'b01110110 + m_i_table[0x76].pkt_type = PTM_PKT_EXCEPTION_RET; + m_i_table[0x76].pptkFn = &TrcPktProcPtm::pktExceptionRet; + + // Ignore 8'b01100110 + m_i_table[0x66].pkt_type = PTM_PKT_IGNORE; + m_i_table[0x66].pptkFn = &TrcPktProcPtm::pktIgnore; +} + +/* End of File trc_pkt_proc_ptm.cpp */ diff --git a/contrib/opencsd/decoder/source/stm/trc_pkt_decode_stm.cpp b/contrib/opencsd/decoder/source/stm/trc_pkt_decode_stm.cpp new file mode 100644 index 000000000000..a47e96312546 --- /dev/null +++ b/contrib/opencsd/decoder/source/stm/trc_pkt_decode_stm.cpp @@ -0,0 +1,299 @@ +/* + * \file trc_pkt_decode_stm.cpp + * \brief OpenCSD : STM packet decoder - output generic SW trace packets. + * + * \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. + */ + +#include "opencsd/stm/trc_pkt_decode_stm.h" +#define DCD_NAME "DCD_STM" + +TrcPktDecodeStm::TrcPktDecodeStm() + : TrcPktDecodeBase(DCD_NAME) +{ + initDecoder(); +} + +TrcPktDecodeStm::TrcPktDecodeStm(int instIDNum) + : TrcPktDecodeBase(DCD_NAME, instIDNum) +{ + initDecoder(); +} + +TrcPktDecodeStm::~TrcPktDecodeStm() +{ + if(m_payload_buffer) + delete [] m_payload_buffer; + m_payload_buffer = 0; +} + +/* implementation packet decoding interface */ +ocsd_datapath_resp_t TrcPktDecodeStm::processPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bPktDone = false; + + m_decode_pass1 = true; + + while(!bPktDone) + { + switch(m_curr_state) + { + case NO_SYNC: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); + resp = outputTraceElement(m_output_elem); + m_curr_state = WAIT_SYNC; + break; + + case WAIT_SYNC: + if(m_curr_packet_in->getPktType() == STM_PKT_ASYNC) + m_curr_state = DECODE_PKTS; + bPktDone = true; + break; + + case DECODE_PKTS: + resp = decodePacket(bPktDone); + break; + } + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeStm::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE); + resp = outputTraceElement(m_output_elem); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeStm::onReset() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + resetDecoder(); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeStm::onFlush() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + // don't currently save unsent packets so nothing to flush + return resp; +} + +ocsd_err_t TrcPktDecodeStm::onProtocolConfig() +{ + if(m_config == 0) + return OCSD_ERR_NOT_INIT; + + // static config - copy of CSID for easy reference + m_CSID = m_config->getTraceID(); + return OCSD_OK; +} + +void TrcPktDecodeStm::initDecoder() +{ + m_payload_buffer = 0; + m_num_pkt_correlation = 1; // fixed at single packet payload correlation - add feature later + m_CSID = 0; + + // base decoder state - STM requires no memory and instruction decode. + setUsesMemAccess(false); + setUsesIDecode(false); + + resetDecoder(); +} + +void TrcPktDecodeStm::resetDecoder() +{ + m_curr_state = NO_SYNC; + m_payload_size = 0; + m_payload_used = 0; + m_payload_odd_nibble = false; + m_output_elem.init(); + m_swt_packet_info.swt_flag_bits = 0; // zero out everything + initPayloadBuffer(); +} + +void TrcPktDecodeStm::initPayloadBuffer() +{ + // set up the payload buffer. If we are correlating indentical packets then + // need a buffer that is a multiple of 64bit packets. + // otherwise a single packet length will do. + if(m_payload_buffer) + delete [] m_payload_buffer; + m_payload_buffer = new (std::nothrow) uint8_t[m_num_pkt_correlation * sizeof(uint64_t)]; +} + +ocsd_datapath_resp_t TrcPktDecodeStm::decodePacket(bool &bPktDone) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bSendPacket = false; // flag to indicate output required. + + bPktDone = true; // assume complete unless 2nd pass required. + m_output_elem.setType(OCSD_GEN_TRC_ELEM_SWTRACE); + clearSWTPerPcktInfo(); + + switch (m_curr_packet_in->getPktType()) + { + case STM_PKT_BAD_SEQUENCE: /**< Incorrect protocol sequence */ + case STM_PKT_RESERVED: + resp = OCSD_RESP_FATAL_INVALID_DATA; + case STM_PKT_NOTSYNC: + resetDecoder(); + break; + + case STM_PKT_VERSION: /**< Version packet - not relevant to generic (versionless) o/p */ + case STM_PKT_ASYNC: /**< Alignment synchronisation packet */ + case STM_PKT_INCOMPLETE_EOT: /**< Incomplete packet flushed at end of trace. */ + // no action required. + break; + +/* markers for valid packets*/ + case STM_PKT_NULL: /**< Null packet */ + if(m_curr_packet_in->isTSPkt()) + bSendPacket = true; // forward NULL packet if associated timestamp. + break; + + case STM_PKT_FREQ: /**< Frequency packet */ + m_swt_packet_info.swt_frequency = 1; + updatePayload(bSendPacket); + break; + + case STM_PKT_TRIG: /**< Trigger event packet. */ + m_swt_packet_info.swt_trigger_event = 1; + updatePayload(bSendPacket); + break; + + case STM_PKT_GERR: /**< Global error packet - protocol error but unknown which master had error */ + m_swt_packet_info.swt_master_id = m_curr_packet_in->getMaster(); + m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); + m_swt_packet_info.swt_global_err = 1; + m_swt_packet_info.swt_id_valid = 0; + updatePayload(bSendPacket); + break; + + case STM_PKT_MERR: /**< Master error packet - current master detected an error (e.g. dropped trace) */ + m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); + m_swt_packet_info.swt_master_err = 1; + updatePayload(bSendPacket); + break; + + case STM_PKT_M8: /**< Set current master */ + m_swt_packet_info.swt_master_id = m_curr_packet_in->getMaster(); + m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); // forced to 0 + m_swt_packet_info.swt_id_valid = 1; + break; + + case STM_PKT_C8: /**< Set lower 8 bits of current channel - packet proc hadnles this */ + case STM_PKT_C16: /**< Set current channel */ + m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); + break; + + case STM_PKT_FLAG: /**< Flag packet */ + m_swt_packet_info.swt_marker_packet = 1; + bSendPacket = true; // send 0 payload marker packet./ + break; + + + case STM_PKT_D4: /**< 4 bit data payload packet */ + case STM_PKT_D8: /**< 8 bit data payload packet */ + case STM_PKT_D16: /**< 16 bit data payload packet */ + case STM_PKT_D32: /**< 32 bit data payload packet */ + case STM_PKT_D64: /**< 64 bit data payload packet */ + updatePayload(bSendPacket); + break; + + } + + if(bSendPacket) + { + if(m_curr_packet_in->isTSPkt()) + { + m_output_elem.setTS(m_curr_packet_in->getTSVal()); + m_swt_packet_info.swt_has_timestamp = 1; + } + m_output_elem.setSWTInfo(m_swt_packet_info); + resp = outputTraceElement(m_output_elem); + } + + return resp; +} + +void TrcPktDecodeStm::clearSWTPerPcktInfo() +{ + m_swt_packet_info.swt_flag_bits &= (uint32_t)(0x0 | SWT_ID_VALID_MASK); // clear flags and current payload size (save id valid flag). +} + +void TrcPktDecodeStm::updatePayload(bool &bSendPacket) +{ + // without buffering similar packets - this function is quite simple + bSendPacket = true; + m_swt_packet_info.swt_payload_num_packets = 1; + + switch(m_curr_packet_in->getPktType()) + { + case STM_PKT_D4: /**< 4 bit data payload packet */ + m_swt_packet_info.swt_payload_pkt_bitsize = 4; + *(uint8_t *)m_payload_buffer = m_curr_packet_in->getD4Val(); + break; + + case STM_PKT_D8: /**< 8 bit data payload packet */ + case STM_PKT_TRIG: /**< Trigger event packet - 8 bits. */ + case STM_PKT_GERR: /**< error packet - 8 bits. */ + case STM_PKT_MERR: /**< error packet - 8 bits. */ + m_swt_packet_info.swt_payload_pkt_bitsize = 8; + *(uint8_t *)m_payload_buffer = m_curr_packet_in->getD8Val(); + break; + + case STM_PKT_D16: /**< 16 bit data payload packet */ + m_swt_packet_info.swt_payload_pkt_bitsize = 16; + *(uint16_t *)m_payload_buffer = m_curr_packet_in->getD16Val(); + break; + + case STM_PKT_D32: /**< 32 bit data payload packet */ + case STM_PKT_FREQ: /**< Frequency packet */ + m_swt_packet_info.swt_payload_pkt_bitsize = 32; + *(uint32_t *)m_payload_buffer = m_curr_packet_in->getD32Val(); + break; + + + case STM_PKT_D64: /**< 64 bit data payload packet */ + m_swt_packet_info.swt_payload_pkt_bitsize = 64; + *(uint64_t *)m_payload_buffer = m_curr_packet_in->getD64Val(); + break; + } + m_output_elem.setExtendedDataPtr(m_payload_buffer); + if (m_curr_packet_in->isMarkerPkt()) + m_swt_packet_info.swt_marker_packet = 1; + +} + +/* End of File trc_pkt_decode_stm.cpp */ diff --git a/contrib/opencsd/decoder/source/stm/trc_pkt_elem_stm.cpp b/contrib/opencsd/decoder/source/stm/trc_pkt_elem_stm.cpp new file mode 100644 index 000000000000..d9adaf695556 --- /dev/null +++ b/contrib/opencsd/decoder/source/stm/trc_pkt_elem_stm.cpp @@ -0,0 +1,314 @@ +/* + * \file trc_pkt_elem_stm.cpp + * \brief OpenCSD : STM decode - packet class + * + * \copyright Copyright (c) 2015, 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. + */ + +#include +#include +#include "opencsd/stm/trc_pkt_elem_stm.h" + +StmTrcPacket::StmTrcPacket() +{ + initStartState(); +} + +StmTrcPacket &StmTrcPacket::operator =(const ocsd_stm_pkt *p_pkt) +{ + *dynamic_cast(this) = *p_pkt; + return *this; +} + +void StmTrcPacket::initStartState() +{ + master = 0; + channel = 0; + timestamp = 0; + ts_type = STM_TS_UNKNOWN; + type = STM_PKT_NOTSYNC; + initNextPacket(); +} + +void StmTrcPacket::initNextPacket() +{ + err_type = STM_PKT_NO_ERR_TYPE; + pkt_ts_bits = 0; + pkt_has_marker = 0; + pkt_has_ts = 0; +} + +void StmTrcPacket::setTS(const uint64_t ts_val, const uint8_t updatedBits) +{ + if(updatedBits == 64) + { + timestamp = ts_val; + } + else + { + uint64_t mask = (0x1ULL << updatedBits) - 1; + timestamp &= ~mask; + timestamp |= ts_val & mask; + } + pkt_ts_bits = updatedBits; // mark number of bits + pkt_has_ts = 1; +} + +// printing +void StmTrcPacket::toString(std::string &str) const +{ + std::string name, desc; + std::ostringstream oss; + + pktTypeName(type,name, desc); + str = name + ":" + desc; + + // extended information + switch(type) + { + case STM_PKT_INCOMPLETE_EOT: + case STM_PKT_BAD_SEQUENCE: + pktTypeName(err_type,name, desc); + str+= "[" + name + "]"; + break; + + case STM_PKT_VERSION: + oss << "; Ver=" << (uint16_t)payload.D8; + str+= oss.str(); + break; + + case STM_PKT_FREQ: + oss << "; Freq=" << std::dec << payload.D32 << "Hz"; + str+= oss.str(); + break; + + case STM_PKT_TRIG: + oss << "; TrigData=0x" << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)payload.D8; + str+= oss.str(); + break; + + case STM_PKT_M8: + oss << "; Master=0x" << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)master; + str+= oss.str(); + break; + + case STM_PKT_C8: + case STM_PKT_C16: + oss << "; Chan=0x" << std::hex << std::setw(4) << std::setfill('0') << channel; + str+= oss.str(); + break; + + case STM_PKT_D4: + oss << "; Data=0x" << std::hex << std::setw(1) << (uint16_t)(payload.D8 & 0xF); + str+= oss.str(); + break; + + case STM_PKT_D8: + oss << "; Data=0x" << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)payload.D8; + str+= oss.str(); + break; + + case STM_PKT_D16: + oss << "; Data=0x" << std::hex << std::setw(4) << std::setfill('0') << payload.D16; + str+= oss.str(); + break; + + case STM_PKT_D32: + oss << "; Data=0x" << std::hex << std::setw(8) << std::setfill('0') << payload.D32; + str+= oss.str(); + break; + + case STM_PKT_D64: + oss << "; Data=0x" << std::hex << std::setw(16) << std::setfill('0') << payload.D64; + str+= oss.str(); + break; + } + + if(isTSPkt()) + { + std::string valStr; + trcPrintableElem::getValStr(valStr,64,64,timestamp,true,pkt_ts_bits); + str += "; TS=" + valStr; + } +} + +void StmTrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const +{ + // no formatting for now. + toString(str); +} + +void StmTrcPacket::pktTypeName(const ocsd_stm_pkt_type pkt_type, std::string &name, std::string &desc) const +{ + std::ostringstream oss_name; + std::ostringstream oss_desc; + bool addMarkerTS = false; + + + switch(pkt_type) + { + case STM_PKT_RESERVED: + oss_name << "RESERVED"; + oss_desc << "Reserved Packet Header"; + break; + + case STM_PKT_NOTSYNC: + oss_name << "NOTSYNC"; + oss_desc << "STM not synchronised"; + break; + + case STM_PKT_INCOMPLETE_EOT: + oss_name << "INCOMPLETE_EOT"; + oss_desc << "Incomplete packet flushed at end of trace"; + break; + + case STM_PKT_NO_ERR_TYPE: + oss_name << "NO_ERR_TYPE"; + oss_desc << "Error type not set"; + break; + + case STM_PKT_BAD_SEQUENCE: + oss_name << "BAD_SEQUENCE"; + oss_desc << "Invalid sequence in packet"; + break; + + case STM_PKT_ASYNC: + oss_name << "ASYNC"; + oss_desc << "Alignment synchronisation packet"; + break; + + case STM_PKT_VERSION: + oss_name << "VERSION"; + oss_desc << "Version packet"; + break; + + case STM_PKT_FREQ: + oss_name << "FREQ"; + oss_desc << "Frequency packet"; + break; + + case STM_PKT_NULL: + oss_name << "NULL"; + oss_desc << "Null packet"; + break; + + case STM_PKT_TRIG: + oss_name << "TRIG"; + oss_desc << "Trigger packet"; + addMarkerTS = true; + break; + + case STM_PKT_GERR: + oss_name << "GERR"; + oss_desc << "Global Error"; + break; + + case STM_PKT_MERR: + oss_name << "MERR"; + oss_desc << "Master Error"; + break; + + case STM_PKT_M8: + oss_name << "M8"; + oss_desc << "Set current master"; + break; + + case STM_PKT_C8: + oss_name << "C8"; + oss_desc << "Set current channel"; + break; + + case STM_PKT_C16: + oss_name << "C16"; + oss_desc << "Set current channel"; + break; + + case STM_PKT_FLAG: + oss_name << "FLAG"; + oss_desc << "Flag packet"; + addMarkerTS = true; + break; + + case STM_PKT_D4: + oss_name << "D4"; + oss_desc << "4 bit data"; + addMarkerTS = true; + break; + + case STM_PKT_D8: + oss_name << "D8"; + oss_desc << "8 bit data"; + addMarkerTS = true; + break; + + case STM_PKT_D16: + oss_name << "D16"; + oss_desc << "16 bit data"; + addMarkerTS = true; + break; + + case STM_PKT_D32: + oss_name << "D32"; + oss_desc << "32 bit data"; + addMarkerTS = true; + break; + + case STM_PKT_D64: + oss_name << "D64"; + oss_desc << "64 bit data"; + addMarkerTS = true; + break; + + default: + oss_name << "UNKNOWN"; + oss_desc << "ERROR: unknown packet type"; + break; + } + + if(addMarkerTS) + { + if(isMarkerPkt()) + { + oss_name << "M"; + oss_desc << " + marker"; + } + + if(isTSPkt()) + { + oss_name << "TS"; + oss_desc << " + timestamp"; + } + } + desc = oss_desc.str(); + name = oss_name.str(); +} + + +/* End of File trc_pkt_elem_stm.cpp */ diff --git a/contrib/opencsd/decoder/source/stm/trc_pkt_proc_stm.cpp b/contrib/opencsd/decoder/source/stm/trc_pkt_proc_stm.cpp new file mode 100644 index 000000000000..b39a053b39c0 --- /dev/null +++ b/contrib/opencsd/decoder/source/stm/trc_pkt_proc_stm.cpp @@ -0,0 +1,1043 @@ +/* + * \file trc_pkt_proc_stm.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "opencsd/stm/trc_pkt_proc_stm.h" + + +// processor object construction +// ************************ + +#ifdef __GNUC__ +// G++ doesn't like the ## pasting +#define STM_PKTS_NAME "PKTP_STM" +#else +#define STM_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_STM" +#endif + +static const uint32_t STM_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON; + +TrcPktProcStm::TrcPktProcStm() : TrcPktProcBase(STM_PKTS_NAME) +{ + initObj(); +} + +TrcPktProcStm::TrcPktProcStm(int instIDNum) : TrcPktProcBase(STM_PKTS_NAME, instIDNum) +{ + initObj(); +} + +TrcPktProcStm::~TrcPktProcStm() +{ + getRawPacketMonAttachPt()->set_notifier(0); +} + +void TrcPktProcStm::initObj() +{ + m_supported_op_flags = STM_SUPPORTED_OP_FLAGS; + initProcessorState(); + getRawPacketMonAttachPt()->set_notifier(&mon_in_use); + buildOpTables(); +} + +// implementation packet processing interface overrides +// ************************ +ocsd_datapath_resp_t TrcPktProcStm::processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + m_p_data_in = pDataBlock; + m_data_in_size = dataBlockSize; + m_data_in_used = 0; + + // while there is data and a continue response on the data path + while( dataToProcess() && OCSD_DATA_RESP_IS_CONT(resp) ) + { + try + { + switch(m_proc_state) + { + case WAIT_SYNC: + waitForSync(index); + break; + + case PROC_HDR: + m_packet_index = index + m_data_in_used; + if(readNibble()) + { + m_proc_state = PROC_DATA; // read the header nibble, next if any has to be data + m_pCurrPktFn = m_1N_ops[m_nibble]; // set packet function and fall through + } + else + break; + + case PROC_DATA: + (this->*m_pCurrPktFn)(); + + // if we have enough to send, fall through, otherwise stop + if(m_proc_state != SEND_PKT) + break; + + case SEND_PKT: + resp = outputPacket(); + break; + } + } + catch(ocsdError &err) + { + LogError(err); + if( ((err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) || + (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)) && + !(getComponentOpMode() & OCSD_OPFLG_PKTPROC_ERR_BAD_PKTS)) + { + // send invalid packets up the pipe to let the next stage decide what to do. + resp = outputPacket(); + if(getComponentOpMode() & OCSD_OPFLG_PKTPROC_UNSYNC_ON_BAD_PKTS) + m_proc_state = WAIT_SYNC; + } + else + { + // bail out on any other error. + resp = OCSD_RESP_FATAL_INVALID_DATA; + } + } + catch(...) + { + /// vv bad at this point. + resp = OCSD_RESP_FATAL_SYS_ERR; + ocsdError fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_config->getTraceID()); + fatal.setMessage("Unknown System Error decoding trace."); + LogError(fatal); + } + } + + *numBytesProcessed = m_data_in_used; + return resp; + +} + +ocsd_datapath_resp_t TrcPktProcStm::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + if(m_num_nibbles > 0) // there is a partial packet in flight + { + m_curr_packet.updateErrType(STM_PKT_INCOMPLETE_EOT); // re mark as incomplete + resp = outputPacket(); + } + return resp; +} + +ocsd_datapath_resp_t TrcPktProcStm::onReset() +{ + initProcessorState(); + return OCSD_RESP_CONT; +} + +ocsd_datapath_resp_t TrcPktProcStm::onFlush() +{ + // packet processor never holds on to flushable data (may have partial packet, + // but any full packets are immediately sent) + return OCSD_RESP_CONT; +} + +ocsd_err_t TrcPktProcStm::onProtocolConfig() +{ + return OCSD_OK; // nothing to do on config for this processor +} + +const bool TrcPktProcStm::isBadPacket() const +{ + return m_curr_packet.isBadPacket(); +} + +ocsd_datapath_resp_t TrcPktProcStm::outputPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + resp = outputOnAllInterfaces(m_packet_index,&m_curr_packet,&m_curr_packet.type,m_packet_data); + m_packet_data.clear(); + initNextPacket(); + if(m_nibble_2nd_valid) + savePacketByte(m_nibble_2nd << 4); // put the unused nibble back on to the data stack and pad for output next time. + m_proc_state = m_bStreamSync ? PROC_HDR : WAIT_SYNC; + return resp; +} + +void TrcPktProcStm::throwBadSequenceError(const char *pszMessage /*= ""*/) +{ + m_curr_packet.updateErrType(STM_PKT_BAD_SEQUENCE); + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,this->m_config->getTraceID(),pszMessage); +} + +void TrcPktProcStm::throwReservedHdrError(const char *pszMessage /*= ""*/) +{ + m_curr_packet.setPacketType(STM_PKT_RESERVED,false); + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,this->m_config->getTraceID(),pszMessage); +} + +// processor / packet init +// ************************ + +void TrcPktProcStm::initProcessorState() +{ + // clear any state that persists between packets + setProcUnsynced(); + clearSyncCount(); + m_curr_packet.initStartState(); + m_nibble_2nd_valid = false; + initNextPacket(); + m_bWaitSyncSaveSuppressed = false; + + m_packet_data.clear(); +} + +void TrcPktProcStm::initNextPacket() +{ + // clear state that is unique to each packet + m_bNeedsTS = false; + m_bIsMarker = false; + m_num_nibbles = 0; + m_num_data_nibbles = 0; + m_curr_packet.initNextPacket(); +} + +// search remaining buffer for a start of sync or full sync packet +void TrcPktProcStm::waitForSync(const ocsd_trc_index_t blk_st_index) +{ + bool bGotData = true; + uint32_t start_offset = m_data_in_used; // record the offset into the buffer at start of this fn. + + // input conditions: + // out of sync - either at start of input stream, or due to bad packet. + // m_data_in_used -> bytes already processed + // m_sync_start -> seen potential start of sync in current stream + + // set a packet index for the start of the data + m_packet_index = blk_st_index + m_data_in_used; + m_num_nibbles = m_is_sync ? m_num_F_nibbles + 1 : m_num_F_nibbles; // sending unsync data may have cleared down num_nibbles. + + m_bWaitSyncSaveSuppressed = true; // no need to save bytes until we want to send data. + + while(bGotData && !m_is_sync) + { + bGotData = readNibble(); // read until we have a sync or run out of data + } + + m_bWaitSyncSaveSuppressed = false; + + // no data from first attempt to read + if(m_num_nibbles == 0) + return; + + // we have found a sync or run out of data + // five possible scenarios + // a) all data none sync data. + // b) some none sync data + start of sync sequence + // c) some none sync data + full sync sequence in this frame + // d) full sync sequence @ start of this frame followed by ??? + // e) completion of sync sequence in this frame (from b)). + + if(!bGotData || m_num_nibbles > 22) + { + // for a), b), c) send the none sync data then re-enter + // if out of data, or sync with some previous data, this is sent as unsynced. + + m_curr_packet.setPacketType(STM_PKT_NOTSYNC,false); + if(mon_in_use.usingMonitor()) + { + uint8_t nibbles_to_send = m_num_nibbles - (m_is_sync ? 22 : m_num_F_nibbles); + uint8_t bytes_to_send = (nibbles_to_send / 2) + (nibbles_to_send % 2); + for(uint8_t i = 0; i < bytes_to_send; i++) + savePacketByte(m_p_data_in[start_offset+i]); + } + + // if we have found a sync then we will re-enter this function with no pre data, + // but the found flags set. + } + else + { + // send the async packet + m_curr_packet.setPacketType(STM_PKT_ASYNC,false); + m_bStreamSync = true; // mark the stream as synchronised + clearSyncCount(); + m_packet_index = m_sync_index; + if(mon_in_use.usingMonitor()) + { + // we may not have the full sync packet still in the local buffer so synthesise it. + for(int i = 0; i < 10; i++) + savePacketByte(0xFF); + savePacketByte(0x0F); + } + } + sendPacket(); // mark packet for sending +} + +// packet processing routines +// ************************ +// 1 nibble opcodes +void TrcPktProcStm::stmPktReserved() +{ + uint16_t bad_opcode = (uint16_t)m_nibble; + m_curr_packet.setD16Payload(bad_opcode); + throwReservedHdrError("STM: Unsupported or Reserved STPv2 Header"); +} + +void TrcPktProcStm::stmPktNull() +{ + m_curr_packet.setPacketType(STM_PKT_NULL,false); + if(m_bNeedsTS) + { + m_pCurrPktFn = &TrcPktProcStm::stmExtractTS; + (this->*m_pCurrPktFn)(); + } + else + { + sendPacket(); + } +} + +void TrcPktProcStm::stmPktNullTS() +{ + pktNeedsTS(); + m_pCurrPktFn = &TrcPktProcStm::stmPktNull; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktM8() +{ + if(m_num_nibbles == 1) // 1st nibble - header - set type + m_curr_packet.setPacketType(STM_PKT_M8,false); + + stmExtractVal8(3); + if(m_num_nibbles == 3) + { + m_curr_packet.setMaster(m_val8); + sendPacket(); + } +} + +void TrcPktProcStm::stmPktMERR() +{ + if(m_num_nibbles == 1) // 1st nibble - header - set type + m_curr_packet.setPacketType(STM_PKT_MERR,false); + + stmExtractVal8(3); + if(m_num_nibbles == 3) + { + m_curr_packet.setChannel(0,false); // MERR resets channel for current master to 0. + m_curr_packet.setD8Payload(m_val8); + sendPacket(); + } + +} + +void TrcPktProcStm::stmPktC8() +{ + if(m_num_nibbles == 1) // 1st nibble - header - set type + m_curr_packet.setPacketType(STM_PKT_C8,false); + stmExtractVal8(3); + if(m_num_nibbles == 3) + { + m_curr_packet.setChannel((uint16_t)m_val8,true); + sendPacket(); + } +} + +void TrcPktProcStm::stmPktD4() +{ + if(m_num_nibbles == 1) // 1st nibble - header - set type + { + m_curr_packet.setPacketType(STM_PKT_D4,m_bIsMarker); + m_num_data_nibbles = 2; // need 2 nibbles to complete data + } + + if(m_num_nibbles != m_num_data_nibbles) + { + if(readNibble()) + { + m_curr_packet.setD4Payload(m_nibble); + if(m_bNeedsTS) + { + m_pCurrPktFn = &TrcPktProcStm::stmExtractTS; + (this->*m_pCurrPktFn)(); + } + else + sendPacket(); + } + } +} + +void TrcPktProcStm::stmPktD8() +{ + if(m_num_nibbles == 1) // 1st nibble - header - set type + { + m_curr_packet.setPacketType(STM_PKT_D8,m_bIsMarker); + m_num_data_nibbles = 3; // need 3 nibbles in total to complete data + } + + stmExtractVal8(m_num_data_nibbles); + if(m_num_nibbles == m_num_data_nibbles) + { + m_curr_packet.setD8Payload(m_val8); + if(m_bNeedsTS) + { + m_pCurrPktFn = &TrcPktProcStm::stmExtractTS; + (this->*m_pCurrPktFn)(); + } + else + { + sendPacket(); + } + } +} + +void TrcPktProcStm::stmPktD16() +{ + if(m_num_nibbles == 1) // 1st nibble - header - set type + { + m_curr_packet.setPacketType(STM_PKT_D16,m_bIsMarker); + m_num_data_nibbles = 5; + } + + stmExtractVal16(m_num_data_nibbles); + if(m_num_nibbles == m_num_data_nibbles) + { + m_curr_packet.setD16Payload(m_val16); + if(m_bNeedsTS) + { + m_pCurrPktFn = &TrcPktProcStm::stmExtractTS; + (this->*m_pCurrPktFn)(); + } + else + { + sendPacket(); + } + } +} + +void TrcPktProcStm::stmPktD32() +{ + if(m_num_nibbles == 1) // 1st nibble - header - set type + { + m_curr_packet.setPacketType(STM_PKT_D32,m_bIsMarker); + m_num_data_nibbles = 9; + } + + stmExtractVal32(m_num_data_nibbles); + if(m_num_nibbles == m_num_data_nibbles) + { + m_curr_packet.setD32Payload(m_val32); + if(m_bNeedsTS) + { + m_pCurrPktFn = &TrcPktProcStm::stmExtractTS; + (this->*m_pCurrPktFn)(); + } + else + { + sendPacket(); + } + } +} + +void TrcPktProcStm::stmPktD64() +{ + if(m_num_nibbles == 1) // 1st nibble - header - set type + { + m_curr_packet.setPacketType(STM_PKT_D64,m_bIsMarker); + m_num_data_nibbles = 17; + } + + stmExtractVal64(m_num_data_nibbles); + if(m_num_nibbles == m_num_data_nibbles) + { + m_curr_packet.setD64Payload(m_val64); + if(m_bNeedsTS) + { + m_pCurrPktFn = &TrcPktProcStm::stmExtractTS; + (this->*m_pCurrPktFn)(); + } + else + { + sendPacket(); + } + } +} + +void TrcPktProcStm::stmPktD4MTS() +{ + pktNeedsTS(); + m_bIsMarker = true; + m_pCurrPktFn = &TrcPktProcStm::stmPktD4; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD8MTS() +{ + pktNeedsTS(); + m_bIsMarker = true; + m_pCurrPktFn = &TrcPktProcStm::stmPktD8; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD16MTS() +{ + pktNeedsTS(); + m_bIsMarker = true; + m_pCurrPktFn = &TrcPktProcStm::stmPktD16; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD32MTS() +{ + pktNeedsTS(); + m_bIsMarker = true; + m_pCurrPktFn = &TrcPktProcStm::stmPktD32; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD64MTS() +{ + pktNeedsTS(); + m_bIsMarker = true; + m_pCurrPktFn = &TrcPktProcStm::stmPktD64; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktFlagTS() +{ + pktNeedsTS(); + m_curr_packet.setPacketType(STM_PKT_FLAG,false); + m_pCurrPktFn = &TrcPktProcStm::stmExtractTS; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktFExt() +{ + // no type, look at the next nibble + if(readNibble()) + { + // switch in 2N function + m_pCurrPktFn = m_2N_ops[m_nibble]; + (this->*m_pCurrPktFn)(); + } +} + +// ************************ +// 2 nibble opcodes 0xFn +void TrcPktProcStm::stmPktReservedFn() +{ + uint16_t bad_opcode = 0x00F; + bad_opcode |= ((uint16_t)m_nibble) << 4; + m_curr_packet.setD16Payload(bad_opcode); + throwReservedHdrError("STM: Unsupported or Reserved STPv2 Header"); +} + +void TrcPktProcStm::stmPktF0Ext() +{ + // no type yet, look at the next nibble + if(readNibble()) + { + // switch in 3N function + m_pCurrPktFn = m_3N_ops[m_nibble]; + (this->*m_pCurrPktFn)(); + } +} + +void TrcPktProcStm::stmPktGERR() +{ + if(m_num_nibbles == 2) // 2nd nibble - header - set type + m_curr_packet.setPacketType(STM_PKT_GERR,false); + stmExtractVal8(4); + if(m_num_nibbles == 4) + { + m_curr_packet.setD8Payload(m_val8); + m_curr_packet.setMaster(0); // GERR sets current master to 0. + sendPacket(); + } +} + +void TrcPktProcStm::stmPktC16() +{ + if(m_num_nibbles == 2) // 2nd nibble - header - set type + m_curr_packet.setPacketType(STM_PKT_C16,false); + stmExtractVal16(6); + if(m_num_nibbles == 6) + { + m_curr_packet.setChannel(m_val16,false); + sendPacket(); + } +} + +void TrcPktProcStm::stmPktD4TS() +{ + pktNeedsTS(); + m_curr_packet.setPacketType(STM_PKT_D4,false); // 2nd nibble, set type here + m_num_data_nibbles = 3; // one more nibble for data + m_pCurrPktFn = &TrcPktProcStm::stmPktD4; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD8TS() +{ + pktNeedsTS(); + m_curr_packet.setPacketType(STM_PKT_D8,false); // 2nd nibble, set type here + m_num_data_nibbles = 4; + m_pCurrPktFn = &TrcPktProcStm::stmPktD8; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD16TS() +{ + pktNeedsTS(); + m_curr_packet.setPacketType(STM_PKT_D16,false); // 2nd nibble, set type here + m_num_data_nibbles = 6; + m_pCurrPktFn = &TrcPktProcStm::stmPktD16; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD32TS() +{ + pktNeedsTS(); + m_curr_packet.setPacketType(STM_PKT_D32,false); // 2nd nibble, set type here + m_num_data_nibbles = 10; + m_pCurrPktFn = &TrcPktProcStm::stmPktD32; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD64TS() +{ + pktNeedsTS(); + m_curr_packet.setPacketType(STM_PKT_D64,false); // 2nd nibble, set type here + m_num_data_nibbles = 18; + m_pCurrPktFn = &TrcPktProcStm::stmPktD64; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD4M() +{ + m_curr_packet.setPacketType(STM_PKT_D4,true); // 2nd nibble, set type here + m_num_data_nibbles = 3; // one more nibble for data + m_pCurrPktFn = &TrcPktProcStm::stmPktD4; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD8M() +{ + m_curr_packet.setPacketType(STM_PKT_D8,true); // 2nd nibble, set type here + m_num_data_nibbles = 4; + m_pCurrPktFn = &TrcPktProcStm::stmPktD8; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD16M() +{ + m_curr_packet.setPacketType(STM_PKT_D16,true); + m_num_data_nibbles = 6; + m_pCurrPktFn = &TrcPktProcStm::stmPktD16; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD32M() +{ + m_curr_packet.setPacketType(STM_PKT_D32,true); + m_num_data_nibbles = 10; + m_pCurrPktFn = &TrcPktProcStm::stmPktD32; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktD64M() +{ + m_curr_packet.setPacketType(STM_PKT_D64,true); + m_num_data_nibbles = 18; + m_pCurrPktFn = &TrcPktProcStm::stmPktD64; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktFlag() +{ + m_curr_packet.setPacketType(STM_PKT_FLAG,false); + sendPacket(); +} + +// ************************ +// 3 nibble opcodes 0xF0n +void TrcPktProcStm::stmPktReservedF0n() +{ + uint16_t bad_opcode = 0x00F; + bad_opcode |= ((uint16_t)m_nibble) << 8; + m_curr_packet.setD16Payload(bad_opcode); + throwReservedHdrError("STM: Unsupported or Reserved STPv2 Header"); +} + +void TrcPktProcStm::stmPktVersion() +{ + if(m_num_nibbles == 3) + m_curr_packet.setPacketType(STM_PKT_VERSION,false); + + if(readNibble()) + { + m_curr_packet.setD8Payload(m_nibble); // record the version number + switch(m_nibble) + { + case 3: + m_curr_packet.onVersionPkt(STM_TS_NATBINARY); break; + case 4: + m_curr_packet.onVersionPkt(STM_TS_GREY); break; + default: + // not a version we support. + throwBadSequenceError("STM VERSION packet : unrecognised version number."); + } + sendPacket(); + } +} + +void TrcPktProcStm::stmPktTrigger() +{ + if(m_num_nibbles == 3) + m_curr_packet.setPacketType(STM_PKT_TRIG,false); + stmExtractVal8(5); + if(m_num_nibbles == 5) + { + m_curr_packet.setD8Payload(m_val8); + if(m_bNeedsTS) + { + m_pCurrPktFn = &TrcPktProcStm::stmExtractTS; + (this->*m_pCurrPktFn)(); + } + else + { + sendPacket(); + } + } +} + +void TrcPktProcStm::stmPktTriggerTS() +{ + pktNeedsTS(); + m_pCurrPktFn = &TrcPktProcStm::stmPktTrigger; + (this->*m_pCurrPktFn)(); +} + +void TrcPktProcStm::stmPktFreq() +{ + if(m_num_nibbles == 3) + { + m_curr_packet.setPacketType(STM_PKT_FREQ,false); + m_val32 = 0; + } + stmExtractVal32(11); + if(m_num_nibbles == 11) + { + m_curr_packet.setD32Payload(m_val32); + sendPacket(); + } +} + +void TrcPktProcStm::stmPktASync() +{ + // 2 nibbles - 0xFF - must be an async or error. + bool bCont = true; + while(bCont) + { + bCont = readNibble(); + if(bCont) + { + if(m_is_sync) + { + bCont = false; // stop reading nibbles + m_bStreamSync = true; // mark stream in sync + m_curr_packet.setPacketType(STM_PKT_ASYNC,false); + clearSyncCount(); + sendPacket(); + } + else if(!m_sync_start) // no longer valid sync packet + { + throwBadSequenceError("STM: Invalid ASYNC sequence"); + } + } + } +} + +// ************************ +// general data processing + +// return false if no more data +// in an STM byte, 3:0 is 1st nibble in protocol order, 7:4 is 2nd nibble. +bool TrcPktProcStm::readNibble() +{ + bool dataFound = true; + if(m_nibble_2nd_valid) + { + m_nibble = m_nibble_2nd; + m_nibble_2nd_valid = false; + m_num_nibbles++; + checkSyncNibble(); + } + else if(m_data_in_used < m_data_in_size ) + { + m_nibble = m_p_data_in[m_data_in_used++]; + savePacketByte(m_nibble); + m_nibble_2nd = (m_nibble >> 4) & 0xF; + m_nibble_2nd_valid = true; + m_nibble &= 0xF; + m_num_nibbles++; + checkSyncNibble(); + } + else + dataFound = false; // no data available + return dataFound; +} + +void TrcPktProcStm::pktNeedsTS() +{ + m_bNeedsTS = true; + m_req_ts_nibbles = 0; + m_curr_ts_nibbles = 0; + m_ts_update_value = 0; + m_ts_req_set = false; +} + +void TrcPktProcStm::stmExtractTS() +{ + if(!m_ts_req_set) + { + if(readNibble()) + { + m_req_ts_nibbles = m_nibble; + if(m_nibble == 0xD) + m_req_ts_nibbles = 14; + else if(m_nibble == 0xE) + m_req_ts_nibbles = 16; + + if(m_nibble == 0xF) + throwBadSequenceError("STM: Invalid timestamp size 0xF"); + m_ts_req_set = true; + } + } + + if(m_ts_req_set) + { + // if we do not have all the nibbles for the TS, get some... + if(m_req_ts_nibbles != m_curr_ts_nibbles) + { + // extract the correct amount of nibbles for the ts value. + bool bCont = true; + while(bCont && (m_curr_ts_nibbles < m_req_ts_nibbles)) + { + bCont = readNibble(); + if(bCont) + { + m_ts_update_value <<= 4; + m_ts_update_value |= m_nibble; + m_curr_ts_nibbles++; + } + } + } + + // at this point we have the correct amount of nibbles, or have run out of data to process. + if(m_req_ts_nibbles == m_curr_ts_nibbles) + { + uint8_t new_bits = m_req_ts_nibbles * 4; + if(m_curr_packet.getTSType() == STM_TS_GREY) + { + uint64_t gray_val = bin_to_gray(m_curr_packet.getTSVal()); + if(new_bits == 64) + { + gray_val = m_ts_update_value; + } + else + { + uint64_t mask = (0x1ULL << new_bits) - 1; + gray_val &= ~mask; + gray_val |= m_ts_update_value & mask; + } + m_curr_packet.setTS(gray_to_bin(gray_val),new_bits); + } + else if(m_curr_packet.getTSType() == STM_TS_NATBINARY) + { + m_curr_packet.setTS(m_ts_update_value, new_bits); + } + else + throwBadSequenceError("STM: unknown timestamp encoding"); + + sendPacket(); + } + } +} + +// pass in number of nibbles needed to extract the value +void TrcPktProcStm::stmExtractVal8(uint8_t nibbles_to_val) +{ + bool bCont = true; + while(bCont && (m_num_nibbles < nibbles_to_val)) + { + bCont = readNibble(); + if(bCont) // got a nibble + { + m_val8 <<= 4; + m_val8 |= m_nibble; + } + } +} + +void TrcPktProcStm::stmExtractVal16(uint8_t nibbles_to_val) +{ + bool bCont = true; + while(bCont && (m_num_nibbles < nibbles_to_val)) + { + bCont = readNibble(); + if(bCont) // got a nibble + { + m_val16 <<= 4; + m_val16 |= m_nibble; + } + } +} + +void TrcPktProcStm::stmExtractVal32(uint8_t nibbles_to_val) +{ + bool bCont = true; + while(bCont && (m_num_nibbles < nibbles_to_val)) + { + bCont = readNibble(); + if(bCont) // got a nibble + { + m_val32 <<= 4; + m_val32 |= m_nibble; + } + } +} + +void TrcPktProcStm::stmExtractVal64(uint8_t nibbles_to_val) +{ + bool bCont = true; + while(bCont && (m_num_nibbles < nibbles_to_val)) + { + bCont = readNibble(); + if(bCont) // got a nibble + { + m_val64 <<= 4; + m_val64 |= m_nibble; + } + } +} + +uint64_t TrcPktProcStm::bin_to_gray(uint64_t bin_value) +{ + uint64_t gray_value = 0; + gray_value = (1ull << 63) & bin_value; + int i = 62; + for (; i >= 0; i--) { + uint64_t gray_arg_1 = ((1ull << (i+1)) & bin_value) >> (i+1); + uint64_t gray_arg_2 = ((1ull << i) & bin_value) >> i; + gray_value |= ((gray_arg_1 ^ gray_arg_2) << i); + } + return gray_value; +} + +uint64_t TrcPktProcStm::gray_to_bin(uint64_t gray_value) +{ + uint64_t bin_value = 0; + int bin_bit = 0; + for (; bin_bit < 64; bin_bit++) { + uint8_t bit_tmp = ((1ull << bin_bit) & gray_value) >> bin_bit; + uint8_t gray_bit = bin_bit + 1; + for (; gray_bit < 64; gray_bit++) + bit_tmp ^= (((1ull << gray_bit) & gray_value) >> gray_bit); + + bin_value |= (bit_tmp << bin_bit); + } + + return bin_value; +} + + +void TrcPktProcStm::buildOpTables() +{ + // init all reserved + for(int i = 0; i < 0x10; i++) + { + m_1N_ops[i] = &TrcPktProcStm::stmPktReserved; + m_2N_ops[i] = &TrcPktProcStm::stmPktReservedFn; + m_3N_ops[i] = &TrcPktProcStm::stmPktReservedF0n; + } + + // set the 1N operations + m_1N_ops[0x0] = &TrcPktProcStm::stmPktNull; + m_1N_ops[0x1] = &TrcPktProcStm::stmPktM8; + m_1N_ops[0x2] = &TrcPktProcStm::stmPktMERR; + m_1N_ops[0x3] = &TrcPktProcStm::stmPktC8; + m_1N_ops[0x4] = &TrcPktProcStm::stmPktD8; + m_1N_ops[0x5] = &TrcPktProcStm::stmPktD16; + m_1N_ops[0x6] = &TrcPktProcStm::stmPktD32; + m_1N_ops[0x7] = &TrcPktProcStm::stmPktD64; + m_1N_ops[0x8] = &TrcPktProcStm::stmPktD8MTS; + m_1N_ops[0x9] = &TrcPktProcStm::stmPktD16MTS; + m_1N_ops[0xA] = &TrcPktProcStm::stmPktD32MTS; + m_1N_ops[0xB] = &TrcPktProcStm::stmPktD64MTS; + m_1N_ops[0xC] = &TrcPktProcStm::stmPktD4; + m_1N_ops[0xD] = &TrcPktProcStm::stmPktD4MTS; + m_1N_ops[0xE] = &TrcPktProcStm::stmPktFlagTS; + m_1N_ops[0xF] = &TrcPktProcStm::stmPktFExt; + + // set the 2N operations 0xFn + m_2N_ops[0x0] = &TrcPktProcStm::stmPktF0Ext; + // 0x1 unused in CS STM + m_2N_ops[0x2] = &TrcPktProcStm::stmPktGERR; + m_2N_ops[0x3] = &TrcPktProcStm::stmPktC16; + m_2N_ops[0x4] = &TrcPktProcStm::stmPktD8TS; + m_2N_ops[0x5] = &TrcPktProcStm::stmPktD16TS; + m_2N_ops[0x6] = &TrcPktProcStm::stmPktD32TS; + m_2N_ops[0x7] = &TrcPktProcStm::stmPktD64TS; + m_2N_ops[0x8] = &TrcPktProcStm::stmPktD8M; + m_2N_ops[0x9] = &TrcPktProcStm::stmPktD16M; + m_2N_ops[0xA] = &TrcPktProcStm::stmPktD32M; + m_2N_ops[0xB] = &TrcPktProcStm::stmPktD64M; + m_2N_ops[0xC] = &TrcPktProcStm::stmPktD4TS; + m_2N_ops[0xD] = &TrcPktProcStm::stmPktD4M; + m_2N_ops[0xE] = &TrcPktProcStm::stmPktFlag; + m_2N_ops[0xF] = &TrcPktProcStm::stmPktASync; + + // set the 3N operations 0xF0n + m_3N_ops[0x0] = &TrcPktProcStm::stmPktVersion; + m_3N_ops[0x1] = &TrcPktProcStm::stmPktNullTS; + // 0x2 .. 0x5 not used by CS STM + m_3N_ops[0x6] = &TrcPktProcStm::stmPktTrigger; + m_3N_ops[0x7] = &TrcPktProcStm::stmPktTriggerTS; + m_3N_ops[0x8] = &TrcPktProcStm::stmPktFreq; + // 0x9 .. 0xF not used by CS STM + +} + +/* End of File trc_pkt_proc_stm.cpp */ diff --git a/contrib/opencsd/decoder/source/trc_component.cpp b/contrib/opencsd/decoder/source/trc_component.cpp new file mode 100644 index 000000000000..47200a1ead67 --- /dev/null +++ b/contrib/opencsd/decoder/source/trc_component.cpp @@ -0,0 +1,149 @@ +/* + * \file trc_component.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "common/trc_component.h" + +class errLogAttachMonitor : public IComponentAttachNotifier +{ +public: + errLogAttachMonitor() + { + m_pComp = 0; + }; + virtual ~ errLogAttachMonitor() {}; + virtual void attachNotify(const int num_attached) + { + if(m_pComp) + m_pComp->do_attach_notify(num_attached); + } + void Init(TraceComponent *pComp) + { + m_pComp = pComp; + if(m_pComp) + m_pComp->getErrorLogAttachPt()->set_notifier(this); + } +private: + TraceComponent *m_pComp; +}; + +TraceComponent::TraceComponent(const std::string &name) +{ + Init(name); +} + +TraceComponent::TraceComponent(const std::string &name, int instIDNum) +{ + std::string name_combined = name; + char num_buffer[32]; + sprintf(num_buffer,"_%04d",instIDNum); + name_combined += (std::string)num_buffer; + Init(name_combined); +} + +TraceComponent::~TraceComponent() +{ +} + +void TraceComponent::Init(const std::string &name) +{ + m_errLogHandle = OCSD_INVALID_HANDLE; + m_errVerbosity = OCSD_ERR_SEV_NONE; + m_name = name; + + m_supported_op_flags = 0; + m_op_flags = 0; + m_assocComp = 0; + + m_pErrAttachMon = new (std::nothrow) errLogAttachMonitor(); + if(m_pErrAttachMon) + m_pErrAttachMon->Init(this); +} + +void TraceComponent::LogError(const ocsdError &Error) +{ + if((m_errLogHandle != OCSD_INVALID_HANDLE) && + isLoggingErrorLevel(Error.getErrorSeverity())) + { + // ensure we have not disabled the attachPt + if(m_error_logger.first()) + m_error_logger.first()->LogError(m_errLogHandle,&Error); + } +} + +void TraceComponent::LogMessage(const ocsd_err_severity_t filter_level, const std::string &msg) +{ + if ((m_errLogHandle != OCSD_INVALID_HANDLE) && + isLoggingErrorLevel(filter_level)) + { + // ensure we have not disabled the attachPt + if (m_error_logger.first()) + m_error_logger.first()->LogMessage(this->m_errLogHandle, filter_level, msg); + } + +} + +void TraceComponent::do_attach_notify(const int num_attached) +{ + if(num_attached) + { + // ensure we have not disabled the attachPt + if(m_error_logger.first()) + { + m_errLogHandle = m_error_logger.first()->RegisterErrorSource(m_name); + m_errVerbosity = m_error_logger.first()->GetErrorLogVerbosity(); + } + } + else + { + m_errLogHandle = OCSD_INVALID_HANDLE; + } +} + +void TraceComponent::updateErrorLogLevel() +{ + if(m_error_logger.first()) + { + m_errVerbosity = m_error_logger.first()->GetErrorLogVerbosity(); + } +} + +ocsd_err_t TraceComponent::setComponentOpMode(uint32_t op_flags) +{ + if( (~m_supported_op_flags & op_flags) != 0) + return OCSD_ERR_INVALID_PARAM_VAL; + m_op_flags = op_flags; + return OCSD_OK; +} + +/* End of File trc_component.cpp */ diff --git a/contrib/opencsd/decoder/source/trc_core_arch_map.cpp b/contrib/opencsd/decoder/source/trc_core_arch_map.cpp new file mode 100644 index 000000000000..66513113d4b8 --- /dev/null +++ b/contrib/opencsd/decoder/source/trc_core_arch_map.cpp @@ -0,0 +1,69 @@ +/* + * \file trc_core_arch_map.cpp + * \brief OpenCSD : Map core names to architecture profiles + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "common/trc_core_arch_map.h" + +static struct _ap_map_elements { + const char *name; + ocsd_arch_profile_t ap; +} ap_map_array[] = +{ + { "Cortex-A72", { ARCH_V8, profile_CortexA } }, + { "Cortex-A57", { ARCH_V8, profile_CortexA } }, + { "Cortex-A53", { ARCH_V8, profile_CortexA } }, + { "Cortex-A17", { ARCH_V7, profile_CortexA } }, + { "Cortex-A15", { ARCH_V7, profile_CortexA } }, + { "Cortex-A12", { ARCH_V7, profile_CortexA } }, + { "Cortex-A9", { ARCH_V7, profile_CortexA } }, + { "Cortex-A8", { ARCH_V7, profile_CortexA } }, + { "Cortex-A7", { ARCH_V7, profile_CortexA } }, + { "Cortex-A5", { ARCH_V7, profile_CortexA } }, + { "Cortex-R7", { ARCH_V7, profile_CortexR } }, + { "Cortex-R5", { ARCH_V7, profile_CortexR } }, + { "Cortex-R4", { ARCH_V7, profile_CortexR } }, + { "Cortex-M0", { ARCH_V7, profile_CortexM } }, + { "Cortex-M0+", { ARCH_V7, profile_CortexM } }, + { "Cortex-M3", { ARCH_V7, profile_CortexM } }, + { "Cortex-M4", { ARCH_V7, profile_CortexM } } +}; + +CoreArchProfileMap::CoreArchProfileMap() +{ + for(unsigned i = 0; i < sizeof(ap_map_array)/sizeof(_ap_map_elements); i++) + { + core_profiles[ap_map_array[i].name] = ap_map_array[i].ap; + } +} + +/* End of File trc_core_arch_map.cpp */ diff --git a/contrib/opencsd/decoder/source/trc_frame_deformatter.cpp b/contrib/opencsd/decoder/source/trc_frame_deformatter.cpp new file mode 100644 index 000000000000..b4f40a2f9b44 --- /dev/null +++ b/contrib/opencsd/decoder/source/trc_frame_deformatter.cpp @@ -0,0 +1,856 @@ +/* + * \file trc_frame_deformatter.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ +#include + +#include "common/trc_frame_deformatter.h" +#include "trc_frame_deformatter_impl.h" + +/***************************************************************/ +/* Implementation */ +/***************************************************************/ + +#ifdef __GNUC__ +// G++ doesn't like the ## pasting +#define DEFORMATTER_NAME "DFMT_CSFRAMES" +#else +// VC is fine +#define DEFORMATTER_NAME OCSD_CMPNAME_PREFIX_FRAMEDEFORMATTER##"_CSFRAMES" +#endif + +TraceFmtDcdImpl::TraceFmtDcdImpl() : TraceComponent(DEFORMATTER_NAME), + m_cfgFlags(0), + m_force_sync_idx(0), + m_use_force_sync(false), + m_alignment(16), // assume frame aligned data as default. + m_b_output_packed_raw(false), + m_b_output_unpacked_raw(false) + +{ + resetStateParams(); + setRawChanFilterAll(true); +} + +TraceFmtDcdImpl::TraceFmtDcdImpl(int instNum) : TraceComponent(DEFORMATTER_NAME, instNum), + m_cfgFlags(0), + m_force_sync_idx(0), + m_use_force_sync(false), + m_alignment(16) +{ + resetStateParams(); + setRawChanFilterAll(true); +} + +TraceFmtDcdImpl::~TraceFmtDcdImpl() +{ +} + +ocsd_datapath_resp_t TraceFmtDcdImpl::TraceDataIn( + const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_FATAL_INVALID_OP; + InitCollateDataPathResp(); + + m_b_output_packed_raw = m_RawTraceFrame.num_attached() && ((m_cfgFlags & OCSD_DFRMTR_PACKED_RAW_OUT) != 0); + m_b_output_unpacked_raw = m_RawTraceFrame.num_attached() && ((m_cfgFlags & OCSD_DFRMTR_UNPACKED_RAW_OUT) != 0); + + switch(op) + { + case OCSD_OP_RESET: + resp = Reset(); + break; + + case OCSD_OP_FLUSH: + resp = Flush(); + break; + + case OCSD_OP_EOT: + // local 'flush' here? + // pass on EOT to connected ID streams + resp = executeNoneDataOpAllIDs(OCSD_OP_EOT); + break; + + case OCSD_OP_DATA: + if((dataBlockSize <= 0) || ( pDataBlock == 0) || (numBytesProcessed == 0)) + resp = OCSD_RESP_FATAL_INVALID_PARAM; + else + resp = processTraceData(index,dataBlockSize, pDataBlock, numBytesProcessed); + break; + + default: + break; + } + + return resp; +} + +/* enable / disable ID streams - default as all enabled */ +ocsd_err_t TraceFmtDcdImpl::OutputFilterIDs(std::vector &id_list, bool bEnable) +{ + ocsd_err_t err = OCSD_OK; + std::vector::iterator iter = id_list.begin(); + uint8_t id = 0; + + while((iter < id_list.end()) && (err == OCSD_OK)) + { + id = *iter; + if(id > 128) + err = OCSD_ERR_INVALID_ID; + else + { + m_IDStreams[id].set_enabled(bEnable); + m_raw_chan_enable[id] = bEnable; + } + iter++; + } + return err; +} + +ocsd_err_t TraceFmtDcdImpl::OutputFilterAllIDs(bool bEnable) +{ + for(uint8_t id = 0; id < 128; id++) + { + m_IDStreams[id].set_enabled(bEnable); + } + setRawChanFilterAll(bEnable); + return OCSD_OK; +} + +void TraceFmtDcdImpl::setRawChanFilterAll(bool bEnable) +{ + for(int i=0; i<128; i++) + { + m_raw_chan_enable[i] = bEnable; + } +} + +const bool TraceFmtDcdImpl::rawChanEnabled(const uint8_t id) const +{ + if(id < 128) + return m_raw_chan_enable[id]; + return false; +} + +/* decode control */ +ocsd_datapath_resp_t TraceFmtDcdImpl::Reset() +{ + resetStateParams(); + InitCollateDataPathResp(); + return executeNoneDataOpAllIDs(OCSD_OP_RESET); +} + +ocsd_datapath_resp_t TraceFmtDcdImpl::Flush() +{ + executeNoneDataOpAllIDs(OCSD_OP_FLUSH); // flush any upstream data. + if(dataPathCont()) + outputFrame(); // try to flush any partial frame data remaining + return highestDataPathResp(); +} + +ocsd_datapath_resp_t TraceFmtDcdImpl::executeNoneDataOpAllIDs(ocsd_datapath_op_t op, + const ocsd_trc_index_t index /* = 0*/) +{ + ITrcDataIn *pTrcComp = 0; + for(uint8_t id = 0; id < 128; id++) + { + if(m_IDStreams[id].num_attached()) + { + pTrcComp = m_IDStreams[id].first(); + while(pTrcComp) + { + CollateDataPathResp(pTrcComp->TraceDataIn(op,index,0,0,0)); + pTrcComp = m_IDStreams[id].next(); + } + } + } + + if( m_RawTraceFrame.num_attached()) + { + if(m_RawTraceFrame.first()) + m_RawTraceFrame.first()->TraceRawFrameIn(op,0,OCSD_FRM_NONE,0,0,0); + } + return highestDataPathResp(); +} + +void TraceFmtDcdImpl::outputRawMonBytes(const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const ocsd_rawframe_elem_t frame_element, + const int dataBlockSize, + const uint8_t *pDataBlock, + const uint8_t traceID) +{ + if( m_RawTraceFrame.num_attached()) + { + if(m_RawTraceFrame.first()) + m_RawTraceFrame.first()->TraceRawFrameIn(op,index,frame_element,dataBlockSize, pDataBlock,traceID); + } +} + +void TraceFmtDcdImpl::CollateDataPathResp(const ocsd_datapath_resp_t resp) +{ + // simple most severe error across multiple IDs. + if(resp > m_highestResp) m_highestResp = resp; +} + +ocsd_datapath_resp_t TraceFmtDcdImpl::processTraceData( + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed + ) +{ + try { + + if(!m_first_data) // is this the initial data block? + { + m_trc_curr_idx = index; + } + else + { + if(m_trc_curr_idx != index) // none continuous trace data - throw an error. + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_DFMTR_NOTCONTTRACE,index); + } + + if(dataBlockSize % m_alignment) // must be correctly aligned data + { + ocsdError err(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PARAM_VAL); + char msg_buffer[64]; + sprintf(msg_buffer,"Input block incorrect size, must be %d byte multiple", m_alignment); + err.setMessage(msg_buffer); + throw ocsdError(&err); + } + + // record the incoming block for extraction routines to use. + m_in_block_base = pDataBlock; + m_in_block_size = dataBlockSize; + m_in_block_processed = 0; + + // processing loop... + if(checkForSync()) + { + bool bProcessing = true; + while(bProcessing) + { + bProcessing = extractFrame(); // will stop on end of input data. + if(bProcessing) + bProcessing = unpackFrame(); + if(bProcessing) + bProcessing = outputFrame(); // will stop on data path halt. + } + } + } + catch(const ocsdError &err) { + LogError(err); + CollateDataPathResp(OCSD_RESP_FATAL_INVALID_DATA); + } + catch(...) { + LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_FAIL)); + CollateDataPathResp(OCSD_RESP_FATAL_SYS_ERR); + } + + if(!m_first_data) + m_first_data = true; + + // update the outputs. + *numBytesProcessed = m_in_block_processed; + + return highestDataPathResp(); +} + +ocsd_err_t TraceFmtDcdImpl::DecodeConfigure(uint32_t flags) +{ + const char *pszErrMsg = ""; + ocsd_err_t err = OCSD_OK; + + if((flags & ~OCSD_DFRMTR_VALID_MASK) != 0) + { + err = OCSD_ERR_INVALID_PARAM_VAL; + pszErrMsg = "Unknown Config Flags"; + } + + if((flags & OCSD_DFRMTR_VALID_MASK) == 0) + { + err = OCSD_ERR_INVALID_PARAM_VAL; + pszErrMsg = "No Config Flags Set"; + } + + if((flags & (OCSD_DFRMTR_HAS_FSYNCS | OCSD_DFRMTR_HAS_HSYNCS)) && + (flags & OCSD_DFRMTR_FRAME_MEM_ALIGN) + ) + { + err = OCSD_ERR_INVALID_PARAM_VAL; + pszErrMsg = "Invalid Config Flag Combination Set"; + } + + if(err != OCSD_OK) + { + ocsdError errObj(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL); + errObj.setMessage(pszErrMsg); + LogError(errObj); + } + else + { + m_cfgFlags = flags; + m_alignment = 16; + if(flags & OCSD_DFRMTR_HAS_FSYNCS) + m_alignment = 4; + else if(flags & OCSD_DFRMTR_HAS_HSYNCS) + m_alignment = 2; + } + return err; +} + +void TraceFmtDcdImpl::resetStateParams() +{ + // overall dynamic state - intra frame + m_trc_curr_idx = OCSD_BAD_TRC_INDEX; /* source index of current trace data */ + m_frame_synced = false; + m_first_data = false; + m_curr_src_ID = OCSD_BAD_CS_SRC_ID; + + // current frame processing + m_ex_frm_n_bytes = 0; + m_trc_curr_idx_sof = OCSD_BAD_TRC_INDEX; +} + +bool TraceFmtDcdImpl::checkForSync() +{ + // we can sync on:- + // 16 byte alignment - standard input buffers such as ETB + // FSYNC packets in the stream + // forced index programmed into the object. + uint32_t unsynced_bytes = 0; + + if(!m_frame_synced) + { + if(m_use_force_sync) + { + // is the force sync point in this block? + if((m_force_sync_idx >= m_trc_curr_idx) && (m_force_sync_idx < (m_trc_curr_idx + m_in_block_size))) + { + unsynced_bytes = m_force_sync_idx - m_trc_curr_idx; + m_frame_synced = true; + } + else + { + unsynced_bytes = m_in_block_size; + } + } + else if( m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) // memory aligned data + { + unsynced_bytes = findfirstFSync(); + + } + else + { + // OCSD_DFRMTR_FRAME_MEM_ALIGN - this has guaranteed 16 byte frame size and alignment. + m_frame_synced = true; + } + + if(unsynced_bytes) + { + outputUnsyncedBytes(unsynced_bytes); + m_in_block_processed = unsynced_bytes; + m_trc_curr_idx += unsynced_bytes; + } + } + return m_frame_synced; +} + +uint32_t TraceFmtDcdImpl::findfirstFSync() +{ + uint32_t unsynced = m_in_block_size; // consider entire block as unsynced at present. + //**TBD - handle fsync patterns in TPIU captured code + return unsynced; +} + +void TraceFmtDcdImpl::outputUnsyncedBytes(uint32_t /*num_bytes*/) +{ + //**TBD: +} + +int TraceFmtDcdImpl::checkForResetFSyncPatterns() +{ + const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC + bool check_for_fsync = true; + int num_fsyncs = 0; + const uint8_t *dataPtr = m_in_block_base + m_in_block_processed; + + while (check_for_fsync && (m_in_block_processed < m_in_block_size)) + { + // look for consecutive fsyncs as padding or for reset downstream - both cases will reset downstream.... + if (*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) + { + dataPtr += sizeof(uint32_t); + num_fsyncs++; + } + else + check_for_fsync = false; + } + + if (num_fsyncs) + { + printf("Frame deformatter: Found %d FSYNCS\n",num_fsyncs); + if ((num_fsyncs % 4) == 0) + { + // reset the upstream decoders + executeNoneDataOpAllIDs(OCSD_OP_RESET,m_trc_curr_idx); + + // reset the intra frame parameters + m_curr_src_ID = OCSD_BAD_CS_SRC_ID; + m_ex_frm_n_bytes = 0; + m_trc_curr_idx_sof = OCSD_BAD_TRC_INDEX; + } + else + { + // TBD: throw processing error, none frame size block of fsyncs + } + } + return num_fsyncs * 4; +} + + +bool TraceFmtDcdImpl::extractFrame() +{ + const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC + const uint16_t HSYNC_PATTERN = 0x7FFF; // LE host pattern for HSYNC + + + bool cont_process = true; // continue processing after extraction. + uint32_t f_sync_bytes = 0; // skipped f sync bytes + uint32_t h_sync_bytes = 0; // skipped h sync bytes + uint32_t ex_bytes = 0; // extracted bytes + + // memory aligned sources are always multiples of frames, aligned to start. + if( m_cfgFlags & OCSD_DFRMTR_FRAME_MEM_ALIGN) + { + // some linux drivers (e.g. for perf) will insert FSYNCS to pad or differentiate + // between blocks of aligned data, always in frame aligned complete 16 byte frames. + if (m_cfgFlags & OCSD_DFRMTR_RESET_ON_4X_FSYNC) + { + f_sync_bytes = checkForResetFSyncPatterns(); + + /* in this case the FSYNC pattern is output on both packed and unpacked cases */ + if (f_sync_bytes && (m_b_output_packed_raw || m_b_output_unpacked_raw)) + { + outputRawMonBytes(OCSD_OP_DATA, + m_trc_curr_idx, + OCSD_FRM_FSYNC, + f_sync_bytes, + m_in_block_base + m_in_block_processed, + 0); + } + } + + if((m_in_block_processed+f_sync_bytes) == m_in_block_size) + { + m_ex_frm_n_bytes = 0; + cont_process = false; // end of input data. + } + else + { + // always a complete frame. + m_ex_frm_n_bytes = OCSD_DFRMTR_FRAME_SIZE; + memcpy(m_ex_frm_data, m_in_block_base + m_in_block_processed + f_sync_bytes, m_ex_frm_n_bytes); + m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; + ex_bytes = OCSD_DFRMTR_FRAME_SIZE; + } + } + else + { + // extract data accounting for frame syncs and hsyncs if present. + // we know we are aligned at this point - could be FSYNC or HSYNCs here. + + // check what we a looking for + bool hasFSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) == OCSD_DFRMTR_HAS_FSYNCS); + bool hasHSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_HSYNCS) == OCSD_DFRMTR_HAS_HSYNCS); + + const uint8_t *dataPtr = m_in_block_base+m_in_block_processed; + const uint8_t *eodPtr = m_in_block_base+m_in_block_size; + + cont_process = (bool)(dataPtr < eodPtr); + + // can have FSYNCS at start of frame (in middle is an error). + if(hasFSyncs && cont_process && (m_ex_frm_n_bytes == 0)) + { + while((*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) && cont_process) + { + f_sync_bytes += 4; + dataPtr += 4; + cont_process = (bool)(dataPtr < eodPtr); + + // TBD: output raw FSYNC data on raw frame channel. + } + } + + // not an FSYNC + while((m_ex_frm_n_bytes < OCSD_DFRMTR_FRAME_SIZE) && cont_process) + { + // check for illegal out of sequence FSYNC + if((m_ex_frm_n_bytes % 4) == 0) + { + if(*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) + { + // throw an illegal FSYNC error + } + } + + // mark start of frame after FSyncs + if(m_ex_frm_n_bytes == 0) + m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; + + m_ex_frm_data[m_ex_frm_n_bytes] = dataPtr[0]; + m_ex_frm_data[m_ex_frm_n_bytes+1] = dataPtr[1]; + m_ex_frm_n_bytes+=2; + ex_bytes +=2; + + // check pair is not HSYNC + if(*((uint16_t *)(dataPtr)) == HSYNC_PATTERN) + { + if(hasHSyncs) + { + m_ex_frm_n_bytes-=2; + ex_bytes -= 2; + h_sync_bytes+=2; + + // TBD: output raw HSYNC data on raw frame channel. + } + else + { + // throw illegal HSYNC error. + } + } + + dataPtr += 2; + cont_process = (bool)(dataPtr < eodPtr); + } + + // if we hit the end of data but still have a complete frame waiting, + // need to continue processing to allow it to be used. + if(!cont_process && (m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE)) + cont_process = true; + } + + // output raw data on raw frame channel - packed raw. + if ((m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE) && m_b_output_packed_raw) + { + outputRawMonBytes( OCSD_OP_DATA, + m_trc_curr_idx, + OCSD_FRM_PACKED, + ex_bytes + f_sync_bytes + h_sync_bytes, + m_in_block_base+m_in_block_processed, + 0); + } + + // update the processed count for the buffer + m_in_block_processed += m_ex_frm_n_bytes + f_sync_bytes + h_sync_bytes; + + // update index past the processed data + m_trc_curr_idx += m_ex_frm_n_bytes + f_sync_bytes + h_sync_bytes; + + return cont_process; +} + +bool TraceFmtDcdImpl::unpackFrame() +{ + // unpack cannot fail as never called on incomplete frame. + uint8_t frameFlagBit = 0x1; + uint8_t newSrcID = OCSD_BAD_CS_SRC_ID; + bool PrevIDandIDChange = false; + + // init output processing + m_out_data_idx = 0; + m_out_processed = 0; + + // set up first out data packet... + m_out_data[m_out_data_idx].id = m_curr_src_ID; + m_out_data[m_out_data_idx].valid = 0; + m_out_data[m_out_data_idx].index = m_trc_curr_idx_sof; + m_out_data[m_out_data_idx].used = 0; + + // work on byte pairs - bytes 0 - 13. + for(int i = 0; i < 14; i+=2) + { + PrevIDandIDChange = false; + + // it's an ID + data + if(m_ex_frm_data[i] & 0x1) + { + newSrcID = (m_ex_frm_data[i] >> 1) & 0x7f; + if(newSrcID != m_curr_src_ID) // ID change + { + PrevIDandIDChange = ((frameFlagBit & m_ex_frm_data[15]) != 0); + + // following byte for old id? + if(PrevIDandIDChange) + // 2nd byte always data + m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i+1]; + + // change ID + m_curr_src_ID = newSrcID; + + // if we already have data in this buffer + if(m_out_data[m_out_data_idx].valid > 0) + { + m_out_data_idx++; // move to next buffer + m_out_data[m_out_data_idx].valid = 0; + m_out_data[m_out_data_idx].used = 0; + m_out_data[m_out_data_idx].index = m_trc_curr_idx_sof + i; + } + + // set new ID on buffer + m_out_data[m_out_data_idx].id = m_curr_src_ID; + + /// TBD - ID indexing in here. + } + } + else + // it's just data + { + m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0); + } + + // 2nd byte always data + if(!PrevIDandIDChange) // output only if we didn't for an ID change + prev ID. + m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i+1]; + + frameFlagBit <<= 1; + } + + // unpack byte 14; + + // it's an ID + if(m_ex_frm_data[14] & 0x1) + { + // no matter if change or not, no associated data in byte 15 anyway so just set. + m_curr_src_ID = (m_ex_frm_data[14] >> 1) & 0x7f; + } + // it's data + else + { + m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[14] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0); + } + m_ex_frm_n_bytes = 0; // mark frame as empty; + return true; +} + +// output data to channels. +bool TraceFmtDcdImpl::outputFrame() +{ + bool cont_processing = true; + ITrcDataIn *pDataIn = 0; + uint32_t bytes_used; + + // output each valid ID within the frame - stopping if we get a wait or error + while((m_out_processed < (m_out_data_idx + 1)) && cont_processing) + { + + // may have data prior to a valid ID appearing + if(m_out_data[m_out_processed].id != OCSD_BAD_CS_SRC_ID) + { + if((pDataIn = m_IDStreams[m_out_data[m_out_processed].id].first()) != 0) + { + // log the stuff we are about to put out early so as to make it visible before interpretation + // however, don't re-output if only part used first time round. + if(m_b_output_unpacked_raw && (m_out_data[m_out_processed].used == 0) && rawChanEnabled( m_out_data[m_out_processed].id)) + { + outputRawMonBytes( OCSD_OP_DATA, + m_out_data[m_out_processed].index, + OCSD_FRM_ID_DATA, + m_out_data[m_out_processed].valid, + m_out_data[m_out_processed].data, + m_out_data[m_out_processed].id); + } + + // output to the connected packet process + CollateDataPathResp(pDataIn->TraceDataIn(OCSD_OP_DATA, + m_out_data[m_out_processed].index + m_out_data[m_out_processed].used, + m_out_data[m_out_processed].valid - m_out_data[m_out_processed].used, + m_out_data[m_out_processed].data + m_out_data[m_out_processed].used, + &bytes_used)); + + if(!dataPathCont()) + { + cont_processing = false; + m_out_data[m_out_processed].used += bytes_used; + if(m_out_data[m_out_processed].used == m_out_data[m_out_processed].valid) + m_out_processed++; // we have used up all this data. + } + else + { + m_out_processed++; // we have sent this data; + } + } + else + { + // optional raw output for debugging / monitor tools + if(m_b_output_unpacked_raw && rawChanEnabled( m_out_data[m_out_processed].id)) + { + outputRawMonBytes( OCSD_OP_DATA, + m_out_data[m_out_processed].index, + OCSD_FRM_ID_DATA, + m_out_data[m_out_processed].valid, + m_out_data[m_out_processed].data, + m_out_data[m_out_processed].id); + } + m_out_processed++; // skip past this data. + } + } + else + { + // optional raw output for debugging / monitor tools of unknown src ID data + if(m_b_output_unpacked_raw) + { + outputRawMonBytes( OCSD_OP_DATA, + m_out_data[m_out_processed].index, + OCSD_FRM_ID_DATA, + m_out_data[m_out_processed].valid, + m_out_data[m_out_processed].data, + m_out_data[m_out_processed].id); + } + m_out_processed++; // skip past this data. + } + } + return cont_processing; +} + +/***************************************************************/ +/* interface */ +/***************************************************************/ +TraceFormatterFrameDecoder::TraceFormatterFrameDecoder() : m_pDecoder(0) +{ + m_instNum = -1; +} + +TraceFormatterFrameDecoder::TraceFormatterFrameDecoder(int instNum) : m_pDecoder(0) +{ + m_instNum = instNum; +} + +TraceFormatterFrameDecoder::~TraceFormatterFrameDecoder() +{ + if(m_pDecoder) + { + delete m_pDecoder; + m_pDecoder = 0; + } +} + + /* the data input interface from the reader / source */ +ocsd_datapath_resp_t TraceFormatterFrameDecoder::TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed); +} + +/* attach a data processor to a stream ID output */ +componentAttachPt *TraceFormatterFrameDecoder::getIDStreamAttachPt(uint8_t ID) +{ + componentAttachPt *pAttachPt = 0; + if((ID < 128) && (m_pDecoder != 0)) + pAttachPt = &(m_pDecoder->m_IDStreams[ID]); + return pAttachPt; +} + +/* attach a data processor to the raw frame output */ +componentAttachPt *TraceFormatterFrameDecoder::getTrcRawFrameAttachPt() +{ + return (m_pDecoder != 0) ? &m_pDecoder->m_RawTraceFrame : 0; +} + + +componentAttachPt *TraceFormatterFrameDecoder::getTrcSrcIndexAttachPt() +{ + return (m_pDecoder != 0) ? &m_pDecoder->m_SrcIndexer : 0; +} + +componentAttachPt *TraceFormatterFrameDecoder::getErrLogAttachPt() +{ + return (m_pDecoder != 0) ? m_pDecoder->getErrorLogAttachPt() : 0; +} + +/* configuration - set operational mode for incoming stream (has FSYNCS etc) */ +ocsd_err_t TraceFormatterFrameDecoder::Configure(uint32_t cfg_flags) +{ + if(!m_pDecoder) + { + if(m_instNum >= 0) + m_pDecoder = new (std::nothrow) TraceFmtDcdImpl(m_instNum); + else + m_pDecoder = new (std::nothrow) TraceFmtDcdImpl(); + if(!m_pDecoder) return OCSD_ERR_MEM; + } + m_pDecoder->m_cfgFlags = cfg_flags; + return OCSD_OK; +} + +const uint32_t TraceFormatterFrameDecoder::getConfigFlags() const +{ + uint32_t flags = 0; + if(m_pDecoder) + flags = m_pDecoder->m_cfgFlags; + return flags; +} + + +/* enable / disable ID streams - default as all enabled */ +ocsd_err_t TraceFormatterFrameDecoder::OutputFilterIDs(std::vector &id_list, bool bEnable) +{ + return (m_pDecoder == 0) ? OCSD_ERR_NOT_INIT : m_pDecoder->OutputFilterIDs(id_list,bEnable); +} + +ocsd_err_t TraceFormatterFrameDecoder::OutputFilterAllIDs(bool bEnable) +{ + return (m_pDecoder == 0) ? OCSD_ERR_NOT_INIT : m_pDecoder->OutputFilterAllIDs(bEnable); +} + +/* decode control */ +ocsd_datapath_resp_t TraceFormatterFrameDecoder::Reset() +{ + return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Reset(); +} + +ocsd_datapath_resp_t TraceFormatterFrameDecoder::Flush() +{ + return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Flush(); +} + + +/* End of File trc_frame_deformatter.cpp */ diff --git a/contrib/opencsd/decoder/source/trc_frame_deformatter_impl.h b/contrib/opencsd/decoder/source/trc_frame_deformatter_impl.h new file mode 100644 index 000000000000..e1fc17ab259f --- /dev/null +++ b/contrib/opencsd/decoder/source/trc_frame_deformatter_impl.h @@ -0,0 +1,167 @@ +/* + * \file trc_frame_decoder_impl.h + * \brief OpenCSD : Trace Deformatter implementation. + * + * \copyright Copyright (c) 2015, 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_TRC_FRAME_DECODER_IMPL_H_INCLUDED +#define ARM_TRC_FRAME_DECODER_IMPL_H_INCLUDED + +#include "opencsd/ocsd_if_types.h" +#include "common/comp_attach_pt_t.h" +#include "interfaces/trc_data_raw_in_i.h" +#include "interfaces/trc_data_rawframe_in_i.h" +#include "interfaces/trc_indexer_src_i.h" +#include "common/trc_component.h" + +//! output data fragment from the current frame - collates bytes associated with an ID. +typedef struct _out_chan_data { + ocsd_trc_index_t index; //!< trace source index for start of these bytes + uint8_t id; //!< Id for these bytes + uint8_t data[15]; //!< frame data bytes for this ID + uint32_t valid; //!< Valid data bytes. + uint32_t used; //!< Data bytes output (used by attached processor). +} out_chan_data; + +class TraceFmtDcdImpl : public TraceComponent, ITrcDataIn +{ +private: + TraceFmtDcdImpl(); + TraceFmtDcdImpl(int instNum); + virtual ~TraceFmtDcdImpl(); + + /* the data input interface from the reader */ + virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + + /* enable / disable ID streams - default as all enabled */ + ocsd_err_t OutputFilterIDs(std::vector &id_list, bool bEnable); + ocsd_err_t OutputFilterAllIDs(bool bEnable); + + /* decode control */ + ocsd_datapath_resp_t Reset(); /* reset the decode to the start state, drop partial data - propogate to attached components */ + ocsd_datapath_resp_t Flush(); + ocsd_err_t DecodeConfigure(uint32_t flags); + ocsd_err_t SetForcedSyncIndex(ocsd_trc_index_t index, bool bSet); + +private: + ocsd_datapath_resp_t executeNoneDataOpAllIDs(ocsd_datapath_op_t op, const ocsd_trc_index_t index = 0); + ocsd_datapath_resp_t processTraceData(const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + // process phases + bool checkForSync(); // find the sync point in the incoming block + bool extractFrame(); // extract the frame data from incoming stream + bool unpackFrame(); // process a complete frame. + bool outputFrame(); // output data to channels. + + + // managing data path responses. + void InitCollateDataPathResp() { m_highestResp = OCSD_RESP_CONT; }; + void CollateDataPathResp(const ocsd_datapath_resp_t resp); + const ocsd_datapath_resp_t highestDataPathResp() const { return m_highestResp; }; + const bool dataPathCont() const { return (bool)(m_highestResp < OCSD_RESP_WAIT); }; + + // deformat state + void resetStateParams(); + + // synchronisation + uint32_t findfirstFSync(); + void outputUnsyncedBytes(uint32_t num_bytes); // output bytes as unsynced from current buffer position. + + // output bytes to raw frame monitor + void outputRawMonBytes(const ocsd_datapath_op_t op, + const ocsd_trc_index_t index, + const ocsd_rawframe_elem_t frame_element, + const int dataBlockSize, + const uint8_t *pDataBlock, + const uint8_t traceID); + + + void setRawChanFilterAll(bool bEnable); + const bool rawChanEnabled(const uint8_t id) const; + + int checkForResetFSyncPatterns(); + + friend class TraceFormatterFrameDecoder; + + // attachment points + + componentAttachPt m_IDStreams[128]; + componentAttachPt m_RawTraceFrame; + + componentAttachPt m_SrcIndexer; + + + ocsd_datapath_resp_t m_highestResp; + + /* static configuration */ + uint32_t m_cfgFlags; /* configuration flags */ + ocsd_trc_index_t m_force_sync_idx; + bool m_use_force_sync; + uint32_t m_alignment; + + /* dynamic state */ + ocsd_trc_index_t m_trc_curr_idx; /* index of current trace data */ + bool m_frame_synced; + bool m_first_data; + uint8_t m_curr_src_ID; + + // incoming frame buffer + uint8_t m_ex_frm_data[OCSD_DFRMTR_FRAME_SIZE]; // buffer the current frame in case we have to stop part way through + int m_ex_frm_n_bytes; // number of valid bytes in the current frame (extraction) + ocsd_trc_index_t m_trc_curr_idx_sof; // trace source index at start of frame. + + // channel output data - can never be more than a frame of data for a single ID. + out_chan_data m_out_data[7]; // can only be 8 ID changes in a frame, but last on has no associated data so 7 possible data blocks + int m_out_data_idx; // number of out_chan_data frames used. + int m_out_processed; // number of complete out_chan_data frames output. + + /* local copy of input buffer pointers*/ + const uint8_t *m_in_block_base; + uint32_t m_in_block_size; + uint32_t m_in_block_processed; + + /* raw output options */ + bool m_b_output_packed_raw; + bool m_b_output_unpacked_raw; + + bool m_raw_chan_enable[128]; +}; + + +#endif // ARM_TRC_FRAME_DECODER_IMPL_H_INCLUDED + +/* End of File trc_frame_decoder_impl.h */ diff --git a/contrib/opencsd/decoder/source/trc_gen_elem.cpp b/contrib/opencsd/decoder/source/trc_gen_elem.cpp new file mode 100644 index 000000000000..d2536f5758a0 --- /dev/null +++ b/contrib/opencsd/decoder/source/trc_gen_elem.cpp @@ -0,0 +1,242 @@ +/* + * \file trc_gen_elem.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "common/trc_gen_elem.h" + +#include +#include +#include + +static const char *s_elem_descs[][2] = +{ + {"OCSD_GEN_TRC_ELEM_UNKNOWN","Unknown trace element - default value or indicate error in stream to client."}, + {"OCSD_GEN_TRC_ELEM_NO_SYNC","Waiting for sync - either at start of decode, or after overflow / bad packet"}, + {"OCSD_GEN_TRC_ELEM_TRACE_ON","Start of trace - beginning of elements or restart after discontinuity (overflow, trace filtering)."}, + {"OCSD_GEN_TRC_ELEM_EO_TRACE","End of the available trace in the buffer."}, + {"OCSD_GEN_TRC_ELEM_PE_CONTEXT","PE status update / change (arch, ctxtid, vmid etc)."}, + {"OCSD_GEN_TRC_ELEM_INSTR_RANGE","Traced N consecutive instructions from addr (no intervening events or data elements), may have data assoc key"}, + {"OCSD_GEN_TRC_ELEM_ADDR_NACC","Tracing in inaccessible memory area."}, + {"OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN","Tracing unknown address area."}, + {"OCSD_GEN_TRC_ELEM_EXCEPTION","Exception"}, + {"OCSD_GEN_TRC_ELEM_EXCEPTION_RET","Expection return"}, + {"OCSD_GEN_TRC_ELEM_TIMESTAMP","Timestamp - preceding elements happeded before this time."}, + {"OCSD_GEN_TRC_ELEM_CYCLE_COUNT","Cycle count - cycles since last cycle count value - associated with a preceding instruction range."}, + {"OCSD_GEN_TRC_ELEM_EVENT","Event - numbered event or trigger"}, + {"OCSD_GEN_TRC_ELEM_SWTRACE","Software trace packet - may contain data payload."}, + {"OCSD_GEN_TRC_ELEM_CUSTOM","Fully custom packet type."} +}; + +static const char *instr_type[] = { + "--- ", + "BR ", + "iBR ", + "ISB ", + "DSB.DMB" +}; + +#define T_SIZE (sizeof(instr_type) / sizeof(const char *)) + +static const char *instr_sub_type[] = { + "--- ", + "b+link ", + "A64:ret ", + "A64:eret " +}; + +#define ST_SIZE (sizeof(instr_sub_type) / sizeof(const char *)) + +static const char *s_trace_on_reason[] = { + "begin or filter", + "overflow", + "debug restart" +}; + + +static const char *s_isa_str[] = { + "A32", /**< V7 ARM 32, V8 AArch32 */ + "T32", /**< Thumb2 -> 16/32 bit instructions */ + "A64", /**< V8 AArch64 */ + "TEE", /**< Thumb EE - unsupported */ + "Jaz", /**< Jazelle - unsupported in trace */ + "Cst", /**< ISA custom */ + "Unk" /**< ISA not yet known */ +}; + +void OcsdTraceElement::toString(std::string &str) const +{ + std::ostringstream oss; + int num_str = ((sizeof(s_elem_descs) / sizeof(const char *)) / 2); + int typeIdx = (int)this->elem_type; + if(typeIdx < num_str) + { + oss << s_elem_descs[typeIdx][0] << "("; + switch(elem_type) + { + case OCSD_GEN_TRC_ELEM_INSTR_RANGE: + oss << "exec range=0x" << std::hex << st_addr << ":[0x" << en_addr << "] "; + oss << "(ISA=" << s_isa_str[(int)isa] << ") "; + oss << ((last_instr_exec == 1) ? "E " : "N "); + if((int)last_i_type < T_SIZE) + oss << instr_type[last_i_type]; + if((last_i_subtype != OCSD_S_INSTR_NONE) && ((int)last_i_subtype < ST_SIZE)) + oss << instr_sub_type[last_i_subtype]; + break; + + case OCSD_GEN_TRC_ELEM_ADDR_NACC: + oss << " 0x" << std::hex << st_addr << " "; + break; + + case OCSD_GEN_TRC_ELEM_EXCEPTION: + if(excep_ret_addr == 1) + { + oss << "pref ret addr:0x" << std::hex << en_addr << "; "; + } + oss << "excep num (0x" << std::setfill('0') << std::setw(2) << std::hex << exception_number << ") "; + break; + + case OCSD_GEN_TRC_ELEM_PE_CONTEXT: + oss << "(ISA=" << s_isa_str[(int)isa] << ") "; + if((context.exception_level > ocsd_EL_unknown) && (context.el_valid)) + { + oss << "EL" << std::dec << (int)(context.exception_level); + } + oss << (context.security_level == ocsd_sec_secure ? "S; " : "N; ") << (context.bits64 ? "64-bit; " : "32-bit; "); + if(context.vmid_valid) + oss << "VMID=0x" << std::hex << context.vmid << "; "; + if(context.ctxt_id_valid) + oss << "CTXTID=0x" << std::hex << context.context_id << "; "; + break; + + case OCSD_GEN_TRC_ELEM_TRACE_ON: + oss << " [" << s_trace_on_reason[trace_on_reason] << "]"; + break; + + case OCSD_GEN_TRC_ELEM_TIMESTAMP: + oss << " [ TS=0x" << std::setfill('0') << std::setw(12) << std::hex << timestamp << "]; "; + break; + + case OCSD_GEN_TRC_ELEM_SWTRACE: + printSWInfoPkt(oss); + break; + + default: break; + } + if(has_cc) + oss << std::dec << " [CC=" << cycle_count << "]; "; + oss << ")"; + } + else + { + oss << "OCSD_GEN_TRC_ELEM??: index out of range."; + } + str = oss.str(); +} + +OcsdTraceElement &OcsdTraceElement::operator =(const ocsd_generic_trace_elem* p_elem) +{ + *dynamic_cast(this) = *p_elem; + return *this; +} + + +void OcsdTraceElement::printSWInfoPkt(std::ostringstream & oss) const +{ + if (!sw_trace_info.swt_global_err) + { + if (sw_trace_info.swt_id_valid) + { + oss << " (Ma:0x" << std::setfill('0') << std::setw(2) << std::hex << sw_trace_info.swt_master_id << "; "; + oss << "Ch:0x" << std::setfill('0') << std::setw(2) << std::hex << sw_trace_info.swt_channel_id << ") "; + } + else + oss << "(Ma:0x??; Ch:0x??" << ") "; + + if (sw_trace_info.swt_payload_pkt_bitsize > 0) + { + oss << "0x" << std::setfill('0') << std::hex; + if (sw_trace_info.swt_payload_pkt_bitsize == 4) + { + oss << std::setw(1); + oss << (uint16_t)(((uint8_t *)ptr_extended_data)[0] & 0xF); + } + else + { + switch (sw_trace_info.swt_payload_pkt_bitsize) + { + case 8: + // force uint8 to uint16 so oss 'sees' them as something to be stringised, rather than absolute char values + oss << std::setw(2) << (uint16_t)((uint8_t *)ptr_extended_data)[0]; + break; + case 16: + oss << std::setw(4) << ((uint16_t *)ptr_extended_data)[0]; + break; + case 32: + oss << std::setw(8) << ((uint32_t *)ptr_extended_data)[0]; + break; + case 64: + oss << std::setw(16) << ((uint64_t *)ptr_extended_data)[0]; + break; + default: + oss << "{Data Error : unsupported bit width.}"; + break; + } + } + oss << "; "; + } + if (sw_trace_info.swt_marker_packet) + oss << "+Mrk "; + if (sw_trace_info.swt_trigger_event) + oss << "Trig "; + if (sw_trace_info.swt_has_timestamp) + oss << " [ TS=0x" << std::setfill('0') << std::setw(12) << std::hex << timestamp << "]; "; + if (sw_trace_info.swt_frequency) + oss << "Freq"; + if (sw_trace_info.swt_master_err) + oss << "{Master Error.}"; + } + else + { + oss << "{Global Error.}"; + } +} + +/* +void OcsdTraceElement::toString(const ocsd_generic_trace_elem *p_elem, std::string &str) +{ + OcsdTraceElement elem; + elem = p_elem; + elem.toString(str); +} +*/ +/* End of File trc_gen_elem.cpp */ diff --git a/contrib/opencsd/decoder/source/trc_printable_elem.cpp b/contrib/opencsd/decoder/source/trc_printable_elem.cpp new file mode 100644 index 000000000000..2fd49d973579 --- /dev/null +++ b/contrib/opencsd/decoder/source/trc_printable_elem.cpp @@ -0,0 +1,120 @@ +/* + * \file trc_printable_elem.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, 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. + */ + +#include "common/trc_printable_elem.h" +#include +#include +#if defined(_MSC_VER) && (_MSC_VER < 1900) + /** VS2010 does not support inttypes - remove when VS2010 support is dropped */ +#define __PRI64_PREFIX "ll" +#define PRIX64 __PRI64_PREFIX "X" +#define PRIu64 __PRI64_PREFIX "u" +#define PRIu32 "u" +#else +#include +#endif + +void trcPrintableElem::getValStr(std::string &valStr, const int valTotalBitSize, const int valValidBits, const uint64_t value, const bool asHex /* = true*/, const int updateBits /* = 0*/) +{ + static char szStrBuffer[128]; + static char szFormatBuffer[32]; + + assert((valTotalBitSize >= 4) && (valTotalBitSize <= 64)); + + uint64_t LimitMask = ~0ULL; + LimitMask >>= 64-valTotalBitSize; + valStr = "0x"; + + if(asHex) + { + int numHexChars = valTotalBitSize / 4; + numHexChars += ((valTotalBitSize % 4) > 0) ? 1 : 0; + + int validChars = valValidBits / 4; + if((valValidBits % 4) > 0) validChars++; + int QM = numHexChars - validChars; + while(QM) + { + QM--; + valStr += "?"; + } + if(valValidBits > 32) + { + sprintf(szFormatBuffer,"%%0%dllX",validChars); // create the format + sprintf(szStrBuffer,szFormatBuffer,value); // fill the buffer + } + else + { + sprintf(szFormatBuffer,"%%0%dlX",validChars); // create the format + sprintf(szStrBuffer,szFormatBuffer,(uint32_t)value); // fill the buffer + } + valStr+=szStrBuffer; + if(valValidBits < valTotalBitSize) + { + sprintf(szStrBuffer," (%d:0)", valValidBits-1); + valStr+=szStrBuffer; + } + + if(updateBits) + { + uint64_t updateMask = ~0ULL; + updateMask >>= 64-updateBits; + sprintf(szStrBuffer," ~[0x%" PRIX64 "]",value & updateMask); + valStr+=szStrBuffer; + } + } + else + { + valStr = ""; + if(valValidBits < valTotalBitSize) + valStr += "??"; + if(valValidBits > 32) + { + sprintf(szStrBuffer,"%" PRIu64 ,value); + } + else + { + sprintf(szStrBuffer,"%" PRIu32 ,(uint32_t)value); + } + valStr += szStrBuffer; + if(valValidBits < valTotalBitSize) + { + sprintf(szStrBuffer," (%d:0)", valValidBits-1); + valStr+=szStrBuffer; + } + } +} + + +/* End of File trc_printable_elem.cpp */ diff --git a/contrib/opencsd/decoder/source/trc_ret_stack.cpp b/contrib/opencsd/decoder/source/trc_ret_stack.cpp new file mode 100644 index 000000000000..a56c6e6c1d60 --- /dev/null +++ b/contrib/opencsd/decoder/source/trc_ret_stack.cpp @@ -0,0 +1,149 @@ +/* +* \file trc_ret_stack.cpp +* \brief OpenCSD : trace decoder return stack feature. +* +* \copyright Copyright (c) 2017, 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. +*/ +#include "common/trc_ret_stack.h" + +#ifdef TRC_RET_STACK_DEBUG +#include +#include +#include "common/trc_component.h" + +#define LOG_POP(A,O,I) LogOp("Pop",A,O,I) +#define LOG_PUSH(A,O,I) LogOp("Push",A,O,I) +#define LOG_FLUSH() LogOp("Flush",0,-1000,(const ocsd_isa)0) + +// uncomment for forced std::cout log, bypassing normal library debug logger. +// useful perhaps when perf is decoding w/o printing. +// #define FORCE_STD_COUT + +#else +#define LOG_POP(A,O,I) +#define LOG_PUSH(A,O,I) +#define LOG_FLUSH() +#endif + +TrcAddrReturnStack::TrcAddrReturnStack() : + m_active(false), + m_pop_pending(false), + head_idx(0), + num_entries(0) +{ +#ifdef TRC_RET_STACK_DEBUG + m_p_debug_logger = 0; +#endif +} + +void TrcAddrReturnStack::push(const ocsd_vaddr_t addr, const ocsd_isa isa) +{ + if (is_active()) + { + head_idx++; + head_idx &= 0xF; + m_stack[head_idx].ret_addr = addr; + m_stack[head_idx].ret_isa = isa; + num_entries++; + if (num_entries > 16) + num_entries = 16; + LOG_PUSH(addr,0,isa); + m_pop_pending = false; + } +} + +ocsd_vaddr_t TrcAddrReturnStack::pop(ocsd_isa &isa) +{ + ocsd_vaddr_t addr = (ocsd_vaddr_t)-1; + if (is_active()) + { + if (num_entries > 0) + { + addr = m_stack[head_idx].ret_addr; + isa = m_stack[head_idx].ret_isa; + head_idx--; + head_idx &= 0xF; + } + num_entries--; + LOG_POP(addr,1,isa); + m_pop_pending = false; + } + return addr; +} + + +void TrcAddrReturnStack::flush() +{ + num_entries = 0; + m_pop_pending = false; + LOG_FLUSH(); +} + +#ifdef TRC_RET_STACK_DEBUG +void TrcAddrReturnStack::LogOp(const char * pszOpString, ocsd_vaddr_t addr, int head_off, ocsd_isa isa) +{ + static const char *isa_names[] = + { + "A32", /**< V7 ARM 32, V8 AArch32 */ + "T32", /**< Thumb2 -> 16/32 bit instructions */ + "A64", /**< V8 AArch64 */ + "TEE", /**< Thumb EE - unsupported */ + "JZL", /**< Jazelle - unsupported in trace */ + "custom", /**< Instruction set - custom arch decoder */ + "unknown" /**< ISA not yet known */ + }; + + if (m_p_debug_logger) + { + std::ostringstream oss; + if(head_off == -1000) + { + oss << "Return stack " << pszOpString << "\n"; + } + else + { + int name_idx = (int)isa; + if (name_idx > 6) + name_idx = 6; + oss << "Return stack " << pszOpString << "[" << std::dec << (head_idx+head_off) << "](0x" << std::hex << addr << "), " << isa_names[name_idx] << ";"; + oss << "current entries = " << std::dec << num_entries << ";"; + oss << "new head idx = " << head_idx << ";"; + oss << "pop pend (pre op) = " << (m_pop_pending ? "true\n" : "false\n"); + } +#ifdef FORCE_STD_COUT + std::cout << oss.str(); + std::cout.flush(); +#endif + m_p_debug_logger->LogDefMessage(oss.str()); + } +} +#endif + +/* End of File trc_ret_stack.cpp */