Index: head/contrib/opencsd/decoder/include/common/ocsd_code_follower.h =================================================================== --- head/contrib/opencsd/decoder/include/common/ocsd_code_follower.h (revision 353392) +++ head/contrib/opencsd/decoder/include/common/ocsd_code_follower.h (revision 353393) @@ -1,231 +1,237 @@ /* * \file ocsd_code_follower.h * \brief OpenCSD : Code follower for instruction trace decode * * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_OCSD_CODE_FOLLOWER_H_INCLUDED #define ARM_OCSD_CODE_FOLLOWER_H_INCLUDED #include "opencsd/ocsd_if_types.h" #include "opencsd/trc_pkt_types.h" #include "comp_attach_pt_t.h" #include "interfaces/trc_tgt_mem_access_i.h" #include "interfaces/trc_instr_decode_i.h" /*! * @class OcsdCodeFollower * @brief The code follower looks for waypoints or addresses. * * Code follower used to determine the trace ranges for Atom or other waypoint * elements. Uses memory accessor and I decoder to follow the code path. * */ class OcsdCodeFollower { public: OcsdCodeFollower(); ~OcsdCodeFollower(); //*********** setup API void initInterfaces(componentAttachPt *pMemAccess, componentAttachPt *pIDecode); // set information for decode operation - static or occasionally changing settings // per decode values are passed as parameters into the decode API calls. void setArchProfile(const ocsd_arch_profile_t profile); //!< core profile void setMemSpaceAccess(const ocsd_mem_space_acc_t mem_acc_rule); //!< memory space to use for access (filtered by S/NS, EL etc). void setMemSpaceCSID(const uint8_t csid); //!< memory spaces might be partitioned by CSID void setISA(const ocsd_isa isa); //!< set the ISA for the decode. void setDSBDMBasWP(); //!< DSB and DMB can be treated as WP in some archs. //********** code following API // standard WP search - for program flow trace //ocsd_err_t followToAtomWP(idec_res_t &op_result, const ocsd_vaddr_t addrStart, const ocsd_atm_val A); // PTM exception code may require follow to an address //ocsd_err_t followToAddress(idec_res_t &op_result, const ocsd_vaddr_t addrStart, const ocsd_atm_val A, const ocsd_vaddr_t addrMatch); // single instruction atom format such as ETMv3 ocsd_err_t followSingleAtom(const ocsd_vaddr_t addrStart, const ocsd_atm_val A); // follow N instructions // ocsd_err_t followNInstructions(idec_res_t &op_result) // ETMv4 Q elements //*********************** results API const ocsd_vaddr_t getRangeSt() const; //!< inclusive start address of decoded range (value passed in) const ocsd_vaddr_t getRangeEn() const; //!< exclusive end address of decoded range (first instruction _not_ executed / potential next instruction). const bool hasRange() const; //!< we have a valid range executed (may be false if nacc). const bool hasNextAddr() const; //!< we have calulated the next address - otherwise this is needed from trace packets. const ocsd_vaddr_t getNextAddr() const; //!< next address - valid if hasNextAddr() true. // information on last instruction executed in range. const ocsd_instr_type getInstrType() const; //!< last instruction type const ocsd_instr_subtype getInstrSubType() const; //!< last instruction sub-type const bool isCondInstr() const; //!< is a conditional instruction const bool isLink() const; //!< is a link (branch with link etc) const bool ISAChanged() const; //!< next ISA different from input ISA. const ocsd_isa nextISA() const; //!< ISA for next instruction + const uint8_t getInstrSize() const; //!< Get the last instruction size. // information on error conditions const bool isNacc() const; //!< true if Memory Not Accessible (nacc) error occurred void clearNacc(); //!< clear the nacc error flag const ocsd_vaddr_t getNaccAddr() const; //!< get the nacc error address. private: bool initFollowerState(); //!< clear all the o/p data and flags, check init valid. ocsd_err_t decodeSingleOpCode(); //!< decode single opcode address from current m_inst_info packet ocsd_instr_info m_instr_info; ocsd_vaddr_t m_st_range_addr; //!< start of excuted range - inclusive address. ocsd_vaddr_t m_en_range_addr; //!< end of executed range - exclusive address. ocsd_vaddr_t m_next_addr; //!< calcuated next address (could be eo range of branch address, not set for indirect branches) bool m_b_next_valid; //!< true if next address valid, false if need address from trace packets. //! memory space rule to use when accessing memory. ocsd_mem_space_acc_t m_mem_acc_rule; //! memory space csid to use when accessing memory. uint8_t m_mem_space_csid; ocsd_vaddr_t m_nacc_address; //!< memory address that was inaccessible - failed read @ start, or during follow operation bool m_b_nacc_err; //!< memory NACC error - required address was unavailable. //! pointers to the memory access and i decode interfaces. componentAttachPt *m_pMemAccess; componentAttachPt *m_pIDecode; }; #endif // ARM_OCSD_CODE_FOLLOWER_H_INCLUDED //*********** setup API inline void OcsdCodeFollower::setArchProfile(const ocsd_arch_profile_t profile) { m_instr_info.pe_type = profile; } inline void OcsdCodeFollower::setMemSpaceAccess(const ocsd_mem_space_acc_t mem_acc_rule) { m_mem_acc_rule = mem_acc_rule; } inline void OcsdCodeFollower::setMemSpaceCSID(const uint8_t csid) { m_mem_space_csid = csid; } inline void OcsdCodeFollower::setISA(const ocsd_isa isa) { m_instr_info.isa = isa; } inline void OcsdCodeFollower::setDSBDMBasWP() { m_instr_info.dsb_dmb_waypoints = 1; } //**************************************** results API inline const ocsd_vaddr_t OcsdCodeFollower::getRangeSt() const { return m_st_range_addr; } inline const ocsd_vaddr_t OcsdCodeFollower::getRangeEn() const { return m_en_range_addr; } inline const bool OcsdCodeFollower::hasRange() const { return m_st_range_addr < m_en_range_addr; } inline const bool OcsdCodeFollower::hasNextAddr() const { return m_b_next_valid; } inline const ocsd_vaddr_t OcsdCodeFollower::getNextAddr() const { return m_next_addr; } // information on last instruction executed in range. inline const ocsd_instr_type OcsdCodeFollower::getInstrType() const { return m_instr_info.type; } inline const ocsd_instr_subtype OcsdCodeFollower::getInstrSubType() const { return m_instr_info.sub_type; +} + +inline const uint8_t OcsdCodeFollower::getInstrSize() const +{ + return m_instr_info.instr_size; } inline const bool OcsdCodeFollower::isCondInstr() const { return (bool)(m_instr_info.is_conditional == 1); } inline const bool OcsdCodeFollower::isLink() const { return (bool)(m_instr_info.is_link == 1); } inline const bool OcsdCodeFollower::ISAChanged() const { return (bool)(m_instr_info.isa != m_instr_info.next_isa); } inline const ocsd_isa OcsdCodeFollower::nextISA() const { return m_instr_info.next_isa; } // information on error conditions inline const bool OcsdCodeFollower::isNacc() const { return m_b_nacc_err; } inline void OcsdCodeFollower::clearNacc() { m_b_nacc_err = false; } inline const ocsd_vaddr_t OcsdCodeFollower::getNaccAddr() const { return m_nacc_address; } /* End of File ocsd_code_follower.h */ Index: head/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h =================================================================== --- head/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h (revision 353392) +++ head/contrib/opencsd/decoder/include/common/ocsd_dcd_tree.h (revision 353393) @@ -1,406 +1,426 @@ /*! * \file ocsd_dcd_tree.h * \brief OpenCSD : Trace Decode Tree. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_OCSD_DCD_TREE_H_INCLUDED #define ARM_OCSD_DCD_TREE_H_INCLUDED #include #include #include "opencsd.h" #include "ocsd_dcd_tree_elem.h" /** @defgroup dcd_tree OpenCSD Library : Trace Decode Tree. @brief Create a multi source decode tree for a single trace capture buffer. Use to create a connected set of decoder objects to decode a trace buffer. There may be multiple trace sources within the capture buffer. @{*/ /*! * @class DecodeTree * @brief Class to manage the decoding of data from a single trace sink . * * Provides functionality to build a tree of decode objects capable of decoding * multiple trace sources within a single trace sink (capture buffer). * */ class DecodeTree : public ITrcDataIn { public: /** @name Creation and Destruction @{*/ DecodeTree(); //!< default constructor ~DecodeTree(); //!< default destructor /*! * @brief Create a decode tree. * Automatically creates a trace frame deformatter if required and a default error log component. * * @param src_type : Data stream source type, can be CoreSight frame formatted trace, or single demuxed trace data stream, * @param formatterCfgFlags : Configuration flags for trace de-formatter. * * @return DecodeTree * : pointer to the decode tree, 0 if creation failed. */ static DecodeTree *CreateDecodeTree(const ocsd_dcd_tree_src_t src_type, const uint32_t formatterCfgFlags); /** @brief Destroy a decode tree */ static void DestroyDecodeTree(DecodeTree *p_dcd_tree); /** @}*/ /** @name Error and element Logging @{*/ /** @brief The library default error logger */ static ocsdDefaultErrorLogger* getDefaultErrorLogger() { return &s_error_logger; }; /** the current error logging interface in use */ static ITraceErrorLog *getCurrentErrorLogI() { return s_i_error_logger; }; /** set an alternate error logging interface. */ static void setAlternateErrorLogger(ITraceErrorLog *p_error_logger); /** get the list of packet printers for this decode tree */ std::vector &getPrinterList() { return m_printer_list; }; /** add a protocol packet printer */ ocsd_err_t addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter **ppPrinter); /** add a raw frame printer */ ocsd_err_t addRawFramePrinter(RawFramePrinter **ppPrinter, uint32_t flags); /** add a generic element output printer */ ocsd_err_t addGenElemPrinter(TrcGenericElementPrinter **ppPrinter); /** @}*/ /** @name Trace Data Path @{*/ /** @brief Trace Data input interface (ITrcDataIn) Decode tree implements the data in interface : ITrcDataIn . Captured raw trace data is passed into the deformatter and decoders via this method. */ virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op, const ocsd_trc_index_t index, const uint32_t dataBlockSize, const uint8_t *pDataBlock, uint32_t *numBytesProcessed); /*! * @brief Decoded Trace output. * * Client trace analysis program attaches a generic trace element interface to * receive the output from the trace decode operations. * * @param *i_gen_trace_elem : Pointer to the interface. */ void setGenTraceElemOutI(ITrcGenElemIn *i_gen_trace_elem); /*! @brief Return the connected generic element interface */ ITrcGenElemIn *getGenTraceElemOutI() const { return m_i_gen_elem_out; }; /** @}*/ /** @name Decoder Management @{*/ /*! * Creates a decoder that is registered with the library under the supplied name. * createFlags determine if a full packet processor / packet decoder pair or * packet processor only is created. * Uses the supplied configuration structure. * * @param &decoderName : registered name of decoder * @param createFlags : Decoder creation options. * @param *pConfig : Pointer to a valid configuration structure for the named decoder. * * @return ocsd_err_t : Library error code or OCSD_OK if successful. */ ocsd_err_t createDecoder(const std::string &decoderName, const int createFlags, const CSConfig *pConfig); /* */ /*! * Remove a decoder / packet processor attached to an Trace ID output on the frame de-mux. * * Once removed another decoder can be created that has a CSConfig using that ID. * * @param CSID : Trace ID to remove. * * @return ocsd_err_t : Library error code or OCSD_OK if successful. */ ocsd_err_t removeDecoder(const uint8_t CSID); /* get decoder elements currently in use */ /*! * Find a decode tree element associated with a specific CoreSight trace ID. * */ DecodeTreeElement *getDecoderElement(const uint8_t CSID) const; /* iterate decoder elements */ /*! * Decode tree iteration. Return the first tree element 0 if no elements avaiable. * * @param &elemID : CoreSight Trace ID associated with this element */ DecodeTreeElement *getFirstElement(uint8_t &elemID); /*! * Return the next tree element - or 0 if no futher elements avaiable. * * @param &elemID : CoreSight Trace ID associated with this element */ DecodeTreeElement *getNextElement(uint8_t &elemID); /* set key interfaces - attach / replace on any existing tree components */ /*! * Set an ARM instruction opcode decoder. * * @param *i_instr_decode : Pointer to the interface. */ void setInstrDecoder(IInstrDecode *i_instr_decode); /*! * Set a target memory access interface - used to access program image memory for instruction * trace decode. * * @param *i_mem_access : Pointer to the interface. */ void setMemAccessI(ITargetMemAccess *i_mem_access); /** @}*/ /** @name Memory Access Mapper A memory mapper is used to organise a collection of memory accessor objects that contain the memory images for different areas of traced instruction memory. These areas could be the executed program and a set of loaded .so libraries for example - each of which would have code sections in different memory locations. A memory accessor represents a snapshot of an area of memory as it appeared during trace capture, for a given memory space. Memory spaces are described by the ocsd_mem_space_acc_t enum. The most general memory space is OCSD_MEM_SPACE_ANY. This represents memory that can be secure or none-secure, available at any exception level. The memory mapper will not allow two accessors to overlap in the same memory space. The trace decdoer will access memory with a memory space parameter that represents the current core state - the mapper will find the closest memory space match for the address. e.g. if the core is accessing secure EL3, then the most specialised matching space will be accessed. If an EL3 space matches that will be used, otherwise the any secure, and finally _ANY. It is no necessary for clients to register memory accessors for all spaces - _ANY will be sufficient in many cases. @{*/ /* */ /*! * This creates a memory mapper within the decode tree. * * @param type : defaults to MEMACC_MAP_GLOBAL (only type available at present) * * @return ocsd_err_t : Library error code or OCSD_OK if successful. */ ocsd_err_t createMemAccMapper(memacc_mapper_t type = MEMACC_MAP_GLOBAL); /*! * Get a pointer to the memory mapper. Allows a client to add memory accessors directly to the mapper. * @return TrcMemAccMapper : Pointer to the mapper. */ TrcMemAccMapper *getMemAccMapper() const { return m_default_mapper; }; /*! * Set an external mapper rather than create a mapper in the decode tree. * Setting this will also destroy any internal mapper that was previously created. * * @param pMapper : pointer to the mapper to add. */ void setExternMemAccMapper(TrcMemAccMapper * pMapper); /*! * Return true if a mapper has been set (internal or external */ const bool hasMemAccMapper() const { return (bool)(m_default_mapper != 0); }; void logMappedRanges(); //!< Log the mapped memory ranges to the default message logger. /** @}*/ /** @name Memory Accessors A memory accessor represents a snapshot of an area of memory as it appeared during trace capture. Memory spaces represent either common global memory, or Secure / none-secure and EL specific spaces. @{*/ /*! * Creates a memory accessor for a memory block in the supplied buffer and adds to the current mapper. * * @param address : Start address for the memory block in the memory map. * @param mem_space : Memory space * @param *p_mem_buffer : start of the buffer. * @param mem_length : length of the buffer. * * @return ocsd_err_t : Library error code or OCSD_OK if successful. */ ocsd_err_t addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length); /*! * Creates a memory accessor for a memory block supplied as a contiguous binary data file, and adds to the current mapper. * * @param address : Start address for the memory block in the memory map. * @param mem_space : Memory space * @param &filepath : Path to the binary data file * * @return ocsd_err_t : Library error code or OCSD_OK if successful. */ ocsd_err_t addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath); /*! * Creates a memory accessor for a memory block supplied as a one or more memory regions in a binary file. * Region structures are created that describe the memory start address, the offset within the binary file * for that address, and the length of the region. This accessor can be used to point to the code section * in a program file for example. * * @param *region_array : array of valid memory regions in the file. * @param num_regions : number of regions * @param mem_space : Memory space * @param &filepath : Path to the binary data file * * @return ocsd_err_t : Library error code or OCSD_OK if successful. */ ocsd_err_t addBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath); + /*! + * 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); + ocsd_dcd_tree_src_t m_dcd_tree_type; IInstrDecode *m_i_instr_decode; ITargetMemAccess *m_i_mem_access; ITrcGenElemIn *m_i_gen_elem_out; //!< Output interface for generic elements from decoder. ITrcDataIn* m_i_decoder_root; /*!< root decoder object interface - either deformatter or single packet processor */ TraceFormatterFrameDecoder *m_frame_deformatter_root; DecodeTreeElement *m_decode_elements[0x80]; uint8_t m_decode_elem_iter; TrcMemAccMapper *m_default_mapper; //!< the mem acc mapper to use bool m_created_mapper; //!< true if created by decode tree object std::vector m_printer_list; //!< list of packet printers. /* global error logger - all sources */ static ITraceErrorLog *s_i_error_logger; static std::list s_trace_dcd_trees; /**! default error logger */ static ocsdDefaultErrorLogger s_error_logger; /**! default instruction decoder */ static TrcIDecode s_instruction_decoder; }; /** @}*/ #endif // ARM_OCSD_DCD_TREE_H_INCLUDED /* End of File ocsd_dcd_tree.h */ Index: head/contrib/opencsd/decoder/include/common/ocsd_error_logger.h =================================================================== --- head/contrib/opencsd/decoder/include/common/ocsd_error_logger.h (revision 353392) +++ head/contrib/opencsd/decoder/include/common/ocsd_error_logger.h (revision 353393) @@ -1,89 +1,89 @@ /*! * \file ocsd_error_logger.h * \brief OpenCSD : Library error logger. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_OCSD_ERROR_LOGGER_H_INCLUDED #define ARM_OCSD_ERROR_LOGGER_H_INCLUDED #include #include -#include +//#include #include "interfaces/trc_error_log_i.h" #include "ocsd_error.h" #include "ocsd_msg_logger.h" class ocsdDefaultErrorLogger : public ITraceErrorLog { public: ocsdDefaultErrorLogger(); virtual ~ocsdDefaultErrorLogger(); - bool initErrorLogger(const ocsd_err_severity_t verbosity, bool bCreateOutputLogger = false); + bool initErrorLogger(const ocsd_err_severity_t verbosity, bool bCreateOutputLogger = false); //!< Initialise the error logger with a severity filter, optionally create an output logger on stderr. virtual ocsdMsgLogger *getOutputLogger() { return m_output_logger; }; virtual void setOutputLogger(ocsdMsgLogger *pLogger); virtual const ocsd_hndl_err_log_t RegisterErrorSource(const std::string &component_name); virtual void LogError(const ocsd_hndl_err_log_t handle, const ocsdError *Error); virtual void LogMessage(const ocsd_hndl_err_log_t handle, const ocsd_err_severity_t filter_level, const std::string &msg ); virtual const ocsd_err_severity_t GetErrorLogVerbosity() const { return m_Verbosity; }; virtual ocsdError *GetLastError() { return m_lastErr; }; virtual ocsdError *GetLastIDError(const uint8_t chan_id) { if(OCSD_IS_VALID_CS_SRC_ID(chan_id)) return m_lastErrID[chan_id]; return 0; }; private: void CreateErrorObj(ocsdError **ppErr, const ocsdError *p_from); ocsdError *m_lastErr; ocsdError *m_lastErrID[0x80]; ocsd_err_severity_t m_Verbosity; ocsdMsgLogger *m_output_logger; // pointer to a standard message output logger; bool m_created_output_logger; // true if this class created it's own logger; std::vector m_error_sources; }; #endif // ARM_OCSD_ERROR_LOGGER_H_INCLUDED /* End of File ocsd_error_logger.h */ Index: head/contrib/opencsd/decoder/include/common/ocsd_msg_logger.h =================================================================== --- head/contrib/opencsd/decoder/include/common/ocsd_msg_logger.h (revision 353392) +++ head/contrib/opencsd/decoder/include/common/ocsd_msg_logger.h (revision 353393) @@ -1,84 +1,87 @@ /*! * \file ocsd_msg_logger.h * \brief OpenCSD : Generic Message logger / printer * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_OCSD_MSG_LOGGER_H_INCLUDED #define ARM_OCSD_MSG_LOGGER_H_INCLUDED #include #include class ocsdMsgLogStrOutI { public: ocsdMsgLogStrOutI() {}; virtual ~ocsdMsgLogStrOutI() {}; virtual void printOutStr(const std::string &outStr) = 0; }; class ocsdMsgLogger { public: ocsdMsgLogger(); ~ocsdMsgLogger(); + /** Typedef enum providing flags to define the output methods for the message logger. + */ typedef enum { - OUT_NONE = 0, - OUT_FILE = 1, - OUT_STDERR = 2, - OUT_STDOUT = 4, - OUT_STR_CB = 8 /* output to external string callback interface */ + OUT_NONE = 0, /*!< No output from logger*/ + OUT_FILE = 1, /*!< Output to file */ + OUT_STDERR = 2, /*!< Output to stderr */ + OUT_STDOUT = 4, /*!< Output to stdout */ + OUT_STR_CB = 8 /*!< output to external string callback interface */ } output_dest; - void setLogOpts(int logOpts); - const int getLogOpts() const { return m_outFlags; }; + void setLogOpts(int logOpts); //!< set the output logging flags. + const int getLogOpts() const //! get the current output logging flags value. + { return m_outFlags; }; - void setLogFileName(const char *fileName); - void setStrOutFn(ocsdMsgLogStrOutI *p_IstrOut); + void setLogFileName(const char *fileName); //!< Set the output log filename, and enable logging to file. + void setStrOutFn(ocsdMsgLogStrOutI *p_IstrOut); //!< Set the output log string callback and enable logging to callback. - void LogMsg(const std::string &msg); + void LogMsg(const std::string &msg); //!< Log a message to the current set output channels. - const bool isLogging() const; + const bool isLogging() const; //!< true if logging active private: int m_outFlags; std::string m_logFileName; std::fstream m_out_file; ocsdMsgLogStrOutI *m_pOutStrI; }; #endif // ARM_OCSD_MSG_LOGGER_H_INCLUDED /* End of File ocsd_msg_logger.h */ Index: head/contrib/opencsd/decoder/include/common/trc_gen_elem.h =================================================================== --- head/contrib/opencsd/decoder/include/common/trc_gen_elem.h (revision 353392) +++ head/contrib/opencsd/decoder/include/common/trc_gen_elem.h (revision 353393) @@ -1,206 +1,209 @@ /*! * \file trc_gen_elem.h * \brief OpenCSD : Decoder Generic trace element output class. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_GEN_ELEM_H_INCLUDED #define ARM_TRC_GEN_ELEM_H_INCLUDED #include "opencsd/trc_gen_elem_types.h" #include "trc_printable_elem.h" #include "ocsd_pe_context.h" /** @addtogroup gen_trc_elem @{*/ /*! * @class OcsdTraceElement * @brief Generic trace element class * */ class OcsdTraceElement : public trcPrintableElem, public ocsd_generic_trace_elem { public: OcsdTraceElement(); OcsdTraceElement(ocsd_gen_trc_elem_t type); virtual ~OcsdTraceElement() {}; void init(); // set elements API void setType(const ocsd_gen_trc_elem_t type); //!< set type and init flags void updateType(const ocsd_gen_trc_elem_t type); //!< change type only - no init void setContext(const ocsd_pe_context &new_context) { context = new_context; }; void setISA(const ocsd_isa isa_update); void setCycleCount(const uint32_t cycleCount); void setEvent(const event_t ev_type, const uint16_t number); void setTS(const uint64_t ts, const bool freqChange = false); void setExcepMarker() { excep_data_marker = 1; }; void setExceptionNum(uint32_t excepNum) { exception_number = excepNum; }; void setTraceOnReason(const trace_on_reason_t reason); - void setAddrRange(const ocsd_vaddr_t st_addr, const ocsd_vaddr_t en_addr); - void setLastInstrInfo(const bool exec, const ocsd_instr_type last_i_type, const ocsd_instr_subtype last_i_subtype); + void 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 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); // stringize the element virtual void toString(std::string &str) const; // get elements API OcsdTraceElement &operator =(const ocsd_generic_trace_elem* p_elem); const ocsd_gen_trc_elem_t getType() const { return elem_type; }; // return current context const ocsd_pe_context &getContext() const { return context; }; private: void printSWInfoPkt(std::ostringstream &oss) const; void clearPerPktData(); //!< clear flags that indicate validity / have values on a per packet basis }; inline OcsdTraceElement::OcsdTraceElement(ocsd_gen_trc_elem_t type) { elem_type = type; } inline OcsdTraceElement::OcsdTraceElement() { elem_type = OCSD_GEN_TRC_ELEM_UNKNOWN; } inline void OcsdTraceElement::setCycleCount(const uint32_t cycleCount) { cycle_count = cycleCount; has_cc = 1; } inline void OcsdTraceElement::setEvent(const event_t ev_type, const uint16_t number) { trace_event.ev_type = (uint16_t)ev_type; trace_event.ev_number = ev_type == EVENT_NUMBERED ? number : 0; } -inline void OcsdTraceElement::setAddrRange(const ocsd_vaddr_t st_addr, const ocsd_vaddr_t en_addr) +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) +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; // union with trace_on_reason / trace_event ptr_extended_data = 0; // extended data pointer } inline void OcsdTraceElement::setTraceOnReason(const trace_on_reason_t reason) { trace_on_reason = reason; } inline void OcsdTraceElement::setISA(const ocsd_isa isa_update) { isa = isa_update; if(isa > ocsd_isa_unknown) isa = ocsd_isa_unknown; } inline void OcsdTraceElement::setTS(const uint64_t ts, const bool freqChange /*= false*/) { timestamp = ts; cpu_freq_change = freqChange ? 1 : 0; has_ts = 1; } inline void OcsdTraceElement::setExtendedDataPtr(const void *data_ptr) { extended_data = 1; ptr_extended_data = data_ptr; } /** @}*/ #endif // ARM_TRC_GEN_ELEM_H_INCLUDED /* End of File trc_gen_elem.h */ Index: head/contrib/opencsd/decoder/include/i_dec/trc_i_decode.h =================================================================== --- head/contrib/opencsd/decoder/include/i_dec/trc_i_decode.h (revision 353392) +++ head/contrib/opencsd/decoder/include/i_dec/trc_i_decode.h (revision 353393) @@ -1,56 +1,57 @@ /* * \file trc_i_decode.h * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_I_DECODE_H_INCLUDED #define ARM_TRC_I_DECODE_H_INCLUDED #include "interfaces/trc_instr_decode_i.h" #include "opencsd/ocsd_if_types.h" class TrcIDecode : public IInstrDecode { public: TrcIDecode() {}; virtual ~TrcIDecode() {}; virtual ocsd_err_t DecodeInstruction(ocsd_instr_info *instr_info); private: ocsd_err_t DecodeA32(ocsd_instr_info *instr_info); ocsd_err_t DecodeA64(ocsd_instr_info *instr_info); ocsd_err_t DecodeT32(ocsd_instr_info *instr_info); + void SetArchVersion(ocsd_instr_info *instr_info); }; #endif // ARM_TRC_I_DECODE_H_INCLUDED /* End of File trc_i_decode.h */ Index: head/contrib/opencsd/decoder/include/i_dec/trc_idec_arminst.h =================================================================== --- head/contrib/opencsd/decoder/include/i_dec/trc_idec_arminst.h (revision 353392) +++ head/contrib/opencsd/decoder/include/i_dec/trc_idec_arminst.h (revision 353393) @@ -1,130 +1,141 @@ /* * \file trc_idec_arminst.h * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_IDEC_ARMINST_H_INCLUDED #define ARM_TRC_IDEC_ARMINST_H_INCLUDED #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS 1 #endif #include "opencsd/ocsd_if_types.h" #include /* For Thumb2, test if a halfword is the first half of a 32-bit instruction, as opposed to a complete 16-bit instruction. */ inline int is_wide_thumb(uint16_t insthw) { return (insthw & 0xF800) >= 0xE800; } /* In the following queries, 16-bit Thumb2 instructions should be passed in as the high halfword, e.g. xxxx0000. */ /* Test whether an instruction is a branch (software change of the PC). This includes branch instructions and all loads and data-processing instructions that write to the PC. It does not include exception instructions such as SVC, HVC and SMC. (Performance event 0x0C includes these.) */ int inst_ARM_is_branch(uint32_t inst); int inst_Thumb_is_branch(uint32_t inst); int inst_A64_is_branch(uint32_t inst); /* Test whether an instruction is a direct (aka immediate) branch. Performance event 0x0D counts these. */ int inst_ARM_is_direct_branch(uint32_t inst); int inst_Thumb_is_direct_branch(uint32_t inst); +int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond); int inst_A64_is_direct_branch(uint32_t inst); +int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link); /* Get branch destination for a direct branch. */ int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc); int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc); int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc); int inst_ARM_is_indirect_branch(uint32_t inst); +int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link); int inst_Thumb_is_indirect_branch(uint32_t inst); +int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link); int inst_A64_is_indirect_branch(uint32_t inst); int inst_ARM_is_branch_and_link(uint32_t inst); int inst_Thumb_is_branch_and_link(uint32_t inst); int inst_A64_is_branch_and_link(uint32_t inst); int inst_ARM_is_conditional(uint32_t inst); int inst_Thumb_is_conditional(uint32_t inst); int inst_A64_is_conditional(uint32_t inst); /* For an IT instruction, return the number of instructions conditionalized (from 1 to 4). For other instructions, return zero. */ unsigned int inst_Thumb_is_IT(uint32_t inst); typedef enum { ARM_BARRIER_NONE, ARM_BARRIER_ISB, ARM_BARRIER_DMB, ARM_BARRIER_DSB } arm_barrier_t; arm_barrier_t inst_ARM_barrier(uint32_t inst); arm_barrier_t inst_Thumb_barrier(uint32_t inst); arm_barrier_t inst_A64_barrier(uint32_t inst); +int inst_ARM_wfiwfe(uint32_t inst); +int inst_Thumb_wfiwfe(uint32_t inst); +int inst_A64_wfiwfe(uint32_t inst); + /* Test whether an instruction is definitely undefined, e.g. because allocated to a "permanently UNDEFINED" space (UDF mnemonic). Other instructions besides the ones indicated, may always or sometimes cause an undefined instruction trap. This call is intended to be helpful in 'runaway decode' prevention. */ int inst_ARM_is_UDF(uint32_t inst); int inst_Thumb_is_UDF(uint32_t inst); int inst_A64_is_UDF(uint32_t inst); /* access sub-type information */ ocsd_instr_subtype get_instr_subtype(); void clear_instr_subtype(); + +/* set arch version info. */ +void set_arch_version(uint16_t version); #endif // ARM_TRC_IDEC_ARMINST_H_INCLUDED /* End of File trc_idec_arminst.h */ Index: head/contrib/opencsd/decoder/include/interfaces/trc_error_log_i.h =================================================================== --- head/contrib/opencsd/decoder/include/interfaces/trc_error_log_i.h (revision 353392) +++ head/contrib/opencsd/decoder/include/interfaces/trc_error_log_i.h (revision 353393) @@ -1,134 +1,134 @@ /*! * \file trc_error_log_i.h * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_ERROR_LOG_I_H_INCLUDED #define ARM_TRC_ERROR_LOG_I_H_INCLUDED #include "opencsd/ocsd_if_types.h" #include class ocsdError; class ocsdMsgLogger; /*! * @class ITraceErrorLog * @brief Error logging interface. * @ingroup ocsd_interfaces * * This class provides a standard interface to the decoder error logger for all trace decode and * reader components. * * Implementation will determine if and how the errors and messages are logged. * */ class ITraceErrorLog { public: - ITraceErrorLog() {}; /**< default constructor */ - virtual ~ITraceErrorLog() {}; /**< default destructor */ + ITraceErrorLog() {}; + virtual ~ITraceErrorLog() {}; /*! * Register a named component error source. Allows the logger to associate errors with components. * returned handle to be used with subsequent error log calls. * * @param &component_name : name of the component. * * @return virtual const : Handle associated with the component. */ virtual const ocsd_hndl_err_log_t RegisterErrorSource(const std::string &component_name) = 0; /*! * Return the verbosity level of the logger. Errors of the returned ocsd_err_severity_t severity * or lower will be logged, others are ignored. * * @return ocsd_err_severity_t : Current logging severity level. */ virtual const ocsd_err_severity_t GetErrorLogVerbosity() const = 0; /*! * Log an error. * Pass an error object and the component or generic handle to associate with the error. * Error will be saved for access by GetLastError(). * * If logger implementation has output print logging enabled then this may be printed to file or screen. * * @param handle : Component handle or standard generic handle * @param *Error : Pointer to an error object. */ virtual void LogError(const ocsd_hndl_err_log_t handle, const ocsdError *Error) = 0; /*! * Log a general message. Associated with component or use generic handle. * Message logged to same output as errors if output enabled, but not saved for GetLastError() * * @param handle : Component handle or standard generic handle. * @param filter_level : Verbosity filter. * @param msg : Pointer to an error object. */ virtual void LogMessage(const ocsd_hndl_err_log_t handle, const ocsd_err_severity_t filter_level, const std::string &msg ) = 0; /*! * Get a pointer to the last logged error. * Returns 0 if no errors have been logged. * * @return ocsdError *: last error pointer. */ virtual ocsdError *GetLastError() = 0; /*! * Get the last error associated with the given Trace source channel ID. * returns a pointer to the error or 0 if no errors associated with the ID. * - * @param chan_id : ID. + * @param chan_id : Trace Source Channel ID (CoreSight Trace ID). * * @return ocsdError *: last error pointer for ID or 0. */ virtual ocsdError *GetLastIDError(const uint8_t chan_id) = 0; virtual ocsdMsgLogger *getOutputLogger() = 0; virtual void setOutputLogger(ocsdMsgLogger *pLogger) = 0; enum generic_handles { HANDLE_GEN_ERR = 0, HANDLE_GEN_WARN, HANDLE_GEN_INFO, /* last value in list */ HANDLE_FIRST_REGISTERED_COMPONENT /**< 1st valid handle value for components registered with logger */ }; }; #endif // ARM_TRC_ERROR_LOG_I_H_INCLUDED /* End of File trc_error_log_i.h */ Index: head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_base.h =================================================================== --- head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_base.h (revision 353392) +++ head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_base.h (revision 353393) @@ -1,244 +1,245 @@ /*! * \file trc_mem_acc_base.h * \brief OpenCSD : Memory accessor base class. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_MEM_ACC_BASE_H_INCLUDED #define ARM_TRC_MEM_ACC_BASE_H_INCLUDED #include "opencsd/ocsd_if_types.h" #include /*! * @class TrcMemAccessorBase * @brief Memory range to access by trace decoder. * * Represents a memory access range for the trace decoder. * Range inclusive from m_startAddress to m_endAddress. * e.g. a 1k range from 0x1000 has start of 0x1000 and end of 0x13FF * * Derived classes provide specific access types such as binary files and memory buffers. * */ class TrcMemAccessorBase { public: /** Describes the storage type of the underlying memory accessor */ enum MemAccTypes { MEMACC_UNKNOWN, MEMACC_FILE, //= m_startAddress) && (s_address <= m_endAddress); } inline const bool TrcMemAccessorBase::addrStartOfRange(const ocsd_vaddr_t s_address) const { return (s_address == m_startAddress); } inline const uint32_t TrcMemAccessorBase::bytesInRange(const ocsd_vaddr_t s_address, const uint32_t reqBytes) const { ocsd_vaddr_t bytesInRange = 0; if(addrInRange(s_address)) // start not in range, return 0. { // bytes available till end address. bytesInRange = m_endAddress - s_address + 1; if(bytesInRange > reqBytes) bytesInRange = reqBytes; } return (uint32_t)bytesInRange; } inline const bool TrcMemAccessorBase::overLapRange(const TrcMemAccessorBase *p_test_acc) const { if( addrInRange(p_test_acc->m_startAddress) || addrInRange(p_test_acc->m_endAddress) ) return true; return false; } inline const bool TrcMemAccessorBase::validateRange() { if(m_startAddress & 0x1) // at least hword aligned for thumb return false; if((m_endAddress + 1) & 0x1) return false; if(m_startAddress == m_endAddress) // zero length range. return false; if(m_startAddress > m_endAddress) // values bakcwards / invalid return false; return true; } class TrcMemAccFactory { public: /** Accessor Creation */ static ocsd_err_t CreateBufferAccessor(TrcMemAccessorBase **pAccessor, const ocsd_vaddr_t s_address, const uint8_t *p_buffer, const uint32_t size); static ocsd_err_t CreateFileAccessor(TrcMemAccessorBase **pAccessor, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset = 0, size_t size = 0); static ocsd_err_t CreateCBAccessor(TrcMemAccessorBase **pAccessor, const ocsd_vaddr_t s_address, const ocsd_vaddr_t e_address, const ocsd_mem_space_acc_t mem_space); /** Accessor Destruction */ static void DestroyAccessor(TrcMemAccessorBase *pAccessor); private: TrcMemAccFactory() {}; ~TrcMemAccFactory() {}; }; #endif // ARM_TRC_MEM_ACC_BASE_H_INCLUDED /* End of File trc_mem_acc_base.h */ Index: head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_bufptr.h =================================================================== --- head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_bufptr.h (revision 353392) +++ head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_bufptr.h (revision 353393) @@ -1,76 +1,76 @@ /* * \file trc_mem_acc_bufptr.h * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_MEM_ACC_BUFPTR_H_INCLUDED #define ARM_TRC_MEM_ACC_BUFPTR_H_INCLUDED #include "mem_acc/trc_mem_acc_base.h" /*! * @class TrcMemAccBufPtr: * @brief Trace memory accessor for a memory buffer. * * Wraps a memory buffer in an memory range accessor object. * Takes a copy of the buffer pointer which must remain valid * for the lifetime of the object. * */ class TrcMemAccBufPtr: public TrcMemAccessorBase { public: /*! * Construct the accessor. * uses the start address as the start of range and calculates the end address * according to the buffer size * * @param s_address : Start address in memory map represented by the data in the buffer. * @param *p_buffer : pointer to a buffer of binary data. * @param size : size of the buffer. * */ TrcMemAccBufPtr(const ocsd_vaddr_t s_address, const uint8_t *p_buffer, const uint32_t size); virtual ~TrcMemAccBufPtr() {}; /**< default destructor */ /** Memory access override - allow decoder to read bytes from the buffer. */ - virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer); + virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint8_t trcID, const uint32_t reqBytes, uint8_t *byteBuffer); private: const uint8_t *m_p_buffer; /**< pointer to the memory buffer */ const uint32_t m_size; /**< size of the memory buffer. */ }; #endif // ARM_TRC_MEM_ACC_BUFPTR_H_INCLUDED /* End of File trc_mem_acc_bufptr.h */ Index: head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cache.h =================================================================== --- head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cache.h (nonexistent) +++ head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cache.h (revision 353393) @@ -0,0 +1,149 @@ +/*! +* \file trc_mem_acc_cache.h +* \brief OpenCSD : Memory accessor cache. +* +* \copyright Copyright (c) 2018, 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_CACHE_H_INCLUDED +#define ARM_TRC_MEM_ACC_CACHE_H_INCLUDED + +#include +#include "opencsd/ocsd_if_types.h" + +#define MEM_ACC_CACHE_PAGE_SIZE 256 +#define MEM_ACC_CACHE_MRU_SIZE 12 + +class TrcMemAccessorBase; +class ITraceErrorLog; + +typedef struct cache_block { + ocsd_vaddr_t st_addr; + uint32_t valid_len; + uint8_t data[MEM_ACC_CACHE_PAGE_SIZE]; +} cache_block_t; + +// enable define to collect stats for debugging / cache performance tests +//#define LOG_CACHE_STATS + + +/** class TrcMemAccCache - cache small amounts of data from accessors to speed up decode. */ +class TrcMemAccCache +{ +public: + TrcMemAccCache(); + ~TrcMemAccCache() {}; + + void enableCaching(bool bEnable) { m_bCacheEnabled = bEnable; }; + void invalidateAll(); + const bool enabled() const { return m_bCacheEnabled; }; + const bool enabled_for_size(const uint32_t reqSize) const + { + return (m_bCacheEnabled && (reqSize <= MEM_ACC_CACHE_PAGE_SIZE)); + } + + + /** read bytes from cache if possible - load new page if needed, bail out if data not available */ + ocsd_err_t readBytesFromCache(TrcMemAccessorBase *p_accessor, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trcID, uint32_t *numBytes, uint8_t *byteBuffer); + + void setErrorLog(ITraceErrorLog *log); + void logAndClearCounts(); + +private: + bool blockInCache(const ocsd_vaddr_t address, const uint32_t reqBytes); // run through each page to look for data. + bool blockInPage(const ocsd_vaddr_t address, const uint32_t reqBytes); + void logMsg(const std::string &szMsg); + + cache_block_t m_mru[MEM_ACC_CACHE_MRU_SIZE]; + int m_mru_idx = 0; // in use index + int m_mru_next_new = 0; // next new page at this index. + bool m_bCacheEnabled = false; + +#ifdef LOG_CACHE_STATS + uint32_t m_hits = 0; + uint32_t m_misses = 0; + uint32_t m_pages = 0; + uint32_t m_hit_rl[MEM_ACC_CACHE_MRU_SIZE]; + uint32_t m_hit_rl_max[MEM_ACC_CACHE_MRU_SIZE]; +#endif + + ITraceErrorLog *m_err_log = 0; +}; + +inline TrcMemAccCache::TrcMemAccCache() +{ + for (int i = 0; i < MEM_ACC_CACHE_MRU_SIZE; i++) + { + m_mru[i].st_addr = 0; + m_mru[i].valid_len = 0; +#ifdef LOG_CACHE_STATS + m_hit_rl[i] = 0; + m_hit_rl_max[i] = 0; +#endif + } +} + +inline bool TrcMemAccCache::blockInPage(const ocsd_vaddr_t address, const uint32_t reqBytes) +{ + if ((m_mru[m_mru_idx].st_addr <= address) && + m_mru[m_mru_idx].st_addr + m_mru[m_mru_idx].valid_len >= (address + reqBytes)) + return true; + return false; +} + +inline bool TrcMemAccCache::blockInCache(const ocsd_vaddr_t address, const uint32_t reqBytes) +{ + int tests = MEM_ACC_CACHE_MRU_SIZE; + while (tests) + { + if (blockInPage(address, reqBytes)) + return true; // found address in page + tests--; + m_mru_idx++; + if (m_mru_idx == MEM_ACC_CACHE_MRU_SIZE) + m_mru_idx = 0; + } + return false; +} + +inline void TrcMemAccCache::invalidateAll() +{ + for (int i = 0; i < MEM_ACC_CACHE_MRU_SIZE; i++) + { + m_mru[i].valid_len = 0; + m_mru[i].st_addr = 0; + } + m_mru_idx = 0; + m_mru_next_new = 0; +} + +#endif // ARM_TRC_MEM_ACC_CACHE_H_INCLUDED + +/* End of File trc_mem_acc_cache.h */ Property changes on: head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cache.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cb.h =================================================================== --- head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cb.h (revision 353392) +++ head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_cb.h (revision 353393) @@ -1,81 +1,96 @@ /*! * \file trc_mem_acc_cb.h * \brief OpenCSD : Callback trace memory accessor. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_MEM_ACC_CB_H_INCLUDED #define ARM_TRC_MEM_ACC_CB_H_INCLUDED #include "mem_acc/trc_mem_acc_base.h" #include "mem_acc/trc_mem_acc_cb_if.h" class TrcMemAccCB : public TrcMemAccessorBase { public: TrcMemAccCB(const ocsd_vaddr_t s_address, const ocsd_vaddr_t e_address, const ocsd_mem_space_acc_t mem_space); virtual ~TrcMemAccCB() {}; /** Memory access override - allow decoder to read bytes from the buffer. */ - virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer); + virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint8_t trcID, const uint32_t reqBytes, uint8_t *byteBuffer); void setCBIfClass(TrcMemAccCBIF *p_if); void setCBIfFn(Fn_MemAcc_CB p_fn, const void *p_context); + void setCBIDIfFn(Fn_MemAccID_CB p_fn, const void *p_context); private: + void clearCBptrs(); TrcMemAccCBIF *m_p_CBclass; // #include #include #include #include "opencsd/ocsd_if_types.h" #include "mem_acc/trc_mem_acc_base.h" // an add-on region to a file - allows setting of a region at a none-zero offset for a file. class FileRegionMemAccessor : public TrcMemAccessorBase { public: FileRegionMemAccessor() : TrcMemAccessorBase(MEMACC_FILE) {}; virtual ~FileRegionMemAccessor() {}; void setOffset(const size_t offset) { m_file_offset = offset; }; const size_t getOffset() const { return m_file_offset; }; bool operator<(const FileRegionMemAccessor& rhs) { return this->m_startAddress < rhs.m_startAddress; }; // not going to use these objects to read bytes - defer to the file class for that. - virtual const uint32_t readBytes(const ocsd_vaddr_t s_address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer) { return 0; }; + virtual const uint32_t readBytes(const ocsd_vaddr_t s_address, const ocsd_mem_space_acc_t memSpace, const uint8_t trcID, const uint32_t reqBytes, uint8_t *byteBuffer) { return 0; }; const ocsd_vaddr_t regionStartAddress() const { return m_startAddress; }; private: size_t m_file_offset; }; /*! * @class TrcMemAccessorFile * @brief Memory accessor for a binary file. * * Memory accessor based on a binary file snapshot of some memory. * * Static creation code to allow reference counted accessor usable for * multiple access maps attached to multiple source trees for the same system. */ class TrcMemAccessorFile : public TrcMemAccessorBase { public: /** read bytes override - reads from file */ - virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer); + virtual const uint32_t readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint8_t trcID, const uint32_t reqBytes, uint8_t *byteBuffer); protected: TrcMemAccessorFile(); /**< protected default constructor */ virtual ~ TrcMemAccessorFile(); /**< protected default destructor */ /** increment reference counter */ void IncRefCount() { m_ref_count++; }; /** decrement reference counter */ void DecRefCount() { m_ref_count--; }; /** get current reference count */ const int getRefCount() const { return m_ref_count; }; /*! * Initialise accessor with file name and path, and start address. * File opened and length calculated to determine end address for the range. * * @param &pathToFile : Binary file path and name * @param startAddr : system memory address associated with start of binary datain file. * * @return bool : true if set up successfully, false if file could not be opened. */ ocsd_err_t initAccessor(const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset, size_t size); /** get the file path */ const std::string &getFilePath() const { return m_file_path; }; /** get an offset region if extant for the address */ FileRegionMemAccessor *getRegionForAddress(const ocsd_vaddr_t startAddr) const; /* validate ranges */ virtual const bool validateRange(); public: /*! * File may contain multiple none-overlapping ranges in a single file. * * @param startAddr : Address for beginning of byte data. * @param size : size of range in bytes. * @param offset : offset into file for that data. * * @return bool : true if set successfully. */ bool AddOffsetRange(const ocsd_vaddr_t startAddr, const size_t size, const size_t offset); /*! * Override in case we have multiple regions in the file. * * @param s_address : Address to test. * * @return const bool : true if the address is in range. */ virtual const bool addrInRange(const ocsd_vaddr_t s_address) const; /*! * test if an address is the start of range for this accessor * * @param s_address : Address to test. * * @return const bool : true if the address is start of range. */ virtual const bool addrStartOfRange(const ocsd_vaddr_t s_address) const; /*! * Test number of bytes available from the start address, up to the number of requested bytes. * Tests if all the requested bytes are available from the supplied start address. * Returns the number available up to full requested amount. * * @param s_address : Start address within the range. * @param reqBytes : Number of bytes needed from the start address. * * @return const uint32_t : Bytes available, up to reqBytes. 0 is s_address not in range. */ virtual const uint32_t bytesInRange(const ocsd_vaddr_t s_address, const uint32_t reqBytes) const; /*! * test is supplied range accessor overlaps this range. * * @param *p_test_acc : Accessor to test for overlap. * * @return bool : true if overlap, false if not. */ virtual const bool overLapRange(const TrcMemAccessorBase *p_test_acc) const; /*! Override to handle ranges and offset accessors plus add in file name. */ virtual void getMemAccString(std::string &accStr) const; /*! * Create a file accessor based on the supplied path and address. * Keeps a list of file accessors created. * * File will be checked to ensure valid accessor can be created. * * If an accessor using the supplied file is currently in use then a reference to that * accessor will be returned and the accessor reference counter updated. * * @param &pathToFile : Path to binary file * @param startAddr : Start address of data represented by file. * * @return TrcMemAccessorFile * : pointer to accessor if successful, 0 if it could not be created. */ static ocsd_err_t createFileAccessor(TrcMemAccessorFile **p_acc, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset = 0, size_t size = 0); /*! * Destroy supplied accessor. * * Reference counter decremented and checked and accessor destroyed if no longer in use. * * @param *p_accessor : File Accessor to destroy. */ static void destroyFileAccessor(TrcMemAccessorFile *p_accessor); /*! * Test if any accessor is currently using the supplied file path * * @param &pathToFile : Path to test. * * @return bool : true if an accessor exists with this file path. */ static const bool isExistingFileAccessor(const std::string &pathToFile); /*! * Get the accessor using the supplied file path * Use after createFileAccessor if additional memory ranges need * adding to an exiting file accessor. * * @param &pathToFile : Path to test. * * @return TrcMemAccessorFile * : none 0 if an accessor exists with this file path. */ static TrcMemAccessorFile * getExistingFileAccessor(const std::string &pathToFile); private: static std::map s_FileAccessorMap; /**< map of file accessors in use. */ private: std::ifstream m_mem_file; /**< input binary file stream */ ocsd_vaddr_t m_file_size; /**< size of the file */ int m_ref_count; /**< accessor reference count */ std::string m_file_path; /**< path to input file */ std::list m_access_regions; /**< additional regions in the file at non-zero offsets */ bool m_base_range_set; /**< true when offset 0 set */ bool m_has_access_regions; /**< true if single file contains multiple regions */ }; #endif // ARM_TRC_MEM_ACC_FILE_H_INCLUDED /* End of File trc_mem_acc_file.h */ Index: head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h =================================================================== --- head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h (revision 353392) +++ head/contrib/opencsd/decoder/include/mem_acc/trc_mem_acc_mapper.h (revision 353393) @@ -1,128 +1,131 @@ /* * \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); // mapper memory area configuration interface // add an accessor to this map virtual ocsd_err_t AddAccessor(TrcMemAccessorBase *p_accessor, const uint8_t cs_trace_id) = 0; // remove a specific accessor virtual ocsd_err_t RemoveAccessor(const TrcMemAccessorBase *p_accessor) = 0; // clear all attached accessors from the map void RemoveAllAccessors(); // remove a single accessor based on address. ocsd_err_t RemoveAccessorByAddress(const ocsd_vaddr_t st_address, const ocsd_mem_space_acc_t mem_space, const uint8_t cs_trace_id = 0); // set the error log. - void setErrorLog(ITraceErrorLog *err_log_i) { m_err_log = err_log_i; }; + 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 */ Index: head/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_types.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_types.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/c_api/ocsd_c_api_types.h (revision 353393) @@ -1,105 +1,106 @@ /*! * \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" /** @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 */ Index: head/contrib/opencsd/decoder/include/opencsd/c_api/opencsd_c_api.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/c_api/opencsd_c_api.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/c_api/opencsd_c_api.h (revision 353393) @@ -1,485 +1,502 @@ /*! * \file opencsd_c_api.h * \brief OpenCSD : "C" API * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_OPENCSD_C_API_H_INCLUDED #define ARM_OPENCSD_C_API_H_INCLUDED /** @defgroup lib_c_api OpenCSD Library : Library "C" API. @brief "C" API for the OpenCSD Library Set of "C" wrapper functions for the OpenCSD library. Defines API, functions and callback types. @{*/ /* ensure C bindings */ #if defined(WIN32) /* windows bindings */ /** Building the C-API DLL **/ #ifdef _OCSD_C_API_DLL_EXPORT #ifdef __cplusplus #define OCSD_C_API extern "C" __declspec(dllexport) #else #define OCSD_C_API __declspec(dllexport) #endif #else /** building or using the static C-API library **/ #if defined(_LIB) || defined(OCSD_USE_STATIC_C_API) #ifdef __cplusplus #define OCSD_C_API extern "C" #else #define OCSD_C_API #endif #else /** using the C-API DLL **/ #ifdef __cplusplus #define OCSD_C_API extern "C" __declspec(dllimport) #else #define OCSD_C_API __declspec(dllimport) #endif #endif #endif #else /* linux bindings */ #ifdef __cplusplus #define OCSD_C_API extern "C" #else #define OCSD_C_API #endif #endif #include "ocsd_c_api_types.h" #include "ocsd_c_api_custom.h" /** @name Library Version API @{*/ -/** Get Library version. Return a 32 bit version in form MMMMnnpp - MMMM = major verison, nn = minor version, pp = patch version */ +/** 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); /** @}*/ /*---------------------- 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); /** @}*/ /** @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 */ Index: head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h (revision 353393) @@ -1,449 +1,465 @@ /* * \file trc_cmp_cfg_etmv4.h * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_CMP_CFG_ETMV4_H_INCLUDED #define ARM_TRC_CMP_CFG_ETMV4_H_INCLUDED #include "trc_pkt_types_etmv4.h" #include "common/trc_cs_config.h" /** @addtogroup ocsd_protocol_cfg @{*/ /** @name ETMv4 configuration @{*/ /*! * @class EtmV4Config * @brief Interpreter class for etm v4 config structure. * * Provides quick value interpretation methods for the ETMv4 config register values. * Primarily inlined for efficient code. */ class EtmV4Config : public CSConfig // public ocsd_etmv4_cfg { public: EtmV4Config(); /**< Default constructor */ EtmV4Config(const ocsd_etmv4_cfg *cfg_regs); ~EtmV4Config() {}; /**< Default destructor */ // operations to convert to and from C-API structure //! copy assignment operator for base structure into class. EtmV4Config & operator=(const ocsd_etmv4_cfg *p_cfg); //! cast operator returning struct const reference operator const ocsd_etmv4_cfg &() const { return m_cfg; }; //! cast operator returning struct const pointer operator const ocsd_etmv4_cfg *() const { return &m_cfg; }; const ocsd_core_profile_t &coreProfile() const { return m_cfg.core_prof; }; const ocsd_arch_version_t &archVersion() const { return m_cfg.arch_ver; }; /* idr 0 */ const bool LSasInstP0() const; const bool hasDataTrace() const; const bool hasBranchBroadcast() const; const bool hasCondTrace() const; const bool hasCycleCountI() const; const bool hasRetStack() const; const uint8_t numEvents() const; typedef enum _condType { COND_PASS_FAIL, COND_HAS_ASPR } condType; const condType hasCondType() const; typedef enum _QSuppType { Q_NONE, Q_ICOUNT_ONLY, Q_NO_ICOUNT_ONLY, Q_FULL } QSuppType; const QSuppType getQSuppType(); const bool hasQElem(); const bool hasQFilter(); const bool hasTrcExcpData() const; const uint32_t TimeStampSize() const; const bool commitOpt1() const; /* idr 1 */ const uint8_t MajVersion() const; const uint8_t MinVersion() const; + 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; 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 uint32_t EtmV4Config::TimeStampSize() const { uint32_t tsSizeF = (m_cfg.reg_idr0 >> 24) & 0x1F; if(tsSizeF == 0x6) return 48; if(tsSizeF == 0x8) return 64; return 0; } inline const bool EtmV4Config::commitOpt1() const { return (bool)((m_cfg.reg_idr0 & 0x20000000) == 0x20000000) && hasCycleCountI(); } /* idr 1 */ inline const uint8_t EtmV4Config::MajVersion() const { - return (uint8_t)((m_cfg.reg_idr1 >> 8) & 0xF); + return m_MajVer; } inline const uint8_t EtmV4Config::MinVersion() const { - return (uint8_t)((m_cfg.reg_idr1 >> 4) & 0xF); + 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 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 */ Index: head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_etmv4_stack_elem.h (revision 353393) @@ -1,338 +1,346 @@ /* * \file trc_etmv4_stack_elem.h * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_ETMV4_STACK_ELEM_H_INCLUDED #define ARM_TRC_ETMV4_STACK_ELEM_H_INCLUDED #include "opencsd/etmv4/trc_pkt_types_etmv4.h" #include #include /* ETMv4 I trace stack elements Speculation requires that we stack certain elements till they are committed or cancelled. (P0 elements + other associated parts.) */ typedef enum _p0_elem_t { P0_UNKNOWN, P0_ATOM, P0_ADDR, P0_CTXT, P0_TRC_ON, P0_EXCEP, P0_EXCEP_RET, P0_EVENT, P0_TS, P0_CC, P0_TS_CC, - P0_OVERFLOW + P0_OVERFLOW, + P0_FUNC_RET, } p0_elem_t; /************************************************************/ /***Trace stack element base class - record originating packet type and index in buffer*/ class TrcStackElem { public: TrcStackElem(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); virtual ~TrcStackElem() {}; const p0_elem_t getP0Type() const { return m_P0_type; }; const ocsd_etmv4_i_pkt_type getRootPkt() const { return m_root_pkt; }; const ocsd_trc_index_t getRootIndex() const { return m_root_idx; }; const bool isP0() const { return m_is_P0; }; private: ocsd_etmv4_i_pkt_type m_root_pkt; ocsd_trc_index_t m_root_idx; p0_elem_t m_P0_type; protected: bool m_is_P0; // true if genuine P0 - commit / cancellable, false otherwise }; inline TrcStackElem::TrcStackElem(p0_elem_t p0_type, const bool isP0, ocsd_etmv4_i_pkt_type root_pkt, ocsd_trc_index_t root_index) : m_root_pkt(root_pkt), m_root_idx(root_index), m_P0_type(p0_type), m_is_P0(isP0) { } /************************************************************/ /** Address element */ class TrcStackElemAddr : public TrcStackElem { protected: TrcStackElemAddr(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); virtual ~TrcStackElemAddr() {}; friend class EtmV4P0Stack; public: void setAddr(const etmv4_addr_val_t &addr_val) { m_addr_val = addr_val; }; const etmv4_addr_val_t &getAddr() const { return m_addr_val; }; private: etmv4_addr_val_t m_addr_val; }; inline TrcStackElemAddr::TrcStackElemAddr(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : TrcStackElem(P0_ADDR, false, root_pkt,root_index) { m_addr_val.val = 0; m_addr_val.isa = 0; } /************************************************************/ /** Context element */ class TrcStackElemCtxt : public TrcStackElem { protected: TrcStackElemCtxt(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); virtual ~TrcStackElemCtxt() {}; friend class EtmV4P0Stack; public: void setContext(const etmv4_context_t &ctxt) { m_context = ctxt; }; const etmv4_context_t &getContext() const { return m_context; }; private: etmv4_context_t m_context; }; inline TrcStackElemCtxt::TrcStackElemCtxt(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : TrcStackElem(P0_CTXT, false, root_pkt,root_index) { } /************************************************************/ /** Exception element */ class TrcStackElemExcept : public TrcStackElem { protected: TrcStackElemExcept(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); virtual ~TrcStackElemExcept() {}; friend class EtmV4P0Stack; public: void setPrevSame(bool bSame) { m_prev_addr_same = bSame; }; const bool getPrevSame() const { return m_prev_addr_same; }; void setExcepNum(const uint16_t num) { m_excep_num = num; }; const uint16_t getExcepNum() const { return m_excep_num; }; private: bool m_prev_addr_same; uint16_t m_excep_num; }; inline TrcStackElemExcept::TrcStackElemExcept(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : TrcStackElem(P0_EXCEP, true, root_pkt,root_index), m_prev_addr_same(false) { } /************************************************************/ /** Atom element */ class TrcStackElemAtom : public TrcStackElem { protected: TrcStackElemAtom(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); virtual ~TrcStackElemAtom() {}; friend class EtmV4P0Stack; public: void setAtom(const ocsd_pkt_atom &atom) { m_atom = atom; }; const ocsd_atm_val commitOldest(); int cancelNewest(const int nCancel); const bool isEmpty() const { return (m_atom.num == 0); }; private: ocsd_pkt_atom m_atom; }; inline TrcStackElemAtom::TrcStackElemAtom(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : TrcStackElem(P0_ATOM, true, root_pkt,root_index) { m_atom.num = 0; } // commit oldest - get value and remove it from pattern inline const ocsd_atm_val TrcStackElemAtom::commitOldest() { ocsd_atm_val val = (m_atom.En_bits & 0x1) ? ATOM_E : ATOM_N; m_atom.num--; m_atom.En_bits >>= 1; return val; } // cancel newest - just reduce the atom count. inline int TrcStackElemAtom::cancelNewest(const int nCancel) { int nRemove = (nCancel <= m_atom.num) ? nCancel : m_atom.num; m_atom.num -= nRemove; return nRemove; } /************************************************************/ /** Generic param element */ class TrcStackElemParam : public TrcStackElem { protected: TrcStackElemParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); virtual ~TrcStackElemParam() {}; friend class EtmV4P0Stack; public: void setParam(const uint32_t param, const int nParamNum) { m_param[(nParamNum & 0x3)] = param; }; const uint32_t &getParam(const int nParamNum) const { return m_param[(nParamNum & 0x3)]; }; private: uint32_t m_param[4]; }; inline TrcStackElemParam::TrcStackElemParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) : TrcStackElem(p0_type, isP0, root_pkt,root_index) { } /************************************************************/ /* P0 element stack that allows push of elements, and deletion of elements when done. */ class EtmV4P0Stack { public: EtmV4P0Stack() {}; ~EtmV4P0Stack(); void push_front(TrcStackElem *pElem); + void push_back(TrcStackElem *pElem); // insert element when processing void pop_back(); TrcStackElem *back(); size_t size(); void delete_all(); void delete_back(); void delete_popped(); // creation functions - create and push if successful. TrcStackElemParam *createParamElem(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const std::vector ¶ms); - TrcStackElemParam *createParamElemNoParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index); + 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); TrcStackElemAddr *createAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val); private: std::deque m_P0_stack; //!< P0 decode element stack std::vector m_popped_elem; //!< save list of popped but not deleted elements. }; inline EtmV4P0Stack::~EtmV4P0Stack() { delete_all(); delete_popped(); } // put an element on the front of the stack inline void EtmV4P0Stack::push_front(TrcStackElem *pElem) { m_P0_stack.push_front(pElem); +} + +// 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() { m_popped_elem.push_back(m_P0_stack.back()); m_P0_stack.pop_back(); } // pop last element pointer off the stack and delete immediately inline void EtmV4P0Stack::delete_back() { if (m_P0_stack.size() > 0) { TrcStackElem* pElem = m_P0_stack.back(); delete pElem; m_P0_stack.pop_back(); } } // get a pointer to the last element on the stack inline TrcStackElem *EtmV4P0Stack::back() { return m_P0_stack.back(); } // remove and delete all the elements left on the stack inline void EtmV4P0Stack::delete_all() { while (m_P0_stack.size() > 0) delete_back(); m_P0_stack.clear(); } // delete list of popped elements. inline void EtmV4P0Stack::delete_popped() { while (m_popped_elem.size() > 0) { delete m_popped_elem.back(); m_popped_elem.pop_back(); } m_popped_elem.clear(); } // get current number of elements on the stack inline size_t EtmV4P0Stack::size() { return m_P0_stack.size(); } #endif // ARM_TRC_ETMV4_STACK_ELEM_H_INCLUDED /* End of File trc_etmv4_stack_elem.h */ Index: head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h (revision 353393) @@ -1,183 +1,190 @@ /* * \file trc_pkt_decode_etmv4i.h * \brief OpenCSD : ETMv4 instruction decoder * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_PKT_DECODE_ETMV4I_H_INCLUDED #define ARM_TRC_PKT_DECODE_ETMV4I_H_INCLUDED #include "common/trc_pkt_decode_base.h" #include "opencsd/etmv4/trc_pkt_elem_etmv4i.h" #include "opencsd/etmv4/trc_cmp_cfg_etmv4.h" #include "common/trc_gen_elem.h" #include "common/trc_ret_stack.h" #include "opencsd/etmv4/trc_etmv4_stack_elem.h" class TrcStackElem; class TrcStackElemParam; class TrcStackElemCtxt; class TrcPktDecodeEtmV4I : public TrcPktDecodeBase { public: TrcPktDecodeEtmV4I(); TrcPktDecodeEtmV4I(int instIDNum); virtual ~TrcPktDecodeEtmV4I(); protected: /* implementation packet decoding interface */ virtual ocsd_datapath_resp_t processPacket(); virtual ocsd_datapath_resp_t onEOT(); virtual ocsd_datapath_resp_t onReset(); virtual ocsd_datapath_resp_t onFlush(); virtual ocsd_err_t onProtocolConfig(); virtual const uint8_t getCoreSightTraceID() { return m_CSID; }; /* local decode methods */ void initDecoder(); // initial state on creation (zeros all config) void resetDecoder(); // reset state to start of decode. (moves state, retains config) ocsd_datapath_resp_t decodePacket(bool &Complete); // return true to indicate decode complete - can change FSM to commit state - return is false. ocsd_datapath_resp_t commitElements(bool &Complete); // commit elements - may get wait response, or flag completion. ocsd_datapath_resp_t flushEOT(); void doTraceInfoPacket(); void updateContext(TrcStackElemCtxt *pCtxtElem); // process atom will output instruction trace, or no memory access trace elements. ocsd_datapath_resp_t processAtom(const ocsd_atm_val, bool &bCont); // process an exception element - output instruction trace + exception generic type. ocsd_datapath_resp_t processException(); // process a bad packet ocsd_datapath_resp_t handleBadPacket(const char *reason); ocsd_datapath_resp_t outputCC(TrcStackElemParam *pParamElem); ocsd_datapath_resp_t outputTS(TrcStackElemParam *pParamElem, bool withCC); ocsd_datapath_resp_t outputEvent(TrcStackElemParam *pParamElem); private: void SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa); ocsd_err_t traceInstrToWP(bool &bWPFound, const bool traceToAddrNext = false, const ocsd_vaddr_t nextAddrMatch = 0); //!< follow instructions from the current address to a WP. true if good, false if memory cannot be accessed. ocsd_datapath_resp_t returnStackPop(); // pop return stack and update instruction address. + ocsd_datapath_resp_t outputTraceRange(const bool executed, ocsd_trc_index_t index); + //** intra packet state (see ETMv4 spec 6.2.1); // timestamping uint64_t m_timestamp; // last broadcast global Timestamp. // state and context uint32_t m_context_id; // most recent context ID uint32_t m_vmid_id; // most recent VMID bool m_is_secure; // true if Secure bool m_is_64bit; // true if 64 bit // cycle counts int m_cc_threshold; // speculative trace (unsupported at present in the decoder). int m_curr_spec_depth; int m_max_spec_depth; // data trace associative elements (unsupported at present in the decoder). int m_p0_key; int m_p0_key_max; // conditional non-branch trace - when data trace active (unsupported at present in the decoder) int m_cond_c_key; int m_cond_r_key; int m_cond_key_max_incr; uint8_t m_CSID; //!< Coresight trace ID for this decoder. bool m_IASize64; //!< True if 64 bit instruction addresses supported. //** Other processor state; // trace decode FSM typedef enum { NO_SYNC, //!< pre start trace - init state or after reset or overflow, loss of sync. WAIT_SYNC, //!< waiting for sync packet. WAIT_TINFO, //!< waiting for trace info packet. DECODE_PKTS, //!< processing packets - creating decode elements on stack COMMIT_ELEM, //!< commit elements for execution - create generic trace elements and pass on. } processor_state_t; processor_state_t m_curr_state; //** P0 element stack EtmV4P0Stack m_P0_stack; //!< P0 decode element stack int m_P0_commit; //!< number of elements to commit // packet decode state bool m_need_ctxt; //!< need context to continue bool m_need_addr; //!< need an address to continue bool m_except_pending_addr; //!< next address packet is part of exception. // exception packet processing state (may need excep elem only, range+excep, range+ typedef enum { EXCEP_POP, // start of processing read exception packets off the stack and analyze EXCEP_RANGE, // output a range element EXCEP_NACC, // output a nacc element + EXCEP_CTXT, // output a ctxt element EXCEP_EXCEP, // output an ecxeption element. } excep_proc_state_t; - excep_proc_state_t m_excep_proc; //!< state of exception processing - etmv4_addr_val_t m_excep_addr; //!< excepiton return address. - ocsd_trc_index_t m_excep_index; //!< trace index for exception element + struct { + excep_proc_state_t proc; //!< state of exception processing + etmv4_addr_val_t addr; //!< excetion return address. + uint32_t number; //!< exception number. + ocsd_trc_index_t index; //!< trace index for exception element + bool addr_b_tgt; //!< return address is also branch tgt address. + } m_excep_info; //!< exception info when processing exception packets ocsd_instr_info m_instr_info; //!< instruction info for code follower - in address is the next to be decoded. bool m_mem_nacc_pending; //!< need to output a memory access failure packet ocsd_vaddr_t m_nacc_addr; //!< record unaccessible address ocsd_pe_context m_pe_context; //!< current context information etmv4_trace_info_t m_trace_info; //!< trace info for this trace run. bool m_prev_overflow; bool m_flush_EOT; //!< true if doing an end of trace flush - cleans up lingering events / TS / CC TrcAddrReturnStack m_return_stack; //** output element OcsdTraceElement m_output_elem; }; #endif // ARM_TRC_PKT_DECODE_ETMV4I_H_INCLUDED /* End of File trc_pkt_decode_etmv4i.h */ Index: head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h (revision 353393) @@ -1,520 +1,525 @@ /* * \file trc_pkt_elem_etmv4i.h * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_PKT_ELEM_ETMV4I_H_INCLUDED #define ARM_TRC_PKT_ELEM_ETMV4I_H_INCLUDED #include "trc_pkt_types_etmv4.h" #include "common/trc_printable_elem.h" #include "common/trc_pkt_elem_base.h" /** @addtogroup trc_pkts @{*/ /*! * @class Etmv4PktAddrStack * @brief ETMv4 Address packet values stack * @ingroup trc_pkts * * This class represents a stack of recent broadcast address values - * used to fulfil the ExactMatch address type where no address is output. * */ class Etmv4PktAddrStack { public: Etmv4PktAddrStack() { for (int i = 0; i < 3; i++) { m_v_addr[i].pkt_bits = 0; m_v_addr[i].size = VA_64BIT; m_v_addr[i].val = 0; m_v_addr[i].valid_bits = 0; m_v_addr_ISA[i] = 0; } } ~Etmv4PktAddrStack() {}; void push(const ocsd_pkt_vaddr vaddr, const uint8_t isa) { m_v_addr[2] = m_v_addr[1]; m_v_addr[1] = m_v_addr[0]; m_v_addr[0] = vaddr; m_v_addr_ISA[2] = m_v_addr_ISA[1]; m_v_addr_ISA[1] = m_v_addr_ISA[0]; m_v_addr_ISA[0] = isa; } void get_idx(const uint8_t idx, ocsd_pkt_vaddr &vaddr, uint8_t &isa) { if (idx < 3) { vaddr = m_v_addr[idx]; isa = m_v_addr_ISA[idx]; } } private: ocsd_pkt_vaddr m_v_addr[3]; //!< most recently broadcast address packet uint8_t m_v_addr_ISA[3]; }; /*! * @class EtmV4ITrcPacket * @brief ETMv4 Instuction Trace Protocol Packet. * @ingroup trc_pkts * * This class represents a single ETMv4 data trace packet, along with intra packet state. * */ class EtmV4ITrcPacket : public TrcPacketBase, public ocsd_etmv4_i_pkt, public trcPrintableElem { public: EtmV4ITrcPacket(); ~EtmV4ITrcPacket(); EtmV4ITrcPacket &operator =(const ocsd_etmv4_i_pkt* p_pkt); virtual const void *c_pkt() const { return (const ocsd_etmv4_i_pkt *)this; }; // update interface - set packet values void initStartState(); //!< Set to initial state - no intra packet state valid. Use on start of trace / discontinuities. void initNextPacket(); //!< clear any single packet only flags / state. void setType(const ocsd_etmv4_i_pkt_type pkt_type) { type = pkt_type; }; - void updateErrType(const ocsd_etmv4_i_pkt_type err_pkt_type); + void 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 setContextVMID(const uint32_t VMID); void setContextCID(const uint32_t CID); void setExceptionInfo(const uint16_t excep_type, const uint8_t addr_interp, const uint8_t m_fault_pending, const uint8_t m_type); void set64BitAddress(const uint64_t addr, const uint8_t IS); void set32BitAddress(const uint32_t addr, const uint8_t IS); void updateShortAddress(const uint32_t addr, const uint8_t IS, const uint8_t update_bits); void setAddressExactMatch(const uint8_t idx); void setDataSyncMarker(const uint8_t dsm_val); void setEvent(const uint8_t event_val); void setQType(const bool has_count, const uint32_t count, const bool has_addr, const bool addr_match, const uint8_t type); // packet status interface - get packet info. const ocsd_etmv4_i_pkt_type getType() const { return type; }; const ocsd_etmv4_i_pkt_type getErrType() const { return err_type; }; //! return true if this packet has set the commit packet count. const bool hasCommitElementsCount() const { return pkt_valid.bits.commit_elem_valid ? true : false; }; // trace info const etmv4_trace_info_t &getTraceInfo() const { return trace_info; }; const uint32_t getCCThreshold() const; const uint32_t getP0Key() const; const uint32_t getCurrSpecDepth() const; // atom const ocsd_pkt_atom &getAtom() const { return atom; }; // context const etmv4_context_t &getContext() const { return context; }; // address const uint8_t &getAddrMatch() const { return addr_exact_match_idx; }; const ocsd_vaddr_t &getAddrVal() const { return v_addr.val; }; const uint8_t &getAddrIS() const { return v_addr_ISA; }; const bool getAddr64Bit() const { return v_addr.size == VA_64BIT; }; // ts const uint64_t getTS() const { return pkt_valid.bits.ts_valid ? ts.timestamp : 0; }; // cc const uint32_t getCC() const { return pkt_valid.bits.cc_valid ? cycle_count : 0; }; // packet type const bool isBadPacket() const; // printing virtual void toString(std::string &str) const; virtual void toStringFmt(const uint32_t fmtFlags, std::string &str) const; private: const char *packetTypeName(const ocsd_etmv4_i_pkt_type type, const char **pDesc) const; void contextStr(std::string &ctxtStr) const; void atomSeq(std::string &valStr) const; void addrMatchIdx(std::string &valStr) const; void exceptionInfo(std::string &valStr) const; void push_vaddr(); void pop_vaddr_idx(const uint8_t idx); Etmv4PktAddrStack m_addr_stack; }; -inline void EtmV4ITrcPacket::updateErrType(const ocsd_etmv4_i_pkt_type err_pkt_type) +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; - pkt_valid.bits.ts_valid = 0; // mark TS as invalid - must be re-updated after trace info. + // set these as defaults - if they don't appear in TINFO this is the state. + setTraceInfo(0); + setTraceInfoSpec(0); } inline void EtmV4ITrcPacket::setTraceInfo(const uint32_t infoVal) { trace_info.val = infoVal; pkt_valid.bits.trace_info_valid = 1; } inline void EtmV4ITrcPacket::setTraceInfoKey(const uint32_t keyVal) { p0_key = keyVal; pkt_valid.bits.p0_key_valid = 1; } inline void EtmV4ITrcPacket::setTraceInfoSpec(const uint32_t specVal) { curr_spec_depth = specVal; pkt_valid.bits.spec_depth_valid = 1; } inline void EtmV4ITrcPacket::setTraceInfoCyct(const uint32_t cyctVal) { cc_threshold = cyctVal; pkt_valid.bits.cc_thresh_valid = 1; } inline void EtmV4ITrcPacket::setTS(const uint64_t value, const uint8_t bits) { uint64_t mask = (uint64_t)-1LL; if(bits < 64) mask = (1ULL << bits) - 1; ts.timestamp = (ts.timestamp & ~mask) | (value & mask); ts.bits_changed = bits; pkt_valid.bits.ts_valid = 1; } inline void EtmV4ITrcPacket::setCycleCount(const uint32_t value) { pkt_valid.bits.cc_valid = 1; cycle_count = value; } inline void EtmV4ITrcPacket::setCommitElements(const uint32_t commit_elem) { pkt_valid.bits.commit_elem_valid = 1; commit_elements = commit_elem; } inline const uint32_t EtmV4ITrcPacket::getCCThreshold() const { if(pkt_valid.bits.cc_thresh_valid) return cc_threshold; return 0; } inline const uint32_t EtmV4ITrcPacket::getP0Key() const { if(pkt_valid.bits.p0_key_valid) return p0_key; return 0; } inline const uint32_t EtmV4ITrcPacket::getCurrSpecDepth() const { if(pkt_valid.bits.spec_depth_valid) return curr_spec_depth; return 0; } inline void EtmV4ITrcPacket::setCancelElements(const uint32_t cancel_elem) { cancel_elements = cancel_elem; } inline void EtmV4ITrcPacket::setAtomPacket(const ocsd_pkt_atm_type type, const uint32_t En_bits, const uint8_t num) { if(type == ATOM_REPEAT) { uint32_t bit_patt = En_bits & 0x1; if(bit_patt) { // none zero - all 1s bit_patt = (bit_patt << num) - 1; } atom.En_bits = bit_patt; } else atom.En_bits = En_bits; atom.num = num; } inline void EtmV4ITrcPacket::setCondIF1(const uint32_t cond_key) { cond_instr.cond_key_set = 1; cond_instr.f3_final_elem = 0; cond_instr.f2_cond_incr = 0; cond_instr.num_c_elem = 1; cond_instr.cond_c_key = cond_key; } inline void EtmV4ITrcPacket::setCondIF2(const uint8_t c_elem_idx) { cond_instr.cond_key_set = 0; cond_instr.f3_final_elem = 0; switch(c_elem_idx & 0x3) { case 0: cond_instr.f2_cond_incr = 1; cond_instr.num_c_elem = 1; break; case 1: cond_instr.f2_cond_incr = 0; cond_instr.num_c_elem = 1; break; case 2: cond_instr.f2_cond_incr = 1; cond_instr.num_c_elem = 2; break; } } inline void EtmV4ITrcPacket::setCondIF3(const uint8_t num_c_elem, const bool finalElem) { cond_instr.cond_key_set = 0; cond_instr.f3_final_elem = finalElem ? 1: 0; cond_instr.f2_cond_incr = 0; cond_instr.num_c_elem = num_c_elem; } inline void EtmV4ITrcPacket::setCondRF1(const uint32_t key[2], const uint8_t res[2], const uint8_t CI[2],const bool set2Keys) { cond_result.key_res_0_set = 1; cond_result.cond_r_key_0 = key[0]; cond_result.res_0 = res[0]; cond_result.ci_0 = CI[0]; if(set2Keys) { cond_result.key_res_1_set = 1; cond_result.cond_r_key_1 = key[1]; cond_result.res_1 = res[1]; cond_result.ci_1 = CI[1]; } } inline void EtmV4ITrcPacket::setCondRF2(const uint8_t key_incr, const uint8_t token) { cond_result.key_res_0_set = 0; cond_result.key_res_1_set = 0; cond_result.f2_key_incr = key_incr; cond_result.f2f4_token = token; } inline void EtmV4ITrcPacket::setCondRF3(const uint16_t tokens) { cond_result.key_res_0_set = 0; cond_result.key_res_1_set = 0; cond_result.f3_tokens = tokens; } inline void EtmV4ITrcPacket::setCondRF4(const uint8_t token) { cond_result.key_res_0_set = 0; cond_result.key_res_1_set = 0; cond_result.f2f4_token = token; } inline void EtmV4ITrcPacket::setContextInfo(const bool update, const uint8_t EL, const uint8_t NS, const uint8_t SF) { pkt_valid.bits.context_valid = 1; if(update) { context.updated = 1; context.EL = EL; context.NS = NS; context.SF = SF; } } inline void EtmV4ITrcPacket::setContextVMID(const uint32_t VMID) { pkt_valid.bits.context_valid = 1; context.updated = 1; context.VMID = VMID; context.updated_v = 1; } inline void EtmV4ITrcPacket::setContextCID(const uint32_t CID) { pkt_valid.bits.context_valid = 1; context.updated = 1; context.ctxtID = CID; context.updated_c = 1; } inline void EtmV4ITrcPacket::setExceptionInfo(const uint16_t excep_type, const uint8_t addr_interp, const uint8_t m_fault_pending, const uint8_t m_type) { exception_info.exceptionType = excep_type; exception_info.addr_interp = addr_interp; exception_info.m_fault_pending = m_fault_pending; exception_info.m_type = m_type; } inline void EtmV4ITrcPacket::set64BitAddress(const uint64_t addr, const uint8_t IS) { v_addr.pkt_bits = 64; v_addr.valid_bits = 64; v_addr.size = VA_64BIT; v_addr.val = addr; v_addr_ISA = IS; push_vaddr(); } inline void EtmV4ITrcPacket::set32BitAddress(const uint32_t addr, const uint8_t IS) { uint64_t mask = OCSD_BIT_MASK(32); v_addr.pkt_bits = 32; - if (pkt_valid.bits.context_valid && context.SF) - v_addr.size = VA_64BIT; + if (pkt_valid.bits.context_valid && context.SF) + { + v_addr.size = VA_64BIT; + 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.val = (v_addr.val & ~mask) | (addr & mask); + } else { - v_addr.val &= 0xFFFFFFFF; // ensure vaddr is only 32 bits if not 64 bit + v_addr.val = addr; v_addr.size = VA_32BIT; - } - - if (v_addr.valid_bits < 32) // may be 64 bit address so only set 32 if less - v_addr.valid_bits = 32; - - v_addr.val = (v_addr.val & ~mask) | (addr & mask); + v_addr.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); } /** @}*/ #endif // ARM_TRC_PKT_ELEM_ETMV4I_H_INCLUDED /* End of File trc_pkt_elem_etmv4i.h */ Index: head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h (revision 353393) @@ -1,350 +1,367 @@ /* * \file trc_pkt_types_etmv4.h - * \brief OpenCSD : + * \brief OpenCSD : ETMv4 packet info * - * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + * \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_TYPES_ETMV4_H_INCLUDED #define ARM_TRC_PKT_TYPES_ETMV4_H_INCLUDED #include "opencsd/trc_pkt_types.h" /** @addtogroup trc_pkts @{*/ /** @name ETMv4 Packet Types @{*/ /** I stream packets. */ typedef enum _ocsd_etmv4_i_pkt_type { /* state of decode markers */ ETM4_PKT_I_NOTSYNC = 0x200, /*!< no sync found yet. */ ETM4_PKT_I_INCOMPLETE_EOT, /*!< flushing incomplete/empty packet at end of trace.*/ ETM4_PKT_I_NO_ERR_TYPE, /*!< error type not set for packet. */ /* markers for unknown/bad packets */ ETM4_PKT_I_BAD_SEQUENCE = 0x300, /*!< invalid sequence for packet type. */ ETM4_PKT_I_BAD_TRACEMODE, /*!< invalid packet type for this trace mode. */ ETM4_PKT_I_RESERVED, /*!< packet type reserved. */ + ETM4_PKT_I_RESERVED_CFG, /*!< packet type reserved for current configuration */ /* I stream packet types. */ /* extension header. */ - ETM4_PKT_I_EXTENSION = 0x00, /*!< b00000000 */ + ETM4_PKT_I_EXTENSION = 0x00, /*!< b00000000 */ - /* address amd context */ - ETM4_PKT_I_ADDR_CTXT_L_32IS0 = 0x82, /*!< b10000010 */ + /* 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 */ + + /* unused encodings 0x08-0xB b00001000 to b00001011 */ + + /* 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, /*!< b0010111x */ + ETM4_PKT_I_MISPREDICT = 0x30, /*!< b001100xx */ + ETM4_PKT_I_CANCEL_F2 = 0x34, /*!< b001101xx */ + ETM4_PKT_I_CANCEL_F3 = 0x38, /*!< b00111xxx */ + + /* conditional instruction tracing */ + 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 b10000100 */ - ETM4_PKT_I_ADDR_CTXT_L_64IS0 = 0x85, /*!< b10000101 */ + /* unused encoding 0x84 b10000100 */ + ETM4_PKT_I_ADDR_CTXT_L_64IS0 = 0x85, /*!< b10000101 */ ETM4_PKT_I_ADDR_CTXT_L_64IS1, /*!< b10000110 */ - /* unused encoding b10000111 */ - ETM4_PKT_I_CTXT = 0x80, /*!< b1000000x */ - ETM4_PKT_I_ADDR_MATCH = 0x90, /*!< b10010000 to b10010010 */ - ETM4_PKT_I_ADDR_L_32IS0 = 0x9A, /*!< b10011010 */ + /* unused encoding 0x87 b10000111 */ + /* unused encodings 0x88-0x8F b10001xxx */ + 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 b10011100 */ - ETM4_PKT_I_ADDR_L_64IS0 = 0x9D, /*!< b10011101 */ + /* unused encoding 0x9C b10011100 */ + ETM4_PKT_I_ADDR_L_64IS0 = 0x9D, /*!< b10011101 */ ETM4_PKT_I_ADDR_L_64IS1, /*!< b10011110 */ - /* unused encoding b10011111 */ - ETM4_PKT_I_ADDR_S_IS0 = 0x95, /*!< b10010101 */ - ETM4_PKT_I_ADDR_S_IS1, /*!< b10010110 */ - /* unused encoding b10010111 - unused encoding b10011000 - unused encoding b10011001 */ + /* unused encoding 0x9F b10011111 */ /* Q packets */ ETM4_PKT_I_Q = 0xA0, /*!< b1010xxxx */ + /* unused encodings 0xB0-0xBF b1011xxxx */ + /* Atom packets */ - ETM4_PKT_I_ATOM_F1 = 0xF6, /*!< b1111011x */ - ETM4_PKT_I_ATOM_F2 = 0xD8, /*!< b110110xx */ - ETM4_PKT_I_ATOM_F3 = 0xF8, //!< b11111xxx - ETM4_PKT_I_ATOM_F4 = 0xDC, //!< b110111xx - ETM4_PKT_I_ATOM_F5 = 0xD5, //!< b11010101 - b11010111, b11110101 - ETM4_PKT_I_ATOM_F6 = 0xC0, //!< b11000000 - b11010100, b11100000 - b11110100 + 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 */ - /* conditional instruction tracing */ - ETM4_PKT_I_COND_FLUSH = 0x43, //!< b01000011 - ETM4_PKT_I_COND_I_F1 = 0x6C, //!< b01101100 - ETM4_PKT_I_COND_I_F2 = 0x40, //!< b01000000 - b01000010 - ETM4_PKT_I_COND_I_F3 = 0x6D, //!< b01101101 - ETM4_PKT_I_COND_RES_F1 = 0x68, //!< b0110111x, b011010xx - ETM4_PKT_I_COND_RES_F2 = 0x48, //!< b0100100x, b01001010, b0100110x, b01001110 - ETM4_PKT_I_COND_RES_F3 = 0x50, //!< b0101xxxx - ETM4_PKT_I_COND_RES_F4 = 0x44, //!< b0100010x, b01000110 - - /* cycle count packets */ - ETM4_PKT_I_CCNT_F1 = 0x0E, //!< b0000111x - ETM4_PKT_I_CCNT_F2 = 0x0C, //!< b0000110x - ETM4_PKT_I_CCNT_F3 = 0x10, //!< b0001xxxx - // data synchronisation markers - ETM4_PKT_I_NUM_DS_MKR = 0x20, //!< b00100xxx - ETM4_PKT_I_UNNUM_DS_MKR = 0x28, //!< b00101000 - b00101100 - // event trace - ETM4_PKT_I_EVENT = 0x70, //!< b0111xxxx - // Exceptions - ETM4_PKT_I_EXCEPT = 0x06, //!< b00000110 - ETM4_PKT_I_EXCEPT_RTN = 0x07, //!< b00000111 - // timestamp - ETM4_PKT_I_TIMESTAMP = 0x02, //!< b0000001x - // speculation - ETM4_PKT_I_CANCEL_F1 = 0x2E, //!< b0010111x - ETM4_PKT_I_CANCEL_F2 = 0x34, //!< b001101xx - ETM4_PKT_I_CANCEL_F3 = 0x38, //!< b00111xxx - ETM4_PKT_I_COMMIT = 0x2D, //!< b00101101 - ETM4_PKT_I_MISPREDICT = 0x30, //!< b001100xx - // Sync - ETM4_PKT_I_TRACE_INFO = 0x01, //!< b00000001 - ETM4_PKT_I_TRACE_ON = 0x04, //!< b00000100 // extension packets - follow 0x00 header ETM4_PKT_I_ASYNC = 0x100, //!< b00000000 ETM4_PKT_I_DISCARD = 0x103, //!< b00000011 - ETM4_PKT_I_OVERFLOW = 0x105 //!< b00000101 + ETM4_PKT_I_OVERFLOW = 0x105, //!< b00000101 } ocsd_etmv4_i_pkt_type; typedef union _etmv4_trace_info_t { uint32_t val; //!< trace info full value. struct { uint32_t cc_enabled:1; //!< 1 if cycle count enabled uint32_t cond_enabled:3; //!< conditional trace enabeld type uint32_t p0_load:1; //!< 1 if tracing with P0 load elements (for data trace) - uint32_t p0_store:1; //1< 1 if tracing with P0 store elements (for data trace) + uint32_t p0_store:1; //!< 1 if tracing with P0 store elements (for data trace) } bits; //!< bitfields for trace info value. } etmv4_trace_info_t; typedef struct _etmv4_context_t { struct { uint32_t EL:2; //!< exception level. uint32_t SF:1; //!< sixty four bit uint32_t NS:1; //!< none secure uint32_t updated:1; //!< updated this context packet (otherwise same as last time) uint32_t updated_c:1; //!< updated CtxtID uint32_t updated_v:1; //!< updated VMID }; uint32_t ctxtID; //!< Current ctxtID uint32_t VMID; //!< current VMID } etmv4_context_t; /** a broadcast address value. */ typedef struct _etmv4_addr_val_t { ocsd_vaddr_t val; //!< Address value. uint8_t isa; //!< instruction set. } etmv4_addr_val_t; typedef struct _ocsd_etmv4_i_pkt { ocsd_etmv4_i_pkt_type type; /**< Trace packet type derived from header byte */ //** intra-packet data - valid across packets. ocsd_pkt_vaddr v_addr; //!< most recently broadcast address packet uint8_t v_addr_ISA; //!< ISA for the address packet. (0 = IS0 / 1 = IS1) etmv4_context_t context; //!< current context for PE struct { uint64_t timestamp; //!< current timestamp value uint8_t bits_changed; //!< bits updated in this timestamp packet. } ts; uint32_t cc_threshold; //!< cycle count threshold - from trace info. // single packet data - only valid for specific packet types on packet instance. ocsd_pkt_atom atom; //!< atom elements - number of atoms indicates validity of packet uint32_t cycle_count; //!< cycle count uint32_t curr_spec_depth; //!< current speculation depth uint32_t p0_key; //!< current P0 key value for data packet synchronisation uint32_t commit_elements; // data value, timestamp value, event value */ ocsd_etmv4_d_pkt_type err_type; } ocsd_etmv4_d_pkt; typedef struct _ocsd_etmv4_cfg { uint32_t reg_idr0; /**< ID0 register */ uint32_t reg_idr1; /**< ID1 register */ uint32_t reg_idr2; /**< ID2 register */ uint32_t reg_idr8; uint32_t reg_idr9; uint32_t reg_idr10; uint32_t reg_idr11; uint32_t reg_idr12; uint32_t reg_idr13; uint32_t reg_configr; /**< Config Register */ uint32_t reg_traceidr; /**< Trace Stream ID register */ ocsd_arch_version_t arch_ver; /**< Architecture version */ ocsd_core_profile_t core_prof; /**< Core Profile */ } ocsd_etmv4_cfg; + /** @}*/ /** @}*/ #endif // ARM_TRC_PKT_TYPES_ETMV4_H_INCLUDED /* End of File trc_pkt_types_etmv4.h */ Index: head/contrib/opencsd/decoder/include/opencsd/ocsd_if_types.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/ocsd_if_types.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/ocsd_if_types.h (revision 353393) @@ -1,592 +1,626 @@ /*! * \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 inteface not supported by this decoder. */ + 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, /**< unknown architecture */ + ARCH_CUSTOM, /**< None ARM, custom architecture */ ARCH_V7, /**< V7 architecture */ ARCH_V8, /**< V8 architecture */ - ARCH_CUSTOM, /**< None ARM, custom architecture */ + ARCH_V8r3, /**< V8.3 architecture */ } 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) + /** Core Profile */ typedef enum _ocsd_core_profile { profile_Unknown, /**< Unknown profile */ profile_CortexM, /**< Cortex-M profile */ profile_CortexR, /**< Cortex-R profile */ profile_CortexA, /**< Cortex-A profile */ profile_Custom, /**< None ARM, custom arch profile */ } ocsd_core_profile_t; /** Combined architecture and profile descriptor for a core */ typedef struct _ocsd_arch_profile_t { ocsd_arch_version_t arch; /**< core architecture */ ocsd_core_profile_t profile; /**< core profile */ } ocsd_arch_profile_t; /* may want to use a 32 bit v-addr when running on 32 bit only ARM platforms. */ #ifdef USE_32BIT_V_ADDR typedef uint32_t ocsd_vaddr_t; /**< 32 bit virtual addressing in library - use if compiling on 32 bit platforms */ #define OCSD_MAX_VA_BITSIZE 32 /**< 32 bit Virtual address bitsize macro */ #define OCSD_VA_MASK ~0UL /**< 32 bit Virtual address bitsize mask */ #else typedef uint64_t ocsd_vaddr_t; /**< 64 bit virtual addressing in library */ #define OCSD_MAX_VA_BITSIZE 64 /**< 64 bit Virtual address bitsize macro */ #define OCSD_VA_MASK ~0ULL /**< 64 bit Virtual address bitsize mask */ #endif /** A bit mask for the first 'bits' consecutive bits of an address */ #define OCSD_BIT_MASK(bits) (bits == OCSD_MAX_VA_BITSIZE) ? OCSD_VA_MASK : ((ocsd_vaddr_t)1 << bits) - 1 /** @}*/ /** @name Instruction Decode Information @{*/ /** Instruction Set Architecture type * */ typedef enum _ocsd_isa { ocsd_isa_arm, /**< V7 ARM 32, V8 AArch32 */ ocsd_isa_thumb2, /**< Thumb2 -> 16/32 bit instructions */ ocsd_isa_aarch64, /**< V8 AArch64 */ ocsd_isa_tee, /**< Thumb EE - unsupported */ ocsd_isa_jazelle, /**< Jazelle - unsupported in trace */ ocsd_isa_custom, /**< Instruction set - custom arch decoder */ ocsd_isa_unknown /**< ISA not yet known */ } ocsd_isa; /** Security level type */ typedef enum _ocsd_sec_level { ocsd_sec_secure, /**< Core is in secure state */ ocsd_sec_nonsecure /**< Core is in non-secure state */ } ocsd_sec_level ; /** Exception level type */ typedef enum _ocsd_ex_level { ocsd_EL_unknown = -1, /**< EL unknown / unsupported in trace */ ocsd_EL0 = 0, /**< EL0 */ ocsd_EL1, /**< EL1 */ ocsd_EL2, /**< EL2 */ ocsd_EL3, /**< EL3 */ } ocsd_ex_level; /** instruction types - significant for waypoint calculaitons */ typedef enum _ocsd_instr_type { OCSD_INSTR_OTHER, /**< Other instruction - not significant for waypoints. */ OCSD_INSTR_BR, /**< Immediate Branch instruction */ OCSD_INSTR_BR_INDIRECT, /**< Indirect Branch instruction */ OCSD_INSTR_ISB, /**< Barrier : ISB instruction */ - OCSD_INSTR_DSB_DMB /**< Barrier : DSB or DMB instruction */ + OCSD_INSTR_DSB_DMB, /**< Barrier : DSB or DMB instruction */ + OCSD_INSTR_WFI_WFE, /**< WFI or WFE traced as direct branch */ } 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_S = 0x9, /**< Any S */ OCSD_MEM_SPACE_N = 0x6, /**< Any NS */ OCSD_MEM_SPACE_ANY = 0xF, /**< Any sec level / EL - live system use current EL + sec state */ } ocsd_mem_space_acc_t; /** * Callback function definition for callback function memory accessor type. * * When using callback memory accessor, the decoder will call this function to obtain the * memory at the address for the current opcodes. The memory space will represent the current * exception level and security context of the traced code. * * Return the number of bytes read, which can be less than the amount requested if this would take the * access address outside the range of addresses defined when this callback was registered with the decoder. * * Return 0 bytes if start address out of covered range, or memory space is not one of those defined as supported * when the callback was registered. * * @param p_context : opaque context pointer set by callback client. * @param address : start address of memory to be accessed * @param mem_space : memory space of accessed memory (current EL & security state) * @param reqBytes : number of bytes required * @param *byteBuffer : buffer for data. * * @return uint32_t : Number of bytes actually read, or 0 for access error. */ -typedef uint32_t (* Fn_MemAcc_CB)(const void *p_context, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer); +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, component specific - top 16 bits. @{*/ #define OCSD_OPFLG_PKTPROC_NOFWD_BAD_PKTS 0x00000001 /**< don't forward bad packets up data path */ #define OCSD_OPFLG_PKTPROC_NOMON_BAD_PKTS 0x00000002 /**< don't forward bad packets to monitor interface */ #define OCSD_OPFLG_PKTPROC_ERR_BAD_PKTS 0x00000004 /**< throw error for bad packets - halt decoding. */ #define OCSD_OPFLG_PKTPROC_UNSYNC_ON_BAD_PKTS 0x00000008 /**< switch to unsynced state on bad packets - wait for next sync point */ /** mask to combine all common packet processor operational control flags */ #define OCSD_OPFLG_PKTPROC_COMMON (OCSD_OPFLG_PKTPROC_NOFWD_BAD_PKTS | \ OCSD_OPFLG_PKTPROC_NOMON_BAD_PKTS | \ OCSD_OPFLG_PKTPROC_ERR_BAD_PKTS | \ OCSD_OPFLG_PKTPROC_UNSYNC_ON_BAD_PKTS ) /** @}*/ /** @name Packet Decoder Operation Control Flags common operational flags - bottom 16 bits, component specific - top 16 bits. @{*/ #define OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS 0x00000001 /**< throw error on bad packets input (default is to unsync and wait) */ /** mask to combine all common packet processor operational control flags */ #define OCSD_OPFLG_PKTDEC_COMMON (OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) /** @}*/ /** @name Decoder creation information Flags to use when creating decoders by name Builtin decoder names. Protocol type enum. @{*/ #define OCSD_CREATE_FLG_PACKET_PROC 0x01 /**< Create packet processor only. */ #define OCSD_CREATE_FLG_FULL_DECODER 0x02 /**< Create packet processor + decoder pair */ #define OCSD_CREATE_FLG_INST_ID 0x04 /**< Use instance ID in decoder instance name */ #define OCSD_BUILTIN_DCD_STM "STM" /**< STM decoder */ #define OCSD_BUILTIN_DCD_ETMV3 "ETMV3" /**< ETMv3 decoder */ #define OCSD_BUILTIN_DCD_ETMV4I "ETMV4I" /**< ETMv4 instruction decoder */ #define OCSD_BUILTIN_DCD_ETMV4D "ETMV4D" /**< ETMv4 data decoder */ #define OCSD_BUILTIN_DCD_PTM "PTM" /**< PTM decoder */ /*! Trace Protocol Builtin Types + extern */ typedef enum _ocsd_trace_protocol_t { OCSD_PROTOCOL_UNKNOWN = 0, /**< Protocol unknown */ /* Built in library decoders */ OCSD_PROTOCOL_ETMV3, /**< ETMV3 instruction and data trace protocol decoder. */ OCSD_PROTOCOL_ETMV4I, /**< ETMV4 instruction trace protocol decoder. */ OCSD_PROTOCOL_ETMV4D, /**< ETMV4 data trace protocol decoder. */ OCSD_PROTOCOL_PTM, /**< PTM program flow instruction trace protocol decoder. */ OCSD_PROTOCOL_STM, /**< STM system trace protocol decoder. */ /* others to be added here */ OCSD_PROTOCOL_BUILTIN_END, /**< Invalid protocol - built-in protocol types end marker */ /* Custom / external decoders */ OCSD_PROTOCOL_CUSTOM_0 = 100, /**< Values from this onwards are assigned to external registered decoders */ OCSD_PROTOCOL_CUSTOM_1, OCSD_PROTOCOL_CUSTOM_2, OCSD_PROTOCOL_CUSTOM_3, OCSD_PROTOCOL_CUSTOM_4, OCSD_PROTOCOL_CUSTOM_5, OCSD_PROTOCOL_CUSTOM_6, OCSD_PROTOCOL_CUSTOM_7, OCSD_PROTOCOL_CUSTOM_8, OCSD_PROTOCOL_CUSTOM_9, OCSD_PROTOCOL_END /**< Invalid protocol - protocol types end marker */ } ocsd_trace_protocol_t; /** Test if protocol type is a library built-in decoder */ #define OCSD_PROTOCOL_IS_BUILTIN(P) ((P > OCSD_PROTOCOL_UNKNOWN) && (P < OCSD_PROTOCOL_BUILTIN_END)) /** Test if protocol type is a custom external registered decoder */ #define OCSD_PROTOCOL_IS_CUSTOM(P) ((P >= OCSD_PROTOCOL_CUSTOM_0) && (P < OCSD_PROTOCOL_END )) /** @}*/ /** @name Software Trace Packets Info Contains the information for the generic software trace output packet. Software trace packet master and channel data. Payload info: size - packet payload size in bits; marker - if this packet has a marker/flag timestamp - if this packet has a timestamp associated number of packets - packet processor can optionally correlate identically sized packets on the same master / channel to be output as a single generic packet Payload output as separate LE buffer, of sufficient bytes to hold all the packets. @{*/ typedef struct _ocsd_swt_info { uint16_t swt_master_id; uint16_t swt_channel_id; union { struct { uint32_t swt_payload_pkt_bitsize:8; /**< [bits 0:7 ] Packet size in bits of the payload packets */ uint32_t swt_payload_num_packets:8; /**< [bits 8:15 ] number of consecutive packets of this type in the payload data */ uint32_t swt_marker_packet:1; /**< [bit 16 ] packet is marker / flag packet */ uint32_t swt_has_timestamp:1; /**< [bit 17 ] packet has timestamp. */ uint32_t swt_marker_first:1; /**< [bit 18 ] for multiple packet payloads, this indicates if any marker is on first or last packet */ uint32_t swt_master_err:1; /**< [bit 19 ] current master has error - payload is error code */ uint32_t swt_global_err:1; /**< [bit 20 ] global error - payload is error code - master and channel ID not valid */ uint32_t swt_trigger_event:1; /**< [bit 21 ] trigger event packet - payload is event number */ uint32_t swt_frequency:1; /**< [bit 22 ] frequency packet - payload is frequency */ uint32_t swt_id_valid:1; /**< [bit 23 ] master & channel ID has been set by input stream */ }; uint32_t swt_flag_bits; }; } ocsd_swt_info_t; /** mask for the swt_id_valid flag - need to retain between packets */ #define SWT_ID_VALID_MASK (0x1 << 23) /** @}*/ /** @}*/ #endif // ARM_OCSD_IF_TYPES_H_INCLUDED /* End of File opencsd/ocsd_if_types.h */ Index: head/contrib/opencsd/decoder/include/opencsd/ocsd_if_version.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/ocsd_if_version.h (nonexistent) +++ head/contrib/opencsd/decoder/include/opencsd/ocsd_if_version.h (revision 353393) @@ -0,0 +1,65 @@ +/* + * \file ocsd_if_version.h + * \brief OpenCSD : Library API versioning + * + * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ARM_OCSD_IF_VERSION_H_INCLUDED +#define ARM_OCSD_IF_VERSION_H_INCLUDED + +#include + +/** @addtogroup ocsd_interfaces +@{*/ + +/** @name Library Versioning +@{*/ +#define OCSD_VER_MAJOR 0x0 /**< Library Major Version */ +#define OCSD_VER_MINOR 0xC /**< 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.12.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 */ Property changes on: head/contrib/opencsd/decoder/include/opencsd/ocsd_if_version.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h =================================================================== --- head/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h (revision 353392) +++ head/contrib/opencsd/decoder/include/opencsd/trc_gen_elem_types.h (revision 353393) @@ -1,126 +1,130 @@ /*! * \file opencsd/trc_gen_elem_types.h * \brief OpenCSD : Decoder Output Generic Element types. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_GEN_ELEM_TYPES_H_INCLUDED #define ARM_TRC_GEN_ELEM_TYPES_H_INCLUDED /** @defgroup gen_trc_elem OpenCSD Library : Generic Trace Elements * @brief Generic trace elements output by the PE trace decode and SW stim decode stages. * * @{*/ #include "opencsd/ocsd_if_types.h" /** Enum for generic element types */ typedef enum _ocsd_gen_trc_elem_t { OCSD_GEN_TRC_ELEM_UNKNOWN = 0, /*!< Unknown trace element - default value or indicate error in stream to client */ OCSD_GEN_TRC_ELEM_NO_SYNC, /*!< Waiting for sync - either at start of decode, or after overflow / bad packet */ OCSD_GEN_TRC_ELEM_TRACE_ON, /*!< Start of trace - beginning of elements or restart after discontinuity (overflow, trace filtering). */ OCSD_GEN_TRC_ELEM_EO_TRACE, /*!< end of the available trace in the buffer. */ OCSD_GEN_TRC_ELEM_PE_CONTEXT, /*!< PE status update / change (arch, ctxtid, vmid etc). */ OCSD_GEN_TRC_ELEM_INSTR_RANGE, /*!< traced N consecutive instructions from addr (no intervening events or data elements), may have data assoc key */ OCSD_GEN_TRC_ELEM_ADDR_NACC, /*!< tracing in inaccessible memory area */ OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN, /*!< address currently unknown - need address packet update */ OCSD_GEN_TRC_ELEM_EXCEPTION, /*!< exception - start address may be exception target, end address may be preferred ret addr. */ OCSD_GEN_TRC_ELEM_EXCEPTION_RET, /*!< expection return */ OCSD_GEN_TRC_ELEM_TIMESTAMP, /*!< Timestamp - preceding elements happeded before this time. */ OCSD_GEN_TRC_ELEM_CYCLE_COUNT, /*!< Cycle count - cycles since last cycle count value - associated with a preceding instruction range. */ - OCSD_GEN_TRC_ELEM_EVENT, /*!< Event - trigger, (TBC - perhaps have a set of event types - cut down additional processing?) */ + OCSD_GEN_TRC_ELEM_EVENT, /*!< Event - trigger or numbered event */ OCSD_GEN_TRC_ELEM_SWTRACE, /*!< Software trace packet - may contain data payload. */ OCSD_GEN_TRC_ELEM_CUSTOM, /*!< Fully custom packet type - used by none-ARM architecture decoders */ } ocsd_gen_trc_elem_t; typedef enum _trace_on_reason_t { TRACE_ON_NORMAL = 0, /**< Trace on at start of trace or filtering discontinuity */ TRACE_ON_OVERFLOW, /**< Trace on due to prior trace overflow discontinuity */ TRACE_ON_EX_DEBUG, /**< Trace restarted due to debug exit */ } trace_on_reason_t; typedef struct _trace_event_t { uint16_t ev_type; /**< event type - unknown (0) trigger (1), numbered event (2)*/ uint16_t ev_number; /**< event number if numbered event type */ } trace_event_t; typedef struct _ocsd_generic_trace_elem { ocsd_gen_trc_elem_t elem_type; /**< Element type - remaining data interpreted according to this value */ ocsd_isa isa; /**< instruction set for executed instructions */ ocsd_vaddr_t st_addr; /**< start address for instruction execution range / inaccessible code address / data address */ ocsd_vaddr_t en_addr; /**< end address (exclusive) for instruction execution range. */ ocsd_pe_context context; /**< PE Context */ uint64_t timestamp; /**< timestamp value for TS element type */ uint32_t cycle_count; /**< cycle count for explicit cycle count element, or count for element with associated cycle count */ ocsd_instr_type last_i_type; /**< Last instruction type if instruction execution range */ ocsd_instr_subtype last_i_subtype; /**< sub type for last instruction in range */ //! per element flags union { struct { uint32_t last_instr_exec:1; /**< 1 if last instruction in range was executed; */ + uint32_t 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 */ + 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) */ }; 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 */ Index: head/contrib/opencsd/decoder/include/pkt_printers/pkt_printer_t.h =================================================================== --- head/contrib/opencsd/decoder/include/pkt_printers/pkt_printer_t.h (revision 353392) +++ head/contrib/opencsd/decoder/include/pkt_printers/pkt_printer_t.h (revision 353393) @@ -1,189 +1,189 @@ /* * \file pkt_printer_t.h * \brief OpenCSD : Test packet printer. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_PKT_PRINTER_T_H_INCLUDED #define ARM_PKT_PRINTER_T_H_INCLUDED #include "opencsd.h" #include #include -#include +//#include #include template class PacketPrinter : public IPktDataIn

, public IPktRawDataMon

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

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

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

::~PacketPrinter() { } template ocsd_datapath_resp_t PacketPrinter

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

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

::printIdx_ID(const ocsd_trc_index_t index_sop) { m_oss << "Idx:" << std::dec << index_sop << "; ID:"<< std::hex << (uint32_t)m_trcID; } #endif // ARM_PKT_PRINTER_T_H_INCLUDED /* End of File pkt_printer_t.h */ Index: head/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp =================================================================== --- head/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/c_api/ocsd_c_api.cpp (revision 353393) @@ -1,572 +1,583 @@ /* * \file ocsd_c_api.cpp * \brief OpenCSD : "C" API libary implementation. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* pull in the C++ decode library */ #include "opencsd.h" /* C-API and wrapper objects */ #include "opencsd/c_api/opencsd_c_api.h" #include "ocsd_c_api_obj.h" /** MSVC2010 unwanted export workaround */ #ifdef WIN32 #if (_MSC_VER == 1600) #include namespace std { const nothrow_t nothrow = nothrow_t(); } #endif #endif /*******************************************************************************/ /* C API internal helper function declarations */ /*******************************************************************************/ static ocsd_err_t ocsd_create_pkt_sink_cb(ocsd_trace_protocol_t protocol, FnDefPktDataIn pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ); static ocsd_err_t ocsd_create_pkt_mon_cb(ocsd_trace_protocol_t protocol, FnDefPktDataMon pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ); static ocsd_err_t ocsd_check_and_add_mem_acc_mapper(const dcd_tree_handle_t handle, DecodeTree **ppDT); /*******************************************************************************/ /* C library data - additional data on top of the C++ library objects */ /*******************************************************************************/ /* keep a list of interface objects for a decode tree for later disposal */ typedef struct _lib_dt_data_list { std::vector cb_objs; DefLogStrCBObj s_def_log_str_cb; } lib_dt_data_list; /* map lists to handles */ static std::map s_data_map; /*******************************************************************************/ /* C API functions */ /*******************************************************************************/ -/** Get Library version. Return a 32 bit version in form MMMMnnpp - MMMM = major verison, nn = minor version, pp = patch version */ +/** 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_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; } /*******************************************************************************/ /* 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 */ Index: head/contrib/opencsd/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp =================================================================== --- head/contrib/opencsd/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp (revision 353393) @@ -1,670 +1,671 @@ /*! * \file trc_pkt_decode_etmv3.cpp * \brief OpenCSD : ETMv3 trace packet decode. * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opencsd/etmv3/trc_pkt_decode_etmv3.h" #define DCD_NAME "DCD_ETMV3" TrcPktDecodeEtmV3::TrcPktDecodeEtmV3() : TrcPktDecodeBase(DCD_NAME) { initDecoder(); } TrcPktDecodeEtmV3::TrcPktDecodeEtmV3(int instIDNum) : TrcPktDecodeBase(DCD_NAME, instIDNum) { initDecoder(); } TrcPktDecodeEtmV3::~TrcPktDecodeEtmV3() { } /* implementation packet decoding interface */ ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; bool bPktDone = false; if(!m_config) return OCSD_RESP_FATAL_NOT_INIT; // iterate round the state machine, waiting for sync, then decoding packets. while(!bPktDone) { switch(m_curr_state) { case NO_SYNC: // output the initial not synced packet to the sink resp = sendUnsyncPacket(); m_curr_state = WAIT_ASYNC; // immediate wait for ASync and actually check out the packet break; case WAIT_ASYNC: // if async, wait for ISync, but this packet done. if(m_curr_packet_in->getType() == ETM3_PKT_A_SYNC) m_curr_state = WAIT_ISYNC; bPktDone = true; break; case WAIT_ISYNC: m_bWaitISync = true; // we are waiting for ISync if((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC) || (m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE)) { // process the ISync immediately as the first ISync seen. resp = processISync((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE),true); m_curr_state = SEND_PKTS; m_bWaitISync = false; } // something like TS, CC, PHDR+CC, which after ASYNC may be valid prior to ISync else if(preISyncValid(m_curr_packet_in->getType())) { // decode anything that might be valid - send will be set automatically resp = decodePacket(bPktDone); } else bPktDone = true; break; case DECODE_PKTS: resp = decodePacket(bPktDone); break; case SEND_PKTS: resp = m_outputElemList.sendElements(); if(OCSD_DATA_RESP_IS_CONT(resp)) m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS; bPktDone = true; break; default: bPktDone = true; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,"Unknown Decoder State")); resetDecoder(); // mark decoder as unsynced - dump any current state. resp = OCSD_RESP_FATAL_SYS_ERR; break; } } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV3::onEOT() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; OcsdTraceElement *pElem = 0; try { pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_EO_TRACE); m_outputElemList.commitAllPendElem(); m_curr_state = SEND_PKTS; resp = m_outputElemList.sendElements(); if(OCSD_DATA_RESP_IS_CONT(resp)) m_curr_state = DECODE_PKTS; } catch(ocsdError &err) { LogError(err); resetDecoder(); // mark decoder as unsynced - dump any current state. } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV3::onReset() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; resetDecoder(); return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV3::onFlush() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; if(m_curr_state == SEND_PKTS) { resp = m_outputElemList.sendElements(); if(OCSD_DATA_RESP_IS_CONT(resp)) m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS; } return resp; } ocsd_err_t TrcPktDecodeEtmV3::onProtocolConfig() { ocsd_err_t err = OCSD_OK; if(m_config) { // set some static config elements m_CSID = m_config->getTraceID(); // check config compatible with current decoder support level. // at present no data trace; if(m_config->GetTraceMode() != EtmV3Config::TM_INSTR_ONLY) { err = OCSD_ERR_HW_CFG_UNSUPP; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv3 trace decoder : data trace decode not yet supported")); } // need to set up core profile info in follower ocsd_arch_profile_t arch_profile; arch_profile.arch = m_config->getArchVersion(); arch_profile.profile = m_config->getCoreProfile(); m_code_follower.setArchProfile(arch_profile); m_code_follower.setMemSpaceCSID(m_CSID); m_outputElemList.initCSID(m_CSID); } else err = OCSD_ERR_NOT_INIT; return err; } /* local decode methods */ // initialise on creation void TrcPktDecodeEtmV3::initDecoder() { m_CSID = 0; resetDecoder(); m_code_follower.initInterfaces(getMemoryAccessAttachPt(),getInstrDecodeAttachPt()); m_outputElemList.initSendIf(getTraceElemOutAttachPt()); } // reset for first use / re-use. void TrcPktDecodeEtmV3::resetDecoder() { m_curr_state = NO_SYNC; // mark as not synced m_bNeedAddr = true; m_bSentUnknown = false; m_bWaitISync = false; m_outputElemList.reset(); } OcsdTraceElement *TrcPktDecodeEtmV3::GetNextOpElem(ocsd_datapath_resp_t &resp) { OcsdTraceElement *pElem = m_outputElemList.getNextElem(m_index_curr_pkt); if(pElem == 0) { resp = OCSD_RESP_FATAL_NOT_INIT; throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_MEM,m_index_curr_pkt,m_CSID,"Memory Allocation Error - fatal"); } return pElem; } bool TrcPktDecodeEtmV3::preISyncValid(ocsd_etmv3_pkt_type pkt_type) { bool bValid = false; // its a timestamp if((pkt_type == ETM3_PKT_TIMESTAMP) || // or we are cycleacc and its a packet that can have CC in it (m_config->isCycleAcc() && ((pkt_type == ETM3_PKT_CYCLE_COUNT) || (pkt_type == ETM3_PKT_P_HDR))) ) bValid = true; return bValid; } // simple packet transforms handled here, more complex processing passed on to specific routines. ocsd_datapath_resp_t TrcPktDecodeEtmV3::decodePacket(bool &pktDone) { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; bool bISyncHasCC = false; OcsdTraceElement *pElem = 0; pktDone = false; // there may be pended packets that can now be committed. // only the branch address with exception and cancel element can cancel // if not one of those, commit immediately, otherwise defer to branch address handler. if(m_curr_packet_in->getType() != ETM3_PKT_BRANCH_ADDRESS) m_outputElemList.commitAllPendElem(); try { switch(m_curr_packet_in->getType()) { case ETM3_PKT_NOTSYNC: // mark as not synced - must have lost sync in the packet processor somehow throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Trace Packet Synchronisation Lost"); break; // no action for these packets - ignore and continue case ETM3_PKT_INCOMPLETE_EOT: case ETM3_PKT_A_SYNC: case ETM3_PKT_IGNORE: break; // markers for valid packets case ETM3_PKT_CYCLE_COUNT: pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); pElem->setCycleCount(m_curr_packet_in->getCycleCount()); break; case ETM3_PKT_TRIGGER: pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_EVENT); pElem->setEvent(EVENT_TRIGGER,0); break; case ETM3_PKT_BRANCH_ADDRESS: resp = processBranchAddr(); break; case ETM3_PKT_I_SYNC_CYCLE: bISyncHasCC = true; case ETM3_PKT_I_SYNC: resp = processISync(bISyncHasCC); break; case ETM3_PKT_P_HDR: resp = processPHdr(); break; case ETM3_PKT_CONTEXT_ID: pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID()); pElem->setContext(m_PeContext); break; case ETM3_PKT_VMID: pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); m_PeContext.setVMID(m_curr_packet_in->getVMID()); pElem->setContext(m_PeContext); break; case ETM3_PKT_EXCEPTION_ENTRY: pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION); pElem->setExcepMarker(); // exception entries are always v7M data markers in ETMv3 trace. break; case ETM3_PKT_EXCEPTION_EXIT: pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); pendExceptionReturn(); break; case ETM3_PKT_TIMESTAMP: pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); pElem->setTS(m_curr_packet_in->getTS()); break; // data packets - data trace not supported at present case ETM3_PKT_STORE_FAIL: case ETM3_PKT_OOO_DATA: case ETM3_PKT_OOO_ADDR_PLC: case ETM3_PKT_NORM_DATA: case ETM3_PKT_DATA_SUPPRESSED: case ETM3_PKT_VAL_NOT_TRACED: case ETM3_PKT_BAD_TRACEMODE: resp = OCSD_RESP_FATAL_INVALID_DATA; throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_index_curr_pkt,m_CSID,"Invalid packet type : Data Tracing decode not supported."); break; // packet errors case ETM3_PKT_BAD_SEQUENCE: resp = OCSD_RESP_FATAL_INVALID_DATA; throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Bad Packet sequence."); break; default: case ETM3_PKT_RESERVED: resp = OCSD_RESP_FATAL_INVALID_DATA; throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Reserved or unknown packet ID."); break; } m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; pktDone = !m_outputElemList.elemToSend(); } catch(ocsdError &err) { LogError(err); resetDecoder(); // mark decoder as unsynced - dump any current state. pktDone = true; } catch(...) { LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,m_CSID,"Bad Packet sequence.")); resp = OCSD_RESP_FATAL_SYS_ERR; resetDecoder(); // mark decoder as unsynced - dump any current state. pktDone = true; } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV3::sendUnsyncPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; OcsdTraceElement *pElem = 0; try { pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_NO_SYNC); resp = m_outputElemList.sendElements(); } catch(ocsdError &err) { LogError(err); resetDecoder(); // mark decoder as unsynced - dump any current state. } return resp; } void TrcPktDecodeEtmV3::setNeedAddr(bool bNeedAddr) { m_bNeedAddr = bNeedAddr; m_bSentUnknown = false; } ocsd_datapath_resp_t TrcPktDecodeEtmV3::processISync(const bool withCC, const bool firstSync /* = false */) { // map ISync reason to generic reason codes. static trace_on_reason_t on_map[] = { TRACE_ON_NORMAL, TRACE_ON_NORMAL, TRACE_ON_OVERFLOW, TRACE_ON_EX_DEBUG }; ocsd_datapath_resp_t resp = OCSD_RESP_CONT; bool ctxtUpdate = m_curr_packet_in->isCtxtUpdated(); OcsdTraceElement *pElem = 0; try { pElem = GetNextOpElem(resp); if(firstSync || (m_curr_packet_in->getISyncReason() != iSync_Periodic)) { pElem->setType(OCSD_GEN_TRC_ELEM_TRACE_ON); pElem->setTraceOnReason(on_map[(int)m_curr_packet_in->getISyncReason()]); pElem = GetNextOpElem(resp); } // look for context changes.... if(ctxtUpdate || firstSync) { // if not first time out, read existing context in output element, // otherwise we are setting it new. if(firstSync) m_PeContext.resetCtxt(); if(m_curr_packet_in->isCtxtIDUpdated()) m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID()); if(m_curr_packet_in->isVMIDUpdated()) m_PeContext.setVMID(m_curr_packet_in->getVMID()); if(m_curr_packet_in->isCtxtFlagsUpdated()) { m_PeContext.setEL(m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown); m_PeContext.setSecLevel(m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure); } // prepare the context packet pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); pElem->setContext(m_PeContext); pElem->setISA(m_curr_packet_in->ISA()); // with cycle count... if(m_curr_packet_in->getISyncHasCC()) pElem->setCycleCount(m_curr_packet_in->getCycleCount()); } // set ISync address - if it is a valid I address if(!m_curr_packet_in->getISyncNoAddr()) { if(m_curr_packet_in->getISyncIsLSiPAddr()) { // TBD: handle extra data processing instruction for data trace // need to output E atom relating to the data instruction // rare - on start-up case. // main instruction address saved in data address for this packet type. m_IAddr = m_curr_packet_in->getDataAddr(); } else { m_IAddr = m_curr_packet_in->getAddr(); } setNeedAddr(false); // ready to process atoms. } m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; } catch(ocsdError &err) { LogError(err); resetDecoder(); // mark decoder as unsynced - dump any current state. } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV3::processBranchAddr() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; OcsdTraceElement *pElem = 0; bool bUpdatePEContext = false; // might need to cancel something ... if the last output was an instruction range or excep return if(m_curr_packet_in->isExcepCancel()) m_outputElemList.cancelPendElem(); else m_outputElemList.commitAllPendElem(); // otherwise commit any pending elements. // record the address m_IAddr = m_curr_packet_in->getAddr(); setNeedAddr(false); // no longer need an address. // exception packet - may need additional output if(m_curr_packet_in->isExcepPkt()) { // exeception packet may have exception, context change, or both. // check for context change if(m_curr_packet_in->isCtxtUpdated()) { ocsd_sec_level sec = m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure; if(sec != m_PeContext.getSecLevel()) { m_PeContext.setSecLevel(sec); bUpdatePEContext = true; } ocsd_ex_level pkt_el = m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown; if(pkt_el != m_PeContext.getEL()) { m_PeContext.setEL(pkt_el); bUpdatePEContext = true; } } // now decide if we need to send any packets out. try { if(bUpdatePEContext) { pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); pElem->setContext(m_PeContext); } // check for exception if(m_curr_packet_in->excepNum() != 0) { pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION); pElem->setExceptionNum(m_curr_packet_in->excepNum()); } // finally - do we have anything to send yet? m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; } catch(ocsdError &err) { LogError(err); resetDecoder(); // mark decoder as unsynced - dump any current state. } } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPHdr() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; OcsdTraceElement *pElem = 0; ocsd_isa isa; Etmv3Atoms atoms(m_config->isCycleAcc()); atoms.initAtomPkt(m_curr_packet_in,m_index_curr_pkt); isa = m_curr_packet_in->ISA(); m_code_follower.setMemSpaceAccess((m_PeContext.getSecLevel() == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N); try { do { // if we do not have a valid address then send any cycle count elements // and stop processing if(m_bNeedAddr) { // output unknown address packet or a cycle count packet if(!m_bSentUnknown || m_config->isCycleAcc()) { pElem = GetNextOpElem(resp); if(m_bSentUnknown || !atoms.numAtoms()) pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); else pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN); if(m_config->isCycleAcc()) pElem->setCycleCount(atoms.getRemainCC()); m_bSentUnknown = true; } atoms.clearAll(); // skip remaining atoms } else // have an address, can process atoms { pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); // cycle accurate may have a cycle count to use if(m_config->isCycleAcc()) { // note: it is possible to have a CC only atom packet. if(!atoms.numAtoms()) // override type if CC only pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); // set cycle count pElem->setCycleCount(atoms.getAtomCC()); } // now process the atom if(atoms.numAtoms()) { m_code_follower.setISA(isa); m_code_follower.followSingleAtom(m_IAddr,atoms.getCurrAtomVal()); // valid code range if(m_code_follower.hasRange()) { pElem->setAddrRange(m_IAddr,m_code_follower.getRangeEn()); pElem->setLastInstrInfo(atoms.getCurrAtomVal() == ATOM_E, m_code_follower.getInstrType(), - m_code_follower.getInstrSubType()); + m_code_follower.getInstrSubType(),m_code_follower.getInstrSize()); + pElem->setLastInstrCond(m_code_follower.isCondInstr()); pElem->setISA(isa); if(m_code_follower.hasNextAddr()) m_IAddr = m_code_follower.getNextAddr(); else setNeedAddr(true); } // next address has new ISA? if(m_code_follower.ISAChanged()) isa = m_code_follower.nextISA(); // there is a nacc if(m_code_follower.isNacc()) { if(m_code_follower.hasRange()) { pElem = GetNextOpElem(resp); pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); } else pElem->updateType(OCSD_GEN_TRC_ELEM_ADDR_NACC); pElem->setAddrStart(m_code_follower.getNaccAddr()); setNeedAddr(true); m_code_follower.clearNacc(); // we have generated some code for the nacc. } } atoms.clearAtom(); // next atom } } while(atoms.numAtoms()); // is tha last element an atom? int numElem = m_outputElemList.getNumElem(); if(numElem >= 1) { // if the last thing is an instruction range, pend it - could be cancelled later. if(m_outputElemList.getElemType(numElem-1) == OCSD_GEN_TRC_ELEM_INSTR_RANGE) m_outputElemList.pendLastNElem(1); } // finally - do we have anything to send yet? m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; } catch(ocsdError &err) { LogError(err); resetDecoder(); // mark decoder as unsynced - dump any current state. } return resp; } // if v7M -> pend only ERET, if V7A/R pend ERET and prev instr. void TrcPktDecodeEtmV3::pendExceptionReturn() { int pendElem = 1; if(m_config->getCoreProfile() != profile_CortexM) { int nElem = m_outputElemList.getNumElem(); if(nElem > 1) { if(m_outputElemList.getElemType(nElem - 2) == OCSD_GEN_TRC_ELEM_INSTR_RANGE) pendElem = 2; // need to pend instr+eret for A/R } } m_outputElemList.pendLastNElem(pendElem); } /* End of File trc_pkt_decode_etmv3.cpp */ Index: head/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp =================================================================== --- head/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp (revision 353393) @@ -1,109 +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) { if(vmidszF == 2) m_VMIDSize = 16; else if(vmidszF == 4) m_VMIDSize = 32; } m_VMIDSzCalc = true; } /* End of File trc_cmp_cfg_etmv4.cpp */ Index: head/contrib/opencsd/decoder/source/etmv4/trc_etmv4_stack_elem.cpp =================================================================== --- head/contrib/opencsd/decoder/source/etmv4/trc_etmv4_stack_elem.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/etmv4/trc_etmv4_stack_elem.cpp (revision 353393) @@ -1,110 +1,116 @@ /* * \file trc_etmv4_stack_elem.cpp * \brief OpenCSD : ETMv4 decoder * * \copyright Copyright (c) 2017, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opencsd/etmv4/trc_etmv4_stack_elem.h" /* implementation of P0 element stack in ETM v4 trace*/ -TrcStackElemParam *EtmV4P0Stack::createParamElemNoParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index) +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*/) { - std::vector params; - params.clear(); - return createParamElem(p0_type, isP0, root_pkt, root_index, params); + 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) { TrcStackElemCtxt *pElem = new (std::nothrow) TrcStackElemCtxt(root_pkt, root_index); if (pElem) { pElem->setContext(context); push_front(pElem); } return pElem; } TrcStackElemAddr *EtmV4P0Stack::createAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val) { TrcStackElemAddr *pElem = new (std::nothrow) TrcStackElemAddr(root_pkt, root_index); if (pElem) { pElem->setAddr(addr_val); push_front(pElem); } return pElem; } /* End of file trc_etmv4_stack_elem.cpp */ Index: head/contrib/opencsd/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp =================================================================== --- head/contrib/opencsd/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp (revision 353393) @@ -1,1121 +1,1155 @@ /* * \file trc_pkt_decode_etmv4i.cpp * \brief OpenCSD : ETMv4 decoder * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opencsd/etmv4/trc_pkt_decode_etmv4i.h" #include "common/trc_gen_elem.h" #define DCD_NAME "DCD_ETMV4" static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS = OCSD_OPFLG_PKTDEC_COMMON; TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I() : TrcPktDecodeBase(DCD_NAME) { initDecoder(); } TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I(int instIDNum) : TrcPktDecodeBase(DCD_NAME,instIDNum) { initDecoder(); } TrcPktDecodeEtmV4I::~TrcPktDecodeEtmV4I() { } /*********************** implementation packet decoding interface */ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; bool bPktDone = false; while(!bPktDone) { switch (m_curr_state) { case NO_SYNC: // output the initial not synced packet to the sink m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); resp = outputTraceElement(m_output_elem); m_curr_state = WAIT_SYNC; // fall through to check if the current packet is the async we are waiting for. break; case WAIT_SYNC: if(m_curr_packet_in->getType() == ETM4_PKT_I_ASYNC) m_curr_state = WAIT_TINFO; bPktDone = true; break; case WAIT_TINFO: m_need_ctxt = true; m_need_addr = true; if(m_curr_packet_in->getType() == ETM4_PKT_I_TRACE_INFO) { doTraceInfoPacket(); m_curr_state = DECODE_PKTS; m_return_stack.flush(); } bPktDone = true; break; case DECODE_PKTS: resp = decodePacket(bPktDone); // this may change the state to commit elem; break; case COMMIT_ELEM: resp = commitElements(bPktDone); // this will change the state to DECODE_PKTS once all elem committed. break; } } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onEOT() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; m_flush_EOT = true; resp = flushEOT(); return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onReset() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; resetDecoder(); return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onFlush() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; // continue exception processing (can't go through processPacket as elements no longer on stack) - if(m_excep_proc != EXCEP_POP) + if(m_excep_info.proc != EXCEP_POP) resp = processException(); // continue ongoing output operations on comitted elements. else if(m_curr_state == COMMIT_ELEM) resp = processPacket(); // continue flushing at end of trace else if(m_flush_EOT) resp = flushEOT(); return resp; } ocsd_err_t TrcPktDecodeEtmV4I::onProtocolConfig() { ocsd_err_t err = OCSD_OK; // set some static config elements m_CSID = m_config->getTraceID(); m_max_spec_depth = m_config->MaxSpecDepth(); m_p0_key_max = m_config->P0_Key_Max(); m_cond_key_max_incr = m_config->CondKeyMaxIncr(); // set up static trace instruction decode elements m_instr_info.dsb_dmb_waypoints = 0; + m_instr_info.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_max_spec_depth != 0) { err = OCSD_ERR_HW_CFG_UNSUPP; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : None-zero speculation depth not supported")); } else if(m_config->enabledDataTrace()) { err = OCSD_ERR_HW_CFG_UNSUPP; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Data trace elements not supported")); } else if(m_config->enabledLSP0Trace()) { err = OCSD_ERR_HW_CFG_UNSUPP; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : LSP0 elements not supported.")); } else if(m_config->enabledCondITrace() != EtmV4Config::COND_TR_DIS) { err = OCSD_ERR_HW_CFG_UNSUPP; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace on conditional non-branch elements not supported.")); } else if(m_config->enabledQE()) { err = OCSD_ERR_HW_CFG_UNSUPP; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace using Q elements not supported.")); } return err; } /************* local decode methods */ void TrcPktDecodeEtmV4I::initDecoder() { // set the operational modes supported. m_supported_op_flags = ETMV4_SUPPORTED_DECODE_OP_FLAGS; /* init elements that get set by config */ m_max_spec_depth = 0; m_p0_key_max = 0; m_CSID = 0; m_cond_key_max_incr = 0; m_IASize64 = false; // reset decoder state to unsynced resetDecoder(); } void TrcPktDecodeEtmV4I::resetDecoder() { m_curr_state = NO_SYNC; m_timestamp = 0; m_context_id = 0; m_vmid_id = 0; m_is_secure = true; m_is_64bit = false; m_cc_threshold = 0; m_curr_spec_depth = 0; m_p0_key = 0; m_cond_c_key = 0; m_cond_r_key = 0; m_need_ctxt = true; m_need_addr = true; m_except_pending_addr = false; m_mem_nacc_pending = false; m_prev_overflow = false; m_P0_stack.delete_all(); m_output_elem.init(); - m_excep_proc = EXCEP_POP; + m_excep_info.proc = EXCEP_POP; m_flush_EOT = false; } // this function can output an immediate generic element if this covers the complete packet decode, // or stack P0 and other elements for later processing on commit or cancel. ocsd_datapath_resp_t TrcPktDecodeEtmV4I::decodePacket(bool &Complete) { bool bAllocErr = false; ocsd_datapath_resp_t resp = OCSD_RESP_CONT; Complete = true; bool is_addr = false; bool is_except = false; switch(m_curr_packet_in->getType()) { case ETM4_PKT_I_ASYNC: // nothing to do with this packet. + 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_OVERFLOW: { if (m_P0_stack.createParamElemNoParam(P0_OVERFLOW, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) bAllocErr = true; } break; case ETM4_PKT_I_ATOM_F1: case ETM4_PKT_I_ATOM_F2: case ETM4_PKT_I_ATOM_F3: case ETM4_PKT_I_ATOM_F4: case ETM4_PKT_I_ATOM_F5: case ETM4_PKT_I_ATOM_F6: { if (m_P0_stack.createAtomElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getAtom()) == 0) bAllocErr = true; else m_curr_spec_depth += m_curr_packet_in->getAtom().num; } break; case ETM4_PKT_I_CTXT: { if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext()) == 0) bAllocErr = true; } break; case ETM4_PKT_I_ADDR_MATCH: { etmv4_addr_val_t addr; addr.val = m_curr_packet_in->getAddrVal(); addr.isa = m_curr_packet_in->getAddrIS(); if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) bAllocErr = true; is_addr = true; } break; case ETM4_PKT_I_ADDR_CTXT_L_64IS0: case ETM4_PKT_I_ADDR_CTXT_L_64IS1: case ETM4_PKT_I_ADDR_CTXT_L_32IS0: case ETM4_PKT_I_ADDR_CTXT_L_32IS1: { if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext()) == 0) bAllocErr = true; } case ETM4_PKT_I_ADDR_L_32IS0: case ETM4_PKT_I_ADDR_L_32IS1: case ETM4_PKT_I_ADDR_L_64IS0: case ETM4_PKT_I_ADDR_L_64IS1: case ETM4_PKT_I_ADDR_S_IS0: case ETM4_PKT_I_ADDR_S_IS1: { etmv4_addr_val_t addr; addr.val = m_curr_packet_in->getAddrVal(); addr.isa = m_curr_packet_in->getAddrIS(); if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) bAllocErr = true; is_addr = true; } break; // Exceptions case ETM4_PKT_I_EXCEPT: { if (m_P0_stack.createExceptElem(m_curr_packet_in->getType(), m_index_curr_pkt, (m_curr_packet_in->exception_info.addr_interp == 0x2), m_curr_packet_in->exception_info.exceptionType) == 0) bAllocErr = true; else { m_except_pending_addr = true; // wait for following packets before marking for commit. is_except = true; } } break; case ETM4_PKT_I_EXCEPT_RTN: { // P0 element if V7M profile. bool bV7MProfile = (m_config->archVersion() == ARCH_V7) && (m_config->coreProfile() == profile_CortexM); if (m_P0_stack.createParamElemNoParam(P0_EXCEP_RET, bV7MProfile, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) bAllocErr = true; + 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_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) + 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(P0_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) + 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 ETM4_PKT_I_BAD_SEQUENCE: resp = handleBadPacket("Bad byte sequence in packet."); break; case ETM4_PKT_I_BAD_TRACEMODE: resp = handleBadPacket("Invalid packet type for trace mode."); break; case ETM4_PKT_I_RESERVED: resp = handleBadPacket("Reserved packet header"); break; /*** presently unsupported packets ***/ /* conditional instruction tracing */ case ETM4_PKT_I_COND_FLUSH: case ETM4_PKT_I_COND_I_F1: case ETM4_PKT_I_COND_I_F2: case ETM4_PKT_I_COND_I_F3: case ETM4_PKT_I_COND_RES_F1: case ETM4_PKT_I_COND_RES_F2: case ETM4_PKT_I_COND_RES_F3: case ETM4_PKT_I_COND_RES_F4: // speculation case ETM4_PKT_I_CANCEL_F1: case ETM4_PKT_I_CANCEL_F2: case ETM4_PKT_I_CANCEL_F3: case ETM4_PKT_I_COMMIT: case ETM4_PKT_I_MISPREDICT: case ETM4_PKT_I_DISCARD: // data synchronisation markers case ETM4_PKT_I_NUM_DS_MKR: case ETM4_PKT_I_UNNUM_DS_MKR: /* Q packets */ case ETM4_PKT_I_Q: resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Unsupported packet type.")); break; default: // any other packet - bad packet error resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Unknown packet type.")); break; } // we need to wait for following address after exception // - work out if we have seen enough here... if(m_except_pending_addr && !is_except) { m_except_pending_addr = false; //next packet has to be an address // exception packet sequence complete if(is_addr) { m_curr_spec_depth++; // exceptions are P0 elements so up the spec depth to commit if needed. } else { resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Expected Address packet to follow exception packet.")); } } if(bAllocErr) { resp = OCSD_RESP_FATAL_SYS_ERR; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM,"Memory allocation error.")); } else if(m_curr_spec_depth > m_max_spec_depth) { // auto commit anything above max spec depth // (this will auto commit anything if spec depth not supported!) m_P0_commit = m_curr_spec_depth - m_max_spec_depth; m_curr_state = COMMIT_ELEM; Complete = false; // force the processing of the commit elements. } return resp; } void TrcPktDecodeEtmV4I::doTraceInfoPacket() { m_trace_info = m_curr_packet_in->getTraceInfo(); m_cc_threshold = m_curr_packet_in->getCCThreshold(); m_p0_key = m_curr_packet_in->getP0Key(); m_curr_spec_depth = m_curr_packet_in->getCurrSpecDepth(); } /* * Walks through the element stack, processing from oldest element to the newest, according to the number of P0 elements that need committing. */ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::commitElements(bool &Complete) { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; bool bPause = false; // pause commit operation bool bPopElem = true; // do we remove the element from the stack (multi atom elements may need to stay!) int num_commit_req = m_P0_commit; + ocsd_trc_index_t err_idx = 0; Complete = true; // assume we exit due to completion of commit operation TrcStackElem *pElem = 0; // stacked element pointer while(m_P0_commit && !bPause) { if(m_P0_stack.size() > 0) { pElem = m_P0_stack.back(); // get oldest element - - switch(pElem->getP0Type()) + err_idx = pElem->getRootIndex(); // save index in case of error. + + switch (pElem->getP0Type()) { // indicates a trace restart - beginning of trace or discontinuiuty case P0_TRC_ON: m_output_elem.setType(OCSD_GEN_TRC_ELEM_TRACE_ON); m_output_elem.trace_on_reason = m_prev_overflow ? TRACE_ON_OVERFLOW : TRACE_ON_NORMAL; m_prev_overflow = false; resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); m_return_stack.flush(); break; case P0_ADDR: { TrcStackElemAddr *pAddrElem = dynamic_cast(pElem); m_return_stack.clear_pop_pending(); // address removes the need to pop the indirect address target from the stack if(pAddrElem) { SetInstrInfoInAddrISA(pAddrElem->getAddr().val, pAddrElem->getAddr().isa); m_need_addr = false; } } break; case P0_CTXT: { TrcStackElemCtxt *pCtxtElem = dynamic_cast(pElem); if(pCtxtElem) { etmv4_context_t ctxt = pCtxtElem->getContext(); // check this is an updated context if(ctxt.updated) { updateContext(pCtxtElem); m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); } } } break; case P0_EVENT: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if(pParamElem) resp = this->outputEvent(pParamElem); } break; case P0_TS: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if(pParamElem) resp = outputTS(pParamElem,false); } break; case P0_CC: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if(pParamElem) resp = outputCC(pParamElem); } break; case P0_TS_CC: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if(pParamElem) resp = outputTS(pParamElem,true); } break; case P0_OVERFLOW: m_prev_overflow = true; break; case P0_ATOM: { TrcStackElemAtom *pAtomElem = dynamic_cast(pElem); if(pAtomElem) { bool bContProcess = true; while(!pAtomElem->isEmpty() && m_P0_commit && bContProcess) { ocsd_atm_val atom = pAtomElem->commitOldest(); // check if prev atom left us an indirect address target on the return stack if ((resp = returnStackPop()) != OCSD_RESP_CONT) break; // if address and context do instruction trace follower. // otherwise skip atom and reduce committed elements if(!m_need_ctxt && !m_need_addr) { resp = processAtom(atom,bContProcess); } m_P0_commit--; // mark committed } if(!pAtomElem->isEmpty()) bPopElem = false; // don't remove if still atoms to process. } } break; case P0_EXCEP: // check if prev atom left us an indirect address target on the return stack if ((resp = returnStackPop()) != OCSD_RESP_CONT) break; - m_excep_proc = EXCEP_POP; // set state in case we need to stop part way through + m_excep_info.proc = EXCEP_POP; // set state in case we need to stop part way through resp = processException(); // output trace + exception elements. m_P0_commit--; break; case P0_EXCEP_RET: m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); if(pElem->isP0()) // are we on a core that counts ERET as P0? m_P0_commit--; break; + + 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_P0_commit--; + break; } if(bPopElem) m_P0_stack.delete_back(); // remove element from stack; // if response not continue, then break out of the loop. if(!OCSD_DATA_RESP_IS_CONT(resp)) { bPause = true; } } else { // too few elements for commit operation - decode error. - ocsd_trc_index_t err_idx = 0; - if(pElem) - err_idx = pElem->getRootIndex(); - resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_COMMIT_PKT_OVERRUN,err_idx,m_CSID,"Not enough elements to commit")); bPause = true; } } // done all elements - need more packets. if(m_P0_commit == 0) m_curr_state = DECODE_PKTS; // reduce the spec depth by number of comitted elements m_curr_spec_depth -= (num_commit_req-m_P0_commit); return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::returnStackPop() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; ocsd_isa nextISA; if (m_return_stack.pop_pending()) { ocsd_vaddr_t popAddr = m_return_stack.pop(nextISA); if (m_return_stack.overflow()) { resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_RET_STACK_OVERFLOW, "Trace Return Stack Overflow.")); } else { m_instr_info.instr_addr = popAddr; m_instr_info.isa = nextISA; m_need_addr = false; } } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::flushEOT() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; if(m_flush_EOT) { TrcStackElem *pElem = 0; while(OCSD_DATA_RESP_IS_CONT(resp) && (m_P0_stack.size() > 0)) { // scan for outstanding events, TS and CC, before any outstanding // P0 commit elements. pElem = m_P0_stack.back(); switch(pElem->getP0Type()) { // clear stack and stop case P0_UNKNOWN: case P0_ATOM: case P0_TRC_ON: case P0_EXCEP: case P0_EXCEP_RET: case P0_OVERFLOW: m_P0_stack.delete_all(); break; //skip case P0_ADDR: case P0_CTXT: break; // output case P0_EVENT: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if(pParamElem) resp = this->outputEvent(pParamElem); } break; case P0_TS: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if(pParamElem) resp = outputTS(pParamElem,false); } break; case P0_CC: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if(pParamElem) resp = outputCC(pParamElem); } break; case P0_TS_CC: { TrcStackElemParam *pParamElem = dynamic_cast(pElem); if(pParamElem) resp = outputTS(pParamElem,true); } break; } m_P0_stack.delete_back(); } if(OCSD_DATA_RESP_IS_CONT(resp) && (m_P0_stack.size() == 0)) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE); resp = outputTraceElement(m_output_elem); m_flush_EOT = false; } } return resp; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputCC(TrcStackElemParam *pParamElem) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); - m_output_elem.cycle_count = pParamElem->getParam(0); + m_output_elem.setCycleCount(pParamElem->getParam(0)); return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputTS(TrcStackElemParam *pParamElem, bool withCC) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); m_output_elem.timestamp = (uint64_t)(pParamElem->getParam(0)) | (((uint64_t)pParamElem->getParam(1)) << 32); if(withCC) m_output_elem.setCycleCount(pParamElem->getParam(2)); return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputEvent(TrcStackElemParam *pParamElem) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT); m_output_elem.trace_event.ev_type = EVENT_NUMBERED; m_output_elem.trace_event.ev_number = pParamElem->getParam(0); return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); } +ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputTraceRange(const bool executed, ocsd_trc_index_t index) +{ + m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + m_output_elem.setLastInstrInfo(executed, m_instr_info.type, m_instr_info.sub_type, m_instr_info.instr_size); + m_output_elem.setISA(m_instr_info.isa); + m_output_elem.setLastInstrCond(m_instr_info.is_conditional); + if (executed) + m_instr_info.isa = m_instr_info.next_isa; + return outputTraceElementIdx(index, m_output_elem); +} + ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom, bool &bCont) { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; TrcStackElem *pElem = m_P0_stack.back(); // get the atom element bool bWPFound = false; ocsd_err_t err; bCont = true; err = traceInstrToWP(bWPFound); if(err != OCSD_OK) { if(err == OCSD_ERR_UNSUPPORTED_ISA) { m_need_addr = true; m_need_ctxt = true; LogError(ocsdError(OCSD_ERR_SEV_WARN,err,pElem->getRootIndex(),m_CSID,"Warning: unsupported instruction set processing atom packet.")); // wait for next context return resp; } else { bCont = false; resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet.")); return resp; } } if(bWPFound) { // save recorded next instuction address ocsd_vaddr_t nextAddr = m_instr_info.instr_addr; // action according to waypoint type and atom value switch(m_instr_info.type) { case OCSD_INSTR_BR: if (atom == ATOM_E) { m_instr_info.instr_addr = m_instr_info.branch_addr; if (m_instr_info.is_link) m_return_stack.push(nextAddr, m_instr_info.isa); } break; case OCSD_INSTR_BR_INDIRECT: if (atom == ATOM_E) { m_need_addr = true; // indirect branch taken - need new address. if (m_instr_info.is_link) m_return_stack.push(nextAddr,m_instr_info.isa); m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen } break; } - m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); - m_output_elem.setLastInstrInfo((atom == ATOM_E),m_instr_info.type, m_instr_info.sub_type); - m_output_elem.setISA(m_instr_info.isa); - resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); + resp = outputTraceRange((atom == ATOM_E), pElem->getRootIndex()); } else { // no waypoint - likely inaccessible memory range. m_need_addr = true; // need an address update if(m_output_elem.st_addr != m_output_elem.en_addr) { // some trace before we were out of memory access range - m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); - m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); - m_output_elem.setISA(m_instr_info.isa); - resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); + resp = outputTraceRange(true, pElem->getRootIndex()); } if(m_mem_nacc_pending && OCSD_DATA_RESP_IS_CONT(resp)) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); m_output_elem.st_addr = m_nacc_addr; resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); m_mem_nacc_pending = false; } } if(!OCSD_DATA_RESP_IS_CONT(resp)) bCont = false; return resp; } // Exception processor ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processException() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; - bool excep_implied_P0 = false; //!< exception implies P0 + TrcStackElemExcept *pExceptElem; - if(m_excep_proc == EXCEP_POP) + m_excep_info.addr_b_tgt = false; + + if(m_excep_info.proc == EXCEP_POP) { - TrcStackElemExcept *pExceptElem = dynamic_cast(m_P0_stack.back()); // get the exception element + pExceptElem = dynamic_cast(m_P0_stack.back()); // get the exception element TrcStackElemAddr *pAddressElem = 0; TrcStackElemCtxt *pCtxtElem = 0; TrcStackElem *pElem = 0; m_P0_stack.pop_back(); // remove the exception element pElem = m_P0_stack.back(); // look at next element. if(pElem->getP0Type() == P0_CTXT) { pCtxtElem = dynamic_cast(pElem); m_P0_stack.pop_back(); // remove the context element pElem = m_P0_stack.back(); // next one should be an address element } if(pElem->getP0Type() != P0_ADDR) { // no following address element - indicate processing error. resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,pExceptElem->getRootIndex(),m_CSID,"Address missing in exception packet.")); } else { // extract address pAddressElem = static_cast(pElem); - m_excep_addr = pAddressElem->getAddr(); + // fill in exception info for use later + m_excep_info.addr = pAddressElem->getAddr(); + m_excep_info.number = pExceptElem->getExcepNum(); + m_excep_info.index = pExceptElem->getRootIndex(); + m_excep_info.addr_b_tgt = pExceptElem->getPrevSame(); - // if we have context, get that. - if(pCtxtElem) - updateContext(pCtxtElem); + // see if there is an address + optional context element implied + // prior to the exception. + if (m_excep_info.addr_b_tgt) + { + // this was a branch target address - update current setting + bool b64bit = m_instr_info.isa == ocsd_isa_aarch64; + if (pCtxtElem) { + b64bit = pCtxtElem->getContext().SF; + } + m_instr_info.instr_addr = m_excep_info.addr.val; + m_instr_info.isa = (m_excep_info.addr.isa == 0) ? + (b64bit ? ocsd_isa_aarch64 : ocsd_isa_arm) : ocsd_isa_thumb2; + m_need_addr = false; + } - // record the exception number - m_output_elem.exception_number = pExceptElem->getExcepNum(); - - // see if there is an implied P0 element on the exception. - excep_implied_P0 = pExceptElem->getPrevSame(); - - // save the trace index. - m_excep_index = pExceptElem->getRootIndex(); - // figure out next move - if(m_excep_addr.val == m_instr_info.instr_addr) - m_excep_proc = EXCEP_EXCEP; + if (pCtxtElem) { + m_excep_info.proc = EXCEP_CTXT; + updateContext(pCtxtElem); + } + else if(m_excep_info.addr.val == m_instr_info.instr_addr) + m_excep_info.proc = EXCEP_EXCEP; else - m_excep_proc = EXCEP_RANGE; + m_excep_info.proc = EXCEP_RANGE; } m_P0_stack.delete_popped(); } + // output a context element + if (m_excep_info.proc == EXCEP_CTXT) + { + m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + resp = outputTraceElementIdx(m_excep_info.index, m_output_elem); + m_excep_info.proc = EXCEP_EXCEP; + if (!OCSD_DATA_RESP_IS_CONT(resp)) + return resp; + } + // output a range element - if(m_excep_proc == EXCEP_RANGE) + if(m_excep_info.proc == EXCEP_RANGE) { bool bWPFound = false; ocsd_err_t err; // last instr_info address is the start address m_output_elem.st_addr = m_instr_info.instr_addr; - // look for either a WP or match to return address. - err = traceInstrToWP(bWPFound,!excep_implied_P0,m_excep_addr.val); + // look for match to return address. + err = traceInstrToWP(bWPFound,true,m_excep_info.addr.val); if(err != OCSD_OK) { if(err == OCSD_ERR_UNSUPPORTED_ISA) { m_need_addr = true; m_need_ctxt = true; - LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_excep_index,m_CSID,"Warning: unsupported instruction set processing exception packet.")); + LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_excep_info.index,m_CSID,"Warning: unsupported instruction set processing exception packet.")); } else { resp = OCSD_RESP_FATAL_INVALID_DATA; - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_excep_index,m_CSID,"Error processing exception packet.")); - m_excep_proc = EXCEP_POP; // nothing more to do, reset to start of exception handling + LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_excep_info.index,m_CSID,"Error processing exception packet.")); + m_excep_info.proc = EXCEP_POP; // nothing more to do, reset to start of exception handling } } if(bWPFound) { - // action according to waypoint type and atom value - if(excep_implied_P0) - { - switch(m_instr_info.type) - { - case OCSD_INSTR_BR: - m_instr_info.instr_addr = m_instr_info.branch_addr; - break; - - case OCSD_INSTR_BR_INDIRECT: - m_instr_info.instr_addr = m_excep_addr.val; - break; - } - } - m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); - m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); - m_output_elem.setISA(m_instr_info.isa); - resp = outputTraceElementIdx(m_excep_index, m_output_elem); - m_excep_proc = EXCEP_EXCEP; + // waypoint address found - output range + resp = outputTraceRange(true, m_excep_info.index); + m_excep_info.proc = EXCEP_EXCEP; } else { // no waypoint - likely inaccessible memory range. m_need_addr = true; // need an address update if(m_output_elem.st_addr != m_output_elem.en_addr) { // some trace before we were out of memory access range - m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); - m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); - m_output_elem.setISA(m_instr_info.isa); - resp = outputTraceElementIdx(m_excep_index,m_output_elem); + resp = outputTraceRange(true, m_excep_info.index); } - m_excep_proc = m_mem_nacc_pending ? EXCEP_NACC : EXCEP_EXCEP; + m_excep_info.proc = m_mem_nacc_pending ? EXCEP_NACC : EXCEP_EXCEP; } } - if((m_excep_proc == EXCEP_NACC) && OCSD_DATA_RESP_IS_CONT(resp)) + if((m_excep_info.proc == EXCEP_NACC) && OCSD_DATA_RESP_IS_CONT(resp)) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); m_output_elem.st_addr = m_nacc_addr; - resp = outputTraceElementIdx(m_excep_index,m_output_elem); - m_excep_proc = EXCEP_EXCEP; + resp = outputTraceElementIdx(m_excep_info.index,m_output_elem); + m_excep_info.proc = EXCEP_EXCEP; m_mem_nacc_pending = false; } - if((m_excep_proc == EXCEP_EXCEP) && OCSD_DATA_RESP_IS_CONT(resp)) + if((m_excep_info.proc == EXCEP_EXCEP) && OCSD_DATA_RESP_IS_CONT(resp)) { // output element. m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION); // add end address as preferred return address to end addr in element - m_output_elem.en_addr = m_excep_addr.val; + m_output_elem.en_addr = m_excep_info.addr.val; m_output_elem.excep_ret_addr = 1; - resp = outputTraceElementIdx(m_excep_index,m_output_elem); - m_excep_proc = EXCEP_POP; + m_output_elem.excep_ret_addr_br_tgt = m_excep_info.addr_b_tgt; + m_output_elem.exception_number = m_excep_info.number; + resp = outputTraceElementIdx(m_excep_info.index,m_output_elem); + m_excep_info.proc = EXCEP_POP; } return resp; } void TrcPktDecodeEtmV4I::SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa) { m_instr_info.instr_addr = addr_val; if(m_is_64bit) m_instr_info.isa = ocsd_isa_aarch64; else m_instr_info.isa = (isa == 0) ? ocsd_isa_arm : ocsd_isa_thumb2; } // trace an instruction range to a waypoint - and set next address to restart from. ocsd_err_t TrcPktDecodeEtmV4I::traceInstrToWP(bool &bWPFound, const bool traceToAddrNext /*= false*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/) { uint32_t opcode; uint32_t bytesReq; ocsd_err_t err = OCSD_OK; // TBD?: update mem space to allow for EL as well. ocsd_mem_space_acc_t mem_space = m_is_secure ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N; m_output_elem.st_addr = m_output_elem.en_addr = m_instr_info.instr_addr; + m_output_elem.num_instr_range = 0; bWPFound = false; while(!bWPFound && !m_mem_nacc_pending) { // start off by reading next opcode; bytesReq = 4; err = accessMemory(m_instr_info.instr_addr,mem_space,&bytesReq,(uint8_t *)&opcode); if(err != OCSD_OK) break; if(bytesReq == 4) // got data back { m_instr_info.opcode = opcode; err = instrDecode(&m_instr_info); if(err != OCSD_OK) break; // increment address - may be adjusted by direct branch value later m_instr_info.instr_addr += m_instr_info.instr_size; // update the range decoded address in the output packet. m_output_elem.en_addr = m_instr_info.instr_addr; + m_output_elem.num_instr_range++; // either walking to match the next instruction address or a real watchpoint if(traceToAddrNext) bWPFound = (m_output_elem.en_addr == nextAddrMatch); else bWPFound = (m_instr_info.type != OCSD_INSTR_OTHER); } else { // not enough memory accessible. m_mem_nacc_pending = true; - m_nacc_addr = m_instr_info.instr_addr; + m_nacc_addr = m_instr_info.instr_addr; } } return err; } void TrcPktDecodeEtmV4I::updateContext(TrcStackElemCtxt *pCtxtElem) { etmv4_context_t ctxt = pCtxtElem->getContext(); // map to output element and local saved state. m_is_64bit = (ctxt.SF != 0); m_output_elem.context.bits64 = ctxt.SF; m_is_secure = (ctxt.NS == 0); m_output_elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure; m_output_elem.context.exception_level = (ocsd_ex_level)ctxt.EL; m_output_elem.context.el_valid = 1; if(ctxt.updated_c) { m_output_elem.context.ctxt_id_valid = 1; m_context_id = m_output_elem.context.context_id = ctxt.ctxtID; } if(ctxt.updated_v) { m_output_elem.context.vmid_valid = 1; m_vmid_id = m_output_elem.context.vmid = ctxt.VMID; } m_need_ctxt = false; } ocsd_datapath_resp_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason) { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; if(getComponentOpMode() && OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) { // error out - stop decoding resp = OCSD_RESP_FATAL_INVALID_DATA; LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,reason)); } else { // switch to unsync - clear decode state m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); resp = outputTraceElement(m_output_elem); resetDecoder(); m_curr_state = WAIT_SYNC; } return resp; } /* End of File trc_pkt_decode_etmv4i.cpp */ Index: head/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp =================================================================== --- head/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp (revision 353393) @@ -1,560 +1,583 @@ /* * \file trc_pkt_elem_etmv4i.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "opencsd/etmv4/trc_pkt_elem_etmv4i.h" EtmV4ITrcPacket::EtmV4ITrcPacket() { } EtmV4ITrcPacket::~EtmV4ITrcPacket() { } void EtmV4ITrcPacket::initStartState() { // clear packet state to start of trace (first sync or post discontinuity) // clear all valid bits pkt_valid.val = 0; // virtual address v_addr.pkt_bits = 0; v_addr.valid_bits = 0; v_addr_ISA = 0; // timestamp ts.bits_changed = 0; ts.timestamp = 0; // per packet init initNextPacket(); } void EtmV4ITrcPacket::initNextPacket() { // clear valid bits for elements that are only valid over a single packet. pkt_valid.bits.cc_valid = 0; pkt_valid.bits.commit_elem_valid = 0; atom.num = 0; context.updated = 0; context.updated_v = 0; context.updated_c = 0; err_type = ETM4_PKT_I_NO_ERR_TYPE; } // printing void EtmV4ITrcPacket::toString(std::string &str) const { const char *name; const char *desc; std::string valStr, ctxtStr = ""; name = packetTypeName(type, &desc); str = name + (std::string)" : " + desc; // extended descriptions switch (type) { case ETM4_PKT_I_BAD_SEQUENCE: case ETM4_PKT_I_INCOMPLETE_EOT: + 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: trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 32) ? v_addr.pkt_bits : 0); str += "; Addr=" + valStr + "; " + ctxtStr; break; case ETM4_PKT_I_ADDR_CTXT_L_64IS0: case ETM4_PKT_I_ADDR_CTXT_L_64IS1: contextStr(ctxtStr); case ETM4_PKT_I_ADDR_L_64IS0: case ETM4_PKT_I_ADDR_L_64IS1: trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 64) ? v_addr.pkt_bits : 0); str += "; Addr=" + valStr + "; " + ctxtStr; break; case ETM4_PKT_I_CTXT: contextStr(ctxtStr); str += "; " + ctxtStr; break; case ETM4_PKT_I_ADDR_S_IS0: case ETM4_PKT_I_ADDR_S_IS1: trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, v_addr.pkt_bits); str += "; Addr=" + valStr; break; case ETM4_PKT_I_ADDR_MATCH: addrMatchIdx(valStr); str += ", " + valStr; trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true); str += "; Addr=" + valStr + "; " + ctxtStr; break; case ETM4_PKT_I_ATOM_F1: case ETM4_PKT_I_ATOM_F2: case ETM4_PKT_I_ATOM_F3: case ETM4_PKT_I_ATOM_F4: case ETM4_PKT_I_ATOM_F5: case ETM4_PKT_I_ATOM_F6: atomSeq(valStr); str += "; " + valStr; break; case ETM4_PKT_I_EXCEPT: exceptionInfo(valStr); str += "; " + valStr; break; case ETM4_PKT_I_TIMESTAMP: { std::ostringstream oss; oss << "; Updated val = " << std::hex << "0x" << ts.timestamp; if (pkt_valid.bits.cc_valid) oss << "; CC=" << std::hex << "0x" << cycle_count; str += oss.str(); } break; case ETM4_PKT_I_TRACE_INFO: { std::ostringstream oss; oss << "; INFO=" << std::hex << "0x" << trace_info.val; if (trace_info.bits.cc_enabled) oss << "; CC_THRESHOLD=" << std::hex << "0x" << cc_threshold; str += oss.str(); } break; case ETM4_PKT_I_CCNT_F1: case ETM4_PKT_I_CCNT_F2: case ETM4_PKT_I_CCNT_F3: { std::ostringstream oss; oss << "; Count=" << std::hex << "0x" << cycle_count; str += oss.str(); } break; } } void EtmV4ITrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const { toString(str); // TBD add in formatted response. } const char *EtmV4ITrcPacket::packetTypeName(const ocsd_etmv4_i_pkt_type type, const char **ppDesc) const { - const char *pName = "I_RESERVED"; - const char *pDesc = "Reserved Packet Header"; + const char *pName = "I_UNKNOWN"; + const char *pDesc = "Unknown Packet Header"; switch(type) { - case ETM4_PKT_I_RESERVED: break; // default; - case ETM4_PKT_I_NOTSYNC: pName = "I_NOT_SYNC"; pDesc = "I Stream not synchronised"; break; + case ETM4_PKT_I_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_INCOMPLETE_EOT: - pName = "I_INCOMPLETE_EOT"; - pDesc = "Incomplete packet at end of trace."; + case ETM4_PKT_I_RESERVED: + pName = "I_RESERVED"; + pDesc = "Reserved Packet Header"; break; - case ETM4_PKT_I_NO_ERR_TYPE: - pName = "I_NO_ERR_TYPE"; - pDesc = "No Error Type."; + 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 = "Extention packet header."; + pDesc = "Extension packet header."; break; - case ETM4_PKT_I_ADDR_CTXT_L_32IS0: - pName = "I_ADDR_CTXT_L_32IS0"; - pDesc = "Address & Context, Long, 32 bit, IS0."; + case ETM4_PKT_I_TRACE_INFO: + pName = "I_TRACE_INFO"; + pDesc = "Trace Info."; break; - case ETM4_PKT_I_ADDR_CTXT_L_32IS1: - pName = "I_ADDR_CTXT_L_32IS1"; - pDesc = "Address & Context, Long, 32 bit, IS0."; + case ETM4_PKT_I_TIMESTAMP: + pName = "I_TIMESTAMP"; + pDesc = "Timestamp."; break; - case ETM4_PKT_I_ADDR_CTXT_L_64IS0: - pName = "I_ADDR_CTXT_L_64IS0"; - pDesc = "Address & Context, Long, 64 bit, IS0."; + case ETM4_PKT_I_TRACE_ON: + pName = "I_TRACE_ON"; + pDesc = "Trace On."; break; - case ETM4_PKT_I_ADDR_CTXT_L_64IS1: - pName = "I_ADDR_CTXT_L_64IS1"; - pDesc = "Address & Context, Long, 64 bit, IS1."; + case ETM4_PKT_I_FUNC_RET: + pName = "I_FUNC_RET"; + pDesc = "V8M - function return."; break; - case ETM4_PKT_I_CTXT: - pName = "I_CTXT"; - pDesc = "Context Packet."; + case ETM4_PKT_I_EXCEPT: + pName = "I_EXCEPT"; + pDesc = "Exception."; break; - case ETM4_PKT_I_ADDR_MATCH: - pName = "I_ADDR_MATCH"; - pDesc = "Exact Address Match."; + case ETM4_PKT_I_EXCEPT_RTN: + pName = "I_EXCEPT_RTN"; + pDesc = "Exception Return."; break; - case ETM4_PKT_I_ADDR_L_32IS0: - pName = "I_ADDR_L_32IS0"; - pDesc = "Address, Long, 32 bit, IS0."; + case ETM4_PKT_I_CCNT_F1: + pName = "I_CCNT_F1"; + pDesc = "Cycle Count format 1."; break; - case ETM4_PKT_I_ADDR_L_32IS1: - pName = "I_ADDR_L_32IS1"; - pDesc = "Address, Long, 32 bit, IS1."; + case ETM4_PKT_I_CCNT_F2: + pName = "I_CCNT_F2"; + pDesc = "Cycle Count format 2."; break; - case ETM4_PKT_I_ADDR_L_64IS0: - pName = "I_ADDR_L_64IS0"; - pDesc = "Address, Long, 64 bit, IS0."; + case ETM4_PKT_I_CCNT_F3: + pName = "I_CCNT_F3"; + pDesc = "Cycle Count format 3."; break; - case ETM4_PKT_I_ADDR_L_64IS1: - pName = "I_ADDR_L_64IS1"; - pDesc = "Address, Long, 64 bit, IS1."; + case ETM4_PKT_I_NUM_DS_MKR: + pName = "I_NUM_DS_MKR"; + pDesc = "Data Synchronisation Marker - Numbered."; break; - case ETM4_PKT_I_ADDR_S_IS0: - pName = "I_ADDR_S_IS0"; - pDesc = "Address, Short, IS0."; + case ETM4_PKT_I_UNNUM_DS_MKR: + pName = "I_UNNUM_DS_MKR"; + pDesc = "Data Synchronisation Marker - Unnumbered."; break; - case ETM4_PKT_I_ADDR_S_IS1: - pName = "I_ADDR_S_IS1"; - pDesc = "Address, Short, IS1."; + case ETM4_PKT_I_COMMIT: + pName = "I_COMMIT"; + pDesc = "Commit"; break; - case ETM4_PKT_I_Q: - pName = "I_Q"; - pDesc = "Q Packet."; + case ETM4_PKT_I_CANCEL_F1: + pName = "I_CANCEL_F1"; + pDesc = "Cancel Format 1."; break; - case ETM4_PKT_I_ATOM_F1: - pName = "I_ATOM_F1"; - pDesc = "Atom format 1."; + case ETM4_PKT_I_MISPREDICT: + pName = "I_MISPREDICT"; + pDesc = "Mispredict."; break; - case ETM4_PKT_I_ATOM_F2: - pName = "I_ATOM_F2"; - pDesc = "Atom format 2."; + case ETM4_PKT_I_CANCEL_F2: + pName = "I_CANCEL_F2"; + pDesc = "Cancel Format 2."; break; - case ETM4_PKT_I_ATOM_F3: - pName = "I_ATOM_F3"; - pDesc = "Atom format 3."; + case ETM4_PKT_I_CANCEL_F3: + pName = "I_CANCEL_F3"; + pDesc = "Cancel Format 3."; break; - case ETM4_PKT_I_ATOM_F4: - pName = "I_ATOM_F4"; - pDesc = "Atom format 4."; + case ETM4_PKT_I_COND_I_F2: + pName = "I_COND_I_F2"; + pDesc = "Conditional Instruction, format 2."; break; - case ETM4_PKT_I_ATOM_F5: - pName = "I_ATOM_F5"; - pDesc = "Atom format 5."; + case ETM4_PKT_I_COND_FLUSH: + pName = "I_COND_FLUSH"; + pDesc = "Conditional Flush."; break; - case ETM4_PKT_I_ATOM_F6: - pName = "I_ATOM_F6"; - pDesc = "Atom format 6."; + case ETM4_PKT_I_COND_RES_F4: + pName = "I_COND_RES_F4"; + pDesc = "Conditional Result, format 4."; break; - case ETM4_PKT_I_COND_FLUSH: - pName = "I_COND_FLUSH"; - pDesc = "Conditional Flush."; + 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_F2: - pName = "I_COND_I_F2"; - pDesc = "Conditional Instruction, format 2."; - break; - case ETM4_PKT_I_COND_I_F3: pName = "I_COND_I_F3"; pDesc = "Conditional Instruction, format 3."; break; - case ETM4_PKT_I_COND_RES_F1: - pName = "I_COND_RES_F1"; - pDesc = "Conditional Result, format 1."; + case ETM4_PKT_I_IGNORE: + pName = "I_IGNORE"; + pDesc = "Ignore."; break; - case ETM4_PKT_I_COND_RES_F2: - pName = "I_COND_RES_F2"; - pDesc = "Conditional Result, format 2."; + case ETM4_PKT_I_EVENT: + pName = "I_EVENT"; + pDesc = "Trace Event."; break; - case ETM4_PKT_I_COND_RES_F3: - pName = "I_COND_RES_F3"; - pDesc = "Conditional Result, format 3."; + case ETM4_PKT_I_CTXT: + pName = "I_CTXT"; + pDesc = "Context Packet."; break; - case ETM4_PKT_I_COND_RES_F4: - pName = "I_COND_RES_F4"; - pDesc = "Conditional Result, format 4."; + 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_CCNT_F1: - pName = "I_CCNT_F1"; - pDesc = "Cycle Count format 1."; + 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_CCNT_F2: - pName = "I_CCNT_F2"; - pDesc = "Cycle Count format 2."; + 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_CCNT_F3: - pName = "I_CCNT_F3"; - pDesc = "Cycle Count format 3."; + case ETM4_PKT_I_ADDR_CTXT_L_64IS1: + pName = "I_ADDR_CTXT_L_64IS1"; + pDesc = "Address & Context, Long, 64 bit, IS1."; break; - case ETM4_PKT_I_NUM_DS_MKR: - pName = "I_NUM_DS_MKR"; - pDesc = "Data Synchronisation Marker - Numbered."; + case ETM4_PKT_I_ADDR_MATCH: + pName = "I_ADDR_MATCH"; + pDesc = "Exact Address Match."; break; - case ETM4_PKT_I_UNNUM_DS_MKR: - pName = "I_UNNUM_DS_MKR"; - pDesc = "Data Synchronisation Marker - Unnumbered."; + case ETM4_PKT_I_ADDR_S_IS0: + pName = "I_ADDR_S_IS0"; + pDesc = "Address, Short, IS0."; break; - case ETM4_PKT_I_EVENT: - pName = "I_EVENT"; - pDesc = "Trace Event."; + case ETM4_PKT_I_ADDR_S_IS1: + pName = "I_ADDR_S_IS1"; + pDesc = "Address, Short, IS1."; break; - case ETM4_PKT_I_EXCEPT: - pName = "I_EXCEPT"; - pDesc = "Exception."; + case ETM4_PKT_I_ADDR_L_32IS0: + pName = "I_ADDR_L_32IS0"; + pDesc = "Address, Long, 32 bit, IS0."; break; - case ETM4_PKT_I_EXCEPT_RTN: - pName = "I_EXCEPT_RTN"; - pDesc = "Exception Return."; + case ETM4_PKT_I_ADDR_L_32IS1: + pName = "I_ADDR_L_32IS1"; + pDesc = "Address, Long, 32 bit, IS1."; break; - case ETM4_PKT_I_TIMESTAMP: - pName = "I_TIMESTAMP"; - pDesc = "Timestamp."; + case ETM4_PKT_I_ADDR_L_64IS0: + pName = "I_ADDR_L_64IS0"; + pDesc = "Address, Long, 64 bit, IS0."; break; - case ETM4_PKT_I_CANCEL_F1: - pName = "I_CANCEL_F1"; - pDesc = "Cancel Format 1."; + case ETM4_PKT_I_ADDR_L_64IS1: + pName = "I_ADDR_L_64IS1"; + pDesc = "Address, Long, 64 bit, IS1."; break; - case ETM4_PKT_I_CANCEL_F2: - pName = "I_CANCEL_F2"; - pDesc = "Cancel Format 2."; + + case ETM4_PKT_I_Q: + pName = "I_Q"; + pDesc = "Q Packet."; break; - case ETM4_PKT_I_CANCEL_F3: - pName = "I_CANCEL_F3"; - pDesc = "Cancel Format 3."; + case ETM4_PKT_I_ATOM_F6: + pName = "I_ATOM_F6"; + pDesc = "Atom format 6."; break; - case ETM4_PKT_I_COMMIT: - pName = "I_COMMIT"; - pDesc = "Commit"; + case ETM4_PKT_I_ATOM_F5: + pName = "I_ATOM_F5"; + pDesc = "Atom format 5."; break; - case ETM4_PKT_I_MISPREDICT: - pName = "I_MISPREDICT"; - pDesc = "Mispredict."; + case ETM4_PKT_I_ATOM_F2: + pName = "I_ATOM_F2"; + pDesc = "Atom format 2."; break; - case ETM4_PKT_I_TRACE_INFO: - pName = "I_TRACE_INFO"; - pDesc = "Trace Info."; + case ETM4_PKT_I_ATOM_F4: + pName = "I_ATOM_F4"; + pDesc = "Atom format 4."; break; - case ETM4_PKT_I_TRACE_ON: - pName = "I_TRACE_ON"; - pDesc = "Trace On."; + 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; + + 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 */ Index: head/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.cpp =================================================================== --- head/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.cpp (revision 353393) @@ -1,1582 +1,1694 @@ /* * \file trc_pkt_proc_etmv4i_impl.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "trc_pkt_proc_etmv4i_impl.h" +/* Trace raw input buffer class */ +TraceRawBuffer::TraceRawBuffer() +{ + m_bufSize = 0; + m_bufProcessed = 0; + m_pBuffer = 0; + pkt = 0; +} + +// init the buffer +void TraceRawBuffer::init(const uint32_t size, const uint8_t *rawtrace, std::vector *out_packet) +{ + m_bufSize = size; + m_bufProcessed = 0; + m_pBuffer = rawtrace; + pkt = out_packet; +} + +void TraceRawBuffer::copyByteToPkt() +{ + if (!empty()) { + pkt->push_back(m_pBuffer[m_bufProcessed]); + m_bufProcessed++; + } +} +uint8_t TraceRawBuffer::peekNextByte() +{ + uint8_t val = 0; + if (!empty()) + val = m_pBuffer[m_bufProcessed]; + return val; +} + +/* trace etmv4 packet processing class */ EtmV4IPktProcImpl::EtmV4IPktProcImpl() : m_isInit(false), m_interface(0), m_first_trace_info(false) { - BuildIPacketTable(); + } EtmV4IPktProcImpl::~EtmV4IPktProcImpl() { } void EtmV4IPktProcImpl::Initialise(TrcPktProcEtmV4I *p_interface) { if(p_interface) { m_interface = p_interface; m_isInit = true; } InitProcessorState(); } ocsd_err_t EtmV4IPktProcImpl::Configure(const EtmV4Config *p_config) { ocsd_err_t err = OCSD_OK; if(p_config != 0) { m_config = *p_config; + BuildIPacketTable(); // packet table based on config } else { err = OCSD_ERR_INVALID_PARAM_VAL; if(m_isInit) m_interface->LogError(ocsdError(OCSD_ERR_SEV_ERROR,err)); } return err; } ocsd_datapath_resp_t EtmV4IPktProcImpl::processData( const ocsd_trc_index_t index, const uint32_t dataBlockSize, const uint8_t *pDataBlock, uint32_t *numBytesProcessed) { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; - m_blockBytesProcessed = 0; + m_trcIn.init(dataBlockSize, pDataBlock, &m_currPacketData); m_blockIndex = index; - uint8_t currByte; - while( ( (m_blockBytesProcessed < dataBlockSize) || - ((m_blockBytesProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) ) && - OCSD_DATA_RESP_IS_CONT(resp)) + bool done = false; + uint8_t nextByte; + + do { - currByte = pDataBlock[m_blockBytesProcessed]; try { - switch(m_process_state) + /* while (((m_blockBytesProcessed < dataBlockSize) || + ((m_blockBytesProcessed == dataBlockSize) && (m_process_state == SEND_PKT))) && + OCSD_DATA_RESP_IS_CONT(resp))*/ + while ( (!m_trcIn.empty() || (m_process_state == SEND_PKT)) && + OCSD_DATA_RESP_IS_CONT(resp) + ) { - case PROC_HDR: - m_packet_index = m_blockIndex + m_blockBytesProcessed; - if(m_is_sync) + switch (m_process_state) { - m_pIPktFn = m_i_table[currByte].pptkFn; - m_curr_packet.type = m_i_table[currByte].pkt_type; - } - else - { - // unsynced - process data until we see a sync point - m_pIPktFn = &EtmV4IPktProcImpl::iNotSync; - m_curr_packet.type = ETM4_PKT_I_NOTSYNC; - } - m_process_state = PROC_DATA; + case PROC_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 = &EtmV4IPktProcImpl::iNotSync; + m_curr_packet.type = ETM4_PKT_I_NOTSYNC; + } + m_process_state = PROC_DATA; - case PROC_DATA: - m_currPacketData.push_back(pDataBlock[m_blockBytesProcessed]); - m_blockBytesProcessed++; - (this->*m_pIPktFn)(); - break; + case 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 + // m_currPacketData.push_back(pDataBlock[m_blockBytesProcessed]); + // m_blockBytesProcessed++; + (this->*m_pIPktFn)(nextByte); + } + break; - case SEND_PKT: - resp = outputPacket(); - InitPacketState(); - m_process_state = PROC_HDR; - 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; + 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; } - m_process_state = PROC_DATA; // after dumping unsynced data, still in data mode. - break; } + done = true; } catch(ocsdError &err) { + done = true; m_interface->LogError(err); if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) || (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)) { // send invalid packets up the pipe to let the next stage decide what to do. m_process_state = SEND_PKT; + 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."); m_interface->LogError(fatal); } - } + } while (!done); - *numBytesProcessed = m_blockBytesProcessed; + *numBytesProcessed = m_trcIn.processed(); return resp; } ocsd_datapath_resp_t EtmV4IPktProcImpl::onEOT() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; // if we have a partial packet then send to attached sinks if(m_currPacketData.size() != 0) { m_curr_packet.updateErrType(ETM4_PKT_I_INCOMPLETE_EOT); resp = outputPacket(); InitPacketState(); } return resp; } ocsd_datapath_resp_t EtmV4IPktProcImpl::onReset() { // prepare for new decoding session InitProcessorState(); return OCSD_RESP_CONT; } ocsd_datapath_resp_t EtmV4IPktProcImpl::onFlush() { // packet processor never holds on to flushable data (may have partial packet, // but any full packets are immediately sent) return OCSD_RESP_CONT; } void EtmV4IPktProcImpl::InitPacketState() { m_currPacketData.clear(); m_curr_packet.initNextPacket(); // clear for next packet. m_update_on_unsync_packet_index = 0; } void EtmV4IPktProcImpl::InitProcessorState() { InitPacketState(); m_pIPktFn = &EtmV4IPktProcImpl::iNotSync; m_packet_index = 0; m_is_sync = false; m_first_trace_info = false; m_sent_notsync_packet = false; m_process_state = PROC_HDR; m_curr_packet.initStartState(); } ocsd_datapath_resp_t EtmV4IPktProcImpl::outputPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&m_curr_packet.type,m_currPacketData); return resp; } ocsd_datapath_resp_t EtmV4IPktProcImpl::outputUnsyncedRawPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; m_interface->outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]); if(!m_sent_notsync_packet) { resp = m_interface->outputDecodedPacket(m_packet_index,&m_curr_packet); m_sent_notsync_packet = true; } if(m_currPacketData.size() <= m_dump_unsynced_bytes) m_currPacketData.clear(); else m_currPacketData.erase(m_currPacketData.begin(),m_currPacketData.begin()+m_dump_unsynced_bytes); return resp; } -void EtmV4IPktProcImpl::iNotSync() +void EtmV4IPktProcImpl::iNotSync(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); // peek at the byte being processed... - // is it an extension byte? - if(lastByte == 0x00) // TBD : add check for forced sync in here? + if (lastByte == 0x00) // TBD : add check for forced sync in here? { - if(m_currPacketData.size() > 1) + if (m_currPacketData.size() > 1) { m_dump_unsynced_bytes = m_currPacketData.size() - 1; m_process_state = SEND_UNSYNCED; // outputting some data then update packet index after so output indexes accurate - m_update_on_unsync_packet_index = m_blockIndex + m_blockBytesProcessed - 1; + m_update_on_unsync_packet_index = m_blockIndex + m_trcIn.processed() - 1; } else - m_packet_index = m_blockIndex + m_blockBytesProcessed - 1; // set it up now otherwise. + m_packet_index = m_blockIndex + m_trcIn.processed() - 1; // set it up now otherwise. - m_pIPktFn = m_i_table[lastByte].pptkFn; + m_pIPktFn = m_i_table[lastByte].pptkFn; } - else if(m_currPacketData.size() >= 8) + else if (m_currPacketData.size() >= 8) { m_dump_unsynced_bytes = m_currPacketData.size(); m_process_state = SEND_UNSYNCED; // outputting some data then update packet index after so output indexes accurate - m_update_on_unsync_packet_index = m_blockIndex + m_blockBytesProcessed; + m_update_on_unsync_packet_index = m_blockIndex + m_trcIn.processed(); } } -void EtmV4IPktProcImpl::iPktNoPayload() +void EtmV4IPktProcImpl::iPktNoPayload(const uint8_t lastByte) { // some expansion may be required... - uint8_t lastByte = m_currPacketData.back(); switch(m_curr_packet.type) { case ETM4_PKT_I_ADDR_MATCH: m_curr_packet.setAddressExactMatch(lastByte & 0x3); break; case ETM4_PKT_I_EVENT: m_curr_packet.setEvent(lastByte & 0xF); break; case ETM4_PKT_I_NUM_DS_MKR: case ETM4_PKT_I_UNNUM_DS_MKR: m_curr_packet.setDataSyncMarker(lastByte & 0x7); break; // these just need the packet type - no processing required. case ETM4_PKT_I_COND_FLUSH: case ETM4_PKT_I_EXCEPT_RTN: case ETM4_PKT_I_TRACE_ON: + case ETM4_PKT_I_FUNC_RET: + case ETM4_PKT_I_IGNORE: default: break; } m_process_state = SEND_PKT; // now just send it.... } -void EtmV4IPktProcImpl::iPktReserved() +void EtmV4IPktProcImpl::iPktReserved(const uint8_t lastByte) { - m_curr_packet.updateErrType(ETM4_PKT_I_RESERVED); // swap type for err type + 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 EtmV4IPktProcImpl::iPktExtension() +void EtmV4IPktProcImpl::iPktInvalidCfg(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); + 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 EtmV4IPktProcImpl::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 = &EtmV4IPktProcImpl::iNotSync; m_curr_packet.type = ETM4_PKT_I_NOTSYNC; return; } switch(lastByte) { case 0x03: // discard packet. m_curr_packet.type = ETM4_PKT_I_DISCARD; m_process_state = SEND_PKT; break; case 0x05: m_curr_packet.type = ETM4_PKT_I_OVERFLOW; m_process_state = SEND_PKT; break; case 0x00: m_curr_packet.type = ETM4_PKT_I_ASYNC; m_pIPktFn = &EtmV4IPktProcImpl::iPktASync; // handle subsequent bytes as async break; default: m_curr_packet.err_type = m_curr_packet.type; m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE; m_process_state = SEND_PKT; break; } } } -void EtmV4IPktProcImpl::iPktASync() +void EtmV4IPktProcImpl::iPktASync(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); if(lastByte != 0x00) { // not sync and not next by 0x00 - not sync sequence if < 12 if(!m_is_sync && m_currPacketData.size() != 12) { m_pIPktFn = &EtmV4IPktProcImpl::iNotSync; m_curr_packet.type = ETM4_PKT_I_NOTSYNC; return; } // 12 bytes and not valid sync sequence - not possible even if not synced m_process_state = SEND_PKT; if((m_currPacketData.size() != 12) || (lastByte != 0x80)) { m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE; m_curr_packet.err_type = ETM4_PKT_I_ASYNC; } else m_is_sync = true; // found a sync packet, mark decoder as synchronised. } else if(m_currPacketData.size() == 12) { if(!m_is_sync) { // if we are not yet synced then ignore extra leading 0x00. m_dump_unsynced_bytes = 1; m_process_state = SEND_UNSYNCED; } else { // bad periodic ASYNC sequence. m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE; m_curr_packet.err_type = ETM4_PKT_I_ASYNC; m_process_state = SEND_PKT; } } } -void EtmV4IPktProcImpl::iPktTraceInfo() +void EtmV4IPktProcImpl::iPktTraceInfo(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); if(m_currPacketData.size() == 1) // header { //clear flags m_tinfo_sections.sectFlags = 0; // mark all sections as incomplete. m_tinfo_sections.ctrlBytes = 1; // assume only a single control section byte for now } else if(m_currPacketData.size() == 2) // first payload control byte { // figure out which sections are absent and set to true - opposite of bitfeild in byte; m_tinfo_sections.sectFlags = (~lastByte) & TINFO_ALL_SECT; // see if there is an extended control section, otherwise this byte is it. if((lastByte & 0x80) == 0x0) m_tinfo_sections.sectFlags |= TINFO_CTRL; } else { if(!(m_tinfo_sections.sectFlags & TINFO_CTRL)) { m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_CTRL; m_tinfo_sections.ctrlBytes++; } else if(!(m_tinfo_sections.sectFlags & TINFO_INFO_SECT)) m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_INFO_SECT; else if(!(m_tinfo_sections.sectFlags & TINFO_KEY_SECT)) m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_KEY_SECT; else if(!(m_tinfo_sections.sectFlags & TINFO_SPEC_SECT)) m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_SPEC_SECT; else if(!(m_tinfo_sections.sectFlags & TINFO_CYCT_SECT)) m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_CYCT_SECT; } // all sections accounted for? if(m_tinfo_sections.sectFlags == TINFO_ALL) { // index of first section is number of payload control bytes + 1 for header byte unsigned idx = m_tinfo_sections.ctrlBytes + 1; uint32_t fieldVal = 0; uint8_t presSect = m_currPacketData[1] & TINFO_ALL_SECT; // first payload control byte m_curr_packet.clearTraceInfo(); if((presSect & TINFO_INFO_SECT) && (idx < m_currPacketData.size())) { idx += extractContField(m_currPacketData,idx,fieldVal); m_curr_packet.setTraceInfo(fieldVal); } if((presSect & TINFO_KEY_SECT) && (idx < m_currPacketData.size())) { idx += extractContField(m_currPacketData,idx,fieldVal); m_curr_packet.setTraceInfoKey(fieldVal); } if((presSect & TINFO_SPEC_SECT) && (idx < m_currPacketData.size())) { idx += extractContField(m_currPacketData,idx,fieldVal); m_curr_packet.setTraceInfoSpec(fieldVal); } if((presSect & TINFO_CYCT_SECT) && (idx < m_currPacketData.size())) { idx += extractContField(m_currPacketData,idx,fieldVal); m_curr_packet.setTraceInfoCyct(fieldVal); } m_process_state = SEND_PKT; m_first_trace_info = true; } } -void EtmV4IPktProcImpl::iPktTimestamp() +void EtmV4IPktProcImpl::iPktTimestamp(const uint8_t lastByte) { - // save the latest byte - uint8_t lastByte = m_currPacketData.back(); - // process the header byte if(m_currPacketData.size() == 1) { m_ccount_done = (bool)((lastByte & 0x1) == 0); // 0 = not present m_ts_done = false; m_ts_bytes = 0; } else { if(!m_ts_done) { m_ts_bytes++; m_ts_done = (m_ts_bytes == 9) || ((lastByte & 0x80) == 0); } else if(!m_ccount_done) { m_ccount_done = (bool)((lastByte & 0x80) == 0); // TBD: check for oorange ccount - bad packet. } } if(m_ts_done && m_ccount_done) { int idx = 1; uint64_t tsVal; int ts_bytes = extractContField64(m_currPacketData, idx, tsVal); int ts_bits = ts_bytes < 7 ? ts_bytes * 7 : 64; if(!m_curr_packet.pkt_valid.bits.ts_valid && m_first_trace_info) ts_bits = 64; // after trace info, missing bits are all 0. m_curr_packet.setTS(tsVal,(uint8_t)ts_bits); if((m_currPacketData[0] & 0x1) == 0x1) { uint32_t countVal, countMask; idx += ts_bytes; extractContField(m_currPacketData, idx, countVal, 3); // only 3 possible count bytes. countMask = (((uint32_t)1UL << m_config.ccSize()) - 1); // mask of the CC size countVal &= countMask; m_curr_packet.setCycleCount(countVal); } m_process_state = SEND_PKT; } } -void EtmV4IPktProcImpl::iPktException() +void EtmV4IPktProcImpl::iPktException(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); + 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; break; } if(m_currPacketData.size() == (unsigned)m_excep_size) { - uint16_t excep_type = (m_currPacketData[1] >> 1) & 0x1F; + excep_type = (m_currPacketData[1] >> 1) & 0x1F; uint8_t addr_interp = (m_currPacketData[1] & 0x40) >> 5 | (m_currPacketData[1] & 0x1); uint8_t m_fault_pending = 0; uint8_t m_type = (m_config.coreProfile() == profile_CortexM) ? 1 : 0; // extended exception packet (probably M class); if(m_currPacketData[1] & 0x80) { excep_type |= ((uint16_t)m_currPacketData[2] & 0x1F) << 5; m_fault_pending = (m_currPacketData[2] >> 5) & 0x1; } m_curr_packet.setExceptionInfo(excep_type,addr_interp,m_fault_pending, m_type); m_process_state = SEND_PKT; // allow the standard address packet handlers to process the address packet field for the exception. } } -void EtmV4IPktProcImpl::iPktCycleCntF123() +void EtmV4IPktProcImpl::iPktCycleCntF123(const uint8_t lastByte) { ocsd_etmv4_i_pkt_type format = m_curr_packet.type; - uint8_t lastByte = m_currPacketData.back(); if( m_currPacketData.size() == 1) { m_count_done = m_commit_done = false; m_has_count = true; if(format == ETM4_PKT_I_CCNT_F3) { // no commit section for TRCIDR0.COMMOPT == 1 if(!m_config.commitOpt1()) { m_curr_packet.setCommitElements(((lastByte >> 2) & 0x3) + 1); } // TBD: warning of non-valid CC threshold here? m_curr_packet.setCycleCount(m_curr_packet.getCCThreshold() + (lastByte & 0x3)); m_process_state = SEND_PKT; } else if(format == ETM4_PKT_I_CCNT_F1) { if((lastByte & 0x1) == 0x1) { m_has_count = false; m_count_done = true; } // no commit section for TRCIDR0.COMMOPT == 1 if(m_config.commitOpt1()) m_commit_done = true; } } else if((format == ETM4_PKT_I_CCNT_F2) && ( m_currPacketData.size() == 2)) { int commit_offset = ((lastByte & 0x1) == 0x1) ? ((int)m_config.MaxSpecDepth() - 15) : 1; int commit_elements = ((lastByte >> 4) & 0xF); commit_elements += commit_offset; // TBD: warning if commit elements < 0? m_curr_packet.setCycleCount(m_curr_packet.getCCThreshold() + (lastByte & 0xF)); m_curr_packet.setCommitElements(commit_elements); m_process_state = SEND_PKT; } else { // F1 and size 2 or more if(!m_commit_done) m_commit_done = ((lastByte & 0x80) == 0x00); else if(!m_count_done) m_count_done = ((lastByte & 0x80) == 0x00); } if((format == ETM4_PKT_I_CCNT_F1) && m_commit_done && m_count_done) { int idx = 1; // index into buffer for payload data. uint32_t field_value = 0; // no commit section for TRCIDR0.COMMOPT == 1 if(!m_config.commitOpt1()) { idx += extractContField(m_currPacketData,idx,field_value); m_curr_packet.setCommitElements(field_value); } if (m_has_count) { extractContField(m_currPacketData, idx, field_value, 3); m_curr_packet.setCycleCount(field_value + m_curr_packet.getCCThreshold()); } else m_curr_packet.setCycleCount(0); /* unknown CC marked as 0 after overflow */ m_process_state = SEND_PKT; } } -void EtmV4IPktProcImpl::iPktSpeclRes() -{ - uint8_t lastByte = m_currPacketData.back(); +void EtmV4IPktProcImpl::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); m_process_state = SEND_PKT; break; case ETM4_PKT_I_CANCEL_F3: if(lastByte & 0x1) m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x1, 1); // E m_curr_packet.setCancelElements(((lastByte >> 1) & 0x3) + 2); m_process_state = SEND_PKT; break; } } else { if((lastByte & 0x80) == 0x00) { uint32_t field_val = 0; extractContField(m_currPacketData,1,field_val); if(m_curr_packet.getType() == ETM4_PKT_I_COMMIT) m_curr_packet.setCommitElements(field_val); else m_curr_packet.setCancelElements(field_val); // TBD: sanity check with max spec depth here? m_process_state = SEND_PKT; } } } -void EtmV4IPktProcImpl::iPktCondInstr() +void EtmV4IPktProcImpl::iPktCondInstr(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); bool bF1Done = false; if(m_currPacketData.size() == 1) { if(m_curr_packet.getType() == ETM4_PKT_I_COND_I_F2) { m_curr_packet.setCondIF2(lastByte & 0x3); m_process_state = SEND_PKT; } } else if(m_currPacketData.size() == 2) { if(m_curr_packet.getType() == ETM4_PKT_I_COND_I_F3) // f3 two bytes long { uint8_t num_c_elem = ((lastByte >> 1) & 0x3F) + (lastByte & 0x1); m_curr_packet.setCondIF3(num_c_elem,(bool)((lastByte & 0x1) == 0x1)); // TBD: check for 0 num_c_elem in here. m_process_state = SEND_PKT; } else { bF1Done = ((lastByte & 0x80) == 0x00); } } else { bF1Done = ((lastByte & 0x80) == 0x00); } if(bF1Done) { uint32_t cond_key = 0; extractContField(m_currPacketData, 1, cond_key); m_process_state = SEND_PKT; } } -void EtmV4IPktProcImpl::iPktCondResult() +void EtmV4IPktProcImpl::iPktCondResult(const uint8_t lastByte) { - //static ocsd_etmv4_i_pkt_type format = ETM4_PKT_I_COND_RES_F1; // conditional result formats F1-F4 - uint8_t lastByte = m_currPacketData.back(); if(m_currPacketData.size() == 1) { m_F1P1_done = false; // F1 payload 1 done m_F1P2_done = false; // F1 payload 2 done m_F1has_P2 = false; // F1 has a payload 2 switch(m_curr_packet.getType()) { case ETM4_PKT_I_COND_RES_F1: m_F1has_P2 = true; if((lastByte & 0xFC) == 0x6C)// only one payload set { m_F1P2_done = true; m_F1has_P2 = false; } break; case ETM4_PKT_I_COND_RES_F2: m_curr_packet.setCondRF2((lastByte & 0x4) ? 2 : 1, lastByte & 0x3); m_process_state = SEND_PKT; break; case ETM4_PKT_I_COND_RES_F3: break; case ETM4_PKT_I_COND_RES_F4: m_curr_packet.setCondRF4(lastByte & 0x3); m_process_state = SEND_PKT; break; } } else if((m_curr_packet.getType() == ETM4_PKT_I_COND_RES_F3) && (m_currPacketData.size() == 2)) { // 2nd F3 packet uint16_t f3_tokens = 0; f3_tokens = (uint16_t)m_currPacketData[1]; f3_tokens |= ((uint16_t)m_currPacketData[0] & 0xf) << 8; m_curr_packet.setCondRF3(f3_tokens); m_process_state = SEND_PKT; } else // !first packet - F1 { if(!m_F1P1_done) m_F1P1_done = ((lastByte & 0x80) == 0x00); else if(!m_F1P2_done) m_F1P2_done = ((lastByte & 0x80) == 0x00); if(m_F1P1_done && m_F1P2_done) { int st_idx = 1; uint32_t key[2]; uint8_t result[2]; uint8_t CI[2]; st_idx+= extractCondResult(m_currPacketData,st_idx,key[0],result[0]); CI[0] = m_currPacketData[0] & 0x1; if(m_F1has_P2) // 2nd payload? { extractCondResult(m_currPacketData,st_idx,key[1],result[1]); CI[1] = (m_currPacketData[0] >> 1) & 0x1; } m_curr_packet.setCondRF1(key,result,CI,m_F1has_P2); m_process_state = SEND_PKT; } } } -void EtmV4IPktProcImpl::iPktContext() +void EtmV4IPktProcImpl::iPktContext(const uint8_t lastByte) { bool bSendPacket = false; - uint8_t lastByte = m_currPacketData.back(); + if(m_currPacketData.size() == 1) { if((lastByte & 0x1) == 0) { m_curr_packet.setContextInfo(false); // no update context packet (ctxt same as last time). m_process_state = SEND_PKT; } } else if(m_currPacketData.size() == 2) { if((lastByte & 0xC0) == 0) // no VMID or CID { bSendPacket = true; } else { m_vmidBytes = ((lastByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0; m_ctxtidBytes = ((lastByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0; } } else // 3rd byte onwards { if(m_vmidBytes > 0) m_vmidBytes--; else if(m_ctxtidBytes > 0) m_ctxtidBytes--; if((m_ctxtidBytes == 0) && (m_vmidBytes == 0)) bSendPacket = true; } if(bSendPacket) { extractAndSetContextInfo(m_currPacketData,1); m_process_state = SEND_PKT; } } void EtmV4IPktProcImpl::extractAndSetContextInfo(const std::vector &buffer, const int st_idx) { // on input, buffer index points at the info byte - always present uint8_t infoByte = m_currPacketData[st_idx]; m_curr_packet.setContextInfo(true, (infoByte & 0x3), (infoByte >> 5) & 0x1, (infoByte >> 4) & 0x1); // see if there are VMID and CID bytes, and how many. int nVMID_bytes = ((infoByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0; int nCtxtID_bytes = ((infoByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0; // extract any VMID and CID int payload_idx = st_idx+1; if(nVMID_bytes) { uint32_t VMID = 0; for(int i = 0; i < nVMID_bytes; i++) { VMID |= ((uint32_t)m_currPacketData[i+payload_idx] << i*8); } payload_idx += nVMID_bytes; m_curr_packet.setContextVMID(VMID); } if(nCtxtID_bytes) { uint32_t CID = 0; for(int i = 0; i < nCtxtID_bytes; i++) { CID |= ((uint32_t)m_currPacketData[i+payload_idx] << i*8); } m_curr_packet.setContextCID(CID); } } -void EtmV4IPktProcImpl::iPktAddrCtxt() +void EtmV4IPktProcImpl::iPktAddrCtxt(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); - if( m_currPacketData.size() == 1) { m_addrIS = 0; m_addrBytes = 4; m_bAddr64bit = false; m_vmidBytes = 0; m_ctxtidBytes = 0; m_bCtxtInfoDone = false; switch(m_curr_packet.type) { case ETM4_PKT_I_ADDR_CTXT_L_32IS1: m_addrIS = 1; case ETM4_PKT_I_ADDR_CTXT_L_32IS0: break; case ETM4_PKT_I_ADDR_CTXT_L_64IS1: m_addrIS = 1; case ETM4_PKT_I_ADDR_CTXT_L_64IS0: m_addrBytes = 8; m_bAddr64bit = true; break; } } else { if(m_addrBytes == 0) { if(m_bCtxtInfoDone == false) { m_bCtxtInfoDone = true; m_vmidBytes = ((lastByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0; m_ctxtidBytes = ((lastByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0; } else { if( m_vmidBytes > 0) m_vmidBytes--; else if(m_ctxtidBytes > 0) m_ctxtidBytes--; } } else m_addrBytes--; if((m_addrBytes == 0) && m_bCtxtInfoDone && (m_vmidBytes == 0) && (m_ctxtidBytes == 0)) { int st_idx = 1; if(m_bAddr64bit) { uint64_t val64; st_idx+=extract64BitLongAddr(m_currPacketData,st_idx,m_addrIS,val64); m_curr_packet.set64BitAddress(val64,m_addrIS); } else { uint32_t val32; st_idx+=extract32BitLongAddr(m_currPacketData,st_idx,m_addrIS,val32); m_curr_packet.set32BitAddress(val32,m_addrIS); } extractAndSetContextInfo(m_currPacketData,st_idx); m_process_state = SEND_PKT; } } } -void EtmV4IPktProcImpl::iPktShortAddr() +void EtmV4IPktProcImpl::iPktShortAddr(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); - if(m_currPacketData.size() == 1) + if (m_currPacketData.size() == 1) { m_addr_done = false; - m_addrIS = (lastByte == ETM4_PKT_I_ADDR_S_IS0) ? 0 : 1; + m_addrIS = 0; + if (lastByte == ETM4_PKT_I_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 EtmV4IPktProcImpl::extractShortAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint32_t &value, int &bits) { int IS_shift = (IS == 0) ? 2 : 1; int idx = 0; bits = 7; // at least 7 bits value = 0; value |= ((uint32_t)(buffer[st_idx+idx] & 0x7F)) << IS_shift; if(m_currPacketData[st_idx+idx] & 0x80) { idx++; value |= ((uint32_t)m_currPacketData[st_idx+idx]) << (7 + IS_shift); bits += 8; } idx++; bits += IS_shift; return idx; } -void EtmV4IPktProcImpl::iPktLongAddr() +void EtmV4IPktProcImpl::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: m_addrIS = 1; case ETM4_PKT_I_ADDR_L_32IS0: m_addrBytes = 4; break; case ETM4_PKT_I_ADDR_L_64IS1: m_addrIS = 1; case ETM4_PKT_I_ADDR_L_64IS0: m_addrBytes = 8; m_bAddr64bit = true; break; } } if(m_currPacketData.size() == (unsigned)(1+m_addrBytes)) { int st_idx = 1; if(m_bAddr64bit) { uint64_t val64; st_idx+=extract64BitLongAddr(m_currPacketData,st_idx,m_addrIS,val64); m_curr_packet.set64BitAddress(val64,m_addrIS); } else { uint32_t val32; st_idx+=extract32BitLongAddr(m_currPacketData,st_idx,m_addrIS,val32); m_curr_packet.set32BitAddress(val32,m_addrIS); } m_process_state = SEND_PKT; } } -void EtmV4IPktProcImpl::iPktQ() +void EtmV4IPktProcImpl::iPktQ(const uint8_t lastByte) { - uint8_t lastByte = m_currPacketData.back(); - if(m_currPacketData.size() == 1) { m_Q_type = lastByte & 0xF; m_addrBytes = 0; m_count_done = false; m_has_addr = false; m_addr_short = true; m_addr_match = false; m_addrIS = 1; m_QE = 0; switch(m_Q_type) { // count only - implied address. case 0x0: case 0x1: case 0x2: m_addr_match = true; m_has_addr = true; m_QE = m_Q_type & 0x3; case 0xC: break; // count + short address case 0x5: m_addrIS = 0; case 0x6: m_has_addr = true; m_addrBytes = 2; // short IS0/1 break; // count + long address case 0xA: m_addrIS = 0; case 0xB: m_has_addr = true; m_addr_short = false; m_addrBytes = 4; // long IS0/1 break; // no count, no address case 0xF: m_count_done = true; break; // reserved values 0x3, 0x4, 0x7, 0x8, 0x9, 0xD, 0xE default: m_curr_packet.err_type = m_curr_packet.type; m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE; //SendBadIPacket( PKT_BAD_SEQUENCE, "ERROR: Bad Q packet type", PKT_Q ); break; } } else { if(m_addrBytes > 0) { if(m_addr_short && m_addrBytes == 2) // short { if((lastByte & 0x80) == 0x00) m_addrBytes--; // short version can have just single byte. } m_addrBytes--; } else if(!m_count_done) { m_count_done = ((lastByte & 0x80) == 0x00); } } if(((m_addrBytes == 0) && m_count_done)) { int idx = 1; // move past the header int bits = 0; uint32_t q_addr; uint32_t q_count; if(m_has_addr) { if(m_addr_match) { m_curr_packet.setAddressExactMatch(m_QE); } else if(m_addr_short) { idx+=extractShortAddr(m_currPacketData,idx,m_addrIS,q_addr,bits); m_curr_packet.updateShortAddress(q_addr,m_addrIS,(uint8_t)bits); } else { idx+=extract32BitLongAddr(m_currPacketData,idx,m_addrIS,q_addr); m_curr_packet.set32BitAddress(q_addr,m_addrIS); } } if(m_Q_type != 0xF) { extractContField(m_currPacketData,idx,q_count); m_curr_packet.setQType(true,q_count,m_has_addr,m_addr_match,m_Q_type); } else { m_curr_packet.setQType(false,0,false,false,0xF); } m_process_state = SEND_PKT; } } -void EtmV4IPktProcImpl::iAtom() +void EtmV4IPktProcImpl::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 lastByte = m_currPacketData.back(); uint8_t pattIdx = 0, pattCount = 0; uint32_t pattern; // atom packets are single byte, no payload. switch(m_curr_packet.type) { case ETM4_PKT_I_ATOM_F1: m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x1), 1); // 1xE or N break; case ETM4_PKT_I_ATOM_F2: m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x3), 2); // 2x (E or N) break; case ETM4_PKT_I_ATOM_F3: m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x7), 3); // 3x (E or N) break; case ETM4_PKT_I_ATOM_F4: m_curr_packet.setAtomPacket(ATOM_PATTERN,f4_patterns[(lastByte & 0x3)], 4); // 4 atom pattern break; case ETM4_PKT_I_ATOM_F5: pattIdx = ((lastByte & 0x20) >> 3) | (lastByte & 0x3); switch(pattIdx) { case 5: // 0b101 m_curr_packet.setAtomPacket(ATOM_PATTERN,0x1E, 5); // 5 atom pattern EEEEN break; case 1: // 0b001 m_curr_packet.setAtomPacket(ATOM_PATTERN,0x00, 5); // 5 atom pattern NNNNN break; case 2: //0b010 m_curr_packet.setAtomPacket(ATOM_PATTERN,0x0A, 5); // 5 atom pattern NENEN break; case 3: //0b011 m_curr_packet.setAtomPacket(ATOM_PATTERN,0x15, 5); // 5 atom pattern ENENE break; default: // TBD: warn about invalid pattern in here. break; } break; case ETM4_PKT_I_ATOM_F6: pattCount = (lastByte & 0x1F) + 3; // count of E's // TBD: check 23 or less at this point? pattern = ((uint32_t)0x1 << pattCount) - 1; // set pattern to string of E's if((lastByte & 0x20) == 0x00) // last atom is E? pattern |= ((uint32_t)0x1 << pattCount); m_curr_packet.setAtomPacket(ATOM_PATTERN,pattern, pattCount+1); break; } m_process_state = SEND_PKT; } // header byte processing is table driven. void EtmV4IPktProcImpl::BuildIPacketTable() { // initialise everything as reserved. for(int i = 0; i < 256; i++) { m_i_table[i].pkt_type = ETM4_PKT_I_RESERVED; m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iPktReserved; } // 0x00 - extension m_i_table[0x00].pkt_type = ETM4_PKT_I_EXTENSION; m_i_table[0x00].pptkFn = &EtmV4IPktProcImpl::iPktExtension; // 0x01 - Trace info m_i_table[0x01].pkt_type = ETM4_PKT_I_TRACE_INFO; m_i_table[0x01].pptkFn = &EtmV4IPktProcImpl::iPktTraceInfo; // b0000001x - timestamp m_i_table[0x02].pkt_type = ETM4_PKT_I_TIMESTAMP; m_i_table[0x02].pptkFn = &EtmV4IPktProcImpl::iPktTimestamp; m_i_table[0x03].pkt_type = ETM4_PKT_I_TIMESTAMP; m_i_table[0x03].pptkFn = &EtmV4IPktProcImpl::iPktTimestamp; // b0000 0100 - trace on m_i_table[0x04].pkt_type = ETM4_PKT_I_TRACE_ON; m_i_table[0x04].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + + // b0000 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 = &EtmV4IPktProcImpl::iPktNoPayload; + } + // b0000 0110 - exception m_i_table[0x06].pkt_type = ETM4_PKT_I_EXCEPT; m_i_table[0x06].pptkFn = &EtmV4IPktProcImpl::iPktException; // b0000 0111 - exception return m_i_table[0x07].pkt_type = ETM4_PKT_I_EXCEPT_RTN; - m_i_table[0x07].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + m_i_table[0x07].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; // b0000 110x - cycle count f2 // b0000 111x - cycle count f1 for(int i = 0; i < 4; i++) { m_i_table[0x0C+i].pkt_type = (i >= 2) ? ETM4_PKT_I_CCNT_F1 : ETM4_PKT_I_CCNT_F2; m_i_table[0x0C+i].pptkFn = &EtmV4IPktProcImpl::iPktCycleCntF123; } // b0001 xxxx - cycle count f3 for(int i = 0; i < 16; i++) { m_i_table[0x10+i].pkt_type = ETM4_PKT_I_CCNT_F3; m_i_table[0x10+i].pptkFn = &EtmV4IPktProcImpl::iPktCycleCntF123; } // b0010 0xxx - NDSM for(int i = 0; i < 8; i++) { - m_i_table[0x20+i].pkt_type = ETM4_PKT_I_NUM_DS_MKR; - m_i_table[0x20+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + m_i_table[0x20 + i].pkt_type = ETM4_PKT_I_NUM_DS_MKR; + if (m_config.enabledDataTrace()) + m_i_table[0x20+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + else + m_i_table[0x20+i].pptkFn = &EtmV4IPktProcImpl::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; - m_i_table[0x28+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + if (m_config.enabledDataTrace()) + m_i_table[0x28+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + else + m_i_table[0x28+i].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; } // b0010 1101 - commit m_i_table[0x2D].pkt_type = ETM4_PKT_I_COMMIT; m_i_table[0x2D].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; - // b0010 111x - cancel f1 for(int i = 0; i < 2; i++) { // G++ doesn't understand [0x2E+i] so... int idx = i + 0x2E; m_i_table[idx].pkt_type = ETM4_PKT_I_CANCEL_F1; m_i_table[idx].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; } // b0011 00xx - mis predict for(int i = 0; i < 4; i++) { m_i_table[0x30+i].pkt_type = ETM4_PKT_I_MISPREDICT; m_i_table[0x30+i].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; } // b0011 01xx - cancel f2 for(int i = 0; i < 4; i++) { m_i_table[0x34+i].pkt_type = ETM4_PKT_I_CANCEL_F2; m_i_table[0x34+i].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; } // b0011 1xxx - cancel f3 for(int i = 0; i < 8; i++) { m_i_table[0x38+i].pkt_type = ETM4_PKT_I_CANCEL_F3; m_i_table[0x38+i].pptkFn = &EtmV4IPktProcImpl::iPktSpeclRes; } + bool bCondValid = m_config.hasCondTrace() && m_config.enabledCondITrace(); + // b0100 000x, b0100 0010 - cond I f2 - for(int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { - m_i_table[0x40+i].pkt_type = ETM4_PKT_I_COND_I_F2; - m_i_table[0x40+i].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + m_i_table[0x40 + i].pkt_type = ETM4_PKT_I_COND_I_F2; + if (bCondValid) + m_i_table[0x40 + i].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + else + m_i_table[0x40 + i].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; } // b0100 0011 - cond flush m_i_table[0x43].pkt_type = ETM4_PKT_I_COND_FLUSH; - m_i_table[0x43].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + if (bCondValid) + m_i_table[0x43].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; + else + m_i_table[0x43].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; // b0100 010x, b0100 0110 - cond res f4 - for(int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { - m_i_table[0x44+i].pkt_type = ETM4_PKT_I_COND_RES_F4; - m_i_table[0x44+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + m_i_table[0x44 + i].pkt_type = ETM4_PKT_I_COND_RES_F4; + if (bCondValid) + m_i_table[0x44 + i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + else + m_i_table[0x44 + i].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; } // b0100 100x, b0100 0110 - cond res f2 // b0100 110x, b0100 1110 - cond res f2 - for(int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { - m_i_table[0x48+i].pkt_type = ETM4_PKT_I_COND_RES_F2; - m_i_table[0x48+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + m_i_table[0x48 + i].pkt_type = ETM4_PKT_I_COND_RES_F2; + if (bCondValid) + m_i_table[0x48 + i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + else + m_i_table[0x48 + i].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; } - for(int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { - m_i_table[0x4C+i].pkt_type = ETM4_PKT_I_COND_RES_F2; - m_i_table[0x4C+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + m_i_table[0x4C + i].pkt_type = ETM4_PKT_I_COND_RES_F2; + if (bCondValid) + m_i_table[0x4C + i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + else + m_i_table[0x4C + i].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; } // b0101xxxx - cond res f3 - for(int i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) { - m_i_table[0x50+i].pkt_type = ETM4_PKT_I_COND_RES_F3; - m_i_table[0x50+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + m_i_table[0x50 + i].pkt_type = ETM4_PKT_I_COND_RES_F3; + if (bCondValid) + m_i_table[0x50 + i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + else + m_i_table[0x50 + i].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; } // b011010xx - cond res f1 - for(int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { - m_i_table[0x68+i].pkt_type = ETM4_PKT_I_COND_RES_F1; - m_i_table[0x68+i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + m_i_table[0x68 + i].pkt_type = ETM4_PKT_I_COND_RES_F1; + if (bCondValid) + m_i_table[0x68 + i].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + else + m_i_table[0x68 + i].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; } // b0110 1100 - cond instr f1 m_i_table[0x6C].pkt_type = ETM4_PKT_I_COND_I_F1; - m_i_table[0x6C].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + if (bCondValid) + m_i_table[0x6C].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + else + m_i_table[0x6C].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; // b0110 1101 - cond instr f3 m_i_table[0x6D].pkt_type = ETM4_PKT_I_COND_I_F3; - m_i_table[0x6D].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + if (bCondValid) + m_i_table[0x6D].pptkFn = &EtmV4IPktProcImpl::iPktCondInstr; + else + m_i_table[0x6D].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; // b0110111x - cond res f1 - for(int i = 0; i < 2; i++) + for (int i = 0; i < 2; i++) { // G++ cannot understand [0x6E+i] so change these round - m_i_table[i+0x6E].pkt_type = ETM4_PKT_I_COND_RES_F1; - m_i_table[i+0x6E].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + m_i_table[i + 0x6E].pkt_type = ETM4_PKT_I_COND_RES_F1; + if (bCondValid) + m_i_table[i + 0x6E].pptkFn = &EtmV4IPktProcImpl::iPktCondResult; + else + m_i_table[i + 0x6E].pptkFn = &EtmV4IPktProcImpl::iPktInvalidCfg; } - // b01110001 - b01111111 - cond res f1 + // 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 = &EtmV4IPktProcImpl::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 = &EtmV4IPktProcImpl::iPktNoPayload; } // 0b1000 000x - context for(int i = 0; i < 2; i++) { m_i_table[0x80+i].pkt_type = ETM4_PKT_I_CTXT; m_i_table[0x80+i].pptkFn = &EtmV4IPktProcImpl::iPktContext; } // 0b1000 0010 to b1000 0011 - addr with ctxt // 0b1000 0101 to b1000 0110 - addr with ctxt for(int i = 0; i < 2; i++) { m_i_table[0x82+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_CTXT_L_32IS0 : ETM4_PKT_I_ADDR_CTXT_L_32IS1; m_i_table[0x82+i].pptkFn = &EtmV4IPktProcImpl::iPktAddrCtxt; } for(int i = 0; i < 2; i++) { m_i_table[0x85+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_CTXT_L_64IS0 : ETM4_PKT_I_ADDR_CTXT_L_64IS1; m_i_table[0x85+i].pptkFn = &EtmV4IPktProcImpl::iPktAddrCtxt; } // 0b1001 0000 to b1001 0010 - exact match addr for(int i = 0; i < 3; i++) { m_i_table[0x90+i].pkt_type = ETM4_PKT_I_ADDR_MATCH; m_i_table[0x90+i].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; } // b1001 0101 - b1001 0110 - addr short address for(int i = 0; i < 2; i++) { m_i_table[0x95+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_S_IS0 : ETM4_PKT_I_ADDR_S_IS1; m_i_table[0x95+i].pptkFn = &EtmV4IPktProcImpl::iPktShortAddr; } // b10011010 - b10011011 - addr long address // b10011101 - b10011110 - addr long address for(int i = 0; i < 2; i++) { m_i_table[0x9A+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_L_32IS0 : ETM4_PKT_I_ADDR_L_32IS1; m_i_table[0x9A+i].pptkFn = &EtmV4IPktProcImpl::iPktLongAddr; } for(int i = 0; i < 2; i++) { m_i_table[0x9D+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_L_64IS0 : ETM4_PKT_I_ADDR_L_64IS1; m_i_table[0x9D+i].pptkFn = &EtmV4IPktProcImpl::iPktLongAddr; } - + // b1010xxxx - Q packet - for(int i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) { - m_i_table[0xA0+i].pkt_type = ETM4_PKT_I_Q; - m_i_table[0xA0+i].pptkFn = &EtmV4IPktProcImpl::iPktQ; + 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 = &EtmV4IPktProcImpl::iPktQ; + } } // Atom Packets - all no payload but have specific pattern generation fn for(int i = 0xC0; i <= 0xD4; i++) // atom f6 { m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F6; m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; } for(int i = 0xD5; i <= 0xD7; i++) // atom f5 { m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F5; m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; } for(int i = 0xD8; i <= 0xDB; i++) // atom f2 { m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F2; m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; } for(int i = 0xDC; i <= 0xDF; i++) // atom f4 { m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F4; m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; } for(int i = 0xE0; i <= 0xF4; i++) // atom f6 { m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F6; m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; } // atom f5 m_i_table[0xF5].pkt_type = ETM4_PKT_I_ATOM_F5; m_i_table[0xF5].pptkFn = &EtmV4IPktProcImpl::iAtom; for(int i = 0xF6; i <= 0xF7; i++) // atom f1 { m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F1; m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; } for(int i = 0xF8; i <= 0xFF; i++) // atom f3 { m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F3; m_i_table[i].pptkFn = &EtmV4IPktProcImpl::iAtom; } } unsigned EtmV4IPktProcImpl::extractContField(const std::vector &buffer, const unsigned st_idx, uint32_t &value, const unsigned byte_limit /*= 5*/) { unsigned idx = 0; bool lastByte = false; uint8_t byteVal; value = 0; while(!lastByte && (idx < byte_limit)) // max 5 bytes for 32 bit value; { if(buffer.size() > (st_idx + idx)) { // each byte has seven bits + cont bit byteVal = buffer[(st_idx + idx)]; lastByte = (byteVal & 0x80) != 0x80; value |= ((uint32_t)(byteVal & 0x7F)) << (idx * 7); idx++; } else { throwBadSequenceError("Invalid 32 bit continuation fields in packet"); } } return idx; } unsigned EtmV4IPktProcImpl::extractContField64(const std::vector &buffer, const unsigned st_idx, uint64_t &value, const unsigned byte_limit /*= 9*/) { unsigned idx = 0; bool lastByte = false; uint8_t byteVal; value = 0; while(!lastByte && (idx < byte_limit)) // max 9 bytes for 64 bit value; { if(buffer.size() > (st_idx + idx)) { // each byte has seven bits + cont bit byteVal = buffer[(st_idx + idx)]; lastByte = (byteVal & 0x80) != 0x80; value |= ((uint64_t)(byteVal & 0x7F)) << (idx * 7); idx++; } else { throwBadSequenceError("Invalid 64 bit continuation fields in packet"); } } return idx; } unsigned EtmV4IPktProcImpl::extractCondResult(const std::vector &buffer, const unsigned st_idx, uint32_t& key, uint8_t &result) { unsigned idx = 0; bool lastByte = false; int incr = 0; key = 0; while(!lastByte && (idx < 6)) // cannot be more than 6 bytes for res + 32 bit key { if(buffer.size() > (st_idx + idx)) { if(idx == 0) { result = buffer[st_idx+idx]; key = (buffer[st_idx+idx] >> 4) & 0x7; incr+=3; } else { key |= ((uint32_t)(buffer[st_idx+idx] & 0x7F)) << incr; incr+=7; } lastByte = (bool)((buffer[st_idx+idx] & 0x80) == 0); idx++; } else { throwBadSequenceError("Invalid continuation fields in packet"); } } return idx; } int EtmV4IPktProcImpl::extract64BitLongAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint64_t &value) { value = 0; if(IS == 0) { value |= ((uint64_t)(buffer[st_idx+0] & 0x7F)) << 2; value |= ((uint64_t)(buffer[st_idx+1] & 0x7F)) << 9; } else { value |= ((uint64_t)(buffer[st_idx+0] & 0x7F)) << 1; value |= ((uint64_t)buffer[st_idx+1]) << 8; } value |= ((uint64_t)buffer[st_idx+2]) << 16; value |= ((uint64_t)buffer[st_idx+3]) << 24; value |= ((uint64_t)buffer[st_idx+4]) << 32; value |= ((uint64_t)buffer[st_idx+5]) << 40; value |= ((uint64_t)buffer[st_idx+6]) << 48; value |= ((uint64_t)buffer[st_idx+7]) << 56; return 8; } int EtmV4IPktProcImpl::extract32BitLongAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint32_t &value) { value = 0; if(IS == 0) { value |= ((uint32_t)(buffer[st_idx+0] & 0x7F)) << 2; value |= ((uint32_t)(buffer[st_idx+1] & 0x7F)) << 9; } else { value |= ((uint32_t)(buffer[st_idx+0] & 0x7F)) << 1; value |= ((uint32_t)buffer[st_idx+1]) << 8; } value |= ((uint32_t)buffer[st_idx+2]) << 16; value |= ((uint32_t)buffer[st_idx+3]) << 24; return 4; } void EtmV4IPktProcImpl::throwBadSequenceError(const char *pszExtMsg) { m_curr_packet.updateErrType(ETM4_PKT_I_BAD_SEQUENCE); // swap type for err type throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,m_config.getTraceID(),pszExtMsg); } /* End of File trc_pkt_proc_etmv4i_impl.cpp */ Index: head/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.h =================================================================== --- head/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.h (revision 353392) +++ head/contrib/opencsd/decoder/source/etmv4/trc_pkt_proc_etmv4i_impl.h (revision 353393) @@ -1,204 +1,231 @@ /* * \file trc_pkt_proc_etmv4i_impl.h * \brief OpenCSD : Implementation of ETMv4 packet processing * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARM_TRC_PKT_PROC_ETMV4I_IMPL_H_INCLUDED #define ARM_TRC_PKT_PROC_ETMV4I_IMPL_H_INCLUDED #include "opencsd/etmv4/trc_pkt_proc_etmv4.h" #include "opencsd/etmv4/trc_cmp_cfg_etmv4.h" #include "opencsd/etmv4/trc_pkt_elem_etmv4i.h" +class TraceRawBuffer +{ +public: + TraceRawBuffer(); + ~TraceRawBuffer() {}; + + // init the buffer + void init(const uint32_t size, const uint8_t *rawtrace, std::vector *out_packet); + void copyByteToPkt(); // move a byte to the packet buffer + uint8_t peekNextByte(); // value of next byte in buffer. + + bool empty() { return m_bufProcessed == m_bufSize; }; + // bytes processed. + uint32_t processed() { return m_bufProcessed; }; + // buffer size; + uint32_t size() { return m_bufSize; } + +private: + uint32_t m_bufSize; + uint32_t m_bufProcessed; + const uint8_t *m_pBuffer; + std::vector *pkt; + +}; + class EtmV4IPktProcImpl { public: EtmV4IPktProcImpl(); ~EtmV4IPktProcImpl(); void Initialise(TrcPktProcEtmV4I *p_interface); ocsd_err_t Configure(const EtmV4Config *p_config); ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, const uint32_t dataBlockSize, const uint8_t *pDataBlock, uint32_t *numBytesProcessed); ocsd_datapath_resp_t onEOT(); ocsd_datapath_resp_t onReset(); ocsd_datapath_resp_t onFlush(); const bool isBadPacket() const; protected: typedef enum _process_state { PROC_HDR, PROC_DATA, SEND_PKT, SEND_UNSYNCED, PROC_ERR, } process_state; process_state m_process_state; void InitPacketState(); // clear current packet state. void InitProcessorState(); // clear all previous process state /** packet processor configuration **/ bool m_isInit; TrcPktProcEtmV4I *m_interface; /**< The interface to the other decode components */ // etmv4 hardware configuration EtmV4Config m_config; /** packet data **/ - std::vector m_currPacketData; // raw data + 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 - uint32_t m_blockBytesProcessed; // number of bytes processed in the current data block +// uint32_t m_blockBytesProcessed; // number of bytes processed in the current data block ocsd_trc_index_t m_blockIndex; // index at the start of the current data block being processed // searching for sync bool m_is_sync; //!< seen first sync packet bool m_first_trace_info; //!< seen first trace info packet after sync bool m_sent_notsync_packet; //!< send one not sync packet if we see any unsynced data on the channel unsigned m_dump_unsynced_bytes; //!< number of unsynced bytes to send ocsd_trc_index_t m_update_on_unsync_packet_index; private: // current processing state data - counts and flags to determine if a packet is complete. // TraceInfo Packet // flags to indicate processing progress for these sections is complete. struct _t_info_pkt_prog { uint8_t sectFlags; uint8_t ctrlBytes; } m_tinfo_sections; #define TINFO_INFO_SECT 0x01 #define TINFO_KEY_SECT 0x02 #define TINFO_SPEC_SECT 0x04 #define TINFO_CYCT_SECT 0x08 - #define TINFO_CTRL 0x10 - #define TINFO_ALL_SECT 0x0F - #define TINFO_ALL 0x1F + #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(); // not synced yet - void iPktNoPayload(); // process a single byte packet - void iPktReserved(); // deal with reserved header value - void iPktExtension(); - void iPktASync(); - void iPktTraceInfo(); - void iPktTimestamp(); - void iPktException(); - void iPktCycleCntF123(); - void iPktSpeclRes(); - void iPktCondInstr(); - void iPktCondResult(); - void iPktContext(); - void iPktAddrCtxt(); - void iPktShortAddr(); - void iPktLongAddr(); - void iPktQ(); - void iAtom(); + 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. unsigned extractContField(const std::vector &buffer, const unsigned st_idx, uint32_t &value, const unsigned byte_limit = 5); unsigned extractContField64(const std::vector &buffer, const unsigned st_idx, uint64_t &value, const unsigned byte_limit = 9); unsigned extractCondResult(const std::vector &buffer, const unsigned st_idx, uint32_t& key, uint8_t &result); void extractAndSetContextInfo(const std::vector &buffer, const int st_idx); int extract64BitLongAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint64_t &value); int extract32BitLongAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint32_t &value); int extractShortAddr(const std::vector &buffer, const int st_idx, const uint8_t IS, uint32_t &value, int &bits); // packet processing is table driven. - typedef void (EtmV4IPktProcImpl::*PPKTFN)(void); + typedef void (EtmV4IPktProcImpl::*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 EtmV4IPktProcImpl::isBadPacket() const { return m_curr_packet.isBadPacket(); } #endif // ARM_TRC_PKT_PROC_ETMV4I_IMPL_H_INCLUDED /* End of File trc_pkt_proc_etmv4i_impl.h */ Index: head/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp =================================================================== --- head/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/i_dec/trc_i_decode.cpp (revision 353393) @@ -1,213 +1,250 @@ /* * \file trc_i_decode.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opencsd/ocsd_if_types.h" #include "i_dec/trc_i_decode.h" #include "i_dec/trc_idec_arminst.h" ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info) { ocsd_err_t err = OCSD_OK; clear_instr_subtype(); + SetArchVersion(instr_info); + switch(instr_info->isa) { case ocsd_isa_arm: err = DecodeA32(instr_info); break; case ocsd_isa_thumb2: err = DecodeT32(instr_info); break; case ocsd_isa_aarch64: err = DecodeA64(instr_info); break; case ocsd_isa_tee: case ocsd_isa_jazelle: default: // unsupported ISA err = OCSD_ERR_UNSUPPORTED_ISA; break; } instr_info->sub_type = get_instr_subtype(); return err; } +void TrcIDecode::SetArchVersion(ocsd_instr_info *instr_info) +{ + uint16_t arch = 0x0700; + + switch (instr_info->pe_type.arch) + { + case ARCH_V8: arch = 0x0800; break; + case ARCH_V8r3: arch = 0x0803; break; + case ARCH_V7: + default: + break; + } + set_arch_version(arch); +} + + ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info) { uint32_t branchAddr = 0; arm_barrier_t barrier; instr_info->instr_size = 4; // instruction size A32 instr_info->type = OCSD_INSTR_OTHER; // default type instr_info->next_isa = instr_info->isa; // assume same ISA instr_info->is_link = 0; if(inst_ARM_is_indirect_branch(instr_info->opcode)) { instr_info->type = OCSD_INSTR_BR_INDIRECT; instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode); } else if(inst_ARM_is_direct_branch(instr_info->opcode)) { inst_ARM_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr); instr_info->type = OCSD_INSTR_BR; if (branchAddr & 0x1) { instr_info->next_isa = ocsd_isa_thumb2; branchAddr &= ~0x1; } instr_info->branch_addr = (ocsd_vaddr_t)branchAddr; instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode); } else if((barrier = inst_ARM_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) { switch(barrier) { case ARM_BARRIER_ISB: instr_info->type = OCSD_INSTR_ISB; break; case ARM_BARRIER_DSB: case ARM_BARRIER_DMB: if(instr_info->dsb_dmb_waypoints) instr_info->type = OCSD_INSTR_DSB_DMB; break; } } - + 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) { uint64_t branchAddr = 0; arm_barrier_t barrier; instr_info->instr_size = 4; // default address update instr_info->type = OCSD_INSTR_OTHER; // default type instr_info->next_isa = instr_info->isa; // assume same ISA instr_info->is_link = 0; - if(inst_A64_is_indirect_branch(instr_info->opcode)) + if(inst_A64_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link)) { instr_info->type = OCSD_INSTR_BR_INDIRECT; - instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); +// instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); } - else if(inst_A64_is_direct_branch(instr_info->opcode)) + else if(inst_A64_is_direct_branch_link(instr_info->opcode, &instr_info->is_link)) { 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); +// 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) + { + if (inst_A64_wfiwfe(instr_info->opcode)) + { + instr_info->type = OCSD_INSTR_WFI_WFE; + } + } instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode); return OCSD_OK; } ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info) { uint32_t branchAddr = 0; arm_barrier_t barrier; // need to align the 32 bit opcode as 2 16 bit, with LS 16 as in top 16 bit of // 32 bit word - T2 routines assume 16 bit in top 16 bit of 32 bit opcode. uint32_t op_temp = (instr_info->opcode >> 16) & 0xFFFF; op_temp |= ((instr_info->opcode & 0xFFFF) << 16); instr_info->opcode = op_temp; instr_info->instr_size = is_wide_thumb((uint16_t)(instr_info->opcode >> 16)) ? 4 : 2; instr_info->type = OCSD_INSTR_OTHER; // default type instr_info->next_isa = instr_info->isa; // assume same ISA instr_info->is_link = 0; + instr_info->is_conditional = 0; - if(inst_Thumb_is_indirect_branch(instr_info->opcode)) + + if(inst_Thumb_is_direct_branch_link(instr_info->opcode,&instr_info->is_link, &instr_info->is_conditional)) { - instr_info->type = OCSD_INSTR_BR_INDIRECT; - instr_info->is_link = inst_Thumb_is_branch_and_link(instr_info->opcode); - } - else if(inst_Thumb_is_direct_branch(instr_info->opcode)) - { inst_Thumb_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr); instr_info->type = OCSD_INSTR_BR; instr_info->branch_addr = (ocsd_vaddr_t)(branchAddr & ~0x1); if((branchAddr & 0x1) == 0) instr_info->next_isa = ocsd_isa_arm; - instr_info->is_link = inst_Thumb_is_branch_and_link(instr_info->opcode); } + else if (inst_Thumb_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link)) + { + 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 */ Index: head/contrib/opencsd/decoder/source/i_dec/trc_idec_arminst.cpp =================================================================== --- head/contrib/opencsd/decoder/source/i_dec/trc_idec_arminst.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/i_dec/trc_idec_arminst.cpp (revision 353393) @@ -1,561 +1,682 @@ /* * \file trc_idec_arminst.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ - /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Basic ARM/Thumb/A64 instruction decode, suitable for e.g. basic block identification and trace decode. */ #include "i_dec/trc_idec_arminst.h" - #include /* for NULL */ #include static ocsd_instr_subtype instr_sub_type = OCSD_S_INSTR_NONE; +/* need to spot the architecture version for certain instructions */ +static uint16_t arch_version = 0x70; + ocsd_instr_subtype get_instr_subtype() { return instr_sub_type; } void clear_instr_subtype() { instr_sub_type = OCSD_S_INSTR_NONE; } +void set_arch_version(uint16_t version) +{ + arch_version = version; +} + 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) { 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) + 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} */ + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; } else if ((inst & 0x0e50f000) == 0x0410f000) { /* LDR PC,imm... inc. POP {PC} */ + if ( (inst & 0x01ff0000) == 0x009D0000) + 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 */ + 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) { + uint8_t link, cond; + return inst_Thumb_is_direct_branch_link(inst, &link, &cond); +} + +int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond) +{ 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; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } } else if ((inst & 0xf800d001) == 0xf000c000) { /* BLX (imm) (encoding T2) */ + *is_link = 1; + 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) { + uint8_t link; + return inst_Thumb_is_indirect_branch_link(inst, &link); +} + +int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link) +{ /* See e.g. PFT Table 2-3 and Table 2-5 */ int is_branch = 1; + if ((inst & 0xff000000) == 0x47000000) { - /* BX, BLX (reg) */ + /* BX, BLX (reg) [v8M includes BXNS, BLXNS] */ + if (inst & 0x00800000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + else if ((inst & 0x00780000) == 0x00700000) { + 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} */ + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; } else if ((inst & 0xfd870000) == 0x44870000) { /* MOV PC,reg or ADD PC,reg */ + if ((inst & 0xffff0000) == 0x46f700000) + 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) + 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]!, */ + 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) { + uint8_t link = 0; + return inst_A64_is_direct_branch_link(inst, &link); +} + +int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link) +{ int is_direct_branch = 1; if ((inst & 0x7c000000) == 0x34000000) { /* CB, TB */ } else if ((inst & 0xff000010) == 0x54000000) { /* B */ } else if ((inst & 0x7c000000) == 0x14000000) { /* B, BL imm */ + if (inst & 0x80000000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } } else { is_direct_branch = 0; } return is_direct_branch; } +int inst_A64_wfiwfe(uint32_t inst) +{ + /* WFI, WFE may be traced as branches in etm 4.3++ */ + if ((inst & 0xffffffdf) == 0xd503205f) + return 1; + return 0; +} int inst_A64_is_indirect_branch(uint32_t inst) { + uint8_t link = 0; + return inst_A64_is_indirect_branch_link(inst, &link); +} + +int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link) +{ int is_indirect_branch = 1; + if ((inst & 0xffdffc1f) == 0xd61f0000) { /* BR, BLR */ + if (inst & 0x00200000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } } else if ((inst & 0xfffffc1f) == 0xd65f0000) { instr_sub_type = OCSD_S_INSTR_V8_RET; /* RET */ } else if ((inst & 0xffffffff) == 0xd69f03e0) { /* ERET */ instr_sub_type = OCSD_S_INSTR_V8_ERET; + } else if (arch_version >= 0x0803) { + /* new pointer auth instr for v8.3 arch */ + if ((inst & 0xffdff800) == 0xd61f0800) { + /* BRAA, BRAB, BLRAA, BLRBB */ + if (inst & 0x00200000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else if ((inst & 0xffdff81F) == 0xd71f081F) { + /* BRAAZ, BRABZ, BLRAAZ, BLRBBZ */ + if (inst & 0x00200000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else if ((inst & 0xfffffbff) == 0xd69f0bff) { + /* ERETAA, ERETAB */ + instr_sub_type = OCSD_S_INSTR_V8_ERET; + } else if ((inst & 0xfffffbff) == 0xd65f0bff) { + /* RETAA, RETAB */ + 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) { /* B */ npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11); } else if ((inst & 0x7c000000) == 0x14000000) { /* B, BL imm */ npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4); } else if ((inst & 0x7e000000) == 0x34000000) { /* CB */ npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11); } else if ((inst & 0x7e000000) == 0x36000000) { /* TB */ npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16); } else { is_direct_branch = 0; } if (is_direct_branch && pnpc != NULL) { *pnpc = npc; } return is_direct_branch; } int inst_ARM_is_branch(uint32_t inst) { return inst_ARM_is_indirect_branch(inst) || inst_ARM_is_direct_branch(inst); } - int inst_Thumb_is_branch(uint32_t inst) { return inst_Thumb_is_indirect_branch(inst) || inst_Thumb_is_direct_branch(inst); } - int inst_A64_is_branch(uint32_t inst) { return inst_A64_is_indirect_branch(inst) || inst_A64_is_direct_branch(inst); } - int inst_ARM_is_branch_and_link(uint32_t inst) { int is_branch = 1; if ((inst & 0xf0000000) == 0xf0000000) { if ((inst & 0xfe000000) == 0xfa000000){ instr_sub_type = OCSD_S_INSTR_BR_LINK; /* BLX (imm) */ } else { is_branch = 0; } } else if ((inst & 0x0f000000) == 0x0b000000) { instr_sub_type = OCSD_S_INSTR_BR_LINK; /* BL */ } else if ((inst & 0x0ff000f0) == 0x01200030) { instr_sub_type = OCSD_S_INSTR_BR_LINK; /* BLX (reg) */ } else { is_branch = 0; } return is_branch; } - int inst_Thumb_is_branch_and_link(uint32_t inst) { int is_branch = 1; if ((inst & 0xff800000) == 0x47800000) { instr_sub_type = OCSD_S_INSTR_BR_LINK; /* BLX (reg) */ } else if ((inst & 0xf800c000) == 0xf000c000) { instr_sub_type = OCSD_S_INSTR_BR_LINK; /* BL, BLX (imm) */ } else { is_branch = 0; } return is_branch; } - int inst_A64_is_branch_and_link(uint32_t inst) { int is_branch = 1; if ((inst & 0xfffffc1f) == 0xd63f0000) { /* BLR */ instr_sub_type = OCSD_S_INSTR_BR_LINK; } else if ((inst & 0xfc000000) == 0x94000000) { /* BL */ instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else if (arch_version >= 0x0803) { + /* new pointer auth instr for v8.3 arch */ + if ((inst & 0xfffff800) == 0xd73f0800) { + /* BLRAA, BLRBB */ + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else if ((inst & 0xfffff81F) == 0xd63f081F) { + /* BLRAAZ, BLRBBZ */ + 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) { /* B.cond */ return 1; } return 0; } - arm_barrier_t inst_ARM_barrier(uint32_t inst) { if ((inst & 0xfff00000) == 0xf5700000) { switch (inst & 0xf0) { case 0x40: return ARM_BARRIER_DSB; case 0x50: return ARM_BARRIER_DMB; case 0x60: return ARM_BARRIER_ISB; default: return ARM_BARRIER_NONE; } } else if ((inst & 0x0fff0f00) == 0x0e070f00) { switch (inst & 0xff) { case 0x9a: return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */ case 0xba: return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */ case 0x95: return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */ default: return ARM_BARRIER_NONE; } } else { return ARM_BARRIER_NONE; } } - arm_barrier_t inst_Thumb_barrier(uint32_t inst) { if ((inst & 0xffffff00) == 0xf3bf8f00) { switch (inst & 0xf0) { case 0x40: return ARM_BARRIER_DSB; case 0x50: return ARM_BARRIER_DMB; case 0x60: return ARM_BARRIER_ISB; default: return ARM_BARRIER_NONE; } } else if ((inst & 0xffff0f00) == 0xee070f00) { /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */ switch (inst & 0xff) { case 0x9a: return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */ case 0xba: return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */ case 0x95: return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */ default: return ARM_BARRIER_NONE; } return ARM_BARRIER_NONE; } else { return ARM_BARRIER_NONE; } } - arm_barrier_t inst_A64_barrier(uint32_t inst) { if ((inst & 0xfffff09f) == 0xd503309f) { switch (inst & 0x60) { case 0x0: return ARM_BARRIER_DSB; case 0x20: return ARM_BARRIER_DMB; case 0x40: return ARM_BARRIER_ISB; default: return ARM_BARRIER_NONE; } } else { return ARM_BARRIER_NONE; } } - int inst_ARM_is_UDF(uint32_t inst) { return (inst & 0xfff000f0) == 0xe7f000f0; } - int inst_Thumb_is_UDF(uint32_t inst) { return (inst & 0xff000000) == 0xde000000 || /* T1 */ (inst & 0xfff0f000) == 0xf7f0a000; /* T2 */ } - int inst_A64_is_UDF(uint32_t inst) { /* No A64 encodings are formally allocated as permanently undefined, but it is intended not to allocate any instructions in the 21-bit regions at the bottom or top of the range. */ return (inst & 0xffe00000) == 0x00000000 || (inst & 0xffe00000) == 0xffe00000; } /* End of File trc_idec_arminst.cpp */ Index: head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp =================================================================== --- head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp (revision 353393) @@ -1,54 +1,54 @@ /* * \file trc_mem_acc_bufptr.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "mem_acc/trc_mem_acc_bufptr.h" TrcMemAccBufPtr::TrcMemAccBufPtr(const ocsd_vaddr_t s_address, const uint8_t *p_buffer, const uint32_t size) : TrcMemAccessorBase(MEMACC_BUFPTR, s_address, s_address+size-1), m_p_buffer(p_buffer), m_size(size) { } -const uint32_t TrcMemAccBufPtr::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer) +const uint32_t TrcMemAccBufPtr::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trcID, const uint32_t reqBytes, uint8_t *byteBuffer) { // mapper wlll filter memory spaces. uint32_t bytesRead = bytesInRange(address,reqBytes); // check bytes available if(bytesRead) memcpy(byteBuffer,m_p_buffer+address-m_startAddress,bytesRead); return bytesRead; } /* End of File trc_mem_acc_bufptr.cpp */ Index: head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cache.cpp =================================================================== --- head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cache.cpp (nonexistent) +++ head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cache.cpp (revision 353393) @@ -0,0 +1,176 @@ +/*! +* \file trc_mem_acc_cache.cpp +* \brief OpenCSD : Memory accessor cache. +* +* \copyright Copyright (c) 2018, 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 "mem_acc/trc_mem_acc_cache.h" +#include "mem_acc/trc_mem_acc_base.h" +#include "interfaces/trc_error_log_i.h" + +#ifdef LOG_CACHE_STATS +#define INC_HITS_RL(idx) m_hits++; m_hit_rl[m_mru_idx]++; +#define INC_MISS() m_misses++; +#define INC_PAGES() m_pages++; +#define SET_MAX_RL(idx) \ + { \ + if (m_hit_rl_max[idx] < m_hit_rl[idx]) \ + m_hit_rl_max[idx] = m_hit_rl[idx]; \ + m_hit_rl[idx] = 0; \ + } +#define INC_RL(idx) m_hit_rl[m_mru_idx]++; +#else +#define INC_HITS_RL(idx) +#define INC_MISS() +#define INC_PAGES() +#define SET_MAX_RL(idx) +#define INC_RL(idx) +#endif + +// uncomment to log cache ops +//#define LOG_CACHE_OPS + +ocsd_err_t TrcMemAccCache::readBytesFromCache(TrcMemAccessorBase *p_accessor, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trcID, uint32_t *numBytes, uint8_t *byteBuffer) +{ + uint32_t bytesRead = 0, reqBytes = *numBytes; + ocsd_err_t err = OCSD_OK; + +#ifdef LOG_CACHE_OPS + std::ostringstream oss; +#endif + + if (m_bCacheEnabled) + { + if (blockInCache(address, reqBytes)) + { + bytesRead = reqBytes; + memcpy(byteBuffer, &m_mru[m_mru_idx].data[address - m_mru[m_mru_idx].st_addr], reqBytes); +#ifdef LOG_CACHE_OPS + oss << "TrcMemAccCache:: hit [page: " << std::dec << m_mru_idx << "[addr:0x" << std::hex << address << ", bytes: " << std::dec << reqBytes << "]\n"; + logMsg(oss.str()); +#endif + INC_HITS_RL(m_mru_idx); + } + else + { + INC_MISS(); +#ifdef LOG_CACHE_OPS + oss << "TrcMemAccCache:: miss [addr:0x" << std::hex << address << ", bytes: " << std::dec << reqBytes << "]\n"; + logMsg(oss.str()); +#endif + /* need a new cache page - check the underlying accessor for the data */ + m_mru_idx = m_mru_next_new; + m_mru[m_mru_idx].valid_len = p_accessor->readBytes(address, mem_space, trcID, MEM_ACC_CACHE_PAGE_SIZE, &m_mru[m_mru_idx].data[0]); + + /* check return length valid - v bad if return length more than request */ + if (m_mru[m_mru_idx].valid_len > MEM_ACC_CACHE_PAGE_SIZE) + { + m_mru[m_mru_idx].valid_len = 0; // set to nothing returned. + err = OCSD_ERR_MEM_ACC_BAD_LEN; + } + + if (m_mru[m_mru_idx].valid_len > 0) + { + // got some data - so save the + m_mru[m_mru_idx].st_addr = address; + + // log the run length hit counts + SET_MAX_RL(m_mru_idx); + +#ifdef LOG_CACHE_OPS + oss.str(""); + oss << "TrcMemAccCache:: load [page: " << std::dec << m_mru_idx << "[addr:0x" << std::hex << address << ", bytes: " << std::dec << m_mru[m_mru_idx].valid_len << "]\n"; + logMsg(oss.str()); +#endif + INC_PAGES(); + + // increment the next new page counter. + m_mru_next_new++; + if (m_mru_next_new == MEM_ACC_CACHE_MRU_SIZE) + m_mru_next_new = 0; + + if (blockInPage(address, reqBytes)) /* check we got the data we needed */ + { + bytesRead = reqBytes; + memcpy(byteBuffer, &m_mru[m_mru_idx].data[address - m_mru[m_mru_idx].st_addr], reqBytes); + INC_RL(m_mru_idx); + } + else + { +#ifdef LOG_CACHE_OPS + oss.str(""); + oss << "TrcMemAccCache:: miss-after-load [page: " << std::dec << m_mru_idx << "[addr:0x" << std::hex << address << ", bytes: " << std::dec << m_mru[m_mru_idx].valid_len << "]\n"; + logMsg(oss.str()); +#endif + INC_MISS(); + } + } + } + } + *numBytes = bytesRead; + return err; +} + +void TrcMemAccCache::logMsg(const std::string &szMsg) +{ + if (m_err_log) + m_err_log->LogMessage(ITraceErrorLog::HANDLE_GEN_INFO, OCSD_ERR_SEV_INFO, szMsg); +} + +void TrcMemAccCache::setErrorLog(ITraceErrorLog *log) +{ + m_err_log = log; +} + +void TrcMemAccCache::logAndClearCounts() +{ +#ifdef LOG_CACHE_STATS + std::ostringstream oss; + + oss << "TrcMemAccCache:: cache performance: hits(" << std::dec << m_hits << "), miss(" << m_misses << "), pages(" << m_pages << ")\n"; + logMsg(oss.str()); + for (int i = 0; i < MEM_ACC_CACHE_MRU_SIZE; i++) + { + if (m_hit_rl_max[i] < m_hit_rl[i]) + m_hit_rl_max[i] = m_hit_rl[i]; + oss.str(""); + oss << "Run length max page " << std::dec << i << ": " << m_hit_rl_max[i] << "\n"; + logMsg(oss.str()); + } + m_hits = m_misses = m_pages = 0; +#endif +} + + +/* End of File trc_mem_acc_cache.cpp */ Property changes on: head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cache.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cb.cpp =================================================================== --- head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cb.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_cb.cpp (revision 353393) @@ -1,32 +1,34 @@ /*! * \file trc_mem_acc_cb.cpp * \brief OpenCSD : Trace Mem accessor - callback function * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ #include "mem_acc/trc_mem_acc_cb.h" TrcMemAccCB::TrcMemAccCB(const ocsd_vaddr_t s_address, const ocsd_vaddr_t e_address, const ocsd_mem_space_acc_t mem_space) : TrcMemAccessorBase(MEMACC_CB_IF, s_address, e_address), m_p_CBclass(0), m_p_CBfn(0), m_p_cbfn_context(0) { setMemSpace(mem_space); } /** Memory access override - allow decoder to read bytes from the buffer. */ -const uint32_t TrcMemAccCB::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint32_t reqBytes, uint8_t *byteBuffer) +const uint32_t TrcMemAccCB::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t memSpace, const uint8_t trcID, const uint32_t reqBytes, uint8_t *byteBuffer) { // if we have a callback object, use it to call back. if(m_p_CBclass) return m_p_CBclass->readBytes(address,memSpace,reqBytes,byteBuffer); if(m_p_CBfn) return m_p_CBfn(m_p_cbfn_context, address,memSpace,reqBytes,byteBuffer); + if (m_p_CBIDfn) + return m_p_CBIDfn(m_p_cbfn_context, address, memSpace, trcID, reqBytes, byteBuffer); return 0; } /* End of File trc_mem_acc_cb.cpp */ Index: head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_file.cpp =================================================================== --- head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_file.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_file.cpp (revision 353393) @@ -1,391 +1,391 @@ /* * \file trc_mem_acc_file.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mem_acc/trc_mem_acc_file.h" #include #include /***************************************************/ /* protected construction and reference counting */ /***************************************************/ TrcMemAccessorFile::TrcMemAccessorFile() : TrcMemAccessorBase(MEMACC_FILE) { m_ref_count = 0; m_base_range_set = false; m_has_access_regions = false; m_file_size = 0; } TrcMemAccessorFile::~TrcMemAccessorFile() { if(m_mem_file.is_open()) m_mem_file.close(); if(m_access_regions.size()) { std::list::iterator it; it = m_access_regions.begin(); while(it != m_access_regions.end()) { delete (*it); it++; } m_access_regions.clear(); } } ocsd_err_t TrcMemAccessorFile::initAccessor(const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset, size_t size) { ocsd_err_t err = OCSD_OK; bool init = false; m_mem_file.open(pathToFile.c_str(), std::ifstream::binary | std::ifstream::ate); if(m_mem_file.is_open()) { m_file_size = (ocsd_vaddr_t)m_mem_file.tellg() & ((ocsd_vaddr_t)~0x1); m_mem_file.seekg(0, m_mem_file.beg); // adding an offset of 0, sets the base range. if((offset == 0) && (size == 0)) { init = AddOffsetRange(startAddr, ((size_t)m_file_size)-offset, offset); } else if((offset + size) <= m_file_size) { // if offset != 0, size must by != 0 init = AddOffsetRange(startAddr, size, offset); } m_file_path = pathToFile; } else err = OCSD_ERR_MEM_ACC_FILE_NOT_FOUND; if(!init) err = OCSD_ERR_NOT_INIT; return err; } FileRegionMemAccessor *TrcMemAccessorFile::getRegionForAddress(const ocsd_vaddr_t startAddr) const { FileRegionMemAccessor *p_region = 0; if(m_has_access_regions) { std::list::const_iterator it; it = m_access_regions.begin(); while((it != m_access_regions.end()) && (p_region == 0)) { if((*it)->addrInRange(startAddr)) p_region = *it; it++; } } return p_region; } /***************************************************/ /* static object creation */ /***************************************************/ std::map TrcMemAccessorFile::s_FileAccessorMap; // return existing or create new accessor ocsd_err_t TrcMemAccessorFile::createFileAccessor(TrcMemAccessorFile **p_acc, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset /*= 0*/, size_t size /*= 0*/) { ocsd_err_t err = OCSD_OK; TrcMemAccessorFile * acc = 0; std::map::iterator it = s_FileAccessorMap.find(pathToFile); if(it != s_FileAccessorMap.end()) { acc = it->second; if(acc->addrStartOfRange(startAddr)) acc->IncRefCount(); else { err = OCSD_ERR_MEM_ACC_FILE_DIFF_RANGE; acc = 0; } } else { acc = new (std::nothrow) TrcMemAccessorFile(); if(acc != 0) { if((err = acc->initAccessor(pathToFile,startAddr, offset,size)) == OCSD_OK) { acc->IncRefCount(); s_FileAccessorMap.insert(std::pair(pathToFile,acc)); } else { delete acc; acc = 0; } } else err = OCSD_ERR_MEM; } *p_acc = acc; return err; } void TrcMemAccessorFile::destroyFileAccessor(TrcMemAccessorFile *p_accessor) { if(p_accessor != 0) { p_accessor->DecRefCount(); if(p_accessor->getRefCount() == 0) { std::map::iterator it = s_FileAccessorMap.find(p_accessor->getFilePath()); if(it != s_FileAccessorMap.end()) { s_FileAccessorMap.erase(it); } delete p_accessor; } } } const bool TrcMemAccessorFile::isExistingFileAccessor(const std::string &pathToFile) { bool bExists = false; std::map::const_iterator it = s_FileAccessorMap.find(pathToFile); if(it != s_FileAccessorMap.end()) bExists = true; return bExists; } TrcMemAccessorFile * TrcMemAccessorFile::getExistingFileAccessor(const std::string &pathToFile) { TrcMemAccessorFile * p_acc = 0; std::map::iterator it = s_FileAccessorMap.find(pathToFile); if(it != s_FileAccessorMap.end()) p_acc = it->second; return p_acc; } /***************************************************/ /* accessor instance functions */ /***************************************************/ -const uint32_t TrcMemAccessorFile::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer) +const uint32_t TrcMemAccessorFile::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trcID, const uint32_t reqBytes, uint8_t *byteBuffer) { if(!m_mem_file.is_open()) return 0; uint32_t bytesRead = 0; if(m_base_range_set) { bytesRead = TrcMemAccessorBase::bytesInRange(address,reqBytes); // get avialable bytes in range. if(bytesRead) { ocsd_vaddr_t addr_pos = (ocsd_vaddr_t)m_mem_file.tellg(); if((address - m_startAddress) != addr_pos) m_mem_file.seekg(address - m_startAddress); m_mem_file.read((char *)byteBuffer,bytesRead); } } if((bytesRead == 0) && m_has_access_regions) { bytesRead = bytesInRange(address,reqBytes); if(bytesRead) { FileRegionMemAccessor *p_region = getRegionForAddress(address); ocsd_vaddr_t addr_pos = (ocsd_vaddr_t)m_mem_file.tellg(); if((address - p_region->regionStartAddress() + p_region->getOffset()) != addr_pos) m_mem_file.seekg(address - p_region->regionStartAddress() + p_region->getOffset()); m_mem_file.read((char *)byteBuffer,bytesRead); } } return bytesRead; } bool TrcMemAccessorFile::AddOffsetRange(const ocsd_vaddr_t startAddr, const size_t size, const size_t offset) { bool addOK = false; if(m_file_size == 0) // must have set the file size return false; if(addrInRange(startAddr) || addrInRange(startAddr+size-1)) // cannot be overlapping return false; // now either set the base range or an offset range if(offset == 0) { if(!m_base_range_set) { setRange(startAddr, startAddr+size-1); m_base_range_set = true; addOK = true; } } else { if((offset + size) <= m_file_size) { FileRegionMemAccessor *frmacc = new (std::nothrow) FileRegionMemAccessor(); if(frmacc) { frmacc->setOffset(offset); frmacc->setRange(startAddr,startAddr+size-1); m_access_regions.push_back(frmacc); m_access_regions.sort(); // may need to trim the 0 offset base range... if(m_base_range_set) { std::list::iterator it; it = m_access_regions.begin(); size_t first_range_offset = (*it)->getOffset(); if((m_startAddress + first_range_offset - 1) > m_endAddress) m_endAddress = m_startAddress + first_range_offset - 1; } addOK = true; m_has_access_regions = true; } } } return addOK; } const bool TrcMemAccessorFile::addrInRange(const ocsd_vaddr_t s_address) const { bool bInRange = false; if(m_base_range_set) bInRange = TrcMemAccessorBase::addrInRange(s_address); if(!bInRange && m_has_access_regions) { if(getRegionForAddress(s_address) != 0) bInRange = true; } return bInRange; } const bool TrcMemAccessorFile::addrStartOfRange(const ocsd_vaddr_t s_address) const { bool bInRange = false; if(m_base_range_set) bInRange = TrcMemAccessorBase::addrStartOfRange(s_address); if(!bInRange && m_has_access_regions) { FileRegionMemAccessor *pRegion = getRegionForAddress(s_address); if(pRegion) bInRange = (pRegion->regionStartAddress() == s_address); } return bInRange; } /* validate ranges */ const bool TrcMemAccessorFile::validateRange() { bool bRangeValid = true; if(m_base_range_set) bRangeValid = TrcMemAccessorBase::validateRange(); if(m_has_access_regions && bRangeValid) { std::list::const_iterator it; it = m_access_regions.begin(); while((it != m_access_regions.end()) && bRangeValid) { bRangeValid = (*it)->validateRange(); it++; } } return bRangeValid; } const uint32_t TrcMemAccessorFile::bytesInRange(const ocsd_vaddr_t s_address, const uint32_t reqBytes) const { uint32_t bytesInRange = 0; if(m_base_range_set) bytesInRange = TrcMemAccessorBase::bytesInRange(s_address,reqBytes); if((bytesInRange == 0) && (m_has_access_regions)) { FileRegionMemAccessor *p_region = getRegionForAddress(s_address); bytesInRange = p_region->bytesInRange(s_address,reqBytes); } return bytesInRange; } const bool TrcMemAccessorFile::overLapRange(const TrcMemAccessorBase *p_test_acc) const { bool bOverLapRange = false; if(m_base_range_set) bOverLapRange = TrcMemAccessorBase::overLapRange(p_test_acc); if(!bOverLapRange && (m_has_access_regions)) { std::list::const_iterator it; it = m_access_regions.begin(); while((it != m_access_regions.end()) && !bOverLapRange) { bOverLapRange = (*it)->overLapRange(p_test_acc); it++; } } return bOverLapRange; } /*! Override to handle ranges and offset accessors plus add in file name. */ void TrcMemAccessorFile::getMemAccString(std::string &accStr) const { std::ostringstream oss; accStr = ""; if(m_base_range_set) { TrcMemAccessorBase::getMemAccString(accStr); } if(m_has_access_regions) { std::string addStr; std::list::const_iterator it; it = m_access_regions.begin(); while(it != m_access_regions.end()) { (*it)->getMemAccString(addStr); if(accStr.length()) accStr += "\n"; accStr += addStr; it++; } } accStr += (std::string)"\nFilename=" + m_file_path; } /* End of File trc_mem_acc_file.cpp */ Index: head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp =================================================================== --- head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/mem_acc/trc_mem_acc_mapper.cpp (revision 353393) @@ -1,238 +1,299 @@ /* * \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); + 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) - *num_bytes = m_acc_curr->readBytes(address, mem_space, *num_bytes,p_buffer); - else - *num_bytes = 0; - return OCSD_OK; + 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::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 */ Index: head/contrib/opencsd/decoder/source/ocsd_code_follower.cpp =================================================================== --- head/contrib/opencsd/decoder/source/ocsd_code_follower.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/ocsd_code_follower.cpp (revision 353393) @@ -1,161 +1,162 @@ /* * \file ocsd_code_follower.cpp * \brief OpenCSD : Instruction Code path follower. * * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common/ocsd_code_follower.h" OcsdCodeFollower::OcsdCodeFollower() { m_instr_info.pe_type.arch = ARCH_UNKNOWN; m_instr_info.pe_type.profile = profile_Unknown; m_instr_info.isa = ocsd_isa_unknown; m_instr_info.dsb_dmb_waypoints = 0; + m_instr_info.wfi_wfe_branch = 0; m_instr_info.instr_addr = 0; m_instr_info.opcode = 0; m_pMemAccess = 0; m_pIDecode = 0; m_mem_space_csid = 0; m_st_range_addr = m_en_range_addr = m_next_addr = 0; m_b_next_valid = false; m_b_nacc_err = false; } OcsdCodeFollower::~OcsdCodeFollower() { } void OcsdCodeFollower::initInterfaces(componentAttachPt *pMemAccess, componentAttachPt *pIDecode) { m_pMemAccess = pMemAccess; m_pIDecode = pIDecode; } bool OcsdCodeFollower::initFollowerState() { bool initDone = false; // reset per follow flags m_b_next_valid = false; m_b_nacc_err = false; // set range addresses m_en_range_addr = m_next_addr = m_st_range_addr; // check initialisation is valid. // must have attached memory access and i-decode objects if(m_pMemAccess && m_pIDecode) { initDone = (m_pMemAccess->hasAttachedAndEnabled() && m_pIDecode->hasAttachedAndEnabled()); } return initDone; } /*! * Decodes an instruction at a single location, calculates the next address * if possible according to the instruction type and atom. * * @param addrStart : Address of the instruction * @param A : Atom value - E or N * * @return ocsd_err_t : OCSD_OK - decode correct, check flags for next address * : OCSD_ERR_MEM_NACC - unable to access memory area @ address - need new address in trace packet stream. * : OCSD_ERR_NOT_INIT - not initialised - fatal. * : OCSD_ - other error occured - fatal. */ ocsd_err_t OcsdCodeFollower::followSingleAtom(const ocsd_vaddr_t addrStart, const ocsd_atm_val A) { ocsd_err_t err = OCSD_ERR_NOT_INIT; if(!initFollowerState()) return err; m_en_range_addr = m_st_range_addr = m_instr_info.instr_addr = addrStart; err = decodeSingleOpCode(); if(err != OCSD_OK) return err; // set end range - always after the instruction executed. m_en_range_addr = m_instr_info.instr_addr + m_instr_info.instr_size; // assume next addr is the instruction after m_next_addr = m_en_range_addr; m_b_next_valid = true; // case when next address is different switch(m_instr_info.type) { case OCSD_INSTR_BR: if(A == ATOM_E) // executed the direct branch m_next_addr = m_instr_info.branch_addr; break; case OCSD_INSTR_BR_INDIRECT: if(A == ATOM_E) // executed indirect branch m_b_next_valid = false; break; } return err; } ocsd_err_t OcsdCodeFollower::decodeSingleOpCode() { ocsd_err_t err = OCSD_OK; // request 4 bytes for the opcode - even for Thumb which may be T32 uint32_t bytesReq = 4; uint32_t opcode; // buffer for opcode // read memory location for opcode err = m_pMemAccess->first()->ReadTargetMemory(m_instr_info.instr_addr,m_mem_space_csid,m_mem_acc_rule,&bytesReq,(uint8_t *)&opcode); // operational error (not access problem - that is indicated by 0 bytes returned) if(err != OCSD_OK) return err; if(bytesReq == 4) // check that we got all memory requested. { m_instr_info.opcode = opcode; err = m_pIDecode->first()->DecodeInstruction(&m_instr_info); } else // otherwise memory unavailable. { m_b_nacc_err = true; m_nacc_address = m_instr_info.instr_addr; err = OCSD_ERR_MEM_NACC; } return err; } /* End of File ocsd_code_follower.cpp */ Index: head/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp =================================================================== --- head/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/ocsd_dcd_tree.cpp (revision 353393) @@ -1,671 +1,715 @@ /* * \file ocsd_dcd_tree.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common/ocsd_dcd_tree.h" #include "common/ocsd_lib_dcd_register.h" #include "mem_acc/trc_mem_acc_mapper.h" /***************************************************************/ ITraceErrorLog *DecodeTree::s_i_error_logger = &DecodeTree::s_error_logger; std::list DecodeTree::s_trace_dcd_trees; /**< list of pointers to decode tree objects */ ocsdDefaultErrorLogger DecodeTree::s_error_logger; /**< The library default error logger */ TrcIDecode DecodeTree::s_instruction_decoder; /**< default instruction decode library */ DecodeTree *DecodeTree::CreateDecodeTree(const ocsd_dcd_tree_src_t src_type, uint32_t formatterCfgFlags) { DecodeTree *dcd_tree = new (std::nothrow) DecodeTree(); if(dcd_tree != 0) { if(dcd_tree->initialise(src_type, formatterCfgFlags)) { s_trace_dcd_trees.push_back(dcd_tree); } else { delete dcd_tree; dcd_tree = 0; } } return dcd_tree; } void DecodeTree::DestroyDecodeTree(DecodeTree *p_dcd_tree) { std::list::iterator it; bool bDestroyed = false; it = s_trace_dcd_trees.begin(); while(!bDestroyed && (it != s_trace_dcd_trees.end())) { if(*it == p_dcd_tree) { s_trace_dcd_trees.erase(it); delete p_dcd_tree; bDestroyed = true; } else it++; } } void DecodeTree::setAlternateErrorLogger(ITraceErrorLog *p_error_logger) { if(p_error_logger) s_i_error_logger = p_error_logger; else s_i_error_logger = &s_error_logger; } /***************************************************************/ DecodeTree::DecodeTree() : m_i_instr_decode(&s_instruction_decoder), m_i_mem_access(0), m_i_gen_elem_out(0), m_i_decoder_root(0), m_frame_deformatter_root(0), m_decode_elem_iter(0), m_default_mapper(0), m_created_mapper(false) { for(int i = 0; i < 0x80; i++) m_decode_elements[i] = 0; } DecodeTree::~DecodeTree() { + destroyMemAccMapper(); for(uint8_t i = 0; i < 0x80; i++) { destroyDecodeElement(i); } PktPrinterFact::destroyAllPrinters(m_printer_list); } ocsd_datapath_resp_t DecodeTree::TraceDataIn( const ocsd_datapath_op_t op, const ocsd_trc_index_t index, const uint32_t dataBlockSize, const uint8_t *pDataBlock, uint32_t *numBytesProcessed) { if(m_i_decoder_root) return m_i_decoder_root->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed); *numBytesProcessed = 0; return OCSD_RESP_FATAL_NOT_INIT; } /* set key interfaces - attach / replace on any existing tree components */ void DecodeTree::setInstrDecoder(IInstrDecode *i_instr_decode) { uint8_t elemID; DecodeTreeElement *pElem = 0; pElem = getFirstElement(elemID); while(pElem != 0) { pElem->getDecoderMngr()->attachInstrDecoder(pElem->getDecoderHandle(),i_instr_decode); pElem = getNextElement(elemID); } } void DecodeTree::setMemAccessI(ITargetMemAccess *i_mem_access) { uint8_t elemID; DecodeTreeElement *pElem = 0; pElem = getFirstElement(elemID); while(pElem != 0) { pElem->getDecoderMngr()->attachMemAccessor(pElem->getDecoderHandle(),i_mem_access); pElem = getNextElement(elemID); } m_i_mem_access = i_mem_access; } void DecodeTree::setGenTraceElemOutI(ITrcGenElemIn *i_gen_trace_elem) { uint8_t elemID; DecodeTreeElement *pElem = 0; pElem = getFirstElement(elemID); while(pElem != 0) { pElem->getDecoderMngr()->attachOutputSink(pElem->getDecoderHandle(),i_gen_trace_elem); pElem = getNextElement(elemID); } } ocsd_err_t DecodeTree::createMemAccMapper(memacc_mapper_t type /* = MEMACC_MAP_GLOBAL*/ ) { // clean up any old one destroyMemAccMapper(); // make a new one switch(type) { default: case MEMACC_MAP_GLOBAL: m_default_mapper = new (std::nothrow) TrcMemAccMapGlobalSpace(); break; } // set the access interface if(m_default_mapper) { m_created_mapper = true; setMemAccessI(m_default_mapper); m_default_mapper->setErrorLog(s_i_error_logger); } return (m_default_mapper != 0) ? OCSD_OK : OCSD_ERR_MEM; } void DecodeTree::setExternMemAccMapper(TrcMemAccMapper* pMapper) { destroyMemAccMapper(); // destroy any existing mapper - if decode tree created it. m_default_mapper = pMapper; } void DecodeTree::destroyMemAccMapper() { if(m_default_mapper && m_created_mapper) { m_default_mapper->RemoveAllAccessors(); delete m_default_mapper; m_default_mapper = 0; m_created_mapper = false; } } void DecodeTree::logMappedRanges() { if(m_default_mapper) m_default_mapper->logMappedRanges(); } /* Memory accessor creation - all on default mem accessor using the 0 CSID for global core space. */ ocsd_err_t DecodeTree::addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length) { if(!hasMemAccMapper()) return OCSD_ERR_NOT_INIT; // need a valid memory buffer, and a least enough bytes for one opcode. if((p_mem_buffer == 0) || (mem_length < 4)) return OCSD_ERR_INVALID_PARAM_VAL; TrcMemAccessorBase *p_accessor; ocsd_err_t err = TrcMemAccFactory::CreateBufferAccessor(&p_accessor, address, p_mem_buffer, mem_length); if(err == OCSD_OK) { TrcMemAccBufPtr *pMBuffAcc = dynamic_cast(p_accessor); if(pMBuffAcc) { pMBuffAcc->setMemSpace(mem_space); err = m_default_mapper->AddAccessor(p_accessor,0); } else err = OCSD_ERR_MEM; // wrong type of object - treat as mem error if(err != OCSD_OK) TrcMemAccFactory::DestroyAccessor(p_accessor); } return err; } ocsd_err_t DecodeTree::addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath) { if(!hasMemAccMapper()) return OCSD_ERR_NOT_INIT; if(filepath.length() == 0) return OCSD_ERR_INVALID_PARAM_VAL; TrcMemAccessorBase *p_accessor; ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,address); if(err == OCSD_OK) { TrcMemAccessorFile *pAcc = dynamic_cast(p_accessor); if(pAcc) { pAcc->setMemSpace(mem_space); err = m_default_mapper->AddAccessor(pAcc,0); } else err = OCSD_ERR_MEM; // wrong type of object - treat as mem error if(err != OCSD_OK) TrcMemAccFactory::DestroyAccessor(p_accessor); } return err; } ocsd_err_t DecodeTree::addBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath) { if(!hasMemAccMapper()) return OCSD_ERR_NOT_INIT; if((region_array == 0) || (num_regions == 0) || (filepath.length() == 0)) return OCSD_ERR_INVALID_PARAM_VAL; TrcMemAccessorBase *p_accessor; int curr_region_idx = 0; // add first region during the creation of the file accessor. ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,region_array[curr_region_idx].start_address,region_array[curr_region_idx].file_offset, region_array[curr_region_idx].region_size); if(err == OCSD_OK) { TrcMemAccessorFile *pAcc = dynamic_cast(p_accessor); if(pAcc) { // add additional regions to the file accessor. curr_region_idx++; while(curr_region_idx < num_regions) { pAcc->AddOffsetRange(region_array[curr_region_idx].start_address, region_array[curr_region_idx].region_size, region_array[curr_region_idx].file_offset); curr_region_idx++; } pAcc->setMemSpace(mem_space); // add the accessor to the map. err = m_default_mapper->AddAccessor(pAcc,0); } else err = OCSD_ERR_MEM; // wrong type of object - treat as mem error if(err != OCSD_OK) TrcMemAccFactory::DestroyAccessor(p_accessor); } return err; } -ocsd_err_t DecodeTree::addCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context) +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) { - pCBAcc->setCBIfFn(p_cb_func, p_context); + 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; } DecodeTreeElement * DecodeTree::getDecoderElement(const uint8_t CSID) const { DecodeTreeElement *ret_elem = 0; if(usingFormatter() && OCSD_IS_VALID_CS_SRC_ID(CSID)) { ret_elem = m_decode_elements[CSID]; } else ret_elem = m_decode_elements[0]; // ID 0 is used if single leaf tree. return ret_elem; } DecodeTreeElement *DecodeTree::getFirstElement(uint8_t &elemID) { m_decode_elem_iter = 0; return getNextElement(elemID); } DecodeTreeElement *DecodeTree::getNextElement(uint8_t &elemID) { DecodeTreeElement *ret_elem = 0; if(m_decode_elem_iter < 0x80) { // find a none zero entry or end of range while((m_decode_elements[m_decode_elem_iter] == 0) && (m_decode_elem_iter < 0x80)) m_decode_elem_iter++; // return entry unless end of range if(m_decode_elem_iter < 0x80) { ret_elem = m_decode_elements[m_decode_elem_iter]; elemID = m_decode_elem_iter; m_decode_elem_iter++; } } return ret_elem; } bool DecodeTree::initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCfgFlags) { bool initOK = true; m_dcd_tree_type = type; if(type == OCSD_TRC_SRC_FRAME_FORMATTED) { // frame formatted - we want to create the deformatter and hook it up m_frame_deformatter_root = new (std::nothrow) TraceFormatterFrameDecoder(); if(m_frame_deformatter_root) { m_frame_deformatter_root->Configure(formatterCfgFlags); m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger); m_i_decoder_root = dynamic_cast(m_frame_deformatter_root); } else initOK = false; } return initOK; } void DecodeTree::setSingleRoot(TrcPktProcI *pComp) { m_i_decoder_root = static_cast(pComp); } ocsd_err_t DecodeTree::createDecodeElement(const uint8_t CSID) { ocsd_err_t err = OCSD_ERR_INVALID_ID; if(CSID < 0x80) { if(m_decode_elements[CSID] == 0) { m_decode_elements[CSID] = new (std::nothrow) DecodeTreeElement(); if(m_decode_elements[CSID] == 0) err = OCSD_ERR_MEM; else err = OCSD_OK; } else err = OCSD_ERR_ATTACH_TOO_MANY; } return err; } void DecodeTree::destroyDecodeElement(const uint8_t CSID) { if(CSID < 0x80) { if(m_decode_elements[CSID] != 0) { m_decode_elements[CSID]->DestroyElem(); delete m_decode_elements[CSID]; m_decode_elements[CSID] = 0; } } } ocsd_err_t DecodeTree::setIDFilter(std::vector &ids) { ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER; if(usingFormatter()) { err = m_frame_deformatter_root->OutputFilterAllIDs(false); if(err == OCSD_OK) err = m_frame_deformatter_root->OutputFilterIDs(ids,true); } return err; } ocsd_err_t DecodeTree::clearIDFilter() { ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER; if(usingFormatter()) { err = m_frame_deformatter_root->OutputFilterAllIDs(true); } return err; } /** add a protocol packet printer */ ocsd_err_t DecodeTree::addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter **ppPrinter) { ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL; DecodeTreeElement *pElement = getDecoderElement(CSID); if (pElement) { ocsd_trace_protocol_t protocol = pElement->getProtocol(); ItemPrinter *pPrinter; pPrinter = PktPrinterFact::createProtocolPrinter(getPrinterList(), protocol, CSID); if (pPrinter) { pPrinter->setMessageLogger(getCurrentErrorLogI()->getOutputLogger()); switch (protocol) { case OCSD_PROTOCOL_ETMV4I: { PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); if (bMonitor) err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); else err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); } break; case OCSD_PROTOCOL_ETMV3: { PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); if (bMonitor) err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); else err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); } break; case OCSD_PROTOCOL_PTM: { PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); if (bMonitor) err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); else err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); } break; case OCSD_PROTOCOL_STM: { PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); if (bMonitor) err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); else err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); } break; default: err = OCSD_ERR_NO_PROTOCOL; break; } if (err == OCSD_OK) { if (ppPrinter) *ppPrinter = pPrinter; } else PktPrinterFact::destroyPrinter(getPrinterList(), pPrinter); } } return err; } /** add a raw frame printer */ ocsd_err_t DecodeTree::addRawFramePrinter(RawFramePrinter **ppPrinter, uint32_t flags) { ocsd_err_t err = OCSD_ERR_MEM; RawFramePrinter *pPrinter = PktPrinterFact::createRawFramePrinter(getPrinterList()); if (pPrinter) { pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger())); TraceFormatterFrameDecoder *pFrameDecoder = getFrameDeformatter(); uint32_t cfgFlags = pFrameDecoder->getConfigFlags(); cfgFlags |= ((uint32_t)flags & (OCSD_DFRMTR_PACKED_RAW_OUT | OCSD_DFRMTR_UNPACKED_RAW_OUT)); pFrameDecoder->Configure(cfgFlags); err = pFrameDecoder->getTrcRawFrameAttachPt()->attach(pPrinter); if (ppPrinter && (err==OCSD_OK)) *ppPrinter = pPrinter; } return err; } /** add a generic element output printer */ ocsd_err_t DecodeTree::addGenElemPrinter(TrcGenericElementPrinter **ppPrinter) { ocsd_err_t err = OCSD_ERR_MEM; TrcGenericElementPrinter *pPrinter = PktPrinterFact::createGenElemPrinter(getPrinterList()); if (pPrinter) { pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger())); setGenTraceElemOutI(pPrinter); err = OCSD_OK; if (ppPrinter) *ppPrinter = pPrinter; } return err; } /* End of File ocsd_dcd_tree.cpp */ Index: head/contrib/opencsd/decoder/source/ocsd_error.cpp =================================================================== --- head/contrib/opencsd/decoder/source/ocsd_error.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/ocsd_error.cpp (revision 353393) @@ -1,230 +1,232 @@ /* * \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 inteface not supported by this decoder."}, + {"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(const char *)) / 2); int code = (int)error.getErrorCode(); ocsd_trc_index_t idx = error.getErrorIndex(); uint8_t chan_ID = error.getErrorChanID(); std::ostringstream oss; oss << "0x" << std::hex << std::setfill('0') << std::setw(4) << code; if(code < numerrstr) oss << " (" << s_errorCodeDescs[code][0] << ") [" << s_errorCodeDescs[code][1] << "]; "; else oss << " (unknown); "; if(idx != OCSD_BAD_TRC_INDEX) oss << "TrcIdx=" << std::dec << idx << "; "; if(chan_ID != OCSD_BAD_CS_SRC_ID) oss << "CS ID=" << std::hex << std::setfill('0') << std::setw(2) << (uint16_t)chan_ID << "; "; oss << error.getMessage(); errStr = oss.str(); } /* End of File ocsd_error.cpp */ Index: head/contrib/opencsd/decoder/source/ocsd_error_logger.cpp =================================================================== --- head/contrib/opencsd/decoder/source/ocsd_error_logger.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/ocsd_error_logger.cpp (revision 353393) @@ -1,159 +1,159 @@ /* * \file ocsd_error_logger.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common/ocsd_error_logger.h" -#include +//#include #include ocsdDefaultErrorLogger::ocsdDefaultErrorLogger() : m_Verbosity(OCSD_ERR_SEV_ERROR), m_output_logger(0), m_created_output_logger(false) { m_lastErr = 0; for(int i = 0; i < 0x80; i++) m_lastErrID[i] = 0; m_error_sources.push_back("Gen_Err"); // handle 0 m_error_sources.push_back("Gen_Warn"); // handle 1 m_error_sources.push_back("Gen_Info"); // handle 2 } ocsdDefaultErrorLogger::~ocsdDefaultErrorLogger() { if(m_created_output_logger) delete m_output_logger; if(m_lastErr) delete m_lastErr; for(int i = 0; i < 0x80; i++) if(m_lastErrID[i] != 0) delete m_lastErrID[i]; } bool ocsdDefaultErrorLogger::initErrorLogger(const ocsd_err_severity_t verbosity, bool bCreateOutputLogger /*= false*/) { bool bInit = true; m_Verbosity = verbosity; if(bCreateOutputLogger) { m_output_logger = new (std::nothrow) ocsdMsgLogger(); if(m_output_logger) { m_created_output_logger = true; m_output_logger->setLogOpts(ocsdMsgLogger::OUT_STDERR); } else bInit = false; } return bInit; } void ocsdDefaultErrorLogger::setOutputLogger(ocsdMsgLogger *pLogger) { // if we created the current logger, delete it. if(m_output_logger && m_created_output_logger) delete m_output_logger; m_created_output_logger = false; m_output_logger = pLogger; } const ocsd_hndl_err_log_t ocsdDefaultErrorLogger::RegisterErrorSource(const std::string &component_name) { ocsd_hndl_err_log_t handle = m_error_sources.size(); m_error_sources.push_back(component_name); return handle; } void ocsdDefaultErrorLogger::LogError(const ocsd_hndl_err_log_t handle, const ocsdError *Error) { // only log errors that match or exceed the current verbosity if(m_Verbosity >= Error->getErrorSeverity()) { // print out only if required if(m_output_logger) { if(m_output_logger->isLogging()) { std::string errStr = "unknown"; if(handle < m_error_sources.size()) errStr = m_error_sources[handle]; errStr += " : " + ocsdError::getErrorString(Error); m_output_logger->LogMsg(errStr); } } // log last error if(m_lastErr == 0) CreateErrorObj(&m_lastErr,Error); else *m_lastErr = Error; // log last error associated with an ID if(OCSD_IS_VALID_CS_SRC_ID(Error->getErrorChanID())) { if(m_lastErrID[Error->getErrorChanID()] == 0) CreateErrorObj(&m_lastErrID[Error->getErrorChanID()], Error); else *m_lastErrID[Error->getErrorChanID()] = Error; } } } void ocsdDefaultErrorLogger::LogMessage(const ocsd_hndl_err_log_t handle, const ocsd_err_severity_t filter_level, const std::string &msg ) { // only log errors that match or exceed the current verbosity if((m_Verbosity >= filter_level)) { if(m_output_logger) { if(m_output_logger->isLogging()) { std::string errStr = "unknown"; if(handle < m_error_sources.size()) errStr = m_error_sources[handle]; errStr += " : " + msg; m_output_logger->LogMsg(errStr); } } } } void ocsdDefaultErrorLogger::CreateErrorObj(ocsdError **ppErr, const ocsdError *p_from) { *ppErr = new (std::nothrow) ocsdError(p_from); } /* End of File ocsd_error_logger.cpp */ Index: head/contrib/opencsd/decoder/source/ocsd_version.cpp =================================================================== --- head/contrib/opencsd/decoder/source/ocsd_version.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/ocsd_version.cpp (revision 353393) @@ -1,48 +1,48 @@ /* * \file ocsd_version.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "ocsd_if_version.h" +#include "opencsd/ocsd_if_version.h" #include "common/ocsd_version.h" const uint32_t ocsdVersion::vers_num() { return OCSD_VER_NUM; } const char *ocsdVersion::vers_str() { return OCSD_VER_STRING; } /* End of File ocsd_version.cpp */ Index: head/contrib/opencsd/decoder/source/ptm/trc_pkt_decode_ptm.cpp =================================================================== --- head/contrib/opencsd/decoder/source/ptm/trc_pkt_decode_ptm.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/ptm/trc_pkt_decode_ptm.cpp (revision 353393) @@ -1,660 +1,665 @@ /* * \file trc_pkt_decode_ptm.cpp * \brief OpenCSD : PTM packet decoder. * * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "opencsd/ptm/trc_pkt_decode_ptm.h" #define DCD_NAME "DCD_PTM" TrcPktDecodePtm::TrcPktDecodePtm() : TrcPktDecodeBase(DCD_NAME) { initDecoder(); } TrcPktDecodePtm::TrcPktDecodePtm(int instIDNum) : TrcPktDecodeBase(DCD_NAME,instIDNum) { initDecoder(); } TrcPktDecodePtm::~TrcPktDecodePtm() { } /*********************** implementation packet decoding interface */ ocsd_datapath_resp_t TrcPktDecodePtm::processPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; bool bPktDone = false; while(!bPktDone) { switch(m_curr_state) { case NO_SYNC: // no sync - output a no sync packet then transition to wait sync. m_output_elem.elem_type = OCSD_GEN_TRC_ELEM_NO_SYNC; resp = outputTraceElement(m_output_elem); m_curr_state = (m_curr_packet_in->getType() == PTM_PKT_A_SYNC) ? WAIT_ISYNC : WAIT_SYNC; bPktDone = true; break; case WAIT_SYNC: if(m_curr_packet_in->getType() == PTM_PKT_A_SYNC) m_curr_state = WAIT_ISYNC; bPktDone = true; break; case WAIT_ISYNC: if(m_curr_packet_in->getType() == PTM_PKT_I_SYNC) m_curr_state = DECODE_PKTS; else bPktDone = true; break; case DECODE_PKTS: resp = decodePacket(); bPktDone = true; break; default: // should only see these after a _WAIT resp - in flush handler case CONT_ISYNC: case CONT_ATOM: bPktDone = true; // throw a decoder error break; } } return resp; } ocsd_datapath_resp_t TrcPktDecodePtm::onEOT() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; // shouldn't be any packets left to be processed - flush shoudl have done this. // just output the end of trace marker m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE); resp = outputTraceElement(m_output_elem); return resp; } ocsd_datapath_resp_t TrcPktDecodePtm::onReset() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; resetDecoder(); return resp; } ocsd_datapath_resp_t TrcPktDecodePtm::onFlush() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; resp = contProcess(); return resp; } // atom and isync packets can have multiple ouput packets that can be _WAITed mid stream. ocsd_datapath_resp_t TrcPktDecodePtm::contProcess() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; switch(m_curr_state) { case CONT_ISYNC: resp = processIsync(); break; case CONT_ATOM: resp = processAtom(); break; case CONT_WPUP: resp = processWPUpdate(); break; case CONT_BRANCH: resp = processBranch(); break; default: break; // not a state that requires further processing } if(OCSD_DATA_RESP_IS_CONT(resp) && processStateIsCont()) m_curr_state = DECODE_PKTS; // continue packet processing - assuming we have not degraded into an unsynced state. return resp; } ocsd_err_t TrcPktDecodePtm::onProtocolConfig() { ocsd_err_t err = OCSD_OK; if(m_config == 0) return OCSD_ERR_NOT_INIT; // static config - copy of CSID for easy reference m_CSID = m_config->getTraceID(); // handle return stack implementation if (m_config->hasRetStack()) { m_return_stack.set_active(m_config->enaRetStack()); #ifdef TRC_RET_STACK_DEBUG m_return_stack.set_dbg_logger(this); #endif } // config options affecting decode m_instr_info.pe_type.profile = m_config->coreProfile(); m_instr_info.pe_type.arch = m_config->archVersion(); m_instr_info.dsb_dmb_waypoints = m_config->dmsbWayPt() ? 1 : 0; + m_instr_info.wfi_wfe_branch = 0; return err; } /****************** local decoder routines */ void TrcPktDecodePtm::initDecoder() { m_CSID = 0; m_instr_info.pe_type.profile = profile_Unknown; m_instr_info.pe_type.arch = ARCH_UNKNOWN; m_instr_info.dsb_dmb_waypoints = 0; resetDecoder(); } void TrcPktDecodePtm::resetDecoder() { m_curr_state = NO_SYNC; m_need_isync = true; // need context to start. m_instr_info.isa = ocsd_isa_unknown; m_mem_nacc_pending = false; m_pe_context.ctxt_id_valid = 0; m_pe_context.bits64 = 0; m_pe_context.vmid_valid = 0; m_pe_context.exception_level = ocsd_EL_unknown; m_pe_context.security_level = ocsd_sec_secure; m_pe_context.el_valid = 0; m_curr_pe_state.instr_addr = 0x0; m_curr_pe_state.isa = ocsd_isa_unknown; m_curr_pe_state.valid = false; m_atoms.clearAll(); m_output_elem.init(); } ocsd_datapath_resp_t TrcPktDecodePtm::decodePacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; switch(m_curr_packet_in->getType()) { // ignore these from trace o/p point of veiw case PTM_PKT_NOTSYNC: case PTM_PKT_INCOMPLETE_EOT: case PTM_PKT_NOERROR: break; // bad / reserved packet - need to wait for next sync point case PTM_PKT_BAD_SEQUENCE: case PTM_PKT_RESERVED: m_curr_state = WAIT_SYNC; m_need_isync = true; // need context to re-start. m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); resp = outputTraceElement(m_output_elem); break; // packets we can ignore if in sync case PTM_PKT_A_SYNC: case PTM_PKT_IGNORE: break; // case PTM_PKT_I_SYNC: resp = processIsync(); break; case PTM_PKT_BRANCH_ADDRESS: resp = processBranch(); break; case PTM_PKT_TRIGGER: m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT); m_output_elem.setEvent(EVENT_TRIGGER, 0); resp = outputTraceElement(m_output_elem); break; case PTM_PKT_WPOINT_UPDATE: resp = processWPUpdate(); break; case PTM_PKT_CONTEXT_ID: { bool bUpdate = true; // see if this is a change if((m_pe_context.ctxt_id_valid) && (m_pe_context.context_id == m_curr_packet_in->context.ctxtID)) bUpdate = false; if(bUpdate) { m_pe_context.context_id = m_curr_packet_in->context.ctxtID; m_pe_context.ctxt_id_valid = 1; m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); m_output_elem.setContext(m_pe_context); resp = outputTraceElement(m_output_elem); } } break; case PTM_PKT_VMID: { bool bUpdate = true; // see if this is a change if((m_pe_context.vmid_valid) && (m_pe_context.vmid == m_curr_packet_in->context.VMID)) bUpdate = false; if(bUpdate) { m_pe_context.vmid = m_curr_packet_in->context.VMID; m_pe_context.vmid_valid = 1; m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); m_output_elem.setContext(m_pe_context); resp = outputTraceElement(m_output_elem); } } break; case PTM_PKT_ATOM: if(m_curr_pe_state.valid) { m_atoms.initAtomPkt(m_curr_packet_in->getAtom(),m_index_curr_pkt); resp = processAtom(); } break; case PTM_PKT_TIMESTAMP: m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); m_output_elem.timestamp = m_curr_packet_in->timestamp; if(m_curr_packet_in->cc_valid) m_output_elem.setCycleCount(m_curr_packet_in->cycle_count); resp = outputTraceElement(m_output_elem); break; case PTM_PKT_EXCEPTION_RET: m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); resp = outputTraceElement(m_output_elem); break; } return resp; } ocsd_datapath_resp_t TrcPktDecodePtm::processIsync() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; // extract the I-Sync data if not re-entering after a _WAIT if(m_curr_state == DECODE_PKTS) { m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal(); m_curr_pe_state.isa = m_curr_packet_in->getISA(); m_curr_pe_state.valid = true; m_i_sync_pe_ctxt = m_curr_packet_in->ISAChanged(); if(m_curr_packet_in->CtxtIDUpdated()) { m_pe_context.context_id = m_curr_packet_in->getCtxtID(); m_pe_context.ctxt_id_valid = 1; m_i_sync_pe_ctxt = true; } if(m_curr_packet_in->VMIDUpdated()) { m_pe_context.vmid = m_curr_packet_in->getVMID(); m_pe_context.vmid_valid = 1; m_i_sync_pe_ctxt = true; } m_pe_context.security_level = m_curr_packet_in->getNS() ? ocsd_sec_nonsecure : ocsd_sec_secure; if(m_need_isync || (m_curr_packet_in->iSyncReason() != iSync_Periodic)) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_TRACE_ON); m_output_elem.trace_on_reason = TRACE_ON_NORMAL; if(m_curr_packet_in->iSyncReason() == iSync_TraceRestartAfterOverflow) m_output_elem.trace_on_reason = TRACE_ON_OVERFLOW; else if(m_curr_packet_in->iSyncReason() == iSync_DebugExit) m_output_elem.trace_on_reason = TRACE_ON_EX_DEBUG; if(m_curr_packet_in->hasCC()) m_output_elem.setCycleCount(m_curr_packet_in->getCCVal()); resp = outputTraceElement(m_output_elem); } else { // periodic - no output m_i_sync_pe_ctxt = false; } m_need_isync = false; // got 1st Isync - can continue to process data. m_return_stack.flush(); } if(m_i_sync_pe_ctxt && OCSD_DATA_RESP_IS_CONT(resp)) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); m_output_elem.setContext(m_pe_context); m_output_elem.setISA(m_curr_pe_state.isa); resp = outputTraceElement(m_output_elem); m_i_sync_pe_ctxt = false; } // if wait and still stuff to process.... if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_i_sync_pe_ctxt)) m_curr_state = CONT_ISYNC; return resp; } // change of address and/or exception in program flow. // implies E atom before the branch if none exception. ocsd_datapath_resp_t TrcPktDecodePtm::processBranch() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; // initial pass - decoding packet. if(m_curr_state == DECODE_PKTS) { // specific behviour if this is an exception packet. if(m_curr_packet_in->isBranchExcepPacket()) { // exception - record address and output exception packet. m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION); m_output_elem.exception_number = m_curr_packet_in->excepNum(); m_output_elem.excep_ret_addr = 0; if(m_curr_pe_state.valid) { m_output_elem.excep_ret_addr = 1; m_output_elem.en_addr = m_curr_pe_state.instr_addr; } // could be an associated cycle count if(m_curr_packet_in->hasCC()) m_output_elem.setCycleCount(m_curr_packet_in->getCCVal()); // output the element resp = outputTraceElement(m_output_elem); } else { // branch address only - implies E atom - need to output a range element based on the atom. if(m_curr_pe_state.valid) resp = processAtomRange(ATOM_E,"BranchAddr"); } // now set the branch address for the next time. m_curr_pe_state.isa = m_curr_packet_in->getISA(); m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal(); m_curr_pe_state.valid = true; } // atom range may return with NACC pending checkPendingNacc(resp); // if wait and still stuff to process.... if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending)) m_curr_state = CONT_BRANCH; return resp; } // effectively completes a range prior to exception or after many bytes of trace (>4096) // ocsd_datapath_resp_t TrcPktDecodePtm::processWPUpdate() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; // if we need an address to run from then the WPUpdate will not form a range as // we do not have a start point - still waiting for branch or other address packet if(m_curr_pe_state.valid) { // WP update implies atom - use E, we cannot be sure if the instruction passed its condition codes // - though it doesn't really matter as it is not a branch so cannot change flow. resp = processAtomRange(ATOM_E,"WP update",TRACE_TO_ADDR_INCL,m_curr_packet_in->getAddrVal()); } // atom range may return with NACC pending checkPendingNacc(resp); // if wait and still stuff to process.... if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending)) m_curr_state = CONT_WPUP; return resp; } // a single atom packet can result in multiple range outputs...need to be re-entrant in case we get a wait response. // also need to handle nacc response from instruction walking routine // ocsd_datapath_resp_t TrcPktDecodePtm::processAtom() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; // loop to process all the atoms in the packet while(m_atoms.numAtoms() && m_curr_pe_state.valid && OCSD_DATA_RESP_IS_CONT(resp)) { resp = processAtomRange(m_atoms.getCurrAtomVal(),"atom"); if(!m_curr_pe_state.valid) m_atoms.clearAll(); else m_atoms.clearAtom(); } // bad address may mean a nacc needs sending checkPendingNacc(resp); // if wait and still stuff to process.... if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending || m_atoms.numAtoms())) m_curr_state = CONT_ATOM; return resp; } void TrcPktDecodePtm::checkPendingNacc(ocsd_datapath_resp_t &resp) { if(m_mem_nacc_pending && OCSD_DATA_RESP_IS_CONT(resp)) { m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); m_output_elem.st_addr = m_nacc_addr; resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem); m_mem_nacc_pending = false; } } // given an atom element - walk the code and output a range or mark nacc. ocsd_datapath_resp_t TrcPktDecodePtm::processAtomRange(const ocsd_atm_val A, const char *pkt_msg, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/) { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; bool bWPFound = false; std::ostringstream oss; m_instr_info.instr_addr = m_curr_pe_state.instr_addr; m_instr_info.isa = m_curr_pe_state.isa; ocsd_err_t err = traceInstrToWP(bWPFound,traceWPOp,nextAddrMatch); if(err != OCSD_OK) { if(err == OCSD_ERR_UNSUPPORTED_ISA) { m_curr_pe_state.valid = false; // need a new address packet oss << "Warning: unsupported instruction set processing " << pkt_msg << " packet."; LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_index_curr_pkt,m_CSID,oss.str())); // wait for next address return OCSD_RESP_WARN_CONT; } else { resp = OCSD_RESP_FATAL_INVALID_DATA; oss << "Error processing " << pkt_msg << " packet."; LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_index_curr_pkt,m_CSID,oss.str())); return resp; } } if(bWPFound) { // save recorded next instuction address ocsd_vaddr_t nextAddr = m_instr_info.instr_addr; // action according to waypoint type and atom value switch(m_instr_info.type) { case OCSD_INSTR_BR: if (A == ATOM_E) { m_instr_info.instr_addr = m_instr_info.branch_addr; if (m_instr_info.is_link) m_return_stack.push(nextAddr,m_instr_info.isa); } break; // For PTM -> branch addresses imply E atom, N atom does not need address (return stack will require this) case OCSD_INSTR_BR_INDIRECT: if (A == ATOM_E) { // atom on indirect branch - either implied E from a branch address packet, or return stack if active. // indirect branch taken - need new address -if the current packet is a branch address packet this will be sorted. m_curr_pe_state.valid = false; // if return stack and the incoming packet is an atom. if (m_return_stack.is_active() && (m_curr_packet_in->getType() == PTM_PKT_ATOM)) { // we have an E atom packet and return stack value - set address from return stack m_instr_info.instr_addr = m_return_stack.pop(m_instr_info.next_isa); if (m_return_stack.overflow()) { resp = OCSD_RESP_FATAL_INVALID_DATA; oss << "Return stack error processing " << pkt_msg << " packet."; LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_RET_STACK_OVERFLOW, m_index_curr_pkt, m_CSID, oss.str())); return resp; } else m_curr_pe_state.valid = true; } if(m_instr_info.is_link) m_return_stack.push(nextAddr, m_instr_info.isa); } break; } m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); - m_output_elem.setLastInstrInfo((A == ATOM_E),m_instr_info.type, m_instr_info.sub_type); + m_output_elem.setLastInstrInfo((A == ATOM_E),m_instr_info.type, m_instr_info.sub_type,m_instr_info.instr_size); m_output_elem.setISA(m_curr_pe_state.isa); if(m_curr_packet_in->hasCC()) m_output_elem.setCycleCount(m_curr_packet_in->getCCVal()); + m_output_elem.setLastInstrCond(m_instr_info.is_conditional); resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem); m_curr_pe_state.instr_addr = m_instr_info.instr_addr; m_curr_pe_state.isa = m_instr_info.next_isa; } else { // no waypoint - likely inaccessible memory range. m_curr_pe_state.valid = false; // need an address update if(m_output_elem.st_addr != m_output_elem.en_addr) { // some trace before we were out of memory access range m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); - m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); + m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type,m_instr_info.instr_size); m_output_elem.setISA(m_curr_pe_state.isa); + m_output_elem.setLastInstrCond(m_instr_info.is_conditional); resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem); } } return resp; } ocsd_err_t TrcPktDecodePtm::traceInstrToWP(bool &bWPFound, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/) { uint32_t opcode; uint32_t bytesReq; ocsd_err_t err = OCSD_OK; ocsd_vaddr_t curr_op_address; ocsd_mem_space_acc_t mem_space = (m_pe_context.security_level == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N; m_output_elem.st_addr = m_output_elem.en_addr = m_instr_info.instr_addr; + m_output_elem.num_instr_range = 0; bWPFound = false; while(!bWPFound && !m_mem_nacc_pending) { // start off by reading next opcode; bytesReq = 4; curr_op_address = m_instr_info.instr_addr; // save the start address for the current opcode err = accessMemory(m_instr_info.instr_addr,mem_space,&bytesReq,(uint8_t *)&opcode); if(err != OCSD_OK) break; if(bytesReq == 4) // got data back { m_instr_info.opcode = opcode; err = instrDecode(&m_instr_info); if(err != OCSD_OK) break; // increment address - may be adjusted by direct branch value later m_instr_info.instr_addr += m_instr_info.instr_size; // update the range decoded address in the output packet. m_output_elem.en_addr = m_instr_info.instr_addr; + m_output_elem.num_instr_range++; m_output_elem.last_i_type = m_instr_info.type; // either walking to match the next instruction address or a real waypoint if(traceWPOp != TRACE_WAYPOINT) { if(traceWPOp == TRACE_TO_ADDR_EXCL) bWPFound = (m_output_elem.en_addr == nextAddrMatch); else bWPFound = (curr_op_address == nextAddrMatch); } else bWPFound = (m_instr_info.type != OCSD_INSTR_OTHER); } else { // not enough memory accessible. m_mem_nacc_pending = true; m_nacc_addr = m_instr_info.instr_addr; } } return err; } /* End of File trc_pkt_decode_ptm.cpp */ Index: head/contrib/opencsd/decoder/source/trc_core_arch_map.cpp =================================================================== --- head/contrib/opencsd/decoder/source/trc_core_arch_map.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/trc_core_arch_map.cpp (revision 353393) @@ -1,69 +1,81 @@ /* * \file trc_core_arch_map.cpp * \brief OpenCSD : Map core names to architecture profiles * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common/trc_core_arch_map.h" static struct _ap_map_elements { const char *name; ocsd_arch_profile_t ap; } ap_map_array[] = { + { "Cortex-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 } } }; CoreArchProfileMap::CoreArchProfileMap() { for(unsigned i = 0; i < sizeof(ap_map_array)/sizeof(_ap_map_elements); i++) { core_profiles[ap_map_array[i].name] = ap_map_array[i].ap; } } /* End of File trc_core_arch_map.cpp */ Index: head/contrib/opencsd/decoder/source/trc_frame_deformatter.cpp =================================================================== --- head/contrib/opencsd/decoder/source/trc_frame_deformatter.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/trc_frame_deformatter.cpp (revision 353393) @@ -1,856 +1,869 @@ /* * \file trc_frame_deformatter.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "common/trc_frame_deformatter.h" #include "trc_frame_deformatter_impl.h" /***************************************************************/ /* Implementation */ /***************************************************************/ #ifdef __GNUC__ // G++ doesn't like the ## pasting #define DEFORMATTER_NAME "DFMT_CSFRAMES" #else // VC is fine #define DEFORMATTER_NAME OCSD_CMPNAME_PREFIX_FRAMEDEFORMATTER##"_CSFRAMES" #endif TraceFmtDcdImpl::TraceFmtDcdImpl() : TraceComponent(DEFORMATTER_NAME), m_cfgFlags(0), m_force_sync_idx(0), m_use_force_sync(false), m_alignment(16), // assume frame aligned data as default. m_b_output_packed_raw(false), m_b_output_unpacked_raw(false) { resetStateParams(); setRawChanFilterAll(true); } TraceFmtDcdImpl::TraceFmtDcdImpl(int instNum) : TraceComponent(DEFORMATTER_NAME, instNum), m_cfgFlags(0), m_force_sync_idx(0), m_use_force_sync(false), m_alignment(16) { resetStateParams(); setRawChanFilterAll(true); } TraceFmtDcdImpl::~TraceFmtDcdImpl() { } ocsd_datapath_resp_t TraceFmtDcdImpl::TraceDataIn( const ocsd_datapath_op_t op, const ocsd_trc_index_t index, const uint32_t dataBlockSize, const uint8_t *pDataBlock, uint32_t *numBytesProcessed) { ocsd_datapath_resp_t resp = OCSD_RESP_FATAL_INVALID_OP; InitCollateDataPathResp(); m_b_output_packed_raw = m_RawTraceFrame.num_attached() && ((m_cfgFlags & OCSD_DFRMTR_PACKED_RAW_OUT) != 0); m_b_output_unpacked_raw = m_RawTraceFrame.num_attached() && ((m_cfgFlags & OCSD_DFRMTR_UNPACKED_RAW_OUT) != 0); switch(op) { case OCSD_OP_RESET: resp = Reset(); break; case OCSD_OP_FLUSH: resp = Flush(); break; case OCSD_OP_EOT: // local 'flush' here? // pass on EOT to connected ID streams resp = executeNoneDataOpAllIDs(OCSD_OP_EOT); break; case OCSD_OP_DATA: if((dataBlockSize <= 0) || ( pDataBlock == 0) || (numBytesProcessed == 0)) resp = OCSD_RESP_FATAL_INVALID_PARAM; else resp = processTraceData(index,dataBlockSize, pDataBlock, numBytesProcessed); break; default: break; } return resp; } /* enable / disable ID streams - default as all enabled */ ocsd_err_t TraceFmtDcdImpl::OutputFilterIDs(std::vector &id_list, bool bEnable) { ocsd_err_t err = OCSD_OK; std::vector::iterator iter = id_list.begin(); uint8_t id = 0; while((iter < id_list.end()) && (err == OCSD_OK)) { id = *iter; if(id > 128) err = OCSD_ERR_INVALID_ID; else { m_IDStreams[id].set_enabled(bEnable); m_raw_chan_enable[id] = bEnable; } iter++; } return err; } ocsd_err_t TraceFmtDcdImpl::OutputFilterAllIDs(bool bEnable) { for(uint8_t id = 0; id < 128; id++) { m_IDStreams[id].set_enabled(bEnable); } setRawChanFilterAll(bEnable); return OCSD_OK; } void TraceFmtDcdImpl::setRawChanFilterAll(bool bEnable) { for(int i=0; i<128; i++) { m_raw_chan_enable[i] = bEnable; } } const bool TraceFmtDcdImpl::rawChanEnabled(const uint8_t id) const { if(id < 128) return m_raw_chan_enable[id]; return false; } /* decode control */ ocsd_datapath_resp_t TraceFmtDcdImpl::Reset() { resetStateParams(); InitCollateDataPathResp(); return executeNoneDataOpAllIDs(OCSD_OP_RESET); } ocsd_datapath_resp_t TraceFmtDcdImpl::Flush() { executeNoneDataOpAllIDs(OCSD_OP_FLUSH); // flush any upstream data. if(dataPathCont()) outputFrame(); // try to flush any partial frame data remaining return highestDataPathResp(); } ocsd_datapath_resp_t TraceFmtDcdImpl::executeNoneDataOpAllIDs(ocsd_datapath_op_t op, const ocsd_trc_index_t index /* = 0*/) { ITrcDataIn *pTrcComp = 0; for(uint8_t id = 0; id < 128; id++) { if(m_IDStreams[id].num_attached()) { pTrcComp = m_IDStreams[id].first(); while(pTrcComp) { CollateDataPathResp(pTrcComp->TraceDataIn(op,index,0,0,0)); pTrcComp = m_IDStreams[id].next(); } } } if( m_RawTraceFrame.num_attached()) { if(m_RawTraceFrame.first()) m_RawTraceFrame.first()->TraceRawFrameIn(op,0,OCSD_FRM_NONE,0,0,0); } return highestDataPathResp(); } void TraceFmtDcdImpl::outputRawMonBytes(const ocsd_datapath_op_t op, const ocsd_trc_index_t index, const ocsd_rawframe_elem_t frame_element, const int dataBlockSize, const uint8_t *pDataBlock, const uint8_t traceID) { if( m_RawTraceFrame.num_attached()) { if(m_RawTraceFrame.first()) m_RawTraceFrame.first()->TraceRawFrameIn(op,index,frame_element,dataBlockSize, pDataBlock,traceID); } } void TraceFmtDcdImpl::CollateDataPathResp(const ocsd_datapath_resp_t resp) { // simple most severe error across multiple IDs. if(resp > m_highestResp) m_highestResp = resp; } ocsd_datapath_resp_t TraceFmtDcdImpl::processTraceData( const ocsd_trc_index_t index, const uint32_t dataBlockSize, const uint8_t *pDataBlock, uint32_t *numBytesProcessed ) { try { if(!m_first_data) // is this the initial data block? { m_trc_curr_idx = index; } else { if(m_trc_curr_idx != index) // none continuous trace data - throw an error. throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_DFMTR_NOTCONTTRACE,index); } if(dataBlockSize % m_alignment) // must be correctly aligned data { ocsdError err(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PARAM_VAL); char msg_buffer[64]; sprintf(msg_buffer,"Input block incorrect size, must be %d byte multiple", m_alignment); err.setMessage(msg_buffer); throw ocsdError(&err); } // record the incoming block for extraction routines to use. m_in_block_base = pDataBlock; m_in_block_size = dataBlockSize; m_in_block_processed = 0; // processing loop... if(checkForSync()) { bool bProcessing = true; while(bProcessing) { bProcessing = extractFrame(); // will stop on end of input data. if(bProcessing) bProcessing = unpackFrame(); if(bProcessing) bProcessing = outputFrame(); // will stop on data path halt. } } } catch(const ocsdError &err) { LogError(err); CollateDataPathResp(OCSD_RESP_FATAL_INVALID_DATA); } catch(...) { LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_FAIL)); CollateDataPathResp(OCSD_RESP_FATAL_SYS_ERR); } if(!m_first_data) m_first_data = true; // update the outputs. *numBytesProcessed = m_in_block_processed; return highestDataPathResp(); } ocsd_err_t TraceFmtDcdImpl::DecodeConfigure(uint32_t flags) { const char *pszErrMsg = ""; ocsd_err_t err = OCSD_OK; if((flags & ~OCSD_DFRMTR_VALID_MASK) != 0) { err = OCSD_ERR_INVALID_PARAM_VAL; pszErrMsg = "Unknown Config Flags"; } if((flags & OCSD_DFRMTR_VALID_MASK) == 0) { err = OCSD_ERR_INVALID_PARAM_VAL; pszErrMsg = "No Config Flags Set"; } if((flags & (OCSD_DFRMTR_HAS_FSYNCS | OCSD_DFRMTR_HAS_HSYNCS)) && (flags & OCSD_DFRMTR_FRAME_MEM_ALIGN) ) { err = OCSD_ERR_INVALID_PARAM_VAL; pszErrMsg = "Invalid Config Flag Combination Set"; } if(err != OCSD_OK) { ocsdError errObj(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL); errObj.setMessage(pszErrMsg); LogError(errObj); } else { m_cfgFlags = flags; m_alignment = 16; if(flags & OCSD_DFRMTR_HAS_FSYNCS) m_alignment = 4; else if(flags & OCSD_DFRMTR_HAS_HSYNCS) m_alignment = 2; } return err; } void TraceFmtDcdImpl::resetStateParams() { // overall dynamic state - intra frame m_trc_curr_idx = OCSD_BAD_TRC_INDEX; /* source index of current trace data */ m_frame_synced = false; m_first_data = false; m_curr_src_ID = OCSD_BAD_CS_SRC_ID; // current frame processing m_ex_frm_n_bytes = 0; m_trc_curr_idx_sof = OCSD_BAD_TRC_INDEX; } bool TraceFmtDcdImpl::checkForSync() { // we can sync on:- // 16 byte alignment - standard input buffers such as ETB // FSYNC packets in the stream // forced index programmed into the object. uint32_t unsynced_bytes = 0; if(!m_frame_synced) { if(m_use_force_sync) { // is the force sync point in this block? if((m_force_sync_idx >= m_trc_curr_idx) && (m_force_sync_idx < (m_trc_curr_idx + m_in_block_size))) { unsynced_bytes = m_force_sync_idx - m_trc_curr_idx; m_frame_synced = true; } else { unsynced_bytes = m_in_block_size; } } else if( m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) // memory aligned data { unsynced_bytes = findfirstFSync(); } else { // OCSD_DFRMTR_FRAME_MEM_ALIGN - this has guaranteed 16 byte frame size and alignment. m_frame_synced = true; } if(unsynced_bytes) { outputUnsyncedBytes(unsynced_bytes); m_in_block_processed = unsynced_bytes; m_trc_curr_idx += unsynced_bytes; } } return m_frame_synced; } uint32_t TraceFmtDcdImpl::findfirstFSync() { - uint32_t unsynced = m_in_block_size; // consider entire block as unsynced at present. - //**TBD - handle fsync patterns in TPIU captured code - return unsynced; + 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() { const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC bool check_for_fsync = true; int num_fsyncs = 0; const uint8_t *dataPtr = m_in_block_base + m_in_block_processed; while (check_for_fsync && (m_in_block_processed < m_in_block_size)) { // look for consecutive fsyncs as padding or for reset downstream - both cases will reset downstream.... if (*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) { dataPtr += sizeof(uint32_t); num_fsyncs++; } else check_for_fsync = false; } if (num_fsyncs) { printf("Frame deformatter: Found %d FSYNCS\n",num_fsyncs); if ((num_fsyncs % 4) == 0) { // reset the upstream decoders executeNoneDataOpAllIDs(OCSD_OP_RESET,m_trc_curr_idx); // reset the intra frame parameters m_curr_src_ID = OCSD_BAD_CS_SRC_ID; m_ex_frm_n_bytes = 0; m_trc_curr_idx_sof = OCSD_BAD_TRC_INDEX; } else { // TBD: throw processing error, none frame size block of fsyncs } } return num_fsyncs * 4; } bool TraceFmtDcdImpl::extractFrame() { const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC const uint16_t HSYNC_PATTERN = 0x7FFF; // LE host pattern for HSYNC bool cont_process = true; // continue processing after extraction. uint32_t f_sync_bytes = 0; // skipped f sync bytes uint32_t h_sync_bytes = 0; // skipped h sync bytes - uint32_t ex_bytes = 0; // extracted bytes + uint32_t ex_bytes = 0; // extracted this pass (may be filling out part frame) // memory aligned sources are always multiples of frames, aligned to start. if( m_cfgFlags & OCSD_DFRMTR_FRAME_MEM_ALIGN) { // some linux drivers (e.g. for perf) will insert FSYNCS to pad or differentiate // between blocks of aligned data, always in frame aligned complete 16 byte frames. if (m_cfgFlags & OCSD_DFRMTR_RESET_ON_4X_FSYNC) { f_sync_bytes = checkForResetFSyncPatterns(); /* in this case the FSYNC pattern is output on both packed and unpacked cases */ if (f_sync_bytes && (m_b_output_packed_raw || m_b_output_unpacked_raw)) { outputRawMonBytes(OCSD_OP_DATA, m_trc_curr_idx, OCSD_FRM_FSYNC, f_sync_bytes, m_in_block_base + m_in_block_processed, 0); } } if((m_in_block_processed+f_sync_bytes) == m_in_block_size) { m_ex_frm_n_bytes = 0; cont_process = false; // end of input data. } else { // always a complete frame. m_ex_frm_n_bytes = OCSD_DFRMTR_FRAME_SIZE; memcpy(m_ex_frm_data, m_in_block_base + m_in_block_processed + f_sync_bytes, m_ex_frm_n_bytes); m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; ex_bytes = OCSD_DFRMTR_FRAME_SIZE; } } else { // extract data accounting for frame syncs and hsyncs if present. // we know we are aligned at this point - could be FSYNC or HSYNCs here. // check what we a looking for bool hasFSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) == OCSD_DFRMTR_HAS_FSYNCS); bool hasHSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_HSYNCS) == OCSD_DFRMTR_HAS_HSYNCS); const uint8_t *dataPtr = m_in_block_base+m_in_block_processed; const uint8_t *eodPtr = m_in_block_base+m_in_block_size; cont_process = (bool)(dataPtr < eodPtr); // can have FSYNCS at start of frame (in middle is an error). if(hasFSyncs && cont_process && (m_ex_frm_n_bytes == 0)) { while((*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) && cont_process) { f_sync_bytes += 4; dataPtr += 4; cont_process = (bool)(dataPtr < eodPtr); - - // TBD: output raw FSYNC data on raw frame channel. } } // not an FSYNC while((m_ex_frm_n_bytes < OCSD_DFRMTR_FRAME_SIZE) && cont_process) { // check for illegal out of sequence FSYNC if((m_ex_frm_n_bytes % 4) == 0) { if(*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) { // throw an illegal FSYNC error + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC in frame."); } } // mark start of frame after FSyncs if(m_ex_frm_n_bytes == 0) m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; m_ex_frm_data[m_ex_frm_n_bytes] = dataPtr[0]; m_ex_frm_data[m_ex_frm_n_bytes+1] = dataPtr[1]; m_ex_frm_n_bytes+=2; ex_bytes +=2; // check pair is not HSYNC if(*((uint16_t *)(dataPtr)) == HSYNC_PATTERN) { if(hasHSyncs) { m_ex_frm_n_bytes-=2; ex_bytes -= 2; h_sync_bytes+=2; - - // TBD: output raw HSYNC data on raw frame channel. } else { // throw illegal HSYNC error. + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad HSYNC in frame."); } } 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) && m_b_output_packed_raw) + if (((m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE) || !cont_process) && m_b_output_packed_raw) { outputRawMonBytes( OCSD_OP_DATA, m_trc_curr_idx, OCSD_FRM_PACKED, - ex_bytes + f_sync_bytes + h_sync_bytes, + total_processed, m_in_block_base+m_in_block_processed, 0); } // update the processed count for the buffer - m_in_block_processed += m_ex_frm_n_bytes + f_sync_bytes + h_sync_bytes; + m_in_block_processed += total_processed; // update index past the processed data - m_trc_curr_idx += m_ex_frm_n_bytes + f_sync_bytes + h_sync_bytes; + m_trc_curr_idx += total_processed; return cont_process; } bool TraceFmtDcdImpl::unpackFrame() { // unpack cannot fail as never called on incomplete frame. uint8_t frameFlagBit = 0x1; uint8_t newSrcID = OCSD_BAD_CS_SRC_ID; bool PrevIDandIDChange = false; // init output processing m_out_data_idx = 0; m_out_processed = 0; // set up first out data packet... m_out_data[m_out_data_idx].id = m_curr_src_ID; m_out_data[m_out_data_idx].valid = 0; m_out_data[m_out_data_idx].index = m_trc_curr_idx_sof; m_out_data[m_out_data_idx].used = 0; // work on byte pairs - bytes 0 - 13. for(int i = 0; i < 14; i+=2) { PrevIDandIDChange = false; // it's an ID + data if(m_ex_frm_data[i] & 0x1) { newSrcID = (m_ex_frm_data[i] >> 1) & 0x7f; if(newSrcID != m_curr_src_ID) // ID change { PrevIDandIDChange = ((frameFlagBit & m_ex_frm_data[15]) != 0); // following byte for old id? if(PrevIDandIDChange) // 2nd byte always data m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i+1]; // change ID m_curr_src_ID = newSrcID; // if we already have data in this buffer if(m_out_data[m_out_data_idx].valid > 0) { m_out_data_idx++; // move to next buffer m_out_data[m_out_data_idx].valid = 0; m_out_data[m_out_data_idx].used = 0; m_out_data[m_out_data_idx].index = m_trc_curr_idx_sof + i; } // set new ID on buffer m_out_data[m_out_data_idx].id = m_curr_src_ID; /// TBD - ID indexing in here. } } else // it's just data { m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0); } // 2nd byte always data if(!PrevIDandIDChange) // output only if we didn't for an ID change + prev ID. m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i+1]; frameFlagBit <<= 1; } // unpack byte 14; // it's an ID if(m_ex_frm_data[14] & 0x1) { // no matter if change or not, no associated data in byte 15 anyway so just set. m_curr_src_ID = (m_ex_frm_data[14] >> 1) & 0x7f; } // it's data else { m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[14] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0); } m_ex_frm_n_bytes = 0; // mark frame as empty; return true; } // output data to channels. bool TraceFmtDcdImpl::outputFrame() { bool cont_processing = true; ITrcDataIn *pDataIn = 0; uint32_t bytes_used; // output each valid ID within the frame - stopping if we get a wait or error while((m_out_processed < (m_out_data_idx + 1)) && cont_processing) { // may have data prior to a valid ID appearing if(m_out_data[m_out_processed].id != OCSD_BAD_CS_SRC_ID) { if((pDataIn = m_IDStreams[m_out_data[m_out_processed].id].first()) != 0) { // log the stuff we are about to put out early so as to make it visible before interpretation // however, don't re-output if only part used first time round. if(m_b_output_unpacked_raw && (m_out_data[m_out_processed].used == 0) && rawChanEnabled( m_out_data[m_out_processed].id)) { outputRawMonBytes( OCSD_OP_DATA, m_out_data[m_out_processed].index, OCSD_FRM_ID_DATA, m_out_data[m_out_processed].valid, m_out_data[m_out_processed].data, m_out_data[m_out_processed].id); } // output to the connected packet process CollateDataPathResp(pDataIn->TraceDataIn(OCSD_OP_DATA, m_out_data[m_out_processed].index + m_out_data[m_out_processed].used, m_out_data[m_out_processed].valid - m_out_data[m_out_processed].used, m_out_data[m_out_processed].data + m_out_data[m_out_processed].used, &bytes_used)); if(!dataPathCont()) { cont_processing = false; m_out_data[m_out_processed].used += bytes_used; if(m_out_data[m_out_processed].used == m_out_data[m_out_processed].valid) m_out_processed++; // we have used up all this data. } else { m_out_processed++; // we have sent this data; } } else { // optional raw output for debugging / monitor tools if(m_b_output_unpacked_raw && rawChanEnabled( m_out_data[m_out_processed].id)) { outputRawMonBytes( OCSD_OP_DATA, m_out_data[m_out_processed].index, OCSD_FRM_ID_DATA, m_out_data[m_out_processed].valid, m_out_data[m_out_processed].data, m_out_data[m_out_processed].id); } m_out_processed++; // skip past this data. } } else { // optional raw output for debugging / monitor tools of unknown src ID data if(m_b_output_unpacked_raw) { outputRawMonBytes( OCSD_OP_DATA, m_out_data[m_out_processed].index, OCSD_FRM_ID_DATA, m_out_data[m_out_processed].valid, m_out_data[m_out_processed].data, m_out_data[m_out_processed].id); } m_out_processed++; // skip past this data. } } return cont_processing; } /***************************************************************/ /* interface */ /***************************************************************/ TraceFormatterFrameDecoder::TraceFormatterFrameDecoder() : m_pDecoder(0) { m_instNum = -1; } TraceFormatterFrameDecoder::TraceFormatterFrameDecoder(int instNum) : m_pDecoder(0) { m_instNum = instNum; } TraceFormatterFrameDecoder::~TraceFormatterFrameDecoder() { if(m_pDecoder) { delete m_pDecoder; m_pDecoder = 0; } } /* the data input interface from the reader / source */ ocsd_datapath_resp_t TraceFormatterFrameDecoder::TraceDataIn( const ocsd_datapath_op_t op, const ocsd_trc_index_t index, const uint32_t dataBlockSize, const uint8_t *pDataBlock, uint32_t *numBytesProcessed) { return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed); } /* attach a data processor to a stream ID output */ componentAttachPt *TraceFormatterFrameDecoder::getIDStreamAttachPt(uint8_t ID) { componentAttachPt *pAttachPt = 0; if((ID < 128) && (m_pDecoder != 0)) pAttachPt = &(m_pDecoder->m_IDStreams[ID]); return pAttachPt; } /* attach a data processor to the raw frame output */ componentAttachPt *TraceFormatterFrameDecoder::getTrcRawFrameAttachPt() { return (m_pDecoder != 0) ? &m_pDecoder->m_RawTraceFrame : 0; } componentAttachPt *TraceFormatterFrameDecoder::getTrcSrcIndexAttachPt() { return (m_pDecoder != 0) ? &m_pDecoder->m_SrcIndexer : 0; } componentAttachPt *TraceFormatterFrameDecoder::getErrLogAttachPt() { return (m_pDecoder != 0) ? m_pDecoder->getErrorLogAttachPt() : 0; } /* configuration - set operational mode for incoming stream (has FSYNCS etc) */ ocsd_err_t TraceFormatterFrameDecoder::Configure(uint32_t cfg_flags) { if(!m_pDecoder) { if(m_instNum >= 0) m_pDecoder = new (std::nothrow) TraceFmtDcdImpl(m_instNum); else m_pDecoder = new (std::nothrow) TraceFmtDcdImpl(); if(!m_pDecoder) return OCSD_ERR_MEM; } - m_pDecoder->m_cfgFlags = cfg_flags; + m_pDecoder->DecodeConfigure(cfg_flags); return OCSD_OK; } const uint32_t TraceFormatterFrameDecoder::getConfigFlags() const { uint32_t flags = 0; if(m_pDecoder) flags = m_pDecoder->m_cfgFlags; return flags; } /* enable / disable ID streams - default as all enabled */ ocsd_err_t TraceFormatterFrameDecoder::OutputFilterIDs(std::vector &id_list, bool bEnable) { return (m_pDecoder == 0) ? OCSD_ERR_NOT_INIT : m_pDecoder->OutputFilterIDs(id_list,bEnable); } ocsd_err_t TraceFormatterFrameDecoder::OutputFilterAllIDs(bool bEnable) { return (m_pDecoder == 0) ? OCSD_ERR_NOT_INIT : m_pDecoder->OutputFilterAllIDs(bEnable); } /* decode control */ ocsd_datapath_resp_t TraceFormatterFrameDecoder::Reset() { return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Reset(); } ocsd_datapath_resp_t TraceFormatterFrameDecoder::Flush() { return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Flush(); } /* End of File trc_frame_deformatter.cpp */ Index: head/contrib/opencsd/decoder/source/trc_gen_elem.cpp =================================================================== --- head/contrib/opencsd/decoder/source/trc_gen_elem.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/trc_gen_elem.cpp (revision 353393) @@ -1,242 +1,259 @@ /* * \file trc_gen_elem.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common/trc_gen_elem.h" #include #include #include static const char *s_elem_descs[][2] = { {"OCSD_GEN_TRC_ELEM_UNKNOWN","Unknown trace element - default value or indicate error in stream to client."}, {"OCSD_GEN_TRC_ELEM_NO_SYNC","Waiting for sync - either at start of decode, or after overflow / bad packet"}, {"OCSD_GEN_TRC_ELEM_TRACE_ON","Start of trace - beginning of elements or restart after discontinuity (overflow, trace filtering)."}, {"OCSD_GEN_TRC_ELEM_EO_TRACE","End of the available trace in the buffer."}, {"OCSD_GEN_TRC_ELEM_PE_CONTEXT","PE status update / change (arch, ctxtid, vmid etc)."}, {"OCSD_GEN_TRC_ELEM_INSTR_RANGE","Traced N consecutive instructions from addr (no intervening events or data elements), may have data assoc key"}, {"OCSD_GEN_TRC_ELEM_ADDR_NACC","Tracing in inaccessible memory area."}, {"OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN","Tracing unknown address area."}, {"OCSD_GEN_TRC_ELEM_EXCEPTION","Exception"}, - {"OCSD_GEN_TRC_ELEM_EXCEPTION_RET","Expection return"}, + {"OCSD_GEN_TRC_ELEM_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_CUSTOM","Fully custom packet type."} }; static const char *instr_type[] = { "--- ", "BR ", "iBR ", "ISB ", "DSB.DMB" }; #define T_SIZE (sizeof(instr_type) / sizeof(const char *)) static const char *instr_sub_type[] = { "--- ", "b+link ", "A64:ret ", - "A64:eret " + "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 */ }; void OcsdTraceElement::toString(std::string &str) const { std::ostringstream oss; int num_str = ((sizeof(s_elem_descs) / sizeof(const char *)) / 2); int typeIdx = (int)this->elem_type; if(typeIdx < num_str) { oss << s_elem_descs[typeIdx][0] << "("; switch(elem_type) { case OCSD_GEN_TRC_ELEM_INSTR_RANGE: oss << "exec range=0x" << std::hex << st_addr << ":[0x" << en_addr << "] "; + oss << "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_EXCEPTION: - if(excep_ret_addr == 1) + if (excep_ret_addr == 1) { - oss << "pref ret addr:0x" << std::hex << en_addr << "; "; + 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; "); 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; 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 */ Index: head/contrib/opencsd/decoder/source/trc_printable_elem.cpp =================================================================== --- head/contrib/opencsd/decoder/source/trc_printable_elem.cpp (revision 353392) +++ head/contrib/opencsd/decoder/source/trc_printable_elem.cpp (revision 353393) @@ -1,120 +1,123 @@ /* * \file trc_printable_elem.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common/trc_printable_elem.h" #include #include #if defined(_MSC_VER) && (_MSC_VER < 1900) /** VS2010 does not support inttypes - remove when VS2010 support is dropped */ #define __PRI64_PREFIX "ll" #define PRIX64 __PRI64_PREFIX "X" #define PRIu64 __PRI64_PREFIX "u" #define PRIu32 "u" #else #include #endif void trcPrintableElem::getValStr(std::string &valStr, const int valTotalBitSize, const int valValidBits, const uint64_t value, const bool asHex /* = true*/, const int updateBits /* = 0*/) { static char szStrBuffer[128]; static char szFormatBuffer[32]; assert((valTotalBitSize >= 4) && (valTotalBitSize <= 64)); uint64_t LimitMask = ~0ULL; LimitMask >>= 64-valTotalBitSize; valStr = "0x"; if(asHex) { int numHexChars = valTotalBitSize / 4; numHexChars += ((valTotalBitSize % 4) > 0) ? 1 : 0; int validChars = valValidBits / 4; if((valValidBits % 4) > 0) validChars++; - int QM = numHexChars - validChars; - while(QM) - { - QM--; - valStr += "?"; - } + if (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 */ Index: head/lib/libopencsd/Makefile =================================================================== --- head/lib/libopencsd/Makefile (revision 353392) +++ head/lib/libopencsd/Makefile (revision 353393) @@ -1,175 +1,176 @@ # $FreeBSD$ PACKAGE=lib${LIB} SHLIBDIR?= /lib .include OPENCSDSRC= ${SRCTOP}/contrib/opencsd .PATH: ${OPENCSDSRC}/decoder/source/etmv4/ \ ${OPENCSDSRC}/decoder/source/etmv3/ \ ${OPENCSDSRC}/decoder/source/pkt_printers/ \ ${OPENCSDSRC}/decoder/source/mem_acc/ \ ${OPENCSDSRC}/decoder/source/i_dec/ \ ${OPENCSDSRC}/decoder/source/c_api/ \ ${OPENCSDSRC}/decoder/source/ptm/ \ ${OPENCSDSRC}/decoder/source/stm/ \ ${OPENCSDSRC}/decoder/source/ \ ${OPENCSDSRC}/decoder/include/opencsd/etmv4/ \ ${OPENCSDSRC}/decoder/include/opencsd/etmv3/ \ ${OPENCSDSRC}/decoder/include/opencsd/stm/ \ ${OPENCSDSRC}/decoder/include/opencsd/ptm/ \ ${OPENCSDSRC}/decoder/include/opencsd/c_api/ \ ${OPENCSDSRC}/decoder/include/opencsd/ \ ${OPENCSDSRC}/decoder/include LIB= opencsd SHLIB_MAJOR=0 # ETMv3 SRCS= \ trc_cmp_cfg_etmv3.cpp \ trc_pkt_decode_etmv3.cpp \ trc_pkt_elem_etmv3.cpp \ trc_pkt_proc_etmv3.cpp \ trc_pkt_proc_etmv3_impl.cpp # ETMv4 SRCS+= \ trc_cmp_cfg_etmv4.cpp \ trc_etmv4_stack_elem.cpp \ trc_pkt_decode_etmv4i.cpp \ trc_pkt_elem_etmv4d.cpp \ trc_pkt_elem_etmv4i.cpp \ trc_pkt_proc_etmv4.cpp \ trc_pkt_proc_etmv4i_impl.cpp # PKT_PRINTERS SRCS+= \ raw_frame_printer.cpp \ trc_print_fact.cpp # PTM SRCS+= \ trc_cmp_cfg_ptm.cpp \ trc_pkt_decode_ptm.cpp \ trc_pkt_elem_ptm.cpp \ trc_pkt_proc_ptm.cpp # STM SRCS+= \ trc_pkt_decode_stm.cpp \ trc_pkt_elem_stm.cpp \ trc_pkt_proc_stm.cpp # C_API SRCS+= \ ocsd_c_api_custom_obj.cpp \ ocsd_c_api.cpp # SRC SRCS+= \ ocsd_code_follower.cpp \ ocsd_dcd_tree.cpp \ ocsd_error.cpp \ ocsd_error_logger.cpp \ ocsd_gen_elem_list.cpp \ ocsd_lib_dcd_register.cpp \ ocsd_msg_logger.cpp \ ocsd_version.cpp \ trc_component.cpp \ trc_core_arch_map.cpp \ trc_frame_deformatter.cpp \ trc_gen_elem.cpp \ trc_printable_elem.cpp \ trc_ret_stack.cpp # MEM_ACC SRCS+= \ trc_mem_acc_base.cpp \ + trc_mem_acc_cache.cpp \ trc_mem_acc_cb.cpp \ trc_mem_acc_mapper.cpp \ trc_mem_acc_bufptr.cpp \ trc_mem_acc_file.cpp # I_DEC SRCS+= \ trc_i_decode.cpp \ trc_idec_arminst.cpp CFLAGS+= \ -I${OPENCSDSRC}/decoder/include/ \ -I${.CURDIR} INCS= \ ocsd_if_types.h \ trc_gen_elem_types.h \ trc_pkt_types.h INCSDIR=${INCLUDEDIR}/opencsd APIINCS= \ ocsd_c_api_cust_fact.h \ ocsd_c_api_cust_impl.h \ ocsd_c_api_custom.h \ ocsd_c_api_types.h \ opencsd_c_api.h APIINCSDIR=${INCLUDEDIR}/opencsd/c_api/ ETMV4INCS= \ etmv4_decoder.h \ trc_cmp_cfg_etmv4.h \ trc_dcd_mngr_etmv4i.h \ trc_etmv4_stack_elem.h \ trc_pkt_decode_etmv4i.h \ trc_pkt_elem_etmv4d.h \ trc_pkt_elem_etmv4i.h \ trc_pkt_proc_etmv4.h \ trc_pkt_types_etmv4.h ETMV4INCSDIR=${INCLUDEDIR}/opencsd/etmv4/ ETMV3INCS= \ etmv3_decoder.h \ trc_cmp_cfg_etmv3.h \ trc_dcd_mngr_etmv3.h \ trc_pkt_decode_etmv3.h \ trc_pkt_elem_etmv3.h \ trc_pkt_proc_etmv3.h \ trc_pkt_types_etmv3.h ETMV3INCSDIR=${INCLUDEDIR}/opencsd/etmv3/ PTMINCS= \ ptm_decoder.h \ trc_cmp_cfg_ptm.h \ trc_dcd_mngr_ptm.h \ trc_pkt_decode_ptm.h \ trc_pkt_elem_ptm.h \ trc_pkt_proc_ptm.h \ trc_pkt_types_ptm.h PTMINCSDIR=${INCLUDEDIR}/opencsd/ptm/ STMINCS= \ stm_decoder.h \ trc_cmp_cfg_stm.h \ trc_dcd_mngr_stm.h \ trc_pkt_decode_stm.h \ trc_pkt_elem_stm.h \ trc_pkt_proc_stm.h \ trc_pkt_types_stm.h STMINCSDIR=${INCLUDEDIR}/opencsd/stm/ INCSGROUPS=INCS APIINCS ETMV3INCS ETMV4INCS PTMINCS STMINCS LIBADD= cxxrt WARNS?= 1 HAS_TESTS= .include