diff --git a/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr.h b/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr.h index 3342eacb24ca..34c4ef1dc1c4 100644 --- a/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr.h +++ b/contrib/opencsd/decoder/include/common/ocsd_dcd_mngr.h @@ -1,402 +1,445 @@ /* * \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. + const ocsd_trace_protocol_t m_builtInProtocol; //!< Protocol ID if built in type. }; template -DecoderMngrBase::DecoderMngrBase(const std::string &decoderTypeName, ocsd_trace_protocol_t builtInProtocol) + DecoderMngrBase::DecoderMngrBase(const std::string &decoderTypeName, ocsd_trace_protocol_t builtInProtocol) : + m_builtInProtocol(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 op mode flags pkt_proc->setComponentOpMode(create_flags & (OCSD_OPFLG_COMP_MODE_MASK | OCSD_OPFLG_PKTPROC_COMMON)); // 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; // set the op mode flags pkt_dcd->setComponentOpMode(create_flags & (OCSD_OPFLG_COMP_MODE_MASK | OCSD_OPFLG_PKTDEC_COMMON)); // 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); } }; +/* full decode - extended config object - base + derived. */ +template< class P, // Packet class. + class Pt, // Packet enum type ID. + class Pc, // Processor config base class. + class PcEx, // Processor config derived class + class PcSt, // Processor config struct type + class PktProc, // Packet processor class. + class PktDcd> // Packet decoder class. + class DecodeMngrFullDcdExCfg : public DecoderMngrBase +{ +public: + DecodeMngrFullDcdExCfg(const std::string &name, ocsd_trace_protocol_t builtInProtocol) + : DecoderMngrBase(name, builtInProtocol) {}; + + virtual ~DecodeMngrFullDcdExCfg() {}; + + 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) PcEx((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_tree.h b/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h index e4e74f2bc659..b1c3dc601cab 100644 --- a/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h +++ b/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h @@ -1,426 +1,453 @@ /*! * \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 the stats block for the channel indicated. + * Caller must check p_stats_block->version to esure that the block + * is filled in a compatible manner. + * + * @param CSID : Configured CoreSight trace ID for the decoder. + * @param p_stats_block: block pointer to set to reference the stats block. + * + * @return ocsd_err_t : Library error code - OCSD_OK if valid block pointer returned, + * OCSD_ERR_NOTINIT if decoder does not support stats counting. + */ + ocsd_err_t getDecoderStats(const uint8_t CSID, ocsd_decode_stats_t **p_stats_block); + + /*! + * Reset the stats block for the chosens decode channel. + * stats block is reset independently of the decoder reset to allow counts across + * multiple decode runs. + * + * @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_err_t resetDecoderStats(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); /*! * Updates/adds to 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 updateBinFileRegionMemAcc(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); ocsd_err_t addCallbackIDMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAccID_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_err_t initCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, void *p_cb_func, bool IDfn, const void *p_context); - + TrcPktProcI *getPktProcI(const uint8_t CSID); 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; + + /**! demux stats block */ + ocsd_demux_stats_t m_demux_stats; }; /** @}*/ #endif // ARM_OCSD_DCD_TREE_H_INCLUDED /* End of File ocsd_dcd_tree.h */ diff --git a/contrib/opencsd/decoder/include/common/ocsd_error.h b/contrib/opencsd/decoder/include/common/ocsd_error.h index e547f4878033..7c6ed3af141f 100644 --- a/contrib/opencsd/decoder/include/common/ocsd_error.h +++ b/contrib/opencsd/decoder/include/common/ocsd_error.h @@ -1,116 +1,127 @@ /*! * \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); } +/* class to get data path response values as strings */ +class ocsdDataRespStr +{ +public: + ocsdDataRespStr(ocsd_datapath_resp_t type) { m_type = type; } + ~ocsdDataRespStr() {}; + + const char* getStr(); +private: + ocsd_datapath_resp_t m_type; +}; /** @}*/ #endif // ARM_OCSD_ERROR_H_INCLUDED /* End of File ocsd_error.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 index b72b4b411fa4..aa976c39f908 100644 --- a/contrib/opencsd/decoder/include/common/trc_core_arch_map.h +++ b/contrib/opencsd/decoder/include/common/trc_core_arch_map.h @@ -1,100 +1,77 @@ /*! * \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 * * @brief Map core / arch name to profile for decoder. * * Helper class for library clients to map core or architecture version names onto * a profile / arch version pair suitable for use with the decode library. * * Valid core names are:- * - Cortex-Axx : where xx = 5,7,12,15,17,32,35,53,55,57,65,72,73,75,76,77; * - Cortex-Rxx : where xx = 5,7,8,52; * - Cortex-Mxx : where xx = 0,0+,3,4,23,33; * * Valid architecture profile names are:- * - ARMv7-A, ARMv7-R, ARMv7-M; - * - ARMv8-A, ARMv8.3A, ARMv8-R, ARMv8-M; + * - ARMv8-A, ARMv8.x-A, ARMv8-R, ARMv8-M; + * - ARM-AA64, ARM-aa64 * */ class CoreArchProfileMap { public: CoreArchProfileMap(); ~CoreArchProfileMap() {}; ocsd_arch_profile_t getArchProfile(const std::string &coreName); private: + ocsd_arch_profile_t getPatternMatchCoreName(const std::string &coreName); std::map core_profiles; std::map arch_profiles; }; -inline ocsd_arch_profile_t CoreArchProfileMap::getArchProfile(const std::string &coreName) -{ - ocsd_arch_profile_t ap = { ARCH_UNKNOWN, profile_Unknown }; - bool bFound = false; - - std::map::const_iterator it; - - /* match against the core name map. */ - it = core_profiles.find(coreName); - if (it != core_profiles.end()) - { - ap = it->second; - bFound = true; - } - - /* scan architecture profiles on no core name match */ - if (!bFound) - { - it = arch_profiles.find(coreName); - if (it != arch_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_frame_deformatter.h b/contrib/opencsd/decoder/include/common/trc_frame_deformatter.h index e4297a41e8fd..cb2960fcdd07 100644 --- a/contrib/opencsd/decoder/include/common/trc_frame_deformatter.h +++ b/contrib/opencsd/decoder/include/common/trc_frame_deformatter.h @@ -1,97 +1,104 @@ /*! * \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(); + /* init decoder implementation object */ + ocsd_err_t Init(); + /* 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 */ + /* demux stats */ + void SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock); + 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 index 5d8983a8c274..405abfef8341 100644 --- a/contrib/opencsd/decoder/include/common/trc_gen_elem.h +++ b/contrib/opencsd/decoder/include/common/trc_gen_elem.h @@ -1,222 +1,230 @@ /*! * \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 setUnSyncEOTReason(const unsync_info_t reason); + void setTransactionType(const trace_memtrans_t trans) { mem_trans = trans; }; void setAddrRange(const ocsd_vaddr_t st_addr, const ocsd_vaddr_t en_addr, const int num_instr = 1); void setLastInstrInfo(const bool exec, const ocsd_instr_type last_i_type, const ocsd_instr_subtype last_i_subtype, const uint8_t size); - void setAddrStart(const ocsd_vaddr_t st_addr) { this->st_addr = st_addr; }; + void setAddrStart(const ocsd_vaddr_t st_addr) { this->st_addr = st_addr; }; void setLastInstrCond(const int is_cond) { this->last_instr_cond = is_cond; }; void setSWTInfo(const ocsd_swt_info_t swt_info) { sw_trace_info = swt_info; }; void setExtendedDataPtr(const void *data_ptr); + void setITEInfo(const trace_sw_ite_t sw_instrumentation) { sw_ite = sw_instrumentation; }; + + void setSyncMarker(const trace_marker_payload_t &marker); + // 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; }; void copyPersistentData(const OcsdTraceElement &src); 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, const int num_instr /* = 1 */) { this->st_addr = st_addr; this->en_addr = en_addr; this->num_instr_range = num_instr; } inline void OcsdTraceElement::setLastInstrInfo(const bool exec, const ocsd_instr_type last_i_type, const ocsd_instr_subtype last_i_subtype, const uint8_t size) { last_instr_exec = exec ? 1 : 0; last_instr_sz = size & 0x7; 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; // bit-field with various flags. exception_number = 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::setUnSyncEOTReason(const unsync_info_t reason) { unsync_eot_info = 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; } +inline void OcsdTraceElement::setSyncMarker(const trace_marker_payload_t &marker) +{ + sync_marker = marker; +} + // set persistent data between output packets. inline void OcsdTraceElement::copyPersistentData(const OcsdTraceElement &src) { isa = src.isa; context = src.context; } /** @}*/ #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 index da702068f372..24ea2b05a6f9 100644 --- a/contrib/opencsd/decoder/include/common/trc_pkt_decode_base.h +++ b/contrib/opencsd/decoder/include/common/trc_pkt_decode_base.h @@ -1,308 +1,317 @@ /*! * \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; /* init handling */ const bool checkInit(); /* Called on first init confirmation */ virtual void onFirstInitOK() {}; /* 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); + ocsd_err_t invalidateMemAccCache(); /* 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; if (m_decode_init_ok) onFirstInitOK(); } 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; } +inline ocsd_err_t TrcPktDecodeI::invalidateMemAccCache() +{ + if (!m_uses_memaccess) + return OCSD_ERR_DCD_INTERFACE_UNUSED; + m_mem_access.first()->InvalidateMemAccCache(getCoreSightTraceID()); + return OCSD_OK; +} + /**********************************************************************/ 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_proc_base.h b/contrib/opencsd/decoder/include/common/trc_pkt_proc_base.h index 3098a3d0c0ea..8ed7d83b2d5a 100644 --- a/contrib/opencsd/decoder/include/common/trc_pkt_proc_base.h +++ b/contrib/opencsd/decoder/include/common/trc_pkt_proc_base.h @@ -1,412 +1,456 @@ /*! * \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" +#include "opencsd/ocsd_if_version.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; + virtual ocsd_err_t getStatsBlock(ocsd_decode_stats_t **pp_stats) = 0; + virtual void resetStats() = 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; }; +/* stats block access - derived class must init stats for the block to be returned. */ + virtual ocsd_err_t getStatsBlock(ocsd_decode_stats_t **pp_stats); + virtual void resetStats(); /* reset the counts - operates separately from decoder reset. */ + 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. + /* stats block updates - called by derived protocol specific decoder */ + void statsAddTotalCount(const uint64_t count) { m_stats.channel_total += count; }; + void statsAddUnsyncCount(const uint64_t count) { m_stats.channel_unsynced += count; }; + void statsAddBadSeqCount(const uint32_t count) { m_stats.bad_sequence_errs += count; }; + void statsAddBadHdrCount(const uint32_t count) { m_stats.bad_header_errs += count; }; + void statsInit() { m_stats_init = true; }; /* mark stats as in use */ + + 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; + + /* decode statistics block */ + ocsd_decode_stats_t m_stats; + bool m_stats_init; /*< true if the specific decoder is using the stats */ + }; template TrcPktProcBase::TrcPktProcBase(const char *component_name) : TrcPktProcI(component_name), m_config(0), - m_b_is_init(false) + m_b_is_init(false), + m_stats_init(false) { + resetStats(); } template TrcPktProcBase::TrcPktProcBase(const char *component_name, int instIDNum) : TrcPktProcI(component_name, instIDNum), m_config(0), - m_b_is_init(false) + m_b_is_init(false), + m_stats_init(false) { + resetStats(); } 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; } +template ocsd_err_t TrcPktProcBase::getStatsBlock(ocsd_decode_stats_t **pp_stats) +{ + + *pp_stats = &m_stats; + return m_stats_init ? OCSD_OK : OCSD_ERR_NOT_INIT; +} + +template void TrcPktProcBase::resetStats() +{ + m_stats.version = OCSD_VER_NUM; + m_stats.revision = OCSD_STATS_REVISION; + m_stats.channel_total = 0; + m_stats.channel_unsynced = 0; + m_stats.bad_header_errs = 0; + m_stats.bad_sequence_errs = 0; + m_stats.demux.frame_bytes = 0; + m_stats.demux.no_id_bytes = 0; + m_stats.demux.valid_id_bytes = 0; +} + /** @}*/ #endif // ARM_TRC_PKT_PROC_BASE_H_INCLUDED /* End of File trc_pkt_proc_base.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 index 911b0cf7db95..e90ec04ae84d 100644 --- a/contrib/opencsd/decoder/include/i_dec/trc_idec_arminst.h +++ b/contrib/opencsd/decoder/include/i_dec/trc_idec_arminst.h @@ -1,139 +1,140 @@ /* * \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 /* supplementary decode information */ struct decode_info { - uint16_t arch_version; + ocsd_arch_version_t arch_version; ocsd_instr_subtype instr_sub_type; }; /* 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, struct decode_info *info); int inst_Thumb_is_branch(uint32_t inst, struct decode_info *info); int inst_A64_is_branch(uint32_t inst, struct decode_info *info); /* 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, struct decode_info *info); int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond, struct decode_info *info); int inst_A64_is_direct_branch(uint32_t inst, struct decode_info *info); int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info); /* 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, struct decode_info *info); int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info); int inst_Thumb_is_indirect_branch(uint32_t inst, struct decode_info *info); int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info); int inst_A64_is_indirect_branch(uint32_t inst, struct decode_info *info); int inst_ARM_is_branch_and_link(uint32_t inst, struct decode_info *info); int inst_Thumb_is_branch_and_link(uint32_t inst, struct decode_info *info); int inst_A64_is_branch_and_link(uint32_t inst, struct decode_info *info); 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); int inst_ARM_wfiwfe(uint32_t inst); int inst_Thumb_wfiwfe(uint32_t inst); -int inst_A64_wfiwfe(uint32_t inst); +int inst_A64_wfiwfe(uint32_t inst, struct decode_info *info); +int inst_A64_Tstart(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); #endif // ARM_TRC_IDEC_ARMINST_H_INCLUDED /* End of File trc_idec_arminst.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 index 6f7b21383024..dfa7e057ca67 100644 --- a/contrib/opencsd/decoder/include/interfaces/trc_pkt_raw_in_i.h +++ b/contrib/opencsd/decoder/include/interfaces/trc_pkt_raw_in_i.h @@ -1,83 +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 + * type, plus the raw packet bytes. Use for tools which need to display complete * 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 index effc9b5e161e..68a4e10055d4 100644 --- a/contrib/opencsd/decoder/include/interfaces/trc_tgt_mem_access_i.h +++ b/contrib/opencsd/decoder/include/interfaces/trc_tgt_mem_access_i.h @@ -1,91 +1,99 @@ /* * \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; + + /*! + * Invalidate any caching that the memory accessor functions are using. + * Generally called when a memory context changes in the trace. + * + * @param cs_trace_id : protocol source trace ID. + */ + virtual void InvalidateMemAccCache(const uint8_t cs_trace_id) = 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_mapper.h b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h index a700e9dbd07e..4a08498df14e 100644 --- a/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h +++ b/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h @@ -1,131 +1,133 @@ /* * \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" #include "mem_acc/trc_mem_acc_cache.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); + virtual void InvalidateMemAccCache(const uint8_t cs_trace_id); + // 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); // 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); void LogWarn(const ocsd_err_t err, 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. TrcMemAccCache m_cache; // memory accessor caching. }; // 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/opencsd.h b/contrib/opencsd/decoder/include/opencsd.h index 615bbcafa2d9..8af4fd0df5ef 100644 --- a/contrib/opencsd/decoder/include/opencsd.h +++ b/contrib/opencsd/decoder/include/opencsd.h @@ -1,84 +1,85 @@ /*! * \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" +#include "opencsd/ete/ete_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_types.h b/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_types.h index cde351fc525f..7f9b4bab9494 100644 --- 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 @@ -1,106 +1,107 @@ /*! * \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/ocsd_if_version.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" +#include "opencsd/ete/trc_pkt_types_ete.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 index 90201d436e08..ebbba87d952e 100644 --- a/contrib/opencsd/decoder/include/opencsd/c_api/opencsd_c_api.h +++ b/contrib/opencsd/decoder/include/opencsd/c_api/opencsd_c_api.h @@ -1,502 +1,550 @@ /*! * \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 version, 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); +/*! + * Get the stats block for the channel indicated. + * Caller must check p_stats_block->version to esure that the block + * is filled in a compatible manner. + * + * @param handle : Handle to decode tree. + * @param CSID : Configured CoreSight trace ID for the decoder. + * @param p_stats_block: block pointer to set to reference the stats block. + * + * @return ocsd_err_t : Library error code - OCSD_OK if valid block pointer returned, + * OCSD_ERR_NOTINIT if decoder does not support stats counting. + */ +OCSD_C_API ocsd_err_t ocsd_dt_get_decode_stats( const dcd_tree_handle_t handle, + const unsigned char CSID, + ocsd_decode_stats_t **p_stats_block); + +/*! + * Reset the stats block for the chosens decode channel. + * stats block is reset independently of the decoder reset to allow counts across + * multiple decode runs. + * + * @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_reset_decode_stats( const dcd_tree_handle_t handle, + const unsigned char CSID); - - /** @}*/ /*---------------------- 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); /*! * 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 - Signature for CB with Trace ID passed to client. * @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_trcid_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_MemAccID_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); +/*! + * Convert an error code into a string. + * + * @param err : error code. + * @param buffer : buffer for return string + * @param buffer_size : length of buffer. + */ +OCSD_C_API void ocsd_err_str(const ocsd_err_t err, char *buffer, const int buffer_size); + +/*! + * returns the last error logged by the system, with the related trace byte index, trace channel id, + * and any error message related string. + * If index or channel ID are not valid these will return OCSD_BAD_TRC_INDEX and OCSD_BAD_CS_SRC_ID. + * + * return value is the error code of the last logged error, OCSD_OK for no error available. + * + * @param index : returns trace byte index relating to error, or OCSD_BAD_TRC_INDEX + * @param chan_id : returns trace channel ID relating to error, or OCSD_BAD_CS_SRC_ID + * @param message : buffer to copy the last error message. + * @param message_len: length of message buffer. + */ +OCSD_C_API ocsd_err_t ocsd_get_last_err(ocsd_trc_index_t *index, uint8_t *chan_id, char *message, const int message_len); /** @}*/ /** @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/ete/ete_decoder.h b/contrib/opencsd/decoder/include/opencsd/ete/ete_decoder.h new file mode 100644 index 000000000000..ba0d718bfff1 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ete/ete_decoder.h @@ -0,0 +1,47 @@ +/* +* \file ete_decoder.h +* \brief OpenCSD : Top level header file for ETE decoder. +* +* \copyright Copyright (c) 2019, 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_ETE_DECODER_H_INCLUDED +#define ARM_ETE_DECODER_H_INCLUDED + +// ETE actually uses extended ETMv4 packet processor and decode +// ETE specifics limited to configuration +// +#include "trc_cmp_cfg_ete.h" +#include "trc_pkt_types_ete.h" + +#endif // ARM_ETE_DECODER_H_INCLUDED + +/* End of File ete_decoder.h */ + diff --git a/contrib/opencsd/decoder/include/opencsd/ete/trc_cmp_cfg_ete.h b/contrib/opencsd/decoder/include/opencsd/ete/trc_cmp_cfg_ete.h new file mode 100644 index 000000000000..8365ffa88460 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ete/trc_cmp_cfg_ete.h @@ -0,0 +1,81 @@ +/* +* \file trc_cmp_cfg_ete.h +* \brief OpenCSD : ETE configuration +* +* \copyright Copyright (c) 2019, 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_ETE_H_INCLUDED +#define ARM_TRC_CMP_CFG_ETE_H_INCLUDED + +#include "trc_pkt_types_ete.h" +#include "opencsd/etmv4/trc_cmp_cfg_etmv4.h" + +/** @addtogroup ocsd_protocol_cfg +@{*/ + +/** @name ETE configuration +@{*/ + +/*! + * @class ETEConfig + * @brief Interpreter class for ETE config structure + * + * ETE trace and config are a superset of ETMv4 trace and config - hence + * use the EtmV4Config class as a base. + */ +class ETEConfig : public EtmV4Config +{ +public: + ETEConfig(); + ETEConfig(const ocsd_ete_cfg *cfg_regs); + ~ETEConfig(); + + //! copy assignment operator for base structure into class. + ETEConfig & operator=(const ocsd_ete_cfg *p_cfg); + + //! cast operator returning struct const reference + operator const ocsd_ete_cfg &() const { return m_ete_cfg; }; + //! cast operator returning struct const pointer + operator const ocsd_ete_cfg *() const { return &m_ete_cfg; }; + +private: + void copyV4(); // copy relevent config to underlying structure. + + ocsd_ete_cfg m_ete_cfg; +}; + + +/** @}*/ +/** @}*/ + +#endif // ARM_TRC_CMP_CFG_ETE_H_INCLUDED + +/* End of File trc_cmp_cfg_ete.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ete/trc_dcd_mngr_ete.h b/contrib/opencsd/decoder/include/opencsd/ete/trc_dcd_mngr_ete.h new file mode 100644 index 000000000000..7b0c134b20c5 --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ete/trc_dcd_mngr_ete.h @@ -0,0 +1,58 @@ +/* +* \file trc_dcd_mngr_ete.h +* \brief OpenCSD : ETE decoder creation. +* +* \copyright Copyright (c) 2019, 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_ETE_H_INCLUDED +#define ARM_TRC_DCD_MNGR_ETE_H_INCLUDED + +#include "common/ocsd_dcd_mngr.h" +#include "trc_cmp_cfg_ete.h" +#include "opencsd/etmv4/trc_pkt_decode_etmv4i.h" +#include "opencsd/etmv4/trc_pkt_proc_etmv4.h" + +class DecoderMngrETE : public DecodeMngrFullDcdExCfg< EtmV4ITrcPacket, + ocsd_etmv4_i_pkt_type, + EtmV4Config, + ETEConfig, + ocsd_ete_cfg, + TrcPktProcEtmV4I, + TrcPktDecodeEtmV4I> +{ +public: + DecoderMngrETE(const std::string &name) : DecodeMngrFullDcdExCfg(name, OCSD_PROTOCOL_ETE) {}; + virtual ~DecoderMngrETE() {}; +}; + +#endif // ARM_TRC_DCD_MNGR_ETE_H_INCLUDED + +/* End of File trc_dcd_mngr_ete.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ete/trc_pkt_types_ete.h b/contrib/opencsd/decoder/include/opencsd/ete/trc_pkt_types_ete.h new file mode 100644 index 000000000000..f87d454605fd --- /dev/null +++ b/contrib/opencsd/decoder/include/opencsd/ete/trc_pkt_types_ete.h @@ -0,0 +1,66 @@ +/* + * \file trc_pkt_types_ete.h + * \brief OpenCSD : ETE types + * + * \copyright Copyright (c) 2019, 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_ETE_H_INCLUDED +#define ARM_TRC_PKT_TYPES_ETE_H_INCLUDED + +#include "opencsd/trc_pkt_types.h" +#include "opencsd/etmv4/trc_pkt_types_etmv4.h" + /** @addtogroup trc_pkts + @{*/ + + /** @name ETE config Types + @{*/ + + +typedef struct _ocsd_ete_cfg +{ + uint32_t reg_idr0; /**< ID0 register */ + uint32_t reg_idr1; /**< ID1 register */ + uint32_t reg_idr2; /**< ID2 register */ + uint32_t reg_idr8; /**< ID8 - maxspec */ + uint32_t reg_devarch; /**< DevArch register */ + 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_ete_cfg; + + +/** @}*/ +/** @}*/ + +#endif // ARM_TRC_PKT_TYPES_ETE_H_INCLUDED + +/* End of File trc_pkt_types_ete.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 index 1d72d97afe59..223dbda44510 100644 --- a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h @@ -1,465 +1,492 @@ /* * \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; + const bool eteHasTSMarker() 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; + const bool commTransP0() const; /* idr 1 */ const uint8_t MajVersion() const; const uint8_t MinVersion() const; const uint8_t FullVersion() 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; const bool wfiwfeBranch() 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; + const bool enabledVMIDOpt() 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; protected: ocsd_etmv4_cfg m_cfg; uint8_t m_MajVer; uint8_t m_MinVer; }; /* 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 bool EtmV4Config::eteHasTSMarker() const +{ + return (FullVersion() >= 0x51) && ((m_cfg.reg_idr0 & 0x800000) == 0x800000); +} + 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(); } +inline const bool EtmV4Config::commTransP0() const +{ + return (bool)((m_cfg.reg_idr0 & 0x40000000) == 0x0); +} + /* idr 1 */ inline const uint8_t EtmV4Config::MajVersion() const { return m_MajVer; } inline const uint8_t EtmV4Config::MinVersion() const { return m_MinVer; } inline const uint8_t EtmV4Config::FullVersion() const { return (m_MajVer << 4) | m_MinVer; } /* 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); } inline const bool EtmV4Config::wfiwfeBranch() const { return (bool)((m_cfg.reg_idr2 & 0x80000000) && (FullVersion() >= 0x43)); } /* 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 bool EtmV4Config::enabledVMIDOpt() const +{ + bool vmidOptVal = ((m_cfg.reg_configr & (0x1 << 15)) != 0); + /* TRIDR2.VMIDOPT[30:29] determine value used */ + if (!vmidOpt()) { /* [29] = 1'b0 */ + vmidOptVal = false; /* res0 */ + if (FullVersion() >= 0x45) { + /* umless version > 4.5 in which case [30] determines res val */ + vmidOptVal = ((m_cfg.reg_idr2 & (0x1 << 30)) != 0); + } + } + return vmidOptVal; +} + 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_etmv4_stack_elem.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h index 5a283c541f3e..21bd7af434de 100644 --- a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h @@ -1,433 +1,503 @@ /* * \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 "opencsd/trc_gen_elem_types.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_MARKER, P0_Q, P0_OVERFLOW, P0_FUNC_RET, + P0_SRC_ADDR, + P0_TRANS_TRACE_INIT, + P0_TRANS_START, + P0_TRANS_COMMIT, + P0_TRANS_FAIL, + P0_ITE, } 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); + TrcStackElemAddr(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const bool src_addr); 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; } +inline TrcStackElemAddr::TrcStackElemAddr(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const bool src_addr) : + TrcStackElem(src_addr ? P0_SRC_ADDR : P0_ADDR, false, root_pkt, root_index) +{ + m_addr_val.val = 0; + m_addr_val.isa = 0; +} + + /************************************************************/ /** Q element */ class TrcStackQElem : public TrcStackElem { protected: TrcStackQElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); virtual ~TrcStackQElem() {}; friend class EtmV4P0Stack; public: void setInstrCount(const int instr_count) { m_instr_count = instr_count; }; const int getInstrCount() const { return m_instr_count; } void setAddr(const etmv4_addr_val_t &addr_val) { m_addr_val = addr_val; m_has_addr = true; }; const etmv4_addr_val_t &getAddr() const { return m_addr_val; }; const bool hasAddr() const { return m_has_addr; }; private: bool m_has_addr; etmv4_addr_val_t m_addr_val; int m_instr_count; }; inline TrcStackQElem::TrcStackQElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : TrcStackElem(P0_Q , true, root_pkt, root_index) { m_addr_val.val = 0; m_addr_val.isa = 0; m_has_addr = false; m_instr_count = 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; }; void setIS(const uint8_t IS) { m_IS = IS; }; const uint8_t getIS() const { return m_IS; }; private: etmv4_context_t m_context; uint8_t m_IS; //!< IS value at time of generation of packet. }; 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); void mispredictNewest(); 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; } // mispredict newest - flip the bit of the newest atom inline void TrcStackElemAtom::mispredictNewest() { uint32_t mask = 0x1 << (m_atom.num - 1); if (m_atom.En_bits & mask) m_atom.En_bits &= ~mask; else m_atom.En_bits |= mask; } /************************************************************/ /** 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) { } +/************************************************************/ +/** Marker element */ + +class TrcStackElemMarker : public TrcStackElem +{ +protected: + TrcStackElemMarker(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + virtual ~TrcStackElemMarker() {}; + + friend class EtmV4P0Stack; + +public: + void setMarker(const trace_marker_payload_t &marker) { m_marker = marker; }; + const trace_marker_payload_t &getMarker() const { return m_marker; }; + +private: + trace_marker_payload_t m_marker; +}; + +inline TrcStackElemMarker::TrcStackElemMarker(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : + TrcStackElem(P0_MARKER, false, root_pkt, root_index) +{ +} + +/************************************************************/ +/* Instrumentation element + */ + +class TrcStackElemITE : public TrcStackElem +{ +protected: + TrcStackElemITE(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + virtual ~TrcStackElemITE() {}; + + friend class EtmV4P0Stack; + +public: + void setITE(const trace_sw_ite_t &ite) { m_ite = ite; }; + const trace_sw_ite_t &getITE() { return m_ite; }; + +private: + trace_sw_ite_t m_ite; +}; + +inline TrcStackElemITE::TrcStackElemITE(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : + TrcStackElem(P0_ITE, false, 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 push_back(TrcStackElem *pElem); // insert element when processing void pop_back(bool pend_delete = true); void pop_front(bool pend_delete = true); TrcStackElem *back(); TrcStackElem *front(); size_t size(); // iterate through stack from front void from_front_init(); TrcStackElem *from_front_next(); void erase_curr_from_front(); // erase the element last returned void delete_all(); void delete_back(); void delete_front(); 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); TrcStackElem *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, bool back = false); 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, const uint8_t IS, const bool back = false); TrcStackElemAddr *createAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val); TrcStackQElem *createQElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const int count); + TrcStackElemMarker *createMarkerElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const trace_marker_payload_t &marker); + TrcStackElemAddr *createSrcAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val); + TrcStackElemITE *createITEElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const trace_sw_ite_t &ite); + private: std::deque m_P0_stack; //!< P0 decode element stack std::vector m_popped_elem; //!< save list of popped but not deleted elements. std::deque::iterator m_iter; //!< iterate across the list w/o removing stuff }; 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); } // put an element on the back of the stack inline void EtmV4P0Stack::push_back(TrcStackElem *pElem) { m_P0_stack.push_back(pElem); } // pop last element pointer off the stack and stash it for later deletion inline void EtmV4P0Stack::pop_back(bool pend_delete /* = true */) { if (pend_delete) m_popped_elem.push_back(m_P0_stack.back()); m_P0_stack.pop_back(); } inline void EtmV4P0Stack::pop_front(bool pend_delete /* = true */) { if (pend_delete) m_popped_elem.push_back(m_P0_stack.front()); m_P0_stack.pop_front(); } // 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(); } } // pop first element pointer off the stack and delete immediately inline void EtmV4P0Stack::delete_front() { if (m_P0_stack.size() > 0) { TrcStackElem* pElem = m_P0_stack.front(); delete pElem; m_P0_stack.pop_front(); } } // get a pointer to the last element on the stack inline TrcStackElem *EtmV4P0Stack::back() { return m_P0_stack.back(); } inline TrcStackElem *EtmV4P0Stack::front() { return m_P0_stack.front(); } // 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 index 419cd828928c..7838ece04e57 100644 --- a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h @@ -1,227 +1,253 @@ /* * \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 "common/ocsd_gen_elem_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) virtual void onFirstInitOK(); // override to set init related info. ocsd_err_t decodePacket(); // decode packet into trace elements. return true to indicate decode complete - can change FSM to commit state - return is false. ocsd_datapath_resp_t resolveElements(); // commit/cancel trace elements generated from latest / prior packets & send to output - may get wait response, or flag completion. ocsd_err_t commitElements(); // commit elements - process element stack to generate output packets. ocsd_err_t commitElemOnEOT(); ocsd_err_t cancelElements(); // cancel elements. These not output ocsd_err_t mispredictAtom(); // mispredict an atom ocsd_err_t discardElements(); // discard elements and flush void doTraceInfoPacket(); void updateContext(TrcStackElemCtxt *pCtxtElem, OcsdTraceElement &elem); // process atom will create instruction trace, or no memory access trace output elements. ocsd_err_t processAtom(const ocsd_atm_val atom); // process an exception element - output instruction trace + exception generic type. ocsd_err_t processException(); // process Q element ocsd_err_t processQElement(); + // process a source address element + ocsd_err_t processSourceAddress(); + // process an element that cannot be cancelled / discarded ocsd_err_t processTS_CC_EventElem(TrcStackElem *pElem); + // process marker elements + ocsd_err_t processMarkerElem(TrcStackElem *pElem); + + // process a transaction element + ocsd_err_t processTransElem(TrcStackElem *pElem); + + // process an Instrumentation element + ocsd_err_t processITEElem(TrcStackElem *pElem); + // process a bad packet - ocsd_err_t handleBadPacket(const char *reason); + ocsd_err_t handleBadPacket(const char *reason, ocsd_trc_index_t index = OCSD_BAD_TRC_INDEX); + + // sequencing error on packet processing - optionally continue + ocsd_err_t handlePacketSeqErr(ocsd_err_t err, ocsd_trc_index_t index, const char *reason); + + // common packet error routine + ocsd_err_t handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason); ocsd_err_t addElemCC(TrcStackElemParam *pParamElem); ocsd_err_t addElemTS(TrcStackElemParam *pParamElem, bool withCC); ocsd_err_t addElemEvent(TrcStackElemParam *pParamElem); private: void SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa); const ocsd_isa calcISA(const bool SF, const uint8_t IS) const { if (SF) return ocsd_isa_aarch64; return (IS == 0) ? ocsd_isa_arm : ocsd_isa_thumb2; } typedef enum { WP_NOT_FOUND, WP_FOUND, WP_NACC } WP_res_t; typedef struct { ocsd_vaddr_t st_addr; ocsd_vaddr_t en_addr; uint32_t num_instr; } instr_range_t; //!< follow instructions from the current address to a WP. true if good, false if memory cannot be accessed. ocsd_err_t traceInstrToWP(instr_range_t &instr_range, WP_res_t &WPRes, const bool traceToAddrNext = false, const ocsd_vaddr_t nextAddrMatch = 0); inline const bool WPFound(WP_res_t res) const { return (res == WP_FOUND); }; inline const bool WPNacc(WP_res_t res) const { return (res == WP_NACC); }; ocsd_err_t returnStackPop(); // pop return stack and update instruction address. void setElemTraceRange(OcsdTraceElement &elemIn, const instr_range_t &addr_range, const bool executed, ocsd_trc_index_t index); + void setElemTraceRangeInstr(OcsdTraceElement &elemIn, const instr_range_t &addr_range, + const bool executed, ocsd_trc_index_t index, ocsd_instr_info &instr); + + // true if we are ETE configured. + inline bool isETEConfig() { + return (m_config->MajVersion() >= ETE_ARCH_VERSION); + } ocsd_mem_space_acc_t getCurrMemSpace(); //** intra packet state (see ETMv4 spec 6.2.1); // timestamping uint64_t m_timestamp; // last broadcast global Timestamp. + bool m_ete_first_ts_marker; // 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 uint8_t m_last_IS; // last instruction set value from address packet. // cycle counts int m_cc_threshold; // speculative trace int m_curr_spec_depth; int m_max_spec_depth; // nax depth - from ID reg, beyond which auto-commit occurs int m_unseen_spec_elem; // speculative elements at decode start /** Remove elements that are associated with data trace */ #ifdef DATA_TRACE_SUPPORTED // 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; #endif 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 RESOLVE_ELEM, //!< analyze / resolve decode elements - create generic trace elements and pass on. } processor_state_t; processor_state_t m_curr_state; unsync_info_t m_unsync_eot_info; //!< addition info when / why unsync / eot //** P0 element stack EtmV4P0Stack m_P0_stack; //!< P0 decode element stack // element resolution struct { int P0_commit; //!< number of elements to commit int P0_cancel; //!< elements to cancel bool mispredict; //!< mispredict latest atom bool discard; //!< discard elements } m_elem_res; //! true if any of the element resolution fields are non-zero const bool isElemForRes() const { return (m_elem_res.P0_commit || m_elem_res.P0_cancel || m_elem_res.mispredict || m_elem_res.discard); } void clearElemRes() { m_elem_res.P0_commit = 0; m_elem_res.P0_cancel = 0; m_elem_res.mispredict = false; m_elem_res.discard = false; } // packet decode state bool m_need_ctxt; //!< need context to continue bool m_need_addr; //!< need an address to continue bool m_elem_pending_addr; //!< next address packet is needed for prev element. ocsd_instr_info m_instr_info; //!< instruction info for code follower - in address is the next to be decoded. etmv4_trace_info_t m_trace_info; //!< trace info for this trace run. bool m_prev_overflow; TrcAddrReturnStack m_return_stack; //!< the address return stack. //** output element handling OcsdGenElemStack m_out_elem; //!< output element stack. OcsdTraceElement &outElem() { return m_out_elem.getCurrElem(); }; //!< current out element }; #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_etmv4i.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h index 8ccf36b373db..02404749718d 100644 --- a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h @@ -1,541 +1,557 @@ /* * \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() { reset_stack(); } ~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]; } } // explicit reset for TInfo. void reset_stack() { for (int i = 0; i < 3; i++) { m_v_addr[i].pkt_bits = 0; m_v_addr[i].size = OCSD_MAX_VA_BITSIZE == 64 ? VA_64BIT : VA_32BIT; m_v_addr[i].val = 0; m_v_addr[i].valid_bits = OCSD_MAX_VA_BITSIZE; m_v_addr_ISA[i] = 0; } } 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, const uint8_t val = 0); 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 setContextInfo(const bool update, const uint8_t EL = 0, const uint8_t NS = 0, const uint8_t SF = 0, const uint8_t NSE = 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); + void setITE(const uint8_t el, const uint64_t value); // 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; }; const int getNumAtoms() const { return atom.num; }; // 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; }; // speculation const int getCommitElem() const { return commit_elements; }; const int getCancelElem() const { return cancel_elements; }; + // ITE + const uint8_t getITE_EL() const { return ite_pkt.el; }; + const uint64_t getITE_value() const { return ite_pkt.value; }; + // 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; + void setProtocolVersion(const uint8_t version) { protocol_version = version; }; + 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); + const bool isETE() const { return (protocol_version & 0xF0) == 0x50; }; + Etmv4PktAddrStack m_addr_stack; }; inline void EtmV4ITrcPacket::updateErrType(const ocsd_etmv4_i_pkt_type err_pkt_type, const uint8_t err_val /* = 0 */) { // set primary type to incoming error type, set packet err type to previous primary type. err_type = type; type = err_pkt_type; err_hdr_val = err_val; } 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; // set these as defaults - if they don't appear in TINFO this is the state. setTraceInfo(0); setTraceInfoSpec(0); // explicitly reset the stack & zero the current address. m_addr_stack.reset_stack(); m_addr_stack.get_idx(0, v_addr, v_addr_ISA); } 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) +inline void EtmV4ITrcPacket::setContextInfo(const bool update, const uint8_t EL, const uint8_t NS, const uint8_t SF, const uint8_t NSE) { pkt_valid.bits.context_valid = 1; if(update) { context.updated = 1; context.EL = EL; context.NS = NS; context.SF = SF; + context.NSE = NSE; } } 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; v_addr.val = (v_addr.val & ~mask) | (addr & mask); } else { v_addr.val = addr; v_addr.size = VA_32BIT; } if (v_addr.valid_bits < 32) // may be updating a 64 bit address so only set 32 if currently less. v_addr.valid_bits = 32; 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); } +inline void EtmV4ITrcPacket::setITE(const uint8_t el, const uint64_t value) +{ + ite_pkt.el = el; + ite_pkt.value = value; +} + /** @}*/ #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_etmv4i.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_proc_etmv4i.h index abc322654b8d..58c0d78806c3 100644 --- a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_proc_etmv4i.h +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_proc_etmv4i.h @@ -1,214 +1,216 @@ /* * \file trc_pkt_proc_etmv4i.h * \brief OpenCSD : Implementation of ETMv4 packet processing * * \copyright Copyright (c) 2015, 2019 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 "trc_pkt_types_etmv4.h" #include "opencsd/etmv4/trc_pkt_proc_etmv4.h" #include "opencsd/etmv4/trc_cmp_cfg_etmv4.h" #include "opencsd/etmv4/trc_pkt_elem_etmv4i.h" #include "common/trc_raw_buffer.h" #include "common/trc_pkt_proc_base.h" class EtmV4ITrcPacket; 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; 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; // etmv4 hardware configuration EtmV4Config m_config; /** packet data **/ TraceRawBuffer m_trcIn; // trace data in buffer std::vector m_currPacketData; // raw data packet 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 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_WNDW_SECT 0x10 #define TINFO_CTRL 0x20 #define TINFO_ALL_SECT 0x1F #define TINFO_ALL 0x3F // 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(const uint8_t lastByte); // not synced yet void iPktNoPayload(const uint8_t lastByte); // process a single byte packet void iPktReserved(const uint8_t lastByte); // deal with reserved header value void iPktExtension(const uint8_t lastByte); void iPktASync(const uint8_t lastByte); void iPktTraceInfo(const uint8_t lastByte); void iPktTimestamp(const uint8_t lastByte); void iPktException(const uint8_t lastByte); void iPktCycleCntF123(const uint8_t lastByte); void iPktSpeclRes(const uint8_t lastByte); void iPktCondInstr(const uint8_t lastByte); void iPktCondResult(const uint8_t lastByte); void iPktContext(const uint8_t lastByte); void iPktAddrCtxt(const uint8_t lastByte); void iPktShortAddr(const uint8_t lastByte); void iPktLongAddr(const uint8_t lastByte); void iPktQ(const uint8_t lastByte); void iAtom(const uint8_t lastByte); void iPktInvalidCfg(const uint8_t lastByte); // packet invalid in current config. + void iPktITE(const uint8_t lastByte); 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 extractTSField64(const std::vector &buffer, const unsigned st_idx, uint64_t &value); 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 (TrcPktProcEtmV4I::*PPKTFN)(uint8_t); 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 TrcPktProcEtmV4I::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/include/opencsd/etmv4/trc_pkt_types_etmv4.h b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h index 7e98050c77c4..2a03b088c043 100644 --- a/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h +++ b/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h @@ -1,368 +1,397 @@ /* * \file trc_pkt_types_etmv4.h - * \brief OpenCSD : ETMv4 packet info + * \brief OpenCSD : ETMv4 / ETE packet info * - * \copyright Copyright (c) 2015,2019 ARM Limited. All Rights Reserved. + * \copyright Copyright (c) 2015,2019,2022 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 +/** @name ETMv4 Packet Types, ETE 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. */ ETM4_PKT_I_RESERVED_CFG, /*!< packet type reserved for current configuration */ /* I stream packet types. */ /* extension header. */ ETM4_PKT_I_EXTENSION = 0x00, /*!< b00000000 */ /* sync */ ETM4_PKT_I_TRACE_INFO = 0x01, /*!< b00000001 */ // timestamp ETM4_PKT_I_TIMESTAMP = 0x02, /*!< b0000001x */ ETM4_PKT_I_TRACE_ON = 0x04, /*!< b00000100 */ ETM4_PKT_I_FUNC_RET = 0x05, /*!< b00000101 (V8M only) */ // Exceptions ETM4_PKT_I_EXCEPT = 0x06, /*!< b00000110 */ - ETM4_PKT_I_EXCEPT_RTN = 0x07, /*!< b00000111 */ + ETM4_PKT_I_EXCEPT_RTN = 0x07, /*!< b00000111 (ETE invalid) */ - /* unused encodings 0x08-0xB b00001000 to b00001011 */ + /* unused encoding 0x08 b00001000 */ + ETE_PKT_I_ITE = 0x09, /*! b00001001 (ETE only) */ + ETE_PKT_I_TRANS_ST = 0x0A, /*! b00001010 (ETE only) */ + ETE_PKT_I_TRANS_COMMIT = 0x0B, /*! b00001011 (ETE only) */ /* cycle count packets */ ETM4_PKT_I_CCNT_F2 = 0x0C, /*!< b0000110x */ ETM4_PKT_I_CCNT_F1 = 0x0E, /*!< b0000111x */ 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 to b00101100 0x2C */ // speculation ETM4_PKT_I_COMMIT = 0x2D, /*!< b00101101 */ ETM4_PKT_I_CANCEL_F1 = 0x2E, /*!< b00101110 */ ETM4_PKT_I_CANCEL_F1_MISPRED = 0x2F, /*!< b00101111 */ ETM4_PKT_I_MISPREDICT = 0x30, /*!< b001100xx */ ETM4_PKT_I_CANCEL_F2 = 0x34, /*!< b001101xx */ ETM4_PKT_I_CANCEL_F3 = 0x38, /*!< b00111xxx */ - /* conditional instruction tracing */ + /* conditional instruction tracing - (reserved encodings ETE) */ ETM4_PKT_I_COND_I_F2 = 0x40, /*!< b01000000 - b01000010 */ ETM4_PKT_I_COND_FLUSH = 0x43, /*!< b01000011 */ ETM4_PKT_I_COND_RES_F4 = 0x44, /*!< b0100010x, b01000110 */ /* unused encoding 0x47 b01000111 */ ETM4_PKT_I_COND_RES_F2 = 0x48, /*!< b0100100x, b01001010, b0100110x, b01001110 */ /* unused encodings 0x4B,0x4F b01001011, b01001111 */ ETM4_PKT_I_COND_RES_F3 = 0x50, /*!< b0101xxxx */ /* unused encodings 0x60-0x67 b01100xxx */ ETM4_PKT_I_COND_RES_F1 = 0x68, /*!< b011010xx, b0110111x 0x68-0x6B, 0x6e-0x6F */ ETM4_PKT_I_COND_I_F1 = 0x6C, /*!< b01101100 */ ETM4_PKT_I_COND_I_F3 = 0x6D, /*!< b01101101 */ // event trace ETM4_PKT_I_IGNORE = 0x70, /*!< b01110000 */ ETM4_PKT_I_EVENT = 0x71, /*!< b01110001 to 0x01111111 0x7F */ /* address and context */ ETM4_PKT_I_CTXT = 0x80, /*!< b1000000x */ ETM4_PKT_I_ADDR_CTXT_L_32IS0 = 0x82, /*!< b10000010 */ ETM4_PKT_I_ADDR_CTXT_L_32IS1, /*!< b10000011 */ /* unused encoding 0x84 b10000100 */ ETM4_PKT_I_ADDR_CTXT_L_64IS0 = 0x85, /*!< b10000101 */ ETM4_PKT_I_ADDR_CTXT_L_64IS1, /*!< b10000110 */ /* unused encoding 0x87 b10000111 */ - /* unused encodings 0x88-0x8F b10001xxx */ + ETE_PKT_I_TS_MARKER = 0x88, /*!< b10001000 */ + /* unused encodings 0x89-0x8F b10001001 to b10001111 */ ETM4_PKT_I_ADDR_MATCH = 0x90, /*!< b10010000 to b10010010 0x92 */ /* unused encodings 0x93-0x94 b10010011 to b10010010 */ ETM4_PKT_I_ADDR_S_IS0 = 0x95, /*!< b10010101 */ ETM4_PKT_I_ADDR_S_IS1, /*!< b10010110 */ /* unused encodings 0x97 b10010111 to b10011001 0x99 */ ETM4_PKT_I_ADDR_L_32IS0 = 0x9A, /*!< b10011010 */ ETM4_PKT_I_ADDR_L_32IS1, /*!< b10011011 */ /* unused encoding 0x9C b10011100 */ ETM4_PKT_I_ADDR_L_64IS0 = 0x9D, /*!< b10011101 */ ETM4_PKT_I_ADDR_L_64IS1, /*!< b10011110 */ /* unused encoding 0x9F b10011111 */ /* Q packets */ ETM4_PKT_I_Q = 0xA0, /*!< b1010xxxx */ - /* unused encodings 0xB0-0xBF b1011xxxx */ + /* ETE source address packets, unused ETMv4 */ + ETE_PKT_I_SRC_ADDR_MATCH = 0xB0, /*!< b101100xx */ + ETE_PKT_I_SRC_ADDR_S_IS0 = 0xB4, /*!< b10110100 */ + ETE_PKT_I_SRC_ADDR_S_IS1 = 0xB5, /*!< b10110101 */ + ETE_PKT_I_SRC_ADDR_L_32IS0 = 0xB6, /*!< b10110110 */ + ETE_PKT_I_SRC_ADDR_L_32IS1 = 0xB7, /*!< b10110111 */ + ETE_PKT_I_SRC_ADDR_L_64IS0 = 0xB8, /*!< b10111000 */ + ETE_PKT_I_SRC_ADDR_L_64IS1 = 0xB9, /*!< b10111001 */ + /* unused encodings 0xBA-0xBF b10111010 - b10111111 */ /* Atom packets */ ETM4_PKT_I_ATOM_F6 = 0xC0, /*!< b11000000 - b11010100 0xC0 - 0xD4, b11100000 - b11110100 0xE0 - 0xF4 */ ETM4_PKT_I_ATOM_F5 = 0xD5, /*!< b11010101 - b11010111 0xD5 - 0xD7, b11110101 0xF5 */ ETM4_PKT_I_ATOM_F2 = 0xD8, /*!< b110110xx to 0xDB */ ETM4_PKT_I_ATOM_F4 = 0xDC, /*!< b110111xx to 0xDF */ ETM4_PKT_I_ATOM_F1 = 0xF6, /*!< b1111011x to 0xF7 */ ETM4_PKT_I_ATOM_F3 = 0xF8, /*!< b11111xxx to 0xFF */ // extension packets - follow 0x00 header ETM4_PKT_I_ASYNC = 0x100, //!< b00000000 ETM4_PKT_I_DISCARD = 0x103, //!< b00000011 ETM4_PKT_I_OVERFLOW = 0x105, //!< b00000101 + // ETE extended types + ETE_PKT_I_PE_RESET = 0x400, // base type is exception packet. + ETE_PKT_I_TRANS_FAIL = 0x401, // base type is exception packet. + } 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 cond_enabled:3; //!< conditional trace enabled type. uint32_t p0_load:1; //!< 1 if tracing with P0 load elements (for data trace) uint32_t p0_store:1; //!< 1 if tracing with P0 store elements (for data trace) + uint32_t in_trans_state:1; //!< 1 if starting trace when in a transactional state (ETE 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 NSE:1; //!< PE FEAT_RME: root / realm indicator }; 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; +#define ETE_ARCH_VERSION 0x5 + +#define ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS 0x00010000 /**< Split source address output ranges for N-atoms */ /** @}*/ /** @}*/ #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 index 23087ee694b1..f5ff6ac6c530 100644 --- a/contrib/opencsd/decoder/include/opencsd/ocsd_if_types.h +++ b/contrib/opencsd/decoder/include/opencsd/ocsd_if_types.h @@ -1,633 +1,691 @@ /*! * \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 */ OCSD_ERR_DFMTR_BAD_FHSYNC, /**< Bad frame or half frame sync in trace deformatter */ /* 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 */ OCSD_ERR_MEM_ACC_BAD_LEN, /**< Memory accessor returned a bad read length value (larger than requested */ /* 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 interface 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 = 0x0000, /**< unknown architecture */ ARCH_CUSTOM = 0x0001, /**< None ARM, custom architecture */ ARCH_V7 = 0x0700, /**< V7 architecture */ ARCH_V8 = 0x0800, /**< V8 architecture */ ARCH_V8r3 = 0x0803, /**< V8.3 architecture */ + ARCH_AA64 = 0x0864, /**< Min v8r3 plus additional AA64 PE features */ + ARCH_V8_max = ARCH_AA64, } ocsd_arch_version_t; // macros for arch version comparisons. -#define OCSD_IS_V8_ARCH(arch) ((arch >= ARCH_V8) && (arch <= ARCH_V8r3)) -#define OCSD_MIN_V8_ARCH(arch) (arch >= ARCH_V8) +#define OCSD_IS_V8_ARCH(arch) ((arch >= ARCH_V8) && (arch <= ARCH_V8_max)) +#define OCSD_IS_ARCH_MINVER(arch, min_arch) (arch >= min_arch) /** 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_secure, /**< Core is in secure state */ + ocsd_sec_nonsecure, /**< Core is in non-secure state */ + ocsd_sec_root, /**< PE FEAT_RME: Core is in root state. */ + ocsd_sec_realm, /**< PE FEAT_RME: Core is in realm 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 */ +/** instruction types - significant for waypoint calculations */ 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_WFI_WFE, /**< WFI or WFE traced as direct branch */ + OCSD_INSTR_TSTART, /**< PE Arch feature FEAT_TME - TSTART 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_S_INSTR_V7_IMPLIED_RET, /**< v7 instruction which could imply return e.g. MOV PC, LR; POP { ,pc} */ } 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 */ uint8_t wfi_wfe_branch; /**< Input: WFI, WFE classed as direct branches */ /* 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_EL2S = 0x10, /**< S EL2 */ OCSD_MEM_SPACE_S = 0x19, /**< Any S */ OCSD_MEM_SPACE_N = 0x6, /**< Any NS */ OCSD_MEM_SPACE_ANY = 0x1F, /**< 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); /** * 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 trcID : Trace ID for source of trace - allow CB to client to associate mem req with source cpu. * @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_MemAccID_CB)(const void *p_context, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trcID, 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, protocol component specific - top 16 bits. (common flags share bitfield with pkt decoder common flags and create flags) @{*/ #define OCSD_OPFLG_PKTPROC_NOFWD_BAD_PKTS 0x00000010 /**< don't forward bad packets up data path */ #define OCSD_OPFLG_PKTPROC_NOMON_BAD_PKTS 0x00000020 /**< don't forward bad packets to monitor interface */ #define OCSD_OPFLG_PKTPROC_ERR_BAD_PKTS 0x00000040 /**< throw error for bad packets - halt decoding. */ #define OCSD_OPFLG_PKTPROC_UNSYNC_ON_BAD_PKTS 0x00000080 /**< 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 ) /** mask for the component spcific flags */ #define OCSD_OPFLG_COMP_MODE_MASK 0xFFFF0000 /** @}*/ /** @name Packet Decoder Operation Control Flags common operational flags - bottom 16 bits, protcol component specific - top 16 bits. (common flags share bitfield with pkt processor common flags and create flags) @{*/ -#define OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS 0x00000100 /**< throw error on bad packets input (default is to unsync and wait) */ +#define OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS 0x00000100 /**< throw error on bad packets input (default is to warn) */ +#define OCSD_OPFLG_PKTDEC_HALT_BAD_PKTS 0x00000200 /**< halt decoder on bad packets (default is to log error and continue by resetting decoder and wait for sync */ /** mask to combine all common packet processor operational control flags */ -#define OCSD_OPFLG_PKTDEC_COMMON (OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) +#define OCSD_OPFLG_PKTDEC_COMMON (OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS | OCSD_OPFLG_PKTDEC_HALT_BAD_PKTS) /** @}*/ /** @name Decoder creation information Flags to use when creating decoders by name. - share bitfield with pkt processor flags and packet decoder common flags. 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 */ +#define OCSD_BUILTIN_DCD_ETE "ETE" /**< ETE 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. */ + OCSD_PROTOCOL_ETE, /**< ETE 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) /** @}*/ +/** @name Demux Statistics + + Contains statistics for the CoreSight frame demultiplexor. + + Counts total bytes sent to decoders registered against a trace ID, bytes in the input stream that are + associated with a trace ID that has no registered decoder, and frame bytes that are not trace data, but + are used to decode the frames - ID bytes, sync bytes etc. +@{*/ + +typedef struct _ocsd_demux_stats { + uint64_t valid_id_bytes; /**< number of bytes associated with an ID that has a registered decoder */ + uint64_t no_id_bytes; /**< number of bytes associated with an ID that has no decoder */ + uint64_t reserved_id_bytes; /**< number of bytes associated with reserved IDs */ + uint64_t unknown_id_bytes; /**< bytes processed before ID seen in input frames */ + uint64_t frame_bytes; /**< number of non-data bytes used for frame de-mux - ID bytes, sync etc */ +} ocsd_demux_stats_t; + +/** @}*/ + +/** @name Decode statistics + + Contains statistics for bytes decoded by the packet decoder, if statistics are supported. + + Stats block instantiated in the base class - derived protocol specific decoder must initialise and + use as required. + + The single channel block contains the stats for the requested channel via the API call. + + The global demux block contains the totals for all channels and non-data bytes used in CoreSight + frame demux. This block will show identical data for every requested channel via the API. + +@{*/ + +typedef struct _ocsd_decode_stats { + uint32_t version; /**< library version number */ + uint16_t revision; /**< revision number - defines the structure version for the stats. */ + /* single channel block */ + uint64_t channel_total; /**< total bytes processed for this channel */ + uint64_t channel_unsynced; /**< number of unsynced bytes processed on this channel */ + uint32_t bad_header_errs; /**< number of bad packet header errors */ + uint32_t bad_sequence_errs; /**< number of bad packet sequence errors */ + + ocsd_demux_stats_t demux; /**< global demux stats block */ +} ocsd_decode_stats_t; + +#define OCSD_STATS_REVISION 0x1 + +/** @}*/ + + /** @}*/ #endif // ARM_OCSD_IF_TYPES_H_INCLUDED /* End of File opencsd/ocsd_if_types.h */ diff --git a/contrib/opencsd/decoder/include/opencsd/ocsd_if_version.h b/contrib/opencsd/decoder/include/opencsd/ocsd_if_version.h index 38baa02e8b48..41033f0675ed 100644 --- a/contrib/opencsd/decoder/include/opencsd/ocsd_if_version.h +++ b/contrib/opencsd/decoder/include/opencsd/ocsd_if_version.h @@ -1,65 +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 0xE /**< Library Minor Version */ -#define OCSD_VER_PATCH 0x2 /**< Library Patch Version */ +#define OCSD_VER_MAJOR 0x1 /**< Library Major Version */ +#define OCSD_VER_MINOR 0x4 /**< Library Minor Version */ +#define OCSD_VER_PATCH 0x0 /**< Library Patch Version */ /** Library version number - MMMMnnpp format. MMMM = major version, nn = minor version, pp = patch version */ #define OCSD_VER_NUM ((OCSD_VER_MAJOR << 16) | (OCSD_VER_MINOR << 8) | OCSD_VER_PATCH) -#define OCSD_VER_STRING "0.14.2" /**< Library Version string */ +#define OCSD_VER_STRING "1.4.0" /**< 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/stm/trc_pkt_proc_stm.h b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_proc_stm.h index 909ac0cb0566..bc4391bfebfb 100644 --- a/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_proc_stm.h +++ b/contrib/opencsd/decoder/include/opencsd/stm/trc_pkt_proc_stm.h @@ -1,289 +1,290 @@ /* * \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 + m_is_sync = true; //this nibble marks a sync sequence + m_num_F_nibbles = 21; // set the F nibble count - lose any extra as unsynced data. } 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/trc_gen_elem_types.h b/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h index 1a285a064b63..99194d118438 100644 --- a/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h +++ b/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h @@ -1,142 +1,169 @@ /*! * \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_I_RANGE_NOPATH, /*!< traced N instructions in a range, but incomplete information as to program execution path from start to end of range */ 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 or numbered event */ - OCSD_GEN_TRC_ELEM_SWTRACE, /*!< Software trace packet - may contain data payload. */ + OCSD_GEN_TRC_ELEM_SWTRACE, /*!< Software trace packet - may contain data payload. STM / ITM hardware trace with channel protocol */ + OCSD_GEN_TRC_ELEM_SYNC_MARKER, /*!< Synchronisation marker - marks position in stream of an element that is output later. */ + OCSD_GEN_TRC_ELEM_MEMTRANS, /*!< Trace indication of transactional memory operations. */ + OCSD_GEN_TRC_ELEM_INSTRUMENTATION, /*!< PE instrumentation trace - PE generated SW trace, application dependent protocol. */ 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 enum _unsync_info_t { UNSYNC_UNKNOWN, /**< unknown /undefined */ UNSYNC_INIT_DECODER, /**< decoder intialisation - start of trace. */ UNSYNC_RESET_DECODER, /**< decoder reset. */ UNSYNC_OVERFLOW, /**< overflow packet - need to re-sync / end of trace after overflow. */ UNSYNC_DISCARD, /**< specl trace discard - need to re-sync. */ UNSYNC_BAD_PACKET, /**< bad packet at input - resync to restart. */ UNSYNC_EOT, /**< end of trace - no additional info */ } unsync_info_t; +typedef enum _trace_sync_marker_t { + ELEM_MARKER_TS, /**< Marker for timestamp element */ +} trace_sync_marker_t; + +typedef struct _trace_marker_payload_t { + trace_sync_marker_t type; /**< type of sync marker */ + uint32_t value; /**< sync marker value - usage depends on type */ +} trace_marker_payload_t; + +typedef enum _memtrans_t { + OCSD_MEM_TRANS_TRACE_INIT,/**< Trace started while PE in transactional state */ + OCSD_MEM_TRANS_START, /**< Trace after this packet is part of a transactional memory sequence */ + OCSD_MEM_TRANS_COMMIT, /**< Transactional memory sequence valid. */ + OCSD_MEM_TRANS_FAIL, /**< Transactional memory sequence failed - operations since start of transaction have been unwound. */ +} trace_memtrans_t; + +typedef struct _sw_ite_t { + uint8_t el; /**< exception level for PE sw instrumentation instruction */ + uint64_t value; /**< payload for PE sw instrumentation instruction */ +} trace_sw_ite_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 last_instr_sz:3; /**< size of last instruction in bytes (2/4) */ 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 last_instr_cond:1; /**< 1 if the last instruction was conditional */ uint32_t excep_ret_addr_br_tgt:1; /**< 1 if exception return address (en_addr) is also the target of a taken branch addr from the previous range. */ }; 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 */ uint32_t num_instr_range; /**< number of instructions covered by range packet (for T32 this cannot be calculated from en-st/i_size) */ unsync_info_t unsync_eot_info; /**< additional information for unsync / end-of-trace packets. */ + trace_marker_payload_t sync_marker; /**< marker element - sync later element to position in stream */ + trace_memtrans_t mem_trans; /**< memory transaction packet - transaction event */ + trace_sw_ite_t sw_ite; /**< PE sw instrumentation using FEAT_ITE */ }; 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/source/c_api/ocsd_c_api.cpp b/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp index 4824c427e3d1..750c847e78c8 100644 --- a/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp +++ b/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp @@ -1,583 +1,632 @@ /* * \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 version, 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_get_decode_stats(const dcd_tree_handle_t handle, + const unsigned char CSID, + ocsd_decode_stats_t **p_stats_block) +{ + DecodeTree *pDT = static_cast(handle); + + return pDT->getDecoderStats(CSID, p_stats_block); +} + +OCSD_C_API ocsd_err_t ocsd_dt_reset_decode_stats(const dcd_tree_handle_t handle, + const unsigned char CSID) +{ + DecodeTree *pDT = static_cast(handle); + + return pDT->resetDecoderStats(CSID); +} +/*** 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_add_callback_trcid_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_MemAccID_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->addCallbackIDMemAcc(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; } +OCSD_C_API void ocsd_err_str(const ocsd_err_t err, char *buffer, const int buffer_size) +{ + std::string err_str; + err_str = ocsdError::getErrorString(ocsdError(OCSD_ERR_SEV_ERROR, err)); + strncpy(buffer, err_str.c_str(), buffer_size - 1); + buffer[buffer_size - 1] = 0; +} + +OCSD_C_API ocsd_err_t ocsd_get_last_err(ocsd_trc_index_t *index, uint8_t *chan_id, char *message, const int message_len) +{ + ocsdError *p_err; + ocsd_err_t err = OCSD_OK; + std::string err_str; + + p_err = DecodeTree::getDefaultErrorLogger()->GetLastError(); + if (p_err) + { + *index = p_err->getErrorIndex(); + *chan_id = p_err->getErrorChanID(); + err_str = p_err->getErrorString(ocsdError(p_err)); + strncpy(message, err_str.c_str(), message_len - 1); + message[message_len - 1] = 0; + err = p_err->getErrorCode(); + } + else + { + message[0] = 0; + *index = OCSD_BAD_TRC_INDEX; + *chan_id = OCSD_BAD_CS_SRC_ID; + } + 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/ete/trc_cmp_cfg_ete.cpp b/contrib/opencsd/decoder/source/ete/trc_cmp_cfg_ete.cpp new file mode 100644 index 000000000000..474cb2f7914a --- /dev/null +++ b/contrib/opencsd/decoder/source/ete/trc_cmp_cfg_ete.cpp @@ -0,0 +1,98 @@ +/* +* \file trc_cmp_cfg_ete.cpp +* \brief OpenCSD : ETE config class +* +* \copyright Copyright (c) 2019, 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/ete/trc_cmp_cfg_ete.h" + +ETEConfig::ETEConfig() : EtmV4Config() +{ + m_ete_cfg.reg_idr0 = 0x28000EA1; + m_ete_cfg.reg_idr1 = 0x4100FFF3; + m_ete_cfg.reg_idr2 = 0x00000488; + m_ete_cfg.reg_idr8 = 0; + m_ete_cfg.reg_configr = 0xC1; + m_ete_cfg.reg_traceidr = 0; + m_ete_cfg.arch_ver = ARCH_AA64; + m_ete_cfg.core_prof = profile_CortexA; + m_ete_cfg.reg_devarch = 0x47705A13; + copyV4(); +} + +ETEConfig::ETEConfig(const ocsd_ete_cfg *cfg_regs) : EtmV4Config() +{ + m_ete_cfg = *cfg_regs; + copyV4(); +} + +ETEConfig::~ETEConfig() +{ + +} + +//! copy assignment operator for base structure into class. +ETEConfig & ETEConfig::operator=(const ocsd_ete_cfg *p_cfg) +{ + m_ete_cfg = *p_cfg; + copyV4(); + return *this; +} + +//! cast operator returning struct const reference +//operator const ocsd_ete_cfg &() const { return m_ete_cfg; }; +//! cast operator returning struct const pointer +//operator const ocsd_ete_cfg *() const { return &m_ete_cfg; }; + +// ete superset of etmv4 - move info to underlying structure. +void ETEConfig::copyV4() +{ + // copy over 1:1 regs + m_cfg.reg_idr0 = m_ete_cfg.reg_idr0; + m_cfg.reg_idr1 = m_ete_cfg.reg_idr1; + m_cfg.reg_idr2 = m_ete_cfg.reg_idr2; + m_cfg.reg_idr8 = m_ete_cfg.reg_idr8; + 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 = m_ete_cfg.reg_configr; + m_cfg.reg_traceidr = m_ete_cfg.reg_traceidr; + m_cfg.core_prof = m_ete_cfg.core_prof; + m_cfg.arch_ver = m_ete_cfg.arch_ver; + + // override major / minor version as part of devarch + m_MajVer = (uint8_t)((m_ete_cfg.reg_devarch & 0xF000) >> 12); + m_MinVer = (uint8_t)((m_ete_cfg.reg_devarch & 0xF0000) >> 16); +} + +/* End of File trc_cmp_cfg_ete.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 index f1e411f72423..74034c3c3e8f 100644 --- a/contrib/opencsd/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp +++ b/contrib/opencsd/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp @@ -1,688 +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","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/etmv4/trc_cmp_cfg_etmv4.cpp b/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp index 9f5b37396b46..6f8bf790d293 100644 --- a/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp +++ b/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp @@ -1,111 +1,111 @@ /* * \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; m_MajVer = (uint8_t)((m_cfg.reg_idr1 >> 8) & 0xF); m_MinVer = (uint8_t)((m_cfg.reg_idr1 >> 4) & 0xF); } 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) + else if(FullVersion() > 0x40) { 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 index 8e9ba9ac43ca..a5d889413eb2 100644 --- a/contrib/opencsd/decoder/source/etmv4/trc_etmv4_stack_elem.cpp +++ b/contrib/opencsd/decoder/source/etmv4/trc_etmv4_stack_elem.cpp @@ -1,156 +1,194 @@ /* * \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*/ TrcStackElem *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, bool back /*= false*/) { TrcStackElem *pElem = new (std::nothrow) TrcStackElem(p0_type, isP0, root_pkt, root_index); if (pElem) { if (back) push_back(pElem); else push_front(pElem); } return pElem; } 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, const uint8_t IS, const bool back /*= false*/) { TrcStackElemCtxt *pElem = new (std::nothrow) TrcStackElemCtxt(root_pkt, root_index); if (pElem) { pElem->setContext(context); pElem->setIS(IS); if (back) push_back(pElem); else 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; } TrcStackQElem *EtmV4P0Stack::createQElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const int count) { TrcStackQElem *pElem = new (std::nothrow) TrcStackQElem(root_pkt, root_index); if (pElem) { pElem->setInstrCount(count); push_front(pElem); } return pElem; } +TrcStackElemMarker *EtmV4P0Stack::createMarkerElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const trace_marker_payload_t &marker) +{ + TrcStackElemMarker *pElem = new (std::nothrow) TrcStackElemMarker(root_pkt, root_index); + if (pElem) + { + pElem->setMarker(marker); + push_front(pElem); + } + return pElem; +} + +TrcStackElemAddr *EtmV4P0Stack::createSrcAddrElem(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, true); + if (pElem) + { + pElem->setAddr(addr_val); + push_front(pElem); + } + return pElem; +} + +TrcStackElemITE *EtmV4P0Stack::createITEElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const trace_sw_ite_t &ite) +{ + TrcStackElemITE *pElem = new (std::nothrow) TrcStackElemITE(root_pkt, root_index); + if (pElem) + { + pElem->setITE(ite); + push_front(pElem); + } + return pElem; +} + + // iteration functions void EtmV4P0Stack::from_front_init() { m_iter = m_P0_stack.begin(); } TrcStackElem *EtmV4P0Stack::from_front_next() { TrcStackElem *pElem = 0; if (m_iter != m_P0_stack.end()) { pElem = *m_iter++; } return pElem; } void EtmV4P0Stack::erase_curr_from_front() { std::deque::iterator erase_iter; erase_iter = m_iter; erase_iter--; m_P0_stack.erase(erase_iter); + + // explicitly delete the item here as the caller can no longer reference it. + // fixes memory leak from github issue #52 + delete *erase_iter; } /* 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 index 393046ba23d1..89c45052868c 100644 --- a/contrib/opencsd/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp @@ -1,1585 +1,1987 @@ /* * \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; +static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS = OCSD_OPFLG_PKTDEC_COMMON | + ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS; 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; ocsd_err_t err = OCSD_OK; bool bPktDone = false; while(!bPktDone) { switch (m_curr_state) { case NO_SYNC: // output the initial not synced packet to the sink err = m_out_elem.resetElemStack(); if (!err) err = m_out_elem.addElemType(m_index_curr_pkt, OCSD_GEN_TRC_ELEM_NO_SYNC); if (!err) { outElem().setUnSyncEOTReason(m_unsync_eot_info); resp = m_out_elem.sendElements(); m_curr_state = WAIT_SYNC; } else resp = OCSD_RESP_FATAL_SYS_ERR; // 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(); } + /* ETE spec allows early event packets. */ + else if ((m_config->MajVersion() >= 0x5) && + (m_curr_packet_in->getType() == ETM4_PKT_I_EVENT)) + { + err = decodePacket(); + if (err) + resp = OCSD_RESP_FATAL_INVALID_DATA; + } bPktDone = true; break; case DECODE_PKTS: // this may change the state to RESOLVE_ELEM if required; err = decodePacket(); if (err) { #ifdef OCSD_WARN_UNSUPPORTED if (err == OCSD_ERR_UNSUPP_DECODE_PKT) resp = OCSD_RESP_WARN_CONT; else #else resp = OCSD_RESP_FATAL_INVALID_DATA; #endif bPktDone = true; } else if (m_curr_state != RESOLVE_ELEM) bPktDone = true; break; case RESOLVE_ELEM: // this will change the state to DECODE_PKTS once required elem resolved & // needed generic packets output resp = resolveElements(); if ((m_curr_state == DECODE_PKTS) || (!OCSD_DATA_RESP_IS_CONT(resp))) bPktDone = true; break; } } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onEOT() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; ocsd_err_t err; if ((err = commitElemOnEOT()) != OCSD_OK) { resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, "Error flushing element stack at end of trace data.")); } else resp = m_out_elem.sendElements(); return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onReset() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; m_unsync_eot_info = UNSYNC_RESET_DECODER; resetDecoder(); return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onFlush() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; if (m_curr_state == RESOLVE_ELEM) resp = resolveElements(); else resp = m_out_elem.sendElements(); 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(); // elements associated with data trace #ifdef DATA_TRACE_SUPPORTED m_p0_key_max = m_config->P0_Key_Max(); m_cond_key_max_incr = m_config->CondKeyMaxIncr(); #endif m_out_elem.initCSID(m_CSID); // set up static trace instruction decode elements m_instr_info.dsb_dmb_waypoints = 0; m_instr_info.wfi_wfe_branch = m_config->wfiwfeBranch() ? 1 : 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_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.")); } 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_CSID = 0; m_IASize64 = false; // elements associated with data trace #ifdef DATA_TRACE_SUPPORTED m_p0_key_max = 0; m_cond_key_max_incr = 0; #endif // reset decoder state to unsynced m_unsync_eot_info = UNSYNC_INIT_DECODER; 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_need_ctxt = true; m_need_addr = true; m_elem_pending_addr = false; m_prev_overflow = false; m_P0_stack.delete_all(); m_out_elem.resetElemStack(); m_last_IS = 0; clearElemRes(); + m_ete_first_ts_marker = false; // elements associated with data trace #ifdef DATA_TRACE_SUPPORTED m_p0_key = 0; m_cond_c_key = 0; m_cond_r_key = 0; #endif } void TrcPktDecodeEtmV4I::onFirstInitOK() { // once init, set the output element interface to the out elem list. m_out_elem.initSendIf(this->getTraceElemOutAttachPt()); } // Changes a packet into stack of trace elements - these will be resolved and output later ocsd_err_t TrcPktDecodeEtmV4I::decodePacket() { ocsd_err_t err = OCSD_OK; bool bAllocErr = false; bool is_addr = false; switch(m_curr_packet_in->getType()) { case ETM4_PKT_I_ASYNC: // nothing to do with this packet. case ETM4_PKT_I_IGNORE: // or this one. 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_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(), m_last_IS) == 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_last_IS = 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: { m_last_IS = m_curr_packet_in->getAddrIS(); if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext(), m_last_IS) == 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_last_IS = 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; + is_addr = true; // may be waiting for target address from indirect branch + } + break; + + case ETE_PKT_I_SRC_ADDR_MATCH: + case ETE_PKT_I_SRC_ADDR_S_IS0: + case ETE_PKT_I_SRC_ADDR_S_IS1: + case ETE_PKT_I_SRC_ADDR_L_32IS0: + case ETE_PKT_I_SRC_ADDR_L_32IS1: + case ETE_PKT_I_SRC_ADDR_L_64IS0: + case ETE_PKT_I_SRC_ADDR_L_64IS1: + { + etmv4_addr_val_t addr; + + addr.val = m_curr_packet_in->getAddrVal(); + addr.isa = m_curr_packet_in->getAddrIS(); + if (m_P0_stack.createSrcAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) + bAllocErr = true; + m_curr_spec_depth++; } 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_elem_pending_addr = true; // wait for following packets before marking for commit. } 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; else if (bV7MProfile) m_curr_spec_depth++; } break; case ETM4_PKT_I_FUNC_RET: { // P0 element iff V8M profile, otherwise ignore if (OCSD_IS_V8_ARCH(m_config->archVersion()) && (m_config->coreProfile() == profile_CortexM)) { if (m_P0_stack.createParamElemNoParam(P0_FUNC_RET, true, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) bAllocErr = true; else m_curr_spec_depth++; } } 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_CC, 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(bTSwithCC ? P0_TS_CC : P0_TS, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) bAllocErr = true; } break; + case ETE_PKT_I_TS_MARKER: + { + trace_marker_payload_t marker; + marker.type = ELEM_MARKER_TS; + marker.value = 0; + if (m_P0_stack.createMarkerElem(m_curr_packet_in->getType(), m_index_curr_pkt, marker) == 0) + bAllocErr = true; + } + break; + case ETM4_PKT_I_BAD_SEQUENCE: - err = handleBadPacket("Bad byte sequence in packet."); + err = handleBadPacket("Bad byte sequence in packet.", m_index_curr_pkt); break; case ETM4_PKT_I_BAD_TRACEMODE: - err = handleBadPacket("Invalid packet type for trace mode."); + err = handleBadPacket("Invalid packet type for trace mode.", m_index_curr_pkt); break; case ETM4_PKT_I_RESERVED: - err = handleBadPacket("Reserved packet header"); + err = handleBadPacket("Reserved packet header", m_index_curr_pkt); break; // speculation case ETM4_PKT_I_MISPREDICT: case ETM4_PKT_I_CANCEL_F1_MISPRED: case ETM4_PKT_I_CANCEL_F2: case ETM4_PKT_I_CANCEL_F3: m_elem_res.mispredict = true; if (m_curr_packet_in->getNumAtoms()) { 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->getNumAtoms(); } case ETM4_PKT_I_CANCEL_F1: m_elem_res.P0_cancel = m_curr_packet_in->getCancelElem(); break; case ETM4_PKT_I_COMMIT: m_elem_res.P0_commit = m_curr_packet_in->getCommitElem(); break; case ETM4_PKT_I_OVERFLOW: m_prev_overflow = true; case ETM4_PKT_I_DISCARD: m_curr_spec_depth = 0; m_elem_res.discard = true; break; /* Q packets */ case ETM4_PKT_I_Q: { TrcStackQElem *pQElem = m_P0_stack.createQElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->Q_pkt.q_count); if (pQElem) { if (m_curr_packet_in->Q_pkt.addr_present) { etmv4_addr_val_t addr; addr.val = m_curr_packet_in->getAddrVal(); addr.isa = m_curr_packet_in->getAddrIS(); pQElem->setAddr(addr); m_curr_spec_depth++; } else m_elem_pending_addr = true; } else bAllocErr = true; } break; + /* transactional memory packets */ + case ETE_PKT_I_TRANS_ST: + { + if (m_P0_stack.createParamElemNoParam(P0_TRANS_START, m_config->commTransP0(), m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + if (m_config->commTransP0()) + m_curr_spec_depth++; + } + break; + + case ETE_PKT_I_TRANS_COMMIT: + { + if (m_P0_stack.createParamElemNoParam(P0_TRANS_COMMIT, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + } + break; + + case ETE_PKT_I_TRANS_FAIL: + { + if (m_P0_stack.createParamElemNoParam(P0_TRANS_FAIL, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + } + break; + + /* PE Instrumentation packet */ + case ETE_PKT_I_ITE: + { + trace_sw_ite_t ite_pkt; + + ite_pkt.el = m_curr_packet_in->getITE_EL(); + ite_pkt.value = m_curr_packet_in->getITE_value(); + if (m_P0_stack.createITEElem(m_curr_packet_in->getType(), m_index_curr_pkt, ite_pkt) == 0) + bAllocErr = true; + } + break; + /*** presently unsupported packets ***/ - /* conditional instruction tracing */ + /* 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: // data synchronisation markers case ETM4_PKT_I_NUM_DS_MKR: case ETM4_PKT_I_UNNUM_DS_MKR: // all currently unsupported { ocsd_err_severity_t sev = OCSD_ERR_SEV_ERROR; #ifdef OCSD_WARN_UNSUPPORTED sev = OCSD_ERR_SEV_WARN; //resp = OCSD_RESP_WARN_CONT; #else //resp = OCSD_RESP_FATAL_INVALID_DATA; #endif err = OCSD_ERR_UNSUPP_DECODE_PKT; - LogError(ocsdError(sev, err, "Data trace releated, unsupported packet type.")); + if (sev == OCSD_ERR_SEV_WARN) + LogError(ocsdError(sev, err, "Data trace related, unsupported packet type.")); + else + err = handlePacketSeqErr(err, m_index_curr_pkt, "Data trace related, unsupported packet type."); } break; default: // any other packet - bad packet error - err = OCSD_ERR_BAD_DECODE_PKT; - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,"Unknown packet type.")); + err = handleBadPacket("Unknown packet type.", m_index_curr_pkt); break; } // we need to wait for following address after certain packets // - work out if we have seen enough here... if (is_addr && m_elem_pending_addr) { m_curr_spec_depth++; // increase spec depth for element waiting on address. m_elem_pending_addr = false; // can't be waiting on both } if(bAllocErr) { err = OCSD_ERR_MEM; 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_elem_res.P0_commit = m_curr_spec_depth - m_max_spec_depth; } if (!err && isElemForRes()) m_curr_state = RESOLVE_ELEM; return err; } void TrcPktDecodeEtmV4I::doTraceInfoPacket() { m_trace_info = m_curr_packet_in->getTraceInfo(); m_cc_threshold = m_curr_packet_in->getCCThreshold(); m_curr_spec_depth = m_curr_packet_in->getCurrSpecDepth(); + /* put a trans marker in stack if started in trans state */ + if (m_trace_info.bits.in_trans_state) + m_P0_stack.createParamElemNoParam(P0_TRANS_TRACE_INIT, false, m_curr_packet_in->getType(), m_index_curr_pkt); // elements associated with data trace #ifdef DATA_TRACE_SUPPORTED m_p0_key = m_curr_packet_in->getP0Key(); #endif } /* Element resolution * Commit or cancel elements as required * Send any buffered output packets. */ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::resolveElements() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; bool Complete = false; while (!Complete) { if (m_out_elem.numElemToSend()) resp = m_out_elem.sendElements(); else if (isElemForRes()) { ocsd_err_t err = OCSD_OK; if (m_elem_res.P0_commit) err = commitElements(); - if (!err && m_elem_res.P0_cancel) - err = cancelElements(); + // allow for early flush on context element + if (!m_elem_res.P0_commit) { - if (!err && m_elem_res.mispredict) - err = mispredictAtom(); - - if (!err && m_elem_res.discard) - err = discardElements(); + if (!err && m_elem_res.P0_cancel) + err = cancelElements(); + + if (!err && m_elem_res.mispredict) + err = mispredictAtom(); + + if (!err && m_elem_res.discard) + err = discardElements(); + } if (err != OCSD_OK) resp = OCSD_RESP_FATAL_INVALID_DATA; } // break out on error or wait request. if (!OCSD_DATA_RESP_IS_CONT(resp)) break; // completion is nothing to send and nothing to commit Complete = !m_out_elem.numElemToSend() && !isElemForRes(); // done all elements - need more packets. if (Complete) { // if we are still in resolve, the goto decode. if (m_curr_state == RESOLVE_ELEM) m_curr_state = DECODE_PKTS; } } return resp; } /* * Walks through the element stack, processing from oldest element to the newest, according to the number of P0 elements that need committing. Build a stack of output elements in the process. */ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() { ocsd_err_t err = OCSD_OK; bool bPopElem = true; // do we remove the element from the stack (multi atom elements may need to stay!) int num_commit_req = m_elem_res.P0_commit; ocsd_trc_index_t err_idx = 0; TrcStackElem *pElem = 0; // stacked element pointer + bool contextFlush = false; err = m_out_elem.resetElemStack(); - while(m_elem_res.P0_commit && !err) + while(m_elem_res.P0_commit && !err && !contextFlush) { if (m_P0_stack.size() > 0) { pElem = m_P0_stack.back(); // get oldest element err_idx = pElem->getRootIndex(); // save index in case of error. switch (pElem->getP0Type()) { - // indicates a trace restart - beginning of trace or discontinuiuty + // indicates a trace restart - beginning of trace or discontinuiuty case P0_TRC_ON: err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_TRACE_ON); if (!err) { m_out_elem.getCurrElem().trace_on_reason = m_prev_overflow ? TRACE_ON_OVERFLOW : TRACE_ON_NORMAL; m_prev_overflow = false; 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) + if (pAddrElem) { SetInstrInfoInAddrISA(pAddrElem->getAddr().val, pAddrElem->getAddr().isa); m_need_addr = false; } } break; case P0_CTXT: { TrcStackElemCtxt *pCtxtElem = dynamic_cast(pElem); - if(pCtxtElem) + if (pCtxtElem) { etmv4_context_t ctxt = pCtxtElem->getContext(); // check this is an updated context if(ctxt.updated) { err = m_out_elem.addElem(pElem->getRootIndex()); - if (!err) + if (!err) { updateContext(pCtxtElem, outElem()); + + // updated context - need to force this to be output to the client so correct memory + // context can be used. + contextFlush = true; + + // invalidate memory accessor cacheing - force next memory access out to client to + // ensure that the correct memory context is in play when decoding subsequent atoms. + invalidateMemAccCache(); + } } } } break; case P0_EVENT: case P0_TS: case P0_CC: case P0_TS_CC: err = processTS_CC_EventElem(pElem); break; + case P0_MARKER: + err = processMarkerElem(pElem); + break; + case P0_ATOM: { TrcStackElemAtom *pAtomElem = dynamic_cast(pElem); - if(pAtomElem) + if (pAtomElem) { while(!pAtomElem->isEmpty() && m_elem_res.P0_commit && !err) { ocsd_atm_val atom = pAtomElem->commitOldest(); // check if prev atom left us an indirect address target on the return stack if ((err = returnStackPop()) != OCSD_OK) break; // if address and context do instruction trace follower. // otherwise skip atom and reduce committed elements - if(!m_need_ctxt && !m_need_addr) + if (!m_need_ctxt && !m_need_addr) { err = processAtom(atom); } m_elem_res.P0_commit--; // mark committed } - if(!pAtomElem->isEmpty()) + 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 ((err = returnStackPop()) != OCSD_OK) break; err = processException(); // output trace + exception elements. m_elem_res.P0_commit--; break; case P0_EXCEP_RET: err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EXCEPTION_RET); if (!err) { if (pElem->isP0()) // are we on a core that counts ERET as P0? m_elem_res.P0_commit--; } break; case P0_FUNC_RET: // func ret is V8M - data trace only - hint that data has been popped off the stack. // at this point nothing to do till the decoder starts handling data trace. if (pElem->isP0()) m_elem_res.P0_commit--; break; + case P0_SRC_ADDR: + err = processSourceAddress(); + m_elem_res.P0_commit--; + break; + case P0_Q: err = processQElement(); m_elem_res.P0_commit--; + break; + + case P0_TRANS_START: + if (m_config->commTransP0()) + m_elem_res.P0_commit--; + case P0_TRANS_COMMIT: + case P0_TRANS_FAIL: + case P0_TRANS_TRACE_INIT: + err = processTransElem(pElem); + break; + + case P0_ITE: + err = processITEElem(pElem); break; } if(bPopElem) m_P0_stack.delete_back(); // remove element from stack; } else { - // too few elements for commit operation - decode error. - err = OCSD_ERR_COMMIT_PKT_OVERRUN; - LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_COMMIT_PKT_OVERRUN,err_idx,m_CSID,"Not enough elements to commit")); + // too few elements for commit operation - decode error. + err = handlePacketSeqErr(OCSD_ERR_COMMIT_PKT_OVERRUN, err_idx, "Not enough elements to commit"); } } // reduce the spec depth by number of comitted elements m_curr_spec_depth -= (num_commit_req-m_elem_res.P0_commit); return err; } ocsd_err_t TrcPktDecodeEtmV4I::returnStackPop() { ocsd_err_t err = OCSD_OK; ocsd_isa nextISA; if (m_return_stack.pop_pending()) { ocsd_vaddr_t popAddr = m_return_stack.pop(nextISA); if (m_return_stack.overflow()) { err = OCSD_ERR_RET_STACK_OVERFLOW; - LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, "Trace Return Stack Overflow.")); + err = handlePacketSeqErr(err, OCSD_BAD_TRC_INDEX, "Trace Return Stack Overflow."); } else { m_instr_info.instr_addr = popAddr; m_instr_info.isa = nextISA; m_need_addr = false; } } return err; } ocsd_err_t TrcPktDecodeEtmV4I::commitElemOnEOT() { ocsd_err_t err = OCSD_OK; TrcStackElem *pElem = 0; // nothing outstanding - reset the stack before we add more if (!m_out_elem.numElemToSend()) m_out_elem.resetElemStack(); while((m_P0_stack.size() > 0) && !err) { // scan for outstanding events, TS and CC, that appear before any outstanding // uncommited P0 element. 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: case P0_Q: m_P0_stack.delete_all(); break; //skip case P0_ADDR: case P0_CTXT: break; + // trans + // P0 trans - clear and stop, otherwise skip + case P0_TRANS_START: + if (m_config->commTransP0()) + m_P0_stack.delete_all(); + break; + + // non-speculative trans fail / commit - could appear at EoT after valid trace + // but without a subsequent P0 that would force output. + case P0_TRANS_FAIL: + case P0_TRANS_COMMIT: + if (m_max_spec_depth == 0 || m_curr_spec_depth == 0) + err = processTransElem(pElem); + break; + + // others - skip non P0 + case P0_TRANS_TRACE_INIT: + break; + // output case P0_EVENT: case P0_TS: case P0_CC: case P0_TS_CC: err = processTS_CC_EventElem(pElem); break; + + case P0_MARKER: + err = processMarkerElem(pElem); + break; + + case P0_ITE: + err = processITEElem(pElem); + break; } m_P0_stack.delete_back(); } if(!err) { err = m_out_elem.addElemType(m_index_curr_pkt, OCSD_GEN_TRC_ELEM_EO_TRACE); outElem().setUnSyncEOTReason(m_prev_overflow ? UNSYNC_OVERFLOW : UNSYNC_EOT); } return err; } // cancel elements. These not output ocsd_err_t TrcPktDecodeEtmV4I::cancelElements() { ocsd_err_t err = OCSD_OK; bool P0StackDone = false; // checked all P0 elements on the stack TrcStackElem *pElem = 0; // stacked element pointer EtmV4P0Stack temp; int num_cancel_req = m_elem_res.P0_cancel; while (m_elem_res.P0_cancel) { //search the stack for the newest elements if (!P0StackDone) { if (m_P0_stack.size() == 0) P0StackDone = true; else { // get the newest element pElem = m_P0_stack.front(); if (pElem->isP0()) { if (pElem->getP0Type() == P0_ATOM) { TrcStackElemAtom *pAtomElem = (TrcStackElemAtom *)pElem; // atom - cancel N atoms m_elem_res.P0_cancel -= pAtomElem->cancelNewest(m_elem_res.P0_cancel); if (pAtomElem->isEmpty()) m_P0_stack.delete_front(); // remove the element } else { m_elem_res.P0_cancel--; m_P0_stack.delete_front(); // remove the element } } else { // not P0, make a keep / remove decision switch (pElem->getP0Type()) { // keep these case P0_EVENT: case P0_TS: case P0_CC: case P0_TS_CC: + case P0_MARKER: + case P0_ITE: m_P0_stack.pop_front(false); temp.push_back(pElem); break; default: m_P0_stack.delete_front(); break; } } + if (m_P0_stack.size() == 0) + P0StackDone = true; } } // may have some unseen elements else if (m_unseen_spec_elem) { m_unseen_spec_elem--; m_elem_res.P0_cancel--; } // otherwise we have some sort of overrun else { // too few elements for commit operation - decode error. err = OCSD_ERR_COMMIT_PKT_OVERRUN; - LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, m_index_curr_pkt, m_CSID, "Not enough elements to cancel")); + err = handlePacketSeqErr(err, m_index_curr_pkt, "Not enough elements to cancel"); m_elem_res.P0_cancel = 0; break; } - - if (temp.size()) + } + + /* restore any saved elements that are unaffected by cancel. */ + if (temp.size()) + { + while (temp.size()) { - while (temp.size()) - { - pElem = temp.back(); - m_P0_stack.push_front(pElem); - temp.pop_back(false); - } + pElem = temp.back(); + m_P0_stack.push_front(pElem); + temp.pop_back(false); } } + m_curr_spec_depth -= num_cancel_req - m_elem_res.P0_cancel; return err; } // mispredict an atom ocsd_err_t TrcPktDecodeEtmV4I::mispredictAtom() { ocsd_err_t err = OCSD_OK; bool bFoundAtom = false, bDone = false; TrcStackElem *pElem = 0; m_P0_stack.from_front_init(); // init iterator at front. while (!bDone) { pElem = m_P0_stack.from_front_next(); if (pElem) { if (pElem->getP0Type() == P0_ATOM) { TrcStackElemAtom *pAtomElem = dynamic_cast(pElem); if (pAtomElem) { pAtomElem->mispredictNewest(); bFoundAtom = true; } bDone = true; } else if (pElem->getP0Type() == P0_ADDR) { // need to disregard any addresses that appear between mispredict and the atom in question m_P0_stack.erase_curr_from_front(); } } else bDone = true; } // if missed atom then either overrun error or mispredict on unseen element if (!bFoundAtom && !m_unseen_spec_elem) { err = OCSD_ERR_COMMIT_PKT_OVERRUN; - LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, m_index_curr_pkt, m_CSID, "Not found mispredict atom")); + err = handlePacketSeqErr(err, m_index_curr_pkt, "Not found mispredict atom"); + //LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, m_index_curr_pkt, m_CSID, "Not found mispredict atom")); } m_elem_res.mispredict = false; return err; } // discard elements and flush ocsd_err_t TrcPktDecodeEtmV4I::discardElements() { ocsd_err_t err = OCSD_OK; TrcStackElem *pElem = 0; // stacked element pointer // dump P0, elemnts - output remaining CC / TS while ((m_P0_stack.size() > 0) && !err) { pElem = m_P0_stack.back(); - err = processTS_CC_EventElem(pElem); + if (pElem->getP0Type() == P0_MARKER) + err = processMarkerElem(pElem); + else if (pElem->getP0Type() == P0_MARKER) + err = processITEElem(pElem); + else + err = processTS_CC_EventElem(pElem); m_P0_stack.delete_back(); } // clear all speculation info clearElemRes(); m_curr_spec_depth = 0; // set decode state m_curr_state = NO_SYNC; m_unsync_eot_info = m_prev_overflow ? UNSYNC_OVERFLOW : UNSYNC_DISCARD; // unsync so need context & address. m_need_ctxt = true; m_need_addr = true; m_elem_pending_addr = false; return err; } ocsd_err_t TrcPktDecodeEtmV4I::processTS_CC_EventElem(TrcStackElem *pElem) { ocsd_err_t err = OCSD_OK; + // ignore ts for ETE if not seen first TS marker on systems that use this. + bool bPermitTS = !m_config->eteHasTSMarker() || m_ete_first_ts_marker; switch (pElem->getP0Type()) { case P0_EVENT: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if (pParamElem) err = addElemEvent(pParamElem); } break; case P0_TS: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); - if (pParamElem) + if (pParamElem && bPermitTS) err = addElemTS(pParamElem, false); } break; case P0_CC: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if (pParamElem) err = addElemCC(pParamElem); } break; case P0_TS_CC: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); - if (pParamElem) + if (pParamElem && bPermitTS) err = addElemTS(pParamElem, true); } break; } return err; } +ocsd_err_t TrcPktDecodeEtmV4I::processMarkerElem(TrcStackElem *pElem) +{ + ocsd_err_t err = OCSD_OK; + TrcStackElemMarker *pMarkerElem = dynamic_cast(pElem); + + if (m_config->eteHasTSMarker() && (pMarkerElem->getMarker().type == ELEM_MARKER_TS)) + m_ete_first_ts_marker = true; + + if (!err) + { + err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_SYNC_MARKER); + if (!err) + m_out_elem.getCurrElem().setSyncMarker(pMarkerElem->getMarker()); + } + return err; +} + +ocsd_err_t TrcPktDecodeEtmV4I::processTransElem(TrcStackElem *pElem) +{ + ocsd_err_t err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_MEMTRANS); + if (!err) + { + outElem().setTransactionType((trace_memtrans_t)((int)OCSD_MEM_TRANS_FAIL - + ((int)P0_TRANS_FAIL - (int)pElem->getP0Type()))); + } + return err; +} + +ocsd_err_t TrcPktDecodeEtmV4I::processITEElem(TrcStackElem *pElem) +{ + ocsd_err_t err = OCSD_OK; + TrcStackElemITE *pITEElem = dynamic_cast(pElem); + + err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_INSTRUMENTATION); + if (!err) { + outElem().setITEInfo(pITEElem->getITE()); + } + return err; +} + ocsd_err_t TrcPktDecodeEtmV4I::addElemCC(TrcStackElemParam *pParamElem) { ocsd_err_t err = OCSD_OK; err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_CYCLE_COUNT); if (!err) outElem().setCycleCount(pParamElem->getParam(0)); return err; } ocsd_err_t TrcPktDecodeEtmV4I::addElemTS(TrcStackElemParam *pParamElem, bool withCC) { ocsd_err_t err = OCSD_OK; err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_TIMESTAMP); if (!err) { outElem().timestamp = (uint64_t)(pParamElem->getParam(0)) | (((uint64_t)pParamElem->getParam(1)) << 32); if (withCC) outElem().setCycleCount(pParamElem->getParam(2)); } return err; } ocsd_err_t TrcPktDecodeEtmV4I::addElemEvent(TrcStackElemParam *pParamElem) { ocsd_err_t err = OCSD_OK; err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EVENT); if (!err) { outElem().trace_event.ev_type = EVENT_NUMBERED; outElem().trace_event.ev_number = pParamElem->getParam(0); } return err; } -void TrcPktDecodeEtmV4I::setElemTraceRange(OcsdTraceElement &elemIn, const instr_range_t &addr_range, - const bool executed, ocsd_trc_index_t index) +void TrcPktDecodeEtmV4I::setElemTraceRange(OcsdTraceElement &elemIn, const instr_range_t &addr_range, + const bool executed, ocsd_trc_index_t index) +{ + setElemTraceRangeInstr(elemIn, addr_range, executed, index, m_instr_info); +} + +void TrcPktDecodeEtmV4I::setElemTraceRangeInstr(OcsdTraceElement &elemIn, const instr_range_t &addr_range, + const bool executed, ocsd_trc_index_t index, ocsd_instr_info &instr) { elemIn.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); - elemIn.setLastInstrInfo(executed, m_instr_info.type, m_instr_info.sub_type, m_instr_info.instr_size); - elemIn.setISA(m_instr_info.isa); - elemIn.setLastInstrCond(m_instr_info.is_conditional); + elemIn.setLastInstrInfo(executed, instr.type, instr.sub_type, instr.instr_size); + elemIn.setISA(instr.isa); + elemIn.setLastInstrCond(instr.is_conditional); elemIn.setAddrRange(addr_range.st_addr, addr_range.en_addr, addr_range.num_instr); if (executed) - m_instr_info.isa = m_instr_info.next_isa; + instr.isa = instr.next_isa; } ocsd_err_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom) { ocsd_err_t err; TrcStackElem *pElem = m_P0_stack.back(); // get the atom element WP_res_t WPRes; instr_range_t addr_range; + bool ETE_ERET = false; // new element for this processed atom if ((err = m_out_elem.addElem(pElem->getRootIndex())) != OCSD_OK) return err; err = traceInstrToWP(addr_range, WPRes); 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 OCSD_OK; } else { - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet.")); + err = handlePacketSeqErr(err, pElem->getRootIndex(), "Error processing atom packet."); + //LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet.")); return err; } } if(WPFound(WPRes)) { // 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 + + /* ETE does not have ERET trace packets - however to maintain the illusion if we see an ERET + output a gen elem ERET packet */ + if (isETEConfig() && (m_instr_info.sub_type == OCSD_S_INSTR_V8_ERET)) + ETE_ERET = true; } break; } setElemTraceRange(outElem(), addr_range, (atom == ATOM_E), pElem->getRootIndex()); + + if (ETE_ERET) + { + err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EXCEPTION_RET); + if (err) + return err; + } } else { // no waypoint - likely inaccessible memory range. m_need_addr = true; // need an address update if(addr_range.st_addr != addr_range.en_addr) { // some trace before we were out of memory access range setElemTraceRange(outElem(), addr_range, true, pElem->getRootIndex()); // another element for the nacc... if (WPNacc(WPRes)) err = m_out_elem.addElem(pElem->getRootIndex()); } if(WPNacc(WPRes) && !err) { outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); outElem().st_addr = m_instr_info.instr_addr; } } return err; } // Exception processor ocsd_err_t TrcPktDecodeEtmV4I::processException() { ocsd_err_t err; TrcStackElem *pElem = 0; TrcStackElemExcept *pExceptElem = 0; TrcStackElemAddr *pAddressElem = 0; TrcStackElemCtxt *pCtxtElem = 0; bool branch_target = false; // exception address implies prior branch target address - ocsd_vaddr_t excep_ret_addr; + ocsd_vaddr_t excep_ret_addr = 0; ocsd_trc_index_t excep_pkt_index; WP_res_t WPRes = WP_NOT_FOUND; + bool ETE_resetPkt = false; // grab the exception element off the stack pExceptElem = dynamic_cast(m_P0_stack.back()); // get the exception element excep_pkt_index = pExceptElem->getRootIndex(); branch_target = pExceptElem->getPrevSame(); + if (pExceptElem->getRootPkt() == ETE_PKT_I_PE_RESET) + ETE_resetPkt = true; m_P0_stack.pop_back(); // remove the exception element - pElem = m_P0_stack.back(); // look at next element. - if(pElem->getP0Type() == P0_CTXT) + // ETE reset has no follow up address, the rest of the exceptions do.... + if (!ETE_resetPkt) { - 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. - LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ, excep_pkt_index,m_CSID,"Address missing in exception packet.")); - return OCSD_ERR_BAD_PACKET_SEQ; - } - else - { - // extract address - pAddressElem = static_cast(pElem); - excep_ret_addr = pAddressElem->getAddr().val; - - // see if there is an address + optional context element implied - // prior to the exception. - if (branch_target) + pElem = m_P0_stack.back(); // look at next element. + if (pElem->getP0Type() == P0_CTXT) { - // this was a branch target address - update current setting - bool b64bit = m_instr_info.isa == ocsd_isa_aarch64; - if (pCtxtElem) { - b64bit = pCtxtElem->getContext().SF; - } + 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 + } - // as the exception address was also a branch target address then update the - // current maintained address value. This also means that there is no range to - // output before the exception packet. - m_instr_info.instr_addr = excep_ret_addr; - m_instr_info.isa = (pAddressElem->getAddr().isa == 0) ? + if (pElem->getP0Type() != P0_ADDR) + { + // no following address element - indicate processing error. + + err = handlePacketSeqErr(OCSD_ERR_BAD_PACKET_SEQ, m_index_curr_pkt, "Address missing in exception packet."); + //LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_BAD_PACKET_SEQ, excep_pkt_index, m_CSID, "Address missing in exception packet.")); + return err; + } + else + { + // extract address + pAddressElem = static_cast(pElem); + excep_ret_addr = pAddressElem->getAddr().val; + + // see if there is an address + optional context element implied + // prior to the exception. + if (branch_target) + { + // this was a branch target address - update current setting + bool b64bit = m_instr_info.isa == ocsd_isa_aarch64; + if (pCtxtElem) { + b64bit = pCtxtElem->getContext().SF; + } + + // as the exception address was also a branch target address then update the + // current maintained address value. This also means that there is no range to + // output before the exception packet. + m_instr_info.instr_addr = excep_ret_addr; + m_instr_info.isa = (pAddressElem->getAddr().isa == 0) ? (b64bit ? ocsd_isa_aarch64 : ocsd_isa_arm) : ocsd_isa_thumb2; - m_need_addr = false; + m_need_addr = false; + } } - } + } // need to output something - set up an element if ((err = m_out_elem.addElem(excep_pkt_index))) return err; // output a context element if present if (pCtxtElem) { updateContext(pCtxtElem, outElem()); // used the element - need another for later stages if ((err = m_out_elem.addElem(excep_pkt_index))) return err; } - // if the preferred return address is not the end of the last output range... - if (m_instr_info.instr_addr != excep_ret_addr) - { - bool range_out = false; - instr_range_t addr_range; + if (!ETE_resetPkt) + { + // if the preferred return address is not the end of the last output range... + if (m_instr_info.instr_addr != excep_ret_addr) + { + bool range_out = false; + instr_range_t addr_range; - // look for match to return address. - err = traceInstrToWP(addr_range, WPRes, true, excep_ret_addr); + // look for match to return address. + err = traceInstrToWP(addr_range, WPRes, true, excep_ret_addr); - if(err != OCSD_OK) - { - if(err == OCSD_ERR_UNSUPPORTED_ISA) + if (err != OCSD_OK) { - m_need_addr = true; - m_need_ctxt = true; - LogError(ocsdError(OCSD_ERR_SEV_WARN,err, excep_pkt_index,m_CSID,"Warning: unsupported instruction set processing exception packet.")); + if (err == OCSD_ERR_UNSUPPORTED_ISA) + { + m_need_addr = true; + m_need_ctxt = true; + LogError(ocsdError(OCSD_ERR_SEV_WARN, err, excep_pkt_index, m_CSID, "Warning: unsupported instruction set processing exception packet.")); + } + else + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, excep_pkt_index, m_CSID, "Error processing exception packet.")); + } + return err; + } + + if (WPFound(WPRes)) + { + // waypoint address found - output range + setElemTraceRange(outElem(), addr_range, true, excep_pkt_index); + range_out = true; } else { - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err, excep_pkt_index,m_CSID,"Error processing exception packet.")); + // no waypoint - likely inaccessible memory range. + m_need_addr = true; // need an address update + + if (addr_range.st_addr != addr_range.en_addr) + { + // some trace before we were out of memory access range + setElemTraceRange(outElem(), addr_range, true, excep_pkt_index); + range_out = true; + } } - return err; - } - if(WPFound(WPRes)) - { - // waypoint address found - output range - setElemTraceRange(outElem(), addr_range, true, excep_pkt_index); - range_out = true; - } - else - { - // no waypoint - likely inaccessible memory range. - m_need_addr = true; // need an address update - - if(addr_range.st_addr != addr_range.en_addr) + // used the element need another for NACC or EXCEP. + if (range_out) { - // some trace before we were out of memory access range - setElemTraceRange(outElem(), addr_range, true, excep_pkt_index); - range_out = true; + if ((err = m_out_elem.addElem(excep_pkt_index))) + return err; } } - // used the element need another for NACC or EXCEP. - if (range_out) + // watchpoint walk resulted in inaccessible memory call... + if (WPNacc(WPRes)) { + + outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + outElem().st_addr = m_instr_info.instr_addr; + + // used the element - need another for the final exception packet. if ((err = m_out_elem.addElem(excep_pkt_index))) return err; } } - - // watchpoint walk resulted in inaccessible memory call... - if (WPNacc(WPRes)) - { - - outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); - outElem().st_addr = m_instr_info.instr_addr; - // used the element - need another for the final exception packet. - if ((err = m_out_elem.addElem(excep_pkt_index))) - return err; - } - // output exception element. outElem().setType(OCSD_GEN_TRC_ELEM_EXCEPTION); // add end address as preferred return address to end addr in element outElem().en_addr = excep_ret_addr; outElem().excep_ret_addr = 1; outElem().excep_ret_addr_br_tgt = branch_target; outElem().exception_number = pExceptElem->getExcepNum(); m_P0_stack.delete_popped(); // clear the used elements from the stack return err; } ocsd_err_t TrcPktDecodeEtmV4I::processQElement() { ocsd_err_t err = OCSD_OK; TrcStackQElem *pQElem; etmv4_addr_val_t QAddr; // address where trace restarts int iCount = 0; pQElem = dynamic_cast(m_P0_stack.back()); // get the exception element m_P0_stack.pop_back(); // remove the Q element. if (!pQElem->hasAddr()) // no address - it must be next on the stack.... { TrcStackElemAddr *pAddressElem = 0; TrcStackElemCtxt *pCtxtElem = 0; TrcStackElem *pElem = 0; 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. err = OCSD_ERR_BAD_PACKET_SEQ; LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pQElem->getRootIndex(), m_CSID, "Address missing in Q packet.")); m_P0_stack.delete_popped(); return err; } pAddressElem = dynamic_cast(pElem); QAddr = pAddressElem->getAddr(); m_P0_stack.pop_back(); // remove the address element m_P0_stack.delete_popped(); // clear used elements // return the context element for processing next time. if (pCtxtElem) { // need a new copy at the back - old one will be deleted as popped. m_P0_stack.createContextElem(pCtxtElem->getRootPkt(), pCtxtElem->getRootIndex(), pCtxtElem->getContext(),true); } } else QAddr = pQElem->getAddr(); // process the Q element with address. iCount = pQElem->getInstrCount(); bool isBranch = false; // need to output something - set up an element if ((err = m_out_elem.addElem(pQElem->getRootIndex()))) return err; instr_range_t addr_range; addr_range.st_addr = addr_range.en_addr = m_instr_info.instr_addr; addr_range.num_instr = 0; // walk iCount instructions for (int i = 0; i < iCount; i++) { uint32_t opcode; uint32_t bytesReq = 4; err = accessMemory(m_instr_info.instr_addr, getCurrMemSpace(), &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; addr_range.num_instr++; isBranch = (m_instr_info.type == OCSD_INSTR_BR) || (m_instr_info.type == OCSD_INSTR_BR_INDIRECT); // on a branch no way of knowing if taken - bail out if (isBranch) break; } else break; // missing memory } if (err == OCSD_OK) { bool inCompleteRange = true; if (iCount && (addr_range.num_instr == (unsigned)iCount)) { if ((m_instr_info.instr_addr == QAddr.val) || // complete range (isBranch)) // or ends on branch - only way we know if branch taken. { // output a range and continue inCompleteRange = false; // update the range decoded address in the output packet. addr_range.en_addr = m_instr_info.instr_addr; setElemTraceRange(outElem(), addr_range, true, pQElem->getRootIndex()); } } if (inCompleteRange) { // unknown instructions executed. addr_range.en_addr = QAddr.val; addr_range.num_instr = iCount; outElem().setType(OCSD_GEN_TRC_ELEM_I_RANGE_NOPATH); outElem().setAddrRange(addr_range.st_addr, addr_range.en_addr, addr_range.num_instr); outElem().setISA(calcISA(m_is_64bit, QAddr.isa)); } // after the Q element, tracing resumes at the address supplied SetInstrInfoInAddrISA(QAddr.val, QAddr.isa); m_need_addr = false; } else { // output error and halt decode. LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pQElem->getRootIndex(), m_CSID, "Error processing Q packet")); } m_P0_stack.delete_popped(); return err; } +ocsd_err_t TrcPktDecodeEtmV4I::processSourceAddress() +{ + ocsd_err_t err = OCSD_OK; + TrcStackElemAddr *pElem = dynamic_cast(m_P0_stack.back()); // get the address element + etmv4_addr_val_t srcAddr = pElem->getAddr(); + uint32_t opcode, bytesReq = 4; + ocsd_vaddr_t currAddr = m_instr_info.instr_addr; // get the latest decoded address. + instr_range_t out_range; + bool bSplitRangeOnN = getComponentOpMode() & ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS ? true : false; + + // check we can read instruction @ source address + err = accessMemory(srcAddr.val, getCurrMemSpace(), &bytesReq, (uint8_t *)&opcode); + if (err != OCSD_OK) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Mem access error processing source address packet.")); + return err; + } + + if (bytesReq != 4) + { + // can't access - no bytes returned - output nacc. + err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_ADDR_NACC); + outElem().setAddrStart(srcAddr.val); + return err; + } + + // analyze opcode @ source address. + m_instr_info.opcode = opcode; + m_instr_info.instr_addr = srcAddr.val; + err = instrDecode(&m_instr_info); + if (err != OCSD_OK) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Instruction decode error processing source address packet.")); + return err; + } + m_instr_info.instr_addr += m_instr_info.instr_size; + + // initial instruction count for the range. + out_range.num_instr = 1; + + // calculate range traced... + if (m_need_addr || (currAddr > srcAddr.val)) + { + // we were waiting for a target address, or missing trace + // that indicates how we got to the source address. + m_need_addr = false; + out_range.st_addr = srcAddr.val; + } + else + out_range.st_addr = currAddr; + out_range.en_addr = m_instr_info.instr_addr; + + // count instructions + if (out_range.en_addr - out_range.st_addr > m_instr_info.instr_size) + { + if ((m_instr_info.isa != ocsd_isa_thumb2) && !bSplitRangeOnN) + { + // all 4 byte instructions - just calculate... + out_range.num_instr = (uint32_t)(out_range.en_addr - out_range.st_addr) / 4; + } + else + { + // need to count T32 - 2 or 4 byte instructions or we are spotting N atoms + ocsd_instr_info instr; // going back to start of range so make a copy of info. + bool bMemAccErr = false; + + instr.instr_addr = out_range.st_addr; + instr.isa = m_instr_info.isa; + instr.pe_type = m_instr_info.pe_type; + instr.dsb_dmb_waypoints = m_instr_info.dsb_dmb_waypoints; + instr.wfi_wfe_branch = m_instr_info.wfi_wfe_branch; + out_range.num_instr = 0; + + while ((instr.instr_addr < out_range.en_addr) && !bMemAccErr) + { + bytesReq = 4; + err = accessMemory(instr.instr_addr, getCurrMemSpace(), &bytesReq, (uint8_t *)&opcode); + if (err != OCSD_OK) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Mem access error processing source address packet.")); + return err; + } + + if (bytesReq == 4) + { + instr.opcode = opcode; + err = instrDecode(&instr); + if (err != OCSD_OK) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Instruction decode error processing source address packet.")); + return err; + } + + instr.instr_addr += instr.instr_size; + out_range.num_instr++; + + /* if we are doing N atom ranges ...*/ + if (bSplitRangeOnN && (instr.instr_addr < out_range.en_addr)) + { + if (instr.type != OCSD_INSTR_OTHER) + { + instr_range_t mid_range = out_range; + mid_range.en_addr = instr.instr_addr; + + err = m_out_elem.addElem(pElem->getRootIndex()); + if (err) + return err; + setElemTraceRangeInstr(outElem(), mid_range, false, pElem->getRootIndex(), instr); + + out_range.st_addr = mid_range.en_addr; + out_range.num_instr = 0; + } + } + } + else + { + // something inaccessible between last and current... + bMemAccErr = true; + + err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_ADDR_NACC); + if (err) + return err; + outElem().setAddrStart(srcAddr.val); + + // force range to the one instruction + out_range.num_instr = 1; + out_range.st_addr = srcAddr.val; + out_range.en_addr = m_instr_info.instr_addr; // instr after the decoded instruction @ srcAddr. + } + } + } + } + + // got to the source address - output trace range, and instruction as E atom. + switch (m_instr_info.type) + { + case OCSD_INSTR_BR: + if (m_instr_info.is_link) + m_return_stack.push(m_instr_info.instr_addr, m_instr_info.isa); + m_instr_info.instr_addr = m_instr_info.branch_addr; + break; + + case OCSD_INSTR_BR_INDIRECT: + m_need_addr = true; // indirect branch taken - need new address. + if (m_instr_info.is_link) + m_return_stack.push(m_instr_info.instr_addr, m_instr_info.isa); + m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen + break; + } + m_instr_info.isa = m_instr_info.next_isa; + + // set the trace range element. + m_out_elem.addElem(pElem->getRootIndex()); + setElemTraceRange(outElem(), out_range, true, pElem->getRootIndex()); + return err; +} + void TrcPktDecodeEtmV4I::SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa) { m_instr_info.instr_addr = addr_val; m_instr_info.isa = calcISA(m_is_64bit, isa); } // trace an instruction range to a waypoint - and set next address to restart from. ocsd_err_t TrcPktDecodeEtmV4I::traceInstrToWP(instr_range_t &range, WP_res_t &WPRes, const bool traceToAddrNext /*= false*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/) { uint32_t opcode; uint32_t bytesReq; ocsd_err_t err = OCSD_OK; range.st_addr = range.en_addr = m_instr_info.instr_addr; range.num_instr = 0; WPRes = WP_NOT_FOUND; while(WPRes == WP_NOT_FOUND) { // start off by reading next opcode; bytesReq = 4; err = accessMemory(m_instr_info.instr_addr, getCurrMemSpace(),&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; range.num_instr++; // either walking to match the next instruction address or a real watchpoint if (traceToAddrNext) { if (m_instr_info.instr_addr == nextAddrMatch) WPRes = WP_FOUND; } else if (m_instr_info.type != OCSD_INSTR_OTHER) WPRes = WP_FOUND; } else { // not enough memory accessible. WPRes = WP_NACC; } } // update the range decoded address in the output packet. range.en_addr = m_instr_info.instr_addr; return err; } void TrcPktDecodeEtmV4I::updateContext(TrcStackElemCtxt *pCtxtElem, OcsdTraceElement &elem) { etmv4_context_t ctxt = pCtxtElem->getContext(); elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); // map to output element and local saved state. m_is_64bit = (ctxt.SF != 0); elem.context.bits64 = ctxt.SF; m_is_secure = (ctxt.NS == 0); - elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure; + if (ctxt.NSE) + elem.context.security_level = ctxt.NS ? ocsd_sec_realm : ocsd_sec_root; + else + elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure; elem.context.exception_level = (ocsd_ex_level)ctxt.EL; elem.context.el_valid = 1; if(ctxt.updated_c) { elem.context.ctxt_id_valid = 1; m_context_id = elem.context.context_id = ctxt.ctxtID; } if(ctxt.updated_v) { elem.context.vmid_valid = 1; m_vmid_id = elem.context.vmid = ctxt.VMID; } // need to update ISA in case context follows address. elem.isa = m_instr_info.isa = calcISA(m_is_64bit, pCtxtElem->getIS()); m_need_ctxt = false; } -ocsd_err_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason) +ocsd_err_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason, ocsd_trc_index_t index /* = OCSD_BAD_TRC_INDEX */) { - ocsd_err_t err = OCSD_OK; + ocsd_err_severity_t sev = OCSD_ERR_SEV_WARN; + if (getComponentOpMode() & OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) + sev = OCSD_ERR_SEV_ERROR; - if(getComponentOpMode() & OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) - { - // error out - stop decoding - err = OCSD_ERR_BAD_DECODE_PKT; - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,reason)); - } - else + return handlePacketErr(OCSD_ERR_BAD_DECODE_PKT, sev, index, reason); +} + +ocsd_err_t TrcPktDecodeEtmV4I::handlePacketSeqErr(ocsd_err_t err, ocsd_trc_index_t index, const char *reason) +{ + return handlePacketErr(err, OCSD_ERR_SEV_ERROR, index, reason); +} + +ocsd_err_t TrcPktDecodeEtmV4I::handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason) +{ + bool resetOnBadPackets = true; + + if(getComponentOpMode() & OCSD_OPFLG_PKTDEC_HALT_BAD_PKTS) + resetOnBadPackets = false; + + LogError(ocsdError(sev, err, index, getCoreSightTraceID(), reason)); + + if (resetOnBadPackets) { - LogError(ocsdError(OCSD_ERR_SEV_WARN, OCSD_ERR_BAD_DECODE_PKT, reason)); // switch to unsync - clear decode state resetDecoder(); m_curr_state = NO_SYNC; m_unsync_eot_info = UNSYNC_BAD_PACKET; + err = OCSD_OK; } return err; + } + inline ocsd_mem_space_acc_t TrcPktDecodeEtmV4I::getCurrMemSpace() { static ocsd_mem_space_acc_t SMemSpace[] = { OCSD_MEM_SPACE_EL1S, OCSD_MEM_SPACE_EL1S, OCSD_MEM_SPACE_EL2S, OCSD_MEM_SPACE_EL3 }; static ocsd_mem_space_acc_t NSMemSpace[] = { OCSD_MEM_SPACE_EL1N, OCSD_MEM_SPACE_EL1N, OCSD_MEM_SPACE_EL2, OCSD_MEM_SPACE_EL3 }; /* if no valid EL value - just use S/NS */ if (!outElem().context.el_valid) return m_is_secure ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N; /* mem space according to EL + S/NS */ int el = (int)(outElem().context.exception_level) & 0x3; return m_is_secure ? SMemSpace[el] : NSMemSpace[el]; } /* End of File trc_pkt_decode_etmv4i.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 index 853fde499a1b..825b5f79e41b 100644 --- a/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp @@ -1,678 +1,762 @@ /* * \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() { + protocol_version = 0x42; // min protocol version. } 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: case ETM4_PKT_I_RESERVED_CFG: 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: + case ETE_PKT_I_SRC_ADDR_L_32IS0: + case ETE_PKT_I_SRC_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: + case ETE_PKT_I_SRC_ADDR_L_64IS0: + case ETE_PKT_I_SRC_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: + case ETE_PKT_I_SRC_ADDR_S_IS0: + case ETE_PKT_I_SRC_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: + case ETE_PKT_I_SRC_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; - oss << " { CC." << std::dec << trace_info.bits.cc_enabled << " }"; + oss << " { CC." << std::dec << trace_info.bits.cc_enabled; + if (isETE()) + oss << ", TSTATE." << std::dec << trace_info.bits.in_trans_state; + oss << " }"; 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; case ETM4_PKT_I_CANCEL_F1: { std::ostringstream oss; oss << "; Cancel(" << std::dec << cancel_elements << ")"; str += oss.str(); } break; case ETM4_PKT_I_CANCEL_F1_MISPRED: { std::ostringstream oss; oss << "; Cancel(" << std::dec << cancel_elements << "), Mispredict"; str += oss.str(); } break; case ETM4_PKT_I_MISPREDICT: { std::ostringstream oss; oss << "; "; if (atom.num) { atomSeq(valStr); oss << "Atom: " << valStr << ", "; } oss << "Mispredict"; str += oss.str(); } break; case ETM4_PKT_I_CANCEL_F2: { std::ostringstream oss; oss << "; "; if (atom.num) { atomSeq(valStr); oss << "Atom: " << valStr << ", "; } oss << "Cancel(1), Mispredict"; str += oss.str(); } break; case ETM4_PKT_I_CANCEL_F3: { std::ostringstream oss; oss << "; "; if (atom.num) { oss << "Atom: E, "; } oss << "Cancel(" << std::dec << cancel_elements << "), Mispredict"; str += oss.str(); } break; case ETM4_PKT_I_COMMIT: { std::ostringstream oss; oss << "; Commit(" << std::dec << commit_elements << ")"; str += oss.str(); } break; case ETM4_PKT_I_Q: { std::ostringstream oss; if (Q_pkt.count_present) { oss << "; Count(" << std::dec << Q_pkt.q_count << ")"; str += oss.str(); } else str += "; Count(Unknown)"; if (Q_pkt.addr_match) { addrMatchIdx(valStr); str += "; " + valStr; } if (Q_pkt.addr_present || Q_pkt.addr_match) { 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; } } break; + + case ETE_PKT_I_ITE: + { + std::ostringstream oss; + oss << "; EL" << std::dec << (int)ite_pkt.el << "; Payload=0x" << std::hex << ite_pkt.value; + 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_UNKNOWN"; const char *pDesc = "Unknown Packet Header"; switch(type) { case ETM4_PKT_I_NOTSYNC: pName = "I_NOT_SYNC"; pDesc = "I Stream not synchronised"; 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_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_RESERVED: pName = "I_RESERVED"; pDesc = "Reserved Packet Header"; break; case ETM4_PKT_I_RESERVED_CFG: pName = "I_RESERVED_CFG"; pDesc = "Reserved header for current configuration."; break; case ETM4_PKT_I_EXTENSION: pName = "I_EXTENSION"; pDesc = "Extension packet header."; break; case ETM4_PKT_I_TRACE_INFO: pName = "I_TRACE_INFO"; pDesc = "Trace Info."; break; case ETM4_PKT_I_TIMESTAMP: pName = "I_TIMESTAMP"; pDesc = "Timestamp."; break; case ETM4_PKT_I_TRACE_ON: pName = "I_TRACE_ON"; pDesc = "Trace On."; break; case ETM4_PKT_I_FUNC_RET: pName = "I_FUNC_RET"; pDesc = "V8M - function return."; 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 ETE_PKT_I_TRANS_ST: + pName = "I_TRANS_ST"; + pDesc = "Transaction Start."; + break; + + case ETE_PKT_I_TRANS_COMMIT: + pName = "I_TRANS_COMMIT"; + pDesc = "Transaction Commit."; + 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_COMMIT: pName = "I_COMMIT"; pDesc = "Commit"; break; case ETM4_PKT_I_CANCEL_F1: pName = "I_CANCEL_F1"; pDesc = "Cancel Format 1."; break; case ETM4_PKT_I_CANCEL_F1_MISPRED: pName = "I_CANCEL_F1_MISPRED"; pDesc = "Cancel Format 1 + Mispredict."; break; case ETM4_PKT_I_MISPREDICT: pName = "I_MISPREDICT"; pDesc = "Mispredict."; 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_COND_I_F2: pName = "I_COND_I_F2"; pDesc = "Conditional Instruction, format 2."; break; case ETM4_PKT_I_COND_FLUSH: pName = "I_COND_FLUSH"; pDesc = "Conditional Flush."; break; case ETM4_PKT_I_COND_RES_F4: pName = "I_COND_RES_F4"; pDesc = "Conditional Result, format 4."; 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_F1: pName = "I_COND_RES_F1"; pDesc = "Conditional Result, format 1."; 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_F3: pName = "I_COND_I_F3"; pDesc = "Conditional Instruction, format 3."; break; case ETM4_PKT_I_IGNORE: pName = "I_IGNORE"; pDesc = "Ignore."; break; case ETM4_PKT_I_EVENT: pName = "I_EVENT"; pDesc = "Trace Event."; break; case ETM4_PKT_I_CTXT: pName = "I_CTXT"; pDesc = "Context Packet."; 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 ETE_PKT_I_TS_MARKER: + pName = "I_TS_MARKER"; + pDesc = "Timestamp Marker"; + break; + case ETM4_PKT_I_ADDR_MATCH: pName = "I_ADDR_MATCH"; pDesc = "Exact Address Match."; 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_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_Q: pName = "I_Q"; pDesc = "Q Packet."; break; + case ETE_PKT_I_SRC_ADDR_MATCH: + pName = "I_SRC_ADDR_MATCH"; + pDesc = "Exact Source Address Match."; + break; + + case ETE_PKT_I_SRC_ADDR_S_IS0: + pName = "I_SRC_ADDR_S_IS0"; + pDesc = "Source Address, Short, IS0."; + break; + + case ETE_PKT_I_SRC_ADDR_S_IS1: + pName = "I_SRC_ADDR_S_IS1"; + pDesc = "Source Address, Short, IS1."; + break; + + case ETE_PKT_I_SRC_ADDR_L_32IS0: + pName = "I_SCR_ADDR_L_32IS0"; + pDesc = "Source Address, Long, 32 bit, IS0."; + break; + + case ETE_PKT_I_SRC_ADDR_L_32IS1: + pName = "I_SRC_ADDR_L_32IS1"; + pDesc = "Source Address, Long, 32 bit, IS1."; + break; + + case ETE_PKT_I_SRC_ADDR_L_64IS0: + pName = "I_SRC_ADDR_L_64IS0"; + pDesc = "Source Address, Long, 64 bit, IS0."; + break; + + case ETE_PKT_I_SRC_ADDR_L_64IS1: + pName = "I_SRC_ADDR_L_64IS1"; + pDesc = "Source Address, Long, 64 bit, IS1."; + break; + case ETM4_PKT_I_ATOM_F6: pName = "I_ATOM_F6"; pDesc = "Atom format 6."; break; case ETM4_PKT_I_ATOM_F5: pName = "I_ATOM_F5"; pDesc = "Atom format 5."; break; case ETM4_PKT_I_ATOM_F2: pName = "I_ATOM_F2"; pDesc = "Atom format 2."; break; case ETM4_PKT_I_ATOM_F4: pName = "I_ATOM_F4"; pDesc = "Atom format 4."; break; case ETM4_PKT_I_ATOM_F1: pName = "I_ATOM_F1"; pDesc = "Atom format 1."; break; case ETM4_PKT_I_ATOM_F3: pName = "I_ATOM_F3"; pDesc = "Atom format 3."; 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; + case ETE_PKT_I_PE_RESET: + pName = "I_PE_RESET"; + pDesc = "PE Reset."; + break; + + case ETE_PKT_I_TRANS_FAIL: + pName = "I_TRANS_FAIL"; + pDesc = "Transaction Fail."; + break; + + case ETE_PKT_I_ITE: + pName = "I_ITE"; + pDesc = "Instrumentation"; + break; + default: 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_etmv4i.cpp b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp index d8c7d84667d1..d767bdc85643 100644 --- a/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp +++ b/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp @@ -1,1667 +1,1803 @@ /* * \file trc_pkt_proc_etmv4i.cpp * \brief OpenCSD : Packet processor for ETMv4 * * \copyright Copyright (c) 2015, 2019, 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 "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; +// test defines - if testing with ETMv4 sources, disable error on ERET. +// #define ETE_TRACE_ERET_AS_IGNORE + /* trace etmv4 packet processing class */ TrcPktProcEtmV4I::TrcPktProcEtmV4I() : TrcPktProcBase(ETMV4I_PKTS_NAME), m_isInit(false), m_first_trace_info(false) { m_supported_op_flags = ETMV4_SUPPORTED_OP_FLAGS; } TrcPktProcEtmV4I::TrcPktProcEtmV4I(int instIDNum) : TrcPktProcBase(ETMV4I_PKTS_NAME, instIDNum), m_isInit(false), m_first_trace_info(false) { m_supported_op_flags = ETMV4_SUPPORTED_OP_FLAGS; } TrcPktProcEtmV4I::~TrcPktProcEtmV4I() { } ocsd_err_t TrcPktProcEtmV4I::onProtocolConfig() { InitProcessorState(); m_config = *TrcPktProcBase::getProtocolConfig(); BuildIPacketTable(); // packet table based on config + m_curr_packet.setProtocolVersion(m_config.FullVersion()); m_isInit = true; + statsInit(); return OCSD_OK; } ocsd_datapath_resp_t TrcPktProcEtmV4I::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; if (!m_isInit) return OCSD_RESP_FATAL_NOT_INIT; m_trcIn.init(dataBlockSize, pDataBlock, &m_currPacketData); m_blockIndex = index; bool done = false; uint8_t nextByte; do { try { while ( (!m_trcIn.empty() || (m_process_state == SEND_PKT)) && OCSD_DATA_RESP_IS_CONT(resp) ) { switch (m_process_state) { case PROC_HDR: m_packet_index = m_blockIndex + m_trcIn.processed(); if (m_is_sync) { nextByte = m_trcIn.peekNextByte(); m_pIPktFn = m_i_table[nextByte].pptkFn; m_curr_packet.type = m_i_table[nextByte].pkt_type; } else { // unsynced - process data until we see a sync point m_pIPktFn = &TrcPktProcEtmV4I::iNotSync; m_curr_packet.type = ETM4_PKT_I_NOTSYNC; } m_process_state = PROC_DATA; case PROC_DATA: // loop till full packet or no more data... while (!m_trcIn.empty() && (m_process_state == PROC_DATA)) { nextByte = m_trcIn.peekNextByte(); m_trcIn.copyByteToPkt(); // move next byte into the packet (this->*m_pIPktFn)(nextByte); } 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; } } done = true; } catch(ocsdError &err) { done = true; 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. + if (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR) + statsAddBadHdrCount(1); + else + statsAddBadSeqCount(1); m_process_state = SEND_PKT; done = false; } else { // bail out on any other error. resp = OCSD_RESP_FATAL_INVALID_DATA; } } catch(...) { done = true; /// 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."); LogError(fatal); } } while (!done); + statsAddTotalCount(m_trcIn.processed()); *numBytesProcessed = m_trcIn.processed(); return resp; } ocsd_datapath_resp_t TrcPktProcEtmV4I::onEOT() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; if (!m_isInit) return OCSD_RESP_FATAL_NOT_INIT; // 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 TrcPktProcEtmV4I::onReset() { if (!m_isInit) return OCSD_RESP_FATAL_NOT_INIT; // prepare for new decoding session InitProcessorState(); return OCSD_RESP_CONT; } ocsd_datapath_resp_t TrcPktProcEtmV4I::onFlush() { if (!m_isInit) return OCSD_RESP_FATAL_NOT_INIT; // packet processor never holds on to flushable data (may have partial packet, // but any full packets are immediately sent) return OCSD_RESP_CONT; } void TrcPktProcEtmV4I::InitPacketState() { m_currPacketData.clear(); m_curr_packet.initNextPacket(); // clear for next packet. m_update_on_unsync_packet_index = 0; } void TrcPktProcEtmV4I::InitProcessorState() { InitPacketState(); m_pIPktFn = &TrcPktProcEtmV4I::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 TrcPktProcEtmV4I::outputPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; resp = outputOnAllInterfaces(m_packet_index,&m_curr_packet,&m_curr_packet.type,m_currPacketData); return resp; } ocsd_datapath_resp_t TrcPktProcEtmV4I::outputUnsyncedRawPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; - - outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]); + statsAddUnsyncCount(m_dump_unsynced_bytes); + outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]); if(!m_sent_notsync_packet) { resp = 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 TrcPktProcEtmV4I::iNotSync(const uint8_t lastByte) { // 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_trcIn.processed() - 1; } else m_packet_index = m_blockIndex + m_trcIn.processed() - 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_trcIn.processed(); } } void TrcPktProcEtmV4I::iPktNoPayload(const uint8_t lastByte) { // some expansion may be required... switch(m_curr_packet.type) { case ETM4_PKT_I_ADDR_MATCH: + case ETE_PKT_I_SRC_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: case ETM4_PKT_I_FUNC_RET: + case ETE_PKT_I_TRANS_ST: + case ETE_PKT_I_TRANS_COMMIT: case ETM4_PKT_I_IGNORE: default: break; } m_process_state = SEND_PKT; // now just send it.... } void TrcPktProcEtmV4I::iPktReserved(const uint8_t lastByte) { m_curr_packet.updateErrType(ETM4_PKT_I_RESERVED, lastByte); // swap type for err type throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,m_config.getTraceID()); } void TrcPktProcEtmV4I::iPktInvalidCfg(const uint8_t lastByte) { m_curr_packet.updateErrType(ETM4_PKT_I_RESERVED_CFG, lastByte); // swap type for err type throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PCKT_HDR, m_packet_index, m_config.getTraceID()); } void TrcPktProcEtmV4I::iPktExtension(const uint8_t lastByte) { if(m_currPacketData.size() == 2) { // not sync and not next by 0x00 - not sync sequence if(!m_is_sync && (lastByte != 0x00)) { m_pIPktFn = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 TrcPktProcEtmV4I::iPktASync(const uint8_t lastByte) { 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 = &TrcPktProcEtmV4I::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 TrcPktProcEtmV4I::iPktTraceInfo(const uint8_t lastByte) { 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; + else if (!(m_tinfo_sections.sectFlags & TINFO_WNDW_SECT)) + m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_WNDW_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); } + if ((presSect & TINFO_WNDW_SECT) && (idx < m_currPacketData.size())) + { + idx += extractContField(m_currPacketData, idx, fieldVal); + /* Trace commit window unsupported in current ETE versions */ + } m_process_state = SEND_PKT; m_first_trace_info = true; } } void TrcPktProcEtmV4I::iPktTimestamp(const uint8_t lastByte) { // 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; + int ts_bytes = extractTSField64(m_currPacketData, idx, tsVal); + int ts_bits; + + // if ts_bytes 8 or less, then cont bits on each byte, otherwise full 64 bit value for 9 bytes + ts_bits = ts_bytes < 9 ? 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 TrcPktProcEtmV4I::iPktException(const uint8_t lastByte) { uint16_t excep_type = 0; switch(m_currPacketData.size()) { case 1: m_excep_size = 3; break; case 2: if((lastByte & 0x80) == 0x00) m_excep_size = 2; + // ETE exception reset or trans failed + if (m_config.MajVersion() >= 0x5) + { + excep_type = (m_currPacketData[1] >> 1) & 0x1F; + if ((excep_type == 0x0) || (excep_type == 0x18)) + m_excep_size = 3; + } break; } if(m_currPacketData.size() == (unsigned)m_excep_size) { 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; + // ETE exception reset or trans failed + if (m_config.MajVersion() >= 0x5) + { + if ((excep_type == 0x0) || (excep_type == 0x18)) + { + m_curr_packet.set64BitAddress(0, 0); + if (excep_type == 0x18) + m_curr_packet.setType(ETE_PKT_I_TRANS_FAIL); + else + m_curr_packet.setType(ETE_PKT_I_PE_RESET); + } + } // allow the standard address packet handlers to process the address packet field for the exception. } } void TrcPktProcEtmV4I::iPktCycleCntF123(const uint8_t lastByte) { ocsd_etmv4_i_pkt_type format = m_curr_packet.type; 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 TrcPktProcEtmV4I::iPktSpeclRes(const uint8_t lastByte) { 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); else m_curr_packet.setCancelElements(0); 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); m_process_state = SEND_PKT; } } } void TrcPktProcEtmV4I::iPktCondInstr(const uint8_t lastByte) { 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 TrcPktProcEtmV4I::iPktCondResult(const uint8_t lastByte) { 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 TrcPktProcEtmV4I::iPktContext(const uint8_t lastByte) { bool bSendPacket = false; 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 TrcPktProcEtmV4I::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); + m_curr_packet.setContextInfo(true, (infoByte & 0x3), (infoByte >> 5) & 0x1, (infoByte >> 4) & 0x1, (infoByte >> 3) & 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 TrcPktProcEtmV4I::iPktAddrCtxt(const uint8_t lastByte) { 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 TrcPktProcEtmV4I::iPktShortAddr(const uint8_t lastByte) { if (m_currPacketData.size() == 1) { m_addr_done = false; m_addrIS = 0; - if (lastByte == ETM4_PKT_I_ADDR_S_IS1) + if ((lastByte == ETM4_PKT_I_ADDR_S_IS1) || + (lastByte == ETE_PKT_I_SRC_ADDR_S_IS1)) m_addrIS = 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 TrcPktProcEtmV4I::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 TrcPktProcEtmV4I::iPktLongAddr(const uint8_t lastByte) { 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: + case ETE_PKT_I_SRC_ADDR_L_32IS1: m_addrIS = 1; case ETM4_PKT_I_ADDR_L_32IS0: + case ETE_PKT_I_SRC_ADDR_L_32IS0: m_addrBytes = 4; break; case ETM4_PKT_I_ADDR_L_64IS1: + case ETE_PKT_I_SRC_ADDR_L_64IS1: m_addrIS = 1; case ETM4_PKT_I_ADDR_L_64IS0: + case ETE_PKT_I_SRC_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 TrcPktProcEtmV4I::iPktQ(const uint8_t lastByte) { 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; m_process_state = SEND_PKT; 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 TrcPktProcEtmV4I::iAtom(const uint8_t lastByte) { // patterns lsbit = oldest atom, ms bit = newest. static const uint32_t f4_patterns[] = { 0xE, // EEEN 0x0, // NNNN 0xA, // ENEN 0x5 // NENE }; 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; } +void TrcPktProcEtmV4I::iPktITE(const uint8_t /* lastByte */) +{ + uint64_t value; + int shift = 0; + + /* packet is always 10 bytes, Header, EL info byte, 8 bytes payload */ + if (m_currPacketData.size() == 10) { + value = 0; + for (int i = 2; i < 10; i++) { + value |= ((uint64_t)m_currPacketData[i]) << shift; + shift += 8; + } + m_curr_packet.setITE(m_currPacketData[1], value); + m_process_state = SEND_PKT; + } +} + // header byte processing is table driven. void TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::iPktReserved; } // 0x00 - extension m_i_table[0x00].pkt_type = ETM4_PKT_I_EXTENSION; m_i_table[0x00].pptkFn = &TrcPktProcEtmV4I::iPktExtension; // 0x01 - Trace info m_i_table[0x01].pkt_type = ETM4_PKT_I_TRACE_INFO; m_i_table[0x01].pptkFn = &TrcPktProcEtmV4I::iPktTraceInfo; // b0000001x - timestamp m_i_table[0x02].pkt_type = ETM4_PKT_I_TIMESTAMP; m_i_table[0x02].pptkFn = &TrcPktProcEtmV4I::iPktTimestamp; m_i_table[0x03].pkt_type = ETM4_PKT_I_TIMESTAMP; m_i_table[0x03].pptkFn = &TrcPktProcEtmV4I::iPktTimestamp; // b0000 0100 - trace on m_i_table[0x04].pkt_type = ETM4_PKT_I_TRACE_ON; m_i_table[0x04].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; // b0000 0101 - Funct ret V8M m_i_table[0x05].pkt_type = ETM4_PKT_I_FUNC_RET; if ((m_config.coreProfile() == profile_CortexM) && (OCSD_IS_V8_ARCH(m_config.archVersion())) && (m_config.FullVersion() >= 0x42)) { m_i_table[0x05].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; } // b0000 0110 - exception m_i_table[0x06].pkt_type = ETM4_PKT_I_EXCEPT; m_i_table[0x06].pptkFn = &TrcPktProcEtmV4I::iPktException; // b0000 0111 - exception return m_i_table[0x07].pkt_type = ETM4_PKT_I_EXCEPT_RTN; - m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + if (m_config.MajVersion() >= 0x5) // not valid for ETE + { +#ifdef ETE_TRACE_ERET_AS_IGNORE + m_i_table[0x07].pkt_type = ETM4_PKT_I_IGNORE; + m_i_table[0x07].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; +#else + m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; +#endif + } + else + m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + + // b00001010, b00001011 ETE TRANS packets + // b00001001 - ETE sw instrumentation packet + if (m_config.MajVersion() >= 0x5) + { + m_i_table[0x0A].pkt_type = ETE_PKT_I_TRANS_ST; + m_i_table[0x0A].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + + m_i_table[0x0B].pkt_type = ETE_PKT_I_TRANS_COMMIT; + m_i_table[0x0B].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + + // FEAT_ITE - sw instrumentation packet + if (m_config.MinVersion() >= 0x3) + { + m_i_table[0x09].pkt_type = ETE_PKT_I_ITE; + m_i_table[0x09].pptkFn = &TrcPktProcEtmV4I::iPktITE; + } + } // 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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::iPktCycleCntF123; } // b0010 0xxx - NDSM for(int i = 0; i < 8; i++) { m_i_table[0x20 + i].pkt_type = ETM4_PKT_I_NUM_DS_MKR; if (m_config.enabledDataTrace()) m_i_table[0x20+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; else m_i_table[0x20+i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } // 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; if (m_config.enabledDataTrace()) m_i_table[0x28+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; else m_i_table[0x28+i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } // b0010 1101 - commit m_i_table[0x2D].pkt_type = ETM4_PKT_I_COMMIT; m_i_table[0x2D].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes; // b0010 111x - cancel f1 (mis pred) m_i_table[0x2E].pkt_type = ETM4_PKT_I_CANCEL_F1; m_i_table[0x2E].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes; m_i_table[0x2F].pkt_type = ETM4_PKT_I_CANCEL_F1_MISPRED; m_i_table[0x2F].pptkFn = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::iPktSpeclRes; } bool bCondValid = m_config.hasCondTrace() && m_config.enabledCondITrace(); // 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; if (bCondValid) m_i_table[0x40 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr; else m_i_table[0x40 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } // b0100 0011 - cond flush m_i_table[0x43].pkt_type = ETM4_PKT_I_COND_FLUSH; if (bCondValid) m_i_table[0x43].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; else m_i_table[0x43].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; // 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; if (bCondValid) m_i_table[0x44 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult; else m_i_table[0x44 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } // 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; if (bCondValid) m_i_table[0x48 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult; else m_i_table[0x48 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } for (int i = 0; i < 3; i++) { m_i_table[0x4C + i].pkt_type = ETM4_PKT_I_COND_RES_F2; if (bCondValid) m_i_table[0x4C + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult; else m_i_table[0x4C + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } // b0101xxxx - cond res f3 for (int i = 0; i < 16; i++) { m_i_table[0x50 + i].pkt_type = ETM4_PKT_I_COND_RES_F3; if (bCondValid) m_i_table[0x50 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult; else m_i_table[0x50 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } // b011010xx - cond res f1 for (int i = 0; i < 4; i++) { m_i_table[0x68 + i].pkt_type = ETM4_PKT_I_COND_RES_F1; if (bCondValid) m_i_table[0x68 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult; else m_i_table[0x68 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } // b0110 1100 - cond instr f1 m_i_table[0x6C].pkt_type = ETM4_PKT_I_COND_I_F1; if (bCondValid) m_i_table[0x6C].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr; else m_i_table[0x6C].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; // b0110 1101 - cond instr f3 m_i_table[0x6D].pkt_type = ETM4_PKT_I_COND_I_F3; if (bCondValid) m_i_table[0x6D].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr; else m_i_table[0x6D].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; // 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; if (bCondValid) m_i_table[i + 0x6E].pptkFn = &TrcPktProcEtmV4I::iPktCondResult; else m_i_table[i + 0x6E].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; } // ETM 4.3 introduces ignore packets if (m_config.FullVersion() >= 0x43) { m_i_table[0x70].pkt_type = ETM4_PKT_I_IGNORE; m_i_table[0x70].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; } // b01110001 - b01111111 - event trace for(int i = 0; i < 15; i++) { m_i_table[0x71+i].pkt_type = ETM4_PKT_I_EVENT; m_i_table[0x71+i].pptkFn = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::iPktAddrCtxt; } + // 0b1000 1000 - ETE 1.1 TS Marker. also ETMv4.6 + if(m_config.FullVersion() >= 0x46) + { + m_i_table[0x88].pkt_type = ETE_PKT_I_TS_MARKER; + m_i_table[0x88].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + } // 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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::iPktLongAddr; } // b1010xxxx - Q packet for (int i = 0; i < 16; i++) { m_i_table[0xA0 + i].pkt_type = ETM4_PKT_I_Q; // certain Q type codes are reserved. switch (i) { case 0x3: case 0x4: case 0x7: case 0x8: case 0x9: case 0xD: case 0xE: // don't update pkt fn - leave at default reserved. break; default: // if this config supports Q elem - otherwise reserved again. if (m_config.hasQElem()) m_i_table[0xA0 + i].pptkFn = &TrcPktProcEtmV4I::iPktQ; } } + // b10110000 - b10111001 - ETE src address packets + if (m_config.FullVersion() >= 0x50) + { + for (int i = 0; i < 3; i++) + { + m_i_table[0xB0 + i].pkt_type = ETE_PKT_I_SRC_ADDR_MATCH; + m_i_table[0xB0 + i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + } + + m_i_table[0xB4].pkt_type = ETE_PKT_I_SRC_ADDR_S_IS0; + m_i_table[0xB4].pptkFn = &TrcPktProcEtmV4I::iPktShortAddr; + m_i_table[0xB5].pkt_type = ETE_PKT_I_SRC_ADDR_S_IS1; + m_i_table[0xB5].pptkFn = &TrcPktProcEtmV4I::iPktShortAddr; + + m_i_table[0xB6].pkt_type = ETE_PKT_I_SRC_ADDR_L_32IS0; + m_i_table[0xB6].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr; + m_i_table[0xB7].pkt_type = ETE_PKT_I_SRC_ADDR_L_32IS1; + m_i_table[0xB7].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr; + m_i_table[0xB8].pkt_type = ETE_PKT_I_SRC_ADDR_L_64IS0; + m_i_table[0xB8].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr; + m_i_table[0xB9].pkt_type = ETE_PKT_I_SRC_ADDR_L_64IS1; + m_i_table[0xB9].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr; + } + // 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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::iAtom; } // atom f5 m_i_table[0xF5].pkt_type = ETM4_PKT_I_ATOM_F5; m_i_table[0xF5].pptkFn = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::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 = &TrcPktProcEtmV4I::iAtom; } } unsigned TrcPktProcEtmV4I::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 TrcPktProcEtmV4I::extractContField64(const std::vector &buffer, const unsigned st_idx, uint64_t &value, const unsigned byte_limit /*= 9*/) +unsigned TrcPktProcEtmV4I::extractTSField64(const std::vector &buffer, const unsigned st_idx, uint64_t &value) { + const unsigned max_byte_idx = 8; /* the 9th byte, index 8, will use full 8 bits for value */ unsigned idx = 0; bool lastByte = false; uint8_t byteVal; + uint8_t byteValMask = 0x7f; + + /* init value */ value = 0; - while(!lastByte && (idx < byte_limit)) // max 9 bytes for 64 bit value; + while(!lastByte) // 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); + + /* detect the final byte - which uses full 8 bits as value */ + if (idx == max_byte_idx) + { + byteValMask = 0xFF; /* last byte of 9, no cont bit */ + lastByte = true; + } + else + lastByte = (byteVal & 0x80) != 0x80; + + value |= ((uint64_t)(byteVal & byteValMask)) << (idx * 7); idx++; } else { throwBadSequenceError("Invalid 64 bit continuation fields in packet"); } } + // index is the count of bytes used here. return idx; } unsigned TrcPktProcEtmV4I::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 TrcPktProcEtmV4I::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 TrcPktProcEtmV4I::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 TrcPktProcEtmV4I::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.cpp */ diff --git a/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp b/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp index 614fc1d8b45c..0e0589512002 100644 --- a/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp +++ b/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp @@ -1,235 +1,236 @@ /* * \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; struct decode_info info; info.instr_sub_type = OCSD_S_INSTR_NONE; - info.arch_version = (uint16_t)(instr_info->pe_type.arch); + info.arch_version = instr_info->pe_type.arch; switch(instr_info->isa) { case ocsd_isa_arm: err = DecodeA32(instr_info, &info); break; case ocsd_isa_thumb2: err = DecodeT32(instr_info, &info); break; case ocsd_isa_aarch64: err = DecodeA64(instr_info, &info); break; case ocsd_isa_tee: case ocsd_isa_jazelle: default: // unsupported ISA err = OCSD_ERR_UNSUPPORTED_ISA; break; } instr_info->sub_type = info.instr_sub_type; return err; } ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info, struct decode_info *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, info)) { instr_info->type = OCSD_INSTR_BR_INDIRECT; instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info); } 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, info); } 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; } } else if (instr_info->wfi_wfe_branch) { if (inst_ARM_wfiwfe(instr_info->opcode)) { instr_info->type = OCSD_INSTR_WFI_WFE; } } instr_info->is_conditional = inst_ARM_is_conditional(instr_info->opcode); return OCSD_OK; } ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info, struct decode_info *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_link(instr_info->opcode, &instr_info->is_link, info)) { 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_link(instr_info->opcode, &instr_info->is_link, info)) { 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; } } - else if (instr_info->wfi_wfe_branch) + else if (instr_info->wfi_wfe_branch && + inst_A64_wfiwfe(instr_info->opcode, info)) { - if (inst_A64_wfiwfe(instr_info->opcode)) - { - instr_info->type = OCSD_INSTR_WFI_WFE; - } + instr_info->type = OCSD_INSTR_WFI_WFE; + } + else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64)) + { + if (inst_A64_Tstart(instr_info->opcode)) + instr_info->type = OCSD_INSTR_TSTART; } instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode); return OCSD_OK; } ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info, struct decode_info *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; instr_info->is_conditional = 0; if(inst_Thumb_is_direct_branch_link(instr_info->opcode,&instr_info->is_link, &instr_info->is_conditional, info)) { 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; } else if (inst_Thumb_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info)) { instr_info->type = OCSD_INSTR_BR_INDIRECT; } 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; } } else if (instr_info->wfi_wfe_branch) { if (inst_Thumb_wfiwfe(instr_info->opcode)) { instr_info->type = OCSD_INSTR_WFI_WFE; } } 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 index 3652e84921f3..76951fd38183 100644 --- a/contrib/opencsd/decoder/source/i_dec/trc_idec_arminst.cpp +++ b/contrib/opencsd/decoder/source/i_dec/trc_idec_arminst.cpp @@ -1,661 +1,679 @@ /* * \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 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_wfiwfe(uint32_t inst) { if ( ((inst & 0xf0000000) != 0xf0000000) && ((inst & 0x0ffffffe) == 0x0320f002) ) /* WFI & WFE may be traced as branches in etm4.3 ++ */ return 1; return 0; } int inst_ARM_is_indirect_branch(uint32_t inst, struct decode_info *info) { 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 */ if ((inst & 0xFF) == 0x1E) info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */ } else if ((inst & 0x0ff000f0) == 0x01200020) { /* BXJ: in v8 this behaves like BX */ } else if ((inst & 0x0e108000) == 0x08108000) { /* POP {...,pc} or LDMxx {...,pc} */ if ((inst & 0x0FFFA000) == 0x08BD8000) /* LDMIA SP!,{...,pc} */ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; } else if ((inst & 0x0e50f000) == 0x0410f000) { /* LDR PC,imm... inc. POP {PC} */ if ( (inst & 0x01ff0000) == 0x009D0000) info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm */ } else if ((inst & 0x0e50f010) == 0x0610f000) { /* LDR PC,reg */ } else if ((inst & 0x0fe0f000) == 0x01a0f000) { /* MOV PC,rx */ if ((inst & 0x00100FFF) == 0x00E) /* ensure the S=0, LSL #0 variant - i.e plain MOV */ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC, R14 */ } 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, struct decode_info *info) { uint8_t link, cond; return inst_Thumb_is_direct_branch_link(inst, &link, &cond, info); } int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond, struct decode_info *info) { int is_direct_branch = 1; if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) { /* B (encoding T1) */ *is_cond = 1; } else if ((inst & 0xf8000000) == 0xe0000000) { /* B (encoding T2) */ } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) { /* B (encoding T3) */ *is_cond = 1; } else if ((inst & 0xf8009000) == 0xf0009000) { /* B (encoding T4); BL (encoding T1) */ if (inst & 0x00004000) { *is_link = 1; info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } } else if ((inst & 0xf800d001) == 0xf000c000) { /* BLX (imm) (encoding T2) */ *is_link = 1; info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } else if ((inst & 0xf5000000) == 0xb1000000) { /* CB(NZ) */ *is_cond = 1; } else { is_direct_branch = 0; } return is_direct_branch; } int inst_Thumb_wfiwfe(uint32_t inst) { int is_wfiwfe = 1; /* WFI, WFE may be branches in etm4.3++ */ if ((inst & 0xfffffffe) == 0xf3af8002) { /* WFI & WFE (encoding T2) */ } else if ((inst & 0xffef0000) == 0xbf200000) { /* WFI & WFE (encoding T1) */ } else { is_wfiwfe = 0; } return is_wfiwfe; } int inst_Thumb_is_indirect_branch(uint32_t inst, struct decode_info *info) { uint8_t link; return inst_Thumb_is_indirect_branch_link(inst, &link, info); } int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info) { /* See e.g. PFT Table 2-3 and Table 2-5 */ int is_branch = 1; if ((inst & 0xff000000) == 0x47000000) { /* BX, BLX (reg) [v8M includes BXNS, BLXNS] */ if (inst & 0x00800000) { *is_link = 1; info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } else if ((inst & 0x00780000) == 0x00700000) { info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */ } } else if ((inst & 0xfff0d000) == 0xf3c08000) { /* BXJ: in v8 this behaves like BX */ } else if ((inst & 0xff000000) == 0xbd000000) { /* POP {pc} */ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; } else if ((inst & 0xfd870000) == 0x44870000) { /* MOV PC,reg or ADD PC,reg */ if ((inst & 0xffff0000) == 0x46f70000) info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC,LR */ } 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) */ if((inst & 0x000f0f00) == 0x000d0b00) info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm*/ } else if ((inst & 0xfff0ffc0) == 0xf850f000) { /* LDR PC,reg (T2) */ } else if ((inst & 0xfe508000) == 0xe8108000) { /* LDM PC */ if ((inst & 0x0FFF0000) == 0x08BD0000) /* LDMIA [SP]!, */ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* POP {...,pc} */ } else { is_branch = 0; } return is_branch; } int inst_A64_is_direct_branch(uint32_t inst, struct decode_info *info) { uint8_t link = 0; return inst_A64_is_direct_branch_link(inst, &link, info); } int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info) { int is_direct_branch = 1; if ((inst & 0x7c000000) == 0x34000000) { /* CB, TB */ - } else if ((inst & 0xff000010) == 0x54000000) { + } else if ((inst & 0xff000000) == 0x54000000) { /* B */ + /* BC 8.8 / 9.3 arch - bit 4 = 1'b1 */ } else if ((inst & 0x7c000000) == 0x14000000) { /* B, BL imm */ if (inst & 0x80000000) { *is_link = 1; info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } } else { is_direct_branch = 0; } return is_direct_branch; } -int inst_A64_wfiwfe(uint32_t inst) +int inst_A64_wfiwfe(uint32_t inst, struct decode_info *info) { /* WFI, WFE may be traced as branches in etm 4.3++ */ if ((inst & 0xffffffdf) == 0xd503205f) return 1; + + /* new feature introduced post v8.3 */ + if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64)) + { + /* WFIT / WFET for later archs */ + if ((inst & 0xffffffc0) == 0xd5031000) + return 1; + } + return 0; +} + +int inst_A64_Tstart(uint32_t inst) +{ + if ((inst & 0xffffffe0) == 0xd5233060) + return 1; return 0; } int inst_A64_is_indirect_branch(uint32_t inst, struct decode_info *info) { uint8_t link = 0; return inst_A64_is_indirect_branch_link(inst, &link, info); } int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info) { int is_indirect_branch = 1; if ((inst & 0xffdffc1f) == 0xd61f0000) { /* BR, BLR */ if (inst & 0x00200000) { *is_link = 1; info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } } else if ((inst & 0xfffffc1f) == 0xd65f0000) { info->instr_sub_type = OCSD_S_INSTR_V8_RET; /* RET */ } else if ((inst & 0xffffffff) == 0xd69f03e0) { /* ERET */ info->instr_sub_type = OCSD_S_INSTR_V8_ERET; - } else if (info->arch_version >= 0x0803) { + } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) { /* new pointer auth instr for v8.3 arch */ if ((inst & 0xffdff800) == 0xd71f0800) { /* BRAA, BRAB, BLRAA, BLRBB */ if (inst & 0x00200000) { *is_link = 1; info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } } else if ((inst & 0xffdff81F) == 0xd61f081F) { /* BRAAZ, BRABZ, BLRAAZ, BLRBBZ */ if (inst & 0x00200000) { *is_link = 1; info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } } else if ((inst & 0xfffffbff) == 0xd69f0bff) { /* ERETAA, ERETAB */ info->instr_sub_type = OCSD_S_INSTR_V8_ERET; } else if ((inst & 0xfffffbff) == 0xd65f0bff) { /* RETAA, RETAB */ info->instr_sub_type = OCSD_S_INSTR_V8_RET; } else { is_indirect_branch = 0; } } 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) { + if ((inst & 0xff000000) == 0x54000000) { /* B */ + /* BC */ 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, struct decode_info *info) { return inst_ARM_is_indirect_branch(inst, info) || inst_ARM_is_direct_branch(inst); } int inst_Thumb_is_branch(uint32_t inst, struct decode_info *info) { return inst_Thumb_is_indirect_branch(inst, info) || inst_Thumb_is_direct_branch(inst, info); } int inst_A64_is_branch(uint32_t inst, struct decode_info *info) { return inst_A64_is_indirect_branch(inst, info) || inst_A64_is_direct_branch(inst, info); } int inst_ARM_is_branch_and_link(uint32_t inst, struct decode_info *info) { int is_branch = 1; if ((inst & 0xf0000000) == 0xf0000000) { if ((inst & 0xfe000000) == 0xfa000000){ info->instr_sub_type = OCSD_S_INSTR_BR_LINK; /* BLX (imm) */ } else { is_branch = 0; } } else if ((inst & 0x0f000000) == 0x0b000000) { info->instr_sub_type = OCSD_S_INSTR_BR_LINK; /* BL */ } else if ((inst & 0x0ff000f0) == 0x01200030) { info->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, struct decode_info *info) { int is_branch = 1; if ((inst & 0xff800000) == 0x47800000) { info->instr_sub_type = OCSD_S_INSTR_BR_LINK; /* BLX (reg) */ } else if ((inst & 0xf800c000) == 0xf000c000) { info->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, struct decode_info *info) { int is_branch = 1; if ((inst & 0xfffffc1f) == 0xd63f0000) { /* BLR */ info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } else if ((inst & 0xfc000000) == 0x94000000) { /* BL */ info->instr_sub_type = OCSD_S_INSTR_BR_LINK; - } else if (info->arch_version >= 0x0803) { + } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) { /* new pointer auth instr for v8.3 arch */ if ((inst & 0xfffff800) == 0xd73f0800) { /* BLRAA, BLRBB */ info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } else if ((inst & 0xfffff81F) == 0xd63f081F) { /* BLRAAZ, BLRBBZ */ info->instr_sub_type = OCSD_S_INSTR_BR_LINK; } else { is_branch = 0; } } 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) { + } else if ((inst & 0xff000000) == 0x54000000) { /* B.cond */ + /* BC.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_mapper.cpp b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp index 53edfe1a1616..dc07a1ed5a25 100644 --- a/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp +++ b/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp @@ -1,299 +1,307 @@ /* * \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" #include "common/ocsd_error.h" /************************************************************************************/ /* mappers base class */ /************************************************************************************/ #define USING_MEM_ACC_CACHE TrcMemAccMapper::TrcMemAccMapper() : m_acc_curr(0), m_trace_id_curr(0), m_using_trace_id(false), m_err_log(0) { #ifdef USING_MEM_ACC_CACHE m_cache.enableCaching(true); #endif } 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) { #ifdef USING_MEM_ACC_CACHE m_cache.enableCaching(true); #endif } TrcMemAccMapper::~TrcMemAccMapper() { } void TrcMemAccMapper::setErrorLog(ITraceErrorLog *err_log_i) { m_err_log = err_log_i; m_cache.setErrorLog(err_log_i); } // 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; uint32_t readBytes = 0; ocsd_err_t err = OCSD_OK; /* 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); // found a new accessor - invalidate any cache entries used by the previous one. if (m_cache.enabled() && bReadFromCurr) m_cache.invalidateAll(); } /* if bReadFromCurr then we know m_acc_curr is set */ if (bReadFromCurr) { // use cache if enabled and the amount fits into a cache page if (m_cache.enabled_for_size(*num_bytes)) { // read from cache - or load a new cache page and read.... readBytes = *num_bytes; err = m_cache.readBytesFromCache(m_acc_curr, address, mem_space, cs_trace_id, &readBytes, p_buffer); if (err != OCSD_OK) LogWarn(err, "Mem Acc: Cache access error"); } else { readBytes = m_acc_curr->readBytes(address, mem_space, cs_trace_id, *num_bytes, p_buffer); // guard against bad accessor returns (e.g. callback not obeying the rules for return values) if (readBytes > *num_bytes) { err = OCSD_ERR_MEM_ACC_BAD_LEN; LogWarn(err,"Mem acc: bad return length"); } } } *num_bytes = readBytes; return err; } +void TrcMemAccMapper::InvalidateMemAccCache(const uint8_t /* cs_trace_id */) +{ + // default mapper does not use cs_trace_id for cache invalidation. + if (m_cache.enabled()) + m_cache.invalidateAll(); + m_acc_curr = 0; +} + void TrcMemAccMapper::RemoveAllAccessors() { TrcMemAccessorBase *pAcc = 0; pAcc = getFirstAccessor(); while(pAcc != 0) { TrcMemAccFactory::DestroyAccessor(pAcc); pAcc = getNextAccessor(); if (m_cache.enabled()) m_cache.invalidateAll(); } clearAccessorList(); if (m_cache.enabled()) m_cache.logAndClearCounts(); } 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; if (m_cache.enabled()) m_cache.invalidateAll(); } else err = OCSD_ERR_INVALID_PARAM_VAL; if (m_cache.enabled()) m_cache.logAndClearCounts(); 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); } void TrcMemAccMapper::LogWarn(const ocsd_err_t err, const std::string &msg) { if (m_err_log) { ocsdError err_ocsd(OCSD_ERR_SEV_WARN,err,msg); m_err_log->LogError(ITraceErrorLog::HANDLE_GEN_INFO, &err_ocsd); } } /************************************************************************************/ /* 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_dcd_tree.cpp b/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp index be15e36e9cb3..8e29269d1690 100644 --- a/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp +++ b/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp @@ -1,716 +1,785 @@ /* * \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; + + // reset the global demux stats. + m_demux_stats.frame_bytes = 0; + m_demux_stats.no_id_bytes = 0; + m_demux_stats.valid_id_bytes = 0; + m_demux_stats.unknown_id_bytes = 0; + m_demux_stats.reserved_id_bytes = 0; } DecodeTree::~DecodeTree() { destroyMemAccMapper(); for(uint8_t i = 0; i < 0x80; i++) { destroyDecodeElement(i); } PktPrinterFact::destroyAllPrinters(m_printer_list); delete m_frame_deformatter_root; } 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::updateBinFileRegionMemAcc(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; TrcMemAccessorFile *pAcc = TrcMemAccessorFile::getExistingFileAccessor(filepath); if (!pAcc) return OCSD_ERR_INVALID_PARAM_VAL; int curr_region_idx = 0; while (curr_region_idx < num_regions) { // check "new" range if (!pAcc->addrStartOfRange(region_array[curr_region_idx].start_address)) { // ensure adds cleanly if (!pAcc->AddOffsetRange(region_array[curr_region_idx].start_address, region_array[curr_region_idx].region_size, region_array[curr_region_idx].file_offset)) return OCSD_ERR_INVALID_PARAM_VAL; // otherwise bail out } curr_region_idx++; } return OCSD_OK; } ocsd_err_t DecodeTree::initCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, void *p_cb_func, bool IDfn, 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) { if (IDfn) pCBAcc->setCBIDIfFn((Fn_MemAccID_CB)p_cb_func, p_context); else pCBAcc->setCBIfFn((Fn_MemAcc_CB)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::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) { return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, false, p_context); } ocsd_err_t DecodeTree::addCallbackIDMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAccID_CB p_cb_func, const void *p_context) { return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, true, p_context); } 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; } +ocsd_err_t DecodeTree::getDecoderStats(const uint8_t CSID, ocsd_decode_stats_t **p_stats_block) +{ + ocsd_err_t err = OCSD_OK; + TrcPktProcI *pPktProc = getPktProcI(CSID); + if (!pPktProc) + return OCSD_ERR_INVALID_PARAM_VAL; + err = pPktProc->getStatsBlock(p_stats_block); + if (err == OCSD_OK) { + // copy in the global demux stats. + (*p_stats_block)->demux.frame_bytes = m_demux_stats.frame_bytes; + (*p_stats_block)->demux.no_id_bytes = m_demux_stats.no_id_bytes; + (*p_stats_block)->demux.valid_id_bytes = m_demux_stats.valid_id_bytes; + (*p_stats_block)->demux.unknown_id_bytes = m_demux_stats.unknown_id_bytes; + (*p_stats_block)->demux.reserved_id_bytes = m_demux_stats.reserved_id_bytes; + } + return err; +} + +ocsd_err_t DecodeTree::resetDecoderStats(const uint8_t CSID) +{ + TrcPktProcI *pPktProc = getPktProcI(CSID); + if (!pPktProc) + return OCSD_ERR_INVALID_PARAM_VAL; + pPktProc->resetStats(); + + // reset the global demux stats. + m_demux_stats.frame_bytes = 0; + m_demux_stats.no_id_bytes = 0; + m_demux_stats.valid_id_bytes = 0; + m_demux_stats.unknown_id_bytes = 0; + m_demux_stats.reserved_id_bytes = 0; + return OCSD_OK; +} + +TrcPktProcI *DecodeTree::getPktProcI(const uint8_t CSID) +{ + TrcPktProcI *pPktProc = 0; + TraceComponent *pComp, *pAssoc; + DecodeTreeElement *pElem = getDecoderElement(CSID); + + if (pElem) + { + pComp = pElem->getDecoderHandle(); + if (pComp) + { + /* if this is a full decoder then the associated component is the packet processor */ + pAssoc = pComp->getAssocComponent(); + if (pAssoc) + pPktProc = dynamic_cast(pAssoc); + else + pPktProc = dynamic_cast(pComp); + } + } + return pPktProc; +} + 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)) + while((m_decode_elem_iter < 0x80) && (m_decode_elements[m_decode_elem_iter] == 0)) 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; + ocsd_err_t err; 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); + if (m_frame_deformatter_root->Init() != OCSD_OK) + return false; m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger); + err = m_frame_deformatter_root->Configure(formatterCfgFlags); + if (err != OCSD_OK) + return false; m_i_decoder_root = dynamic_cast(m_frame_deformatter_root); + m_frame_deformatter_root->SetDemuxStatsBlock(&m_demux_stats); } else - initOK = false; + return false; } - return initOK; + return true; } 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: + case OCSD_PROTOCOL_ETE: { 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 index 74e9e4977f60..ee01064a3476 100644 --- a/contrib/opencsd/decoder/source/ocsd_error.cpp +++ b/contrib/opencsd/decoder/source/ocsd_error.cpp @@ -1,232 +1,253 @@ /* * \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"}, {"OCSD_ERR_DFMTR_BAD_FHSYNC", "Bad frame or half frame sync in trace deformatter"}, /* 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_BAD_LEN","Memory accessor returned a bad read length value (larger than requested."}, {"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 interface 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(s_errorCodeDescs[0]); 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(); } + +const char* ocsdDataRespStr::getStr() +{ + static const char* szRespStr[] = { + "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." + }; + if ((m_type < OCSD_RESP_CONT) || (m_type > OCSD_RESP_FATAL_SYS_ERR)) + return "Unknown OCSD_RESP type."; + return szRespStr[m_type]; +} + /* End of File ocsd_error.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_gen_elem_stack.cpp b/contrib/opencsd/decoder/source/ocsd_gen_elem_stack.cpp index bb758427a9b8..66fe75d9899a 100644 --- a/contrib/opencsd/decoder/source/ocsd_gen_elem_stack.cpp +++ b/contrib/opencsd/decoder/source/ocsd_gen_elem_stack.cpp @@ -1,196 +1,197 @@ /* * \file ocsd_gen_elem_stack.cpp * \brief OpenCSD : List of Generic trace elements for output. * * \copyright Copyright (c) 2020, 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_stack.h" OcsdGenElemStack::OcsdGenElemStack() : m_pElemArray(0), m_elemArraySize(0), m_elem_to_send(0), m_curr_elem_idx(0), m_send_elem_idx(0), m_CSID(0), + m_sendIf(NULL), m_is_init(false) { } OcsdGenElemStack::~OcsdGenElemStack() { for (int i = 0; i 0) copyPersistentData(m_curr_elem_idx, 0); // indexes to bottom of stack, nothing in use at present m_curr_elem_idx = 0; m_send_elem_idx = 0; m_elem_to_send = 0; } ocsd_datapath_resp_t OcsdGenElemStack::sendElements() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; if (!isInit()) return OCSD_RESP_FATAL_NOT_INIT; while (m_elem_to_send && OCSD_DATA_RESP_IS_CONT(resp)) { resp = m_sendIf->first()->TraceElemIn(m_pElemArray[m_send_elem_idx].trc_pkt_idx, m_CSID, *(m_pElemArray[m_send_elem_idx].pElem)); m_send_elem_idx++; m_elem_to_send--; } // clear the indexes if we are done. if (!m_elem_to_send) resetIndexes(); return resp; } ocsd_err_t OcsdGenElemStack::growArray() { elemPtr_t *p_new_array = 0; const int increment = 4; p_new_array = new (std::nothrow) elemPtr_t[m_elemArraySize + increment]; if (p_new_array != 0) { OcsdTraceElement *pElem = 0; // fill the last increment elements with new objects for (int i = 0; i < increment; i++) { pElem = new (std::nothrow) OcsdTraceElement(); if (!pElem) return OCSD_ERR_MEM; pElem->init(); p_new_array[m_elemArraySize + i].pElem = pElem; } // copy the existing objects from the old array to the start of the new one if (m_elemArraySize > 0) { for (int i = 0; i < m_elemArraySize; i++) { p_new_array[i].pElem = m_pElemArray[i].pElem; p_new_array[i].trc_pkt_idx = m_pElemArray[i].trc_pkt_idx; } } // delete the old pointer array. delete[] m_pElemArray; m_elemArraySize += increment; m_pElemArray = p_new_array; } else return OCSD_ERR_MEM; return OCSD_OK; } void OcsdGenElemStack::copyPersistentData(int src, int dst) { m_pElemArray[dst].pElem->copyPersistentData(*(m_pElemArray[src].pElem)); } const bool OcsdGenElemStack::isInit() { if (!m_is_init) { if (m_elemArraySize && m_pElemArray && m_sendIf) m_is_init = true; } return m_is_init; } /* End of File ocsd_gen_elem_stack.cpp */ diff --git a/contrib/opencsd/decoder/source/ocsd_lib_dcd_register.cpp b/contrib/opencsd/decoder/source/ocsd_lib_dcd_register.cpp index adb042dcadff..0233c89eaa06 100644 --- a/contrib/opencsd/decoder/source/ocsd_lib_dcd_register.cpp +++ b/contrib/opencsd/decoder/source/ocsd_lib_dcd_register.cpp @@ -1,215 +1,216 @@ /* * \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" +#include "opencsd/ete/trc_dcd_mngr_ete.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) + CREATE_BUILTIN_ENTRY(DecoderMngrStm, OCSD_BUILTIN_DCD_STM), + CREATE_BUILTIN_ENTRY(DecoderMngrETE, OCSD_BUILTIN_DCD_ETE) //{ 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/pkt_printers/trc_print_fact.cpp b/contrib/opencsd/decoder/source/pkt_printers/trc_print_fact.cpp index 52dcb6b3e1ac..6b5df1f472e0 100644 --- a/contrib/opencsd/decoder/source/pkt_printers/trc_print_fact.cpp +++ b/contrib/opencsd/decoder/source/pkt_printers/trc_print_fact.cpp @@ -1,123 +1,124 @@ /* * \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: + case OCSD_PROTOCOL_ETE: 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_pkt_proc_ptm.cpp b/contrib/opencsd/decoder/source/ptm/trc_pkt_proc_ptm.cpp index 7c90b62e6413..668a14b73df0 100644 --- a/contrib/opencsd/decoder/source/ptm/trc_pkt_proc_ptm.cpp +++ b/contrib/opencsd/decoder/source/ptm/trc_pkt_proc_ptm.cpp @@ -1,1215 +1,1218 @@ /* * \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_excepAltISA = 0; 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 + 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) + // byteIdx for address byte will run from 1 to 5 - first 4 my have continuation or not. + 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/trc_core_arch_map.cpp b/contrib/opencsd/decoder/source/trc_core_arch_map.cpp index a26f79db996e..f25ab1e5ddfa 100644 --- a/contrib/opencsd/decoder/source/trc_core_arch_map.cpp +++ b/contrib/opencsd/decoder/source/trc_core_arch_map.cpp @@ -1,99 +1,177 @@ /* * \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" typedef struct _ap_map_elements { const char *name; ocsd_arch_profile_t ap; } ap_map_elem_t; static ap_map_elem_t ap_map_array[] = { { "Cortex-A77", { ARCH_V8r3, profile_CortexA } }, { "Cortex-A76", { ARCH_V8r3, profile_CortexA } }, { "Cortex-A75", { ARCH_V8r3, profile_CortexA } }, { "Cortex-A73", { ARCH_V8, profile_CortexA } }, { "Cortex-A72", { ARCH_V8, profile_CortexA } }, { "Cortex-A65", { ARCH_V8r3, profile_CortexA } }, { "Cortex-A57", { ARCH_V8, profile_CortexA } }, { "Cortex-A55", { ARCH_V8r3, profile_CortexA } }, { "Cortex-A53", { ARCH_V8, profile_CortexA } }, { "Cortex-A35", { ARCH_V8, profile_CortexA } }, { "Cortex-A32", { 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-R52", { ARCH_V8, profile_CortexR } }, { "Cortex-R8", { ARCH_V7, profile_CortexR } }, { "Cortex-R7", { ARCH_V7, profile_CortexR } }, { "Cortex-R5", { ARCH_V7, profile_CortexR } }, { "Cortex-R4", { ARCH_V7, profile_CortexR } }, { "Cortex-M33", { ARCH_V8, profile_CortexM } }, { "Cortex-M23", { ARCH_V8, profile_CortexM } }, { "Cortex-M0", { ARCH_V7, profile_CortexM } }, { "Cortex-M0+", { ARCH_V7, profile_CortexM } }, { "Cortex-M3", { ARCH_V7, profile_CortexM } }, { "Cortex-M4", { ARCH_V7, profile_CortexM } } }; -static ap_map_elem_t arch_map_array[] = -{ - { "ARMv7-A", { ARCH_V7, profile_CortexA } }, - { "ARMv7-R", { ARCH_V7, profile_CortexR } }, - { "ARMv7-M", { ARCH_V7, profile_CortexM } }, - { "ARMv8-A", { ARCH_V8, profile_CortexA } }, - { "ARMv8.3-A", { ARCH_V8r3, profile_CortexA } }, - { "ARMv8-R", { ARCH_V8, profile_CortexR } }, - { "ARMv8-M", { ARCH_V8, profile_CortexM } }, -}; - CoreArchProfileMap::CoreArchProfileMap() { unsigned i; for (i = 0; i < sizeof(ap_map_array) / sizeof(_ap_map_elements); i++) { core_profiles[ap_map_array[i].name] = ap_map_array[i].ap; } - for (i = 0; i < sizeof(arch_map_array) / sizeof(_ap_map_elements); i++) +} + +ocsd_arch_profile_t CoreArchProfileMap::getArchProfile(const std::string &coreName) +{ + ocsd_arch_profile_t ap = { ARCH_UNKNOWN, profile_Unknown }; + bool bFound = false; + + std::map::const_iterator it; + + /* match against the core name map. */ + it = core_profiles.find(coreName); + if (it != core_profiles.end()) { - arch_profiles[arch_map_array[i].name] = arch_map_array[i].ap; + ap = it->second; + bFound = true; } + + /* try a pattern match on core name - pick up ARMvM[.m]-P and ARM-{aa|AA}64[-P] */ + if (!bFound) + ap = getPatternMatchCoreName(coreName); + + return ap; } +ocsd_arch_profile_t CoreArchProfileMap::getPatternMatchCoreName(const std::string &coreName) +{ + ocsd_arch_profile_t ap = { ARCH_UNKNOWN, profile_Unknown }; + size_t pos; + /* look for ARMvM[.m]-P */ + pos = coreName.find("ARMv"); + if (pos == 0) + { + int majver = coreName[4] - '0'; + int minver = 0; + int dotoffset = 0; + + pos = coreName.find_first_of("."); + if (pos == 5) { + minver = coreName[6] - '0'; + dotoffset = 2; + } + else if (pos != std::string::npos) + return ap; + + if (majver == 7) + ap.arch = ARCH_V7; + else if (majver >= 8) { + ap.arch = ARCH_AA64; /* default to 8.3+*/ + if (majver == 8) { + if (minver < 3) + ap.arch = ARCH_V8; + else if (minver == 3) + ap.arch = ARCH_V8r3; + } + } + else + return ap; /* no valid version - return unknown */ + + if (coreName.find_first_of("-", 4) == (size_t)(5 + dotoffset)) { + int profile_idx = 6 + dotoffset; + if (coreName[profile_idx] == 'A') + ap.profile = profile_CortexA; + else if (coreName[profile_idx] == 'R') + ap.profile = profile_CortexR; + else if (coreName[profile_idx] == 'M') + ap.profile = profile_CortexM; + else + ap.arch = ARCH_UNKNOWN; /*reset arch, return unknown*/ + } + else + ap.arch = ARCH_UNKNOWN; /*reset arch, return unknown*/ + return ap; + } + + /* look for ARM-{AA|aa}64[-P] */ + pos = coreName.find("ARM-"); + if (pos == 0) + { + pos = coreName.find("aa64"); + if (pos != 4) + pos = coreName.find("AA64"); + if (pos == 4) + { + ap.arch = ARCH_AA64; + ap.profile = profile_CortexA; + if (coreName.find_first_of("-", 7) == 8) { + if (coreName[9] == 'R') + ap.profile = profile_CortexR; + else if (coreName[9] == 'M') + ap.profile = profile_CortexM; + } + } + } + return 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 index 4d46854a655b..3b2aead875ca 100644 --- a/contrib/opencsd/decoder/source/trc_frame_deformatter.cpp +++ b/contrib/opencsd/decoder/source/trc_frame_deformatter.cpp @@ -1,869 +1,970 @@ /* * \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) + m_b_output_unpacked_raw(false), + m_pStatsBlock(0) { 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); } - + + // record the incoming block for extraction routines to use. + m_in_block_base = pDataBlock; + m_in_block_size = dataBlockSize; + m_in_block_processed = 0; + 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 { + // alightment is the multiple of bytes the buffer size must be. m_cfgFlags = flags; + + // using memory aligned buffers, the formatter always outputs 16 byte frames so enforce + // this on the input m_alignment = 16; - if(flags & OCSD_DFRMTR_HAS_FSYNCS) - m_alignment = 4; - else if(flags & OCSD_DFRMTR_HAS_HSYNCS) + // if we have HSYNCS then always align to 2 byte buffers + if(flags & OCSD_DFRMTR_HAS_HSYNCS) m_alignment = 2; + // otherwise FSYNCS only can have 4 byte aligned buffers. + else if(flags & OCSD_DFRMTR_HAS_FSYNCS) + m_alignment = 4; } 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_b_fsync_start_eob = false; 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 processed = 0; const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC const uint8_t *dataPtr = m_in_block_base; while (processed < (m_in_block_size - 3)) { if (*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) { m_frame_synced = true; break; } processed++; dataPtr++; } return processed; } void TraceFmtDcdImpl::outputUnsyncedBytes(uint32_t /*num_bytes*/) { //**TBD: } -int TraceFmtDcdImpl::checkForResetFSyncPatterns() +ocsd_err_t TraceFmtDcdImpl::checkForResetFSyncPatterns(uint32_t &f_sync_bytes) { 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; + uint32_t bytes_processed = m_in_block_processed; + const uint8_t *dataPtr = m_in_block_base + bytes_processed; + ocsd_err_t err = OCSD_OK; - while (check_for_fsync && (m_in_block_processed < m_in_block_size)) + while (check_for_fsync && (bytes_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++; + num_fsyncs++; + bytes_processed += sizeof(uint32_t); } 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 + err = OCSD_ERR_DFMTR_BAD_FHSYNC; } } - return num_fsyncs * 4; + f_sync_bytes += num_fsyncs * 4; + return err; } - +/* Extract a single frame from the input buffer. */ 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 + const uint16_t FSYNC_START = 0xFFFF; // LE host pattern for start 2 bytes of fsync - - bool cont_process = true; // continue processing after extraction. + ocsd_err_t err; 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 this pass (may be filling out part frame) + uint32_t buf_left = m_in_block_size - m_in_block_processed; // bytes remaining in buffer this pass. - // memory aligned sources are always multiples of frames, aligned to start. + // last call was end of input block - but carried on to process full frame. + // exit early here. + if (!buf_left) + return false; + + // memory aligned input data is forced to be always multiples of 16 byte 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. + // between blocks of aligned data, always in frame aligned complete 16 byte frames. + // we need to skip past these frames, resetting as we go. if (m_cfgFlags & OCSD_DFRMTR_RESET_ON_4X_FSYNC) { - f_sync_bytes = checkForResetFSyncPatterns(); + err = checkForResetFSyncPatterns(f_sync_bytes); /* 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); } + + // throw processing error, none frame size block of fsyncs + if (err) + throw ocsdError(OCSD_ERR_SEV_ERROR, err, m_trc_curr_idx, "Incorrect FSYNC frame reset pattern"); + + buf_left -= f_sync_bytes; } - if((m_in_block_processed+f_sync_bytes) == m_in_block_size) + if (buf_left) { - 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; + // always a complete frame - the input data has to be 16 byte multiple alignment. + 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. + // HSYNC present, library forces input to be aligned 2 byte multiples + // FSYNC - w/o HSYNCs, forces input to be aligned 4 byte multiples. // 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); + 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; + uint16_t data_pair_val; - 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)) + if (hasFSyncs && (m_ex_frm_n_bytes == 0)) { - while((*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) && cont_process) + // was there an fsync start at the end of the last buffer? + if (m_b_fsync_start_eob) { + // last 2 of FSYNC look like HSYNC + if (*(uint16_t*)(dataPtr) != HSYNC_PATTERN) + { + // this means 0xFFFF followed by something else - invalid ID + ???? + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC pattern before frame or invalid ID.(0x7F)"); + } + else + { + f_sync_bytes += 2; + buf_left -= 2; + dataPtr += 2; + } + m_b_fsync_start_eob = false; + } + + // regular fsync checks + while ((buf_left >= 4) && (*((uint32_t*)(dataPtr)) == FSYNC_PATTERN)) { f_sync_bytes += 4; dataPtr += 4; - cont_process = (bool)(dataPtr < eodPtr); + buf_left -= 4; } - } - // 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) + // handle possible part fsync at the end of a buffer + if (buf_left == 2) { - if(*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) + if (*(uint16_t*)(dataPtr) == FSYNC_START) { - // throw an illegal FSYNC error - throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC in frame."); + f_sync_bytes += 2; + buf_left -= 2; + dataPtr += 2; + m_b_fsync_start_eob = true; } } + } + // process remaining data in pairs of bytes + while ((m_ex_frm_n_bytes < OCSD_DFRMTR_FRAME_SIZE) && buf_left) + { // mark start of frame after FSyncs - if(m_ex_frm_n_bytes == 0) + 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; + m_ex_frm_data[m_ex_frm_n_bytes + 1] = dataPtr[1]; + + data_pair_val = *((uint16_t*)(dataPtr)); // check pair is not HSYNC - if(*((uint16_t *)(dataPtr)) == HSYNC_PATTERN) + if (data_pair_val == HSYNC_PATTERN) { - if(hasHSyncs) + if (hasHSyncs) { - m_ex_frm_n_bytes-=2; - ex_bytes -= 2; - h_sync_bytes+=2; + h_sync_bytes += 2; } else { // throw illegal HSYNC error. throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad HSYNC in frame."); } } + // can't have a start of FSYNC here / illegal trace ID + else if (data_pair_val == FSYNC_START) + { + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC start in frame or invalid ID (0x7F)."); + } + else + { + m_ex_frm_n_bytes += 2; + ex_bytes += 2; + } + buf_left -= 2; 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; } // total bytes processed this pass uint32_t total_processed = ex_bytes + f_sync_bytes + h_sync_bytes; // output raw data on raw frame channel - packed raw. - if (((m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE) || !cont_process) && m_b_output_packed_raw) + if (((m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE) || (buf_left == 0)) && m_b_output_packed_raw) { outputRawMonBytes( OCSD_OP_DATA, m_trc_curr_idx, OCSD_FRM_PACKED, total_processed, m_in_block_base+m_in_block_processed, 0); } // update the processed count for the buffer m_in_block_processed += total_processed; // update index past the processed data m_trc_curr_idx += total_processed; - return cont_process; + // update any none trace data byte stats + addToFrameStats((uint64_t)(f_sync_bytes + h_sync_bytes)); + + // if we are exiting with a full frame then signal processing to continue + return (bool)(m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE); } 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; + uint64_t noneDataBytes = 0; // 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. } + noneDataBytes++; } 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; + noneDataBytes++; } // 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; + + noneDataBytes++; // byte 15 is always non-data. + addToFrameStats(noneDataBytes); // update the non data byte stats. 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)); + addToIDStats((uint64_t)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); - } + } + + if (isReservedID(m_out_data[m_out_processed].id)) + addToReservedIDStats((uint64_t)m_out_data[m_out_processed].valid); + else + addToNoIDStats((uint64_t)m_out_data[m_out_processed].valid); 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); - } + } + addToUnknownIDStats((uint64_t)m_out_data[m_out_processed].valid); m_out_processed++; // skip past this data. } } return cont_processing; } + +void TraceFmtDcdImpl::addToIDStats(uint64_t val) +{ + if (m_pStatsBlock) + m_pStatsBlock->valid_id_bytes += val; +} + +void TraceFmtDcdImpl::addToNoIDStats(uint64_t val) +{ + if (m_pStatsBlock) + m_pStatsBlock->no_id_bytes += val; +} + +void TraceFmtDcdImpl::addToFrameStats(uint64_t val) +{ + if (m_pStatsBlock) + m_pStatsBlock->frame_bytes += val; +} + +void TraceFmtDcdImpl::addToUnknownIDStats(uint64_t val) +{ + if (m_pStatsBlock) + m_pStatsBlock->unknown_id_bytes += val; +} +void TraceFmtDcdImpl::addToReservedIDStats(uint64_t val) +{ + if (m_pStatsBlock) + m_pStatsBlock->reserved_id_bytes += val; +} + /***************************************************************/ /* 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) +ocsd_err_t TraceFormatterFrameDecoder::Init() { - if(!m_pDecoder) - { - if(m_instNum >= 0) + 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; + if (!m_pDecoder) return OCSD_ERR_MEM; } - m_pDecoder->DecodeConfigure(cfg_flags); return OCSD_OK; } +/* configuration - set operational mode for incoming stream (has FSYNCS etc) */ +ocsd_err_t TraceFormatterFrameDecoder::Configure(uint32_t cfg_flags) +{ + if (!m_pDecoder) + return OCSD_ERR_NOT_INIT; + return m_pDecoder->DecodeConfigure(cfg_flags); +} + 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(); } +void TraceFormatterFrameDecoder::SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock) +{ + if (m_pDecoder) + m_pDecoder->SetDemuxStatsBlock(pStatsBlock); +} /* 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 index e1fc17ab259f..3571d5f2fc47 100644 --- a/contrib/opencsd/decoder/source/trc_frame_deformatter_impl.h +++ b/contrib/opencsd/decoder/source/trc_frame_deformatter_impl.h @@ -1,167 +1,185 @@ /* * \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); + void SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock) { m_pStatsBlock = pStatsBlock; }; + 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(); + ocsd_err_t checkForResetFSyncPatterns(uint32_t &f_sync_bytes); friend class TraceFormatterFrameDecoder; - // attachment points + // stats updates + void addToIDStats(uint64_t val); + void addToNoIDStats(uint64_t val); + void addToFrameStats(uint64_t val); + void addToUnknownIDStats(uint64_t val); + void addToReservedIDStats(uint64_t val); + + bool isReservedID(uint8_t ID) { return ((ID == 0) || (ID >= 0x70)); }; + // 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) + bool m_b_fsync_start_eob; // flag to indicate that the end of the last buffer was a pair of bytes + // (0xffff) that could only validly be the start and FSYNC. 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 + /* channel output data - can never be more than a frame of data for a single ID. + * 8 possible ID changes per frame. Although the final one can have no associated data, a pathological + * case exists with 7 ID changes, all data associated with a previous frame, except for last + * ID / data byte which is data. Not possible with normal hardware but guard against corrupt input. + */ + out_chan_data m_out_data[8]; // output data for a given ID int m_out_data_idx; // number of out_chan_data frames used. - int m_out_processed; // number of complete out_chan_data frames output. + 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]; + + ocsd_demux_stats_t *m_pStatsBlock; }; #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 index e1774203ebc5..c94c5a7c6848 100644 --- a/contrib/opencsd/decoder/source/trc_gen_elem.cpp +++ b/contrib/opencsd/decoder/source/trc_gen_elem.cpp @@ -1,282 +1,316 @@ /* * \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_I_RANGE_NOPATH","Traced N instructions in a range, but incomplete information as to program execution path from start to end of range"}, {"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","Exception 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_SWTRACE","Software trace packet - may contain data payload. STM / ITM hardware trace with channel protocol."}, + {"OCSD_GEN_TRC_ELEM_SYNC_MARKER","Synchronisation marker - marks position in stream of an element that is output later."}, + {"OCSD_GEN_TRC_ELEM_MEMTRANS","Trace indication of transactional memory operations."}, + {"OCSD_GEN_TRC_ELEM_INSTRUMENTATION", "PE instrumentation trace - PE generated SW trace, application dependent protocol."}, {"OCSD_GEN_TRC_ELEM_CUSTOM","Fully custom packet type."} }; static const char *instr_type[] = { "--- ", "BR ", "iBR ", "ISB ", "DSB.DMB", - "WFI.WFE" + "WFI.WFE", + "TSTART" }; #define T_SIZE (sizeof(instr_type) / sizeof(const char *)) static const char *instr_sub_type[] = { "--- ", "b+link ", "A64:ret ", "A64:eret ", "V7:impl ret", }; #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 */ }; static const char *s_unsync_reason[] = { "undefined", // UNSYNC_UNKNOWN - unknown /undefined "init-decoder", // UNSYNC_INIT_DECODER - decoder intialisation - start of trace. "reset-decoder", // UNSYNC_RESET_DECODER - decoder reset. "overflow", // UNSYNC_OVERFLOW - overflow packet - need to re-sync "discard", // UNSYNC_DISCARD - specl trace discard - need to re-sync "bad-packet", // UNSYNC_BAD_PACKET - bad packet at input - resync to restart. "end-of-trace", // UNSYNC_EOT - end of trace info. }; +static const char *s_transaction_type[] = { + "Init", + "Start", + "Commit", + "Fail" +}; + +static const char *s_marker_t[] = { + "Timestamp marker", // ELEM_MARKER_TS +}; void OcsdTraceElement::toString(std::string &str) const { std::ostringstream oss; int num_str = sizeof(s_elem_descs) / sizeof(s_elem_descs[0]); 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 << "num_i(" << std::dec << num_instr_range << ") "; oss << "last_sz(" << last_instr_sz << ") "; 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]; if (last_instr_cond) oss << " "; break; case OCSD_GEN_TRC_ELEM_ADDR_NACC: oss << " 0x" << std::hex << st_addr << " "; break; case OCSD_GEN_TRC_ELEM_I_RANGE_NOPATH: oss << "first 0x" << std::hex << st_addr << ":[next 0x" << en_addr << "] "; oss << "num_i(" << std::dec << num_instr_range << ") "; break; case OCSD_GEN_TRC_ELEM_EXCEPTION: if (excep_ret_addr == 1) { oss << "pref ret addr:0x" << std::hex << en_addr; if (excep_ret_addr_br_tgt) { oss << " [addr also prev br tgt]"; } oss << "; "; } 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; "); + switch (context.security_level) + { + case ocsd_sec_secure: oss << "S; "; break; + case ocsd_sec_nonsecure: oss << "N; "; break; + case ocsd_sec_root: oss << "Root; "; break; + case ocsd_sec_realm: oss << "Realm; "; break; + } + oss << (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; case OCSD_GEN_TRC_ELEM_EVENT: if(trace_event.ev_type == EVENT_TRIGGER) oss << " Trigger; "; else if(trace_event.ev_type == EVENT_NUMBERED) oss << " Numbered:" << std::dec << trace_event.ev_number << "; "; break; case OCSD_GEN_TRC_ELEM_EO_TRACE: case OCSD_GEN_TRC_ELEM_NO_SYNC: if (unsync_eot_info <= UNSYNC_EOT) oss << " [" << s_unsync_reason[unsync_eot_info] << "]"; break; + case OCSD_GEN_TRC_ELEM_SYNC_MARKER: + oss << " [" << s_marker_t[sync_marker.type] << "(0x" << std::setfill('0') << std::setw(8) << std::hex << sync_marker.value << ")]"; + break; + + case OCSD_GEN_TRC_ELEM_MEMTRANS: + if (mem_trans <= OCSD_MEM_TRANS_FAIL) + oss << s_transaction_type[mem_trans]; + break; + + case OCSD_GEN_TRC_ELEM_INSTRUMENTATION: + oss << "EL" << std::dec << (int)sw_ite.el << "; 0x" << std::setfill('0') << std::setw(16) << std::hex << sw_ite.value; + 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 index 88c7bb226f41..2b60c030d53f 100644 --- a/contrib/opencsd/decoder/source/trc_printable_elem.cpp +++ b/contrib/opencsd/decoder/source/trc_printable_elem.cpp @@ -1,123 +1,121 @@ /* * \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++; if (validChars < numHexChars) { 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 */