summaryrefslogtreecommitdiffstats
path: root/decoder/source
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--decoder/source/c_api/ocsd_c_api.cpp632
-rw-r--r--decoder/source/c_api/ocsd_c_api_custom_obj.cpp431
-rw-r--r--decoder/source/c_api/ocsd_c_api_custom_obj.h189
-rw-r--r--decoder/source/c_api/ocsd_c_api_obj.h182
-rw-r--r--decoder/source/ete/trc_cmp_cfg_ete.cpp98
-rw-r--r--decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp65
-rw-r--r--decoder/source/etmv3/trc_pkt_decode_etmv3.cpp681
-rw-r--r--decoder/source/etmv3/trc_pkt_elem_etmv3.cpp688
-rw-r--r--decoder/source/etmv3/trc_pkt_proc_etmv3.cpp122
-rw-r--r--decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp1224
-rw-r--r--decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h175
-rw-r--r--decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp111
-rw-r--r--decoder/source/etmv4/trc_etmv4_stack_elem.cpp178
-rw-r--r--decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp1957
-rw-r--r--decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp754
-rw-r--r--decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp1778
-rw-r--r--decoder/source/i_dec/trc_i_decode.cpp236
-rw-r--r--decoder/source/i_dec/trc_idec_arminst.cpp679
-rw-r--r--decoder/source/mem_acc/trc_mem_acc_base.cpp148
-rw-r--r--decoder/source/mem_acc/trc_mem_acc_bufptr.cpp53
-rw-r--r--decoder/source/mem_acc/trc_mem_acc_cache.cpp176
-rw-r--r--decoder/source/mem_acc/trc_mem_acc_cb.cpp34
-rw-r--r--decoder/source/mem_acc/trc_mem_acc_file.cpp391
-rw-r--r--decoder/source/mem_acc/trc_mem_acc_mapper.cpp307
-rw-r--r--decoder/source/ocsd_code_follower.cpp162
-rw-r--r--decoder/source/ocsd_dcd_tree.cpp785
-rw-r--r--decoder/source/ocsd_error.cpp253
-rw-r--r--decoder/source/ocsd_error_logger.cpp159
-rw-r--r--decoder/source/ocsd_gen_elem_list.cpp168
-rw-r--r--decoder/source/ocsd_gen_elem_stack.cpp197
-rw-r--r--decoder/source/ocsd_lib_dcd_register.cpp216
-rw-r--r--decoder/source/ocsd_msg_logger.cpp120
-rw-r--r--decoder/source/ocsd_version.cpp48
-rw-r--r--decoder/source/pkt_printers/raw_frame_printer.cpp104
-rw-r--r--decoder/source/pkt_printers/trc_print_fact.cpp124
-rw-r--r--decoder/source/ptm/trc_cmp_cfg_ptm.cpp59
-rw-r--r--decoder/source/ptm/trc_pkt_decode_ptm.cpp671
-rw-r--r--decoder/source/ptm/trc_pkt_elem_ptm.cpp473
-rw-r--r--decoder/source/ptm/trc_pkt_proc_ptm.cpp1218
-rw-r--r--decoder/source/stm/trc_pkt_decode_stm.cpp303
-rw-r--r--decoder/source/stm/trc_pkt_elem_stm.cpp314
-rw-r--r--decoder/source/stm/trc_pkt_proc_stm.cpp1043
-rw-r--r--decoder/source/trc_component.cpp155
-rw-r--r--decoder/source/trc_core_arch_map.cpp177
-rw-r--r--decoder/source/trc_frame_deformatter.cpp970
-rw-r--r--decoder/source/trc_frame_deformatter_impl.h185
-rw-r--r--decoder/source/trc_gen_elem.cpp311
-rw-r--r--decoder/source/trc_printable_elem.cpp121
-rw-r--r--decoder/source/trc_ret_stack.cpp149
49 files changed, 19774 insertions, 0 deletions
diff --git a/decoder/source/c_api/ocsd_c_api.cpp b/decoder/source/c_api/ocsd_c_api.cpp
new file mode 100644
index 0000000..750c847
--- /dev/null
+++ b/decoder/source/c_api/ocsd_c_api.cpp
@@ -0,0 +1,632 @@
+/*
+ * \file ocsd_c_api.cpp
+ * \brief OpenCSD : "C" API libary implementation.
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cstring>
+
+/* 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 <new>
+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<ITrcTypedBase *> cb_objs;
+ DefLogStrCBObj s_def_log_str_cb;
+} lib_dt_data_list;
+
+/* map lists to handles */
+static std::map<dcd_tree_handle_t, lib_dt_data_list *> s_data_map;
+
+/*******************************************************************************/
+/* C API functions */
+/*******************************************************************************/
+
+/** Get Library version. Return a 32 bit version in form MMMMnnpp - MMMM = major version, nn = minor version, pp = patch version */
+OCSD_C_API uint32_t ocsd_get_version(void)
+{
+ return ocsdVersion::vers_num();
+}
+
+/** Get library version string */
+OCSD_C_API const char * ocsd_get_version_str(void)
+{
+ return ocsdVersion::vers_str();
+}
+
+
+/*** Decode tree creation etc. */
+
+OCSD_C_API dcd_tree_handle_t ocsd_create_dcd_tree(const ocsd_dcd_tree_src_t src_type, const uint32_t deformatterCfgFlags)
+{
+ dcd_tree_handle_t handle = C_API_INVALID_TREE_HANDLE;
+ handle = (dcd_tree_handle_t)DecodeTree::CreateDecodeTree(src_type,deformatterCfgFlags);
+ if(handle != C_API_INVALID_TREE_HANDLE)
+ {
+ lib_dt_data_list *pList = new (std::nothrow) lib_dt_data_list;
+ if(pList != 0)
+ {
+ s_data_map.insert(std::pair<dcd_tree_handle_t, lib_dt_data_list *>(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<dcd_tree_handle_t, lib_dt_data_list *>::iterator it;
+ it = s_data_map.find(handle);
+ if(it != s_data_map.end())
+ {
+ std::vector<ITrcTypedBase *>::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<DecodeTree *>(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<dcd_tree_handle_t, lib_dt_data_list *>::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;
+}
+
+OCSD_C_API ocsd_err_t ocsd_dt_get_decode_stats(const dcd_tree_handle_t handle,
+ const unsigned char CSID,
+ ocsd_decode_stats_t **p_stats_block)
+{
+ DecodeTree *pDT = static_cast<DecodeTree *>(handle);
+
+ return pDT->getDecoderStats(CSID, p_stats_block);
+}
+
+OCSD_C_API ocsd_err_t ocsd_dt_reset_decode_stats(const dcd_tree_handle_t handle,
+ const unsigned char CSID)
+{
+ DecodeTree *pDT = static_cast<DecodeTree *>(handle);
+
+ return pDT->resetDecoderStats(CSID);
+}
+
+/*** Decode tree set element output */
+OCSD_C_API ocsd_err_t ocsd_dt_set_gen_elem_outfn(const dcd_tree_handle_t handle, FnTraceElemIn pFn, const void *p_context)
+{
+
+ GenTraceElemCBObj * pCBObj = new (std::nothrow)GenTraceElemCBObj(pFn, p_context);
+ if(pCBObj)
+ {
+ ((DecodeTree *)handle)->setGenTraceElemOutI(pCBObj);
+ return OCSD_OK;
+ }
+ return OCSD_ERR_MEM;
+}
+
+
+/*** Default error logging */
+
+OCSD_C_API ocsd_err_t ocsd_def_errlog_init(const ocsd_err_severity_t verbosity, const int create_output_logger)
+{
+ if(DecodeTree::getDefaultErrorLogger()->initErrorLogger(verbosity,(bool)(create_output_logger != 0)))
+ return OCSD_OK;
+ return OCSD_ERR_NOT_INIT;
+}
+
+OCSD_C_API ocsd_err_t ocsd_def_errlog_config_output(const int output_flags, const char *log_file_name)
+{
+ ocsdMsgLogger *pLogger = DecodeTree::getDefaultErrorLogger()->getOutputLogger();
+ if(pLogger)
+ {
+ pLogger->setLogOpts(output_flags & C_API_MSGLOGOUT_MASK);
+ if(log_file_name != NULL)
+ {
+ pLogger->setLogFileName(log_file_name);
+ }
+ return OCSD_OK;
+ }
+ return OCSD_ERR_NOT_INIT;
+}
+
+
+OCSD_C_API ocsd_err_t ocsd_def_errlog_set_strprint_cb(const dcd_tree_handle_t handle, void *p_context, FnDefLoggerPrintStrCB p_str_print_cb)
+{
+ ocsdMsgLogger *pLogger = DecodeTree::getDefaultErrorLogger()->getOutputLogger();
+ if (pLogger)
+ {
+ std::map<dcd_tree_handle_t, lib_dt_data_list *>::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<EtmV4ITrcPacket,ocsd_etmv4_i_pkt>(p_pkt, pktStr);
+ break;
+
+ case OCSD_PROTOCOL_ETMV3:
+ trcPrintElemToString<EtmV3TrcPacket,ocsd_etmv3_pkt>(p_pkt, pktStr);
+ break;
+
+ case OCSD_PROTOCOL_STM:
+ trcPrintElemToString<StmTrcPacket,ocsd_stm_pkt>(p_pkt, pktStr);
+ break;
+
+ case OCSD_PROTOCOL_PTM:
+ trcPrintElemToString<PtmTrcPacket,ocsd_ptm_pkt>(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<OcsdTraceElement,ocsd_generic_trace_elem>(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<DecodeTree *>(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<DecodeTree *>(handle);
+ pDT->logMappedRanges();
+ }
+}
+
+OCSD_C_API void ocsd_gen_elem_init(ocsd_generic_trace_elem *p_pkt, const ocsd_gen_trc_elem_t elem_type)
+{
+ p_pkt->elem_type = elem_type;
+ p_pkt->flag_bits = 0;
+ p_pkt->ptr_extended_data = 0;
+}
+
+OCSD_C_API ocsd_err_t ocsd_dt_set_raw_frame_printer(const dcd_tree_handle_t handle, int flags)
+{
+ if (handle != C_API_INVALID_TREE_HANDLE)
+ return ((DecodeTree *)handle)->addRawFramePrinter(0, (uint32_t)flags);
+ return OCSD_ERR_NOT_INIT;
+}
+
+OCSD_C_API ocsd_err_t ocsd_dt_set_gen_elem_printer(const dcd_tree_handle_t handle)
+{
+ if (handle != C_API_INVALID_TREE_HANDLE)
+ return ((DecodeTree *)handle)->addGenElemPrinter(0);
+ return OCSD_ERR_NOT_INIT;
+}
+
+OCSD_C_API ocsd_err_t ocsd_dt_set_pkt_protocol_printer(const dcd_tree_handle_t handle, uint8_t cs_id, int monitor)
+{
+ ocsd_err_t err = OCSD_ERR_NOT_INIT;
+ if (handle != C_API_INVALID_TREE_HANDLE)
+ {
+ DecodeTree *p_tree = (DecodeTree *)handle;
+ err = p_tree->addPacketPrinter(cs_id, (bool)(monitor != 0), 0);
+ }
+ return err;
+}
+
+OCSD_C_API void ocsd_err_str(const ocsd_err_t err, char *buffer, const int buffer_size)
+{
+ std::string err_str;
+ err_str = ocsdError::getErrorString(ocsdError(OCSD_ERR_SEV_ERROR, err));
+ strncpy(buffer, err_str.c_str(), buffer_size - 1);
+ buffer[buffer_size - 1] = 0;
+}
+
+OCSD_C_API ocsd_err_t ocsd_get_last_err(ocsd_trc_index_t *index, uint8_t *chan_id, char *message, const int message_len)
+{
+ ocsdError *p_err;
+ ocsd_err_t err = OCSD_OK;
+ std::string err_str;
+
+ p_err = DecodeTree::getDefaultErrorLogger()->GetLastError();
+ if (p_err)
+ {
+ *index = p_err->getErrorIndex();
+ *chan_id = p_err->getErrorChanID();
+ err_str = p_err->getErrorString(ocsdError(p_err));
+ strncpy(message, err_str.c_str(), message_len - 1);
+ message[message_len - 1] = 0;
+ err = p_err->getErrorCode();
+ }
+ else
+ {
+ message[0] = 0;
+ *index = OCSD_BAD_TRC_INDEX;
+ *chan_id = OCSD_BAD_CS_SRC_ID;
+ }
+ return err;
+}
+
+/*******************************************************************************/
+/* C API local fns */
+/*******************************************************************************/
+static ocsd_err_t ocsd_create_pkt_sink_cb(ocsd_trace_protocol_t protocol, FnDefPktDataIn pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj )
+{
+ ocsd_err_t err = OCSD_OK;
+ *ppCBObj = 0;
+
+ switch(protocol)
+ {
+ case OCSD_PROTOCOL_ETMV4I:
+ *ppCBObj = new (std::nothrow) PktCBObj<EtmV4ITrcPacket>(pPktInFn,p_context);
+ break;
+
+ case OCSD_PROTOCOL_ETMV3:
+ *ppCBObj = new (std::nothrow) PktCBObj<EtmV3TrcPacket>(pPktInFn,p_context);
+ break;
+
+ case OCSD_PROTOCOL_PTM:
+ *ppCBObj = new (std::nothrow) PktCBObj<PtmTrcPacket>(pPktInFn,p_context);
+ break;
+
+ case OCSD_PROTOCOL_STM:
+ *ppCBObj = new (std::nothrow) PktCBObj<StmTrcPacket>(pPktInFn,p_context);
+ break;
+
+ default:
+ if ((protocol >= OCSD_PROTOCOL_CUSTOM_0) && (protocol < OCSD_PROTOCOL_END))
+ {
+ *ppCBObj = new (std::nothrow) PktCBObj<void>(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<EtmV4ITrcPacket>(pPktInFn,p_context);
+ break;
+
+ case OCSD_PROTOCOL_ETMV3:
+ *ppCBObj = new (std::nothrow) PktMonCBObj<EtmV3TrcPacket>(pPktInFn,p_context);
+ break;
+
+ case OCSD_PROTOCOL_PTM:
+ *ppCBObj = new (std::nothrow) PktMonCBObj<PtmTrcPacket>(pPktInFn,p_context);
+ break;
+
+ case OCSD_PROTOCOL_STM:
+ *ppCBObj = new (std::nothrow) PktMonCBObj<StmTrcPacket>(pPktInFn,p_context);
+ break;
+
+ default:
+ if ((protocol >= OCSD_PROTOCOL_CUSTOM_0) && (protocol < OCSD_PROTOCOL_END))
+ {
+ *ppCBObj = new (std::nothrow) PktMonCBObj<void>(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<DecodeTree *>(handle);
+ if(!(*ppDT)->hasMemAccMapper())
+ return (*ppDT)->createMemAccMapper();
+ return OCSD_OK;
+}
+
+/*******************************************************************************/
+/* C API Helper objects */
+/*******************************************************************************/
+
+/****************** Generic trace element output callback function ************/
+GenTraceElemCBObj::GenTraceElemCBObj(FnTraceElemIn pCBFn, const void *p_context) :
+ m_c_api_cb_fn(pCBFn),
+ m_p_cb_context(p_context)
+{
+}
+
+ocsd_datapath_resp_t GenTraceElemCBObj::TraceElemIn(const ocsd_trc_index_t index_sop,
+ const uint8_t trc_chan_id,
+ const OcsdTraceElement &elem)
+{
+ return m_c_api_cb_fn(m_p_cb_context, index_sop, trc_chan_id, &elem);
+}
+
+/* End of File ocsd_c_api.cpp */
diff --git a/decoder/source/c_api/ocsd_c_api_custom_obj.cpp b/decoder/source/c_api/ocsd_c_api_custom_obj.cpp
new file mode 100644
index 0000000..dbd0bd1
--- /dev/null
+++ b/decoder/source/c_api/ocsd_c_api_custom_obj.cpp
@@ -0,0 +1,431 @@
+/*
+ * \file ocsd_c_api_custom_obj.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* pull in the C++ decode library */
+#include "opencsd.h"
+
+#include "opencsd/c_api/opencsd_c_api.h"
+#include "ocsd_c_api_custom_obj.h"
+#include "common/ocsd_lib_dcd_register.h"
+
+/***************** C-API functions ********************************/
+
+/** register a custom decoder with the library */
+OCSD_C_API ocsd_err_t ocsd_register_custom_decoder(const char *name, ocsd_extern_dcd_fact_t *p_dcd_fact)
+{
+ ocsd_err_t err = OCSD_OK;
+ OcsdLibDcdRegister *pRegister = OcsdLibDcdRegister::getDecoderRegister();
+
+ // check not already registered
+ if(pRegister->isRegisteredDecoder(name))
+ return OCSD_ERR_DCDREG_NAME_REPEAT;
+
+ // validate the factory interface structure
+ if((p_dcd_fact->createDecoder == 0) ||
+ (p_dcd_fact->destroyDecoder == 0) ||
+ (p_dcd_fact->csidFromConfig == 0)
+ )
+ return OCSD_ERR_INVALID_PARAM_VAL;
+
+ // create a wrapper.
+ CustomDcdMngrWrapper *pWrapper = new (std::nothrow) CustomDcdMngrWrapper();
+ if(pRegister == 0)
+ return OCSD_ERR_MEM;
+
+ p_dcd_fact->protocol_id = OcsdLibDcdRegister::getNextCustomProtocolID();
+ if(p_dcd_fact->protocol_id < OCSD_PROTOCOL_END)
+ {
+ // fill out the wrapper and register it
+ pWrapper->setAPIDcdFact(p_dcd_fact);
+ err = pRegister->registerDecoderTypeByName(name,pWrapper);
+ if(err != OCSD_OK)
+ OcsdLibDcdRegister::releaseLastCustomProtocolID();
+ }
+ else
+ err = OCSD_ERR_DCDREG_TOOMANY; // too many decoders
+
+ if(err != OCSD_OK)
+ delete pWrapper;
+
+ return err;
+}
+
+OCSD_C_API ocsd_err_t ocsd_deregister_decoders()
+{
+ // destroys all builtin and custom decoders & library registration object.
+ OcsdLibDcdRegister::deregisterAllDecoders();
+ return OCSD_OK;
+}
+
+OCSD_C_API ocsd_err_t ocsd_cust_protocol_to_str(const ocsd_trace_protocol_t pkt_protocol, const void *trc_pkt, char *buffer, const int buflen)
+{
+ OcsdLibDcdRegister *pRegister = OcsdLibDcdRegister::getDecoderRegister();
+ IDecoderMngr *p_mngr = 0;
+ if (OCSD_PROTOCOL_IS_CUSTOM(pkt_protocol) && (pRegister->getDecoderMngrByType(pkt_protocol, &p_mngr) == OCSD_OK))
+ {
+ CustomDcdMngrWrapper *pWrapper = static_cast<CustomDcdMngrWrapper *>(p_mngr);
+ pWrapper->pktToString(trc_pkt, buffer, buflen);
+ return OCSD_OK;
+ }
+ return OCSD_ERR_NO_PROTOCOL;
+}
+
+/***************** Decode Manager Wrapper *****************************/
+
+CustomDcdMngrWrapper::CustomDcdMngrWrapper()
+{
+ m_dcd_fact.protocol_id = OCSD_PROTOCOL_END;
+}
+
+
+ // set the C-API decoder factory interface
+void CustomDcdMngrWrapper::setAPIDcdFact(ocsd_extern_dcd_fact_t *p_dcd_fact)
+{
+ m_dcd_fact = *p_dcd_fact;
+}
+
+// create and destroy decoders
+ocsd_err_t CustomDcdMngrWrapper::createDecoder(const int create_flags, const int instID, const CSConfig *p_config, TraceComponent **ppComponent)
+{
+ ocsd_err_t err = OCSD_OK;
+ if(m_dcd_fact.protocol_id == OCSD_PROTOCOL_END)
+ return OCSD_ERR_NOT_INIT;
+
+ CustomDecoderWrapper *pComp = new (std::nothrow) CustomDecoderWrapper();
+ *ppComponent = pComp;
+ if (pComp == 0)
+ return OCSD_ERR_MEM;
+
+ ocsd_extern_dcd_cb_fns lib_callbacks;
+ CustomDecoderWrapper::SetCallbacks(lib_callbacks);
+ lib_callbacks.lib_context = pComp;
+ lib_callbacks.packetCBFlags = 0;
+
+ ocsd_extern_dcd_inst_t *pDecodeInst = pComp->getDecoderInstInfo();
+
+ err = m_dcd_fact.createDecoder( create_flags,
+ ((CustomConfigWrapper *)p_config)->getConfig(),
+ &lib_callbacks,
+ pDecodeInst);
+
+ if (err == OCSD_OK)
+ {
+ // validate the decoder
+ if ((pDecodeInst->fn_data_in == 0) ||
+ (pDecodeInst->fn_update_pkt_mon == 0) ||
+ (pDecodeInst->cs_id == 0) ||
+ (pDecodeInst->decoder_handle == 0) ||
+ (pDecodeInst->p_decoder_name == 0)
+ )
+ {
+ err = OCSD_ERR_INVALID_PARAM_VAL;
+ }
+ }
+
+ if (err != OCSD_OK)
+ delete pComp;
+ else
+ pComp->updateNameFromDcdInst();
+ return err;
+}
+
+ocsd_err_t CustomDcdMngrWrapper::destroyDecoder(TraceComponent *pComponent)
+{
+ CustomDecoderWrapper *pCustWrap = dynamic_cast<CustomDecoderWrapper *>(pComponent);
+ if(m_dcd_fact.protocol_id != OCSD_PROTOCOL_END)
+ m_dcd_fact.destroyDecoder(pCustWrap->getDecoderInstInfo()->decoder_handle);
+ delete pCustWrap;
+ return OCSD_OK;
+}
+
+const ocsd_trace_protocol_t CustomDcdMngrWrapper::getProtocolType() const
+{
+ return m_dcd_fact.protocol_id;
+}
+
+ocsd_err_t CustomDcdMngrWrapper::createConfigFromDataStruct(CSConfig **pConfigBase, const void *pDataStruct)
+{
+ ocsd_err_t err = OCSD_OK;
+ CustomConfigWrapper *pConfig = new (std::nothrow) CustomConfigWrapper(pDataStruct);
+ if(!pConfig)
+ return OCSD_ERR_MEM;
+
+ if(m_dcd_fact.csidFromConfig == 0)
+ return OCSD_ERR_NOT_INIT;
+
+ unsigned char csid;
+ err = m_dcd_fact.csidFromConfig(pDataStruct,&csid);
+ if(err == OCSD_OK)
+ {
+ pConfig->setCSID(csid);
+ *pConfigBase = pConfig;
+ }
+ return err;
+}
+
+ocsd_err_t CustomDcdMngrWrapper::getDataInputI(TraceComponent *pComponent, ITrcDataIn **ppDataIn)
+{
+ CustomDecoderWrapper *pDecoder = dynamic_cast<CustomDecoderWrapper *>(pComponent);
+ if(pDecoder == 0)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+
+ *ppDataIn = pDecoder;
+ return OCSD_OK;
+}
+
+// component connections
+// all
+ocsd_err_t CustomDcdMngrWrapper::attachErrorLogger(TraceComponent *pComponent, ITraceErrorLog *pIErrorLog)
+{
+ CustomDecoderWrapper *pDecoder = dynamic_cast<CustomDecoderWrapper *>(pComponent);
+ if (pDecoder == 0)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+ pDecoder->getErrorLogAttachPt()->replace_first(pIErrorLog);
+ return OCSD_OK;
+}
+
+// full decoder
+ocsd_err_t CustomDcdMngrWrapper::attachInstrDecoder(TraceComponent *pComponent, IInstrDecode *pIInstrDec)
+{
+ CustomDecoderWrapper *pDecoder = dynamic_cast<CustomDecoderWrapper *>(pComponent);
+ if(pDecoder == 0)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+ pDecoder->attachInstrDecI(pIInstrDec);
+ return OCSD_OK;
+}
+
+ocsd_err_t CustomDcdMngrWrapper::attachMemAccessor(TraceComponent *pComponent, ITargetMemAccess *pMemAccessor)
+{
+ CustomDecoderWrapper *pDecoder = dynamic_cast<CustomDecoderWrapper *>(pComponent);
+ if(pDecoder == 0)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+ pDecoder->attachMemAccI(pMemAccessor);
+ return OCSD_OK;
+}
+
+ocsd_err_t CustomDcdMngrWrapper::attachOutputSink(TraceComponent *pComponent, ITrcGenElemIn *pOutSink)
+{
+ CustomDecoderWrapper *pDecoder = dynamic_cast<CustomDecoderWrapper *>(pComponent);
+ if(pDecoder == 0)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+ pDecoder->attachGenElemI(pOutSink);
+ return OCSD_OK;
+}
+
+// pkt processor only
+ocsd_err_t CustomDcdMngrWrapper::attachPktMonitor(TraceComponent *pComponent, ITrcTypedBase *pPktRawDataMon)
+{
+ CustomDecoderWrapper *pDecoder = dynamic_cast<CustomDecoderWrapper *>(pComponent);
+ if(pDecoder == 0)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+ IPktRawDataMon<void> *pIF = 0;
+ if (pPktRawDataMon)
+ {
+ pIF = dynamic_cast<IPktRawDataMon<void> *>(pPktRawDataMon);
+ if (!pIF)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+ }
+ pDecoder->attachPtkMonI(pIF);
+ return OCSD_OK;
+}
+
+ocsd_err_t CustomDcdMngrWrapper::attachPktIndexer(TraceComponent *pComponent, ITrcTypedBase *pPktIndexer)
+{
+ // indexers for external custom will also be external and custom.
+ return OCSD_ERR_DCD_INTERFACE_UNUSED;
+}
+
+ocsd_err_t CustomDcdMngrWrapper::attachPktSink(TraceComponent *pComponent, ITrcTypedBase *pPktDataInSink)
+{
+ CustomDecoderWrapper *pDecoder = dynamic_cast<CustomDecoderWrapper *>(pComponent);
+ if(pDecoder == 0)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+ IPktDataIn<void> *pIF = 0;
+ if (pPktDataInSink)
+ {
+ pIF = dynamic_cast<IPktDataIn<void> *>(pPktDataInSink);
+ if(!pIF)
+ return OCSD_ERR_INVALID_PARAM_TYPE;
+ }
+ pDecoder->attachPtkSinkI(pIF);
+ return OCSD_OK;
+}
+
+void CustomDcdMngrWrapper::pktToString(const void *pkt, char *pStrBuffer, int bufSize)
+{
+ if (m_dcd_fact.pktToString)
+ m_dcd_fact.pktToString(pkt, pStrBuffer, bufSize);
+ else
+ snprintf(pStrBuffer, bufSize, "CUSTOM_PKT[]: print unsupported; protocol(%d).",m_dcd_fact.protocol_id);
+}
+
+/************************** Decoder instance wrapper **************************************/
+
+/* callback functions */
+ocsd_datapath_resp_t GenElemOpCB( const void *lib_context,
+ const ocsd_trc_index_t index_sop,
+ const uint8_t trc_chan_id,
+ const ocsd_generic_trace_elem *elem)
+{
+ if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pGenElemIn)
+ return ((CustomDecoderWrapper *)lib_context)->m_pGenElemIn->TraceElemIn(index_sop,trc_chan_id,*(OcsdTraceElement *)elem);
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+void LogErrorCB(const void *lib_context, const ocsd_err_severity_t filter_level, const ocsd_err_t code, const ocsd_trc_index_t idx, const uint8_t chan_id, const char *pMsg)
+{
+ if (lib_context)
+ {
+ if(pMsg)
+ ((CustomDecoderWrapper *)lib_context)->LogError(ocsdError(filter_level, code, idx, chan_id, std::string(pMsg)));
+ else
+ ((CustomDecoderWrapper *)lib_context)->LogError(ocsdError(filter_level, code, idx, chan_id));
+ }
+}
+
+void LogMsgCB(const void *lib_context, const ocsd_err_severity_t filter_level, const char *msg)
+{
+ if (lib_context && msg)
+ ((CustomDecoderWrapper *)lib_context)->LogMessage(filter_level, std::string(msg));
+}
+
+ocsd_err_t DecodeArmInstCB(const void *lib_context, ocsd_instr_info *instr_info)
+{
+ if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pIInstrDec)
+ return ((CustomDecoderWrapper *)lib_context)->m_pIInstrDec->DecodeInstruction(instr_info);
+ return OCSD_ERR_ATTACH_INVALID_PARAM;
+}
+
+ocsd_err_t MemAccessCB(const void *lib_context,
+ const ocsd_vaddr_t address,
+ const uint8_t cs_trace_id,
+ const ocsd_mem_space_acc_t mem_space,
+ uint32_t *num_bytes,
+ uint8_t *p_buffer)
+{
+ if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pMemAccessor)
+ return ((CustomDecoderWrapper *)lib_context)->m_pMemAccessor->ReadTargetMemory(address, cs_trace_id, mem_space, num_bytes, p_buffer);
+ return OCSD_ERR_INVALID_PARAM_VAL;
+}
+
+void PktMonCB(const void *lib_context,
+ const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const void *pkt,
+ const uint32_t size,
+ const uint8_t *p_data)
+{
+ if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pPktMon)
+ ((CustomDecoderWrapper *)lib_context)->m_pPktMon->RawPacketDataMon(op, index_sop, pkt, size, p_data);
+}
+
+ocsd_datapath_resp_t PktDataSinkCB(const void *lib_context,
+ const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const void *pkt)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ if (lib_context && ((CustomDecoderWrapper *)lib_context)->m_pPktIn)
+ resp = ((CustomDecoderWrapper *)lib_context)->m_pPktIn->PacketDataIn(op, index_sop, pkt);
+ return resp;
+}
+
+
+
+/** decoder instance object */
+CustomDecoderWrapper::CustomDecoderWrapper() : TraceComponent("extern_wrapper"),
+ m_pGenElemIn(0),
+ m_pIInstrDec(0),
+ m_pMemAccessor(0),
+ m_pPktMon(0),
+ m_pPktIn(0)
+{
+}
+
+CustomDecoderWrapper::~CustomDecoderWrapper()
+{
+}
+
+ocsd_datapath_resp_t CustomDecoderWrapper::TraceDataIn( const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ if(m_decoder_inst.fn_data_in)
+ return m_decoder_inst.fn_data_in( m_decoder_inst.decoder_handle,
+ op,
+ index,
+ dataBlockSize,
+ pDataBlock,
+ numBytesProcessed);
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+void CustomDecoderWrapper::attachPtkMonI(IPktRawDataMon<void>* pIF)
+{
+ m_pPktMon = pIF;
+ int flags = (m_pPktMon ? OCSD_CUST_DCD_PKT_CB_USE_MON : 0) | (m_pPktIn ? OCSD_CUST_DCD_PKT_CB_USE_SINK : 0);
+ m_decoder_inst.fn_update_pkt_mon(m_decoder_inst.decoder_handle, flags);
+}
+
+void CustomDecoderWrapper::attachPtkSinkI(IPktDataIn<void>* pIF)
+{
+ m_pPktIn = pIF;
+ int flags = (m_pPktMon ? OCSD_CUST_DCD_PKT_CB_USE_MON : 0) | (m_pPktIn ? OCSD_CUST_DCD_PKT_CB_USE_SINK : 0);
+ m_decoder_inst.fn_update_pkt_mon(m_decoder_inst.decoder_handle, flags);
+}
+
+void CustomDecoderWrapper::updateNameFromDcdInst()
+{
+ // create a unique component name from the decoder name + cs-id.
+ std::string name_combined = m_decoder_inst.p_decoder_name;
+ char num_buffer[32];
+ sprintf(num_buffer, "_%04d", m_decoder_inst.cs_id);
+ name_combined += (std::string)num_buffer;
+ setComponentName(name_combined);
+}
+
+void CustomDecoderWrapper::SetCallbacks(ocsd_extern_dcd_cb_fns & callbacks)
+{
+ callbacks.fn_arm_instruction_decode = DecodeArmInstCB;
+ callbacks.fn_gen_elem_out = GenElemOpCB;
+ callbacks.fn_log_error = LogErrorCB;
+ callbacks.fn_log_msg = LogMsgCB;
+ callbacks.fn_memory_access = MemAccessCB;
+ callbacks.fn_packet_data_sink = PktDataSinkCB;
+ callbacks.fn_packet_mon = PktMonCB;
+}
+
+/* End of File ocsd_c_api_custom_obj.cpp */
diff --git a/decoder/source/c_api/ocsd_c_api_custom_obj.h b/decoder/source/c_api/ocsd_c_api_custom_obj.h
new file mode 100644
index 0000000..d4845bd
--- /dev/null
+++ b/decoder/source/c_api/ocsd_c_api_custom_obj.h
@@ -0,0 +1,189 @@
+/*
+ * \file ocsd_c_api_custom_obj.h
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef ARM_OCSD_C_API_CUSTOM_OBJ_H_INCLUDED
+#define ARM_OCSD_C_API_CUSTOM_OBJ_H_INCLUDED
+
+#include "opencsd/c_api/ocsd_c_api_custom.h"
+#include "common/ocsd_dcd_mngr_i.h"
+
+/***** Decoder manager interface ******************************/
+class CustomDcdMngrWrapper : public IDecoderMngr
+{
+public:
+ CustomDcdMngrWrapper();
+ virtual ~CustomDcdMngrWrapper() {};
+
+ // set the C-API decoder factory interface.
+ void setAPIDcdFact(ocsd_extern_dcd_fact_t *p_dcd_fact);
+
+// create and destroy decoders
+ virtual ocsd_err_t createDecoder(const int create_flags, const int instID, const CSConfig *p_config, TraceComponent **ppComponent);
+ virtual ocsd_err_t destroyDecoder(TraceComponent *pComponent);
+
+ //! Get the built in protocol type ID managed by this instance - extern for custom decoders
+ virtual const ocsd_trace_protocol_t getProtocolType() const;
+
+// connect decoders to other components - (replace current / 0 pointer value to detach );
+// compatible with all decoders
+ //!attach error logger to ptk-processor, or both of pkt processor and pkt decoder pair
+ virtual ocsd_err_t attachErrorLogger(TraceComponent *pComponent, ITraceErrorLog *pIErrorLog);
+
+// pkt decoder only
+ //! attach instruction decoder to pkt decoder
+ virtual ocsd_err_t attachInstrDecoder(TraceComponent *pComponent, IInstrDecode *pIInstrDec);
+
+ //! attach memory accessor to pkt decoder
+ virtual ocsd_err_t attachMemAccessor(TraceComponent *pComponent, ITargetMemAccess *pMemAccessor);
+
+ //! attach generic output interface to pkt decoder
+ virtual ocsd_err_t attachOutputSink(TraceComponent *pComponent, ITrcGenElemIn *pOutSink);
+
+// pkt processor only
+ //! attach a raw packet monitor to pkt processor (solo pkt processor, or pkt processor part of pair)
+ virtual ocsd_err_t attachPktMonitor(TraceComponent *pComponent, ITrcTypedBase *pPktRawDataMon);
+
+ //! attach a packet indexer to pkt processor (solo pkt processor, or pkt processor part of pair)
+ virtual ocsd_err_t attachPktIndexer(TraceComponent *pComponent, ITrcTypedBase *pPktIndexer);
+
+ //! attach a packet data sink to pkt processor output (solo pkt processor only - instead of decoder when pkt processor only created.)
+ virtual ocsd_err_t attachPktSink(TraceComponent *pComponent, ITrcTypedBase *pPktDataInSink);
+
+// data input connection interface
+ //! get raw data input interface from packet processor
+ virtual ocsd_err_t getDataInputI(TraceComponent *pComponent, ITrcDataIn **ppDataIn);
+
+// create configuration from data structure
+ virtual ocsd_err_t createConfigFromDataStruct(CSConfig **pConfigBase, const void *pDataStruct);
+
+// custom packet to string interface.
+ void pktToString(const void *pkt, char *pStrBuffer, int bufSize);
+
+private:
+
+ ocsd_extern_dcd_fact_t m_dcd_fact;
+};
+
+/**** Decoder instance wrapper */
+class CustomDecoderWrapper : public TraceComponent, public ITrcDataIn
+{
+public:
+ CustomDecoderWrapper();
+ virtual ~CustomDecoderWrapper();
+ ocsd_extern_dcd_inst_t *getDecoderInstInfo() { return &m_decoder_inst; }
+
+ virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed);
+
+ void attachGenElemI(ITrcGenElemIn *pIF) { m_pGenElemIn = pIF; };
+ void attachInstrDecI(IInstrDecode *pIF) { m_pIInstrDec = pIF; };
+ void attachMemAccI(ITargetMemAccess *pIF) { m_pMemAccessor = pIF; };
+
+ void attachPtkMonI(IPktRawDataMon<void> *pIF);
+ void attachPtkSinkI(IPktDataIn<void> *pIF);
+
+ void updateNameFromDcdInst();
+
+ static void SetCallbacks(ocsd_extern_dcd_cb_fns &callbacks);
+
+private:
+ // declare the callback functions as friend functions.
+ friend ocsd_datapath_resp_t GenElemOpCB( const void *lib_context,
+ const ocsd_trc_index_t index_sop,
+ const uint8_t trc_chan_id,
+ const ocsd_generic_trace_elem *elem);
+
+ friend void LogErrorCB( const void *lib_context,
+ const ocsd_err_severity_t filter_level,
+ const ocsd_err_t code,
+ const ocsd_trc_index_t idx,
+ const uint8_t chan_id,
+ const char *pMsg);
+
+ friend void LogMsgCB(const void *lib_context,
+ const ocsd_err_severity_t filter_level,
+ const char *msg);
+
+ friend ocsd_err_t DecodeArmInstCB(const void *lib_context, ocsd_instr_info *instr_info);
+
+ friend ocsd_err_t MemAccessCB(const void *lib_context,
+ const ocsd_vaddr_t address,
+ const uint8_t cs_trace_id,
+ const ocsd_mem_space_acc_t mem_space,
+ uint32_t *num_bytes,
+ uint8_t *p_buffer);
+
+ friend void PktMonCB(const void *lib_context,
+ const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const void *pkt,
+ const uint32_t size,
+ const uint8_t *p_data);
+
+ friend ocsd_datapath_resp_t PktDataSinkCB(const void *lib_context,
+ const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const void *pkt);
+
+private:
+ ITrcGenElemIn *m_pGenElemIn; //!< generic element sink interface - output from decoder fed to common sink.
+ IInstrDecode *m_pIInstrDec; //!< arm instruction decode interface - decoder may want to use this.
+ ITargetMemAccess *m_pMemAccessor; //!< system memory accessor insterface - decoder may want to use this.
+ IPktRawDataMon<void> *m_pPktMon; //!< interface to packet monitor (full or packet only decode).
+ IPktDataIn<void> *m_pPktIn; //!< interface to packet sink (decode packets only).
+
+ ocsd_extern_dcd_inst_t m_decoder_inst;
+};
+
+/**** Decoder configuration wrapper - implements CSConfig base class interface ***/
+class CustomConfigWrapper : public CSConfig
+{
+public:
+ CustomConfigWrapper(const void *p_config) : m_p_config(p_config), m_CSID(0) {};
+ virtual ~CustomConfigWrapper() {};
+ virtual const uint8_t getTraceID() const { return m_CSID; };
+ void setCSID(const uint8_t CSID) { m_CSID = CSID; };
+ const void *getConfig() { return m_p_config; };
+private:
+ const void *m_p_config;
+ uint8_t m_CSID;
+};
+
+#endif // ARM_OCSD_C_API_CUSTOM_OBJ_H_INCLUDED
+
+/* End of File ocsd_c_api_custom_obj.h */
diff --git a/decoder/source/c_api/ocsd_c_api_obj.h b/decoder/source/c_api/ocsd_c_api_obj.h
new file mode 100644
index 0000000..0476ac6
--- /dev/null
+++ b/decoder/source/c_api/ocsd_c_api_obj.h
@@ -0,0 +1,182 @@
+/*
+ * \file ocsd_c_api_obj.h
+ * \brief OpenCSD : C API callback objects.
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+#ifndef ARM_OCSD_C_API_OBJ_H_INCLUDED
+#define ARM_OCSD_C_API_OBJ_H_INCLUDED
+
+#include "opencsd/c_api/ocsd_c_api_types.h"
+#include "interfaces/trc_gen_elem_in_i.h"
+#include "common/ocsd_msg_logger.h"
+
+class TraceElemCBBase
+{
+public:
+ TraceElemCBBase() {};
+ virtual ~TraceElemCBBase() {};
+};
+
+class GenTraceElemCBObj : public ITrcGenElemIn, public TraceElemCBBase
+{
+public:
+ GenTraceElemCBObj(FnTraceElemIn pCBFn, const void *p_context);
+ virtual ~GenTraceElemCBObj() {};
+
+ virtual ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop,
+ const uint8_t trc_chan_id,
+ const OcsdTraceElement &elem);
+
+private:
+ FnTraceElemIn m_c_api_cb_fn;
+ const void *m_p_cb_context;
+};
+
+
+
+template<class TrcPkt>
+class PktCBObj : public IPktDataIn<TrcPkt>
+{
+public:
+ PktCBObj( FnDefPktDataIn pCBFunc, const void *p_context)
+ {
+ m_c_api_cb_fn = pCBFunc;
+ m_p_context = p_context;
+ };
+
+ virtual ~PktCBObj() {};
+
+ virtual ocsd_datapath_resp_t PacketDataIn( const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const TrcPkt *p_packet_in)
+ {
+ const void *c_pkt_struct = 0;
+ if(op == OCSD_OP_DATA)
+ c_pkt_struct = p_packet_in->c_pkt(); // always output the c struct packet
+ return m_c_api_cb_fn(m_p_context,op,index_sop,c_pkt_struct);
+ };
+
+private:
+ FnDefPktDataIn m_c_api_cb_fn;
+ const void *m_p_context;
+};
+
+// void specialisation for custom decoders that pass packets as const void * pointers
+template<>
+class PktCBObj<void> : public IPktDataIn<void>
+{
+public:
+ PktCBObj(FnDefPktDataIn pCBFunc, const void *p_context)
+ {
+ m_c_api_cb_fn = pCBFunc;
+ m_p_context = p_context;
+ };
+
+ virtual ~PktCBObj() {};
+
+ virtual ocsd_datapath_resp_t PacketDataIn(const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const void *p_packet_in)
+ {
+ return m_c_api_cb_fn(m_p_context, op, index_sop, p_packet_in);
+ };
+
+private:
+ FnDefPktDataIn m_c_api_cb_fn;
+ const void *m_p_context;
+};
+
+
+template<class TrcPkt>
+class PktMonCBObj : public IPktRawDataMon<TrcPkt>
+{
+public:
+ PktMonCBObj( FnDefPktDataMon pCBFunc, const void *p_context)
+ {
+ m_c_api_cb_fn = pCBFunc;
+ m_p_context = p_context;
+ };
+
+ virtual ~PktMonCBObj() {};
+
+ virtual void RawPacketDataMon( const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const TrcPkt *p_packet_in,
+ const uint32_t size,
+ const uint8_t *p_data)
+ {
+ const void *c_pkt_struct = 0;
+ if(op == OCSD_OP_DATA)
+ c_pkt_struct = p_packet_in->c_pkt(); // always output the c struct packet
+ m_c_api_cb_fn(m_p_context,op,index_sop,c_pkt_struct,size,p_data);
+ };
+
+private:
+ FnDefPktDataMon m_c_api_cb_fn;
+ const void *m_p_context;
+};
+
+// void specialisation for custom decoders that pass packets as const void * pointers
+template<>
+class PktMonCBObj<void> : public IPktRawDataMon<void>
+{
+public:
+ PktMonCBObj(FnDefPktDataMon pCBFunc, const void *p_context)
+ {
+ m_c_api_cb_fn = pCBFunc;
+ m_p_context = p_context;
+ };
+
+ virtual ~PktMonCBObj() {};
+ virtual void RawPacketDataMon(const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const void *p_packet_in,
+ const uint32_t size,
+ const uint8_t *p_data)
+ {
+ m_c_api_cb_fn(m_p_context, op, index_sop, p_packet_in, size, p_data);
+ };
+
+private:
+ FnDefPktDataMon m_c_api_cb_fn;
+ const void *m_p_context;
+};
+
+/* handler for default string print CB object */
+class DefLogStrCBObj : public ocsdMsgLogStrOutI
+{
+public:
+ DefLogStrCBObj()
+ {
+ m_c_api_cb_fn = 0;
+ m_p_context = 0;
+ };
+
+ virtual ~DefLogStrCBObj()
+ {
+ m_c_api_cb_fn = 0;
+ m_p_context = 0;
+ };
+
+ void setCBFn(const void *p_context, FnDefLoggerPrintStrCB pCBFn)
+ {
+ m_c_api_cb_fn = pCBFn;
+ m_p_context = p_context;
+ };
+
+ virtual void printOutStr(const std::string &outStr)
+ {
+ if(m_c_api_cb_fn)
+ m_c_api_cb_fn(m_p_context, outStr.c_str(), outStr.length());
+ }
+
+private:
+ FnDefLoggerPrintStrCB m_c_api_cb_fn;
+ const void *m_p_context;
+};
+
+#endif // ARM_OCSD_C_API_OBJ_H_INCLUDED
+
+/* End of File ocsd_c_api_obj.h */
diff --git a/decoder/source/ete/trc_cmp_cfg_ete.cpp b/decoder/source/ete/trc_cmp_cfg_ete.cpp
new file mode 100644
index 0000000..474cb2f
--- /dev/null
+++ b/decoder/source/ete/trc_cmp_cfg_ete.cpp
@@ -0,0 +1,98 @@
+/*
+* \file trc_cmp_cfg_ete.cpp
+* \brief OpenCSD : ETE config class
+*
+* \copyright Copyright (c) 2019, ARM Limited. All Rights Reserved.
+*/
+
+/*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its contributors
+* may be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "opencsd/ete/trc_cmp_cfg_ete.h"
+
+ETEConfig::ETEConfig() : EtmV4Config()
+{
+ m_ete_cfg.reg_idr0 = 0x28000EA1;
+ m_ete_cfg.reg_idr1 = 0x4100FFF3;
+ m_ete_cfg.reg_idr2 = 0x00000488;
+ m_ete_cfg.reg_idr8 = 0;
+ m_ete_cfg.reg_configr = 0xC1;
+ m_ete_cfg.reg_traceidr = 0;
+ m_ete_cfg.arch_ver = ARCH_AA64;
+ m_ete_cfg.core_prof = profile_CortexA;
+ m_ete_cfg.reg_devarch = 0x47705A13;
+ copyV4();
+}
+
+ETEConfig::ETEConfig(const ocsd_ete_cfg *cfg_regs) : EtmV4Config()
+{
+ m_ete_cfg = *cfg_regs;
+ copyV4();
+}
+
+ETEConfig::~ETEConfig()
+{
+
+}
+
+//! copy assignment operator for base structure into class.
+ETEConfig & ETEConfig::operator=(const ocsd_ete_cfg *p_cfg)
+{
+ m_ete_cfg = *p_cfg;
+ copyV4();
+ return *this;
+}
+
+//! cast operator returning struct const reference
+//operator const ocsd_ete_cfg &() const { return m_ete_cfg; };
+//! cast operator returning struct const pointer
+//operator const ocsd_ete_cfg *() const { return &m_ete_cfg; };
+
+// ete superset of etmv4 - move info to underlying structure.
+void ETEConfig::copyV4()
+{
+ // copy over 1:1 regs
+ m_cfg.reg_idr0 = m_ete_cfg.reg_idr0;
+ m_cfg.reg_idr1 = m_ete_cfg.reg_idr1;
+ m_cfg.reg_idr2 = m_ete_cfg.reg_idr2;
+ m_cfg.reg_idr8 = m_ete_cfg.reg_idr8;
+ m_cfg.reg_idr9 = 0;
+ m_cfg.reg_idr10 = 0;
+ m_cfg.reg_idr11 = 0;
+ m_cfg.reg_idr12 = 0;
+ m_cfg.reg_idr13 = 0;
+ m_cfg.reg_configr = m_ete_cfg.reg_configr;
+ m_cfg.reg_traceidr = m_ete_cfg.reg_traceidr;
+ m_cfg.core_prof = m_ete_cfg.core_prof;
+ m_cfg.arch_ver = m_ete_cfg.arch_ver;
+
+ // override major / minor version as part of devarch
+ m_MajVer = (uint8_t)((m_ete_cfg.reg_devarch & 0xF000) >> 12);
+ m_MinVer = (uint8_t)((m_ete_cfg.reg_devarch & 0xF0000) >> 16);
+}
+
+/* End of File trc_cmp_cfg_ete.cpp */
diff --git a/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp b/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp
new file mode 100644
index 0000000..f2556e4
--- /dev/null
+++ b/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp
@@ -0,0 +1,65 @@
+/*
+ * \file trc_cmp_cfg_etmv3.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h"
+
+EtmV3Config::EtmV3Config()
+{
+ // defaults set ETMv3.4, V7A, instruction only.
+ m_cfg.arch_ver = ARCH_V7;
+ m_cfg.core_prof = profile_CortexA;
+ m_cfg.reg_ccer = 0;
+ m_cfg.reg_idr = 0x4100F240; // default trace IDR value
+ m_cfg.reg_ctrl = 0;
+}
+
+EtmV3Config::EtmV3Config(const ocsd_etmv3_cfg *cfg_regs)
+{
+ m_cfg = *cfg_regs;
+}
+
+EtmV3Config::EtmTraceMode const EtmV3Config::GetTraceMode() const
+{
+ int mode = 0 + ( isDataValTrace() ? 1 : 0 ) + (isDataAddrTrace() ? 2 : 0) + (isInstrTrace() ? 0 : 3);
+ return (EtmTraceMode)mode;
+}
+
+const int EtmV3Config::CtxtIDBytes() const
+{
+ int ctxtIdsizes[] = { 0, 1, 2, 4 };
+ return ctxtIdsizes[(m_cfg.reg_ctrl >> 14) & 0x3];
+}
+
+/* End of File trc_cmp_cfg_etmv3.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp b/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp
new file mode 100644
index 0000000..e68a73f
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp
@@ -0,0 +1,681 @@
+/*!
+ * \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);
+ pElem->setUnSyncEOTReason(UNSYNC_EOT);
+ 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;
+ m_unsync_info = UNSYNC_RESET_DECODER;
+ 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_unsync_info = UNSYNC_INIT_DECODER;
+ 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);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ 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;
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ 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);
+ pElem->setUnSyncEOTReason(m_unsync_info);
+ resp = m_outputElemList.sendElements();
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ 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);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ 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);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ 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.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);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ }
+ return resp;
+}
+
+// if v7M -> pend only ERET, if V7A/R pend ERET and prev instr.
+void TrcPktDecodeEtmV3::pendExceptionReturn()
+{
+ int pendElem = 1;
+ if(m_config->getCoreProfile() != profile_CortexM)
+ {
+ int nElem = m_outputElemList.getNumElem();
+ if(nElem > 1)
+ {
+ if(m_outputElemList.getElemType(nElem - 2) == OCSD_GEN_TRC_ELEM_INSTR_RANGE)
+ pendElem = 2; // need to pend instr+eret for A/R
+ }
+ }
+ m_outputElemList.pendLastNElem(pendElem);
+}
+
+/* End of File trc_pkt_decode_etmv3.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp b/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp
new file mode 100644
index 0000000..74034c3
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp
@@ -0,0 +1,688 @@
+/*
+ * \file trc_pkt_elem_etmv3.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cstring>
+#include <sstream>
+#include <iomanip>
+
+#include "opencsd/etmv3/trc_pkt_elem_etmv3.h"
+
+EtmV3TrcPacket::EtmV3TrcPacket()
+{
+ m_pkt_data.addr.size = VA_32BIT; // etm v3 only handles 32 bit addresses.
+}
+
+EtmV3TrcPacket::~EtmV3TrcPacket()
+{
+}
+
+// update interface - set packet values
+
+// clear this packet info
+void EtmV3TrcPacket::Clear()
+{
+ // clear structure flags and counter elements etc, that work per packet.
+ // leave intra packet data unchanged
+ m_pkt_data.addr.pkt_bits = 0;
+ m_pkt_data.prev_isa = m_pkt_data.curr_isa; // mark ISA as not changed
+ m_pkt_data.exception.bits.present = 0;
+ m_pkt_data.atom.num = 0;
+ m_pkt_data.cycle_count = 0;
+ m_pkt_data.context.updated = 0;
+ m_pkt_data.context.updated_c = 0;
+ m_pkt_data.context.updated_v = 0;
+ m_pkt_data.data.ooo_tag = 0;
+ m_pkt_data.data.value = 0;
+ m_pkt_data.data.update_addr = 0;
+ m_pkt_data.data.update_be = 0;
+ m_pkt_data.data.update_dval = 0;
+ m_pkt_data.ts_update_bits = 0;
+ m_pkt_data.isync_info.has_cycle_count = 0;
+ m_pkt_data.isync_info.has_LSipAddress = 0;
+ m_pkt_data.isync_info.no_address = 0;
+}
+
+// reset all state including intra packet
+void EtmV3TrcPacket::ResetState()
+{
+ memset(&m_pkt_data,0,sizeof(ocsd_etmv3_pkt));
+ m_pkt_data.curr_isa = m_pkt_data.prev_isa = ocsd_isa_unknown;
+}
+
+void EtmV3TrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits)
+{
+ ocsd_vaddr_t validMask = OCSD_VA_MASK;
+ validMask >>= OCSD_MAX_VA_BITSIZE-updateBits;
+ m_pkt_data.addr.pkt_bits = updateBits;
+ m_pkt_data.addr.val &= ~validMask;
+ m_pkt_data.addr.val |= (partAddrVal & validMask);
+ if(updateBits > m_pkt_data.addr.valid_bits)
+ m_pkt_data.addr.valid_bits = updateBits;
+}
+
+void EtmV3TrcPacket::UpdateDataAddress(const uint32_t value, const uint8_t valid_bits)
+{
+ // ETMv3 data addresses 32 bits.
+ uint32_t validMask = 0xFFFFFFFF;
+ validMask >>= 32-valid_bits;
+ m_pkt_data.addr.pkt_bits = valid_bits;
+ m_pkt_data.addr.val &= ~validMask;
+ m_pkt_data.addr.val |= (value & validMask);
+ if(valid_bits > m_pkt_data.addr.valid_bits)
+ m_pkt_data.addr.valid_bits = valid_bits;
+ m_pkt_data.data.update_addr = 1;
+}
+
+void EtmV3TrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits)
+{
+ uint64_t validMask = ~0ULL;
+ validMask >>= 64-updateBits;
+ m_pkt_data.timestamp &= ~validMask;
+ m_pkt_data.timestamp |= (tsVal & validMask);
+ m_pkt_data.ts_update_bits = updateBits;
+}
+
+
+
+void EtmV3TrcPacket::SetException( const ocsd_armv7_exception type,
+ const uint16_t number,
+ const bool cancel,
+ const bool cm_type,
+ const int irq_n /*= 0*/,
+ const int resume /* = 0*/)
+{
+ // initial data
+ m_pkt_data.exception.bits.cancel = cancel ? 1 : 0;
+ m_pkt_data.exception.bits.cm_irq_n = irq_n;
+ m_pkt_data.exception.bits.cm_resume = resume;
+ m_pkt_data.exception.bits.cm_type = cm_type ? 1 : 0;
+ m_pkt_data.exception.number = number;
+ m_pkt_data.exception.type = type;
+
+ // mark as valid in this packet
+ m_pkt_data.exception.bits.present = 1;
+}
+
+bool EtmV3TrcPacket::UpdateAtomFromPHdr(const uint8_t pHdr, const bool cycleAccurate)
+{
+ bool bValid = true;
+ uint8_t E = 0, N = 0;
+ if(!cycleAccurate)
+ {
+ if((pHdr & 0x3) == 0x0)
+ {
+ E = ((pHdr >> 2) & 0xF);
+ N = (pHdr & 0x40) ? 1 : 0;
+ m_pkt_data.atom.num = E+N;
+ m_pkt_data.atom.En_bits = (((uint32_t)0x1) << E) - 1;
+ m_pkt_data.p_hdr_fmt = 1;
+ }
+ else if((pHdr & 0x3) == 0x2)
+ {
+ m_pkt_data.atom.num = 2;
+ m_pkt_data.p_hdr_fmt = 2;
+ m_pkt_data.atom.En_bits = (pHdr & 0x8 ? 0 : 1) | (pHdr & 0x4 ? 0 : 0x2);
+ }
+ else
+ bValid = false;
+ }
+ else
+ {
+ uint8_t pHdr_code = pHdr & 0xA3;
+ switch(pHdr_code)
+ {
+ case 0x80:
+ m_pkt_data.p_hdr_fmt = 1;
+ E = ((pHdr >> 2) & 0x7);
+ N = (pHdr & 0x40) ? 1 : 0;
+ m_pkt_data.atom.num = E+N;
+ if(m_pkt_data.atom.num)
+ {
+ m_pkt_data.atom.En_bits = (((uint32_t)0x1) << E) - 1;
+ m_pkt_data.cycle_count = E+N;
+ }
+ else
+ bValid = false; // deprecated 8b'10000000 code
+
+ break;
+
+ case 0x82:
+ m_pkt_data.p_hdr_fmt = 2;
+ if(pHdr & 0x10)
+ {
+ m_pkt_data.p_hdr_fmt = 4;
+ m_pkt_data.atom.num = 1;
+ m_pkt_data.cycle_count = 0;
+ m_pkt_data.atom.En_bits = pHdr & 0x04 ? 0 : 1;
+ }
+ else
+ {
+ m_pkt_data.atom.num = 2;
+ m_pkt_data.cycle_count = 1;
+ m_pkt_data.atom.En_bits = (pHdr & 0x8 ? 0 : 1) | (pHdr & 0x4 ? 0 : 0x2);
+ }
+ break;
+
+ case 0xA0:
+ m_pkt_data.p_hdr_fmt = 3;
+ m_pkt_data.cycle_count = ((pHdr >> 2) & 7) + 1;
+ E = pHdr & 0x40 ? 1 : 0;
+ m_pkt_data.atom.num = E;
+ m_pkt_data.atom.En_bits = E;
+ break;
+
+ default:
+ bValid = false;
+ break;
+
+ }
+ }
+ return bValid;
+}
+
+EtmV3TrcPacket &EtmV3TrcPacket::operator =(const ocsd_etmv3_pkt* p_pkt)
+{
+ m_pkt_data = *p_pkt;
+ return *this;
+}
+
+ // printing
+void EtmV3TrcPacket::toString(std::string &str) const
+{
+ const char *name;
+ const char *desc;
+ std::string valStr, ctxtStr = "";
+
+ name = packetTypeName(m_pkt_data.type, &desc);
+ str = name + (std::string)" : " + desc;
+
+ switch(m_pkt_data.type)
+ {
+ // print the original header type for the bad sequences.
+ case ETM3_PKT_BAD_SEQUENCE:
+ case ETM3_PKT_BAD_TRACEMODE:
+ name = packetTypeName(m_pkt_data.err_type,0);
+ str += "[" + (std::string)name + "]";
+ break;
+
+ case ETM3_PKT_BRANCH_ADDRESS:
+ getBranchAddressStr(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM3_PKT_I_SYNC_CYCLE:
+ case ETM3_PKT_I_SYNC:
+ getISyncStr(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM3_PKT_P_HDR:
+ getAtomStr(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM3_PKT_CYCLE_COUNT:
+ {
+ std::ostringstream oss;
+ oss << "; Cycles=" << m_pkt_data.cycle_count;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_CONTEXT_ID:
+ {
+ std::ostringstream oss;
+ oss << "; CtxtID=" << std::hex << "0x" << m_pkt_data.context.ctxtID;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_VMID:
+ {
+ std::ostringstream oss;
+ oss << "; VMID=" << std::hex << "0x" << m_pkt_data.context.VMID;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_TIMESTAMP:
+ {
+ std::ostringstream oss;
+ oss << "; TS=" << std::hex << "0x" << m_pkt_data.timestamp << " (" << std::dec << m_pkt_data.timestamp << ") ";
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_OOO_DATA:
+ {
+ std::ostringstream oss;
+ oss << "; Val=" << std::hex << "0x" << m_pkt_data.data.value;
+ oss << "; OO_Tag=" << std::hex << "0x" << m_pkt_data.data.ooo_tag;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_VAL_NOT_TRACED:
+ if(m_pkt_data.data.update_addr)
+ {
+ trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits,
+ m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits);
+ str += "; Addr=" + valStr;
+ }
+ break;
+
+ case ETM3_PKT_OOO_ADDR_PLC:
+ if(m_pkt_data.data.update_addr)
+ {
+ trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits,
+ m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits);
+ str += "; Addr=" + valStr;
+ }
+ {
+ std::ostringstream oss;
+ oss << "; OO_Tag=" << std::hex << "0x" << m_pkt_data.data.ooo_tag;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_NORM_DATA:
+ if(m_pkt_data.data.update_addr)
+ {
+ trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits,
+ m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits);
+ str += "; Addr=" + valStr;
+ }
+ if(m_pkt_data.data.update_dval)
+ {
+ std::ostringstream oss;
+ oss << "; Val=" << std::hex << "0x" << m_pkt_data.data.value;
+ str += oss.str();
+ }
+ break;
+ }
+}
+
+void EtmV3TrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const
+{
+ // no formatting implemented at present.
+ toString(str);
+}
+
+const char *EtmV3TrcPacket::packetTypeName(const ocsd_etmv3_pkt_type type, const char **ppDesc) const
+{
+ const char *pName = "I_RESERVED";
+ const char *pDesc = "Reserved Packet Header";
+
+ switch(type)
+ {
+// markers for unknown packets
+ // case ETM3_PKT_NOERROR:, //!< no error in packet - supplimentary data.
+ case ETM3_PKT_NOTSYNC: //!< no sync found yet
+ pName = "NOTSYNC";
+ pDesc = "Trace Stream not synchronised";
+ break;
+
+ case ETM3_PKT_INCOMPLETE_EOT: //!< flushing incomplete/empty packet at end of trace.
+ pName = "INCOMPLETE_EOT.";
+ pDesc = "Incomplete packet at end of trace data.";
+ break;
+
+// markers for valid packets
+ case ETM3_PKT_BRANCH_ADDRESS:
+ pName = "BRANCH_ADDRESS";
+ pDesc = "Branch address.";
+ break;
+
+ case ETM3_PKT_A_SYNC:
+ pName = "A_SYNC";
+ pDesc = "Alignment Synchronisation.";
+ break;
+
+ case ETM3_PKT_CYCLE_COUNT:
+ pName = "CYCLE_COUNT";
+ pDesc = "Cycle Count.";
+ break;
+
+ case ETM3_PKT_I_SYNC:
+ pName = "I_SYNC";
+ pDesc = "Instruction Packet synchronisation.";
+ break;
+
+ case ETM3_PKT_I_SYNC_CYCLE:
+ pName = "I_SYNC_CYCLE";
+ pDesc = "Instruction Packet synchronisation with cycle count.";
+ break;
+
+ case ETM3_PKT_TRIGGER:
+ pName = "TRIGGER";
+ pDesc = "Trace Trigger Event.";
+ break;
+
+ case ETM3_PKT_P_HDR:
+ pName = "P_HDR";
+ pDesc = "Atom P-header.";
+ break;
+
+ case ETM3_PKT_STORE_FAIL:
+ pName = "STORE_FAIL";
+ pDesc = "Data Store Failed.";
+ break;
+
+ case ETM3_PKT_OOO_DATA:
+ pName = "OOO_DATA";
+ pDesc = "Out of Order data value packet.";
+ break;
+
+ case ETM3_PKT_OOO_ADDR_PLC:
+ pName = "OOO_ADDR_PLC";
+ pDesc = "Out of Order data address placeholder.";
+ break;
+
+ case ETM3_PKT_NORM_DATA:
+ pName = "NORM_DATA";
+ pDesc = "Data trace packet.";
+ break;
+
+ case ETM3_PKT_DATA_SUPPRESSED:
+ pName = "DATA_SUPPRESSED";
+ pDesc = "Data trace suppressed.";
+ break;
+
+ case ETM3_PKT_VAL_NOT_TRACED:
+ pName = "VAL_NOT_TRACED";
+ pDesc = "Data trace value not traced.";
+ break;
+
+ case ETM3_PKT_IGNORE:
+ pName = "IGNORE";
+ pDesc = "Packet ignored.";
+ break;
+
+ case ETM3_PKT_CONTEXT_ID:
+ pName = "CONTEXT_ID";
+ pDesc = "Context ID change.";
+ break;
+
+ case ETM3_PKT_VMID:
+ pName = "VMID";
+ pDesc = "VMID change.";
+ break;
+
+ case ETM3_PKT_EXCEPTION_ENTRY:
+ pName = "EXCEPTION_ENTRY";
+ pDesc = "Exception entry data marker.";
+ break;
+
+ case ETM3_PKT_EXCEPTION_EXIT:
+ pName = "EXCEPTION_EXIT";
+ pDesc = "Exception return.";
+ break;
+
+ case ETM3_PKT_TIMESTAMP:
+ pName = "TIMESTAMP";
+ pDesc = "Timestamp Value.";
+ break;
+
+// internal processing types
+ // case ETM3_PKT_BRANCH_OR_BYPASS_EOT: not externalised
+
+// packet errors
+ case ETM3_PKT_BAD_SEQUENCE:
+ pName = "BAD_SEQUENCE";
+ pDesc = "Invalid sequence for packet type.";
+ break;
+
+ case ETM3_PKT_BAD_TRACEMODE:
+ pName = "BAD_TRACEMODE";
+ pDesc = "Invalid packet type for this trace mode.";
+ break;
+
+ // leave thest unchanged.
+ case ETM3_PKT_RESERVED:
+ default:
+ break;
+
+ }
+
+ if(ppDesc) *ppDesc = pDesc;
+ return pName;
+}
+
+void EtmV3TrcPacket::getBranchAddressStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ std::string subStr;
+
+ // print address.
+ trcPrintableElem::getValStr(subStr,32,m_pkt_data.addr.valid_bits,
+ m_pkt_data.addr.val,true,m_pkt_data.addr.pkt_bits);
+ oss << "Addr=" << subStr << "; ";
+
+ // current ISA if changed.
+ if(m_pkt_data.curr_isa != m_pkt_data.prev_isa)
+ {
+ getISAStr(subStr);
+ oss << subStr;
+ }
+
+ // S / NS etc if changed.
+ if(m_pkt_data.context.updated)
+ {
+ oss << (m_pkt_data.context.curr_NS ? "NS; " : "S; ");
+ oss << (m_pkt_data.context.curr_Hyp ? "Hyp; " : "");
+ }
+
+ // exception?
+ if(m_pkt_data.exception.bits.present)
+ {
+ getExcepStr(subStr);
+ oss << subStr;
+ }
+ valStr = oss.str();
+}
+
+void EtmV3TrcPacket::getAtomStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ uint32_t bitpattern = m_pkt_data.atom.En_bits; // arranged LSBit oldest, MSbit newest
+
+ if(!m_pkt_data.cycle_count)
+ {
+ for(int i = 0; i < m_pkt_data.atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ bitpattern >>= 1;
+ }
+ }
+ else
+ {
+ switch(m_pkt_data.p_hdr_fmt)
+ {
+ case 1:
+ for(int i = 0; i < m_pkt_data.atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "WE" : "WN"); // in spec read L->R, oldest->newest
+ bitpattern >>= 1;
+ }
+ break;
+
+ case 2:
+ oss << "W";
+ for(int i = 0; i < m_pkt_data.atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ bitpattern >>= 1;
+ }
+ break;
+
+ case 3:
+ for(uint32_t i = 0; i < m_pkt_data.cycle_count; i++)
+ oss << "W";
+ if(m_pkt_data.atom.num)
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ break;
+ }
+ oss << "; Cycles=" << m_pkt_data.cycle_count;
+ }
+ valStr = oss.str();
+}
+
+void EtmV3TrcPacket::getISyncStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" };
+
+ // reason.
+ oss << "(" << reason[(int)m_pkt_data.isync_info.reason] << "); ";
+
+ // full address.
+ if(!m_pkt_data.isync_info.no_address)
+ {
+ if(m_pkt_data.isync_info.has_LSipAddress)
+ oss << "Data Instr Addr=0x";
+ else
+ oss << "Addr=0x";
+ oss << std::hex << std::setfill('0') << std::setw(8) << m_pkt_data.addr.val << "; ";
+ }
+
+ oss << (m_pkt_data.context.curr_NS ? "NS; " : "S; ");
+ oss << (m_pkt_data.context.curr_Hyp ? "Hyp; " : " ");
+
+ if(m_pkt_data.context.updated_c)
+ {
+ oss << "CtxtID=" << std::hex << m_pkt_data.context.ctxtID << "; ";
+ }
+
+ if(m_pkt_data.isync_info.no_address)
+ {
+ valStr = oss.str();
+ return; // bail out at this point if a data only ISYNC
+ }
+
+ std::string isaStr;
+ getISAStr(isaStr);
+ oss << isaStr;
+
+ if(m_pkt_data.isync_info.has_cycle_count)
+ {
+ oss << "Cycles=" << std::dec << m_pkt_data.cycle_count << "; ";
+ }
+
+ if(m_pkt_data.isync_info.has_LSipAddress)
+ {
+ std::string addrStr;
+
+ // extract address updata.
+ trcPrintableElem::getValStr(addrStr,32,m_pkt_data.data.addr.valid_bits,
+ m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits);
+ oss << "Curr Instr Addr=" << addrStr << ";";
+ }
+ valStr = oss.str();
+}
+
+void EtmV3TrcPacket::getISAStr(std::string &isaStr) const
+{
+ std::ostringstream oss;
+ oss << "ISA=";
+ switch(m_pkt_data.curr_isa)
+ {
+ case ocsd_isa_arm:
+ oss << "ARM(32); ";
+ break;
+
+ case ocsd_isa_thumb2:
+ oss << "Thumb2; ";
+ break;
+
+ case ocsd_isa_aarch64:
+ oss << "AArch64; ";
+ break;
+
+ case ocsd_isa_tee:
+ oss << "ThumbEE; ";
+ break;
+
+ case ocsd_isa_jazelle:
+ oss << "Jazelle; ";
+ break;
+
+ default:
+ case ocsd_isa_unknown:
+ oss << "Unknown; ";
+ break;
+ }
+ isaStr = oss.str();
+}
+
+void EtmV3TrcPacket::getExcepStr(std::string &excepStr) const
+{
+ static const char *ARv7Excep[] = {
+ "No Exception", "Debug Halt", "SMC", "Hyp",
+ "Async Data Abort", "Jazelle", "Reserved", "Reserved",
+ "PE Reset", "Undefined Instr", "SVC", "Prefetch Abort",
+ "Data Fault", "Generic", "IRQ", "FIQ"
+ };
+
+ static const char *MExcep[] = {
+ "No Exception", "IRQ1", "IRQ2", "IRQ3",
+ "IRQ4", "IRQ5", "IRQ6", "IRQ7",
+ "IRQ0","usage Fault","NMI","SVC",
+ "DebugMonitor", "Mem Manage","PendSV","SysTick",
+ "Reserved","PE Reset","Reserved","HardFault",
+ "Reserved","BusFault","Reserved","Reserved"
+ };
+
+ std::ostringstream oss;
+ oss << "Exception=";
+
+ if(m_pkt_data.exception.bits.cm_type)
+ {
+ if(m_pkt_data.exception.number < 0x18)
+ oss << MExcep[m_pkt_data.exception.number];
+ else
+ oss << "IRQ" << std::dec << (m_pkt_data.exception.number - 0x10);
+ if(m_pkt_data.exception.bits.cm_resume)
+ oss << "; Resume=" << m_pkt_data.exception.bits.cm_resume;
+ if(m_pkt_data.exception.bits.cancel)
+ oss << "; Cancel prev instr";
+ }
+ else
+ {
+ oss << ARv7Excep[m_pkt_data.exception.number] << "; ";
+ if(m_pkt_data.exception.bits.cancel)
+ oss << "; Cancel prev instr";
+ }
+ excepStr = oss.str();
+}
+/* End of File trc_pkt_elem_etmv3.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp b/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp
new file mode 100644
index 0000000..7871619
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp
@@ -0,0 +1,122 @@
+/*
+ * \file trc_pkt_proc_etmv3.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opencsd/etmv3/trc_pkt_proc_etmv3.h"
+#include "trc_pkt_proc_etmv3_impl.h"
+#include "common/ocsd_error.h"
+
+#ifdef __GNUC__
+// G++ doesn't like the ## pasting
+#define ETMV3_PKTS_NAME "PKTP_ETMV3"
+#else
+#define ETMV3_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_"##OCSD_BUILTIN_DCD_ETMV3
+#endif
+
+static const uint32_t ETMV3_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON |
+ ETMV3_OPFLG_UNFORMATTED_SOURCE;
+
+TrcPktProcEtmV3::TrcPktProcEtmV3() : TrcPktProcBase(ETMV3_PKTS_NAME),
+ m_pProcessor(0)
+{
+ m_supported_op_flags = ETMV3_SUPPORTED_OP_FLAGS;
+}
+
+TrcPktProcEtmV3::TrcPktProcEtmV3(int instIDNum) : TrcPktProcBase(ETMV3_PKTS_NAME, instIDNum),
+ m_pProcessor(0)
+{
+ m_supported_op_flags = ETMV3_SUPPORTED_OP_FLAGS;
+}
+
+TrcPktProcEtmV3::~TrcPktProcEtmV3()
+{
+ if(m_pProcessor)
+ delete m_pProcessor;
+ m_pProcessor = 0;
+}
+
+ocsd_err_t TrcPktProcEtmV3::onProtocolConfig()
+{
+ if(m_pProcessor == 0)
+ {
+ m_pProcessor = new (std::nothrow) EtmV3PktProcImpl();
+ if(m_pProcessor == 0)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM));
+ return OCSD_ERR_MEM;
+ }
+ m_pProcessor->Initialise(this);
+ }
+ return m_pProcessor->Configure(m_config);
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV3::processData( const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ if(m_pProcessor)
+ return m_pProcessor->processData(index,dataBlockSize,pDataBlock,numBytesProcessed);
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV3::onEOT()
+{
+ if(m_pProcessor)
+ return m_pProcessor->onEOT();
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV3::onReset()
+{
+ if(m_pProcessor)
+ return m_pProcessor->onReset();
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV3::onFlush()
+{
+ if(m_pProcessor)
+ return m_pProcessor->onFlush();
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+const bool TrcPktProcEtmV3::isBadPacket() const
+{
+ if(m_pProcessor)
+ return m_pProcessor->isBadPacket();
+ return false;
+}
+
+/* End of File trc_pkt_proc_etmv3.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp
new file mode 100644
index 0000000..fc39a5e
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp
@@ -0,0 +1,1224 @@
+/*
+ * \file trc_pkt_proc_etmv3_impl.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "trc_pkt_proc_etmv3_impl.h"
+
+EtmV3PktProcImpl::EtmV3PktProcImpl() :
+ m_isInit(false),
+ m_interface(0)
+{
+}
+
+EtmV3PktProcImpl::~EtmV3PktProcImpl()
+{
+}
+
+ocsd_err_t EtmV3PktProcImpl::Configure(const EtmV3Config *p_config)
+{
+ ocsd_err_t err = OCSD_OK;
+ if(p_config != 0)
+ {
+ m_config = *p_config;
+ m_chanIDCopy = m_config.getTraceID();
+ }
+ else
+ {
+ err = OCSD_ERR_INVALID_PARAM_VAL;
+ if(m_isInit)
+ m_interface->LogError(ocsdError(OCSD_ERR_SEV_ERROR,err));
+ }
+ return err;
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::processData(const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_bytesProcessed = 0;
+
+ while( ( (m_bytesProcessed < dataBlockSize) ||
+ ((m_bytesProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) )
+ && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ try
+ {
+ switch(m_process_state)
+ {
+ case WAIT_SYNC:
+ if(!m_bStartOfSync)
+ m_packet_index = index + m_bytesProcessed;
+ m_bytesProcessed += waitForSync(dataBlockSize-m_bytesProcessed,pDataBlock+m_bytesProcessed);
+ break;
+
+ case PROC_HDR:
+ m_packet_index = index + m_bytesProcessed;
+ processHeaderByte(pDataBlock[m_bytesProcessed++]);
+ break;
+
+ case PROC_DATA:
+ processPayloadByte(pDataBlock [m_bytesProcessed++]);
+ break;
+
+ case SEND_PKT:
+ resp = outputPacket();
+ break;
+ }
+ }
+ catch(ocsdError &err)
+ {
+ m_interface->LogError(err);
+ if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) ||
+ (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR))
+ {
+ // send invalid packets up the pipe to let the next stage decide what to do.
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ // bail out on any other error.
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+ }
+ catch(...)
+ {
+ /// vv bad at this point.
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+ ocsdError fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_chanIDCopy);
+ fatal.setMessage("Unknown System Error decoding trace.");
+ m_interface->LogError(fatal);
+ }
+ }
+
+ *numBytesProcessed = m_bytesProcessed;
+ return resp;
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ // if we have a partial packet then send to attached sinks
+ if(m_currPacketData.size() != 0)
+ {
+ // TBD: m_curr_packet.updateErrType(ETM4_ETM3_PKT_I_INCOMPLETE_EOT);
+ resp = outputPacket();
+ InitPacketState();
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::onReset()
+{
+ InitProcessorState();
+ return OCSD_RESP_CONT;
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::onFlush()
+{
+ // packet processor never holds on to flushable data (may have partial packet,
+ // but any full packets are immediately sent)
+ return OCSD_RESP_CONT;
+}
+
+void EtmV3PktProcImpl::Initialise(TrcPktProcEtmV3 *p_interface)
+{
+ if(p_interface)
+ {
+ m_interface = p_interface;
+ m_isInit = true;
+
+ }
+ InitProcessorState();
+ /* not using pattern matcher for sync at present
+ static const uint8_t a_sync[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 };
+ m_syncMatch.setPattern(a_sync, sizeof(a_sync));*/
+}
+
+void EtmV3PktProcImpl::InitProcessorState()
+{
+ m_bStreamSync = false; // not synced
+ m_process_state = WAIT_SYNC; // waiting for sync
+ m_bStartOfSync = false; // not seen start of sync packet
+ m_curr_packet.ResetState(); // reset intra packet state
+ InitPacketState(); // set curr packet state
+ m_bSendPartPkt = false;
+}
+
+void EtmV3PktProcImpl::InitPacketState()
+{
+ m_bytesExpectedThisPkt = 0;
+ m_BranchPktNeedsException = false;
+ m_bIsync_got_cycle_cnt = false;
+ m_bIsync_get_LSiP_addr = false;
+ m_IsyncInfoIdx = false;
+ m_bExpectingDataAddress = false;
+ m_bFoundDataAddress = false;
+ m_currPacketData.clear();
+ m_currPktIdx = 0; // index into processed bytes in current packet
+ m_curr_packet.Clear();
+
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::outputPacket()
+{
+ ocsd_datapath_resp_t dp_resp = OCSD_RESP_FATAL_NOT_INIT;
+ if(m_isInit)
+ {
+ ocsd_etmv3_pkt_type type = m_curr_packet.getType();
+ if(!m_bSendPartPkt)
+ {
+ dp_resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&type,m_currPacketData);
+ m_process_state = m_bStreamSync ? PROC_HDR : WAIT_SYNC; // need a header next time, or still waiting to sync.
+ m_currPacketData.clear();
+ }
+ else
+ {
+ // sending part packet, still some data in the main packet
+ dp_resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&type,m_partPktData);
+ m_process_state = m_post_part_pkt_state;
+ m_packet_index += m_partPktData.size();
+ m_bSendPartPkt = false;
+ m_curr_packet.SetType(m_post_part_pkt_type);
+ }
+ }
+ return dp_resp;
+}
+
+void EtmV3PktProcImpl::setBytesPartPkt(int numBytes, process_state nextState, const ocsd_etmv3_pkt_type nextType)
+{
+ m_partPktData.clear();
+ for(int i=0; i < numBytes; i++)
+ {
+ m_partPktData.push_back(m_currPacketData[i]);
+ }
+ m_currPacketData.erase(m_currPacketData.begin(), m_currPacketData.begin()+numBytes);
+ m_bSendPartPkt = true;
+ m_post_part_pkt_state = nextState;
+ m_post_part_pkt_type = nextType;
+}
+
+uint32_t EtmV3PktProcImpl::waitForSync(const uint32_t dataBlockSize, const uint8_t *pDataBlock)
+{
+ uint8_t currByte;
+ uint32_t bytesProcessed = 0;
+ bool bSendBlock = false;
+
+ // need to wait for the first sync packet
+ while(!bSendBlock && (bytesProcessed < dataBlockSize))
+ {
+ currByte = pDataBlock[bytesProcessed++];
+ // TBD: forced sync point
+
+ if(m_bStartOfSync)
+ {
+ // need to handle consecutive 0 bytes followed by genuine A-SYNC.
+
+ m_currPacketData.push_back(currByte);
+ if((currByte == 0x80) && (m_currPacketData.size() >= 6))
+ {
+ // it is a sync packet possibly with leading zeros
+ bSendBlock = true;
+ if(m_currPacketData.size() > 6)
+ {
+ m_currPacketData.pop_back();
+ bytesProcessed--; // return 0x80 to the input buffer to re-process next pass after stripping 0's
+ setBytesPartPkt(m_currPacketData.size()-5,WAIT_SYNC,ETM3_PKT_NOTSYNC);
+ }
+ else
+ {
+ m_bStreamSync = true;
+ m_curr_packet.SetType(ETM3_PKT_A_SYNC);
+ }
+ }
+ else if(currByte != 0x00)
+ {
+ m_bStartOfSync = false; // not a sync packet
+ }
+ else if(m_currPacketData.size() >= 13) // 13 0's, strip 8 of them...
+ {
+ setBytesPartPkt(8,WAIT_SYNC,ETM3_PKT_NOTSYNC);
+ bSendBlock = true;
+ }
+ }
+ else // not seen a start of sync candidate yet
+ {
+ if(currByte == 0x00) // could be the start of a-sync
+ {
+ if(m_currPacketData.size() == 0)
+ {
+ m_currPacketData.push_back(currByte);
+ m_bStartOfSync = true;
+ }
+ else
+ {
+ bytesProcessed--;
+ bSendBlock = true; // send none sync packet data, re-process this byte next time.
+ m_curr_packet.SetType(ETM3_PKT_NOTSYNC); // send unsynced data packet.
+ }
+ }
+ else
+ {
+ //save a byte - not start of a-sync
+ m_currPacketData.push_back(currByte);
+
+ // done all data in this block, or got 16 unsynced bytes
+ if((bytesProcessed == dataBlockSize) || (m_currPacketData.size() == 16))
+ {
+ bSendBlock = true; // send none sync packet block
+ m_curr_packet.SetType(ETM3_PKT_NOTSYNC); // send unsynced data packet.
+ }
+ }
+ }
+ }
+ if(bSendBlock)
+ SendPacket();
+ return bytesProcessed;
+}
+
+ocsd_err_t EtmV3PktProcImpl::processHeaderByte(uint8_t by)
+{
+ InitPacketState(); // new packet, clear old single packet state (retains intra packet state).
+
+ // save byte
+ m_currPacketData.push_back(by);
+
+ m_process_state = PROC_DATA; // assume next is data packet
+
+ // check for branch address 0bCxxxxxxx1
+ if((by & 0x01) == 0x01 ) {
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS);
+ m_BranchPktNeedsException = false;
+ if((by & 0x80) != 0x80) {
+ // no continuation - 1 byte branch same in alt and std...
+ if((by == 0x01) && (m_interface->getComponentOpMode() & ETMV3_OPFLG_UNFORMATTED_SOURCE))
+ {
+ // TBD: need to fix up for handling bypassed ETM stream at some point.
+ throwUnsupportedErr("Bypassed ETM stream not supported in this version of the decoder.");
+ // could be EOTrace marker from bypassed formatter
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_OR_BYPASS_EOT);
+ }
+ else
+ {
+ OnBranchAddress();
+ SendPacket(); // mark ready to send.
+ }
+ }
+ }
+ // check for p-header - 0b1xxxxxx0
+ else if((by & 0x81) == 0x80) {
+ m_curr_packet.SetType(ETM3_PKT_P_HDR);
+ if(m_curr_packet.UpdateAtomFromPHdr(by,m_config.isCycleAcc()))
+ SendPacket();
+ else
+ throwPacketHeaderErr("Invalid P-Header.");
+ }
+ // check 0b0000xx00 group
+ else if((by & 0xF3) == 0x00) {
+
+ // A-Sync
+ if(by == 0x00) {
+ m_curr_packet.SetType(ETM3_PKT_A_SYNC);
+ }
+ // cycle count
+ else if(by == 0x04) {
+ m_curr_packet.SetType(ETM3_PKT_CYCLE_COUNT);
+ }
+ // I-Sync
+ else if(by == 0x08) {
+ m_curr_packet.SetType(ETM3_PKT_I_SYNC);
+ m_bIsync_got_cycle_cnt = false;
+ m_bIsync_get_LSiP_addr = false;
+ }
+ // trigger
+ else if(by == 0x0C) {
+ m_curr_packet.SetType(ETM3_PKT_TRIGGER);
+ // no payload - just send it.
+ SendPacket();
+ }
+ }
+ // check remaining 0bxxxxxx00 codes
+ else if((by & 0x03 )== 0x00) {
+ // OoO data 0b0xx0xx00
+ if((by & 0x93 )== 0x00) {
+ if(!m_config.isDataValTrace()) {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (out of order data) - not tracing data values.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_OOO_DATA);
+ uint8_t size = ((by & 0x0C) >> 2);
+ // header contains a count of the data to follow
+ // size 3 == 4 bytes, other sizes == size bytes
+ if(size == 0)
+ {
+ m_curr_packet.SetDataOOOTag((by >> 5) & 0x3);
+ m_curr_packet.SetDataValue(0);
+ SendPacket();
+ }
+ else
+ m_bytesExpectedThisPkt = (short)(1 + ((size == 3) ? 4 : size));
+ }
+ // I-Sync + cycle count
+ else if(by == 0x70) {
+ m_curr_packet.SetType(ETM3_PKT_I_SYNC_CYCLE);
+ m_bIsync_got_cycle_cnt = false;
+ m_bIsync_get_LSiP_addr = false;
+ }
+ // store failed
+ else if(by == 0x50) {
+ if(!m_config.isDataValTrace())
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (store failed) - not tracing data values.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_STORE_FAIL);
+ SendPacket();
+ }
+ // OoO placeholder 0b01x1xx00
+ else if((by & 0xD3 )== 0x50) {
+ m_curr_packet.SetType(ETM3_PKT_OOO_ADDR_PLC);
+ if(!m_config.isDataTrace())
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (out of order placeholder) - not tracing data.");
+ }
+ // expecting data address if flagged and address tracing enabled (flag can be set even if address tracing disabled)
+ m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace();
+ m_bFoundDataAddress = false;
+ m_curr_packet.SetDataOOOTag((by >> 2) & 0x3);
+ if(!m_bExpectingDataAddress) {
+ SendPacket();
+ }
+ }
+ // vmid 0b00111100
+ else if(by == 0x3c) {
+ m_curr_packet.SetType(ETM3_PKT_VMID);
+ }
+ else
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_RESERVED);
+ throwPacketHeaderErr("Packet header reserved encoding");
+ }
+ }
+ // normal data 0b00x0xx10
+ else if((by & 0xD3 )== 0x02) {
+ uint8_t size = ((by & 0x0C) >> 2);
+ if(!m_config.isDataTrace()) {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (normal data) - not tracing data.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_NORM_DATA);
+ m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace();
+ m_bFoundDataAddress = false;
+
+ // set this with the data bytes expected this packet, plus the header byte.
+ m_bytesExpectedThisPkt = (short)( 1 + ((size == 3) ? 4 : size));
+ if(!m_bExpectingDataAddress && (m_bytesExpectedThisPkt == 1)) {
+ // single byte data packet, value = 0;
+ m_curr_packet.SetDataValue(0);
+ SendPacket();
+ }
+
+ }
+ // data suppressed 0b01100010
+ else if(by == 0x62) {
+ if(!m_config.isDataTrace())
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (data suppressed) - not tracing data.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_DATA_SUPPRESSED);
+ SendPacket();
+ }
+ // value not traced 0b011x1010
+ else if((by & 0xEF )== 0x6A) {
+ if(!m_config.isDataTrace()) {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (value not traced) - not tracing data.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_VAL_NOT_TRACED);
+ m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace();
+ m_bFoundDataAddress = false;
+ if(!m_bExpectingDataAddress) {
+ SendPacket();
+ }
+ }
+ // ignore 0b01100110
+ else if(by == 0x66) {
+ m_curr_packet.SetType(ETM3_PKT_IGNORE);
+ SendPacket();
+ }
+ // context ID 0b01101110
+ else if(by == 0x6E) {
+ m_curr_packet.SetType(ETM3_PKT_CONTEXT_ID);
+ m_bytesExpectedThisPkt = (short)(1 + m_config.CtxtIDBytes());
+ }
+ // exception return 0b01110110
+ else if(by == 0x76) {
+ m_curr_packet.SetType(ETM3_PKT_EXCEPTION_EXIT);
+ SendPacket();
+ }
+ // exception entry 0b01111110
+ else if(by == 0x7E) {
+ m_curr_packet.SetType(ETM3_PKT_EXCEPTION_ENTRY);
+ SendPacket();
+ }
+ // timestamp packet 0b01000x10
+ else if((by & 0xFB )== 0x42)
+ {
+ m_curr_packet.SetType(ETM3_PKT_TIMESTAMP);
+ }
+ else
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_RESERVED);
+ throwPacketHeaderErr("Packet header reserved encoding.");
+ }
+ return OCSD_OK;
+}
+
+ocsd_err_t EtmV3PktProcImpl::processPayloadByte(uint8_t by)
+{
+ bool bTopBitSet = false;
+ bool packetDone = false;
+
+ // pop byte into buffer
+ m_currPacketData.push_back(by);
+
+ switch(m_curr_packet.getType()) {
+ default:
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_PKT_INTERP_FAIL,m_packet_index,m_chanIDCopy,"Interpreter failed - cannot process payload for unexpected or unsupported packet.");
+ break;
+
+ case ETM3_PKT_BRANCH_ADDRESS:
+ bTopBitSet = (bool)((by & 0x80) == 0x80);
+ if(m_config.isAltBranch()) // etm implements the alternative branch encoding
+ {
+ if(!bTopBitSet) // no continuation
+ {
+ if(!m_BranchPktNeedsException)
+ {
+ if((by & 0xC0) == 0x40)
+ m_BranchPktNeedsException = true;
+ else
+ packetDone = true;
+ }
+ else
+ packetDone = true;
+ }
+ }
+ else
+ {
+ // standard encoding < 5 bytes cannot be exception branch
+ // 5 byte packet
+ if(m_currPacketData.size() == 5) {
+ if((by & 0xC0) == 0x40)
+ // expecting follow up byte(s)
+ m_BranchPktNeedsException = true;
+ else
+ packetDone = true;
+ }
+ // waiting for exception packet
+ else if(m_BranchPktNeedsException){
+ if(!bTopBitSet)
+ packetDone = true;
+ }
+ else {
+ // not exception - end of packets
+ if(!bTopBitSet)
+ packetDone = true;
+ }
+ }
+
+ if(packetDone)
+ {
+ OnBranchAddress();
+ SendPacket();
+ }
+ break;
+
+ case ETM3_PKT_BRANCH_OR_BYPASS_EOT:
+ /*
+ if((by != 0x00) || ( m_currPacketData.size() == ETM3_PKT_BUFF_SIZE)) {
+ if(by == 0x80 && ( m_currPacketData.size() == 7)) {
+ // branch 0 followed by A-sync!
+ m_currPacketData.size() = 1;
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS;
+ SendPacket();
+ memcpy(m_currPacketData, &m_currPacketData[1],6);
+ m_currPacketData.size() = 6;
+ m_curr_packet.SetType(ETM3_PKT_A_SYNC;
+ SendPacket();
+ }
+ else if( m_currPacketData.size() == 2) {
+ // branch followed by another byte
+ m_currPacketData.size() = 1;
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS;
+ SendPacket();
+ ProcessHeaderByte(by);
+ }
+ else if(by == 0x00) {
+ // end of buffer...output something - incomplete / unknown.
+ SendPacket();
+ }
+ else if(by == 0x01) {
+ // 0x01 - 0x00 x N - 0x1
+ // end of buffer...output something
+ m_currPacketData.size()--;
+ SendPacket();
+ ProcessHeaderByte(by);
+ }
+ else {
+ // branch followed by unknown sequence
+ int oldidx = m_currPacketData.size();
+ m_currPacketData.size() = 1;
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS;
+ SendPacket();
+ oldidx--;
+ memcpy(m_currPacketData, &m_currPacketData[1],oldidx);
+ m_currPacketData.size() = oldidx;
+ SendBadPacket("ERROR : unknown sequence");
+ }
+ }*/
+ // just ignore zeros
+ break;
+
+
+
+ case ETM3_PKT_A_SYNC:
+ if(by == 0x00) {
+ if( m_currPacketData.size() > 5) {
+ // extra 0, need to lose one
+
+ // set error type
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_SEQUENCE);
+ // mark extra 0 for sending, retain remaining, restart in A-SYNC processing mode.
+ setBytesPartPkt(1,PROC_DATA,ETM3_PKT_A_SYNC);
+ throwMalformedPacketErr("A-Sync ?: Extra 0x00 in sequence");
+ }
+ }
+ else if((by == 0x80) && ( m_currPacketData.size() == 6)) {
+ SendPacket();
+ m_bStreamSync = true;
+ }
+ else
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_SEQUENCE);
+ m_bytesProcessed--; // remove the last byte from the number processed to re-try
+ m_currPacketData.pop_back(); // remove the last byte processed from the packet
+ throwMalformedPacketErr("A-Sync ? : Unexpected byte in sequence");
+ }
+ break;
+
+ case ETM3_PKT_CYCLE_COUNT:
+ bTopBitSet = ((by & 0x80) == 0x80);
+ if(!bTopBitSet || ( m_currPacketData.size() >= 6)) {
+ m_currPktIdx = 1;
+ m_curr_packet.SetCycleCount(extractCycleCount());
+ SendPacket();
+ }
+ break;
+
+ case ETM3_PKT_I_SYNC_CYCLE:
+ if(!m_bIsync_got_cycle_cnt) {
+ if(((by & 0x80) != 0x80) || ( m_currPacketData.size() >= 6)) {
+ m_bIsync_got_cycle_cnt = true;
+ }
+ break;
+ }
+ // fall through when we have the first non-cycle count byte
+ case ETM3_PKT_I_SYNC:
+ if(m_bytesExpectedThisPkt == 0) {
+ int cycCountBytes = m_currPacketData.size() - 2;
+ int ctxtIDBytes = m_config.CtxtIDBytes();
+ // bytes expected = header + n x ctxt id + info byte + 4 x addr;
+ if(m_config.isInstrTrace())
+ m_bytesExpectedThisPkt = cycCountBytes + 6 + ctxtIDBytes;
+ else
+ m_bytesExpectedThisPkt = 2 + ctxtIDBytes;
+ m_IsyncInfoIdx = 1 + cycCountBytes + ctxtIDBytes;
+ }
+ if(( m_currPacketData.size() - 1) == (unsigned)m_IsyncInfoIdx) {
+ m_bIsync_get_LSiP_addr = ((m_currPacketData[m_IsyncInfoIdx] & 0x80) == 0x80);
+ }
+
+ // if bytes collected >= bytes expected
+ if( m_currPacketData.size() >= m_bytesExpectedThisPkt) {
+ // if we still need the LSip Addr, then this is not part of the expected
+ // count as we have no idea how long it is
+ if(m_bIsync_get_LSiP_addr) {
+ if((by & 0x80) != 0x80) {
+ OnISyncPacket();
+ }
+ }
+ else {
+ // otherwise, output now
+ OnISyncPacket();
+ }
+ }
+ break;
+
+ case ETM3_PKT_NORM_DATA:
+ if(m_bExpectingDataAddress && !m_bFoundDataAddress) {
+ // look for end of continuation bits
+ if((by & 0x80) != 0x80) {
+ m_bFoundDataAddress = true;
+ // add on the bytes we have found for the address to the expected data bytes
+ m_bytesExpectedThisPkt += ( m_currPacketData.size() - 1);
+ }
+ else
+ break;
+ }
+ // found any data address we were expecting
+ else if(m_bytesExpectedThisPkt == m_currPacketData.size()) {
+ m_currPktIdx = 1;
+ if(m_bExpectingDataAddress)
+ {
+ uint8_t bits = 0, beVal = 0;
+ bool updateBE = false;
+ uint32_t dataAddress = extractDataAddress(bits,updateBE,beVal);
+ m_curr_packet.UpdateDataAddress(dataAddress, bits);
+ if(updateBE)
+ m_curr_packet.UpdateDataEndian(beVal);
+ }
+ m_curr_packet.SetDataValue(extractDataValue((m_currPacketData[0] >> 2) & 0x3));
+ SendPacket();
+ }
+ break;
+
+ case ETM3_PKT_OOO_DATA:
+ if(m_bytesExpectedThisPkt == m_currPacketData.size())
+ {
+ m_currPktIdx = 1;
+ m_curr_packet.SetDataValue(extractDataValue((m_currPacketData[0] >> 2) & 0x3));
+ m_curr_packet.SetDataOOOTag((m_currPacketData[0] >> 5) & 0x3);
+ SendPacket();
+ }
+ if(m_bytesExpectedThisPkt < m_currPacketData.size())
+ throwMalformedPacketErr("Malformed out of order data packet.");
+ break;
+
+ // both these expect an address only.
+ case ETM3_PKT_VAL_NOT_TRACED:
+ case ETM3_PKT_OOO_ADDR_PLC: // we set the tag earlier.
+ if(m_bExpectingDataAddress) {
+ // look for end of continuation bits
+ if((by & 0x80) != 0x80) {
+ uint8_t bits = 0, beVal = 0;
+ bool updateBE = false;
+ m_currPktIdx = 1;
+ uint32_t dataAddress = extractDataAddress(bits,updateBE,beVal);
+ m_curr_packet.UpdateDataAddress(dataAddress, bits);
+ if(updateBE)
+ m_curr_packet.UpdateDataEndian(beVal);
+ SendPacket();
+ }
+ }
+ break;
+
+ case ETM3_PKT_CONTEXT_ID:
+ if(m_bytesExpectedThisPkt == m_currPacketData.size()) {
+ m_currPktIdx = 1;
+ m_curr_packet.UpdateContextID(extractCtxtID());
+ SendPacket();
+ }
+ if(m_bytesExpectedThisPkt < m_currPacketData.size())
+ throwMalformedPacketErr("Malformed context id packet.");
+ break;
+
+ case ETM3_PKT_TIMESTAMP:
+ if((by & 0x80) != 0x80) {
+ uint8_t tsBits = 0;
+ m_currPktIdx = 1;
+ uint64_t tsVal = extractTimestamp(tsBits);
+ m_curr_packet.UpdateTimestamp(tsVal,tsBits);
+ SendPacket();
+ }
+ break;
+
+ case ETM3_PKT_VMID:
+ // single byte payload
+ m_curr_packet.UpdateVMID(by);
+ SendPacket();
+ break;
+ }
+
+ return OCSD_OK;
+}
+
+// extract branch address packet at current location in packet data.
+void EtmV3PktProcImpl::OnBranchAddress()
+{
+ int validBits = 0;
+ ocsd_vaddr_t partAddr = 0;
+
+ partAddr = extractBrAddrPkt(validBits);
+ m_curr_packet.UpdateAddress(partAddr,validBits);
+}
+
+uint32_t EtmV3PktProcImpl::extractBrAddrPkt(int &nBitsOut)
+{
+ static int addrshift[] = {
+ 2, // ARM_ISA
+ 1, // thumb
+ 1, // thumb EE
+ 0 // jazelle
+ };
+
+ static uint8_t addrMask[] = { // byte 5 masks
+ 0x7, // ARM_ISA
+ 0xF, // thumb
+ 0xF, // thumb EE
+ 0x1F // jazelle
+ };
+
+ static int addrBits[] = { // address bits in byte 5
+ 3, // ARM_ISA
+ 4, // thumb
+ 4, // thumb EE
+ 5 // jazelle
+ };
+
+ static ocsd_armv7_exception exceptionTypeARMdeprecated[] = {
+ Excp_Reset,
+ Excp_IRQ,
+ Excp_Reserved,
+ Excp_Reserved,
+ Excp_Jazelle,
+ Excp_FIQ,
+ Excp_AsyncDAbort,
+ Excp_DebugHalt
+ };
+
+ bool CBit = true;
+ int bytecount = 0;
+ int bitcount = 0;
+ int shift = 0;
+ int isa_idx = 0;
+ uint32_t value = 0;
+ uint8_t addrbyte;
+ bool byte5AddrUpdate = false;
+
+ while(CBit && bytecount < 4)
+ {
+ checkPktLimits();
+ addrbyte = m_currPacketData[m_currPktIdx++];
+ CBit = (bool)((addrbyte & 0x80) != 0);
+ shift = bitcount;
+ if(bytecount == 0)
+ {
+ addrbyte &= ~0x81;
+ bitcount+=6;
+ addrbyte >>= 1;
+ }
+ else
+ {
+ // bytes 2-4, no continuation, alt format uses bit 6 to indicate following exception bytes
+ if(m_config.isAltBranch() && !CBit)
+ {
+ // last compressed address byte with exception
+ if((addrbyte & 0x40) == 0x40)
+ extractExceptionData();
+ addrbyte &= 0x3F;
+ bitcount+=6;
+ }
+ else
+ {
+ addrbyte &= 0x7F;
+ bitcount+=7;
+ }
+ }
+ value |= ((uint32_t)addrbyte) << shift;
+ bytecount++;
+ }
+
+ // byte 5 - indicates following exception bytes (or not!)
+ if(CBit)
+ {
+ checkPktLimits();
+ addrbyte = m_currPacketData[m_currPktIdx++];
+
+ // deprecated original byte 5 encoding - ARM state exception only
+ if(addrbyte & 0x80)
+ {
+ uint8_t excep_num = (addrbyte >> 3) & 0x7;
+ m_curr_packet.UpdateISA(ocsd_isa_arm);
+ m_curr_packet.SetException(exceptionTypeARMdeprecated[excep_num], excep_num, (addrbyte & 0x40) ? true : false,m_config.isV7MArch());
+ }
+ else
+ // normal 5 byte branch, or uses exception bytes.
+ {
+ // go grab the exception bits to correctly interpret the ISA state
+ if((addrbyte & 0x40) == 0x40)
+ extractExceptionData();
+
+ if((addrbyte & 0xB8) == 0x08)
+ m_curr_packet.UpdateISA(ocsd_isa_arm);
+ else if ((addrbyte & 0xB0) == 0x10)
+ m_curr_packet.UpdateISA(m_curr_packet.AltISA() ? ocsd_isa_tee : ocsd_isa_thumb2);
+ else if ((addrbyte & 0xA0) == 0x20)
+ m_curr_packet.UpdateISA(ocsd_isa_jazelle);
+ else
+ throwMalformedPacketErr("Malformed Packet - Unknown ISA.");
+ }
+
+ byte5AddrUpdate = true; // need to update the address value from byte 5
+ }
+
+ // figure out the correct ISA shifts for the address bits
+ switch(m_curr_packet.ISA())
+ {
+ case ocsd_isa_thumb2: isa_idx = 1; break;
+ case ocsd_isa_tee: isa_idx = 2; break;
+ case ocsd_isa_jazelle: isa_idx = 3; break;
+ default: break;
+ }
+
+ if(byte5AddrUpdate)
+ {
+ value |= ((uint32_t)(addrbyte & addrMask[isa_idx])) << bitcount;
+ bitcount += addrBits[isa_idx];
+ }
+
+ // finally align according to ISA
+ shift = addrshift[isa_idx];
+ value <<= shift;
+ bitcount += shift;
+
+ nBitsOut = bitcount;
+ return value;
+}
+
+// extract exception data from bytes after address.
+void EtmV3PktProcImpl::extractExceptionData()
+{
+ static const ocsd_armv7_exception exceptionTypesStd[] = {
+ Excp_NoException, Excp_DebugHalt, Excp_SMC, Excp_Hyp,
+ Excp_AsyncDAbort, Excp_Jazelle, Excp_Reserved, Excp_Reserved,
+ Excp_Reset, Excp_Undef, Excp_SVC, Excp_PrefAbort,
+ Excp_SyncDataAbort, Excp_Generic, Excp_IRQ, Excp_FIQ
+ };
+
+ static const ocsd_armv7_exception exceptionTypesCM[] = {
+ Excp_NoException, Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn,
+ Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn,
+ Excp_CMIRQn, Excp_CMUsageFault, Excp_CMNMI, Excp_SVC,
+ Excp_CMDebugMonitor, Excp_CMMemManage, Excp_CMPendSV, Excp_CMSysTick,
+ Excp_Reserved, Excp_Reset, Excp_Reserved, Excp_CMHardFault,
+ Excp_Reserved, Excp_CMBusFault, Excp_Reserved, Excp_Reserved
+ };
+
+ uint16_t exceptionNum = 0;
+ ocsd_armv7_exception excep_type = Excp_Reserved;
+ int resume = 0;
+ int irq_n = 0;
+ bool cancel_prev_instr = 0;
+ bool Byte2 = false;
+
+ checkPktLimits();
+
+ //**** exception info Byte 0
+ uint8_t dataByte = m_currPacketData[m_currPktIdx++];
+
+ m_curr_packet.UpdateNS(dataByte & 0x1);
+ exceptionNum |= (dataByte >> 1) & 0xF;
+ cancel_prev_instr = (dataByte & 0x20) ? true : false;
+ m_curr_packet.UpdateAltISA(((dataByte & 0x40) != 0) ? 1 : 0);
+
+ //** another byte?
+ if(dataByte & 0x80)
+ {
+ checkPktLimits();
+ dataByte = m_currPacketData[m_currPktIdx++];
+
+ if(dataByte & 0x40)
+ Byte2 = true; //** immediate info byte 2, skipping 1
+ else
+ {
+ //**** exception info Byte 1
+ if(m_config.isV7MArch())
+ {
+ exceptionNum |= ((uint16_t)(dataByte & 0x1F)) << 4;
+ }
+ m_curr_packet.UpdateHyp(dataByte & 0x20 ? 1 : 0);
+
+ if(dataByte & 0x80)
+ {
+ checkPktLimits();
+ dataByte = m_currPacketData[m_currPktIdx++];
+ Byte2 = true;
+ }
+ }
+ //**** exception info Byte 2
+ if(Byte2)
+ {
+ resume = dataByte & 0xF;
+ }
+ }
+
+ // set the exception type - according to the number and core profile
+ if(m_config.isV7MArch())
+ {
+ exceptionNum &= 0x1FF;
+ if(exceptionNum < 0x018)
+ excep_type= exceptionTypesCM[exceptionNum];
+ else
+ excep_type = Excp_CMIRQn;
+
+ if(excep_type == Excp_CMIRQn)
+ {
+ if(exceptionNum > 0x018)
+ irq_n = exceptionNum - 0x10;
+ else if(exceptionNum == 0x008)
+ irq_n = 0;
+ else
+ irq_n = exceptionNum;
+ }
+ }
+ else
+ {
+ exceptionNum &= 0xF;
+ excep_type = exceptionTypesStd[exceptionNum];
+ }
+ m_curr_packet.SetException(excep_type, exceptionNum, cancel_prev_instr,m_config.isV7MArch(), irq_n,resume);
+}
+
+void EtmV3PktProcImpl::checkPktLimits()
+{
+ // index running off the end of the packet means a malformed packet.
+ if(m_currPktIdx >= m_currPacketData.size())
+ throwMalformedPacketErr("Malformed Packet - oversized packet.");
+}
+
+uint32_t EtmV3PktProcImpl::extractCtxtID()
+{
+ uint32_t ctxtID = 0;
+ int size = m_config.CtxtIDBytes();
+
+ // check we have enough data
+ if((m_currPktIdx + size) > m_currPacketData.size())
+ throwMalformedPacketErr("Too few bytes to extract context ID.");
+
+ switch(size)
+ {
+ case 1:
+ ctxtID = (uint32_t)m_currPacketData[m_currPktIdx];
+ m_currPktIdx++;
+ break;
+
+ case 2:
+ ctxtID = (uint32_t)m_currPacketData[m_currPktIdx]
+ | ((uint32_t)m_currPacketData[m_currPktIdx+1]) << 8;
+ m_currPktIdx+=2;
+ break;
+
+ case 4:
+ ctxtID = (uint32_t)m_currPacketData[m_currPktIdx]
+ | ((uint32_t)m_currPacketData[m_currPktIdx+1]) << 8
+ | ((uint32_t)m_currPacketData[m_currPktIdx+2]) << 16
+ | ((uint32_t)m_currPacketData[m_currPktIdx+3]) << 24;
+ m_currPktIdx+=4;
+ break;
+ }
+ return ctxtID;
+}
+
+uint64_t EtmV3PktProcImpl::extractTimestamp(uint8_t &tsBits)
+{
+ uint64_t ts = 0;
+ unsigned tsMaxBytes = m_config.TSPkt64() ? 9 : 7;
+ unsigned tsCurrBytes = 0;
+ bool bCont = true;
+ uint8_t mask = 0x7F;
+ uint8_t last_mask = m_config.TSPkt64() ? 0xFF : 0x3F;
+ uint8_t ts_iter_bits = 7;
+ uint8_t ts_last_iter_bits = m_config.TSPkt64() ? 8 : 6;
+ uint8_t currByte;
+ tsBits = 0;
+
+ while((tsCurrBytes < tsMaxBytes) && bCont)
+ {
+ if(m_currPacketData.size() < (m_currPktIdx + tsCurrBytes + 1))
+ throwMalformedPacketErr("Insufficient bytes to extract timestamp.");
+
+ currByte = m_currPacketData[m_currPktIdx+tsCurrBytes];
+ ts |= ((uint64_t)(currByte & mask)) << (7 * tsCurrBytes);
+ tsCurrBytes++;
+ tsBits += ts_iter_bits;
+ bCont = ((0x80 & currByte) == 0x80);
+ if(tsCurrBytes == (tsMaxBytes - 1))
+ {
+ mask = last_mask;
+ ts_iter_bits = ts_last_iter_bits;
+ }
+ }
+ m_currPktIdx += tsCurrBytes;
+ return ts;
+}
+
+
+uint32_t EtmV3PktProcImpl::extractDataAddress(uint8_t &bits, bool &updateBE, uint8_t &beVal)
+{
+ uint32_t dataAddr = 0;
+ int bytesIdx = 0;
+ bool bCont = true;
+ uint8_t currByte = 0;
+
+ updateBE = false;
+ bits = 0;
+
+ while(bCont)
+ {
+ checkPktLimits();
+ currByte = m_currPacketData[m_currPktIdx++] & ((bytesIdx == 4) ? 0x0F : 0x7F);
+ dataAddr |= (((uint32_t)currByte) << (bytesIdx * 7));
+ bCont = ((currByte & 0x80) == 0x80);
+ if(bytesIdx == 4)
+ {
+ bits += 4;
+ updateBE = true;
+ beVal = ((currByte >> 4) & 0x1);
+ bCont = false;
+ }
+ else
+ bits+=7;
+ bytesIdx++;
+ }
+ return dataAddr;
+}
+
+uint32_t EtmV3PktProcImpl::extractDataValue(const int dataByteSize)
+{
+ static int bytesReqTable[] = { 0,1,2,4 };
+
+ uint32_t dataVal = 0;
+ int bytesUsed = 0;
+ int bytesReq = bytesReqTable[dataByteSize & 0x3];
+ while(bytesUsed < bytesReq)
+ {
+ checkPktLimits();
+ dataVal |= (((uint32_t)m_currPacketData[m_currPktIdx++]) << (bytesUsed * 8));
+ bytesUsed++;
+ }
+ return dataVal;
+}
+
+
+uint32_t EtmV3PktProcImpl::extractCycleCount()
+{
+ uint32_t cycleCount = 0;
+ int byteIdx = 0;
+ uint8_t mask = 0x7F;
+ bool bCond = true;
+ uint8_t currByte = 0;
+
+ while(bCond)
+ {
+ checkPktLimits();
+ currByte = m_currPacketData[m_currPktIdx++];
+ cycleCount |= ((uint32_t)(currByte & mask)) << (7 * byteIdx);
+ bCond = ((currByte & 0x80) == 0x80);
+ byteIdx++;
+
+ if(byteIdx == 4)
+ mask = 0x0F;
+
+ if(byteIdx == 5)
+ bCond = false;
+ }
+ return cycleCount;
+}
+
+void EtmV3PktProcImpl::OnISyncPacket()
+{
+ uint8_t iSyncInfoByte = 0;
+ uint32_t instrAddr = 0, LSiPAddr = 0;
+ int LSiPBits = 0;
+ uint8_t T = 0, J = 0, AltISA = 0;
+
+ m_currPktIdx = 1;
+ if(m_bIsync_got_cycle_cnt)
+ {
+ m_curr_packet.SetCycleCount(extractCycleCount());
+ m_curr_packet.SetISyncHasCC();
+ }
+
+ if(m_config.CtxtIDBytes() != 0)
+ {
+ m_curr_packet.UpdateContextID(extractCtxtID());
+ }
+
+ // extract context info
+ iSyncInfoByte = m_currPacketData[m_currPktIdx++];
+ m_curr_packet.SetISyncReason((ocsd_iSync_reason)((iSyncInfoByte >> 5) & 0x3));
+ J = (iSyncInfoByte >> 4) & 0x1;
+ AltISA = m_config.MinorRev() >= 3 ? (iSyncInfoByte >> 2) & 0x1 : 0;
+ m_curr_packet.UpdateNS((iSyncInfoByte >> 3) & 0x1);
+ if(m_config.hasVirtExt())
+ m_curr_packet.UpdateHyp((iSyncInfoByte >> 1) & 0x1);
+
+ // main address value - full 32 bit address value
+ if(m_config.isInstrTrace())
+ {
+ for(int i = 0; i < 4; i++)
+ instrAddr |= ((uint32_t)m_currPacketData[m_currPktIdx++]) << (8*i);
+ T = instrAddr & 0x1; // get the T bit.
+ instrAddr &= ~0x1; // remove from address.
+ m_curr_packet.UpdateAddress(instrAddr,32);
+
+ // enough data now to set the instruction set.
+ ocsd_isa currISA = ocsd_isa_arm;
+ if(J)
+ currISA = ocsd_isa_jazelle;
+ else if(T)
+ currISA = AltISA ? ocsd_isa_tee : ocsd_isa_thumb2;
+ m_curr_packet.UpdateISA(currISA);
+
+ // possible follow up address value - rarely uses unless trace enabled during
+ // load and store instruction executing on top of other instruction.
+ if(m_bIsync_get_LSiP_addr)
+ {
+ LSiPAddr = extractBrAddrPkt(LSiPBits);
+ // follow up address value is compressed relative to the main value
+ // we store this in the data address value temporarily.
+ m_curr_packet.UpdateDataAddress(instrAddr,32);
+ m_curr_packet.UpdateDataAddress(LSiPAddr,LSiPBits);
+ }
+ }
+ else
+ m_curr_packet.SetISyncNoAddr();
+
+ SendPacket(); // mark ready to send
+}
+
+/* End of File trc_pkt_proc_etmv3_impl.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h
new file mode 100644
index 0000000..a8e4fd1
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h
@@ -0,0 +1,175 @@
+/*
+ * \file trc_pkt_proc_etmv3_impl.h
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED
+#define ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED
+
+#include "opencsd/etmv3/trc_pkt_proc_etmv3.h"
+#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h"
+#include "opencsd/etmv3/trc_pkt_elem_etmv3.h"
+
+#define MAX_PACKET_SIZE 32
+#define ASYNC_SIZE 6
+
+class EtmV3PktProcImpl
+{
+public:
+ EtmV3PktProcImpl();
+ ~EtmV3PktProcImpl();
+
+ void Initialise(TrcPktProcEtmV3 *p_interface);
+
+ ocsd_err_t Configure(const EtmV3Config *p_config);
+
+
+ ocsd_datapath_resp_t processData( const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed);
+ ocsd_datapath_resp_t onEOT();
+ ocsd_datapath_resp_t onReset();
+ ocsd_datapath_resp_t onFlush();
+ const bool isBadPacket() const;
+
+protected:
+ typedef enum _process_state {
+ WAIT_SYNC,
+ PROC_HDR,
+ PROC_DATA,
+ SEND_PKT,
+ PROC_ERR,
+ } process_state;
+
+ process_state m_process_state;
+
+
+ void InitPacketState(); // clear current packet state.
+ void InitProcessorState(); // clear all previous process state
+
+ // byte processing
+
+ uint32_t waitForSync(const uint32_t dataBlockSize, const uint8_t *pDataBlock); //!< look for sync, return none-sync bytes processed.
+ ocsd_err_t processHeaderByte(uint8_t by);
+ ocsd_err_t processPayloadByte(uint8_t by);
+
+ // packet handling - main routines
+ void OnBranchAddress();
+ void OnISyncPacket();
+ uint32_t extractCtxtID();
+ uint64_t extractTimestamp(uint8_t &tsBits);
+ uint32_t extractDataAddress(uint8_t &bits, bool &updateBE, uint8_t &beVal);
+ uint32_t extractDataValue(const int dataByteSize);
+ uint32_t extractCycleCount();
+
+ // packet handling - helper routines
+ uint32_t extractBrAddrPkt(int &nBitsOut);
+ void extractExceptionData();
+ void checkPktLimits();
+ void setBytesPartPkt(const int numBytes, const process_state nextState, const ocsd_etmv3_pkt_type nextType); // set first n bytes from current packet to be sent via alt packet.
+
+ // packet output
+ void SendPacket(); // mark state for packet output
+ ocsd_datapath_resp_t outputPacket(); // output a packet
+
+ // bad packets
+ void throwMalformedPacketErr(const char *pszErrMsg);
+ void throwPacketHeaderErr(const char *pszErrMsg);
+ void throwUnsupportedErr(const char *pszErrMsg);
+
+ uint32_t m_bytesProcessed; // bytes processed by the process data routine (index into input buffer)
+ std::vector<uint8_t> m_currPacketData; // raw data
+ uint32_t m_currPktIdx; // index into packet when expanding
+ EtmV3TrcPacket m_curr_packet; // expanded packet
+
+ std::vector<uint8_t> m_partPktData; // raw data when we need to split a packet.
+ bool m_bSendPartPkt; // mark the part packet as the one we send.
+ process_state m_post_part_pkt_state; // state to set after part packet set
+ ocsd_etmv3_pkt_type m_post_part_pkt_type; // reset the packet type.
+
+ // process state
+ bool m_bStreamSync; //!< true if we have synced this stream
+ bool m_bStartOfSync; //!< true if we have a start of sync.
+
+ // packet state
+ uint32_t m_bytesExpectedThisPkt; // used by some of the variable packet length types.
+ bool m_BranchPktNeedsException;
+ bool m_bIsync_got_cycle_cnt;
+ bool m_bIsync_get_LSiP_addr;
+ int m_IsyncInfoIdx;
+ bool m_bExpectingDataAddress;
+ bool m_bFoundDataAddress;
+
+ ocsd_trc_index_t m_packet_index; // index of the start of the current packet
+ ocsd_trc_index_t m_packet_curr_byte_index; // index of the current byte.
+
+ bool m_isInit;
+ TrcPktProcEtmV3 *m_interface; /**< The interface to the other decode components */
+
+ EtmV3Config m_config;
+
+ uint8_t m_chanIDCopy;
+};
+
+
+inline void EtmV3PktProcImpl::SendPacket()
+{
+ m_process_state = SEND_PKT;
+}
+
+inline void EtmV3PktProcImpl::throwMalformedPacketErr(const char *pszErrMsg)
+{
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,m_chanIDCopy,pszErrMsg);
+}
+
+inline void EtmV3PktProcImpl::throwPacketHeaderErr(const char *pszErrMsg)
+{
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,m_chanIDCopy,pszErrMsg);
+}
+
+inline void EtmV3PktProcImpl::throwUnsupportedErr(const char *pszErrMsg)
+{
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_packet_index,m_chanIDCopy,pszErrMsg);
+}
+
+
+inline const bool EtmV3PktProcImpl::isBadPacket() const
+{
+ return m_curr_packet.isBadPacket();
+}
+
+
+#endif // ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED
+
+/* End of File trc_pkt_proc_etmv3_impl.h */
diff --git a/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp b/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp
new file mode 100644
index 0000000..6f8bf79
--- /dev/null
+++ b/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp
@@ -0,0 +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(FullVersion() > 0x40)
+ {
+ if(vmidszF == 2)
+ m_VMIDSize = 16;
+ else if(vmidszF == 4)
+ m_VMIDSize = 32;
+ }
+ m_VMIDSzCalc = true;
+}
+
+/* End of File trc_cmp_cfg_etmv4.cpp */
diff --git a/decoder/source/etmv4/trc_etmv4_stack_elem.cpp b/decoder/source/etmv4/trc_etmv4_stack_elem.cpp
new file mode 100644
index 0000000..1207444
--- /dev/null
+++ b/decoder/source/etmv4/trc_etmv4_stack_elem.cpp
@@ -0,0 +1,178 @@
+/*
+* \file trc_etmv4_stack_elem.cpp
+* \brief OpenCSD : ETMv4 decoder
+*
+* \copyright Copyright (c) 2017, ARM Limited. All Rights Reserved.
+*/
+
+
+/*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its contributors
+* may be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "opencsd/etmv4/trc_etmv4_stack_elem.h"
+
+/* implementation of P0 element stack in ETM v4 trace*/
+TrcStackElem *EtmV4P0Stack::createParamElemNoParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, bool back /*= false*/)
+{
+ TrcStackElem *pElem = new (std::nothrow) TrcStackElem(p0_type, isP0, root_pkt, root_index);
+ if (pElem)
+ {
+ if (back)
+ push_back(pElem);
+ else
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemParam *EtmV4P0Stack::createParamElem(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const std::vector<uint32_t> &params)
+{
+ TrcStackElemParam *pElem = new (std::nothrow) TrcStackElemParam(p0_type, isP0, root_pkt, root_index);
+ if (pElem)
+ {
+ int param_idx = 0;
+ int params_to_fill = params.size();
+ while ((param_idx < 4) && params_to_fill)
+ {
+ pElem->setParam(params[param_idx], param_idx);
+ param_idx++;
+ params_to_fill--;
+ }
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemAtom *EtmV4P0Stack::createAtomElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const ocsd_pkt_atom &atom)
+{
+ TrcStackElemAtom *pElem = new (std::nothrow) TrcStackElemAtom(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setAtom(atom);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemExcept *EtmV4P0Stack::createExceptElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const bool bSame, const uint16_t excepNum)
+{
+ TrcStackElemExcept *pElem = new (std::nothrow) TrcStackElemExcept(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setExcepNum(excepNum);
+ pElem->setPrevSame(bSame);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemCtxt *EtmV4P0Stack::createContextElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_context_t &context, const uint8_t IS, const bool back /*= false*/)
+{
+ TrcStackElemCtxt *pElem = new (std::nothrow) TrcStackElemCtxt(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setContext(context);
+ pElem->setIS(IS);
+ if (back)
+ push_back(pElem);
+ else
+ push_front(pElem);
+ }
+ return pElem;
+
+}
+
+TrcStackElemAddr *EtmV4P0Stack::createAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val)
+{
+ TrcStackElemAddr *pElem = new (std::nothrow) TrcStackElemAddr(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setAddr(addr_val);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackQElem *EtmV4P0Stack::createQElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const int count)
+{
+ TrcStackQElem *pElem = new (std::nothrow) TrcStackQElem(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setInstrCount(count);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemMarker *EtmV4P0Stack::createMarkerElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const trace_marker_payload_t &marker)
+{
+ TrcStackElemMarker *pElem = new (std::nothrow) TrcStackElemMarker(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setMarker(marker);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemAddr *EtmV4P0Stack::createSrcAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val)
+{
+ TrcStackElemAddr *pElem = new (std::nothrow) TrcStackElemAddr(root_pkt, root_index, true);
+ if (pElem)
+ {
+ pElem->setAddr(addr_val);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+// iteration functions
+void EtmV4P0Stack::from_front_init()
+{
+ m_iter = m_P0_stack.begin();
+}
+
+TrcStackElem *EtmV4P0Stack::from_front_next()
+{
+ TrcStackElem *pElem = 0;
+ if (m_iter != m_P0_stack.end())
+ {
+ pElem = *m_iter++;
+ }
+ return pElem;
+}
+
+void EtmV4P0Stack::erase_curr_from_front()
+{
+ std::deque<TrcStackElem *>::iterator erase_iter;
+ erase_iter = m_iter;
+ erase_iter--;
+ m_P0_stack.erase(erase_iter);
+}
+
+
+/* End of file trc_etmv4_stack_elem.cpp */
diff --git a/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
new file mode 100644
index 0000000..a9b059a
--- /dev/null
+++ b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
@@ -0,0 +1,1957 @@
+/*
+ * \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 |
+ ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS;
+
+TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I()
+ : TrcPktDecodeBase(DCD_NAME)
+{
+ initDecoder();
+}
+
+TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I(int instIDNum)
+ : TrcPktDecodeBase(DCD_NAME,instIDNum)
+{
+ initDecoder();
+}
+
+TrcPktDecodeEtmV4I::~TrcPktDecodeEtmV4I()
+{
+}
+
+/*********************** implementation packet decoding interface */
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ ocsd_err_t err = OCSD_OK;
+ bool bPktDone = false;
+
+ while(!bPktDone)
+ {
+ switch (m_curr_state)
+ {
+ case NO_SYNC:
+ // output the initial not synced packet to the sink
+ err = m_out_elem.resetElemStack();
+ if (!err)
+ err = m_out_elem.addElemType(m_index_curr_pkt, OCSD_GEN_TRC_ELEM_NO_SYNC);
+ if (!err)
+ {
+ outElem().setUnSyncEOTReason(m_unsync_eot_info);
+ resp = m_out_elem.sendElements();
+ m_curr_state = WAIT_SYNC;
+ }
+ else
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+
+ // fall through to check if the current packet is the async we are waiting for.
+ break;
+
+ case WAIT_SYNC:
+ if(m_curr_packet_in->getType() == ETM4_PKT_I_ASYNC)
+ m_curr_state = WAIT_TINFO;
+ bPktDone = true;
+ break;
+
+ case WAIT_TINFO:
+ m_need_ctxt = true;
+ m_need_addr = true;
+ if(m_curr_packet_in->getType() == ETM4_PKT_I_TRACE_INFO)
+ {
+ doTraceInfoPacket();
+ m_curr_state = DECODE_PKTS;
+ m_return_stack.flush();
+ }
+ /* ETE spec allows early event packets. */
+ else if ((m_config->MajVersion() >= 0x5) &&
+ (m_curr_packet_in->getType() == ETM4_PKT_I_EVENT))
+ {
+ err = decodePacket();
+ if (err)
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+ bPktDone = true;
+ break;
+
+ case DECODE_PKTS:
+ // this may change the state to RESOLVE_ELEM if required;
+ err = decodePacket();
+ if (err)
+ {
+#ifdef OCSD_WARN_UNSUPPORTED
+ if (err == OCSD_ERR_UNSUPP_DECODE_PKT)
+ resp = OCSD_RESP_WARN_CONT;
+ else
+#else
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+#endif
+
+ bPktDone = true;
+ }
+ else if (m_curr_state != RESOLVE_ELEM)
+ bPktDone = true;
+ break;
+
+ case RESOLVE_ELEM:
+ // this will change the state to DECODE_PKTS once required elem resolved &
+ // needed generic packets output
+ resp = resolveElements();
+ if ((m_curr_state == DECODE_PKTS) || (!OCSD_DATA_RESP_IS_CONT(resp)))
+ bPktDone = true;
+ break;
+ }
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ ocsd_err_t err;
+ if ((err = commitElemOnEOT()) != OCSD_OK)
+ {
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, "Error flushing element stack at end of trace data."));
+ }
+ else
+ resp = m_out_elem.sendElements();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onReset()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_unsync_eot_info = UNSYNC_RESET_DECODER;
+ resetDecoder();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onFlush()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ if (m_curr_state == RESOLVE_ELEM)
+ resp = resolveElements();
+ else
+ resp = m_out_elem.sendElements();
+ return resp;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::onProtocolConfig()
+{
+ ocsd_err_t err = OCSD_OK;
+
+ // set some static config elements
+ m_CSID = m_config->getTraceID();
+ m_max_spec_depth = m_config->MaxSpecDepth();
+
+ // elements associated with data trace
+#ifdef DATA_TRACE_SUPPORTED
+ m_p0_key_max = m_config->P0_Key_Max();
+ m_cond_key_max_incr = m_config->CondKeyMaxIncr();
+#endif
+
+ m_out_elem.initCSID(m_CSID);
+
+ // set up static trace instruction decode elements
+ m_instr_info.dsb_dmb_waypoints = 0;
+ m_instr_info.wfi_wfe_branch = m_config->wfiwfeBranch() ? 1 : 0;
+ m_instr_info.pe_type.arch = m_config->archVersion();
+ m_instr_info.pe_type.profile = m_config->coreProfile();
+
+ m_IASize64 = (m_config->iaSizeMax() == 64);
+
+ if (m_config->enabledRetStack())
+ {
+ m_return_stack.set_active(true);
+#ifdef TRC_RET_STACK_DEBUG
+ m_return_stack.set_dbg_logger(this);
+#endif
+ }
+
+ // check config compatible with current decoder support level.
+ // at present no data trace, no spec depth, no return stack, no QE
+ // Remove these checks as support is added.
+ if(m_config->enabledDataTrace())
+ {
+ err = OCSD_ERR_HW_CFG_UNSUPP;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Data trace elements not supported"));
+ }
+ else if(m_config->enabledLSP0Trace())
+ {
+ err = OCSD_ERR_HW_CFG_UNSUPP;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : LSP0 elements not supported."));
+ }
+ else if(m_config->enabledCondITrace() != EtmV4Config::COND_TR_DIS)
+ {
+ err = OCSD_ERR_HW_CFG_UNSUPP;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace on conditional non-branch elements not supported."));
+ }
+ return err;
+}
+
+/************* local decode methods */
+void TrcPktDecodeEtmV4I::initDecoder()
+{
+ // set the operational modes supported.
+ m_supported_op_flags = ETMV4_SUPPORTED_DECODE_OP_FLAGS;
+
+ /* init elements that get set by config */
+ m_max_spec_depth = 0;
+ m_CSID = 0;
+ m_IASize64 = false;
+
+ // elements associated with data trace
+#ifdef DATA_TRACE_SUPPORTED
+ m_p0_key_max = 0;
+ m_cond_key_max_incr = 0;
+#endif
+
+ // reset decoder state to unsynced
+ m_unsync_eot_info = UNSYNC_INIT_DECODER;
+ resetDecoder();
+}
+
+void TrcPktDecodeEtmV4I::resetDecoder()
+{
+ m_curr_state = NO_SYNC;
+ m_timestamp = 0;
+ m_context_id = 0;
+ m_vmid_id = 0;
+ m_is_secure = true;
+ m_is_64bit = false;
+ m_cc_threshold = 0;
+ m_curr_spec_depth = 0;
+ m_need_ctxt = true;
+ m_need_addr = true;
+ m_elem_pending_addr = false;
+ m_prev_overflow = false;
+ m_P0_stack.delete_all();
+ m_out_elem.resetElemStack();
+ m_last_IS = 0;
+ clearElemRes();
+ m_ete_first_ts_marker = false;
+
+ // elements associated with data trace
+#ifdef DATA_TRACE_SUPPORTED
+ m_p0_key = 0;
+ m_cond_c_key = 0;
+ m_cond_r_key = 0;
+#endif
+}
+
+void TrcPktDecodeEtmV4I::onFirstInitOK()
+{
+ // once init, set the output element interface to the out elem list.
+ m_out_elem.initSendIf(this->getTraceElemOutAttachPt());
+}
+
+// Changes a packet into stack of trace elements - these will be resolved and output later
+ocsd_err_t TrcPktDecodeEtmV4I::decodePacket()
+{
+ ocsd_err_t err = OCSD_OK;
+ bool bAllocErr = false;
+ bool is_addr = false;
+
+ switch(m_curr_packet_in->getType())
+ {
+ case ETM4_PKT_I_ASYNC: // nothing to do with this packet.
+ case ETM4_PKT_I_IGNORE: // or this one.
+ break;
+
+ case ETM4_PKT_I_TRACE_INFO:
+ // skip subsequent TInfo packets.
+ m_return_stack.flush();
+ break;
+
+ case ETM4_PKT_I_TRACE_ON:
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_TRC_ON, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ case ETM4_PKT_I_ATOM_F1:
+ case ETM4_PKT_I_ATOM_F2:
+ case ETM4_PKT_I_ATOM_F3:
+ case ETM4_PKT_I_ATOM_F4:
+ case ETM4_PKT_I_ATOM_F5:
+ case ETM4_PKT_I_ATOM_F6:
+ {
+ if (m_P0_stack.createAtomElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getAtom()) == 0)
+ bAllocErr = true;
+ else
+ m_curr_spec_depth += m_curr_packet_in->getAtom().num;
+ }
+ break;
+
+ case ETM4_PKT_I_CTXT:
+ {
+ if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext(), m_last_IS) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ case ETM4_PKT_I_ADDR_MATCH:
+ {
+ etmv4_addr_val_t addr;
+
+ addr.val = m_curr_packet_in->getAddrVal();
+ addr.isa = m_last_IS = m_curr_packet_in->getAddrIS();
+
+ if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0)
+ bAllocErr = true;
+ is_addr = true;
+ }
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS0:
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS1:
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS0:
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS1:
+ {
+ m_last_IS = m_curr_packet_in->getAddrIS();
+ if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext(), m_last_IS) == 0)
+ bAllocErr = true;
+ }
+ case ETM4_PKT_I_ADDR_L_32IS0:
+ case ETM4_PKT_I_ADDR_L_32IS1:
+ case ETM4_PKT_I_ADDR_L_64IS0:
+ case ETM4_PKT_I_ADDR_L_64IS1:
+ case ETM4_PKT_I_ADDR_S_IS0:
+ case ETM4_PKT_I_ADDR_S_IS1:
+ {
+ etmv4_addr_val_t addr;
+
+ addr.val = m_curr_packet_in->getAddrVal();
+ addr.isa = m_last_IS = m_curr_packet_in->getAddrIS();
+
+ if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0)
+ bAllocErr = true;
+ is_addr = true; // may be waiting for target address from indirect branch
+ }
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_MATCH:
+ case ETE_PKT_I_SRC_ADDR_S_IS0:
+ case ETE_PKT_I_SRC_ADDR_S_IS1:
+ case ETE_PKT_I_SRC_ADDR_L_32IS0:
+ case ETE_PKT_I_SRC_ADDR_L_32IS1:
+ case ETE_PKT_I_SRC_ADDR_L_64IS0:
+ case ETE_PKT_I_SRC_ADDR_L_64IS1:
+ {
+ etmv4_addr_val_t addr;
+
+ addr.val = m_curr_packet_in->getAddrVal();
+ addr.isa = m_curr_packet_in->getAddrIS();
+ if (m_P0_stack.createSrcAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0)
+ bAllocErr = true;
+ m_curr_spec_depth++;
+ }
+ break;
+
+ // Exceptions
+ case ETM4_PKT_I_EXCEPT:
+ {
+ if (m_P0_stack.createExceptElem(m_curr_packet_in->getType(), m_index_curr_pkt,
+ (m_curr_packet_in->exception_info.addr_interp == 0x2),
+ m_curr_packet_in->exception_info.exceptionType) == 0)
+ bAllocErr = true;
+ else
+ m_elem_pending_addr = true; // wait for following packets before marking for commit.
+ }
+ break;
+
+ case ETM4_PKT_I_EXCEPT_RTN:
+ {
+ // P0 element if V7M profile.
+ bool bV7MProfile = (m_config->archVersion() == ARCH_V7) && (m_config->coreProfile() == profile_CortexM);
+ if (m_P0_stack.createParamElemNoParam(P0_EXCEP_RET, bV7MProfile, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ else if (bV7MProfile)
+ m_curr_spec_depth++;
+ }
+ break;
+
+ case ETM4_PKT_I_FUNC_RET:
+ {
+ // P0 element iff V8M profile, otherwise ignore
+ if (OCSD_IS_V8_ARCH(m_config->archVersion()) && (m_config->coreProfile() == profile_CortexM))
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_FUNC_RET, true, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ else
+ m_curr_spec_depth++;
+ }
+ }
+ break;
+
+ // event trace
+ case ETM4_PKT_I_EVENT:
+ {
+ std::vector<uint32_t> 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<uint32_t> params = { 0 };
+ params[0] = m_curr_packet_in->getCC();
+ if (m_P0_stack.createParamElem(P0_CC, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0)
+ bAllocErr = true;
+
+ }
+ break;
+
+ // timestamp
+ case ETM4_PKT_I_TIMESTAMP:
+ {
+ bool bTSwithCC = m_config->enabledCCI();
+ uint64_t ts = m_curr_packet_in->getTS();
+ std::vector<uint32_t> params = { 0, 0, 0 };
+ params[0] = (uint32_t)(ts & 0xFFFFFFFF);
+ params[1] = (uint32_t)((ts >> 32) & 0xFFFFFFFF);
+ if (bTSwithCC)
+ params[2] = m_curr_packet_in->getCC();
+ if (m_P0_stack.createParamElem(bTSwithCC ? P0_TS_CC : P0_TS, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0)
+ bAllocErr = true;
+
+ }
+ break;
+
+ case ETE_PKT_I_TS_MARKER:
+ {
+ trace_marker_payload_t marker;
+ marker.type = ELEM_MARKER_TS;
+ marker.value = 0;
+ if (m_P0_stack.createMarkerElem(m_curr_packet_in->getType(), m_index_curr_pkt, marker) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ case ETM4_PKT_I_BAD_SEQUENCE:
+ err = handleBadPacket("Bad byte sequence in packet.", m_index_curr_pkt);
+ break;
+
+ case ETM4_PKT_I_BAD_TRACEMODE:
+ err = handleBadPacket("Invalid packet type for trace mode.", m_index_curr_pkt);
+ break;
+
+ case ETM4_PKT_I_RESERVED:
+ err = handleBadPacket("Reserved packet header", m_index_curr_pkt);
+ break;
+
+ // speculation
+ case ETM4_PKT_I_MISPREDICT:
+ case ETM4_PKT_I_CANCEL_F1_MISPRED:
+ case ETM4_PKT_I_CANCEL_F2:
+ case ETM4_PKT_I_CANCEL_F3:
+ m_elem_res.mispredict = true;
+ if (m_curr_packet_in->getNumAtoms())
+ {
+ if (m_P0_stack.createAtomElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getAtom()) == 0)
+ bAllocErr = true;
+ else
+ m_curr_spec_depth += m_curr_packet_in->getNumAtoms();
+ }
+
+ case ETM4_PKT_I_CANCEL_F1:
+ m_elem_res.P0_cancel = m_curr_packet_in->getCancelElem();
+ break;
+
+ case ETM4_PKT_I_COMMIT:
+ m_elem_res.P0_commit = m_curr_packet_in->getCommitElem();
+ break;
+
+ case ETM4_PKT_I_OVERFLOW:
+ m_prev_overflow = true;
+ case ETM4_PKT_I_DISCARD:
+ m_curr_spec_depth = 0;
+ m_elem_res.discard = true;
+ break;
+
+ /* Q packets */
+ case ETM4_PKT_I_Q:
+ {
+ TrcStackQElem *pQElem = m_P0_stack.createQElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->Q_pkt.q_count);
+ if (pQElem)
+ {
+ if (m_curr_packet_in->Q_pkt.addr_present)
+ {
+ etmv4_addr_val_t addr;
+
+ addr.val = m_curr_packet_in->getAddrVal();
+ addr.isa = m_curr_packet_in->getAddrIS();
+ pQElem->setAddr(addr);
+ m_curr_spec_depth++;
+ }
+ else
+ m_elem_pending_addr = true;
+ }
+ else
+ bAllocErr = true;
+ }
+ break;
+
+ /* transactional memory packets */
+ case ETE_PKT_I_TRANS_ST:
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_TRANS_START, m_config->commTransP0(), m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ if (m_config->commTransP0())
+ m_curr_spec_depth++;
+ }
+ break;
+
+ case ETE_PKT_I_TRANS_COMMIT:
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_TRANS_COMMIT, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ case ETE_PKT_I_TRANS_FAIL:
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_TRANS_FAIL, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ /*** presently unsupported packets ***/
+ /* ETE commit window - not supported in current ETE versions - blocked by packet processor */
+ case ETE_PKT_I_COMMIT_WIN_MV:
+ err = OCSD_ERR_UNSUPP_DECODE_PKT;
+ err = handlePacketSeqErr(err, m_index_curr_pkt, "ETE Commit Window Move, unsupported packet type.");
+ break;
+ /* conditional instruction tracing */
+ case ETM4_PKT_I_COND_FLUSH:
+ case ETM4_PKT_I_COND_I_F1:
+ case ETM4_PKT_I_COND_I_F2:
+ case ETM4_PKT_I_COND_I_F3:
+ case ETM4_PKT_I_COND_RES_F1:
+ case ETM4_PKT_I_COND_RES_F2:
+ case ETM4_PKT_I_COND_RES_F3:
+ case ETM4_PKT_I_COND_RES_F4:
+ // data synchronisation markers
+ case ETM4_PKT_I_NUM_DS_MKR:
+ case ETM4_PKT_I_UNNUM_DS_MKR:
+ // all currently unsupported
+ {
+ ocsd_err_severity_t sev = OCSD_ERR_SEV_ERROR;
+#ifdef OCSD_WARN_UNSUPPORTED
+ sev = OCSD_ERR_SEV_WARN;
+ //resp = OCSD_RESP_WARN_CONT;
+#else
+ //resp = OCSD_RESP_FATAL_INVALID_DATA;
+#endif
+ err = OCSD_ERR_UNSUPP_DECODE_PKT;
+ if (sev == OCSD_ERR_SEV_WARN)
+ LogError(ocsdError(sev, err, "Data trace related, unsupported packet type."));
+ else
+ err = handlePacketSeqErr(err, m_index_curr_pkt, "Data trace related, unsupported packet type.");
+ }
+ break;
+
+ default:
+ // any other packet - bad packet error
+ err = handleBadPacket("Unknown packet type.", m_index_curr_pkt);
+ break;
+ }
+
+ // we need to wait for following address after certain packets
+ // - work out if we have seen enough here...
+ if (is_addr && m_elem_pending_addr)
+ {
+ m_curr_spec_depth++; // increase spec depth for element waiting on address.
+ m_elem_pending_addr = false; // can't be waiting on both
+ }
+
+ if(bAllocErr)
+ {
+ err = OCSD_ERR_MEM;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM,"Memory allocation error."));
+ }
+ else if(m_curr_spec_depth > m_max_spec_depth)
+ {
+ // auto commit anything above max spec depth
+ // (this will auto commit anything if spec depth not supported!)
+ m_elem_res.P0_commit = m_curr_spec_depth - m_max_spec_depth;
+ }
+
+ if (!err && isElemForRes())
+ m_curr_state = RESOLVE_ELEM;
+ return err;
+}
+
+void TrcPktDecodeEtmV4I::doTraceInfoPacket()
+{
+ m_trace_info = m_curr_packet_in->getTraceInfo();
+ m_cc_threshold = m_curr_packet_in->getCCThreshold();
+ m_curr_spec_depth = m_curr_packet_in->getCurrSpecDepth();
+ /* put a trans marker in stack if started in trans state */
+ if (m_trace_info.bits.in_trans_state)
+ m_P0_stack.createParamElemNoParam(P0_TRANS_TRACE_INIT, false, m_curr_packet_in->getType(), m_index_curr_pkt);
+
+ // elements associated with data trace
+#ifdef DATA_TRACE_SUPPORTED
+ m_p0_key = m_curr_packet_in->getP0Key();
+#endif
+}
+
+/* Element resolution
+ * Commit or cancel elements as required
+ * Send any buffered output packets.
+ */
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::resolveElements()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool Complete = false;
+
+ while (!Complete)
+ {
+ if (m_out_elem.numElemToSend())
+ resp = m_out_elem.sendElements();
+ else if (isElemForRes())
+ {
+ ocsd_err_t err = OCSD_OK;
+ if (m_elem_res.P0_commit)
+ err = commitElements();
+
+ // allow for early flush on context element
+ if (!m_elem_res.P0_commit) {
+
+ if (!err && m_elem_res.P0_cancel)
+ err = cancelElements();
+
+ if (!err && m_elem_res.mispredict)
+ err = mispredictAtom();
+
+ if (!err && m_elem_res.discard)
+ err = discardElements();
+ }
+
+ if (err != OCSD_OK)
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+
+ // break out on error or wait request.
+ if (!OCSD_DATA_RESP_IS_CONT(resp))
+ break;
+
+ // completion is nothing to send and nothing to commit
+ Complete = !m_out_elem.numElemToSend() && !isElemForRes();
+
+ // done all elements - need more packets.
+ if (Complete) {
+ // if we are still in resolve, the goto decode.
+ if (m_curr_state == RESOLVE_ELEM)
+ m_curr_state = DECODE_PKTS;
+ }
+ }
+ return resp;
+}
+
+/*
+ * Walks through the element stack, processing from oldest element to the newest,
+ according to the number of P0 elements that need committing.
+ Build a stack of output elements in the process.
+ */
+ocsd_err_t TrcPktDecodeEtmV4I::commitElements()
+{
+ ocsd_err_t err = OCSD_OK;
+ bool bPopElem = true; // do we remove the element from the stack (multi atom elements may need to stay!)
+ int num_commit_req = m_elem_res.P0_commit;
+ ocsd_trc_index_t err_idx = 0;
+ TrcStackElem *pElem = 0; // stacked element pointer
+ bool contextFlush = false;
+
+ err = m_out_elem.resetElemStack();
+
+ while(m_elem_res.P0_commit && !err && !contextFlush)
+ {
+ if (m_P0_stack.size() > 0)
+ {
+ pElem = m_P0_stack.back(); // get oldest element
+ err_idx = pElem->getRootIndex(); // save index in case of error.
+
+ switch (pElem->getP0Type())
+ {
+ // indicates a trace restart - beginning of trace or discontinuiuty
+ case P0_TRC_ON:
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_TRACE_ON);
+ if (!err)
+ {
+ m_out_elem.getCurrElem().trace_on_reason = m_prev_overflow ? TRACE_ON_OVERFLOW : TRACE_ON_NORMAL;
+ m_prev_overflow = false;
+ m_return_stack.flush();
+ }
+ break;
+
+ case P0_ADDR:
+ {
+ TrcStackElemAddr *pAddrElem = dynamic_cast<TrcStackElemAddr *>(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<TrcStackElemCtxt *>(pElem);
+ if (pCtxtElem)
+ {
+ etmv4_context_t ctxt = pCtxtElem->getContext();
+ // check this is an updated context
+ if(ctxt.updated)
+ {
+ err = m_out_elem.addElem(pElem->getRootIndex());
+ if (!err) {
+ updateContext(pCtxtElem, outElem());
+
+ // updated context - need to force this to be output to the client so correct memory
+ // context can be used.
+ contextFlush = true;
+
+ // invalidate memory accessor cacheing - force next memory access out to client to
+ // ensure that the correct memory context is in play when decoding subsequent atoms.
+ invalidateMemAccCache();
+ }
+ }
+ }
+ }
+ break;
+
+ case P0_EVENT:
+ case P0_TS:
+ case P0_CC:
+ case P0_TS_CC:
+ err = processTS_CC_EventElem(pElem);
+ break;
+
+ case P0_MARKER:
+ err = processMarkerElem(pElem);
+ break;
+
+ case P0_ATOM:
+ {
+ TrcStackElemAtom *pAtomElem = dynamic_cast<TrcStackElemAtom *>(pElem);
+
+ if (pAtomElem)
+ {
+ while(!pAtomElem->isEmpty() && m_elem_res.P0_commit && !err)
+ {
+ ocsd_atm_val atom = pAtomElem->commitOldest();
+
+ // check if prev atom left us an indirect address target on the return stack
+ if ((err = returnStackPop()) != OCSD_OK)
+ break;
+
+ // if address and context do instruction trace follower.
+ // otherwise skip atom and reduce committed elements
+ if (!m_need_ctxt && !m_need_addr)
+ {
+ err = processAtom(atom);
+ }
+ m_elem_res.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 ((err = returnStackPop()) != OCSD_OK)
+ break;
+
+ err = processException(); // output trace + exception elements.
+ m_elem_res.P0_commit--;
+ break;
+
+ case P0_EXCEP_RET:
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
+ if (!err)
+ {
+ if (pElem->isP0()) // are we on a core that counts ERET as P0?
+ m_elem_res.P0_commit--;
+ }
+ break;
+
+ case P0_FUNC_RET:
+ // func ret is V8M - data trace only - hint that data has been popped off the stack.
+ // at this point nothing to do till the decoder starts handling data trace.
+ if (pElem->isP0())
+ m_elem_res.P0_commit--;
+ break;
+
+ case P0_SRC_ADDR:
+ err = processSourceAddress();
+ m_elem_res.P0_commit--;
+ break;
+
+ case P0_Q:
+ err = processQElement();
+ m_elem_res.P0_commit--;
+ break;
+
+ case P0_TRANS_START:
+ if (m_config->commTransP0())
+ m_elem_res.P0_commit--;
+ case P0_TRANS_COMMIT:
+ case P0_TRANS_FAIL:
+ case P0_TRANS_TRACE_INIT:
+ err = processTransElem(pElem);
+ break;
+ }
+
+ if(bPopElem)
+ m_P0_stack.delete_back(); // remove element from stack;
+ }
+ else
+ {
+ // too few elements for commit operation - decode error.
+ err = handlePacketSeqErr(OCSD_ERR_COMMIT_PKT_OVERRUN, err_idx, "Not enough elements to commit");
+ }
+ }
+
+ // reduce the spec depth by number of comitted elements
+ m_curr_spec_depth -= (num_commit_req-m_elem_res.P0_commit);
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::returnStackPop()
+{
+ ocsd_err_t err = OCSD_OK;
+ ocsd_isa nextISA;
+
+ if (m_return_stack.pop_pending())
+ {
+ ocsd_vaddr_t popAddr = m_return_stack.pop(nextISA);
+ if (m_return_stack.overflow())
+ {
+ err = OCSD_ERR_RET_STACK_OVERFLOW;
+ err = handlePacketSeqErr(err, OCSD_BAD_TRC_INDEX, "Trace Return Stack Overflow.");
+ }
+ else
+ {
+ m_instr_info.instr_addr = popAddr;
+ m_instr_info.isa = nextISA;
+ m_need_addr = false;
+ }
+ }
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::commitElemOnEOT()
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackElem *pElem = 0;
+
+ // nothing outstanding - reset the stack before we add more
+ if (!m_out_elem.numElemToSend())
+ m_out_elem.resetElemStack();
+
+ while((m_P0_stack.size() > 0) && !err)
+ {
+ // scan for outstanding events, TS and CC, that appear before any outstanding
+ // uncommited P0 element.
+ pElem = m_P0_stack.back();
+
+ switch(pElem->getP0Type())
+ {
+ // clear stack and stop
+ case P0_UNKNOWN:
+ case P0_ATOM:
+ case P0_TRC_ON:
+ case P0_EXCEP:
+ case P0_EXCEP_RET:
+ case P0_OVERFLOW:
+ case P0_Q:
+ m_P0_stack.delete_all();
+ break;
+
+ //skip
+ case P0_ADDR:
+ case P0_CTXT:
+ break;
+
+ // trans
+ // P0 trans - clear and stop, otherwise skip
+ case P0_TRANS_START:
+ if (m_config->commTransP0())
+ m_P0_stack.delete_all();
+ break;
+
+ // non-speculative trans fail / commit - could appear at EoT after valid trace
+ // but without a subsequent P0 that would force output.
+ case P0_TRANS_FAIL:
+ case P0_TRANS_COMMIT:
+ if (m_max_spec_depth == 0 || m_curr_spec_depth == 0)
+ err = processTransElem(pElem);
+ break;
+
+ // others - skip non P0
+ case P0_TRANS_TRACE_INIT:
+ break;
+
+ // output
+ case P0_EVENT:
+ case P0_TS:
+ case P0_CC:
+ case P0_TS_CC:
+ err = processTS_CC_EventElem(pElem);
+ break;
+
+ case P0_MARKER:
+ err = processMarkerElem(pElem);
+ break;
+ }
+ m_P0_stack.delete_back();
+ }
+
+ if(!err)
+ {
+ err = m_out_elem.addElemType(m_index_curr_pkt, OCSD_GEN_TRC_ELEM_EO_TRACE);
+ outElem().setUnSyncEOTReason(m_prev_overflow ? UNSYNC_OVERFLOW : UNSYNC_EOT);
+ }
+ return err;
+}
+
+// cancel elements. These not output
+ocsd_err_t TrcPktDecodeEtmV4I::cancelElements()
+{
+ ocsd_err_t err = OCSD_OK;
+ bool P0StackDone = false; // checked all P0 elements on the stack
+ TrcStackElem *pElem = 0; // stacked element pointer
+ EtmV4P0Stack temp;
+ int num_cancel_req = m_elem_res.P0_cancel;
+
+ while (m_elem_res.P0_cancel)
+ {
+ //search the stack for the newest elements
+ if (!P0StackDone)
+ {
+ if (m_P0_stack.size() == 0)
+ P0StackDone = true;
+ else
+ {
+ // get the newest element
+ pElem = m_P0_stack.front();
+ if (pElem->isP0()) {
+ if (pElem->getP0Type() == P0_ATOM)
+ {
+ TrcStackElemAtom *pAtomElem = (TrcStackElemAtom *)pElem;
+ // atom - cancel N atoms
+ m_elem_res.P0_cancel -= pAtomElem->cancelNewest(m_elem_res.P0_cancel);
+ if (pAtomElem->isEmpty())
+ m_P0_stack.delete_front(); // remove the element
+ }
+ else
+ {
+ m_elem_res.P0_cancel--;
+ m_P0_stack.delete_front(); // remove the element
+ }
+ } else {
+ // not P0, make a keep / remove decision
+ switch (pElem->getP0Type())
+ {
+ // keep these
+ case P0_EVENT:
+ case P0_TS:
+ case P0_CC:
+ case P0_TS_CC:
+ case P0_MARKER:
+ m_P0_stack.pop_front(false);
+ temp.push_back(pElem);
+ break;
+
+ default:
+ m_P0_stack.delete_front();
+ break;
+ }
+ }
+ if (m_P0_stack.size() == 0)
+ P0StackDone = true;
+ }
+ }
+ // may have some unseen elements
+ else if (m_unseen_spec_elem)
+ {
+ m_unseen_spec_elem--;
+ m_elem_res.P0_cancel--;
+ }
+ // otherwise we have some sort of overrun
+ else
+ {
+ // too few elements for commit operation - decode error.
+ err = OCSD_ERR_COMMIT_PKT_OVERRUN;
+ err = handlePacketSeqErr(err, m_index_curr_pkt, "Not enough elements to cancel");
+ m_elem_res.P0_cancel = 0;
+ break;
+ }
+ }
+
+ /* restore any saved elements that are unaffected by cancel. */
+ if (temp.size())
+ {
+ while (temp.size())
+ {
+ pElem = temp.back();
+ m_P0_stack.push_front(pElem);
+ temp.pop_back(false);
+ }
+ }
+
+ m_curr_spec_depth -= num_cancel_req - m_elem_res.P0_cancel;
+ return err;
+}
+
+// mispredict an atom
+ocsd_err_t TrcPktDecodeEtmV4I::mispredictAtom()
+{
+ ocsd_err_t err = OCSD_OK;
+ bool bFoundAtom = false, bDone = false;
+ TrcStackElem *pElem = 0;
+
+ m_P0_stack.from_front_init(); // init iterator at front.
+ while (!bDone)
+ {
+ pElem = m_P0_stack.from_front_next();
+ if (pElem)
+ {
+ if (pElem->getP0Type() == P0_ATOM)
+ {
+ TrcStackElemAtom *pAtomElem = dynamic_cast<TrcStackElemAtom *>(pElem);
+ if (pAtomElem)
+ {
+ pAtomElem->mispredictNewest();
+ bFoundAtom = true;
+ }
+ bDone = true;
+ }
+ else if (pElem->getP0Type() == P0_ADDR)
+ {
+ // need to disregard any addresses that appear between mispredict and the atom in question
+ m_P0_stack.erase_curr_from_front();
+ }
+ }
+ else
+ bDone = true;
+ }
+
+ // if missed atom then either overrun error or mispredict on unseen element
+ if (!bFoundAtom && !m_unseen_spec_elem)
+ {
+ err = OCSD_ERR_COMMIT_PKT_OVERRUN;
+ err = handlePacketSeqErr(err, m_index_curr_pkt, "Not found mispredict atom");
+ //LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, m_index_curr_pkt, m_CSID, "Not found mispredict atom"));
+ }
+ m_elem_res.mispredict = false;
+ return err;
+}
+
+// discard elements and flush
+ocsd_err_t TrcPktDecodeEtmV4I::discardElements()
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackElem *pElem = 0; // stacked element pointer
+
+ // dump P0, elemnts - output remaining CC / TS
+ while ((m_P0_stack.size() > 0) && !err)
+ {
+ pElem = m_P0_stack.back();
+ if (pElem->getP0Type() == P0_MARKER)
+ err = processMarkerElem(pElem);
+ else
+ err = processTS_CC_EventElem(pElem);
+ m_P0_stack.delete_back();
+ }
+
+ // clear all speculation info
+ clearElemRes();
+ m_curr_spec_depth = 0;
+
+ // set decode state
+ m_curr_state = NO_SYNC;
+ m_unsync_eot_info = m_prev_overflow ? UNSYNC_OVERFLOW : UNSYNC_DISCARD;
+
+ // unsync so need context & address.
+ m_need_ctxt = true;
+ m_need_addr = true;
+ m_elem_pending_addr = false;
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processTS_CC_EventElem(TrcStackElem *pElem)
+{
+ ocsd_err_t err = OCSD_OK;
+ // ignore ts for ETE if not seen first TS marker on systems that use this.
+ bool bPermitTS = !m_config->eteHasTSMarker() || m_ete_first_ts_marker;
+
+ switch (pElem->getP0Type())
+ {
+ case P0_EVENT:
+ {
+ TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem);
+ if (pParamElem)
+ err = addElemEvent(pParamElem);
+ }
+ break;
+
+ case P0_TS:
+ {
+ TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem);
+ if (pParamElem && bPermitTS)
+ err = addElemTS(pParamElem, false);
+ }
+ break;
+
+ case P0_CC:
+ {
+ TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem);
+ if (pParamElem)
+ err = addElemCC(pParamElem);
+ }
+ break;
+
+ case P0_TS_CC:
+ {
+ TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem);
+ if (pParamElem && bPermitTS)
+ err = addElemTS(pParamElem, true);
+ }
+ break;
+ }
+ return err;
+
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processMarkerElem(TrcStackElem *pElem)
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackElemMarker *pMarkerElem = dynamic_cast<TrcStackElemMarker *>(pElem);
+
+ if (m_config->eteHasTSMarker() && (pMarkerElem->getMarker().type == ELEM_MARKER_TS))
+ m_ete_first_ts_marker = true;
+
+ if (!err)
+ {
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_SYNC_MARKER);
+ if (!err)
+ m_out_elem.getCurrElem().setSyncMarker(pMarkerElem->getMarker());
+ }
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processTransElem(TrcStackElem *pElem)
+{
+ ocsd_err_t err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_MEMTRANS);
+ if (!err)
+ {
+ outElem().setTransactionType((trace_memtrans_t)((int)OCSD_MEM_TRANS_FAIL -
+ ((int)P0_TRANS_FAIL - (int)pElem->getP0Type())));
+ }
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::addElemCC(TrcStackElemParam *pParamElem)
+{
+ ocsd_err_t err = OCSD_OK;
+
+ err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
+ if (!err)
+ outElem().setCycleCount(pParamElem->getParam(0));
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::addElemTS(TrcStackElemParam *pParamElem, bool withCC)
+{
+ ocsd_err_t err = OCSD_OK;
+
+ err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_TIMESTAMP);
+ if (!err)
+ {
+ outElem().timestamp = (uint64_t)(pParamElem->getParam(0)) | (((uint64_t)pParamElem->getParam(1)) << 32);
+ if (withCC)
+ outElem().setCycleCount(pParamElem->getParam(2));
+ }
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::addElemEvent(TrcStackElemParam *pParamElem)
+{
+ ocsd_err_t err = OCSD_OK;
+
+ err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EVENT);
+ if (!err)
+ {
+ outElem().trace_event.ev_type = EVENT_NUMBERED;
+ outElem().trace_event.ev_number = pParamElem->getParam(0);
+ }
+ return err;
+}
+
+void TrcPktDecodeEtmV4I::setElemTraceRange(OcsdTraceElement &elemIn, const instr_range_t &addr_range,
+ const bool executed, ocsd_trc_index_t index)
+{
+ setElemTraceRangeInstr(elemIn, addr_range, executed, index, m_instr_info);
+}
+
+void TrcPktDecodeEtmV4I::setElemTraceRangeInstr(OcsdTraceElement &elemIn, const instr_range_t &addr_range,
+ const bool executed, ocsd_trc_index_t index, ocsd_instr_info &instr)
+{
+ elemIn.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
+ elemIn.setLastInstrInfo(executed, instr.type, instr.sub_type, instr.instr_size);
+ elemIn.setISA(instr.isa);
+ elemIn.setLastInstrCond(instr.is_conditional);
+ elemIn.setAddrRange(addr_range.st_addr, addr_range.en_addr, addr_range.num_instr);
+ if (executed)
+ instr.isa = instr.next_isa;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom)
+{
+ ocsd_err_t err;
+ TrcStackElem *pElem = m_P0_stack.back(); // get the atom element
+ WP_res_t WPRes;
+ instr_range_t addr_range;
+ bool ETE_ERET = false;
+
+ // new element for this processed atom
+ if ((err = m_out_elem.addElem(pElem->getRootIndex())) != OCSD_OK)
+ return err;
+
+ err = traceInstrToWP(addr_range, WPRes);
+ if(err != OCSD_OK)
+ {
+ if(err == OCSD_ERR_UNSUPPORTED_ISA)
+ {
+ m_need_addr = true;
+ m_need_ctxt = true;
+ LogError(ocsdError(OCSD_ERR_SEV_WARN,err,pElem->getRootIndex(),m_CSID,"Warning: unsupported instruction set processing atom packet."));
+ // wait for next context
+ return OCSD_OK;
+ }
+ else
+ {
+ err = handlePacketSeqErr(err, pElem->getRootIndex(), "Error processing atom packet.");
+ //LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet."));
+ return err;
+ }
+ }
+
+ if(WPFound(WPRes))
+ {
+ // save recorded next instuction address
+ ocsd_vaddr_t nextAddr = m_instr_info.instr_addr;
+
+ // action according to waypoint type and atom value
+ switch(m_instr_info.type)
+ {
+ case OCSD_INSTR_BR:
+ if (atom == ATOM_E)
+ {
+ m_instr_info.instr_addr = m_instr_info.branch_addr;
+ if (m_instr_info.is_link)
+ m_return_stack.push(nextAddr, m_instr_info.isa);
+
+ }
+ break;
+
+ case OCSD_INSTR_BR_INDIRECT:
+ if (atom == ATOM_E)
+ {
+ m_need_addr = true; // indirect branch taken - need new address.
+ if (m_instr_info.is_link)
+ m_return_stack.push(nextAddr,m_instr_info.isa);
+ m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen
+
+ /* ETE does not have ERET trace packets - however to maintain the illusion if we see an ERET
+ output a gen elem ERET packet */
+ if (isETEConfig() && (m_instr_info.sub_type == OCSD_S_INSTR_V8_ERET))
+ ETE_ERET = true;
+ }
+ break;
+ }
+ setElemTraceRange(outElem(), addr_range, (atom == ATOM_E), pElem->getRootIndex());
+
+ if (ETE_ERET)
+ {
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
+ if (err)
+ return err;
+ }
+ }
+ else
+ {
+ // no waypoint - likely inaccessible memory range.
+ m_need_addr = true; // need an address update
+
+ if(addr_range.st_addr != addr_range.en_addr)
+ {
+ // some trace before we were out of memory access range
+ setElemTraceRange(outElem(), addr_range, true, pElem->getRootIndex());
+
+ // another element for the nacc...
+ if (WPNacc(WPRes))
+ err = m_out_elem.addElem(pElem->getRootIndex());
+ }
+
+ if(WPNacc(WPRes) && !err)
+ {
+ outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ outElem().st_addr = m_instr_info.instr_addr;
+ }
+ }
+ return err;
+}
+
+// Exception processor
+ocsd_err_t TrcPktDecodeEtmV4I::processException()
+{
+ ocsd_err_t err;
+ TrcStackElem *pElem = 0;
+ TrcStackElemExcept *pExceptElem = 0;
+ TrcStackElemAddr *pAddressElem = 0;
+ TrcStackElemCtxt *pCtxtElem = 0;
+ bool branch_target = false; // exception address implies prior branch target address
+ ocsd_vaddr_t excep_ret_addr = 0;
+ ocsd_trc_index_t excep_pkt_index;
+ WP_res_t WPRes = WP_NOT_FOUND;
+ bool ETE_resetPkt = false;
+
+ // grab the exception element off the stack
+ pExceptElem = dynamic_cast<TrcStackElemExcept *>(m_P0_stack.back()); // get the exception element
+ excep_pkt_index = pExceptElem->getRootIndex();
+ branch_target = pExceptElem->getPrevSame();
+ if (pExceptElem->getRootPkt() == ETE_PKT_I_PE_RESET)
+ ETE_resetPkt = true;
+ m_P0_stack.pop_back(); // remove the exception element
+
+ // ETE reset has no follow up address, the rest of the exceptions do....
+ if (!ETE_resetPkt)
+ {
+ pElem = m_P0_stack.back(); // look at next element.
+ if (pElem->getP0Type() == P0_CTXT)
+ {
+ pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem);
+ m_P0_stack.pop_back(); // remove the context element
+ pElem = m_P0_stack.back(); // next one should be an address element
+ }
+
+ if (pElem->getP0Type() != P0_ADDR)
+ {
+ // no following address element - indicate processing error.
+
+ err = handlePacketSeqErr(OCSD_ERR_BAD_PACKET_SEQ, m_index_curr_pkt, "Address missing in exception packet.");
+ //LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_BAD_PACKET_SEQ, excep_pkt_index, m_CSID, "Address missing in exception packet."));
+ return err;
+ }
+ else
+ {
+ // extract address
+ pAddressElem = static_cast<TrcStackElemAddr *>(pElem);
+ excep_ret_addr = pAddressElem->getAddr().val;
+
+ // see if there is an address + optional context element implied
+ // prior to the exception.
+ if (branch_target)
+ {
+ // this was a branch target address - update current setting
+ bool b64bit = m_instr_info.isa == ocsd_isa_aarch64;
+ if (pCtxtElem) {
+ b64bit = pCtxtElem->getContext().SF;
+ }
+
+ // as the exception address was also a branch target address then update the
+ // current maintained address value. This also means that there is no range to
+ // output before the exception packet.
+ m_instr_info.instr_addr = excep_ret_addr;
+ m_instr_info.isa = (pAddressElem->getAddr().isa == 0) ?
+ (b64bit ? ocsd_isa_aarch64 : ocsd_isa_arm) : ocsd_isa_thumb2;
+ m_need_addr = false;
+ }
+ }
+ }
+
+ // need to output something - set up an element
+ if ((err = m_out_elem.addElem(excep_pkt_index)))
+ return err;
+
+ // output a context element if present
+ if (pCtxtElem)
+ {
+ updateContext(pCtxtElem, outElem());
+
+ // used the element - need another for later stages
+ if ((err = m_out_elem.addElem(excep_pkt_index)))
+ return err;
+ }
+
+ if (!ETE_resetPkt)
+ {
+ // if the preferred return address is not the end of the last output range...
+ if (m_instr_info.instr_addr != excep_ret_addr)
+ {
+ bool range_out = false;
+ instr_range_t addr_range;
+
+ // look for match to return address.
+ err = traceInstrToWP(addr_range, WPRes, true, excep_ret_addr);
+
+ 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, excep_pkt_index, m_CSID, "Warning: unsupported instruction set processing exception packet."));
+ }
+ else
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, excep_pkt_index, m_CSID, "Error processing exception packet."));
+ }
+ return err;
+ }
+
+ if (WPFound(WPRes))
+ {
+ // waypoint address found - output range
+ setElemTraceRange(outElem(), addr_range, true, excep_pkt_index);
+ range_out = true;
+ }
+ else
+ {
+ // no waypoint - likely inaccessible memory range.
+ m_need_addr = true; // need an address update
+
+ if (addr_range.st_addr != addr_range.en_addr)
+ {
+ // some trace before we were out of memory access range
+ setElemTraceRange(outElem(), addr_range, true, excep_pkt_index);
+ range_out = true;
+ }
+ }
+
+ // used the element need another for NACC or EXCEP.
+ if (range_out)
+ {
+ if ((err = m_out_elem.addElem(excep_pkt_index)))
+ return err;
+ }
+ }
+
+ // watchpoint walk resulted in inaccessible memory call...
+ if (WPNacc(WPRes))
+ {
+
+ outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ outElem().st_addr = m_instr_info.instr_addr;
+
+ // used the element - need another for the final exception packet.
+ if ((err = m_out_elem.addElem(excep_pkt_index)))
+ return err;
+ }
+ }
+
+ // output exception element.
+ outElem().setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
+
+ // add end address as preferred return address to end addr in element
+ outElem().en_addr = excep_ret_addr;
+ outElem().excep_ret_addr = 1;
+ outElem().excep_ret_addr_br_tgt = branch_target;
+ outElem().exception_number = pExceptElem->getExcepNum();
+
+ m_P0_stack.delete_popped(); // clear the used elements from the stack
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processQElement()
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackQElem *pQElem;
+ etmv4_addr_val_t QAddr; // address where trace restarts
+ int iCount = 0;
+
+ pQElem = dynamic_cast<TrcStackQElem *>(m_P0_stack.back()); // get the exception element
+ m_P0_stack.pop_back(); // remove the Q element.
+
+ if (!pQElem->hasAddr()) // no address - it must be next on the stack....
+ {
+ TrcStackElemAddr *pAddressElem = 0;
+ TrcStackElemCtxt *pCtxtElem = 0;
+ TrcStackElem *pElem = 0;
+
+ pElem = m_P0_stack.back(); // look at next element.
+ if (pElem->getP0Type() == P0_CTXT)
+ {
+ pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem);
+ m_P0_stack.pop_back(); // remove the context element
+ pElem = m_P0_stack.back(); // next one should be an address element
+ }
+
+ if (pElem->getP0Type() != P0_ADDR)
+ {
+ // no following address element - indicate processing error.
+ err = OCSD_ERR_BAD_PACKET_SEQ;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pQElem->getRootIndex(), m_CSID, "Address missing in Q packet."));
+ m_P0_stack.delete_popped();
+ return err;
+ }
+ pAddressElem = dynamic_cast<TrcStackElemAddr *>(pElem);
+ QAddr = pAddressElem->getAddr();
+ m_P0_stack.pop_back(); // remove the address element
+ m_P0_stack.delete_popped(); // clear used elements
+
+ // return the context element for processing next time.
+ if (pCtxtElem)
+ {
+ // need a new copy at the back - old one will be deleted as popped.
+ m_P0_stack.createContextElem(pCtxtElem->getRootPkt(), pCtxtElem->getRootIndex(), pCtxtElem->getContext(),true);
+ }
+ }
+ else
+ QAddr = pQElem->getAddr();
+
+ // process the Q element with address.
+ iCount = pQElem->getInstrCount();
+
+ bool isBranch = false;
+
+ // need to output something - set up an element
+ if ((err = m_out_elem.addElem(pQElem->getRootIndex())))
+ return err;
+
+ instr_range_t addr_range;
+ addr_range.st_addr = addr_range.en_addr = m_instr_info.instr_addr;
+ addr_range.num_instr = 0;
+
+ // walk iCount instructions
+ for (int i = 0; i < iCount; i++)
+ {
+ uint32_t opcode;
+ uint32_t bytesReq = 4;
+
+ err = accessMemory(m_instr_info.instr_addr, getCurrMemSpace(), &bytesReq, (uint8_t *)&opcode);
+ if (err != OCSD_OK) break;
+
+ if (bytesReq == 4) // got data back
+ {
+ m_instr_info.opcode = opcode;
+ err = instrDecode(&m_instr_info);
+ if (err != OCSD_OK) break;
+
+ // increment address - may be adjusted by direct branch value later
+ m_instr_info.instr_addr += m_instr_info.instr_size;
+ addr_range.num_instr++;
+
+ isBranch = (m_instr_info.type == OCSD_INSTR_BR) ||
+ (m_instr_info.type == OCSD_INSTR_BR_INDIRECT);
+
+ // on a branch no way of knowing if taken - bail out
+ if (isBranch)
+ break;
+ }
+ else
+ break; // missing memory
+
+ }
+
+ if (err == OCSD_OK)
+ {
+ bool inCompleteRange = true;
+ if (iCount && (addr_range.num_instr == (unsigned)iCount))
+ {
+ if ((m_instr_info.instr_addr == QAddr.val) || // complete range
+ (isBranch)) // or ends on branch - only way we know if branch taken.
+ {
+ // output a range and continue
+ inCompleteRange = false;
+ // update the range decoded address in the output packet.
+ addr_range.en_addr = m_instr_info.instr_addr;
+ setElemTraceRange(outElem(), addr_range, true, pQElem->getRootIndex());
+ }
+ }
+
+ if (inCompleteRange)
+ {
+ // unknown instructions executed.
+ addr_range.en_addr = QAddr.val;
+ addr_range.num_instr = iCount;
+
+ outElem().setType(OCSD_GEN_TRC_ELEM_I_RANGE_NOPATH);
+ outElem().setAddrRange(addr_range.st_addr, addr_range.en_addr, addr_range.num_instr);
+ outElem().setISA(calcISA(m_is_64bit, QAddr.isa));
+ }
+
+ // after the Q element, tracing resumes at the address supplied
+ SetInstrInfoInAddrISA(QAddr.val, QAddr.isa);
+ m_need_addr = false;
+ }
+ else
+ {
+ // output error and halt decode.
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pQElem->getRootIndex(), m_CSID, "Error processing Q packet"));
+ }
+ m_P0_stack.delete_popped();
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processSourceAddress()
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackElemAddr *pElem = dynamic_cast<TrcStackElemAddr *>(m_P0_stack.back()); // get the address element
+ etmv4_addr_val_t srcAddr = pElem->getAddr();
+ uint32_t opcode, bytesReq = 4;
+ ocsd_vaddr_t currAddr = m_instr_info.instr_addr; // get the latest decoded address.
+ instr_range_t out_range;
+ bool bSplitRangeOnN = getComponentOpMode() & ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS ? true : false;
+
+ // check we can read instruction @ source address
+ err = accessMemory(srcAddr.val, getCurrMemSpace(), &bytesReq, (uint8_t *)&opcode);
+ if (err != OCSD_OK)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Mem access error processing source address packet."));
+ return err;
+ }
+
+ if (bytesReq != 4)
+ {
+ // can't access - no bytes returned - output nacc.
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ outElem().setAddrStart(srcAddr.val);
+ return err;
+ }
+
+ // analyze opcode @ source address.
+ m_instr_info.opcode = opcode;
+ m_instr_info.instr_addr = srcAddr.val;
+ err = instrDecode(&m_instr_info);
+ if (err != OCSD_OK)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Instruction decode error processing source address packet."));
+ return err;
+ }
+ m_instr_info.instr_addr += m_instr_info.instr_size;
+
+ // initial instruction count for the range.
+ out_range.num_instr = 1;
+
+ // calculate range traced...
+ if (m_need_addr || (currAddr > srcAddr.val))
+ {
+ // we were waiting for a target address, or missing trace
+ // that indicates how we got to the source address.
+ m_need_addr = false;
+ out_range.st_addr = srcAddr.val;
+ }
+ else
+ out_range.st_addr = currAddr;
+ out_range.en_addr = m_instr_info.instr_addr;
+
+ // count instructions
+ if (out_range.en_addr - out_range.st_addr > m_instr_info.instr_size)
+ {
+ if ((m_instr_info.isa != ocsd_isa_thumb2) && !bSplitRangeOnN)
+ {
+ // all 4 byte instructions - just calculate...
+ out_range.num_instr = (uint32_t)(out_range.en_addr - out_range.st_addr) / 4;
+ }
+ else
+ {
+ // need to count T32 - 2 or 4 byte instructions or we are spotting N atoms
+ ocsd_instr_info instr; // going back to start of range so make a copy of info.
+ bool bMemAccErr = false;
+
+ instr.instr_addr = out_range.st_addr;
+ instr.isa = m_instr_info.isa;
+ instr.pe_type = m_instr_info.pe_type;
+ instr.dsb_dmb_waypoints = m_instr_info.dsb_dmb_waypoints;
+ instr.wfi_wfe_branch = m_instr_info.wfi_wfe_branch;
+ out_range.num_instr = 0;
+
+ while ((instr.instr_addr < out_range.en_addr) && !bMemAccErr)
+ {
+ bytesReq = 4;
+ err = accessMemory(instr.instr_addr, getCurrMemSpace(), &bytesReq, (uint8_t *)&opcode);
+ if (err != OCSD_OK)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Mem access error processing source address packet."));
+ return err;
+ }
+
+ if (bytesReq == 4)
+ {
+ instr.opcode = opcode;
+ err = instrDecode(&instr);
+ if (err != OCSD_OK)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Instruction decode error processing source address packet."));
+ return err;
+ }
+
+ instr.instr_addr += instr.instr_size;
+ out_range.num_instr++;
+
+ /* if we are doing N atom ranges ...*/
+ if (bSplitRangeOnN && (instr.instr_addr < out_range.en_addr))
+ {
+ if (instr.type != OCSD_INSTR_OTHER)
+ {
+ instr_range_t mid_range = out_range;
+ mid_range.en_addr = instr.instr_addr;
+
+ err = m_out_elem.addElem(pElem->getRootIndex());
+ if (err)
+ return err;
+ setElemTraceRangeInstr(outElem(), mid_range, false, pElem->getRootIndex(), instr);
+
+ out_range.st_addr = mid_range.en_addr;
+ out_range.num_instr = 0;
+ }
+ }
+ }
+ else
+ {
+ // something inaccessible between last and current...
+ bMemAccErr = true;
+
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ if (err)
+ return err;
+ outElem().setAddrStart(srcAddr.val);
+
+ // force range to the one instruction
+ out_range.num_instr = 1;
+ out_range.st_addr = srcAddr.val;
+ out_range.en_addr = m_instr_info.instr_addr; // instr after the decoded instruction @ srcAddr.
+ }
+ }
+ }
+ }
+
+ // got to the source address - output trace range, and instruction as E atom.
+ switch (m_instr_info.type)
+ {
+ case OCSD_INSTR_BR:
+ if (m_instr_info.is_link)
+ m_return_stack.push(m_instr_info.instr_addr, m_instr_info.isa);
+ m_instr_info.instr_addr = m_instr_info.branch_addr;
+ break;
+
+ case OCSD_INSTR_BR_INDIRECT:
+ m_need_addr = true; // indirect branch taken - need new address.
+ if (m_instr_info.is_link)
+ m_return_stack.push(m_instr_info.instr_addr, m_instr_info.isa);
+ m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen
+ break;
+ }
+ m_instr_info.isa = m_instr_info.next_isa;
+
+ // set the trace range element.
+ m_out_elem.addElem(pElem->getRootIndex());
+ setElemTraceRange(outElem(), out_range, true, pElem->getRootIndex());
+ return err;
+}
+
+void TrcPktDecodeEtmV4I::SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa)
+{
+ m_instr_info.instr_addr = addr_val;
+ m_instr_info.isa = calcISA(m_is_64bit, isa);
+}
+
+// trace an instruction range to a waypoint - and set next address to restart from.
+ocsd_err_t TrcPktDecodeEtmV4I::traceInstrToWP(instr_range_t &range, WP_res_t &WPRes, const bool traceToAddrNext /*= false*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/)
+{
+ uint32_t opcode;
+ uint32_t bytesReq;
+ ocsd_err_t err = OCSD_OK;
+
+ range.st_addr = range.en_addr = m_instr_info.instr_addr;
+ range.num_instr = 0;
+
+ WPRes = WP_NOT_FOUND;
+
+ while(WPRes == WP_NOT_FOUND)
+ {
+ // start off by reading next opcode;
+ bytesReq = 4;
+ err = accessMemory(m_instr_info.instr_addr, getCurrMemSpace(),&bytesReq,(uint8_t *)&opcode);
+ if(err != OCSD_OK) break;
+
+ if(bytesReq == 4) // got data back
+ {
+ m_instr_info.opcode = opcode;
+ err = instrDecode(&m_instr_info);
+ if(err != OCSD_OK) break;
+
+ // increment address - may be adjusted by direct branch value later
+ m_instr_info.instr_addr += m_instr_info.instr_size;
+ range.num_instr++;
+
+ // either walking to match the next instruction address or a real watchpoint
+ if (traceToAddrNext)
+ {
+ if (m_instr_info.instr_addr == nextAddrMatch)
+ WPRes = WP_FOUND;
+ }
+ else if (m_instr_info.type != OCSD_INSTR_OTHER)
+ WPRes = WP_FOUND;
+ }
+ else
+ {
+ // not enough memory accessible.
+ WPRes = WP_NACC;
+ }
+ }
+ // update the range decoded address in the output packet.
+ range.en_addr = m_instr_info.instr_addr;
+ return err;
+}
+
+void TrcPktDecodeEtmV4I::updateContext(TrcStackElemCtxt *pCtxtElem, OcsdTraceElement &elem)
+{
+ etmv4_context_t ctxt = pCtxtElem->getContext();
+
+ elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+
+ // map to output element and local saved state.
+ m_is_64bit = (ctxt.SF != 0);
+ elem.context.bits64 = ctxt.SF;
+ m_is_secure = (ctxt.NS == 0);
+ if (ctxt.NSE)
+ elem.context.security_level = ctxt.NS ? ocsd_sec_realm : ocsd_sec_root;
+ else
+ elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure;
+ elem.context.exception_level = (ocsd_ex_level)ctxt.EL;
+ elem.context.el_valid = 1;
+ if(ctxt.updated_c)
+ {
+ elem.context.ctxt_id_valid = 1;
+ m_context_id = elem.context.context_id = ctxt.ctxtID;
+ }
+ if(ctxt.updated_v)
+ {
+ elem.context.vmid_valid = 1;
+ m_vmid_id = elem.context.vmid = ctxt.VMID;
+ }
+
+ // need to update ISA in case context follows address.
+ elem.isa = m_instr_info.isa = calcISA(m_is_64bit, pCtxtElem->getIS());
+ m_need_ctxt = false;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason, ocsd_trc_index_t index /* = OCSD_BAD_TRC_INDEX */)
+{
+ ocsd_err_severity_t sev = OCSD_ERR_SEV_WARN;
+ if (getComponentOpMode() & OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS)
+ sev = OCSD_ERR_SEV_ERROR;
+
+ return handlePacketErr(OCSD_ERR_BAD_DECODE_PKT, sev, index, reason);
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::handlePacketSeqErr(ocsd_err_t err, ocsd_trc_index_t index, const char *reason)
+{
+ return handlePacketErr(err, OCSD_ERR_SEV_ERROR, index, reason);
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason)
+{
+ bool resetOnBadPackets = true;
+
+ if(getComponentOpMode() & OCSD_OPFLG_PKTDEC_HALT_BAD_PKTS)
+ resetOnBadPackets = false;
+
+ LogError(ocsdError(sev, err, index, getCoreSightTraceID(), reason));
+
+ if (resetOnBadPackets)
+ {
+ // switch to unsync - clear decode state
+ resetDecoder();
+ m_curr_state = NO_SYNC;
+ m_unsync_eot_info = UNSYNC_BAD_PACKET;
+ err = OCSD_OK;
+ }
+ return err;
+
+}
+
+
+inline ocsd_mem_space_acc_t TrcPktDecodeEtmV4I::getCurrMemSpace()
+{
+ static ocsd_mem_space_acc_t SMemSpace[] = {
+ OCSD_MEM_SPACE_EL1S,
+ OCSD_MEM_SPACE_EL1S,
+ OCSD_MEM_SPACE_EL2S,
+ OCSD_MEM_SPACE_EL3
+ };
+
+ static ocsd_mem_space_acc_t NSMemSpace[] = {
+ OCSD_MEM_SPACE_EL1N,
+ OCSD_MEM_SPACE_EL1N,
+ OCSD_MEM_SPACE_EL2,
+ OCSD_MEM_SPACE_EL3
+ };
+
+ /* if no valid EL value - just use S/NS */
+ if (!outElem().context.el_valid)
+ return m_is_secure ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N;
+
+ /* mem space according to EL + S/NS */
+ int el = (int)(outElem().context.exception_level) & 0x3;
+ return m_is_secure ? SMemSpace[el] : NSMemSpace[el];
+}
+/* End of File trc_pkt_decode_etmv4i.cpp */
diff --git a/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp
new file mode 100644
index 0000000..b417540
--- /dev/null
+++ b/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp
@@ -0,0 +1,754 @@
+/*
+ * \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 <sstream>
+#include <iomanip>
+
+#include "opencsd/etmv4/trc_pkt_elem_etmv4i.h"
+
+EtmV4ITrcPacket::EtmV4ITrcPacket()
+{
+ protocol_version = 0x42; // min protocol version.
+}
+
+EtmV4ITrcPacket::~EtmV4ITrcPacket()
+{
+}
+
+void EtmV4ITrcPacket::initStartState()
+{
+ // clear packet state to start of trace (first sync or post discontinuity)
+
+ // clear all valid bits
+ pkt_valid.val = 0;
+
+ // virtual address
+ v_addr.pkt_bits = 0;
+ v_addr.valid_bits = 0;
+ v_addr_ISA = 0;
+
+ // timestamp
+ ts.bits_changed = 0;
+ ts.timestamp = 0;
+
+ // per packet init
+ initNextPacket();
+}
+
+void EtmV4ITrcPacket::initNextPacket()
+{
+ // clear valid bits for elements that are only valid over a single packet.
+ pkt_valid.bits.cc_valid = 0;
+ pkt_valid.bits.commit_elem_valid = 0;
+ atom.num = 0;
+ context.updated = 0;
+ context.updated_v = 0;
+ context.updated_c = 0;
+ err_type = ETM4_PKT_I_NO_ERR_TYPE;
+}
+
+// printing
+void EtmV4ITrcPacket::toString(std::string &str) const
+{
+ const char *name;
+ const char *desc;
+ std::string valStr, ctxtStr = "";
+
+ name = packetTypeName(type, &desc);
+ str = name + (std::string)" : " + desc;
+
+ // extended descriptions
+ switch (type)
+ {
+ case ETM4_PKT_I_BAD_SEQUENCE:
+ case ETM4_PKT_I_INCOMPLETE_EOT:
+ case ETM4_PKT_I_RESERVED_CFG:
+ name = packetTypeName(err_type, 0);
+ str += "[" + (std::string)name + "]";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS0:
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS1:
+ contextStr(ctxtStr);
+ case ETM4_PKT_I_ADDR_L_32IS0:
+ case ETM4_PKT_I_ADDR_L_32IS1:
+ case ETE_PKT_I_SRC_ADDR_L_32IS0:
+ case ETE_PKT_I_SRC_ADDR_L_32IS1:
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 32) ? v_addr.pkt_bits : 0);
+ str += "; Addr=" + valStr + "; " + ctxtStr;
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS0:
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS1:
+ contextStr(ctxtStr);
+ case ETM4_PKT_I_ADDR_L_64IS0:
+ case ETM4_PKT_I_ADDR_L_64IS1:
+ case ETE_PKT_I_SRC_ADDR_L_64IS0:
+ case ETE_PKT_I_SRC_ADDR_L_64IS1:
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 64) ? v_addr.pkt_bits : 0);
+ str += "; Addr=" + valStr + "; " + ctxtStr;
+ break;
+
+ case ETM4_PKT_I_CTXT:
+ contextStr(ctxtStr);
+ str += "; " + ctxtStr;
+ break;
+
+ case ETM4_PKT_I_ADDR_S_IS0:
+ case ETM4_PKT_I_ADDR_S_IS1:
+ case ETE_PKT_I_SRC_ADDR_S_IS0:
+ case ETE_PKT_I_SRC_ADDR_S_IS1:
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, v_addr.pkt_bits);
+ str += "; Addr=" + valStr;
+ break;
+
+ case ETM4_PKT_I_ADDR_MATCH:
+ case ETE_PKT_I_SRC_ADDR_MATCH:
+ addrMatchIdx(valStr);
+ str += ", " + valStr;
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true);
+ str += "; Addr=" + valStr + "; " + ctxtStr;
+ break;
+
+ case ETM4_PKT_I_ATOM_F1:
+ case ETM4_PKT_I_ATOM_F2:
+ case ETM4_PKT_I_ATOM_F3:
+ case ETM4_PKT_I_ATOM_F4:
+ case ETM4_PKT_I_ATOM_F5:
+ case ETM4_PKT_I_ATOM_F6:
+ atomSeq(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM4_PKT_I_EXCEPT:
+ exceptionInfo(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM4_PKT_I_TIMESTAMP:
+ {
+ std::ostringstream oss;
+ oss << "; Updated val = " << std::hex << "0x" << ts.timestamp;
+ if (pkt_valid.bits.cc_valid)
+ oss << "; CC=" << std::hex << "0x" << cycle_count;
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_TRACE_INFO:
+ {
+ std::ostringstream oss;
+ oss << "; INFO=" << std::hex << "0x" << trace_info.val;
+ oss << " { CC." << std::dec << trace_info.bits.cc_enabled;
+ if (isETE())
+ oss << ", TSTATE." << std::dec << trace_info.bits.in_trans_state;
+ oss << " }";
+ if (trace_info.bits.cc_enabled)
+ oss << "; CC_THRESHOLD=" << std::hex << "0x" << cc_threshold;
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CCNT_F1:
+ case ETM4_PKT_I_CCNT_F2:
+ case ETM4_PKT_I_CCNT_F3:
+ {
+ std::ostringstream oss;
+ oss << "; Count=" << std::hex << "0x" << cycle_count;
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CANCEL_F1:
+ {
+ std::ostringstream oss;
+ oss << "; Cancel(" << std::dec << cancel_elements << ")";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CANCEL_F1_MISPRED:
+ {
+ std::ostringstream oss;
+ oss << "; Cancel(" << std::dec << cancel_elements << "), Mispredict";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_MISPREDICT:
+ {
+ std::ostringstream oss;
+ oss << "; ";
+ if (atom.num) {
+ atomSeq(valStr);
+ oss << "Atom: " << valStr << ", ";
+ }
+ oss << "Mispredict";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CANCEL_F2:
+ {
+ std::ostringstream oss;
+ oss << "; ";
+ if (atom.num) {
+ atomSeq(valStr);
+ oss << "Atom: " << valStr << ", ";
+ }
+ oss << "Cancel(1), Mispredict";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CANCEL_F3:
+ {
+ std::ostringstream oss;
+ oss << "; ";
+ if (atom.num) {
+ oss << "Atom: E, ";
+ }
+ oss << "Cancel(" << std::dec << cancel_elements << "), Mispredict";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_COMMIT:
+ {
+ std::ostringstream oss;
+ oss << "; Commit(" << std::dec << commit_elements << ")";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_Q:
+ {
+ std::ostringstream oss;
+ if (Q_pkt.count_present)
+ {
+ oss << "; Count(" << std::dec << Q_pkt.q_count << ")";
+ str += oss.str();
+ }
+ else
+ str += "; Count(Unknown)";
+
+ if (Q_pkt.addr_match)
+ {
+ addrMatchIdx(valStr);
+ str += "; " + valStr;
+ }
+
+ if (Q_pkt.addr_present || Q_pkt.addr_match)
+ {
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 64) ? v_addr.pkt_bits : 0);
+ str += "; Addr=" + valStr;
+ }
+ }
+ break;
+ }
+
+}
+
+void EtmV4ITrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const
+{
+ toString(str); // TBD add in formatted response.
+}
+
+const char *EtmV4ITrcPacket::packetTypeName(const ocsd_etmv4_i_pkt_type type, const char **ppDesc) const
+{
+ const char *pName = "I_UNKNOWN";
+ const char *pDesc = "Unknown Packet Header";
+
+ switch(type)
+ {
+ case ETM4_PKT_I_NOTSYNC:
+ pName = "I_NOT_SYNC";
+ pDesc = "I Stream not synchronised";
+ break;
+
+ case ETM4_PKT_I_INCOMPLETE_EOT:
+ pName = "I_INCOMPLETE_EOT";
+ pDesc = "Incomplete packet at end of trace.";
+ break;
+
+ case ETM4_PKT_I_NO_ERR_TYPE:
+ pName = "I_NO_ERR_TYPE";
+ pDesc = "No Error Type.";
+ break;
+
+ case ETM4_PKT_I_BAD_SEQUENCE:
+ pName = "I_BAD_SEQUENCE";
+ pDesc = "Invalid Sequence in packet.";
+ break;
+
+ case ETM4_PKT_I_BAD_TRACEMODE:
+ pName = "I_BAD_TRACEMODE";
+ pDesc = "Invalid Packet for trace mode.";
+ break;
+
+ case ETM4_PKT_I_RESERVED:
+ pName = "I_RESERVED";
+ pDesc = "Reserved Packet Header";
+ break;
+
+ case ETM4_PKT_I_RESERVED_CFG:
+ pName = "I_RESERVED_CFG";
+ pDesc = "Reserved header for current configuration.";
+ break;
+
+ case ETM4_PKT_I_EXTENSION:
+ pName = "I_EXTENSION";
+ pDesc = "Extension packet header.";
+ break;
+
+ case ETM4_PKT_I_TRACE_INFO:
+ pName = "I_TRACE_INFO";
+ pDesc = "Trace Info.";
+ break;
+
+ case ETM4_PKT_I_TIMESTAMP:
+ pName = "I_TIMESTAMP";
+ pDesc = "Timestamp.";
+ break;
+
+ case ETM4_PKT_I_TRACE_ON:
+ pName = "I_TRACE_ON";
+ pDesc = "Trace On.";
+ break;
+
+ case ETM4_PKT_I_FUNC_RET:
+ pName = "I_FUNC_RET";
+ pDesc = "V8M - function return.";
+ break;
+
+ case ETM4_PKT_I_EXCEPT:
+ pName = "I_EXCEPT";
+ pDesc = "Exception.";
+ break;
+
+ case ETM4_PKT_I_EXCEPT_RTN:
+ pName = "I_EXCEPT_RTN";
+ pDesc = "Exception Return.";
+ break;
+
+ case ETE_PKT_I_COMMIT_WIN_MV:
+ pName = "I_COMMIT_WIN_MV";
+ pDesc = "Commit window move.";
+ break;
+
+ case ETE_PKT_I_TRANS_ST:
+ pName = "I_TRANS_ST";
+ pDesc = "Transaction Start.";
+ break;
+
+ case ETE_PKT_I_TRANS_COMMIT:
+ pName = "I_TRANS_COMMIT";
+ pDesc = "Transaction Commit.";
+ break;
+
+ case ETM4_PKT_I_CCNT_F1:
+ pName = "I_CCNT_F1";
+ pDesc = "Cycle Count format 1.";
+ break;
+
+ case ETM4_PKT_I_CCNT_F2:
+ pName = "I_CCNT_F2";
+ pDesc = "Cycle Count format 2.";
+ break;
+
+ case ETM4_PKT_I_CCNT_F3:
+ pName = "I_CCNT_F3";
+ pDesc = "Cycle Count format 3.";
+ break;
+
+ case ETM4_PKT_I_NUM_DS_MKR:
+ pName = "I_NUM_DS_MKR";
+ pDesc = "Data Synchronisation Marker - Numbered.";
+ break;
+
+ case ETM4_PKT_I_UNNUM_DS_MKR:
+ pName = "I_UNNUM_DS_MKR";
+ pDesc = "Data Synchronisation Marker - Unnumbered.";
+ break;
+
+ case ETM4_PKT_I_COMMIT:
+ pName = "I_COMMIT";
+ pDesc = "Commit";
+ break;
+
+ case ETM4_PKT_I_CANCEL_F1:
+ pName = "I_CANCEL_F1";
+ pDesc = "Cancel Format 1.";
+ break;
+
+ case ETM4_PKT_I_CANCEL_F1_MISPRED:
+ pName = "I_CANCEL_F1_MISPRED";
+ pDesc = "Cancel Format 1 + Mispredict.";
+ break;
+
+
+ case ETM4_PKT_I_MISPREDICT:
+ pName = "I_MISPREDICT";
+ pDesc = "Mispredict.";
+ break;
+
+ case ETM4_PKT_I_CANCEL_F2:
+ pName = "I_CANCEL_F2";
+ pDesc = "Cancel Format 2.";
+ break;
+
+ case ETM4_PKT_I_CANCEL_F3:
+ pName = "I_CANCEL_F3";
+ pDesc = "Cancel Format 3.";
+ break;
+
+ case ETM4_PKT_I_COND_I_F2:
+ pName = "I_COND_I_F2";
+ pDesc = "Conditional Instruction, format 2.";
+ break;
+
+ case ETM4_PKT_I_COND_FLUSH:
+ pName = "I_COND_FLUSH";
+ pDesc = "Conditional Flush.";
+ break;
+
+ case ETM4_PKT_I_COND_RES_F4:
+ pName = "I_COND_RES_F4";
+ pDesc = "Conditional Result, format 4.";
+ break;
+
+ case ETM4_PKT_I_COND_RES_F2:
+ pName = "I_COND_RES_F2";
+ pDesc = "Conditional Result, format 2.";
+ break;
+
+ case ETM4_PKT_I_COND_RES_F3:
+ pName = "I_COND_RES_F3";
+ pDesc = "Conditional Result, format 3.";
+ break;
+
+ case ETM4_PKT_I_COND_RES_F1:
+ pName = "I_COND_RES_F1";
+ pDesc = "Conditional Result, format 1.";
+ break;
+
+ case ETM4_PKT_I_COND_I_F1:
+ pName = "I_COND_I_F1";
+ pDesc = "Conditional Instruction, format 1.";
+ break;
+
+ case ETM4_PKT_I_COND_I_F3:
+ pName = "I_COND_I_F3";
+ pDesc = "Conditional Instruction, format 3.";
+ break;
+
+ case ETM4_PKT_I_IGNORE:
+ pName = "I_IGNORE";
+ pDesc = "Ignore.";
+ break;
+
+ case ETM4_PKT_I_EVENT:
+ pName = "I_EVENT";
+ pDesc = "Trace Event.";
+ break;
+
+ case ETM4_PKT_I_CTXT:
+ pName = "I_CTXT";
+ pDesc = "Context Packet.";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS0:
+ pName = "I_ADDR_CTXT_L_32IS0";
+ pDesc = "Address & Context, Long, 32 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS1:
+ pName = "I_ADDR_CTXT_L_32IS1";
+ pDesc = "Address & Context, Long, 32 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS0:
+ pName = "I_ADDR_CTXT_L_64IS0";
+ pDesc = "Address & Context, Long, 64 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS1:
+ pName = "I_ADDR_CTXT_L_64IS1";
+ pDesc = "Address & Context, Long, 64 bit, IS1.";
+ break;
+
+ case ETE_PKT_I_TS_MARKER:
+ pName = "I_TS_MARKER";
+ pDesc = "Timestamp Marker";
+ break;
+
+ case ETM4_PKT_I_ADDR_MATCH:
+ pName = "I_ADDR_MATCH";
+ pDesc = "Exact Address Match.";
+ break;
+
+ case ETM4_PKT_I_ADDR_S_IS0:
+ pName = "I_ADDR_S_IS0";
+ pDesc = "Address, Short, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_S_IS1:
+ pName = "I_ADDR_S_IS1";
+ pDesc = "Address, Short, IS1.";
+ break;
+
+ case ETM4_PKT_I_ADDR_L_32IS0:
+ pName = "I_ADDR_L_32IS0";
+ pDesc = "Address, Long, 32 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_L_32IS1:
+ pName = "I_ADDR_L_32IS1";
+ pDesc = "Address, Long, 32 bit, IS1.";
+ break;
+
+ case ETM4_PKT_I_ADDR_L_64IS0:
+ pName = "I_ADDR_L_64IS0";
+ pDesc = "Address, Long, 64 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_L_64IS1:
+ pName = "I_ADDR_L_64IS1";
+ pDesc = "Address, Long, 64 bit, IS1.";
+ break;
+
+ case ETM4_PKT_I_Q:
+ pName = "I_Q";
+ pDesc = "Q Packet.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_MATCH:
+ pName = "I_SRC_ADDR_MATCH";
+ pDesc = "Exact Source Address Match.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_S_IS0:
+ pName = "I_SRC_ADDR_S_IS0";
+ pDesc = "Source Address, Short, IS0.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_S_IS1:
+ pName = "I_SRC_ADDR_S_IS1";
+ pDesc = "Source Address, Short, IS1.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_L_32IS0:
+ pName = "I_SCR_ADDR_L_32IS0";
+ pDesc = "Source Address, Long, 32 bit, IS0.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_L_32IS1:
+ pName = "I_SRC_ADDR_L_32IS1";
+ pDesc = "Source Address, Long, 32 bit, IS1.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_L_64IS0:
+ pName = "I_SRC_ADDR_L_64IS0";
+ pDesc = "Source Address, Long, 64 bit, IS0.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_L_64IS1:
+ pName = "I_SRC_ADDR_L_64IS1";
+ pDesc = "Source Address, Long, 64 bit, IS1.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F6:
+ pName = "I_ATOM_F6";
+ pDesc = "Atom format 6.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F5:
+ pName = "I_ATOM_F5";
+ pDesc = "Atom format 5.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F2:
+ pName = "I_ATOM_F2";
+ pDesc = "Atom format 2.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F4:
+ pName = "I_ATOM_F4";
+ pDesc = "Atom format 4.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F1:
+ pName = "I_ATOM_F1";
+ pDesc = "Atom format 1.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F3:
+ pName = "I_ATOM_F3";
+ pDesc = "Atom format 3.";
+ break;
+
+ case ETM4_PKT_I_ASYNC:
+ pName = "I_ASYNC";
+ pDesc = "Alignment Synchronisation.";
+ break;
+
+ case ETM4_PKT_I_DISCARD:
+ pName = "I_DISCARD";
+ pDesc = "Discard.";
+ break;
+
+ case ETM4_PKT_I_OVERFLOW:
+ pName = "I_OVERFLOW";
+ pDesc = "Overflow.";
+ break;
+
+ case ETE_PKT_I_PE_RESET:
+ pName = "I_PE_RESET";
+ pDesc = "PE Reset.";
+ break;
+
+ case ETE_PKT_I_TRANS_FAIL:
+ pName = "I_TRANS_FAIL";
+ pDesc = "Transaction Fail.";
+ break;
+
+ 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<ocsd_etmv4_i_pkt *>(this) = *p_pkt;
+ return *this;
+}
+
+/* End of File trc_pkt_elem_etmv4i.cpp */
diff --git a/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp
new file mode 100644
index 0000000..d0573d6
--- /dev/null
+++ b/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp
@@ -0,0 +1,1778 @@
+/*
+ * \file trc_pkt_proc_etmv4i.cpp
+ * \brief OpenCSD : Packet processor for ETMv4
+ *
+ * \copyright Copyright (c) 2015, 2019, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opencsd/etmv4/trc_pkt_proc_etmv4.h"
+#include "common/ocsd_error.h"
+
+#ifdef __GNUC__
+ // G++ doesn't like the ## pasting
+#define ETMV4I_PKTS_NAME "PKTP_ETMV4I"
+#else
+ // VC++ is fine
+#define ETMV4I_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_ETMV4I"
+#endif
+
+static const uint32_t ETMV4_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON;
+
+// test defines - if testing with ETMv4 sources, disable error on ERET.
+// #define ETE_TRACE_ERET_AS_IGNORE
+
+/* trace etmv4 packet processing class */
+TrcPktProcEtmV4I::TrcPktProcEtmV4I() : TrcPktProcBase(ETMV4I_PKTS_NAME),
+ m_isInit(false),
+ m_first_trace_info(false)
+{
+ m_supported_op_flags = ETMV4_SUPPORTED_OP_FLAGS;
+}
+
+TrcPktProcEtmV4I::TrcPktProcEtmV4I(int instIDNum) : TrcPktProcBase(ETMV4I_PKTS_NAME, instIDNum),
+ m_isInit(false),
+ m_first_trace_info(false)
+{
+ m_supported_op_flags = ETMV4_SUPPORTED_OP_FLAGS;
+}
+
+
+TrcPktProcEtmV4I::~TrcPktProcEtmV4I()
+{
+}
+
+ocsd_err_t TrcPktProcEtmV4I::onProtocolConfig()
+{
+ InitProcessorState();
+ m_config = *TrcPktProcBase::getProtocolConfig();
+ BuildIPacketTable(); // packet table based on config
+ m_curr_packet.setProtocolVersion(m_config.FullVersion());
+ m_isInit = true;
+ statsInit();
+ return OCSD_OK;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::processData( const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ if (!m_isInit)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ m_trcIn.init(dataBlockSize, pDataBlock, &m_currPacketData);
+ m_blockIndex = index;
+ bool done = false;
+ uint8_t nextByte;
+
+ do
+ {
+ try
+ {
+ while ( (!m_trcIn.empty() || (m_process_state == SEND_PKT)) &&
+ OCSD_DATA_RESP_IS_CONT(resp)
+ )
+ {
+ switch (m_process_state)
+ {
+ case PROC_HDR:
+ m_packet_index = m_blockIndex + m_trcIn.processed();
+ if (m_is_sync)
+ {
+ nextByte = m_trcIn.peekNextByte();
+ m_pIPktFn = m_i_table[nextByte].pptkFn;
+ m_curr_packet.type = m_i_table[nextByte].pkt_type;
+ }
+ else
+ {
+ // unsynced - process data until we see a sync point
+ m_pIPktFn = &TrcPktProcEtmV4I::iNotSync;
+ m_curr_packet.type = ETM4_PKT_I_NOTSYNC;
+ }
+ m_process_state = PROC_DATA;
+
+ case PROC_DATA:
+ // loop till full packet or no more data...
+ while (!m_trcIn.empty() && (m_process_state == PROC_DATA))
+ {
+ nextByte = m_trcIn.peekNextByte();
+ m_trcIn.copyByteToPkt(); // move next byte into the packet
+ (this->*m_pIPktFn)(nextByte);
+ }
+ break;
+
+ case SEND_PKT:
+ resp = outputPacket();
+ InitPacketState();
+ m_process_state = PROC_HDR;
+ break;
+
+ case SEND_UNSYNCED:
+ resp = outputUnsyncedRawPacket();
+ if (m_update_on_unsync_packet_index != 0)
+ {
+ m_packet_index = m_update_on_unsync_packet_index;
+ m_update_on_unsync_packet_index = 0;
+ }
+ m_process_state = PROC_DATA; // after dumping unsynced data, still in data mode.
+ break;
+ }
+ }
+ done = true;
+ }
+ catch(ocsdError &err)
+ {
+ done = true;
+ LogError(err);
+ if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) ||
+ (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR))
+ {
+ // send invalid packets up the pipe to let the next stage decide what to do.
+ if (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)
+ statsAddBadHdrCount(1);
+ else
+ statsAddBadSeqCount(1);
+ m_process_state = SEND_PKT;
+ done = false;
+ }
+ else
+ {
+ // bail out on any other error.
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+ }
+ catch(...)
+ {
+ done = true;
+ /// vv bad at this point.
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+ const ocsdError &fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_config.getTraceID(),"Unknown System Error decoding trace.");
+ LogError(fatal);
+ }
+ } while (!done);
+
+ statsAddTotalCount(m_trcIn.processed());
+ *numBytesProcessed = m_trcIn.processed();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ if (!m_isInit)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ // if we have a partial packet then send to attached sinks
+ if(m_currPacketData.size() != 0)
+ {
+ m_curr_packet.updateErrType(ETM4_PKT_I_INCOMPLETE_EOT);
+ resp = outputPacket();
+ InitPacketState();
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::onReset()
+{
+ if (!m_isInit)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ // prepare for new decoding session
+ InitProcessorState();
+ return OCSD_RESP_CONT;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::onFlush()
+{
+ if (!m_isInit)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ // packet processor never holds on to flushable data (may have partial packet,
+ // but any full packets are immediately sent)
+ return OCSD_RESP_CONT;
+}
+
+void TrcPktProcEtmV4I::InitPacketState()
+{
+ m_currPacketData.clear();
+ m_curr_packet.initNextPacket(); // clear for next packet.
+ m_update_on_unsync_packet_index = 0;
+}
+
+void TrcPktProcEtmV4I::InitProcessorState()
+{
+ InitPacketState();
+ m_pIPktFn = &TrcPktProcEtmV4I::iNotSync;
+ m_packet_index = 0;
+ m_is_sync = false;
+ m_first_trace_info = false;
+ m_sent_notsync_packet = false;
+ m_process_state = PROC_HDR;
+ m_curr_packet.initStartState();
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::outputPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ resp = outputOnAllInterfaces(m_packet_index,&m_curr_packet,&m_curr_packet.type,m_currPacketData);
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::outputUnsyncedRawPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ statsAddUnsyncCount(m_dump_unsynced_bytes);
+ outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]);
+
+ if(!m_sent_notsync_packet)
+ {
+ resp = outputDecodedPacket(m_packet_index,&m_curr_packet);
+ m_sent_notsync_packet = true;
+ }
+
+ if(m_currPacketData.size() <= m_dump_unsynced_bytes)
+ m_currPacketData.clear();
+ else
+ m_currPacketData.erase(m_currPacketData.begin(),m_currPacketData.begin()+m_dump_unsynced_bytes);
+
+ return resp;
+}
+
+void TrcPktProcEtmV4I::iNotSync(const uint8_t lastByte)
+{
+ // is it an extension byte?
+ if (lastByte == 0x00) // TBD : add check for forced sync in here?
+ {
+ if (m_currPacketData.size() > 1)
+ {
+ m_dump_unsynced_bytes = m_currPacketData.size() - 1;
+ m_process_state = SEND_UNSYNCED;
+ // outputting some data then update packet index after so output indexes accurate
+ m_update_on_unsync_packet_index = m_blockIndex + m_trcIn.processed() - 1;
+ }
+ else
+ m_packet_index = m_blockIndex + m_trcIn.processed() - 1; // set it up now otherwise.
+
+ m_pIPktFn = m_i_table[lastByte].pptkFn;
+ }
+ else if (m_currPacketData.size() >= 8)
+ {
+ m_dump_unsynced_bytes = m_currPacketData.size();
+ m_process_state = SEND_UNSYNCED;
+ // outputting some data then update packet index after so output indexes accurate
+ m_update_on_unsync_packet_index = m_blockIndex + m_trcIn.processed();
+ }
+}
+
+void TrcPktProcEtmV4I::iPktNoPayload(const uint8_t lastByte)
+{
+ // some expansion may be required...
+ switch(m_curr_packet.type)
+ {
+ case ETM4_PKT_I_ADDR_MATCH:
+ case ETE_PKT_I_SRC_ADDR_MATCH:
+ m_curr_packet.setAddressExactMatch(lastByte & 0x3);
+ break;
+
+ case ETM4_PKT_I_EVENT:
+ m_curr_packet.setEvent(lastByte & 0xF);
+ break;
+
+ case ETM4_PKT_I_NUM_DS_MKR:
+ case ETM4_PKT_I_UNNUM_DS_MKR:
+ m_curr_packet.setDataSyncMarker(lastByte & 0x7);
+ break;
+
+ // these just need the packet type - no processing required.
+ case ETM4_PKT_I_COND_FLUSH:
+ case ETM4_PKT_I_EXCEPT_RTN:
+ case ETM4_PKT_I_TRACE_ON:
+ case ETM4_PKT_I_FUNC_RET:
+ case ETE_PKT_I_TRANS_ST:
+ case ETE_PKT_I_TRANS_COMMIT:
+ case ETM4_PKT_I_IGNORE:
+ default: break;
+ }
+ m_process_state = SEND_PKT; // now just send it....
+}
+
+void TrcPktProcEtmV4I::iPktReserved(const uint8_t lastByte)
+{
+ m_curr_packet.updateErrType(ETM4_PKT_I_RESERVED, lastByte); // swap type for err type
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,m_config.getTraceID());
+}
+
+void TrcPktProcEtmV4I::iPktInvalidCfg(const uint8_t lastByte)
+{
+ m_curr_packet.updateErrType(ETM4_PKT_I_RESERVED_CFG, lastByte); // swap type for err type
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PCKT_HDR, m_packet_index, m_config.getTraceID());
+}
+
+void TrcPktProcEtmV4I::iPktExtension(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 2)
+ {
+ // not sync and not next by 0x00 - not sync sequence
+ if(!m_is_sync && (lastByte != 0x00))
+ {
+ m_pIPktFn = &TrcPktProcEtmV4I::iNotSync;
+ m_curr_packet.type = ETM4_PKT_I_NOTSYNC;
+ return;
+ }
+
+ switch(lastByte)
+ {
+ case 0x03: // discard packet.
+ m_curr_packet.type = ETM4_PKT_I_DISCARD;
+ m_process_state = SEND_PKT;
+ break;
+
+ case 0x05:
+ m_curr_packet.type = ETM4_PKT_I_OVERFLOW;
+ m_process_state = SEND_PKT;
+ break;
+
+ case 0x00:
+ m_curr_packet.type = ETM4_PKT_I_ASYNC;
+ m_pIPktFn = &TrcPktProcEtmV4I::iPktASync; // handle subsequent bytes as async
+ break;
+
+ default:
+ m_curr_packet.err_type = m_curr_packet.type;
+ m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE;
+ m_process_state = SEND_PKT;
+ break;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktASync(const uint8_t lastByte)
+{
+ if(lastByte != 0x00)
+ {
+ // not sync and not next by 0x00 - not sync sequence if < 12
+ if(!m_is_sync && m_currPacketData.size() != 12)
+ {
+ m_pIPktFn = &TrcPktProcEtmV4I::iNotSync;
+ m_curr_packet.type = ETM4_PKT_I_NOTSYNC;
+ return;
+ }
+
+ // 12 bytes and not valid sync sequence - not possible even if not synced
+ m_process_state = SEND_PKT;
+ if((m_currPacketData.size() != 12) || (lastByte != 0x80))
+ {
+ m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE;
+ m_curr_packet.err_type = ETM4_PKT_I_ASYNC;
+ }
+ else
+ m_is_sync = true; // found a sync packet, mark decoder as synchronised.
+ }
+ else if(m_currPacketData.size() == 12)
+ {
+ if(!m_is_sync)
+ {
+ // if we are not yet synced then ignore extra leading 0x00.
+ m_dump_unsynced_bytes = 1;
+ m_process_state = SEND_UNSYNCED;
+ }
+ else
+ {
+ // bad periodic ASYNC sequence.
+ m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE;
+ m_curr_packet.err_type = ETM4_PKT_I_ASYNC;
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktTraceInfo(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1) // header
+ {
+ //clear flags
+ m_tinfo_sections.sectFlags = 0; // mark all sections as incomplete.
+ m_tinfo_sections.ctrlBytes = 1; // assume only a single control section byte for now
+
+ }
+ else if(m_currPacketData.size() == 2) // first payload control byte
+ {
+ // figure out which sections are absent and set to true - opposite of bitfeild in byte;
+ m_tinfo_sections.sectFlags = (~lastByte) & TINFO_ALL_SECT;
+
+ // see if there is an extended control section, otherwise this byte is it.
+ if((lastByte & 0x80) == 0x0)
+ m_tinfo_sections.sectFlags |= TINFO_CTRL;
+
+ }
+ else
+ {
+ if(!(m_tinfo_sections.sectFlags & TINFO_CTRL))
+ {
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_CTRL;
+ m_tinfo_sections.ctrlBytes++;
+ }
+ else if(!(m_tinfo_sections.sectFlags & TINFO_INFO_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_INFO_SECT;
+ else if(!(m_tinfo_sections.sectFlags & TINFO_KEY_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_KEY_SECT;
+ else if(!(m_tinfo_sections.sectFlags & TINFO_SPEC_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_SPEC_SECT;
+ else if(!(m_tinfo_sections.sectFlags & TINFO_CYCT_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_CYCT_SECT;
+ else if (!(m_tinfo_sections.sectFlags & TINFO_WNDW_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_WNDW_SECT;
+ }
+
+ // all sections accounted for?
+ if(m_tinfo_sections.sectFlags == TINFO_ALL)
+ {
+ // index of first section is number of payload control bytes + 1 for header byte
+ unsigned idx = m_tinfo_sections.ctrlBytes + 1;
+ uint32_t fieldVal = 0;
+ uint8_t presSect = m_currPacketData[1] & TINFO_ALL_SECT; // first payload control byte
+
+ m_curr_packet.clearTraceInfo();
+
+ if((presSect & TINFO_INFO_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData,idx,fieldVal);
+ m_curr_packet.setTraceInfo(fieldVal);
+ }
+ if((presSect & TINFO_KEY_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData,idx,fieldVal);
+ m_curr_packet.setTraceInfoKey(fieldVal);
+ }
+ if((presSect & TINFO_SPEC_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData,idx,fieldVal);
+ m_curr_packet.setTraceInfoSpec(fieldVal);
+ }
+ if((presSect & TINFO_CYCT_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData,idx,fieldVal);
+ m_curr_packet.setTraceInfoCyct(fieldVal);
+ }
+ if ((presSect & TINFO_WNDW_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData, idx, fieldVal);
+ /* Trace commit window unsupported in current ETE versions */
+ }
+ m_process_state = SEND_PKT;
+ m_first_trace_info = true;
+ }
+
+}
+
+void TrcPktProcEtmV4I::iPktTimestamp(const uint8_t lastByte)
+{
+ // process the header byte
+ if(m_currPacketData.size() == 1)
+ {
+ m_ccount_done = (bool)((lastByte & 0x1) == 0); // 0 = not present
+ m_ts_done = false;
+ m_ts_bytes = 0;
+ }
+ else
+ {
+ if(!m_ts_done)
+ {
+ m_ts_bytes++;
+ m_ts_done = (m_ts_bytes == 9) || ((lastByte & 0x80) == 0);
+ }
+ else if(!m_ccount_done)
+ {
+ m_ccount_done = (bool)((lastByte & 0x80) == 0);
+ // TBD: check for oorange ccount - bad packet.
+ }
+ }
+
+ if(m_ts_done && m_ccount_done)
+ {
+ int idx = 1;
+ uint64_t tsVal;
+ int ts_bytes = extractTSField64(m_currPacketData, idx, tsVal);
+ int ts_bits;
+
+ // if ts_bytes 8 or less, then cont bits on each byte, otherwise full 64 bit value for 9 bytes
+ ts_bits = ts_bytes < 9 ? ts_bytes * 7 : 64;
+
+ if(!m_curr_packet.pkt_valid.bits.ts_valid && m_first_trace_info)
+ ts_bits = 64; // after trace info, missing bits are all 0.
+
+ m_curr_packet.setTS(tsVal,(uint8_t)ts_bits);
+
+ if((m_currPacketData[0] & 0x1) == 0x1)
+ {
+ uint32_t countVal, countMask;
+
+ idx += ts_bytes;
+ extractContField(m_currPacketData, idx, countVal, 3); // only 3 possible count bytes.
+ countMask = (((uint32_t)1UL << m_config.ccSize()) - 1); // mask of the CC size
+ countVal &= countMask;
+ m_curr_packet.setCycleCount(countVal);
+ }
+
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::iPktException(const uint8_t lastByte)
+{
+ uint16_t excep_type = 0;
+
+ switch(m_currPacketData.size())
+ {
+ case 1: m_excep_size = 3; break;
+ case 2: if((lastByte & 0x80) == 0x00)
+ m_excep_size = 2;
+ // ETE exception reset or trans failed
+ if (m_config.MajVersion() >= 0x5)
+ {
+ excep_type = (m_currPacketData[1] >> 1) & 0x1F;
+ if ((excep_type == 0x0) || (excep_type == 0x18))
+ m_excep_size = 3;
+ }
+ break;
+ }
+
+ if(m_currPacketData.size() == (unsigned)m_excep_size)
+ {
+ excep_type = (m_currPacketData[1] >> 1) & 0x1F;
+ uint8_t addr_interp = (m_currPacketData[1] & 0x40) >> 5 | (m_currPacketData[1] & 0x1);
+ uint8_t m_fault_pending = 0;
+ uint8_t m_type = (m_config.coreProfile() == profile_CortexM) ? 1 : 0;
+
+ // extended exception packet (probably M class);
+ if(m_currPacketData[1] & 0x80)
+ {
+ excep_type |= ((uint16_t)m_currPacketData[2] & 0x1F) << 5;
+ m_fault_pending = (m_currPacketData[2] >> 5) & 0x1;
+ }
+ m_curr_packet.setExceptionInfo(excep_type,addr_interp,m_fault_pending, m_type);
+ m_process_state = SEND_PKT;
+
+ // ETE exception reset or trans failed
+ if (m_config.MajVersion() >= 0x5)
+ {
+ if ((excep_type == 0x0) || (excep_type == 0x18))
+ {
+ m_curr_packet.set64BitAddress(0, 0);
+ if (excep_type == 0x18)
+ m_curr_packet.setType(ETE_PKT_I_TRANS_FAIL);
+ else
+ m_curr_packet.setType(ETE_PKT_I_PE_RESET);
+ }
+ }
+ // allow the standard address packet handlers to process the address packet field for the exception.
+ }
+}
+
+void TrcPktProcEtmV4I::iPktCycleCntF123(const uint8_t lastByte)
+{
+ ocsd_etmv4_i_pkt_type format = m_curr_packet.type;
+
+ if( m_currPacketData.size() == 1)
+ {
+ m_count_done = m_commit_done = false;
+ m_has_count = true;
+
+ if(format == ETM4_PKT_I_CCNT_F3)
+ {
+ // no commit section for TRCIDR0.COMMOPT == 1
+ if(!m_config.commitOpt1())
+ {
+ m_curr_packet.setCommitElements(((lastByte >> 2) & 0x3) + 1);
+ }
+ // TBD: warning of non-valid CC threshold here?
+ m_curr_packet.setCycleCount(m_curr_packet.getCCThreshold() + (lastByte & 0x3));
+ m_process_state = SEND_PKT;
+ }
+ else if(format == ETM4_PKT_I_CCNT_F1)
+ {
+ if((lastByte & 0x1) == 0x1)
+ {
+ m_has_count = false;
+ m_count_done = true;
+ }
+
+ // no commit section for TRCIDR0.COMMOPT == 1
+ if(m_config.commitOpt1())
+ m_commit_done = true;
+ }
+ }
+ else if((format == ETM4_PKT_I_CCNT_F2) && ( m_currPacketData.size() == 2))
+ {
+ int commit_offset = ((lastByte & 0x1) == 0x1) ? ((int)m_config.MaxSpecDepth() - 15) : 1;
+ int commit_elements = ((lastByte >> 4) & 0xF);
+ commit_elements += commit_offset;
+
+ // TBD: warning if commit elements < 0?
+
+ m_curr_packet.setCycleCount(m_curr_packet.getCCThreshold() + (lastByte & 0xF));
+ m_curr_packet.setCommitElements(commit_elements);
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ // F1 and size 2 or more
+ if(!m_commit_done)
+ m_commit_done = ((lastByte & 0x80) == 0x00);
+ else if(!m_count_done)
+ m_count_done = ((lastByte & 0x80) == 0x00);
+ }
+
+ if((format == ETM4_PKT_I_CCNT_F1) && m_commit_done && m_count_done)
+ {
+ int idx = 1; // index into buffer for payload data.
+ uint32_t field_value = 0;
+ // no commit section for TRCIDR0.COMMOPT == 1
+ if(!m_config.commitOpt1())
+ {
+ idx += extractContField(m_currPacketData,idx,field_value);
+ m_curr_packet.setCommitElements(field_value);
+ }
+ if (m_has_count)
+ {
+ extractContField(m_currPacketData, idx, field_value, 3);
+ m_curr_packet.setCycleCount(field_value + m_curr_packet.getCCThreshold());
+ }
+ else
+ m_curr_packet.setCycleCount(0); /* unknown CC marked as 0 after overflow */
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::iPktSpeclRes(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1)
+ {
+ switch(m_curr_packet.getType())
+ {
+ case ETM4_PKT_I_MISPREDICT:
+ case ETM4_PKT_I_CANCEL_F2:
+ switch(lastByte & 0x3)
+ {
+ case 0x1: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x1, 1); break; // E
+ case 0x2: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x3, 2); break; // EE
+ case 0x3: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x0, 1); break; // N
+ }
+ if (m_curr_packet.getType() == ETM4_PKT_I_CANCEL_F2)
+ m_curr_packet.setCancelElements(1);
+ else
+ m_curr_packet.setCancelElements(0);
+ m_process_state = SEND_PKT;
+ break;
+
+ case ETM4_PKT_I_CANCEL_F3:
+ if(lastByte & 0x1)
+ m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x1, 1); // E
+ m_curr_packet.setCancelElements(((lastByte >> 1) & 0x3) + 2);
+ m_process_state = SEND_PKT;
+ break;
+ }
+ }
+ else
+ {
+ if((lastByte & 0x80) == 0x00)
+ {
+ uint32_t field_val = 0;
+ extractContField(m_currPacketData,1,field_val);
+ if(m_curr_packet.getType() == ETM4_PKT_I_COMMIT)
+ m_curr_packet.setCommitElements(field_val);
+ else
+ m_curr_packet.setCancelElements(field_val);
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktCondInstr(const uint8_t lastByte)
+{
+ bool bF1Done = false;
+
+ if(m_currPacketData.size() == 1)
+ {
+ if(m_curr_packet.getType() == ETM4_PKT_I_COND_I_F2)
+ {
+ m_curr_packet.setCondIF2(lastByte & 0x3);
+ m_process_state = SEND_PKT;
+ }
+
+ }
+ else if(m_currPacketData.size() == 2)
+ {
+ if(m_curr_packet.getType() == ETM4_PKT_I_COND_I_F3) // f3 two bytes long
+ {
+ uint8_t num_c_elem = ((lastByte >> 1) & 0x3F) + (lastByte & 0x1);
+ m_curr_packet.setCondIF3(num_c_elem,(bool)((lastByte & 0x1) == 0x1));
+ // TBD: check for 0 num_c_elem in here.
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ bF1Done = ((lastByte & 0x80) == 0x00);
+ }
+ }
+ else
+ {
+ bF1Done = ((lastByte & 0x80) == 0x00);
+ }
+
+ if(bF1Done)
+ {
+ uint32_t cond_key = 0;
+ extractContField(m_currPacketData, 1, cond_key);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::iPktCondResult(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1)
+ {
+ m_F1P1_done = false; // F1 payload 1 done
+ m_F1P2_done = false; // F1 payload 2 done
+ m_F1has_P2 = false; // F1 has a payload 2
+
+ switch(m_curr_packet.getType())
+ {
+ case ETM4_PKT_I_COND_RES_F1:
+
+ m_F1has_P2 = true;
+ if((lastByte & 0xFC) == 0x6C)// only one payload set
+ {
+ m_F1P2_done = true;
+ m_F1has_P2 = false;
+ }
+ break;
+
+ case ETM4_PKT_I_COND_RES_F2:
+ m_curr_packet.setCondRF2((lastByte & 0x4) ? 2 : 1, lastByte & 0x3);
+ m_process_state = SEND_PKT;
+ break;
+
+ case ETM4_PKT_I_COND_RES_F3:
+ break;
+
+ case ETM4_PKT_I_COND_RES_F4:
+ m_curr_packet.setCondRF4(lastByte & 0x3);
+ m_process_state = SEND_PKT;
+ break;
+ }
+ }
+ else if((m_curr_packet.getType() == ETM4_PKT_I_COND_RES_F3) && (m_currPacketData.size() == 2))
+ {
+ // 2nd F3 packet
+ uint16_t f3_tokens = 0;
+ f3_tokens = (uint16_t)m_currPacketData[1];
+ f3_tokens |= ((uint16_t)m_currPacketData[0] & 0xf) << 8;
+ m_curr_packet.setCondRF3(f3_tokens);
+ m_process_state = SEND_PKT;
+ }
+ else // !first packet - F1
+ {
+ if(!m_F1P1_done)
+ m_F1P1_done = ((lastByte & 0x80) == 0x00);
+ else if(!m_F1P2_done)
+ m_F1P2_done = ((lastByte & 0x80) == 0x00);
+
+ if(m_F1P1_done && m_F1P2_done)
+ {
+ int st_idx = 1;
+ uint32_t key[2];
+ uint8_t result[2];
+ uint8_t CI[2];
+
+ st_idx+= extractCondResult(m_currPacketData,st_idx,key[0],result[0]);
+ CI[0] = m_currPacketData[0] & 0x1;
+ if(m_F1has_P2) // 2nd payload?
+ {
+ extractCondResult(m_currPacketData,st_idx,key[1],result[1]);
+ CI[1] = (m_currPacketData[0] >> 1) & 0x1;
+ }
+ m_curr_packet.setCondRF1(key,result,CI,m_F1has_P2);
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktContext(const uint8_t lastByte)
+{
+ bool bSendPacket = false;
+
+ if(m_currPacketData.size() == 1)
+ {
+ if((lastByte & 0x1) == 0)
+ {
+ m_curr_packet.setContextInfo(false); // no update context packet (ctxt same as last time).
+ m_process_state = SEND_PKT;
+ }
+ }
+ else if(m_currPacketData.size() == 2)
+ {
+ if((lastByte & 0xC0) == 0) // no VMID or CID
+ {
+ bSendPacket = true;
+ }
+ else
+ {
+ m_vmidBytes = ((lastByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0;
+ m_ctxtidBytes = ((lastByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0;
+ }
+ }
+ else // 3rd byte onwards
+ {
+ if(m_vmidBytes > 0)
+ m_vmidBytes--;
+ else if(m_ctxtidBytes > 0)
+ m_ctxtidBytes--;
+
+ if((m_ctxtidBytes == 0) && (m_vmidBytes == 0))
+ bSendPacket = true;
+ }
+
+ if(bSendPacket)
+ {
+ extractAndSetContextInfo(m_currPacketData,1);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::extractAndSetContextInfo(const std::vector<uint8_t> &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, (infoByte >> 3) & 0x1);
+
+ // see if there are VMID and CID bytes, and how many.
+ int nVMID_bytes = ((infoByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0;
+ int nCtxtID_bytes = ((infoByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0;
+
+ // extract any VMID and CID
+ int payload_idx = st_idx+1;
+ if(nVMID_bytes)
+ {
+ uint32_t VMID = 0;
+ for(int i = 0; i < nVMID_bytes; i++)
+ {
+ VMID |= ((uint32_t)m_currPacketData[i+payload_idx] << i*8);
+ }
+ payload_idx += nVMID_bytes;
+ m_curr_packet.setContextVMID(VMID);
+ }
+
+ if(nCtxtID_bytes)
+ {
+ uint32_t CID = 0;
+ for(int i = 0; i < nCtxtID_bytes; i++)
+ {
+ CID |= ((uint32_t)m_currPacketData[i+payload_idx] << i*8);
+ }
+ m_curr_packet.setContextCID(CID);
+ }
+}
+
+void TrcPktProcEtmV4I::iPktAddrCtxt(const uint8_t lastByte)
+{
+ if( m_currPacketData.size() == 1)
+ {
+ m_addrIS = 0;
+ m_addrBytes = 4;
+ m_bAddr64bit = false;
+ m_vmidBytes = 0;
+ m_ctxtidBytes = 0;
+ m_bCtxtInfoDone = false;
+
+ switch(m_curr_packet.type)
+ {
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS1:
+ m_addrIS = 1;
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS0:
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS1:
+ m_addrIS = 1;
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS0:
+ m_addrBytes = 8;
+ m_bAddr64bit = true;
+ break;
+ }
+ }
+ else
+ {
+ if(m_addrBytes == 0)
+ {
+ if(m_bCtxtInfoDone == false)
+ {
+ m_bCtxtInfoDone = true;
+ m_vmidBytes = ((lastByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0;
+ m_ctxtidBytes = ((lastByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0;
+ }
+ else
+ {
+ if( m_vmidBytes > 0)
+ m_vmidBytes--;
+ else if(m_ctxtidBytes > 0)
+ m_ctxtidBytes--;
+ }
+ }
+ else
+ m_addrBytes--;
+
+ if((m_addrBytes == 0) && m_bCtxtInfoDone && (m_vmidBytes == 0) && (m_ctxtidBytes == 0))
+ {
+ int st_idx = 1;
+ if(m_bAddr64bit)
+ {
+ uint64_t val64;
+ st_idx+=extract64BitLongAddr(m_currPacketData,st_idx,m_addrIS,val64);
+ m_curr_packet.set64BitAddress(val64,m_addrIS);
+ }
+ else
+ {
+ uint32_t val32;
+ st_idx+=extract32BitLongAddr(m_currPacketData,st_idx,m_addrIS,val32);
+ m_curr_packet.set32BitAddress(val32,m_addrIS);
+ }
+ extractAndSetContextInfo(m_currPacketData,st_idx);
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktShortAddr(const uint8_t lastByte)
+{
+ if (m_currPacketData.size() == 1)
+ {
+ m_addr_done = false;
+ m_addrIS = 0;
+ if ((lastByte == ETM4_PKT_I_ADDR_S_IS1) ||
+ (lastByte == ETE_PKT_I_SRC_ADDR_S_IS1))
+ m_addrIS = 1;
+ }
+ else if(!m_addr_done)
+ {
+ m_addr_done = (m_currPacketData.size() == 3) || ((lastByte & 0x80) == 0x00);
+ }
+
+ if(m_addr_done)
+ {
+ uint32_t addr_val = 0;
+ int bits = 0;
+
+ extractShortAddr(m_currPacketData,1,m_addrIS,addr_val,bits);
+ m_curr_packet.updateShortAddress(addr_val,m_addrIS,(uint8_t)bits);
+ m_process_state = SEND_PKT;
+ }
+}
+
+int TrcPktProcEtmV4I::extractShortAddr(const std::vector<uint8_t> &buffer, const int st_idx, const uint8_t IS, uint32_t &value, int &bits)
+{
+ int IS_shift = (IS == 0) ? 2 : 1;
+ int idx = 0;
+
+ bits = 7; // at least 7 bits
+ value = 0;
+ value |= ((uint32_t)(buffer[st_idx+idx] & 0x7F)) << IS_shift;
+
+ if(m_currPacketData[st_idx+idx] & 0x80)
+ {
+ idx++;
+ value |= ((uint32_t)m_currPacketData[st_idx+idx]) << (7 + IS_shift);
+ bits += 8;
+ }
+ idx++;
+ bits += IS_shift;
+ return idx;
+}
+
+void TrcPktProcEtmV4I::iPktLongAddr(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1)
+ {
+ // init the intra-byte data
+ m_addrIS = 0;
+ m_bAddr64bit = false;
+ m_addrBytes = 4;
+
+ switch(m_curr_packet.type)
+ {
+ case ETM4_PKT_I_ADDR_L_32IS1:
+ case ETE_PKT_I_SRC_ADDR_L_32IS1:
+ m_addrIS = 1;
+ case ETM4_PKT_I_ADDR_L_32IS0:
+ case ETE_PKT_I_SRC_ADDR_L_32IS0:
+ m_addrBytes = 4;
+ break;
+
+ case ETM4_PKT_I_ADDR_L_64IS1:
+ case ETE_PKT_I_SRC_ADDR_L_64IS1:
+ m_addrIS = 1;
+ case ETM4_PKT_I_ADDR_L_64IS0:
+ case ETE_PKT_I_SRC_ADDR_L_64IS0:
+ m_addrBytes = 8;
+ m_bAddr64bit = true;
+ break;
+ }
+ }
+ if(m_currPacketData.size() == (unsigned)(1+m_addrBytes))
+ {
+ int st_idx = 1;
+ if(m_bAddr64bit)
+ {
+ uint64_t val64;
+ st_idx+=extract64BitLongAddr(m_currPacketData,st_idx,m_addrIS,val64);
+ m_curr_packet.set64BitAddress(val64,m_addrIS);
+ }
+ else
+ {
+ uint32_t val32;
+ st_idx+=extract32BitLongAddr(m_currPacketData,st_idx,m_addrIS,val32);
+ m_curr_packet.set32BitAddress(val32,m_addrIS);
+ }
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::iPktQ(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1)
+ {
+ m_Q_type = lastByte & 0xF;
+
+ m_addrBytes = 0;
+ m_count_done = false;
+ m_has_addr = false;
+ m_addr_short = true;
+ m_addr_match = false;
+ m_addrIS = 1;
+ m_QE = 0;
+
+ switch(m_Q_type)
+ {
+ // count only - implied address.
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ m_addr_match = true;
+ m_has_addr = true;
+ m_QE = m_Q_type & 0x3;
+ case 0xC:
+ break;
+
+ // count + short address
+ case 0x5:
+ m_addrIS = 0;
+ case 0x6:
+ m_has_addr = true;
+ m_addrBytes = 2; // short IS0/1
+ break;
+
+ // count + long address
+ case 0xA:
+ m_addrIS = 0;
+ case 0xB:
+ m_has_addr = true;
+ m_addr_short = false;
+ m_addrBytes = 4; // long IS0/1
+ break;
+
+ // no count, no address
+ case 0xF:
+ m_count_done = true;
+ break;
+
+ // reserved values 0x3, 0x4, 0x7, 0x8, 0x9, 0xD, 0xE
+ default:
+ m_curr_packet.err_type = m_curr_packet.type;
+ m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE;
+ m_process_state = SEND_PKT;
+ break;
+ }
+ }
+ else
+ {
+ if(m_addrBytes > 0)
+ {
+ if(m_addr_short && m_addrBytes == 2) // short
+ {
+ if((lastByte & 0x80) == 0x00)
+ m_addrBytes--; // short version can have just single byte.
+ }
+ m_addrBytes--;
+ }
+ else if(!m_count_done)
+ {
+ m_count_done = ((lastByte & 0x80) == 0x00);
+ }
+ }
+
+ if(((m_addrBytes == 0) && m_count_done))
+ {
+ int idx = 1; // move past the header
+ int bits = 0;
+ uint32_t q_addr;
+ uint32_t q_count;
+
+ if(m_has_addr)
+ {
+ if(m_addr_match)
+ {
+ m_curr_packet.setAddressExactMatch(m_QE);
+ }
+ else if(m_addr_short)
+ {
+ idx+=extractShortAddr(m_currPacketData,idx,m_addrIS,q_addr,bits);
+ m_curr_packet.updateShortAddress(q_addr,m_addrIS,(uint8_t)bits);
+ }
+ else
+ {
+ idx+=extract32BitLongAddr(m_currPacketData,idx,m_addrIS,q_addr);
+ m_curr_packet.set32BitAddress(q_addr,m_addrIS);
+ }
+ }
+
+ if(m_Q_type != 0xF)
+ {
+ extractContField(m_currPacketData,idx,q_count);
+ m_curr_packet.setQType(true,q_count,m_has_addr,m_addr_match,m_Q_type);
+ }
+ else
+ {
+ m_curr_packet.setQType(false,0,false,false,0xF);
+ }
+ m_process_state = SEND_PKT;
+ }
+
+}
+
+void TrcPktProcEtmV4I::iAtom(const uint8_t lastByte)
+{
+ // patterns lsbit = oldest atom, ms bit = newest.
+ static const uint32_t f4_patterns[] = {
+ 0xE, // EEEN
+ 0x0, // NNNN
+ 0xA, // ENEN
+ 0x5 // NENE
+ };
+
+ uint8_t pattIdx = 0, pattCount = 0;
+ uint32_t pattern;
+
+ // atom packets are single byte, no payload.
+ switch(m_curr_packet.type)
+ {
+ case ETM4_PKT_I_ATOM_F1:
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x1), 1); // 1xE or N
+ break;
+
+ case ETM4_PKT_I_ATOM_F2:
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x3), 2); // 2x (E or N)
+ break;
+
+ case ETM4_PKT_I_ATOM_F3:
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x7), 3); // 3x (E or N)
+ break;
+
+ case ETM4_PKT_I_ATOM_F4:
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,f4_patterns[(lastByte & 0x3)], 4); // 4 atom pattern
+ break;
+
+ case ETM4_PKT_I_ATOM_F5:
+ pattIdx = ((lastByte & 0x20) >> 3) | (lastByte & 0x3);
+ switch(pattIdx)
+ {
+ case 5: // 0b101
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,0x1E, 5); // 5 atom pattern EEEEN
+ break;
+
+ case 1: // 0b001
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,0x00, 5); // 5 atom pattern NNNNN
+ break;
+
+ case 2: //0b010
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,0x0A, 5); // 5 atom pattern NENEN
+ break;
+
+ case 3: //0b011
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,0x15, 5); // 5 atom pattern ENENE
+ break;
+
+ default:
+ // TBD: warn about invalid pattern in here.
+ break;
+ }
+ break;
+
+ case ETM4_PKT_I_ATOM_F6:
+ pattCount = (lastByte & 0x1F) + 3; // count of E's
+ // TBD: check 23 or less at this point?
+ pattern = ((uint32_t)0x1 << pattCount) - 1; // set pattern to string of E's
+ if((lastByte & 0x20) == 0x00) // last atom is E?
+ pattern |= ((uint32_t)0x1 << pattCount);
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,pattern, pattCount+1);
+ break;
+ }
+
+ m_process_state = SEND_PKT;
+}
+
+// header byte processing is table driven.
+void TrcPktProcEtmV4I::BuildIPacketTable()
+{
+ // initialise everything as reserved.
+ for(int i = 0; i < 256; i++)
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_RESERVED;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iPktReserved;
+ }
+
+ // 0x00 - extension
+ m_i_table[0x00].pkt_type = ETM4_PKT_I_EXTENSION;
+ m_i_table[0x00].pptkFn = &TrcPktProcEtmV4I::iPktExtension;
+
+ // 0x01 - Trace info
+ m_i_table[0x01].pkt_type = ETM4_PKT_I_TRACE_INFO;
+ m_i_table[0x01].pptkFn = &TrcPktProcEtmV4I::iPktTraceInfo;
+
+ // b0000001x - timestamp
+ m_i_table[0x02].pkt_type = ETM4_PKT_I_TIMESTAMP;
+ m_i_table[0x02].pptkFn = &TrcPktProcEtmV4I::iPktTimestamp;
+ m_i_table[0x03].pkt_type = ETM4_PKT_I_TIMESTAMP;
+ m_i_table[0x03].pptkFn = &TrcPktProcEtmV4I::iPktTimestamp;
+
+ // b0000 0100 - trace on
+ m_i_table[0x04].pkt_type = ETM4_PKT_I_TRACE_ON;
+ m_i_table[0x04].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+
+
+ // b0000 0101 - Funct ret V8M
+ m_i_table[0x05].pkt_type = ETM4_PKT_I_FUNC_RET;
+ if ((m_config.coreProfile() == profile_CortexM) &&
+ (OCSD_IS_V8_ARCH(m_config.archVersion())) &&
+ (m_config.FullVersion() >= 0x42))
+ {
+ m_i_table[0x05].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // b0000 0110 - exception
+ m_i_table[0x06].pkt_type = ETM4_PKT_I_EXCEPT;
+ m_i_table[0x06].pptkFn = &TrcPktProcEtmV4I::iPktException;
+
+ // b0000 0111 - exception return
+ m_i_table[0x07].pkt_type = ETM4_PKT_I_EXCEPT_RTN;
+ if (m_config.MajVersion() >= 0x5) // not valid for ETE
+ {
+#ifdef ETE_TRACE_ERET_AS_IGNORE
+ m_i_table[0x07].pkt_type = ETM4_PKT_I_IGNORE;
+ m_i_table[0x07].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload;
+#else
+ m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+#endif
+ }
+ else
+ m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+
+ // b00001010, b00001011 ETE TRANS packets
+ if (m_config.MajVersion() >= 0x5)
+ {
+ m_i_table[0x0A].pkt_type = ETE_PKT_I_TRANS_ST;
+ m_i_table[0x0A].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+
+ m_i_table[0x0B].pkt_type = ETE_PKT_I_TRANS_COMMIT;
+ m_i_table[0x0B].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // b0000 110x - cycle count f2
+ // b0000 111x - cycle count f1
+ for(int i = 0; i < 4; i++)
+ {
+ m_i_table[0x0C+i].pkt_type = (i >= 2) ? ETM4_PKT_I_CCNT_F1 : ETM4_PKT_I_CCNT_F2;
+ m_i_table[0x0C+i].pptkFn = &TrcPktProcEtmV4I::iPktCycleCntF123;
+ }
+
+ // b0001 xxxx - cycle count f3
+ for(int i = 0; i < 16; i++)
+ {
+ m_i_table[0x10+i].pkt_type = ETM4_PKT_I_CCNT_F3;
+ m_i_table[0x10+i].pptkFn = &TrcPktProcEtmV4I::iPktCycleCntF123;
+ }
+
+ // b0010 0xxx - NDSM
+ for(int i = 0; i < 8; i++)
+ {
+ m_i_table[0x20 + i].pkt_type = ETM4_PKT_I_NUM_DS_MKR;
+ if (m_config.enabledDataTrace())
+ m_i_table[0x20+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ else
+ m_i_table[0x20+i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0010 10xx, b0010 1100 - UDSM
+ for(int i = 0; i < 5; i++)
+ {
+ m_i_table[0x28+i].pkt_type = ETM4_PKT_I_UNNUM_DS_MKR;
+ if (m_config.enabledDataTrace())
+ m_i_table[0x28+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ else
+ m_i_table[0x28+i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0010 1101 - commit
+ m_i_table[0x2D].pkt_type = ETM4_PKT_I_COMMIT;
+ m_i_table[0x2D].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+
+ // b0010 111x - cancel f1 (mis pred)
+ m_i_table[0x2E].pkt_type = ETM4_PKT_I_CANCEL_F1;
+ m_i_table[0x2E].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+ m_i_table[0x2F].pkt_type = ETM4_PKT_I_CANCEL_F1_MISPRED;
+ m_i_table[0x2F].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+
+ // b0011 00xx - mis predict
+ for(int i = 0; i < 4; i++)
+ {
+ m_i_table[0x30+i].pkt_type = ETM4_PKT_I_MISPREDICT;
+ m_i_table[0x30+i].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+ }
+
+ // b0011 01xx - cancel f2
+ for(int i = 0; i < 4; i++)
+ {
+ m_i_table[0x34+i].pkt_type = ETM4_PKT_I_CANCEL_F2;
+ m_i_table[0x34+i].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+ }
+
+ // b0011 1xxx - cancel f3
+ for(int i = 0; i < 8; i++)
+ {
+ m_i_table[0x38+i].pkt_type = ETM4_PKT_I_CANCEL_F3;
+ m_i_table[0x38+i].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+ }
+
+ bool bCondValid = m_config.hasCondTrace() && m_config.enabledCondITrace();
+
+ // b0100 000x, b0100 0010 - cond I f2
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0x40 + i].pkt_type = ETM4_PKT_I_COND_I_F2;
+ if (bCondValid)
+ m_i_table[0x40 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr;
+ else
+ m_i_table[0x40 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0100 0011 - cond flush
+ m_i_table[0x43].pkt_type = ETM4_PKT_I_COND_FLUSH;
+ if (bCondValid)
+ m_i_table[0x43].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ else
+ m_i_table[0x43].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+
+ // b0100 010x, b0100 0110 - cond res f4
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0x44 + i].pkt_type = ETM4_PKT_I_COND_RES_F4;
+ if (bCondValid)
+ m_i_table[0x44 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x44 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0100 100x, b0100 0110 - cond res f2
+ // b0100 110x, b0100 1110 - cond res f2
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0x48 + i].pkt_type = ETM4_PKT_I_COND_RES_F2;
+ if (bCondValid)
+ m_i_table[0x48 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x48 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0x4C + i].pkt_type = ETM4_PKT_I_COND_RES_F2;
+ if (bCondValid)
+ m_i_table[0x4C + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x4C + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0101xxxx - cond res f3
+ for (int i = 0; i < 16; i++)
+ {
+ m_i_table[0x50 + i].pkt_type = ETM4_PKT_I_COND_RES_F3;
+ if (bCondValid)
+ m_i_table[0x50 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x50 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b011010xx - cond res f1
+ for (int i = 0; i < 4; i++)
+ {
+ m_i_table[0x68 + i].pkt_type = ETM4_PKT_I_COND_RES_F1;
+ if (bCondValid)
+ m_i_table[0x68 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x68 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0110 1100 - cond instr f1
+ m_i_table[0x6C].pkt_type = ETM4_PKT_I_COND_I_F1;
+ if (bCondValid)
+ m_i_table[0x6C].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr;
+ else
+ m_i_table[0x6C].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+
+ // b0110 1101 - cond instr f3
+ m_i_table[0x6D].pkt_type = ETM4_PKT_I_COND_I_F3;
+ if (bCondValid)
+ m_i_table[0x6D].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr;
+ else
+ m_i_table[0x6D].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+
+ // b0110111x - cond res f1
+ for (int i = 0; i < 2; i++)
+ {
+ // G++ cannot understand [0x6E+i] so change these round
+ m_i_table[i + 0x6E].pkt_type = ETM4_PKT_I_COND_RES_F1;
+ if (bCondValid)
+ m_i_table[i + 0x6E].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[i + 0x6E].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // ETM 4.3 introduces ignore packets
+ if (m_config.FullVersion() >= 0x43)
+ {
+ m_i_table[0x70].pkt_type = ETM4_PKT_I_IGNORE;
+ m_i_table[0x70].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // b01110001 - b01111111 - event trace
+ for(int i = 0; i < 15; i++)
+ {
+ m_i_table[0x71+i].pkt_type = ETM4_PKT_I_EVENT;
+ m_i_table[0x71+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // 0b1000 000x - context
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x80+i].pkt_type = ETM4_PKT_I_CTXT;
+ m_i_table[0x80+i].pptkFn = &TrcPktProcEtmV4I::iPktContext;
+ }
+
+ // 0b1000 0010 to b1000 0011 - addr with ctxt
+ // 0b1000 0101 to b1000 0110 - addr with ctxt
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x82+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_CTXT_L_32IS0 : ETM4_PKT_I_ADDR_CTXT_L_32IS1;
+ m_i_table[0x82+i].pptkFn = &TrcPktProcEtmV4I::iPktAddrCtxt;
+ }
+
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x85+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_CTXT_L_64IS0 : ETM4_PKT_I_ADDR_CTXT_L_64IS1;
+ m_i_table[0x85+i].pptkFn = &TrcPktProcEtmV4I::iPktAddrCtxt;
+ }
+
+ // 0b1000 1000 - ETE 1.1 TS Marker. also ETMv4.6
+ if(m_config.FullVersion() >= 0x46)
+ {
+ m_i_table[0x88].pkt_type = ETE_PKT_I_TS_MARKER;
+ m_i_table[0x88].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+ // 0b1001 0000 to b1001 0010 - exact match addr
+ for(int i = 0; i < 3; i++)
+ {
+ m_i_table[0x90+i].pkt_type = ETM4_PKT_I_ADDR_MATCH;
+ m_i_table[0x90+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // b1001 0101 - b1001 0110 - addr short address
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x95+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_S_IS0 : ETM4_PKT_I_ADDR_S_IS1;
+ m_i_table[0x95+i].pptkFn = &TrcPktProcEtmV4I::iPktShortAddr;
+ }
+
+ // b10011010 - b10011011 - addr long address
+ // b10011101 - b10011110 - addr long address
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x9A+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_L_32IS0 : ETM4_PKT_I_ADDR_L_32IS1;
+ m_i_table[0x9A+i].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ }
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x9D+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_L_64IS0 : ETM4_PKT_I_ADDR_L_64IS1;
+ m_i_table[0x9D+i].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ }
+
+ // b1010xxxx - Q packet
+ for (int i = 0; i < 16; i++)
+ {
+ m_i_table[0xA0 + i].pkt_type = ETM4_PKT_I_Q;
+ // certain Q type codes are reserved.
+ switch (i) {
+ case 0x3:
+ case 0x4:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ case 0xD:
+ case 0xE:
+ // don't update pkt fn - leave at default reserved.
+ break;
+ default:
+ // if this config supports Q elem - otherwise reserved again.
+ if (m_config.hasQElem())
+ m_i_table[0xA0 + i].pptkFn = &TrcPktProcEtmV4I::iPktQ;
+ }
+ }
+
+ // b10110000 - b10111001 - ETE src address packets
+ if (m_config.FullVersion() >= 0x50)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0xB0 + i].pkt_type = ETE_PKT_I_SRC_ADDR_MATCH;
+ m_i_table[0xB0 + i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ m_i_table[0xB4].pkt_type = ETE_PKT_I_SRC_ADDR_S_IS0;
+ m_i_table[0xB4].pptkFn = &TrcPktProcEtmV4I::iPktShortAddr;
+ m_i_table[0xB5].pkt_type = ETE_PKT_I_SRC_ADDR_S_IS1;
+ m_i_table[0xB5].pptkFn = &TrcPktProcEtmV4I::iPktShortAddr;
+
+ m_i_table[0xB6].pkt_type = ETE_PKT_I_SRC_ADDR_L_32IS0;
+ m_i_table[0xB6].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ m_i_table[0xB7].pkt_type = ETE_PKT_I_SRC_ADDR_L_32IS1;
+ m_i_table[0xB7].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ m_i_table[0xB8].pkt_type = ETE_PKT_I_SRC_ADDR_L_64IS0;
+ m_i_table[0xB8].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ m_i_table[0xB9].pkt_type = ETE_PKT_I_SRC_ADDR_L_64IS1;
+ m_i_table[0xB9].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ }
+
+ // Atom Packets - all no payload but have specific pattern generation fn
+ for(int i = 0xC0; i <= 0xD4; i++) // atom f6
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F6;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xD5; i <= 0xD7; i++) // atom f5
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F5;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xD8; i <= 0xDB; i++) // atom f2
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F2;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xDC; i <= 0xDF; i++) // atom f4
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F4;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xE0; i <= 0xF4; i++) // atom f6
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F6;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+
+ // atom f5
+ m_i_table[0xF5].pkt_type = ETM4_PKT_I_ATOM_F5;
+ m_i_table[0xF5].pptkFn = &TrcPktProcEtmV4I::iAtom;
+
+ for(int i = 0xF6; i <= 0xF7; i++) // atom f1
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F1;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xF8; i <= 0xFF; i++) // atom f3
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F3;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+}
+
+ unsigned TrcPktProcEtmV4I::extractContField(const std::vector<uint8_t> &buffer, const unsigned st_idx, uint32_t &value, const unsigned byte_limit /*= 5*/)
+{
+ unsigned idx = 0;
+ bool lastByte = false;
+ uint8_t byteVal;
+ value = 0;
+ while(!lastByte && (idx < byte_limit)) // max 5 bytes for 32 bit value;
+ {
+ if(buffer.size() > (st_idx + idx))
+ {
+ // each byte has seven bits + cont bit
+ byteVal = buffer[(st_idx + idx)];
+ lastByte = (byteVal & 0x80) != 0x80;
+ value |= ((uint32_t)(byteVal & 0x7F)) << (idx * 7);
+ idx++;
+ }
+ else
+ {
+ throwBadSequenceError("Invalid 32 bit continuation fields in packet");
+ }
+ }
+ return idx;
+}
+
+unsigned TrcPktProcEtmV4I::extractTSField64(const std::vector<uint8_t> &buffer, const unsigned st_idx, uint64_t &value)
+{
+ const unsigned max_byte_idx = 8; /* the 9th byte, index 8, will use full 8 bits for value */
+ unsigned idx = 0;
+ bool lastByte = false;
+ uint8_t byteVal;
+ uint8_t byteValMask = 0x7f;
+
+ /* init value */
+ value = 0;
+ while(!lastByte) // 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)];
+
+ /* detect the final byte - which uses full 8 bits as value */
+ if (idx == max_byte_idx)
+ {
+ byteValMask = 0xFF; /* last byte of 9, no cont bit */
+ lastByte = true;
+ }
+ else
+ lastByte = (byteVal & 0x80) != 0x80;
+
+ value |= ((uint64_t)(byteVal & byteValMask)) << (idx * 7);
+ idx++;
+ }
+ else
+ {
+ throwBadSequenceError("Invalid 64 bit continuation fields in packet");
+ }
+ }
+ // index is the count of bytes used here.
+ return idx;
+}
+
+ unsigned TrcPktProcEtmV4I::extractCondResult(const std::vector<uint8_t> &buffer, const unsigned st_idx, uint32_t& key, uint8_t &result)
+{
+ unsigned idx = 0;
+ bool lastByte = false;
+ int incr = 0;
+
+ key = 0;
+
+ while(!lastByte && (idx < 6)) // cannot be more than 6 bytes for res + 32 bit key
+ {
+ if(buffer.size() > (st_idx + idx))
+ {
+ if(idx == 0)
+ {
+ result = buffer[st_idx+idx];
+ key = (buffer[st_idx+idx] >> 4) & 0x7;
+ incr+=3;
+ }
+ else
+ {
+ key |= ((uint32_t)(buffer[st_idx+idx] & 0x7F)) << incr;
+ incr+=7;
+ }
+ lastByte = (bool)((buffer[st_idx+idx] & 0x80) == 0);
+ idx++;
+ }
+ else
+ {
+ throwBadSequenceError("Invalid continuation fields in packet");
+ }
+ }
+ return idx;
+}
+
+int TrcPktProcEtmV4I::extract64BitLongAddr(const std::vector<uint8_t> &buffer, const int st_idx, const uint8_t IS, uint64_t &value)
+{
+ value = 0;
+ if(IS == 0)
+ {
+ value |= ((uint64_t)(buffer[st_idx+0] & 0x7F)) << 2;
+ value |= ((uint64_t)(buffer[st_idx+1] & 0x7F)) << 9;
+ }
+ else
+ {
+ value |= ((uint64_t)(buffer[st_idx+0] & 0x7F)) << 1;
+ value |= ((uint64_t)buffer[st_idx+1]) << 8;
+ }
+ value |= ((uint64_t)buffer[st_idx+2]) << 16;
+ value |= ((uint64_t)buffer[st_idx+3]) << 24;
+ value |= ((uint64_t)buffer[st_idx+4]) << 32;
+ value |= ((uint64_t)buffer[st_idx+5]) << 40;
+ value |= ((uint64_t)buffer[st_idx+6]) << 48;
+ value |= ((uint64_t)buffer[st_idx+7]) << 56;
+ return 8;
+}
+
+int TrcPktProcEtmV4I::extract32BitLongAddr(const std::vector<uint8_t> &buffer, const int st_idx, const uint8_t IS, uint32_t &value)
+{
+ value = 0;
+ if(IS == 0)
+ {
+ value |= ((uint32_t)(buffer[st_idx+0] & 0x7F)) << 2;
+ value |= ((uint32_t)(buffer[st_idx+1] & 0x7F)) << 9;
+ }
+ else
+ {
+ value |= ((uint32_t)(buffer[st_idx+0] & 0x7F)) << 1;
+ value |= ((uint32_t)buffer[st_idx+1]) << 8;
+ }
+ value |= ((uint32_t)buffer[st_idx+2]) << 16;
+ value |= ((uint32_t)buffer[st_idx+3]) << 24;
+ return 4;
+}
+
+void TrcPktProcEtmV4I::throwBadSequenceError(const char *pszExtMsg)
+{
+ m_curr_packet.updateErrType(ETM4_PKT_I_BAD_SEQUENCE); // swap type for err type
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,m_config.getTraceID(),pszExtMsg);
+}
+
+
+/* End of File trc_pkt_proc_etmv4i.cpp */
diff --git a/decoder/source/i_dec/trc_i_decode.cpp b/decoder/source/i_dec/trc_i_decode.cpp
new file mode 100644
index 0000000..0e05895
--- /dev/null
+++ b/decoder/source/i_dec/trc_i_decode.cpp
@@ -0,0 +1,236 @@
+/*
+ * \file trc_i_decode.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opencsd/ocsd_if_types.h"
+#include "i_dec/trc_i_decode.h"
+#include "i_dec/trc_idec_arminst.h"
+
+ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info)
+{
+ ocsd_err_t err = OCSD_OK;
+ struct decode_info info;
+
+ info.instr_sub_type = OCSD_S_INSTR_NONE;
+ info.arch_version = instr_info->pe_type.arch;
+
+ switch(instr_info->isa)
+ {
+ case ocsd_isa_arm:
+ err = DecodeA32(instr_info, &info);
+ break;
+
+ case ocsd_isa_thumb2:
+ err = DecodeT32(instr_info, &info);
+ break;
+
+ case ocsd_isa_aarch64:
+ err = DecodeA64(instr_info, &info);
+ break;
+
+ case ocsd_isa_tee:
+ case ocsd_isa_jazelle:
+ default:
+ // unsupported ISA
+ err = OCSD_ERR_UNSUPPORTED_ISA;
+ break;
+ }
+ instr_info->sub_type = info.instr_sub_type;
+ return err;
+}
+
+ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info, struct decode_info *info)
+{
+ uint32_t branchAddr = 0;
+ arm_barrier_t barrier;
+
+ instr_info->instr_size = 4; // instruction size A32
+ instr_info->type = OCSD_INSTR_OTHER; // default type
+ instr_info->next_isa = instr_info->isa; // assume same ISA
+ instr_info->is_link = 0;
+
+ if(inst_ARM_is_indirect_branch(instr_info->opcode, info))
+ {
+ instr_info->type = OCSD_INSTR_BR_INDIRECT;
+ instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info);
+ }
+ else if(inst_ARM_is_direct_branch(instr_info->opcode))
+ {
+ inst_ARM_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr);
+ instr_info->type = OCSD_INSTR_BR;
+ if (branchAddr & 0x1)
+ {
+ instr_info->next_isa = ocsd_isa_thumb2;
+ branchAddr &= ~0x1;
+ }
+ instr_info->branch_addr = (ocsd_vaddr_t)branchAddr;
+ instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info);
+ }
+ else if((barrier = inst_ARM_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
+ {
+ switch(barrier)
+ {
+ case ARM_BARRIER_ISB:
+ instr_info->type = OCSD_INSTR_ISB;
+ break;
+
+ case ARM_BARRIER_DSB:
+ case ARM_BARRIER_DMB:
+ if(instr_info->dsb_dmb_waypoints)
+ instr_info->type = OCSD_INSTR_DSB_DMB;
+ break;
+ }
+ }
+ else if (instr_info->wfi_wfe_branch)
+ {
+ if (inst_ARM_wfiwfe(instr_info->opcode))
+ {
+ instr_info->type = OCSD_INSTR_WFI_WFE;
+ }
+ }
+ instr_info->is_conditional = inst_ARM_is_conditional(instr_info->opcode);
+
+ return OCSD_OK;
+}
+
+ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info, struct decode_info *info)
+{
+ uint64_t branchAddr = 0;
+ arm_barrier_t barrier;
+
+ instr_info->instr_size = 4; // default address update
+ instr_info->type = OCSD_INSTR_OTHER; // default type
+ instr_info->next_isa = instr_info->isa; // assume same ISA
+ instr_info->is_link = 0;
+
+ if(inst_A64_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info))
+ {
+ instr_info->type = OCSD_INSTR_BR_INDIRECT;
+ }
+ else if(inst_A64_is_direct_branch_link(instr_info->opcode, &instr_info->is_link, info))
+ {
+ inst_A64_branch_destination(instr_info->instr_addr,instr_info->opcode,&branchAddr);
+ instr_info->type = OCSD_INSTR_BR;
+ instr_info->branch_addr = (ocsd_vaddr_t)branchAddr;
+ }
+ 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 &&
+ inst_A64_wfiwfe(instr_info->opcode, info))
+ {
+ instr_info->type = OCSD_INSTR_WFI_WFE;
+ }
+ else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64))
+ {
+ if (inst_A64_Tstart(instr_info->opcode))
+ instr_info->type = OCSD_INSTR_TSTART;
+ }
+
+ instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode);
+
+ return OCSD_OK;
+}
+
+ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info, struct decode_info *info)
+{
+ uint32_t branchAddr = 0;
+ arm_barrier_t barrier;
+
+ // need to align the 32 bit opcode as 2 16 bit, with LS 16 as in top 16 bit of
+ // 32 bit word - T2 routines assume 16 bit in top 16 bit of 32 bit opcode.
+ uint32_t op_temp = (instr_info->opcode >> 16) & 0xFFFF;
+ op_temp |= ((instr_info->opcode & 0xFFFF) << 16);
+ instr_info->opcode = op_temp;
+
+
+ instr_info->instr_size = is_wide_thumb((uint16_t)(instr_info->opcode >> 16)) ? 4 : 2;
+ instr_info->type = OCSD_INSTR_OTHER; // default type
+ instr_info->next_isa = instr_info->isa; // assume same ISA
+ instr_info->is_link = 0;
+ instr_info->is_conditional = 0;
+
+
+ if(inst_Thumb_is_direct_branch_link(instr_info->opcode,&instr_info->is_link, &instr_info->is_conditional, info))
+ {
+ inst_Thumb_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr);
+ instr_info->type = OCSD_INSTR_BR;
+ instr_info->branch_addr = (ocsd_vaddr_t)(branchAddr & ~0x1);
+ if((branchAddr & 0x1) == 0)
+ instr_info->next_isa = ocsd_isa_arm;
+ }
+ else if (inst_Thumb_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info))
+ {
+ instr_info->type = OCSD_INSTR_BR_INDIRECT;
+ }
+ else if((barrier = inst_Thumb_barrier(instr_info->opcode)) != ARM_BARRIER_NONE)
+ {
+ switch(barrier)
+ {
+ case ARM_BARRIER_ISB:
+ instr_info->type = OCSD_INSTR_ISB;
+ break;
+
+ case ARM_BARRIER_DSB:
+ case ARM_BARRIER_DMB:
+ if(instr_info->dsb_dmb_waypoints)
+ instr_info->type = OCSD_INSTR_DSB_DMB;
+ break;
+ }
+ }
+ else if (instr_info->wfi_wfe_branch)
+ {
+ if (inst_Thumb_wfiwfe(instr_info->opcode))
+ {
+ instr_info->type = OCSD_INSTR_WFI_WFE;
+ }
+ }
+ instr_info->is_conditional = inst_Thumb_is_conditional(instr_info->opcode);
+ instr_info->thumb_it_conditions = inst_Thumb_is_IT(instr_info->opcode);
+
+ return OCSD_OK;
+}
+
+/* End of File trc_i_decode.cpp */
diff --git a/decoder/source/i_dec/trc_idec_arminst.cpp b/decoder/source/i_dec/trc_idec_arminst.cpp
new file mode 100644
index 0000000..76951fd
--- /dev/null
+++ b/decoder/source/i_dec/trc_idec_arminst.cpp
@@ -0,0 +1,679 @@
+/*
+ * \file trc_idec_arminst.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+Basic ARM/Thumb/A64 instruction decode, suitable for e.g. basic
+block identification and trace decode.
+*/
+
+#include "i_dec/trc_idec_arminst.h"
+
+#include <stddef.h> /* for NULL */
+#include <assert.h>
+
+int inst_ARM_is_direct_branch(uint32_t inst)
+{
+ int is_direct_branch = 1;
+ if ((inst & 0xf0000000) == 0xf0000000) {
+ /* NV space */
+ if ((inst & 0xfe000000) == 0xfa000000){
+ /* BLX (imm) */
+ } else {
+ is_direct_branch = 0;
+ }
+ } else if ((inst & 0x0e000000) == 0x0a000000) {
+ /* B, BL */
+ } else {
+ is_direct_branch = 0;
+ }
+ return is_direct_branch;
+}
+
+int inst_ARM_wfiwfe(uint32_t inst)
+{
+ if ( ((inst & 0xf0000000) != 0xf0000000) &&
+ ((inst & 0x0ffffffe) == 0x0320f002)
+ )
+ /* WFI & WFE may be traced as branches in etm4.3 ++ */
+ return 1;
+ return 0;
+}
+
+int inst_ARM_is_indirect_branch(uint32_t inst, struct decode_info *info)
+{
+ int is_indirect_branch = 1;
+ if ((inst & 0xf0000000) == 0xf0000000) {
+ /* NV space */
+ if ((inst & 0xfe500000) == 0xf8100000) {
+ /* RFE */
+ } else {
+ is_indirect_branch = 0;
+ }
+ } else if ((inst & 0x0ff000d0) == 0x01200010) {
+ /* BLX (register), BX */
+ if ((inst & 0xFF) == 0x1E)
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */
+ } else if ((inst & 0x0ff000f0) == 0x01200020) {
+ /* BXJ: in v8 this behaves like BX */
+ } else if ((inst & 0x0e108000) == 0x08108000) {
+ /* POP {...,pc} or LDMxx {...,pc} */
+ if ((inst & 0x0FFFA000) == 0x08BD8000) /* LDMIA SP!,{...,pc} */
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET;
+ } else if ((inst & 0x0e50f000) == 0x0410f000) {
+ /* LDR PC,imm... inc. POP {PC} */
+ if ( (inst & 0x01ff0000) == 0x009D0000)
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm */
+ } else if ((inst & 0x0e50f010) == 0x0610f000) {
+ /* LDR PC,reg */
+ } else if ((inst & 0x0fe0f000) == 0x01a0f000) {
+ /* MOV PC,rx */
+ if ((inst & 0x00100FFF) == 0x00E) /* ensure the S=0, LSL #0 variant - i.e plain MOV */
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC, R14 */
+ } else if ((inst & 0x0f900080) == 0x01000000) {
+ /* "Miscellaneous instructions" - in DP space */
+ is_indirect_branch = 0;
+ } else if ((inst & 0x0f9000f0) == 0x01800090) {
+ /* Some extended loads and stores */
+ is_indirect_branch = 0;
+ } else if ((inst & 0x0fb0f000) == 0x0320f000) {
+ /* MSR #imm */
+ is_indirect_branch = 0;
+ } else if ((inst & 0x0e00f000) == 0x0200f000) {
+ /* DP PC,imm shift */
+ if ((inst & 0x0f90f000) == 0x0310f000) {
+ /* TST/CMP */
+ is_indirect_branch = 0;
+ }
+ } else if ((inst & 0x0e00f000) == 0x0000f000) {
+ /* DP PC,reg */
+ } else {
+ is_indirect_branch = 0;
+ }
+ return is_indirect_branch;
+}
+
+int inst_Thumb_is_direct_branch(uint32_t inst, struct decode_info *info)
+{
+ uint8_t link, cond;
+ return inst_Thumb_is_direct_branch_link(inst, &link, &cond, info);
+}
+
+int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond, struct decode_info *info)
+{
+ int is_direct_branch = 1;
+
+ if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
+ /* B<c> (encoding T1) */
+ *is_cond = 1;
+ } else if ((inst & 0xf8000000) == 0xe0000000) {
+ /* B (encoding T2) */
+ } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
+ /* B (encoding T3) */
+ *is_cond = 1;
+ } else if ((inst & 0xf8009000) == 0xf0009000) {
+ /* B (encoding T4); BL (encoding T1) */
+ if (inst & 0x00004000) {
+ *is_link = 1;
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ }
+ } else if ((inst & 0xf800d001) == 0xf000c000) {
+ /* BLX (imm) (encoding T2) */
+ *is_link = 1;
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ } else if ((inst & 0xf5000000) == 0xb1000000) {
+ /* CB(NZ) */
+ *is_cond = 1;
+ } else {
+ is_direct_branch = 0;
+ }
+ return is_direct_branch;
+}
+
+int inst_Thumb_wfiwfe(uint32_t inst)
+{
+ int is_wfiwfe = 1;
+ /* WFI, WFE may be branches in etm4.3++ */
+ if ((inst & 0xfffffffe) == 0xf3af8002) {
+ /* WFI & WFE (encoding T2) */
+ }
+ else if ((inst & 0xffef0000) == 0xbf200000) {
+ /* WFI & WFE (encoding T1) */
+ }
+ else {
+ is_wfiwfe = 0;
+ }
+ return is_wfiwfe;
+}
+
+int inst_Thumb_is_indirect_branch(uint32_t inst, struct decode_info *info)
+{
+ uint8_t link;
+ return inst_Thumb_is_indirect_branch_link(inst, &link, info);
+}
+
+int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info)
+{
+ /* See e.g. PFT Table 2-3 and Table 2-5 */
+ int is_branch = 1;
+
+ if ((inst & 0xff000000) == 0x47000000) {
+ /* BX, BLX (reg) [v8M includes BXNS, BLXNS] */
+ if (inst & 0x00800000) {
+ *is_link = 1;
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ }
+ else if ((inst & 0x00780000) == 0x00700000) {
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */
+ }
+ } else if ((inst & 0xfff0d000) == 0xf3c08000) {
+ /* BXJ: in v8 this behaves like BX */
+ } else if ((inst & 0xff000000) == 0xbd000000) {
+ /* POP {pc} */
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET;
+ } else if ((inst & 0xfd870000) == 0x44870000) {
+ /* MOV PC,reg or ADD PC,reg */
+ if ((inst & 0xffff0000) == 0x46f70000)
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC,LR */
+ } else if ((inst & 0xfff0ffe0) == 0xe8d0f000) {
+ /* TBB/TBH */
+ } else if ((inst & 0xffd00000) == 0xe8100000) {
+ /* RFE (T1) */
+ } else if ((inst & 0xffd00000) == 0xe9900000) {
+ /* RFE (T2) */
+ } else if ((inst & 0xfff0d000) == 0xf3d08000) {
+ /* SUBS PC,LR,#imm inc.ERET */
+ } else if ((inst & 0xfff0f000) == 0xf8d0f000) {
+ /* LDR PC,imm (T3) */
+ } else if ((inst & 0xff7ff000) == 0xf85ff000) {
+ /* LDR PC,literal (T2) */
+ } else if ((inst & 0xfff0f800) == 0xf850f800) {
+ /* LDR PC,imm (T4) */
+ if((inst & 0x000f0f00) == 0x000d0b00)
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm*/
+ } else if ((inst & 0xfff0ffc0) == 0xf850f000) {
+ /* LDR PC,reg (T2) */
+ } else if ((inst & 0xfe508000) == 0xe8108000) {
+ /* LDM PC */
+ if ((inst & 0x0FFF0000) == 0x08BD0000) /* LDMIA [SP]!, */
+ info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* POP {...,pc} */
+ } else {
+ is_branch = 0;
+ }
+ return is_branch;
+}
+
+int inst_A64_is_direct_branch(uint32_t inst, struct decode_info *info)
+{
+ uint8_t link = 0;
+ return inst_A64_is_direct_branch_link(inst, &link, info);
+}
+
+int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info)
+{
+ int is_direct_branch = 1;
+ if ((inst & 0x7c000000) == 0x34000000) {
+ /* CB, TB */
+ } else if ((inst & 0xff000000) == 0x54000000) {
+ /* B<cond> */
+ /* BC<cond> 8.8 / 9.3 arch - bit 4 = 1'b1 */
+ } else if ((inst & 0x7c000000) == 0x14000000) {
+ /* B, BL imm */
+ if (inst & 0x80000000) {
+ *is_link = 1;
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ }
+ } else {
+ is_direct_branch = 0;
+ }
+ return is_direct_branch;
+}
+
+int inst_A64_wfiwfe(uint32_t inst, struct decode_info *info)
+{
+ /* WFI, WFE may be traced as branches in etm 4.3++ */
+ if ((inst & 0xffffffdf) == 0xd503205f)
+ return 1;
+
+ /* new feature introduced post v8.3 */
+ if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64))
+ {
+ /* WFIT / WFET for later archs */
+ if ((inst & 0xffffffc0) == 0xd5031000)
+ return 1;
+ }
+ return 0;
+}
+
+int inst_A64_Tstart(uint32_t inst)
+{
+ if ((inst & 0xffffffe0) == 0xd5233060)
+ return 1;
+ return 0;
+}
+
+int inst_A64_is_indirect_branch(uint32_t inst, struct decode_info *info)
+{
+ uint8_t link = 0;
+ return inst_A64_is_indirect_branch_link(inst, &link, info);
+}
+
+int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info)
+{
+ int is_indirect_branch = 1;
+
+ if ((inst & 0xffdffc1f) == 0xd61f0000) {
+ /* BR, BLR */
+ if (inst & 0x00200000) {
+ *is_link = 1;
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ }
+ } else if ((inst & 0xfffffc1f) == 0xd65f0000) {
+ info->instr_sub_type = OCSD_S_INSTR_V8_RET;
+ /* RET */
+ } else if ((inst & 0xffffffff) == 0xd69f03e0) {
+ /* ERET */
+ info->instr_sub_type = OCSD_S_INSTR_V8_ERET;
+ } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) {
+ /* new pointer auth instr for v8.3 arch */
+ if ((inst & 0xffdff800) == 0xd71f0800) {
+ /* BRAA, BRAB, BLRAA, BLRBB */
+ if (inst & 0x00200000) {
+ *is_link = 1;
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ }
+ } else if ((inst & 0xffdff81F) == 0xd61f081F) {
+ /* BRAAZ, BRABZ, BLRAAZ, BLRBBZ */
+ if (inst & 0x00200000) {
+ *is_link = 1;
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ }
+ } else if ((inst & 0xfffffbff) == 0xd69f0bff) {
+ /* ERETAA, ERETAB */
+ info->instr_sub_type = OCSD_S_INSTR_V8_ERET;
+ } else if ((inst & 0xfffffbff) == 0xd65f0bff) {
+ /* RETAA, RETAB */
+ info->instr_sub_type = OCSD_S_INSTR_V8_RET;
+ } else {
+ is_indirect_branch = 0;
+ }
+ } else {
+ is_indirect_branch = 0;
+ }
+ return is_indirect_branch;
+}
+
+int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
+{
+ uint32_t npc;
+ int is_direct_branch = 1;
+ if ((inst & 0x0e000000) == 0x0a000000) {
+ /*
+ B: cccc:1010:imm24
+ BL: cccc:1011:imm24
+ BLX: 1111:101H:imm24
+ */
+ npc = addr + 8 + ((int32_t)((inst & 0xffffff) << 8) >> 6);
+ if ((inst & 0xf0000000) == 0xf0000000) {
+ npc |= 1; /* indicate ISA is now Thumb */
+ npc |= ((inst >> 23) & 2); /* apply the H bit */
+ }
+ } else {
+ is_direct_branch = 0;
+ }
+ if (is_direct_branch && pnpc != NULL) {
+ *pnpc = npc;
+ }
+ return is_direct_branch;
+}
+
+int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
+{
+ uint32_t npc;
+ int is_direct_branch = 1;
+ if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
+ /* B<c> (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 & 0xff000000) == 0x54000000) {
+ /* B<cond> */
+ /* BC<cond> */
+ npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
+ } else if ((inst & 0x7c000000) == 0x14000000) {
+ /* B, BL imm */
+ npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4);
+ } else if ((inst & 0x7e000000) == 0x34000000) {
+ /* CB */
+ npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
+ } else if ((inst & 0x7e000000) == 0x36000000) {
+ /* TB */
+ npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16);
+ } else {
+ is_direct_branch = 0;
+ }
+ if (is_direct_branch && pnpc != NULL) {
+ *pnpc = npc;
+ }
+ return is_direct_branch;
+}
+
+int inst_ARM_is_branch(uint32_t inst, struct decode_info *info)
+{
+ return inst_ARM_is_indirect_branch(inst, info) ||
+ inst_ARM_is_direct_branch(inst);
+}
+
+int inst_Thumb_is_branch(uint32_t inst, struct decode_info *info)
+{
+ return inst_Thumb_is_indirect_branch(inst, info) ||
+ inst_Thumb_is_direct_branch(inst, info);
+}
+
+int inst_A64_is_branch(uint32_t inst, struct decode_info *info)
+{
+ return inst_A64_is_indirect_branch(inst, info) ||
+ inst_A64_is_direct_branch(inst, info);
+}
+
+int inst_ARM_is_branch_and_link(uint32_t inst, struct decode_info *info)
+{
+ int is_branch = 1;
+ if ((inst & 0xf0000000) == 0xf0000000) {
+ if ((inst & 0xfe000000) == 0xfa000000){
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ /* BLX (imm) */
+ } else {
+ is_branch = 0;
+ }
+ } else if ((inst & 0x0f000000) == 0x0b000000) {
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ /* BL */
+ } else if ((inst & 0x0ff000f0) == 0x01200030) {
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ /* BLX (reg) */
+ } else {
+ is_branch = 0;
+ }
+ return is_branch;
+}
+
+int inst_Thumb_is_branch_and_link(uint32_t inst, struct decode_info *info)
+{
+ int is_branch = 1;
+ if ((inst & 0xff800000) == 0x47800000) {
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ /* BLX (reg) */
+ } else if ((inst & 0xf800c000) == 0xf000c000) {
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ /* BL, BLX (imm) */
+ } else {
+ is_branch = 0;
+ }
+ return is_branch;
+}
+
+int inst_A64_is_branch_and_link(uint32_t inst, struct decode_info *info)
+{
+ int is_branch = 1;
+ if ((inst & 0xfffffc1f) == 0xd63f0000) {
+ /* BLR */
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ } else if ((inst & 0xfc000000) == 0x94000000) {
+ /* BL */
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) {
+ /* new pointer auth instr for v8.3 arch */
+ if ((inst & 0xfffff800) == 0xd73f0800) {
+ /* BLRAA, BLRBB */
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ } else if ((inst & 0xfffff81F) == 0xd63f081F) {
+ /* BLRAAZ, BLRBBZ */
+ info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
+ } else {
+ is_branch = 0;
+ }
+ } else {
+ is_branch = 0;
+ }
+ return is_branch;
+}
+
+int inst_ARM_is_conditional(uint32_t inst)
+{
+ return (inst & 0xe0000000) != 0xe0000000;
+}
+
+int inst_Thumb_is_conditional(uint32_t inst)
+{
+ if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
+ /* B<c> (encoding T1) */
+ return 1;
+ } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
+ /* B<c> (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 & 0xff000000) == 0x54000000) {
+ /* B.cond */
+ /* BC.cond */
+ return 1;
+ }
+ return 0;
+}
+
+arm_barrier_t inst_ARM_barrier(uint32_t inst)
+{
+ if ((inst & 0xfff00000) == 0xf5700000) {
+ switch (inst & 0xf0) {
+ case 0x40:
+ return ARM_BARRIER_DSB;
+ case 0x50:
+ return ARM_BARRIER_DMB;
+ case 0x60:
+ return ARM_BARRIER_ISB;
+ default:
+ return ARM_BARRIER_NONE;
+ }
+ } else if ((inst & 0x0fff0f00) == 0x0e070f00) {
+ switch (inst & 0xff) {
+ case 0x9a:
+ return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */
+ case 0xba:
+ return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */
+ case 0x95:
+ return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */
+ default:
+ return ARM_BARRIER_NONE;
+ }
+ } else {
+ return ARM_BARRIER_NONE;
+ }
+}
+
+arm_barrier_t inst_Thumb_barrier(uint32_t inst)
+{
+ if ((inst & 0xffffff00) == 0xf3bf8f00) {
+ switch (inst & 0xf0) {
+ case 0x40:
+ return ARM_BARRIER_DSB;
+ case 0x50:
+ return ARM_BARRIER_DMB;
+ case 0x60:
+ return ARM_BARRIER_ISB;
+ default:
+ return ARM_BARRIER_NONE;
+ }
+ } else if ((inst & 0xffff0f00) == 0xee070f00) {
+ /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */
+ switch (inst & 0xff) {
+ case 0x9a:
+ return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */
+ case 0xba:
+ return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */
+ case 0x95:
+ return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */
+ default:
+ return ARM_BARRIER_NONE;
+ }
+ return ARM_BARRIER_NONE;
+ } else {
+ return ARM_BARRIER_NONE;
+ }
+}
+
+arm_barrier_t inst_A64_barrier(uint32_t inst)
+{
+ if ((inst & 0xfffff09f) == 0xd503309f) {
+ switch (inst & 0x60) {
+ case 0x0:
+ return ARM_BARRIER_DSB;
+ case 0x20:
+ return ARM_BARRIER_DMB;
+ case 0x40:
+ return ARM_BARRIER_ISB;
+ default:
+ return ARM_BARRIER_NONE;
+ }
+ } else {
+ return ARM_BARRIER_NONE;
+ }
+}
+
+int inst_ARM_is_UDF(uint32_t inst)
+{
+ return (inst & 0xfff000f0) == 0xe7f000f0;
+}
+
+int inst_Thumb_is_UDF(uint32_t inst)
+{
+ return (inst & 0xff000000) == 0xde000000 || /* T1 */
+ (inst & 0xfff0f000) == 0xf7f0a000; /* T2 */
+}
+
+int inst_A64_is_UDF(uint32_t inst)
+{
+ /* No A64 encodings are formally allocated as permanently undefined,
+ but it is intended not to allocate any instructions in the 21-bit
+ regions at the bottom or top of the range. */
+ return (inst & 0xffe00000) == 0x00000000 ||
+ (inst & 0xffe00000) == 0xffe00000;
+}
+
+/* End of File trc_idec_arminst.cpp */
diff --git a/decoder/source/mem_acc/trc_mem_acc_base.cpp b/decoder/source/mem_acc/trc_mem_acc_base.cpp
new file mode 100644
index 0000000..1250bdc
--- /dev/null
+++ b/decoder/source/mem_acc/trc_mem_acc_base.cpp
@@ -0,0 +1,148 @@
+/*!
+ * \file trc_mem_acc_base.cpp
+ * \brief OpenCSD : Trace memory accessor base class.
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mem_acc/trc_mem_acc_base.h"
+#include "mem_acc/trc_mem_acc_file.h"
+#include "mem_acc/trc_mem_acc_cb.h"
+#include "mem_acc/trc_mem_acc_bufptr.h"
+
+#include <sstream>
+#include <iomanip>
+
+ /** Accessor Creation */
+ocsd_err_t TrcMemAccFactory::CreateBufferAccessor(TrcMemAccessorBase **pAccessor, const ocsd_vaddr_t s_address, const uint8_t *p_buffer, const uint32_t size)
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcMemAccessorBase *pAcc = 0;
+ pAcc = new (std::nothrow) TrcMemAccBufPtr(s_address,p_buffer,size);
+ if(pAcc == 0)
+ err = OCSD_ERR_MEM;
+ *pAccessor = pAcc;
+ return err;
+}
+
+ocsd_err_t TrcMemAccFactory::CreateFileAccessor(TrcMemAccessorBase **pAccessor, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset /*= 0*/, size_t size /*= 0*/)
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcMemAccessorFile *pFileAccessor = 0;
+ err = TrcMemAccessorFile::createFileAccessor(&pFileAccessor, pathToFile, startAddr, offset,size);
+ *pAccessor = pFileAccessor;
+ return err;
+}
+
+ocsd_err_t TrcMemAccFactory::CreateCBAccessor(TrcMemAccessorBase **pAccessor, const ocsd_vaddr_t s_address, const ocsd_vaddr_t e_address, const ocsd_mem_space_acc_t mem_space)
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcMemAccessorBase *pAcc = 0;
+ pAcc = new (std::nothrow) TrcMemAccCB(s_address,e_address,mem_space);
+ if(pAcc == 0)
+ err = OCSD_ERR_MEM;
+ *pAccessor = pAcc;
+ return err;
+}
+
+/** Accessor Destruction */
+void TrcMemAccFactory::DestroyAccessor(TrcMemAccessorBase *pAccessor)
+{
+ switch(pAccessor->getType())
+ {
+ case TrcMemAccessorBase::MEMACC_FILE:
+ TrcMemAccessorFile::destroyFileAccessor(dynamic_cast<TrcMemAccessorFile *>(pAccessor));
+ break;
+
+ case TrcMemAccessorBase::MEMACC_CB_IF:
+ case TrcMemAccessorBase::MEMACC_BUFPTR:
+ delete pAccessor;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* memory access info logging */
+void TrcMemAccessorBase::getMemAccString(std::string &accStr) const
+{
+ std::ostringstream oss;
+
+ switch(m_type)
+ {
+ case MEMACC_FILE:
+ oss << "FileAcc; Range::0x";
+ break;
+
+ case MEMACC_BUFPTR:
+ oss << "BuffAcc; Range::0x";
+ break;
+
+ case MEMACC_CB_IF:
+ oss << "CB Acc; Range::0x";
+ break;
+
+ default:
+ oss << "UnknAcc; Range::0x";
+ break;
+ }
+ oss << std::hex << std::setw(2) << std::setfill('0') << m_startAddress << ":" << m_endAddress;
+ oss << "; Mem Space::";
+ switch(m_mem_space)
+ {
+ case OCSD_MEM_SPACE_EL1S: oss << "EL1S"; break;
+ case OCSD_MEM_SPACE_EL1N: oss << "EL1N"; break;
+ case OCSD_MEM_SPACE_EL2: oss << "EL2"; break;
+ case OCSD_MEM_SPACE_EL3: oss << "EL3"; break;
+ case OCSD_MEM_SPACE_S: oss << "Any S"; break;
+ case OCSD_MEM_SPACE_N: oss << "Any NS"; break;
+ case OCSD_MEM_SPACE_ANY: oss << "Any"; break;
+
+ default:
+ {
+ uint8_t MSBits = (uint8_t)m_mem_space;
+ if(MSBits & (uint8_t)OCSD_MEM_SPACE_EL1S)
+ oss << "EL1S,";
+ if(MSBits & (uint8_t)OCSD_MEM_SPACE_EL1N)
+ oss << "EL1N,";
+ if(MSBits & (uint8_t)OCSD_MEM_SPACE_EL2)
+ oss << "EL2,";
+ if(MSBits & (uint8_t)OCSD_MEM_SPACE_EL3)
+ oss << "EL3,";
+ }
+ break;
+ }
+ accStr = oss.str();
+}
+
+/* End of File trc_mem_acc_base.cpp */
diff --git a/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp b/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp
new file mode 100644
index 0000000..7ecd3b0
--- /dev/null
+++ b/decoder/source/mem_acc/trc_mem_acc_bufptr.cpp
@@ -0,0 +1,53 @@
+/*
+ * \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 <cstring>
+
+#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)
+{
+}
+
+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 */
diff --git a/decoder/source/mem_acc/trc_mem_acc_cache.cpp b/decoder/source/mem_acc/trc_mem_acc_cache.cpp
new file mode 100644
index 0000000..444314e
--- /dev/null
+++ b/decoder/source/mem_acc/trc_mem_acc_cache.cpp
@@ -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 <cstring>
+#include <sstream>
+#include <iomanip>
+#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 */
diff --git a/decoder/source/mem_acc/trc_mem_acc_cb.cpp b/decoder/source/mem_acc/trc_mem_acc_cb.cpp
new file mode 100644
index 0000000..1a1565b
--- /dev/null
+++ b/decoder/source/mem_acc/trc_mem_acc_cb.cpp
@@ -0,0 +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 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 */
diff --git a/decoder/source/mem_acc/trc_mem_acc_file.cpp b/decoder/source/mem_acc/trc_mem_acc_file.cpp
new file mode 100644
index 0000000..25b718e
--- /dev/null
+++ b/decoder/source/mem_acc/trc_mem_acc_file.cpp
@@ -0,0 +1,391 @@
+/*
+ * \file trc_mem_acc_file.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mem_acc/trc_mem_acc_file.h"
+
+#include <sstream>
+#include <iomanip>
+
+/***************************************************/
+/* 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<FileRegionMemAccessor *>::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<FileRegionMemAccessor *>::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<std::string, TrcMemAccessorFile *> 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<std::string, TrcMemAccessorFile *>::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<std::string, TrcMemAccessorFile *>(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<std::string, TrcMemAccessorFile *>::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<std::string, TrcMemAccessorFile *>::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<std::string, TrcMemAccessorFile *>::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 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<FileRegionMemAccessor *>::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<FileRegionMemAccessor *>::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<FileRegionMemAccessor *>::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<FileRegionMemAccessor *>::const_iterator it;
+ it = m_access_regions.begin();
+ while(it != m_access_regions.end())
+ {
+ (*it)->getMemAccString(addStr);
+ if(accStr.length())
+ accStr += "\n";
+ accStr += addStr;
+ it++;
+ }
+ }
+ accStr += (std::string)"\nFilename=" + m_file_path;
+}
+
+/* End of File trc_mem_acc_file.cpp */
diff --git a/decoder/source/mem_acc/trc_mem_acc_mapper.cpp b/decoder/source/mem_acc/trc_mem_acc_mapper.cpp
new file mode 100644
index 0000000..dc07a1e
--- /dev/null
+++ b/decoder/source/mem_acc/trc_mem_acc_mapper.cpp
@@ -0,0 +1,307 @@
+/*
+ * \file trc_mem_acc_mapper.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mem_acc/trc_mem_acc_mapper.h"
+#include "mem_acc/trc_mem_acc_file.h"
+#include "common/ocsd_error.h"
+
+/************************************************************************************/
+/* mappers base class */
+/************************************************************************************/
+
+#define USING_MEM_ACC_CACHE
+
+TrcMemAccMapper::TrcMemAccMapper() :
+ m_acc_curr(0),
+ m_trace_id_curr(0),
+ m_using_trace_id(false),
+ m_err_log(0)
+{
+#ifdef USING_MEM_ACC_CACHE
+ m_cache.enableCaching(true);
+#endif
+}
+
+TrcMemAccMapper::TrcMemAccMapper(bool using_trace_id) :
+ m_acc_curr(0),
+ m_trace_id_curr(0),
+ m_using_trace_id(using_trace_id),
+ m_err_log(0)
+{
+#ifdef USING_MEM_ACC_CACHE
+ m_cache.enableCaching(true);
+#endif
+}
+
+TrcMemAccMapper::~TrcMemAccMapper()
+{
+}
+
+void TrcMemAccMapper::setErrorLog(ITraceErrorLog *err_log_i)
+{
+ m_err_log = err_log_i;
+ m_cache.setErrorLog(err_log_i);
+}
+
+// memory access interface
+ocsd_err_t TrcMemAccMapper::ReadTargetMemory(const ocsd_vaddr_t address, const uint8_t cs_trace_id, const ocsd_mem_space_acc_t mem_space, uint32_t *num_bytes, uint8_t *p_buffer)
+{
+ bool bReadFromCurr = true;
+ uint32_t readBytes = 0;
+ ocsd_err_t err = OCSD_OK;
+
+ /* see if the address is in any range we know */
+ if (!readFromCurrent(address, mem_space, cs_trace_id))
+ {
+ bReadFromCurr = findAccessor(address, mem_space, cs_trace_id);
+
+ // found a new accessor - invalidate any cache entries used by the previous one.
+ if (m_cache.enabled() && bReadFromCurr)
+ m_cache.invalidateAll();
+ }
+
+ /* if bReadFromCurr then we know m_acc_curr is set */
+ if (bReadFromCurr)
+ {
+ // use cache if enabled and the amount fits into a cache page
+ if (m_cache.enabled_for_size(*num_bytes))
+ {
+ // read from cache - or load a new cache page and read....
+ readBytes = *num_bytes;
+ err = m_cache.readBytesFromCache(m_acc_curr, address, mem_space, cs_trace_id, &readBytes, p_buffer);
+ if (err != OCSD_OK)
+ LogWarn(err, "Mem Acc: Cache access error");
+ }
+ else
+ {
+ readBytes = m_acc_curr->readBytes(address, mem_space, cs_trace_id, *num_bytes, p_buffer);
+ // guard against bad accessor returns (e.g. callback not obeying the rules for return values)
+ if (readBytes > *num_bytes)
+ {
+ err = OCSD_ERR_MEM_ACC_BAD_LEN;
+ LogWarn(err,"Mem acc: bad return length");
+ }
+ }
+ }
+
+ *num_bytes = readBytes;
+ return err;
+}
+
+void TrcMemAccMapper::InvalidateMemAccCache(const uint8_t /* cs_trace_id */)
+{
+ // default mapper does not use cs_trace_id for cache invalidation.
+ if (m_cache.enabled())
+ m_cache.invalidateAll();
+ m_acc_curr = 0;
+}
+
+void TrcMemAccMapper::RemoveAllAccessors()
+{
+ TrcMemAccessorBase *pAcc = 0;
+ pAcc = getFirstAccessor();
+ while(pAcc != 0)
+ {
+ TrcMemAccFactory::DestroyAccessor(pAcc);
+ pAcc = getNextAccessor();
+ if (m_cache.enabled())
+ m_cache.invalidateAll();
+ }
+ clearAccessorList();
+ if (m_cache.enabled())
+ m_cache.logAndClearCounts();
+}
+
+ocsd_err_t TrcMemAccMapper::RemoveAccessorByAddress(const ocsd_vaddr_t st_address, const ocsd_mem_space_acc_t mem_space, const uint8_t cs_trace_id /* = 0 */)
+{
+ ocsd_err_t err = OCSD_OK;
+ if(findAccessor(st_address,mem_space,cs_trace_id))
+ {
+ err = RemoveAccessor(m_acc_curr);
+ m_acc_curr = 0;
+ if (m_cache.enabled())
+ m_cache.invalidateAll();
+ }
+ else
+ err = OCSD_ERR_INVALID_PARAM_VAL;
+ if (m_cache.enabled())
+ m_cache.logAndClearCounts();
+ return err;
+}
+
+void TrcMemAccMapper::LogMessage(const std::string &msg)
+{
+ if(m_err_log)
+ m_err_log->LogMessage(ITraceErrorLog::HANDLE_GEN_INFO,OCSD_ERR_SEV_INFO,msg);
+}
+
+void TrcMemAccMapper::LogWarn(const ocsd_err_t err, const std::string &msg)
+{
+ if (m_err_log)
+ {
+ ocsdError err_ocsd(OCSD_ERR_SEV_WARN,err,msg);
+ m_err_log->LogError(ITraceErrorLog::HANDLE_GEN_INFO, &err_ocsd);
+ }
+}
+
+
+/************************************************************************************/
+/* mappers global address space class - no differentiation in core trace IDs */
+/************************************************************************************/
+TrcMemAccMapGlobalSpace::TrcMemAccMapGlobalSpace() : TrcMemAccMapper()
+{
+}
+
+TrcMemAccMapGlobalSpace::~TrcMemAccMapGlobalSpace()
+{
+}
+
+ocsd_err_t TrcMemAccMapGlobalSpace::AddAccessor(TrcMemAccessorBase *p_accessor, const uint8_t /*cs_trace_id*/)
+{
+ ocsd_err_t err = OCSD_OK;
+ bool bOverLap = false;
+
+ if(!p_accessor->validateRange())
+ return OCSD_ERR_MEM_ACC_RANGE_INVALID;
+
+ std::vector<TrcMemAccessorBase *>::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<TrcMemAccessorBase *>::const_iterator it = m_acc_global.begin();
+ while((it != m_acc_global.end()) && !bFound)
+ {
+ if( (*it)->addrInRange(address) &&
+ (*it)->inMemSpace(mem_space))
+ {
+ bFound = true;
+ m_acc_curr = *it;
+ }
+ it++;
+ }
+ return bFound;
+}
+
+bool TrcMemAccMapGlobalSpace::readFromCurrent(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t /*cs_trace_id*/)
+{
+ bool readFromCurr = false;
+ if(m_acc_curr)
+ readFromCurr = (m_acc_curr->addrInRange(address) && m_acc_curr->inMemSpace(mem_space));
+ return readFromCurr;
+}
+
+
+TrcMemAccessorBase * TrcMemAccMapGlobalSpace::getFirstAccessor()
+{
+ TrcMemAccessorBase *p_acc = 0;
+ m_acc_it = m_acc_global.begin();
+ if(m_acc_it != m_acc_global.end())
+ {
+ p_acc = *m_acc_it;
+ }
+ return p_acc;
+}
+
+TrcMemAccessorBase *TrcMemAccMapGlobalSpace::getNextAccessor()
+{
+ TrcMemAccessorBase *p_acc = 0;
+ m_acc_it++;
+ if(m_acc_it != m_acc_global.end())
+ {
+ p_acc = *m_acc_it;
+ }
+ return p_acc;
+}
+
+void TrcMemAccMapGlobalSpace::clearAccessorList()
+{
+ m_acc_global.clear();
+}
+
+ocsd_err_t TrcMemAccMapGlobalSpace::RemoveAccessor(const TrcMemAccessorBase *p_accessor)
+{
+ bool bFound = false;
+ TrcMemAccessorBase *p_acc = getFirstAccessor();
+ while(p_acc != 0)
+ {
+ if(p_acc == p_accessor)
+ {
+ m_acc_global.erase(m_acc_it);
+ TrcMemAccFactory::DestroyAccessor(p_acc);
+ p_acc = 0;
+ bFound = true;
+ }
+ else
+ p_acc = getNextAccessor();
+ }
+ return bFound ? OCSD_OK : OCSD_ERR_INVALID_PARAM_VAL;
+}
+
+
+void TrcMemAccMapGlobalSpace::logMappedRanges()
+{
+ std::string accStr;
+ TrcMemAccessorBase *pAccessor = getFirstAccessor();
+ LogMessage("Mapped Memory Accessors\n");
+ while(pAccessor != 0)
+ {
+ pAccessor->getMemAccString(accStr);
+ accStr += "\n";
+ LogMessage(accStr);
+ pAccessor = getNextAccessor();
+ }
+ LogMessage("========================\n");
+}
+
+/* End of File trc_mem_acc_mapper.cpp */
diff --git a/decoder/source/ocsd_code_follower.cpp b/decoder/source/ocsd_code_follower.cpp
new file mode 100644
index 0000000..4386eb4
--- /dev/null
+++ b/decoder/source/ocsd_code_follower.cpp
@@ -0,0 +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<ITargetMemAccess> *pMemAccess, componentAttachPt<IInstrDecode> *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> - other error occured - fatal.
+ */
+ocsd_err_t OcsdCodeFollower::followSingleAtom(const ocsd_vaddr_t addrStart, const ocsd_atm_val A)
+{
+ ocsd_err_t err = OCSD_ERR_NOT_INIT;
+
+ if(!initFollowerState())
+ return err;
+
+ m_en_range_addr = m_st_range_addr = m_instr_info.instr_addr = addrStart;
+ err = decodeSingleOpCode();
+
+ if(err != OCSD_OK)
+ return err;
+
+ // set end range - always after the instruction executed.
+ m_en_range_addr = m_instr_info.instr_addr + m_instr_info.instr_size;
+
+ // assume next addr is the instruction after
+ m_next_addr = m_en_range_addr;
+ m_b_next_valid = true;
+
+ // case when next address is different
+ switch(m_instr_info.type)
+ {
+ case OCSD_INSTR_BR:
+ if(A == ATOM_E) // executed the direct branch
+ m_next_addr = m_instr_info.branch_addr;
+ break;
+
+ case OCSD_INSTR_BR_INDIRECT:
+ if(A == ATOM_E) // executed indirect branch
+ m_b_next_valid = false;
+ break;
+ }
+ return err;
+}
+
+ocsd_err_t OcsdCodeFollower::decodeSingleOpCode()
+{
+ ocsd_err_t err = OCSD_OK;
+ // request 4 bytes for the opcode - even for Thumb which may be T32
+ uint32_t bytesReq = 4;
+ uint32_t opcode; // buffer for opcode
+
+ // read memory location for opcode
+ err = m_pMemAccess->first()->ReadTargetMemory(m_instr_info.instr_addr,m_mem_space_csid,m_mem_acc_rule,&bytesReq,(uint8_t *)&opcode);
+
+ // operational error (not access problem - that is indicated by 0 bytes returned)
+ if(err != OCSD_OK)
+ return err;
+
+ if(bytesReq == 4) // check that we got all memory requested.
+ {
+ m_instr_info.opcode = opcode;
+ err = m_pIDecode->first()->DecodeInstruction(&m_instr_info);
+ }
+ else // otherwise memory unavailable.
+ {
+ m_b_nacc_err = true;
+ m_nacc_address = m_instr_info.instr_addr;
+ err = OCSD_ERR_MEM_NACC;
+ }
+ return err;
+}
+
+/* End of File ocsd_code_follower.cpp */
diff --git a/decoder/source/ocsd_dcd_tree.cpp b/decoder/source/ocsd_dcd_tree.cpp
new file mode 100644
index 0000000..8e29269
--- /dev/null
+++ b/decoder/source/ocsd_dcd_tree.cpp
@@ -0,0 +1,785 @@
+/*
+ * \file ocsd_dcd_tree.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/ocsd_dcd_tree.h"
+#include "common/ocsd_lib_dcd_register.h"
+#include "mem_acc/trc_mem_acc_mapper.h"
+
+/***************************************************************/
+ITraceErrorLog *DecodeTree::s_i_error_logger = &DecodeTree::s_error_logger;
+std::list<DecodeTree *> 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<DecodeTree *>::iterator it;
+ bool bDestroyed = false;
+ it = s_trace_dcd_trees.begin();
+ while(!bDestroyed && (it != s_trace_dcd_trees.end()))
+ {
+ if(*it == p_dcd_tree)
+ {
+ s_trace_dcd_trees.erase(it);
+ delete p_dcd_tree;
+ bDestroyed = true;
+ }
+ else
+ it++;
+ }
+}
+
+void DecodeTree::setAlternateErrorLogger(ITraceErrorLog *p_error_logger)
+{
+ if(p_error_logger)
+ s_i_error_logger = p_error_logger;
+ else
+ s_i_error_logger = &s_error_logger;
+}
+
+/***************************************************************/
+
+DecodeTree::DecodeTree() :
+ m_i_instr_decode(&s_instruction_decoder),
+ m_i_mem_access(0),
+ m_i_gen_elem_out(0),
+ m_i_decoder_root(0),
+ m_frame_deformatter_root(0),
+ m_decode_elem_iter(0),
+ m_default_mapper(0),
+ m_created_mapper(false)
+{
+ for(int i = 0; i < 0x80; i++)
+ m_decode_elements[i] = 0;
+
+ // reset the global demux stats.
+ m_demux_stats.frame_bytes = 0;
+ m_demux_stats.no_id_bytes = 0;
+ m_demux_stats.valid_id_bytes = 0;
+ m_demux_stats.unknown_id_bytes = 0;
+ m_demux_stats.reserved_id_bytes = 0;
+}
+
+DecodeTree::~DecodeTree()
+{
+ destroyMemAccMapper();
+ for(uint8_t i = 0; i < 0x80; i++)
+ {
+ destroyDecodeElement(i);
+ }
+ PktPrinterFact::destroyAllPrinters(m_printer_list);
+ delete m_frame_deformatter_root;
+}
+
+
+
+ocsd_datapath_resp_t DecodeTree::TraceDataIn( const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ if(m_i_decoder_root)
+ return m_i_decoder_root->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed);
+ *numBytesProcessed = 0;
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+/* set key interfaces - attach / replace on any existing tree components */
+void DecodeTree::setInstrDecoder(IInstrDecode *i_instr_decode)
+{
+ uint8_t elemID;
+ DecodeTreeElement *pElem = 0;
+
+ pElem = getFirstElement(elemID);
+ while(pElem != 0)
+ {
+ pElem->getDecoderMngr()->attachInstrDecoder(pElem->getDecoderHandle(),i_instr_decode);
+ pElem = getNextElement(elemID);
+ }
+}
+
+void DecodeTree::setMemAccessI(ITargetMemAccess *i_mem_access)
+{
+ uint8_t elemID;
+ DecodeTreeElement *pElem = 0;
+
+ pElem = getFirstElement(elemID);
+ while(pElem != 0)
+ {
+ pElem->getDecoderMngr()->attachMemAccessor(pElem->getDecoderHandle(),i_mem_access);
+ pElem = getNextElement(elemID);
+ }
+ m_i_mem_access = i_mem_access;
+}
+
+void DecodeTree::setGenTraceElemOutI(ITrcGenElemIn *i_gen_trace_elem)
+{
+ uint8_t elemID;
+ DecodeTreeElement *pElem = 0;
+
+ pElem = getFirstElement(elemID);
+ while(pElem != 0)
+ {
+ pElem->getDecoderMngr()->attachOutputSink(pElem->getDecoderHandle(),i_gen_trace_elem);
+ pElem = getNextElement(elemID);
+ }
+}
+
+ocsd_err_t DecodeTree::createMemAccMapper(memacc_mapper_t type /* = MEMACC_MAP_GLOBAL*/ )
+{
+ // clean up any old one
+ destroyMemAccMapper();
+
+ // make a new one
+ switch(type)
+ {
+ default:
+ case MEMACC_MAP_GLOBAL:
+ m_default_mapper = new (std::nothrow) TrcMemAccMapGlobalSpace();
+ break;
+ }
+
+ // set the access interface
+ if(m_default_mapper)
+ {
+ m_created_mapper = true;
+ setMemAccessI(m_default_mapper);
+ m_default_mapper->setErrorLog(s_i_error_logger);
+ }
+
+ return (m_default_mapper != 0) ? OCSD_OK : OCSD_ERR_MEM;
+}
+
+void DecodeTree::setExternMemAccMapper(TrcMemAccMapper* pMapper)
+{
+ destroyMemAccMapper(); // destroy any existing mapper - if decode tree created it.
+ m_default_mapper = pMapper;
+}
+
+void DecodeTree::destroyMemAccMapper()
+{
+ if(m_default_mapper && m_created_mapper)
+ {
+ m_default_mapper->RemoveAllAccessors();
+ delete m_default_mapper;
+ m_default_mapper = 0;
+ m_created_mapper = false;
+ }
+}
+
+void DecodeTree::logMappedRanges()
+{
+ if(m_default_mapper)
+ m_default_mapper->logMappedRanges();
+}
+
+/* Memory accessor creation - all on default mem accessor using the 0 CSID for global core space. */
+ocsd_err_t DecodeTree::addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length)
+{
+ if(!hasMemAccMapper())
+ return OCSD_ERR_NOT_INIT;
+
+ // need a valid memory buffer, and a least enough bytes for one opcode.
+ if((p_mem_buffer == 0) || (mem_length < 4))
+ return OCSD_ERR_INVALID_PARAM_VAL;
+
+ TrcMemAccessorBase *p_accessor;
+ ocsd_err_t err = TrcMemAccFactory::CreateBufferAccessor(&p_accessor, address, p_mem_buffer, mem_length);
+ if(err == OCSD_OK)
+ {
+ TrcMemAccBufPtr *pMBuffAcc = dynamic_cast<TrcMemAccBufPtr *>(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<TrcMemAccessorFile *>(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<TrcMemAccessorFile *>(p_accessor);
+ if(pAcc)
+ {
+ // add additional regions to the file accessor.
+ curr_region_idx++;
+ while(curr_region_idx < num_regions)
+ {
+ pAcc->AddOffsetRange(region_array[curr_region_idx].start_address,
+ region_array[curr_region_idx].region_size,
+ region_array[curr_region_idx].file_offset);
+ curr_region_idx++;
+ }
+ pAcc->setMemSpace(mem_space);
+
+ // add the accessor to the map.
+ err = m_default_mapper->AddAccessor(pAcc,0);
+ }
+ else
+ err = OCSD_ERR_MEM; // wrong type of object - treat as mem error
+
+ if(err != OCSD_OK)
+ TrcMemAccFactory::DestroyAccessor(p_accessor);
+ }
+ return err;
+}
+
+ocsd_err_t DecodeTree::updateBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath)
+{
+ if (!hasMemAccMapper())
+ return OCSD_ERR_NOT_INIT;
+
+ if ((region_array == 0) || (num_regions == 0) || (filepath.length() == 0))
+ return OCSD_ERR_INVALID_PARAM_VAL;
+
+ TrcMemAccessorFile *pAcc = TrcMemAccessorFile::getExistingFileAccessor(filepath);
+ if (!pAcc)
+ return OCSD_ERR_INVALID_PARAM_VAL;
+
+ int curr_region_idx = 0;
+ while (curr_region_idx < num_regions)
+ {
+ // check "new" range
+ if (!pAcc->addrStartOfRange(region_array[curr_region_idx].start_address))
+ {
+ // ensure adds cleanly
+ if (!pAcc->AddOffsetRange(region_array[curr_region_idx].start_address,
+ region_array[curr_region_idx].region_size,
+ region_array[curr_region_idx].file_offset))
+ return OCSD_ERR_INVALID_PARAM_VAL; // otherwise bail out
+ }
+ curr_region_idx++;
+ }
+ return OCSD_OK;
+}
+ocsd_err_t DecodeTree::initCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address,
+ const ocsd_mem_space_acc_t mem_space, void *p_cb_func, bool IDfn, const void *p_context)
+{
+ if(!hasMemAccMapper())
+ return OCSD_ERR_NOT_INIT;
+
+ if(p_cb_func == 0)
+ return OCSD_ERR_INVALID_PARAM_VAL;
+
+ TrcMemAccessorBase *p_accessor;
+ ocsd_err_t err = TrcMemAccFactory::CreateCBAccessor(&p_accessor, st_address, en_address, mem_space);
+ if(err == OCSD_OK)
+ {
+ TrcMemAccCB *pCBAcc = dynamic_cast<TrcMemAccCB *>(p_accessor);
+ if(pCBAcc)
+ {
+ if (IDfn)
+ pCBAcc->setCBIDIfFn((Fn_MemAccID_CB)p_cb_func, p_context);
+ else
+ pCBAcc->setCBIfFn((Fn_MemAcc_CB)p_cb_func, p_context);
+
+ err = m_default_mapper->AddAccessor(p_accessor,0);
+ }
+ else
+ err = OCSD_ERR_MEM; // wrong type of object - treat as mem error
+
+ if(err != OCSD_OK)
+ TrcMemAccFactory::DestroyAccessor(p_accessor);
+ }
+ return err;
+}
+
+ocsd_err_t DecodeTree::addCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context)
+{
+ return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, false, p_context);
+}
+
+ocsd_err_t DecodeTree::addCallbackIDMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAccID_CB p_cb_func, const void *p_context)
+{
+ return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, true, p_context);
+}
+
+ocsd_err_t DecodeTree::removeMemAccByAddress(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space)
+{
+ if(!hasMemAccMapper())
+ return OCSD_ERR_NOT_INIT;
+ return m_default_mapper->RemoveAccessorByAddress(address,mem_space,0);
+}
+
+ocsd_err_t DecodeTree::createDecoder(const std::string &decoderName, const int createFlags, const CSConfig *pConfig)
+{
+ ocsd_err_t err = OCSD_OK;
+ IDecoderMngr *pDecoderMngr = 0;
+ TraceComponent *pTraceComp = 0;
+ int crtFlags = createFlags;
+
+ uint8_t CSID = 0; // default for single stream decoder (no deformatter) - we ignore the ID
+ if(usingFormatter())
+ {
+ CSID = pConfig->getTraceID();
+ crtFlags |= OCSD_CREATE_FLG_INST_ID;
+ }
+
+ // create the decode element to attach to the channel.
+ if((err = createDecodeElement(CSID)) != OCSD_OK)
+ return err;
+
+ // get the libary decoder register.
+ OcsdLibDcdRegister * lib_reg = OcsdLibDcdRegister::getDecoderRegister();
+ if(lib_reg == 0)
+ return OCSD_ERR_NOT_INIT;
+
+ // find the named decoder
+ if((err = lib_reg->getDecoderMngrByName(decoderName,&pDecoderMngr)) != OCSD_OK)
+ return err;
+
+ // got the decoder...
+ if((err = pDecoderMngr->createDecoder(crtFlags,(int)CSID,pConfig,&pTraceComp)) != OCSD_OK)
+ return err;
+
+ m_decode_elements[CSID]->SetDecoderElement(decoderName, pDecoderMngr, pTraceComp, true);
+
+ // always attach an error logger
+ if(err == OCSD_OK)
+ err = pDecoderMngr->attachErrorLogger(pTraceComp,DecodeTree::s_i_error_logger);
+
+ // if we created a packet decoder it may need additional components.
+ if(crtFlags & OCSD_CREATE_FLG_FULL_DECODER)
+ {
+ if(m_i_instr_decode && (err == OCSD_OK))
+ err = pDecoderMngr->attachInstrDecoder(pTraceComp,m_i_instr_decode);
+
+ if(err == OCSD_ERR_DCD_INTERFACE_UNUSED) // ignore if instruction decoder refused
+ err = OCSD_OK;
+
+ if(m_i_mem_access && (err == OCSD_OK))
+ err = pDecoderMngr->attachMemAccessor(pTraceComp,m_i_mem_access);
+
+ if(err == OCSD_ERR_DCD_INTERFACE_UNUSED) // ignore if mem accessor refused
+ err = OCSD_OK;
+
+ if( m_i_gen_elem_out && (err == OCSD_OK))
+ err = pDecoderMngr->attachOutputSink(pTraceComp,m_i_gen_elem_out);
+ }
+
+ // finally attach the packet processor input to the demux output channel
+ if(err == OCSD_OK)
+ {
+ ITrcDataIn *pDataIn = 0;
+ if((err = pDecoderMngr->getDataInputI(pTraceComp,&pDataIn)) == OCSD_OK)
+ {
+ // got the interface -> attach to demux, or direct to input of decode tree
+ if(usingFormatter())
+ err = m_frame_deformatter_root->getIDStreamAttachPt(CSID)->attach(pDataIn);
+ else
+ m_i_decoder_root = pDataIn;
+ }
+ }
+
+ if(err != OCSD_OK)
+ {
+ destroyDecodeElement(CSID); // will destroy decoder as well.
+ }
+ return err;
+}
+
+ocsd_err_t DecodeTree::removeDecoder(const uint8_t CSID)
+{
+ ocsd_err_t err = OCSD_OK;
+ uint8_t localID = CSID;
+ if(!usingFormatter())
+ localID = 0;
+
+ if(usingFormatter() && !OCSD_IS_VALID_CS_SRC_ID(CSID))
+ err = OCSD_ERR_INVALID_ID;
+ else
+ {
+ destroyDecodeElement(localID);
+ }
+ return err;
+}
+
+ocsd_err_t DecodeTree::getDecoderStats(const uint8_t CSID, ocsd_decode_stats_t **p_stats_block)
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcPktProcI *pPktProc = getPktProcI(CSID);
+ if (!pPktProc)
+ return OCSD_ERR_INVALID_PARAM_VAL;
+ err = pPktProc->getStatsBlock(p_stats_block);
+ if (err == OCSD_OK) {
+ // copy in the global demux stats.
+ (*p_stats_block)->demux.frame_bytes = m_demux_stats.frame_bytes;
+ (*p_stats_block)->demux.no_id_bytes = m_demux_stats.no_id_bytes;
+ (*p_stats_block)->demux.valid_id_bytes = m_demux_stats.valid_id_bytes;
+ (*p_stats_block)->demux.unknown_id_bytes = m_demux_stats.unknown_id_bytes;
+ (*p_stats_block)->demux.reserved_id_bytes = m_demux_stats.reserved_id_bytes;
+ }
+ return err;
+}
+
+ocsd_err_t DecodeTree::resetDecoderStats(const uint8_t CSID)
+{
+ TrcPktProcI *pPktProc = getPktProcI(CSID);
+ if (!pPktProc)
+ return OCSD_ERR_INVALID_PARAM_VAL;
+ pPktProc->resetStats();
+
+ // reset the global demux stats.
+ m_demux_stats.frame_bytes = 0;
+ m_demux_stats.no_id_bytes = 0;
+ m_demux_stats.valid_id_bytes = 0;
+ m_demux_stats.unknown_id_bytes = 0;
+ m_demux_stats.reserved_id_bytes = 0;
+ return OCSD_OK;
+}
+
+TrcPktProcI *DecodeTree::getPktProcI(const uint8_t CSID)
+{
+ TrcPktProcI *pPktProc = 0;
+ TraceComponent *pComp, *pAssoc;
+ DecodeTreeElement *pElem = getDecoderElement(CSID);
+
+ if (pElem)
+ {
+ pComp = pElem->getDecoderHandle();
+ if (pComp)
+ {
+ /* if this is a full decoder then the associated component is the packet processor */
+ pAssoc = pComp->getAssocComponent();
+ if (pAssoc)
+ pPktProc = dynamic_cast<TrcPktProcI *>(pAssoc);
+ else
+ pPktProc = dynamic_cast<TrcPktProcI *>(pComp);
+ }
+ }
+ return pPktProc;
+}
+
+DecodeTreeElement * DecodeTree::getDecoderElement(const uint8_t CSID) const
+{
+ DecodeTreeElement *ret_elem = 0;
+ if(usingFormatter() && OCSD_IS_VALID_CS_SRC_ID(CSID))
+ {
+ ret_elem = m_decode_elements[CSID];
+ }
+ else
+ ret_elem = m_decode_elements[0]; // ID 0 is used if single leaf tree.
+ return ret_elem;
+}
+
+DecodeTreeElement *DecodeTree::getFirstElement(uint8_t &elemID)
+{
+ m_decode_elem_iter = 0;
+ return getNextElement(elemID);
+}
+
+DecodeTreeElement *DecodeTree::getNextElement(uint8_t &elemID)
+{
+ DecodeTreeElement *ret_elem = 0;
+
+ if(m_decode_elem_iter < 0x80)
+ {
+ // find a none zero entry or end of range
+ while((m_decode_elem_iter < 0x80) && (m_decode_elements[m_decode_elem_iter] == 0))
+ m_decode_elem_iter++;
+
+ // return entry unless end of range
+ if(m_decode_elem_iter < 0x80)
+ {
+ ret_elem = m_decode_elements[m_decode_elem_iter];
+ elemID = m_decode_elem_iter;
+ m_decode_elem_iter++;
+ }
+ }
+ return ret_elem;
+}
+
+bool DecodeTree::initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCfgFlags)
+{
+ ocsd_err_t err;
+ m_dcd_tree_type = type;
+ if(type == OCSD_TRC_SRC_FRAME_FORMATTED)
+ {
+ // frame formatted - we want to create the deformatter and hook it up
+ m_frame_deformatter_root = new (std::nothrow) TraceFormatterFrameDecoder();
+ if(m_frame_deformatter_root)
+ {
+ if (m_frame_deformatter_root->Init() != OCSD_OK)
+ return false;
+ m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger);
+ err = m_frame_deformatter_root->Configure(formatterCfgFlags);
+ if (err != OCSD_OK)
+ return false;
+ m_i_decoder_root = dynamic_cast<ITrcDataIn*>(m_frame_deformatter_root);
+ m_frame_deformatter_root->SetDemuxStatsBlock(&m_demux_stats);
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
+void DecodeTree::setSingleRoot(TrcPktProcI *pComp)
+{
+ m_i_decoder_root = static_cast<ITrcDataIn*>(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<uint8_t> &ids)
+{
+ ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER;
+ if(usingFormatter())
+ {
+ err = m_frame_deformatter_root->OutputFilterAllIDs(false);
+ if(err == OCSD_OK)
+ err = m_frame_deformatter_root->OutputFilterIDs(ids,true);
+ }
+ return err;
+}
+
+ocsd_err_t DecodeTree::clearIDFilter()
+{
+ ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER;
+ if(usingFormatter())
+ {
+ err = m_frame_deformatter_root->OutputFilterAllIDs(true);
+ }
+ return err;
+}
+
+/** add a protocol packet printer */
+ocsd_err_t DecodeTree::addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter **ppPrinter)
+{
+ ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL;
+ DecodeTreeElement *pElement = getDecoderElement(CSID);
+ if (pElement)
+ {
+ ocsd_trace_protocol_t protocol = pElement->getProtocol();
+ ItemPrinter *pPrinter;
+
+ pPrinter = PktPrinterFact::createProtocolPrinter(getPrinterList(), protocol, CSID);
+ if (pPrinter)
+ {
+ pPrinter->setMessageLogger(getCurrentErrorLogI()->getOutputLogger());
+ switch (protocol)
+ {
+ case OCSD_PROTOCOL_ETMV4I:
+ case OCSD_PROTOCOL_ETE:
+ {
+ PacketPrinter<EtmV4ITrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV4ITrcPacket> *>(pPrinter);
+ if (bMonitor)
+ err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<EtmV4ITrcPacket> *)pTPrinter);
+ else
+ err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<EtmV4ITrcPacket> *)pTPrinter);
+ }
+ break;
+
+ case OCSD_PROTOCOL_ETMV3:
+ {
+ PacketPrinter<EtmV3TrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV3TrcPacket> *>(pPrinter);
+ if (bMonitor)
+ err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<EtmV3TrcPacket> *)pTPrinter);
+ else
+ err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<EtmV3TrcPacket> *)pTPrinter);
+ }
+ break;
+
+ case OCSD_PROTOCOL_PTM:
+ {
+ PacketPrinter<PtmTrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<PtmTrcPacket> *>(pPrinter);
+ if (bMonitor)
+ err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<PtmTrcPacket> *)pTPrinter);
+ else
+ err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<PtmTrcPacket> *)pTPrinter);
+ }
+ break;
+
+ case OCSD_PROTOCOL_STM:
+ {
+ PacketPrinter<StmTrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<StmTrcPacket> *>(pPrinter);
+ if (bMonitor)
+ err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<StmTrcPacket> *)pTPrinter);
+ else
+ err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<StmTrcPacket> *)pTPrinter);
+ }
+ break;
+
+ default:
+ err = OCSD_ERR_NO_PROTOCOL;
+ break;
+ }
+
+ if (err == OCSD_OK)
+ {
+ if (ppPrinter)
+ *ppPrinter = pPrinter;
+ }
+ else
+ PktPrinterFact::destroyPrinter(getPrinterList(), pPrinter);
+ }
+ }
+ return err;
+}
+
+/** add a raw frame printer */
+ocsd_err_t DecodeTree::addRawFramePrinter(RawFramePrinter **ppPrinter, uint32_t flags)
+{
+ ocsd_err_t err = OCSD_ERR_MEM;
+ RawFramePrinter *pPrinter = PktPrinterFact::createRawFramePrinter(getPrinterList());
+ if (pPrinter)
+ {
+ pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger()));
+ TraceFormatterFrameDecoder *pFrameDecoder = getFrameDeformatter();
+ uint32_t cfgFlags = pFrameDecoder->getConfigFlags();
+ cfgFlags |= ((uint32_t)flags & (OCSD_DFRMTR_PACKED_RAW_OUT | OCSD_DFRMTR_UNPACKED_RAW_OUT));
+ pFrameDecoder->Configure(cfgFlags);
+ err = pFrameDecoder->getTrcRawFrameAttachPt()->attach(pPrinter);
+ if (ppPrinter && (err==OCSD_OK))
+ *ppPrinter = pPrinter;
+ }
+ return err;
+}
+
+/** add a generic element output printer */
+ocsd_err_t DecodeTree::addGenElemPrinter(TrcGenericElementPrinter **ppPrinter)
+{
+ ocsd_err_t err = OCSD_ERR_MEM;
+ TrcGenericElementPrinter *pPrinter = PktPrinterFact::createGenElemPrinter(getPrinterList());
+ if (pPrinter)
+ {
+ pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger()));
+ setGenTraceElemOutI(pPrinter);
+ err = OCSD_OK;
+ if (ppPrinter)
+ *ppPrinter = pPrinter;
+ }
+ return err;
+
+}
+
+/* End of File ocsd_dcd_tree.cpp */
diff --git a/decoder/source/ocsd_error.cpp b/decoder/source/ocsd_error.cpp
new file mode 100644
index 0000000..ee01064
--- /dev/null
+++ b/decoder/source/ocsd_error.cpp
@@ -0,0 +1,253 @@
+/*
+ * \file ocsd_error.cpp
+ * \brief OpenCSD : Library error class.
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/ocsd_error.h"
+#include <sstream>
+#include <iomanip>
+
+static const char *s_errorCodeDescs[][2] = {
+ /* general return errors */
+ {"OCSD_OK", "No Error."},
+ {"OCSD_ERR_FAIL","General failure."},
+ {"OCSD_ERR_MEM","Internal memory allocation error."},
+ {"OCSD_ERR_NOT_INIT","Component not initialised."},
+ {"OCSD_ERR_INVALID_ID","Invalid CoreSight Trace Source ID."},
+ {"OCSD_ERR_BAD_HANDLE","Invalid handle passed to component."},
+ {"OCSD_ERR_INVALID_PARAM_VAL","Invalid value parameter passed to component."},
+ {"OCSD_ERR_INVALID_PARAM_TYPE","Type mismatch on abstract interface."},
+ {"OCSD_ERR_FILE_ERROR","File access error"},
+ {"OCSD_ERR_NO_PROTOCOL","Trace protocol unsupported"},
+ /* attachment point errors */
+ {"OCSD_ERR_ATTACH_TOO_MANY","Cannot attach - attach device limit reached."},
+ {"OCSD_ERR_ATTACH_INVALID_PARAM"," Cannot attach - invalid parameter."},
+ {"OCSD_ERR_ATTACH_COMP_NOT_FOUND","Cannot detach - component not found."},
+ /* source reader errors */
+ {"OCSD_ERR_RDR_FILE_NOT_FOUND","source reader - file not found."},
+ {"OCSD_ERR_RDR_INVALID_INIT", "source reader - invalid initialisation parameter."},
+ {"OCSD_ERR_RDR_NO_DECODER", "source reader - not trace decoder set."},
+ /* data path errors */
+ {"OCSD_ERR_DATA_DECODE_FATAL", "A decoder in the data path has returned a fatal error."},
+ /* frame deformatter errors */
+ {"OCSD_ERR_DFMTR_NOTCONTTRACE", "Trace input to deformatter none-continuous"},
+ {"OCSD_ERR_DFMTR_BAD_FHSYNC", "Bad frame or half frame sync in trace deformatter"},
+ /* packet processor errors - protocol issues etc */
+ {"OCSD_ERR_BAD_PACKET_SEQ","Bad packet sequence"},
+ {"OCSD_ERR_INVALID_PCKT_HDR","Invalid packet header"},
+ {"OCSD_ERR_PKT_INTERP_FAIL","Interpreter failed - cannot recover - bad data or sequence"},
+ /* packet decoder errors */
+ {"OCSD_ERR_UNSUPPORTED_ISA","ISA not supported in decoder"},
+ {"OCSD_ERR_HW_CFG_UNSUPP","Programmed trace configuration not supported by decodUer."},
+ {"OCSD_ERR_UNSUPP_DECODE_PKT","Packet not supported in decoder"},
+ {"OCSD_ERR_BAD_DECODE_PKT","Reserved or unknown packet in decoder."},
+ {"OCSD_ERR_COMMIT_PKT_OVERRUN","Overrun in commit packet stack - tried to commit more than available"},
+ {"OCSD_ERR_MEM_NACC","Unable to access required memory address."},
+ {"OCSD_ERR_RET_STACK_OVERFLOW","Internal return stack overflow checks failed - popped more than we pushed."},
+ /* decode tree errors */
+ {"OCSD_ERR_DCDT_NO_FORMATTER","No formatter in use - operation not valid."},
+ /* target memory access errors */
+ {"OCSD_ERR_MEM_ACC_OVERLAP","Attempted to set an overlapping range in memory access map."},
+ {"OCSD_ERR_MEM_ACC_FILE_NOT_FOUND","Memory access file could not be opened."},
+ {"OCSD_ERR_MEM_ACC_FILE_DIFF_RANGE","Attempt to re-use the same memory access file for a different address range."},
+ {"OCSD_ERR_MEM_ACC_BAD_LEN","Memory accessor returned a bad read length value (larger than requested."},
+ {"OCSD_ERR_MEM_ACC_RANGE_INVALID","Address range in accessor set to invalid values."},
+ /* test errors - errors generated only by the test code, not the library */
+ {"OCSD_ERR_TEST_SNAPSHOT_PARSE", "Test snapshot file parse error"},
+ {"OCSD_ERR_TEST_SNAPSHOT_PARSE_INFO", "Test snapshot file parse information"},
+ {"OCSD_ERR_TEST_SNAPSHOT_READ","test snapshot reader error"},
+ {"OCSD_ERR_TEST_SS_TO_DECODER","test snapshot to decode tree conversion error"},
+ /* decoder registration */
+ {"OCSD_ERR_DCDREG_NAME_REPEAT","Attempted to register a decoder with the same name as another one."},
+ {"OCSD_ERR_DCDREG_NAME_UNKNOWN","Attempted to find a decoder with a name that is not known in the library."},
+ {"OCSD_ERR_DCDREG_TYPE_UNKNOWN","Attempted to find a decoder with a type that is not known in the library."},
+ /* decoder config */
+ {"OCSD_ERR_DCD_INTERFACE_UNUSED","Attempt to connect or use and interface not supported by this decoder."},
+ /* end marker*/
+ {"OCSD_ERR_LAST", "No error - error code end marker"}
+};
+
+ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code) :
+ m_error_code(code),
+ m_sev(sev_type),
+ m_idx(OCSD_BAD_TRC_INDEX),
+ m_chan_ID(OCSD_BAD_CS_SRC_ID)
+{
+}
+
+ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx) :
+ m_error_code(code),
+ m_sev(sev_type),
+ m_idx(idx),
+ m_chan_ID(OCSD_BAD_CS_SRC_ID)
+{
+}
+
+ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const uint8_t chan_id) :
+ m_error_code(code),
+ m_sev(sev_type),
+ m_idx(idx),
+ m_chan_ID(chan_id)
+{
+}
+
+ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const std::string &msg) :
+ m_error_code(code),
+ m_sev(sev_type),
+ m_idx(OCSD_BAD_TRC_INDEX),
+ m_chan_ID(OCSD_BAD_CS_SRC_ID),
+ m_err_message(msg)
+{
+}
+
+ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const std::string &msg) :
+ m_error_code(code),
+ m_sev(sev_type),
+ m_idx(idx),
+ m_chan_ID(OCSD_BAD_CS_SRC_ID),
+ m_err_message(msg)
+{
+}
+
+ocsdError::ocsdError(const ocsd_err_severity_t sev_type, const ocsd_err_t code, const ocsd_trc_index_t idx, const uint8_t chan_id, const std::string &msg) :
+ m_error_code(code),
+ m_sev(sev_type),
+ m_idx(idx),
+ m_chan_ID(chan_id),
+ m_err_message(msg)
+{
+}
+
+
+ocsdError::ocsdError(const ocsdError *pError) :
+ m_error_code(pError->getErrorCode()),
+ m_sev(pError->getErrorSeverity()),
+ m_idx(pError->getErrorIndex()),
+ m_chan_ID(pError->getErrorChanID())
+{
+ setMessage(pError->getMessage());
+}
+
+ocsdError::ocsdError(const ocsdError &Error) :
+ m_error_code(Error.getErrorCode()),
+ m_sev(Error.getErrorSeverity()),
+ m_idx(Error.getErrorIndex()),
+ m_chan_ID(Error.getErrorChanID())
+{
+ setMessage(Error.getMessage());
+}
+
+ocsdError::ocsdError():
+ m_error_code(OCSD_ERR_LAST),
+ m_sev(OCSD_ERR_SEV_NONE),
+ m_idx(OCSD_BAD_TRC_INDEX),
+ m_chan_ID(OCSD_BAD_CS_SRC_ID)
+{
+}
+
+ocsdError::~ocsdError()
+{
+}
+
+const std::string ocsdError::getErrorString(const ocsdError &error)
+{
+ std::string szErrStr = "LIBRARY INTERNAL ERROR: Invalid Error Object";
+ const char *sev_type_sz[] = {
+ "NONE ",
+ "ERROR:",
+ "WARN :",
+ "INFO :"
+ };
+
+ switch(error.getErrorSeverity())
+ {
+ default:
+ case OCSD_ERR_SEV_NONE:
+ break;
+
+ case OCSD_ERR_SEV_ERROR:
+ case OCSD_ERR_SEV_WARN:
+ case OCSD_ERR_SEV_INFO:
+ szErrStr = sev_type_sz[(int)error.getErrorSeverity()];
+ appendErrorDetails(szErrStr,error);
+ break;
+ }
+ return szErrStr;
+}
+
+void ocsdError::appendErrorDetails(std::string &errStr, const ocsdError &error)
+{
+ int numerrstr = sizeof(s_errorCodeDescs) / sizeof(s_errorCodeDescs[0]);
+ int code = (int)error.getErrorCode();
+ ocsd_trc_index_t idx = error.getErrorIndex();
+ uint8_t chan_ID = error.getErrorChanID();
+ std::ostringstream oss;
+
+ oss << "0x" << std::hex << std::setfill('0') << std::setw(4) << code;
+ if(code < numerrstr)
+ oss << " (" << s_errorCodeDescs[code][0] << ") [" << s_errorCodeDescs[code][1] << "]; ";
+ else
+ oss << " (unknown); ";
+
+ if(idx != OCSD_BAD_TRC_INDEX)
+ oss << "TrcIdx=" << std::dec << idx << "; ";
+
+ if(chan_ID != OCSD_BAD_CS_SRC_ID)
+ oss << "CS ID=" << std::hex << std::setfill('0') << std::setw(2) << (uint16_t)chan_ID << "; ";
+
+ oss << error.getMessage();
+ errStr = oss.str();
+}
+
+
+const char* ocsdDataRespStr::getStr()
+{
+ static const char* szRespStr[] = {
+ "OCSD_RESP_CONT: Continue processing.",
+ "OCSD_RESP_WARN_CONT: Continue processing -> a component logged a warning.",
+ "OCSD_RESP_ERR_CONT: Continue processing -> a component logged an error.",
+ "OCSD_RESP_WAIT: Pause processing",
+ "OCSD_RESP_WARN_WAIT: Pause processing -> a component logged a warning.",
+ "OCSD_RESP_ERR_WAIT: Pause processing -> a component logged an error.",
+ "OCSD_RESP_FATAL_NOT_INIT: Processing Fatal Error : component unintialised.",
+ "OCSD_RESP_FATAL_INVALID_OP: Processing Fatal Error : invalid data path operation.",
+ "OCSD_RESP_FATAL_INVALID_PARAM: Processing Fatal Error : invalid parameter in datapath call.",
+ "OCSD_RESP_FATAL_INVALID_DATA: Processing Fatal Error : invalid trace data.",
+ "OCSD_RESP_FATAL_SYS_ERR: Processing Fatal Error : internal system error."
+ };
+ if ((m_type < OCSD_RESP_CONT) || (m_type > OCSD_RESP_FATAL_SYS_ERR))
+ return "Unknown OCSD_RESP type.";
+ return szRespStr[m_type];
+}
+
+/* End of File ocsd_error.cpp */
diff --git a/decoder/source/ocsd_error_logger.cpp b/decoder/source/ocsd_error_logger.cpp
new file mode 100644
index 0000000..42794a7
--- /dev/null
+++ b/decoder/source/ocsd_error_logger.cpp
@@ -0,0 +1,159 @@
+/*
+ * \file ocsd_error_logger.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/ocsd_error_logger.h"
+
+//#include <iostream>
+#include <sstream>
+
+ocsdDefaultErrorLogger::ocsdDefaultErrorLogger() :
+ m_Verbosity(OCSD_ERR_SEV_ERROR),
+ m_output_logger(0),
+ m_created_output_logger(false)
+{
+ m_lastErr = 0;
+ for(int i = 0; i < 0x80; i++)
+ m_lastErrID[i] = 0;
+ m_error_sources.push_back("Gen_Err"); // handle 0
+ m_error_sources.push_back("Gen_Warn"); // handle 1
+ m_error_sources.push_back("Gen_Info"); // handle 2
+}
+
+ocsdDefaultErrorLogger::~ocsdDefaultErrorLogger()
+{
+ if(m_created_output_logger)
+ delete m_output_logger;
+
+ if(m_lastErr)
+ delete m_lastErr;
+
+ for(int i = 0; i < 0x80; i++)
+ if(m_lastErrID[i] != 0) delete m_lastErrID[i];
+}
+
+bool ocsdDefaultErrorLogger::initErrorLogger(const ocsd_err_severity_t verbosity, bool bCreateOutputLogger /*= false*/)
+{
+ bool bInit = true;
+ m_Verbosity = verbosity;
+ if(bCreateOutputLogger)
+ {
+ m_output_logger = new (std::nothrow) ocsdMsgLogger();
+ if(m_output_logger)
+ {
+ m_created_output_logger = true;
+ m_output_logger->setLogOpts(ocsdMsgLogger::OUT_STDERR);
+ }
+ else
+ bInit = false;
+ }
+ return bInit;
+}
+
+void ocsdDefaultErrorLogger::setOutputLogger(ocsdMsgLogger *pLogger)
+{
+ // if we created the current logger, delete it.
+ if(m_output_logger && m_created_output_logger)
+ delete m_output_logger;
+ m_created_output_logger = false;
+ m_output_logger = pLogger;
+}
+
+const ocsd_hndl_err_log_t ocsdDefaultErrorLogger::RegisterErrorSource(const std::string &component_name)
+{
+ ocsd_hndl_err_log_t handle = m_error_sources.size();
+ m_error_sources.push_back(component_name);
+ return handle;
+}
+
+void ocsdDefaultErrorLogger::LogError(const ocsd_hndl_err_log_t handle, const ocsdError *Error)
+{
+ // only log errors that match or exceed the current verbosity
+ if(m_Verbosity >= Error->getErrorSeverity())
+ {
+ // print out only if required
+ if(m_output_logger)
+ {
+ if(m_output_logger->isLogging())
+ {
+ std::string errStr = "unknown";
+ if(handle < m_error_sources.size())
+ errStr = m_error_sources[handle];
+ errStr += " : " + ocsdError::getErrorString(Error);
+ m_output_logger->LogMsg(errStr);
+ }
+ }
+
+ // log last error
+ if(m_lastErr == 0)
+ CreateErrorObj(&m_lastErr,Error);
+ else
+ *m_lastErr = Error;
+
+ // log last error associated with an ID
+ if(OCSD_IS_VALID_CS_SRC_ID(Error->getErrorChanID()))
+ {
+ if(m_lastErrID[Error->getErrorChanID()] == 0)
+ CreateErrorObj(&m_lastErrID[Error->getErrorChanID()], Error);
+ else
+ *m_lastErrID[Error->getErrorChanID()] = Error;
+ }
+ }
+}
+
+void ocsdDefaultErrorLogger::LogMessage(const ocsd_hndl_err_log_t handle, const ocsd_err_severity_t filter_level, const std::string &msg )
+{
+ // only log errors that match or exceed the current verbosity
+ if((m_Verbosity >= filter_level))
+ {
+ if(m_output_logger)
+ {
+ if(m_output_logger->isLogging())
+ {
+ std::string errStr = "unknown";
+ if(handle < m_error_sources.size())
+ errStr = m_error_sources[handle];
+ errStr += " : " + msg;
+ m_output_logger->LogMsg(errStr);
+ }
+ }
+ }
+}
+
+void ocsdDefaultErrorLogger::CreateErrorObj(ocsdError **ppErr, const ocsdError *p_from)
+{
+ *ppErr = new (std::nothrow) ocsdError(p_from);
+}
+
+/* End of File ocsd_error_logger.cpp */
diff --git a/decoder/source/ocsd_gen_elem_list.cpp b/decoder/source/ocsd_gen_elem_list.cpp
new file mode 100644
index 0000000..1a568ec
--- /dev/null
+++ b/decoder/source/ocsd_gen_elem_list.cpp
@@ -0,0 +1,168 @@
+/*
+ * \file ocsd_gen_elem_list.cpp
+ * \brief OpenCSD : List of Generic trace elements for output.
+ *
+ * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/ocsd_gen_elem_list.h"
+
+OcsdGenElemList::OcsdGenElemList()
+{
+ m_firstElemIdx=0;
+ m_numUsed=0;
+ m_numPend=0;
+
+ m_elemArraySize = 0;
+ m_sendIf = 0;
+ m_CSID = 0;
+ m_pElemArray = 0;
+}
+
+OcsdGenElemList::~OcsdGenElemList()
+{
+ for(int i = 0; i<m_elemArraySize; i++)
+ {
+ delete m_pElemArray[i].pElem;
+ }
+ delete [] m_pElemArray;
+ m_pElemArray = 0;
+}
+
+void OcsdGenElemList::reset()
+{
+ m_firstElemIdx=0;
+ m_numUsed=0;
+ m_numPend=0;
+}
+
+OcsdTraceElement *OcsdGenElemList::getNextElem(const ocsd_trc_index_t trc_pkt_idx)
+{
+ OcsdTraceElement *pElem = 0;
+ if(getNumElem() == m_elemArraySize) // all in use
+ growArray();
+
+ if(m_pElemArray != 0)
+ {
+ m_numUsed++;
+ int idx = getAdjustedIdx(m_firstElemIdx + m_numUsed - 1);
+ pElem = m_pElemArray[idx].pElem;
+ m_pElemArray[idx].trc_pkt_idx = trc_pkt_idx;
+ }
+ return pElem;
+}
+
+const ocsd_gen_trc_elem_t OcsdGenElemList::getElemType(const int entryN) const
+{
+ ocsd_gen_trc_elem_t elem_type = OCSD_GEN_TRC_ELEM_UNKNOWN;
+ if(entryN < getNumElem())
+ {
+ int idx = getAdjustedIdx(m_firstElemIdx + entryN);
+ elem_type = m_pElemArray[idx].pElem->getType();
+ }
+ return elem_type;
+}
+
+ocsd_datapath_resp_t OcsdGenElemList::sendElements()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ if((m_elemArraySize == 0) || (m_sendIf == 0))
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ if(!m_sendIf->hasAttachedAndEnabled())
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ while(elemToSend() && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ resp = m_sendIf->first()->TraceElemIn(m_pElemArray[m_firstElemIdx].trc_pkt_idx, m_CSID, *(m_pElemArray[m_firstElemIdx].pElem));
+ m_firstElemIdx++;
+ if(m_firstElemIdx >= m_elemArraySize)
+ m_firstElemIdx = 0;
+ m_numUsed--;
+ }
+ return resp;
+}
+
+// this function will enlarge the array, and create extra element objects.
+// existing objects will be moved to the front of the array
+// called if all elements are in use. (sets indexes accordingly)
+void OcsdGenElemList::growArray()
+{
+ elemPtr_t *p_new_array = 0;
+
+ int increment;
+ if(m_elemArraySize == 0)
+ // starting from scratch...
+ increment = 8;
+ else
+ increment = m_elemArraySize / 2; // grow by 50%
+
+
+ p_new_array = new (std::nothrow) elemPtr_t[m_elemArraySize+increment];
+
+ if(p_new_array != 0)
+ {
+ // fill the last increment elements with new objects
+ for(int i=0; i < increment; i++)
+ {
+ p_new_array[m_elemArraySize+i].pElem = new (std::nothrow) OcsdTraceElement();
+ }
+
+ // copy the existing objects from the old array to the start of the new one
+ // and adjust the indices.
+ if(m_elemArraySize > 0)
+ {
+ int inIdx = m_firstElemIdx;
+ for(int i = 0; i < m_elemArraySize; i++)
+ {
+ p_new_array[i].pElem = m_pElemArray[inIdx].pElem;
+ p_new_array[i].trc_pkt_idx = m_pElemArray[inIdx].trc_pkt_idx;
+ inIdx++;
+ if(inIdx >= m_elemArraySize)
+ inIdx = 0;
+ }
+ }
+
+ // delete the old pointer array.
+ delete [] m_pElemArray;
+ m_elemArraySize += increment;
+ }
+ else
+ m_elemArraySize = 0;
+
+ // update the internal array pointers to the new array
+ if(m_firstElemIdx >= 0)
+ m_firstElemIdx = 0;
+ m_pElemArray = p_new_array;
+}
+
+/* End of File ocsd_gen_elem_list.cpp */
diff --git a/decoder/source/ocsd_gen_elem_stack.cpp b/decoder/source/ocsd_gen_elem_stack.cpp
new file mode 100644
index 0000000..66fe75d
--- /dev/null
+++ b/decoder/source/ocsd_gen_elem_stack.cpp
@@ -0,0 +1,197 @@
+/*
+* \file ocsd_gen_elem_stack.cpp
+* \brief OpenCSD : List of Generic trace elements for output.
+*
+* \copyright Copyright (c) 2020, ARM Limited. All Rights Reserved.
+*/
+
+
+/*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its contributors
+* may be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "common/ocsd_gen_elem_stack.h"
+
+OcsdGenElemStack::OcsdGenElemStack() :
+ m_pElemArray(0),
+ m_elemArraySize(0),
+ m_elem_to_send(0),
+ m_curr_elem_idx(0),
+ m_send_elem_idx(0),
+ m_CSID(0),
+ m_sendIf(NULL),
+ m_is_init(false)
+{
+
+}
+
+OcsdGenElemStack::~OcsdGenElemStack()
+{
+ for (int i = 0; i<m_elemArraySize; i++)
+ {
+ delete m_pElemArray[i].pElem;
+ }
+ delete [] m_pElemArray;
+ m_pElemArray = 0;
+}
+
+ocsd_err_t OcsdGenElemStack::addElem(const ocsd_trc_index_t trc_pkt_idx)
+{
+ ocsd_err_t err = OCSD_OK;
+
+ if (((m_curr_elem_idx + 1) == m_elemArraySize) || !m_pElemArray)
+ {
+ err = growArray();
+ if (err)
+ return err;
+ }
+
+ // if there is a least one element then copy and increment
+ // otherwise we are at base of stack.
+ if (m_elem_to_send)
+ {
+ copyPersistentData(m_curr_elem_idx, m_curr_elem_idx + 1);
+ m_curr_elem_idx++;
+ }
+ m_pElemArray[m_curr_elem_idx].trc_pkt_idx = trc_pkt_idx;
+ m_elem_to_send++;
+ return err;
+}
+
+ocsd_err_t OcsdGenElemStack::addElemType(const ocsd_trc_index_t trc_pkt_idx, ocsd_gen_trc_elem_t elem_type)
+{
+ ocsd_err_t err = addElem(trc_pkt_idx);
+ if (!err)
+ getCurrElem().setType(elem_type);
+ return err;
+}
+
+ocsd_err_t OcsdGenElemStack::resetElemStack()
+{
+ ocsd_err_t err = OCSD_OK;
+ if (!m_pElemArray)
+ {
+ err = growArray();
+ if (err)
+ return err;
+ }
+
+ if (!isInit())
+ return OCSD_ERR_NOT_INIT;
+
+ resetIndexes();
+ return err;
+}
+
+void OcsdGenElemStack::resetIndexes()
+{
+ // last time there was more than one element on stack
+ if (m_curr_elem_idx > 0)
+ copyPersistentData(m_curr_elem_idx, 0);
+
+ // indexes to bottom of stack, nothing in use at present
+ m_curr_elem_idx = 0;
+ m_send_elem_idx = 0;
+ m_elem_to_send = 0;
+}
+
+ocsd_datapath_resp_t OcsdGenElemStack::sendElements()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ if (!isInit())
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ while (m_elem_to_send && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ resp = m_sendIf->first()->TraceElemIn(m_pElemArray[m_send_elem_idx].trc_pkt_idx, m_CSID, *(m_pElemArray[m_send_elem_idx].pElem));
+ m_send_elem_idx++;
+ m_elem_to_send--;
+ }
+
+ // clear the indexes if we are done.
+ if (!m_elem_to_send)
+ resetIndexes();
+ return resp;
+}
+
+ocsd_err_t OcsdGenElemStack::growArray()
+{
+ elemPtr_t *p_new_array = 0;
+ const int increment = 4;
+
+ p_new_array = new (std::nothrow) elemPtr_t[m_elemArraySize + increment];
+
+ if (p_new_array != 0)
+ {
+ OcsdTraceElement *pElem = 0;
+
+ // fill the last increment elements with new objects
+ for (int i = 0; i < increment; i++)
+ {
+ pElem = new (std::nothrow) OcsdTraceElement();
+ if (!pElem)
+ return OCSD_ERR_MEM;
+ pElem->init();
+ p_new_array[m_elemArraySize + i].pElem = pElem;
+ }
+
+ // copy the existing objects from the old array to the start of the new one
+ if (m_elemArraySize > 0)
+ {
+ for (int i = 0; i < m_elemArraySize; i++)
+ {
+ p_new_array[i].pElem = m_pElemArray[i].pElem;
+ p_new_array[i].trc_pkt_idx = m_pElemArray[i].trc_pkt_idx;
+ }
+ }
+
+ // delete the old pointer array.
+ delete[] m_pElemArray;
+ m_elemArraySize += increment;
+ m_pElemArray = p_new_array;
+ }
+ else
+ return OCSD_ERR_MEM;
+
+ return OCSD_OK;
+}
+
+void OcsdGenElemStack::copyPersistentData(int src, int dst)
+{
+ m_pElemArray[dst].pElem->copyPersistentData(*(m_pElemArray[src].pElem));
+}
+
+const bool OcsdGenElemStack::isInit()
+{
+ if (!m_is_init) {
+ if (m_elemArraySize && m_pElemArray && m_sendIf)
+ m_is_init = true;
+ }
+ return m_is_init;
+}
+
+
+/* End of File ocsd_gen_elem_stack.cpp */
diff --git a/decoder/source/ocsd_lib_dcd_register.cpp b/decoder/source/ocsd_lib_dcd_register.cpp
new file mode 100644
index 0000000..0233c89
--- /dev/null
+++ b/decoder/source/ocsd_lib_dcd_register.cpp
@@ -0,0 +1,216 @@
+/*
+ * \file ocsd_lib_dcd_register.cpp
+ * \brief OpenCSD : Library decoder register object
+ *
+ * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/ocsd_lib_dcd_register.h"
+
+// include built-in decode manager headers
+#include "opencsd/etmv4/trc_dcd_mngr_etmv4i.h"
+#include "opencsd/etmv3/trc_dcd_mngr_etmv3.h"
+#include "opencsd/ptm/trc_dcd_mngr_ptm.h"
+#include "opencsd/stm/trc_dcd_mngr_stm.h"
+#include "opencsd/ete/trc_dcd_mngr_ete.h"
+
+// create array of built-in decoders to register with library
+static built_in_decoder_info_t sBuiltInArray[] = {
+ CREATE_BUILTIN_ENTRY(DecoderMngrEtmV4I,OCSD_BUILTIN_DCD_ETMV4I),
+ CREATE_BUILTIN_ENTRY(DecoderMngrEtmV3, OCSD_BUILTIN_DCD_ETMV3),
+ CREATE_BUILTIN_ENTRY(DecoderMngrPtm, OCSD_BUILTIN_DCD_PTM),
+ CREATE_BUILTIN_ENTRY(DecoderMngrStm, OCSD_BUILTIN_DCD_STM),
+ CREATE_BUILTIN_ENTRY(DecoderMngrETE, OCSD_BUILTIN_DCD_ETE)
+ //{ 0, 0, 0}
+};
+
+#define NUM_BUILTINS sizeof(sBuiltInArray) / sizeof(built_in_decoder_info_t)
+
+
+OcsdLibDcdRegister *OcsdLibDcdRegister::m_p_libMngr = 0;
+bool OcsdLibDcdRegister::m_b_registeredBuiltins = false;
+ocsd_trace_protocol_t OcsdLibDcdRegister::m_nextCustomProtocolID = OCSD_PROTOCOL_CUSTOM_0;
+
+OcsdLibDcdRegister *OcsdLibDcdRegister::getDecoderRegister()
+{
+ if(m_p_libMngr == 0)
+ m_p_libMngr = new (std::nothrow) OcsdLibDcdRegister();
+ return m_p_libMngr;
+}
+
+const ocsd_trace_protocol_t OcsdLibDcdRegister::getNextCustomProtocolID()
+{
+ ocsd_trace_protocol_t ret = m_nextCustomProtocolID;
+ if(m_nextCustomProtocolID < OCSD_PROTOCOL_END)
+ m_nextCustomProtocolID = (ocsd_trace_protocol_t)(((int)m_nextCustomProtocolID)+1);
+ return ret;
+}
+
+void OcsdLibDcdRegister::releaseLastCustomProtocolID()
+{
+ if(m_nextCustomProtocolID > OCSD_PROTOCOL_CUSTOM_0)
+ m_nextCustomProtocolID = (ocsd_trace_protocol_t)(((int)m_nextCustomProtocolID)-1);
+}
+
+OcsdLibDcdRegister::OcsdLibDcdRegister()
+{
+ m_iter = m_decoder_mngrs.begin();
+ m_pLastTypedDecoderMngr = 0;
+}
+
+OcsdLibDcdRegister::~OcsdLibDcdRegister()
+{
+ m_decoder_mngrs.clear();
+ m_typed_decoder_mngrs.clear();
+ m_pLastTypedDecoderMngr = 0;
+}
+
+const ocsd_err_t OcsdLibDcdRegister::registerDecoderTypeByName(const std::string &name, IDecoderMngr *p_decoder_fact)
+{
+ if(isRegisteredDecoder(name))
+ return OCSD_ERR_DCDREG_NAME_REPEAT;
+ m_decoder_mngrs.emplace(std::pair<const std::string, IDecoderMngr *>(name,p_decoder_fact));
+ m_typed_decoder_mngrs.emplace(std::pair<const ocsd_trace_protocol_t, IDecoderMngr *>(p_decoder_fact->getProtocolType(),p_decoder_fact));
+ return OCSD_OK;
+}
+
+void OcsdLibDcdRegister::registerBuiltInDecoders()
+{
+ bool memFail = false;
+ for(unsigned i = 0; i < NUM_BUILTINS; i++)
+ {
+ if(sBuiltInArray[i].PFn)
+ {
+ sBuiltInArray[i].pMngr = sBuiltInArray[i].PFn( sBuiltInArray[i].name);
+ if(!sBuiltInArray[i].pMngr)
+ memFail=true;
+ }
+ }
+ m_b_registeredBuiltins = !memFail;
+}
+
+void OcsdLibDcdRegister::deregisterAllDecoders()
+{
+ if(m_b_registeredBuiltins)
+ {
+ for(unsigned i = 0; i < NUM_BUILTINS; i++)
+ delete sBuiltInArray[i].pMngr;
+ m_b_registeredBuiltins = false;
+ }
+
+ if(m_p_libMngr)
+ {
+ m_p_libMngr->deRegisterCustomDecoders();
+ delete m_p_libMngr;
+ m_p_libMngr = 0;
+ }
+}
+
+void OcsdLibDcdRegister::deRegisterCustomDecoders()
+{
+ std::map<const ocsd_trace_protocol_t, IDecoderMngr *>::const_iterator iter = m_typed_decoder_mngrs.begin();
+ while(iter != m_typed_decoder_mngrs.end())
+ {
+ IDecoderMngr *pMngr = iter->second;
+ if(pMngr->getProtocolType() >= OCSD_PROTOCOL_CUSTOM_0)
+ delete pMngr;
+ iter++;
+ }
+}
+
+const ocsd_err_t OcsdLibDcdRegister::getDecoderMngrByName(const std::string &name, IDecoderMngr **p_decoder_mngr)
+{
+ if(!m_b_registeredBuiltins)
+ {
+ registerBuiltInDecoders();
+ if(!m_b_registeredBuiltins)
+ return OCSD_ERR_MEM;
+ }
+
+ std::map<const std::string, IDecoderMngr *>::const_iterator iter = m_decoder_mngrs.find(name);
+ if(iter == m_decoder_mngrs.end())
+ return OCSD_ERR_DCDREG_NAME_UNKNOWN;
+ *p_decoder_mngr = iter->second;
+ return OCSD_OK;
+}
+
+const ocsd_err_t OcsdLibDcdRegister::getDecoderMngrByType(const ocsd_trace_protocol_t decoderType, IDecoderMngr **p_decoder_mngr)
+{
+ if(!m_b_registeredBuiltins)
+ {
+ registerBuiltInDecoders();
+ if(!m_b_registeredBuiltins)
+ return OCSD_ERR_MEM;
+ }
+
+ if (m_pLastTypedDecoderMngr && (m_pLastTypedDecoderMngr->getProtocolType() == decoderType))
+ *p_decoder_mngr = m_pLastTypedDecoderMngr;
+ else
+ {
+ std::map<const ocsd_trace_protocol_t, IDecoderMngr *>::const_iterator iter = m_typed_decoder_mngrs.find(decoderType);
+ if (iter == m_typed_decoder_mngrs.end())
+ return OCSD_ERR_DCDREG_TYPE_UNKNOWN;
+ *p_decoder_mngr = m_pLastTypedDecoderMngr = iter->second;
+ }
+ return OCSD_OK;
+}
+
+const bool OcsdLibDcdRegister::isRegisteredDecoder(const std::string &name)
+{
+ std::map<const std::string, IDecoderMngr *>::const_iterator iter = m_decoder_mngrs.find(name);
+ if(iter != m_decoder_mngrs.end())
+ return true;
+ return false;
+}
+
+const bool OcsdLibDcdRegister::isRegisteredDecoderType(const ocsd_trace_protocol_t decoderType)
+{
+ std::map<const ocsd_trace_protocol_t, IDecoderMngr *>::const_iterator iter = m_typed_decoder_mngrs.find(decoderType);
+ if(iter != m_typed_decoder_mngrs.end())
+ return true;
+ return false;
+}
+
+const bool OcsdLibDcdRegister::getFirstNamedDecoder(std::string &name)
+{
+ m_iter = m_decoder_mngrs.begin();
+ return getNextNamedDecoder(name);
+}
+
+const bool OcsdLibDcdRegister::getNextNamedDecoder(std::string &name)
+{
+ if(m_iter == m_decoder_mngrs.end())
+ return false;
+ name = m_iter->first;
+ m_iter++;
+ return true;
+}
+
+/* End of File ocsd_lib_dcd_register.cpp */
diff --git a/decoder/source/ocsd_msg_logger.cpp b/decoder/source/ocsd_msg_logger.cpp
new file mode 100644
index 0000000..287edfa
--- /dev/null
+++ b/decoder/source/ocsd_msg_logger.cpp
@@ -0,0 +1,120 @@
+/*
+ * \file ocsd_msg_logger.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/ocsd_msg_logger.h"
+
+#include <iostream>
+#include <sstream>
+
+#define MSGLOG_OUT_MASK (ocsdMsgLogger::OUT_FILE | ocsdMsgLogger::OUT_STDERR | ocsdMsgLogger::OUT_STDOUT | ocsdMsgLogger::OUT_STR_CB)
+
+ocsdMsgLogger::ocsdMsgLogger() :
+ m_outFlags(ocsdMsgLogger::OUT_STDOUT),
+ m_logFileName("ocsd_trace_decode.log"),
+ m_pOutStrI(0)
+{
+}
+
+ocsdMsgLogger::~ocsdMsgLogger()
+{
+ m_out_file.close();
+}
+
+void ocsdMsgLogger::setLogOpts(int logOpts)
+{
+ m_outFlags = logOpts & (MSGLOG_OUT_MASK);
+}
+
+void ocsdMsgLogger::setLogFileName(const char *fileName)
+{
+ if (fileName == 0)
+ m_logFileName = "";
+ else
+ m_logFileName = fileName;
+
+ if(m_out_file.is_open())
+ m_out_file.close();
+
+ if (m_logFileName.length())
+ m_outFlags |= (int)ocsdMsgLogger::OUT_FILE;
+ else
+ m_outFlags &= ~((int)ocsdMsgLogger::OUT_FILE);
+}
+
+void ocsdMsgLogger::setStrOutFn(ocsdMsgLogStrOutI *p_IstrOut)
+{
+ m_pOutStrI = p_IstrOut;
+ if (p_IstrOut)
+ m_outFlags |= (int)ocsdMsgLogger::OUT_STR_CB;
+ else
+ m_outFlags &= ~((int)ocsdMsgLogger::OUT_STR_CB);
+}
+
+void ocsdMsgLogger::LogMsg(const std::string &msg)
+{
+ if(m_outFlags & OUT_STDOUT)
+ {
+ std::cout << msg;
+ std::cout.flush();
+ }
+
+ if(m_outFlags & OUT_STDERR)
+ {
+ std::cerr << msg;
+ std::cerr.flush();
+ }
+
+ if(m_outFlags & OUT_FILE)
+ {
+ if(!m_out_file.is_open())
+ {
+ m_out_file.open(m_logFileName.c_str(),std::fstream::out | std::fstream::app);
+ }
+ m_out_file << msg;
+ m_out_file.flush();
+ }
+
+ if (m_outFlags & OUT_STR_CB)
+ {
+ if (m_pOutStrI)
+ m_pOutStrI->printOutStr(msg);
+ }
+}
+
+const bool ocsdMsgLogger::isLogging() const
+{
+ return (bool)((m_outFlags & MSGLOG_OUT_MASK) != 0);
+}
+
+/* End of File ocsd_msg_logger.cpp */
diff --git a/decoder/source/ocsd_version.cpp b/decoder/source/ocsd_version.cpp
new file mode 100644
index 0000000..6dd3f2c
--- /dev/null
+++ b/decoder/source/ocsd_version.cpp
@@ -0,0 +1,48 @@
+/*
+ * \file ocsd_version.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "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 */
diff --git a/decoder/source/pkt_printers/raw_frame_printer.cpp b/decoder/source/pkt_printers/raw_frame_printer.cpp
new file mode 100644
index 0000000..7ac2ddf
--- /dev/null
+++ b/decoder/source/pkt_printers/raw_frame_printer.cpp
@@ -0,0 +1,104 @@
+/*
+ * \file raw_frame_printer.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+
+#include "opencsd.h"
+
+
+ocsd_err_t RawFramePrinter::TraceRawFrameIn( const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const ocsd_rawframe_elem_t frame_element,
+ const int dataBlockSize,
+ const uint8_t *pDataBlock,
+ const uint8_t traceID)
+{
+
+ if(op == OCSD_OP_DATA) // only interested in actual frame data.
+ {
+ std::string strData;
+ std::ostringstream oss;
+ int printDataSize = dataBlockSize;
+
+ oss << "Frame Data; Index" << std::setw(7) << index << "; ";
+
+ switch(frame_element)
+ {
+ case OCSD_FRM_PACKED: oss << std::setw(15) << "RAW_PACKED; "; break;
+ case OCSD_FRM_HSYNC: oss << std::setw(15) << "HSYNC; "; break;
+ case OCSD_FRM_FSYNC: oss << std::setw(15) << "FSYNC; "; break;
+ case OCSD_FRM_ID_DATA:
+ oss << std::setw(10) << "ID_DATA[";
+ if (traceID == OCSD_BAD_CS_SRC_ID)
+ oss << "????";
+ else
+ oss << "0x" << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)traceID;
+ oss << "]; ";
+ break;
+ default: oss << std::setw(15) << "UNKNOWN; "; break;
+ }
+
+ if(printDataSize)
+ {
+ createDataString(printDataSize,pDataBlock,16,strData);
+ oss << strData;
+ }
+ oss << std::endl;
+ itemPrintLine(oss.str());
+ }
+ return OCSD_OK;
+}
+
+void RawFramePrinter::createDataString(const int dataSize, const uint8_t *pData, int bytesPerLine, std::string &dataStr)
+{
+ int lineBytes = 0;
+ std::ostringstream oss;
+
+ for(int i = 0; i < dataSize; i++)
+ {
+ if(lineBytes == bytesPerLine)
+ {
+ oss << std::endl;
+ lineBytes = 0;
+ }
+ oss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)pData[i] << " ";
+ lineBytes ++;
+ }
+ dataStr = oss.str();
+}
+
+
+/* End of File raw_frame_printer.cpp */
diff --git a/decoder/source/pkt_printers/trc_print_fact.cpp b/decoder/source/pkt_printers/trc_print_fact.cpp
new file mode 100644
index 0000000..6b5df1f
--- /dev/null
+++ b/decoder/source/pkt_printers/trc_print_fact.cpp
@@ -0,0 +1,124 @@
+/*
+* \file trc_print_fact.cpp
+* \brief OpenCSD : Trace Packet printer factory.
+*
+* \copyright Copyright (c) 2017, ARM Limited. All Rights Reserved.
+*/
+
+
+/*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its contributors
+* may be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "pkt_printers/trc_print_fact.h"
+
+RawFramePrinter * PktPrinterFact::createRawFramePrinter(std::vector<ItemPrinter *> &printer_list, ocsdMsgLogger *pMsgLogger /*= 0*/)
+{
+ RawFramePrinter *pPrinter = 0;
+ pPrinter = new (std::nothrow)RawFramePrinter();
+ SavePrinter(printer_list, pPrinter, pMsgLogger);
+ return pPrinter;
+}
+
+TrcGenericElementPrinter *PktPrinterFact::createGenElemPrinter(std::vector<ItemPrinter *> &printer_list, ocsdMsgLogger *pMsgLogger /*= 0*/)
+{
+ TrcGenericElementPrinter *pPrinter = 0;
+ pPrinter = new (std::nothrow)TrcGenericElementPrinter();
+ SavePrinter(printer_list, pPrinter, pMsgLogger);
+ return pPrinter;
+}
+
+ItemPrinter *PktPrinterFact::createProtocolPrinter(std::vector<ItemPrinter *> &printer_list, ocsd_trace_protocol_t protocol, uint8_t CSID, ocsdMsgLogger *pMsgLogger /*= 0*/)
+{
+ ItemPrinter *pPrinter = 0;
+ switch (protocol)
+ {
+ case OCSD_PROTOCOL_ETMV4I:
+ case OCSD_PROTOCOL_ETE:
+ pPrinter = new (std::nothrow) PacketPrinter<EtmV4ITrcPacket>(CSID);
+ break;
+ case OCSD_PROTOCOL_ETMV3:
+ pPrinter = new (std::nothrow) PacketPrinter<EtmV3TrcPacket>(CSID);
+ break;
+ case OCSD_PROTOCOL_PTM:
+ pPrinter = new (std::nothrow) PacketPrinter<PtmTrcPacket>(CSID);
+ break;
+ case OCSD_PROTOCOL_STM:
+ pPrinter = new (std::nothrow) PacketPrinter<StmTrcPacket>(CSID);
+ break;
+ default:
+ break;
+ }
+ SavePrinter(printer_list, pPrinter, pMsgLogger);
+ return pPrinter;
+}
+
+const int PktPrinterFact::numPrinters(std::vector<ItemPrinter *> &printer_list)
+{
+ return printer_list.size();
+}
+
+void PktPrinterFact::SavePrinter(std::vector<ItemPrinter *> &printer_list, ItemPrinter *pPrinter, ocsdMsgLogger *pMsgLogger)
+{
+ if (pPrinter)
+ {
+ pPrinter->setMessageLogger(pMsgLogger);
+ printer_list.push_back((ItemPrinter *)pPrinter);
+ }
+}
+
+void PktPrinterFact::destroyAllPrinters(std::vector<ItemPrinter *> &printer_list)
+{
+ std::vector<ItemPrinter *>::iterator it;
+ it = printer_list.begin();
+ while (it != printer_list.end())
+ {
+ delete *it;
+ it++;
+ }
+ printer_list.clear();
+}
+
+void PktPrinterFact::destroyPrinter(std::vector<ItemPrinter *> &printer_list, ItemPrinter *pPrinter)
+{
+ std::vector<ItemPrinter *>::iterator it;
+ it = printer_list.begin();
+ while (it != printer_list.end())
+ {
+ if (*it == pPrinter)
+ {
+ printer_list.erase(it);
+ delete pPrinter;
+ return;
+ }
+ else
+ it++;
+ }
+}
+
+
+
+/* end of file trc_print_fact.cpp */
diff --git a/decoder/source/ptm/trc_cmp_cfg_ptm.cpp b/decoder/source/ptm/trc_cmp_cfg_ptm.cpp
new file mode 100644
index 0000000..74ded02
--- /dev/null
+++ b/decoder/source/ptm/trc_cmp_cfg_ptm.cpp
@@ -0,0 +1,59 @@
+/*
+ * \file trc_cmp_cfg_ptm.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opencsd/ptm/trc_cmp_cfg_ptm.h"
+
+PtmConfig::PtmConfig()
+{
+ // defaults set ETMv1.1, V7A
+ m_cfg.arch_ver = ARCH_V7;
+ m_cfg.core_prof = profile_CortexA;
+ m_cfg.reg_ccer = 0;
+ m_cfg.reg_idr = 0x4100F310;
+ m_cfg.reg_ctrl = 0;
+}
+
+PtmConfig::PtmConfig(const ocsd_ptm_cfg *cfg_regs)
+{
+ m_cfg = *cfg_regs;
+}
+
+const int PtmConfig::CtxtIDBytes() const
+{
+ int ctxtIdsizes[] = { 0, 1, 2, 4 };
+ return ctxtIdsizes[(m_cfg.reg_ctrl >> 14) & 0x3];
+}
+
+
+/* End of File trc_cmp_cfg_ptm.cpp */
diff --git a/decoder/source/ptm/trc_pkt_decode_ptm.cpp b/decoder/source/ptm/trc_pkt_decode_ptm.cpp
new file mode 100644
index 0000000..7abee84
--- /dev/null
+++ b/decoder/source/ptm/trc_pkt_decode_ptm.cpp
@@ -0,0 +1,671 @@
+/*
+ * \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 <sstream>
+#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;
+ m_output_elem.unsync_eot_info = m_unsync_info;
+ 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);
+ m_output_elem.setUnSyncEOTReason(UNSYNC_EOT);
+ resp = outputTraceElement(m_output_elem);
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodePtm::onReset()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_unsync_info = UNSYNC_RESET_DECODER;
+ 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;
+ m_unsync_info = UNSYNC_INIT_DECODER;
+ 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;
+ ocsd_err_t err = OCSD_OK;
+
+ m_instr_info.instr_addr = m_curr_pe_state.instr_addr;
+ m_instr_info.isa = m_curr_pe_state.isa;
+
+ // set type (which resets out-elem) before traceInstrToWP modifies out-elem values
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
+
+ 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.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.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 */
diff --git a/decoder/source/ptm/trc_pkt_elem_ptm.cpp b/decoder/source/ptm/trc_pkt_elem_ptm.cpp
new file mode 100644
index 0000000..7c8bcd7
--- /dev/null
+++ b/decoder/source/ptm/trc_pkt_elem_ptm.cpp
@@ -0,0 +1,473 @@
+/*
+ * \file trc_pkt_elem_ptm.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sstream>
+#include <iomanip>
+
+#include "opencsd/ptm/trc_pkt_elem_ptm.h"
+
+PtmTrcPacket::PtmTrcPacket()
+{
+}
+
+PtmTrcPacket::~PtmTrcPacket()
+{
+}
+
+PtmTrcPacket &PtmTrcPacket::operator =(const ocsd_ptm_pkt* p_pkt)
+{
+ *dynamic_cast<ocsd_ptm_pkt *>(this) = *p_pkt;
+ return *this;
+}
+
+void PtmTrcPacket::Clear()
+{
+ err_type = PTM_PKT_NOERROR;
+ cycle_count = 0;
+ cc_valid = 0;
+ context.updated = 0;
+ context.updated_c = 0;
+ context.updated_v = 0;
+ ts_update_bits = 0;
+ atom.En_bits = 0;
+ exception.bits.present = 0;
+ prev_isa = curr_isa; // mark ISA as not changed
+}
+
+void PtmTrcPacket::ResetState()
+{
+ type = PTM_PKT_NOTSYNC;
+
+ context.ctxtID = 0;
+ context.VMID = 0;
+ context.curr_alt_isa = 0;
+ context.curr_Hyp = 0;
+ context.curr_NS = 0;
+
+ addr.valid_bits = 0;
+ addr.size = VA_32BIT;
+ addr.val = 0;
+
+ prev_isa = curr_isa = ocsd_isa_unknown;
+
+ timestamp = 0;
+
+ Clear();
+}
+
+void PtmTrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits)
+{
+ ocsd_vaddr_t validMask = OCSD_VA_MASK;
+ validMask >>= OCSD_MAX_VA_BITSIZE-updateBits;
+ addr.pkt_bits = updateBits;
+ addr.val &= ~validMask;
+ addr.val |= (partAddrVal & validMask);
+ if(updateBits > addr.valid_bits)
+ addr.valid_bits = updateBits;
+}
+
+void PtmTrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits)
+{
+ uint64_t validMask = ~0ULL;
+ validMask >>= 64-updateBits;
+ timestamp &= ~validMask;
+ timestamp |= (tsVal & validMask);
+ ts_update_bits = updateBits;
+}
+
+void PtmTrcPacket::SetCycleAccAtomFromPHdr(const uint8_t pHdr)
+{
+ atom.num = 1;
+ atom.En_bits = (pHdr & 0x2) ? 0x0 : 0x1;
+}
+
+void PtmTrcPacket::SetAtomFromPHdr(const uint8_t pHdr)
+{
+ // how many atoms
+ uint8_t atom_fmt_id = pHdr & 0xF0;
+ if(atom_fmt_id == 0x80)
+ {
+ // format 1 or 2
+ if((pHdr & 0x08) == 0x08)
+ atom.num = 2;
+ else
+ atom.num = 1;
+ }
+ else if(atom_fmt_id == 0x90)
+ {
+ atom.num = 3;
+ }
+ else
+ {
+ if((pHdr & 0xE0) == 0xA0)
+ atom.num = 4;
+ else
+ atom.num = 5;
+ }
+
+ // extract the E/N bits
+ uint8_t atom_mask = 0x2; // start @ bit 1 - newest instruction
+ atom.En_bits = 0;
+ for(int i = 0; i < atom.num; i++)
+ {
+ atom.En_bits <<= 1;
+ if(!(atom_mask & pHdr)) // 0 bit is an E in PTM -> a one in the standard atom bit type
+ atom.En_bits |= 0x1;
+ atom_mask <<= 1;
+ }
+}
+
+ // printing
+void PtmTrcPacket::toString(std::string &str) const
+{
+ std::string temp1, temp2;
+ std::ostringstream oss;
+
+ packetTypeName(type, temp1,temp2);
+ oss << temp1 << " : " << temp2 << "; ";
+
+ // some packets require additional data.
+ switch(type)
+ {
+ case PTM_PKT_BAD_SEQUENCE:
+ packetTypeName(err_type, temp1,temp2);
+ oss << "[" << temp1 << "]; ";
+ break;
+
+ case PTM_PKT_ATOM:
+ getAtomStr(temp1);
+ oss << temp1;
+ break;
+
+ case PTM_PKT_CONTEXT_ID:
+ oss << "CtxtID=0x" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; ";
+ break;
+
+ case PTM_PKT_VMID:
+ oss << "VMID=0x" << std::hex << std::setw(2) << std::setfill('0') << context.VMID << "; ";
+ break;
+
+ case PTM_PKT_WPOINT_UPDATE:
+ case PTM_PKT_BRANCH_ADDRESS:
+ getBranchAddressStr(temp1);
+ oss << temp1;
+ break;
+
+ case PTM_PKT_I_SYNC:
+ getISyncStr(temp1);
+ oss << temp1;
+ break;
+
+ case PTM_PKT_TIMESTAMP:
+ getTSStr(temp1);
+ oss << temp1;
+ break;
+ }
+
+ str = oss.str();
+}
+
+void PtmTrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const
+{
+ toString(str);
+}
+
+void PtmTrcPacket::getAtomStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ uint32_t bitpattern = atom.En_bits; // arranged LSBit oldest, MSbit newest
+
+ if(cc_valid) // cycle accurate trace - single atom
+ {
+ std::string subStr;
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ oss << "; ";
+ getCycleCountStr(subStr);
+ oss << subStr;
+ }
+ else
+ {
+ // none cycle count
+ for(int i = 0; i < atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ bitpattern >>= 1;
+ }
+ oss << "; ";
+ }
+ valStr = oss.str();
+}
+
+void PtmTrcPacket::getBranchAddressStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ std::string subStr;
+
+ // print address.
+ trcPrintableElem::getValStr(subStr,32,addr.valid_bits,addr.val,true,addr.pkt_bits);
+ oss << "Addr=" << subStr << "; ";
+
+ // current ISA if changed.
+ if(curr_isa != prev_isa)
+ {
+ getISAStr(subStr);
+ oss << subStr;
+ }
+
+ // S / NS etc if changed.
+ if(context.updated)
+ {
+ oss << (context.curr_NS ? "NS; " : "S; ");
+ oss << (context.curr_Hyp ? "Hyp; " : "");
+ }
+
+ // exception?
+ if(exception.bits.present)
+ {
+ getExcepStr(subStr);
+ oss << subStr;
+ }
+
+ if(cc_valid)
+ {
+ getCycleCountStr(subStr);
+ oss << subStr;
+ }
+ valStr = oss.str();
+}
+
+void PtmTrcPacket::getISAStr(std::string &isaStr) const
+{
+ std::ostringstream oss;
+ oss << "ISA=";
+ switch(curr_isa)
+ {
+ case ocsd_isa_arm:
+ oss << "ARM(32); ";
+ break;
+
+ case ocsd_isa_thumb2:
+ oss << "Thumb2; ";
+ break;
+
+ case ocsd_isa_aarch64:
+ oss << "AArch64; ";
+ break;
+
+ case ocsd_isa_tee:
+ oss << "ThumbEE; ";
+ break;
+
+ case ocsd_isa_jazelle:
+ oss << "Jazelle; ";
+ break;
+
+ default:
+ case ocsd_isa_unknown:
+ oss << "Unknown; ";
+ break;
+ }
+ isaStr = oss.str();
+}
+
+void PtmTrcPacket::getExcepStr(std::string &excepStr) const
+{
+ static const char *ARv7Excep[] = {
+ "No Exception", "Debug Halt", "SMC", "Hyp",
+ "Async Data Abort", "Jazelle", "Reserved", "Reserved",
+ "PE Reset", "Undefined Instr", "SVC", "Prefetch Abort",
+ "Data Fault", "Generic", "IRQ", "FIQ"
+ };
+
+ std::ostringstream oss;
+ oss << "Excep=";
+ if(exception.number < 16)
+ oss << ARv7Excep[exception.number];
+ else
+ oss << "Unknown";
+ oss << " [" << std::hex << std::setw(2) << std::setfill('0') << exception.number << "]; ";
+ excepStr = oss.str();
+}
+
+void PtmTrcPacket::getISyncStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ std::string tmpStr;
+ static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" };
+
+ // reason.
+ oss << "(" << reason[(int)i_sync_reason] << "); ";
+
+ // full address.
+ oss << "Addr=0x" << std::hex << std::setfill('0') << std::setw(8) << (uint32_t)addr.val << "; ";
+
+ oss << (context.curr_NS ? "NS; " : "S; ");
+ oss << (context.curr_Hyp ? "Hyp; " : " ");
+
+ if(context.updated_c)
+ {
+ oss << "CtxtID=" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; ";
+ }
+
+ getISAStr(tmpStr);
+ oss << tmpStr;
+
+ if(cc_valid)
+ {
+ getCycleCountStr(tmpStr);
+ oss << tmpStr;
+ }
+ valStr = oss.str();
+}
+
+void PtmTrcPacket::getTSStr(std::string &valStr) const
+{
+ std::string tmpStr;
+ std::ostringstream oss;
+
+ trcPrintableElem::getValStr(tmpStr,64,64,timestamp,true,ts_update_bits);
+ oss << "TS=" << tmpStr + "(" << std::dec << timestamp << "); ";
+ if(cc_valid)
+ {
+ getCycleCountStr(tmpStr);
+ oss << tmpStr;
+ }
+ valStr = oss.str();
+}
+
+
+void PtmTrcPacket::getCycleCountStr(std::string &subStr) const
+{
+ std::ostringstream oss;
+ oss << "Cycles=" << std::dec << cycle_count << "; ";
+ subStr = oss.str();
+}
+
+
+void PtmTrcPacket::packetTypeName(const ocsd_ptm_pkt_type pkt_type, std::string &name, std::string &desc) const
+{
+ switch(pkt_type)
+ {
+ case PTM_PKT_NOTSYNC: //!< no sync found yet
+ name = "NOTSYNC";
+ desc = "PTM Not Synchronised";
+ break;
+
+ case PTM_PKT_INCOMPLETE_EOT:
+ name = "INCOMPLETE_EOT";
+ desc = "Incomplete packet flushed at end of trace";
+ break;
+
+ case PTM_PKT_NOERROR:
+ name = "NO_ERROR";
+ desc = "Error type not set";
+ break;
+
+ case PTM_PKT_BAD_SEQUENCE:
+ name = "BAD_SEQUENCE";
+ desc = "Invalid sequence in packet";
+ break;
+
+ case PTM_PKT_RESERVED:
+ name = "RESERVED";
+ desc = "Reserved Packet Header";
+ break;
+
+ case PTM_PKT_BRANCH_ADDRESS:
+ name = "BRANCH_ADDRESS";
+ desc = "Branch address packet";
+ break;
+
+ case PTM_PKT_A_SYNC:
+ name = "ASYNC";
+ desc = "Alignment Synchronisation Packet";
+ break;
+
+ case PTM_PKT_I_SYNC:
+ name = "ISYNC";
+ desc = "Instruction Synchronisation packet";
+ break;
+
+ case PTM_PKT_TRIGGER:
+ name = "TRIGGER";
+ desc = "Trigger Event packet";
+ break;
+
+ case PTM_PKT_WPOINT_UPDATE:
+ name = "WP_UPDATE";
+ desc = "Waypoint update packet";
+ break;
+
+ case PTM_PKT_IGNORE:
+ name = "IGNORE";
+ desc = "Ignore packet";
+ break;
+
+ case PTM_PKT_CONTEXT_ID:
+ name = "CTXTID";
+ desc = "Context ID packet";
+ break;
+
+ case PTM_PKT_VMID:
+ name = "VMID";
+ desc = "VM ID packet";
+ break;
+
+ case PTM_PKT_ATOM:
+ name = "ATOM";
+ desc = "Atom packet";
+ break;
+
+ case PTM_PKT_TIMESTAMP:
+ name = "TIMESTAMP";
+ desc = "Timestamp packet";
+ break;
+
+ case PTM_PKT_EXCEPTION_RET:
+ name = "ERET";
+ desc = "Exception return packet";
+ break;
+
+ default:
+ name = "UNKNOWN";
+ desc = "Unknown packet type";
+ break;
+
+ //PTM_PKT_BRANCH_OR_BYPASS_EOT,
+ //PTM_PKT_TPIU_PAD_EOB,
+ }
+}
+
+/* End of File trc_pkt_elem_ptm.cpp */
diff --git a/decoder/source/ptm/trc_pkt_proc_ptm.cpp b/decoder/source/ptm/trc_pkt_proc_ptm.cpp
new file mode 100644
index 0000000..668a14b
--- /dev/null
+++ b/decoder/source/ptm/trc_pkt_proc_ptm.cpp
@@ -0,0 +1,1218 @@
+/*
+ * \file trc_pkt_proc_ptm.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opencsd/ptm/trc_pkt_proc_ptm.h"
+#include "opencsd/ptm/trc_cmp_cfg_ptm.h"
+#include "common/ocsd_error.h"
+
+
+#ifdef __GNUC__
+// G++ doesn't like the ## pasting
+#define PTM_PKTS_NAME "PKTP_PTM"
+#else
+// VC++ is OK
+#define PTM_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_PTM"
+#endif
+
+TrcPktProcPtm::TrcPktProcPtm() : TrcPktProcBase(PTM_PKTS_NAME)
+{
+ InitProcessorState();
+ BuildIPacketTable();
+}
+
+TrcPktProcPtm::TrcPktProcPtm(int instIDNum) : TrcPktProcBase(PTM_PKTS_NAME, instIDNum)
+{
+ InitProcessorState();
+ BuildIPacketTable();
+}
+
+TrcPktProcPtm::~TrcPktProcPtm()
+{
+
+}
+
+ocsd_err_t TrcPktProcPtm::onProtocolConfig()
+{
+ ocsd_err_t err = OCSD_ERR_NOT_INIT;
+
+ if(m_config != 0)
+ {
+ m_chanIDCopy = m_config->getTraceID();
+ err = OCSD_OK;
+ }
+ return err;
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::processData( const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ uint8_t currByte = 0;
+
+ m_dataInProcessed = 0;
+
+ if(!checkInit())
+ {
+ resp = OCSD_RESP_FATAL_NOT_INIT;
+ }
+ else
+ {
+ m_pDataIn = pDataBlock;
+ m_dataInLen = dataBlockSize;
+ m_block_idx = index; // index start for current block
+ }
+
+ while( ( ( m_dataInProcessed < dataBlockSize) ||
+ (( m_dataInProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) ) &&
+ OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ try
+ {
+ switch(m_process_state)
+ {
+ case WAIT_SYNC:
+ if(!m_waitASyncSOPkt)
+ {
+ m_curr_pkt_index = m_block_idx + m_dataInProcessed;
+ m_curr_packet.type = PTM_PKT_NOTSYNC;
+ m_bAsyncRawOp = hasRawMon();
+ }
+ resp = waitASync();
+ break;
+
+ case PROC_HDR:
+ m_curr_pkt_index = m_block_idx + m_dataInProcessed;
+ if(readByte(currByte))
+ {
+ m_pIPktFn = m_i_table[currByte].pptkFn;
+ m_curr_packet.type = m_i_table[currByte].pkt_type;
+ }
+ else
+ {
+ // sequencing error - should not get to the point where readByte
+ // fails and m_DataInProcessed < dataBlockSize
+ // throw data overflow error
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_PKT_INTERP_FAIL,m_curr_pkt_index,this->m_chanIDCopy,"Data Buffer Overrun");
+ }
+ m_process_state = PROC_DATA;
+
+ case PROC_DATA:
+ (this->*m_pIPktFn)();
+ break;
+
+ case SEND_PKT:
+ resp = outputPacket();
+ InitPacketState();
+ m_process_state = PROC_HDR;
+ break;
+ }
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) ||
+ (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR))
+ {
+ // send invalid packets up the pipe to let the next stage decide what to do.
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ // bail out on any other error.
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+ }
+ catch(...)
+ {
+ /// vv bad at this point.
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+ const ocsdError &fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_curr_pkt_index,m_chanIDCopy,"Unknown System Error decoding trace.");
+ LogError(fatal);
+ }
+
+ }
+ *numBytesProcessed = m_dataInProcessed;
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::onEOT()
+{
+ ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT;
+ if(checkInit())
+ {
+ err = OCSD_RESP_CONT;
+ if(m_currPacketData.size() > 0)
+ {
+ m_curr_packet.SetErrType(PTM_PKT_INCOMPLETE_EOT);
+ err = outputPacket();
+ }
+ }
+ return err;
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::onReset()
+{
+ ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT;
+ if(checkInit())
+ {
+ InitProcessorState();
+ err = OCSD_RESP_CONT;
+ }
+ return err;
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::onFlush()
+{
+ ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT;
+ if(checkInit())
+ {
+ err = OCSD_RESP_CONT;
+ }
+ return err;
+}
+
+const bool TrcPktProcPtm::isBadPacket() const
+{
+ return m_curr_packet.isBadPacket();
+}
+
+void TrcPktProcPtm::InitPacketState()
+{
+ m_curr_packet.Clear();
+
+}
+
+void TrcPktProcPtm::InitProcessorState()
+{
+ m_curr_packet.SetType(PTM_PKT_NOTSYNC);
+ m_pIPktFn = &TrcPktProcPtm::pktReserved;
+ m_process_state = WAIT_SYNC;
+ m_async_0 = 0;
+ m_waitASyncSOPkt = false;
+ m_bAsyncRawOp = false;
+ m_bOPNotSyncPkt = false;
+ m_excepAltISA = 0;
+
+ m_curr_packet.ResetState();
+ InitPacketState();
+}
+
+const bool TrcPktProcPtm::readByte(uint8_t &currByte)
+{
+ bool bValidByte = false;
+
+ if(m_dataInProcessed < m_dataInLen)
+ {
+ currByte = m_pDataIn[m_dataInProcessed++];
+ m_currPacketData.push_back(currByte);
+ bValidByte = true;
+ }
+ return bValidByte;
+}
+
+void TrcPktProcPtm::unReadByte()
+{
+ m_dataInProcessed--;
+ m_currPacketData.pop_back();
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::outputPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ resp = outputOnAllInterfaces(m_curr_pkt_index,&m_curr_packet,&m_curr_packet.type,m_currPacketData);
+ m_currPacketData.clear();
+ return resp;
+}
+
+/*** sync and packet functions ***/
+ocsd_datapath_resp_t TrcPktProcPtm::waitASync()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ // looking for possible patterns in input buffer:-
+ // a) ASYNC @ start : 00 00 00 00 00 80
+ // b) unsync then async: xx xx xx xx xx xx xx xx 00 00 00 00 00 80
+ // c) unsync (may have 00) xx xx xx xx 00 xx xx 00 00 00 xx xx xx xx
+ // d) unsync then part async: xx xx xx xx xx xx xx xx xx xx xx 00 00 00
+ // e) unsync with prev part async [00 00 00] 00 xx xx xx xx xx xx xx xx [] = byte in previous input buffer
+
+ // bytes to read before throwing an unsynced packet
+ #define UNSYNC_PKT_MAX 16
+ static const uint8_t spare_zeros[] = { 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0 };
+
+ bool doScan = true;
+ bool bSendUnsyncedData = false;
+ bool bHaveASync = false;
+ int unsynced_bytes = 0;
+ int unsync_scan_block_start = 0;
+ int pktBytesOnEntry = m_currPacketData.size(); // did we have part of a potential async last time?
+
+ while(doScan && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ // may have spotted the start of an async
+ if(m_waitASyncSOPkt == true)
+ {
+ switch(findAsync())
+ {
+ case ASYNC:
+ case ASYNC_EXTRA_0:
+ m_process_state = SEND_PKT;
+ m_waitASyncSOPkt = false;
+ bSendUnsyncedData = true;
+ bHaveASync = true;
+ doScan = false;
+ break;
+
+ case THROW_0:
+ // remove a bunch of 0s
+ unsynced_bytes += ASYNC_PAD_0_LIMIT;
+ m_waitASyncSOPkt = false;
+ m_currPacketData.erase( m_currPacketData.begin(), m_currPacketData.begin()+ASYNC_PAD_0_LIMIT);
+ break;
+
+ case NOT_ASYNC:
+ unsynced_bytes += m_currPacketData.size();
+ m_waitASyncSOPkt = false;
+ m_currPacketData.clear();
+ break;
+
+ case ASYNC_INCOMPLETE:
+ bSendUnsyncedData = true;
+ doScan = false;
+ break;
+ }
+ }
+ else
+ {
+ if(m_pDataIn[m_dataInProcessed++] == 0x00)
+ {
+ m_waitASyncSOPkt = true;
+ m_currPacketData.push_back(0);
+ m_async_0 = 1;
+ }
+ else
+ {
+ unsynced_bytes++;
+ }
+ }
+
+ // may need to send some unsynced data here, either if we have enought to make it worthwhile,
+ // or are at the end of the buffer.
+ if(unsynced_bytes >= UNSYNC_PKT_MAX)
+ bSendUnsyncedData = true;
+
+ if(m_dataInProcessed == m_dataInLen)
+ {
+ bSendUnsyncedData = true;
+ doScan = false; // no more data available - stop the scan
+ }
+
+ // will send any unsynced data
+ if(bSendUnsyncedData && (unsynced_bytes > 0))
+ {
+ if(m_bAsyncRawOp)
+ {
+ // there were some 0's in the packet buyffer from the last pass that are no longer in the raw buffer,
+ // and these turned out not to be an async
+ if(pktBytesOnEntry)
+ {
+ outputRawPacketToMonitor(m_curr_pkt_index,&m_curr_packet,pktBytesOnEntry,spare_zeros);
+ m_curr_pkt_index += pktBytesOnEntry;
+ }
+ outputRawPacketToMonitor(m_curr_pkt_index,&m_curr_packet,unsynced_bytes,m_pDataIn+unsync_scan_block_start);
+ }
+ if (!m_bOPNotSyncPkt)
+ {
+ resp = outputDecodedPacket(m_curr_pkt_index, &m_curr_packet);
+ m_bOPNotSyncPkt = true;
+ }
+ unsync_scan_block_start += unsynced_bytes;
+ m_curr_pkt_index+= unsynced_bytes;
+ unsynced_bytes = 0;
+ bSendUnsyncedData = false;
+ }
+
+ // mark next packet as the ASYNC we are looking for.
+ if(bHaveASync)
+ m_curr_packet.SetType(PTM_PKT_A_SYNC);
+ }
+
+ return resp;
+}
+
+void TrcPktProcPtm::pktASync()
+{
+ if(m_currPacketData.size() == 1) // header byte
+ {
+ m_async_0 = 1;
+ }
+
+ switch(findAsync())
+ {
+ case ASYNC:
+ case ASYNC_EXTRA_0:
+ m_process_state = SEND_PKT;
+ break;
+
+ case THROW_0:
+ case NOT_ASYNC:
+ throwMalformedPacketErr("Bad Async packet");
+ break;
+
+ case ASYNC_INCOMPLETE:
+ break;
+
+ }
+}
+
+TrcPktProcPtm::async_result_t TrcPktProcPtm::findAsync()
+{
+ async_result_t async_res = NOT_ASYNC;
+ bool bFound = false; // found non-zero byte in sequence
+ bool bByteAvail = true;
+ uint8_t currByte;
+
+ while(!bFound && bByteAvail)
+ {
+ if(readByte(currByte))
+ {
+ if(currByte == 0x00)
+ {
+ m_async_0++;
+ if(m_async_0 >= (ASYNC_PAD_0_LIMIT + ASYNC_REQ_0))
+ {
+ bFound = true;
+ async_res = THROW_0;
+ }
+ }
+ else
+ {
+ if(currByte == 0x80)
+ {
+ if(m_async_0 == 5)
+ async_res = ASYNC;
+ else if(m_async_0 > 5)
+ async_res = ASYNC_EXTRA_0;
+ }
+ bFound = true;
+ }
+ }
+ else
+ {
+ bByteAvail = false;
+ async_res = ASYNC_INCOMPLETE;
+ }
+ }
+ return async_res;
+}
+
+void TrcPktProcPtm::pktISync()
+{
+ uint8_t currByte = 0;
+ int pktIndex = m_currPacketData.size() - 1;
+ bool bGotBytes = false, validByte = true;
+
+ if(pktIndex == 0)
+ {
+ m_numCtxtIDBytes = m_config->CtxtIDBytes();
+ m_gotCtxtIDBytes = 0;
+
+ // total bytes = 6 + ctxtID; (perhaps more later)
+ m_numPktBytesReq = 6 + m_numCtxtIDBytes;
+ }
+
+ while(validByte && !bGotBytes)
+ {
+ if(readByte(currByte))
+ {
+ pktIndex = m_currPacketData.size() - 1;
+ if(pktIndex == 5)
+ {
+ // got the info byte
+ int altISA = (currByte >> 2) & 0x1;
+ int reason = (currByte >> 5) & 0x3;
+ m_curr_packet.SetISyncReason((ocsd_iSync_reason)(reason));
+ m_curr_packet.UpdateNS((currByte >> 3) & 0x1);
+ m_curr_packet.UpdateAltISA((currByte >> 2) & 0x1);
+ m_curr_packet.UpdateHyp((currByte >> 1) & 0x1);
+
+ ocsd_isa isa = ocsd_isa_arm;
+ if(m_currPacketData[1] & 0x1)
+ isa = altISA ? ocsd_isa_tee : ocsd_isa_thumb2;
+ m_curr_packet.UpdateISA(isa);
+
+ // check cycle count required - not if reason == 0;
+ m_needCycleCount = (reason != 0) ? m_config->enaCycleAcc() : false;
+ m_gotCycleCount = false;
+ m_numPktBytesReq += (m_needCycleCount ? 1 : 0);
+ m_gotCCBytes = 0;
+
+ }
+ else if(pktIndex > 5)
+ {
+ // cycle count appears first if present
+ if(m_needCycleCount && !m_gotCycleCount)
+ {
+ if(pktIndex == 6)
+ m_gotCycleCount = (bool)((currByte & 0x40) == 0); // no cont bit, got cycle count
+ else
+ m_gotCycleCount = ((currByte & 0x80) == 0) || (pktIndex == 10);
+
+ m_gotCCBytes++; // count the cycle count bytes for later use.
+ if(!m_gotCycleCount) // need more cycle count bytes
+ m_numPktBytesReq++;
+ }
+ // then context ID if present.
+ else if( m_numCtxtIDBytes > m_gotCtxtIDBytes)
+ {
+ m_gotCtxtIDBytes++;
+ }
+ }
+
+ // check if we have enough bytes
+ bGotBytes = (bool)((unsigned)m_numPktBytesReq == m_currPacketData.size());
+ }
+ else
+ validByte = false; // no byte available, exit.
+ }
+
+ if(bGotBytes)
+ {
+ // extract address value, cycle count and ctxt id.
+ uint32_t cycleCount = 0;
+ uint32_t ctxtID = 0;
+ int optIdx = 6; // start index for optional elements.
+
+ // address is always full fixed 32 bit value
+ uint32_t address = ((uint32_t)m_currPacketData[1]) & 0xFE;
+ address |= ((uint32_t)m_currPacketData[2]) << 8;
+ address |= ((uint32_t)m_currPacketData[3]) << 16;
+ address |= ((uint32_t)m_currPacketData[4]) << 24;
+ m_curr_packet.UpdateAddress(address,32);
+
+ if(m_needCycleCount)
+ {
+ extractCycleCount(optIdx,cycleCount);
+ m_curr_packet.SetCycleCount(cycleCount);
+ optIdx+=m_gotCCBytes;
+ }
+
+ if(m_numCtxtIDBytes)
+ {
+ extractCtxtID(optIdx,ctxtID);
+ m_curr_packet.UpdateContextID(ctxtID);
+ }
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktTrigger()
+{
+ m_process_state = SEND_PKT; // no payload
+}
+
+void TrcPktProcPtm::pktWPointUpdate()
+{
+ bool bDone = false;
+ bool bBytesAvail = true;
+ uint8_t currByte = 0;
+ int byteIdx = 0;
+
+ if(m_currPacketData.size() == 1)
+ {
+ m_gotAddrBytes = false; // flag to indicate got all needed address bytes
+ m_numAddrBytes = 0; // number of address bytes so far - in this case header is not part of the address
+
+ m_gotExcepBytes = false; // mark as not got all required exception bytes thus far
+ m_numExcepBytes = 0; // 0 read in
+
+ m_addrPktIsa = ocsd_isa_unknown; // not set by this packet as yet
+ }
+
+ // collect all the bytes needed
+ while(!bDone && bBytesAvail)
+ {
+ if(readByte(currByte))
+ {
+
+ byteIdx = m_currPacketData.size() - 1;
+ if(!m_gotAddrBytes)
+ {
+ // byteIdx for address byte will run from 1 to 5 - first 4 my have continuation or not.
+ if(byteIdx <= 4)
+ {
+ // address bytes 1 - 4;
+ // ISA stays the same
+ if((currByte & 0x80) == 0x00)
+ {
+ // no further bytes
+ m_gotAddrBytes = true;
+ bDone = true;
+ m_gotExcepBytes = true;
+ }
+ }
+ else
+ {
+ // 5th address byte - determine ISA from this.
+ if((currByte & 0x40) == 0x00)
+ m_gotExcepBytes = true; // no exception bytes - mark as done
+ m_gotAddrBytes = true;
+ bDone = m_gotExcepBytes;
+
+ m_addrPktIsa = ocsd_isa_arm; // assume ARM, but then check
+ if((currByte & 0x20) == 0x20) // bit 5 == 1'b1 - jazelle, bits 4 & 3 part of address.
+ m_addrPktIsa = ocsd_isa_jazelle;
+ else if((currByte & 0x30) == 0x10) // bit [5:4] == 2'b01 - thumb, bit 3 part of address.
+ m_addrPktIsa = ocsd_isa_thumb2;
+ }
+ m_numAddrBytes++;
+ }
+ else if(!m_gotExcepBytes)
+ {
+ // excep byte is actually a WP update byte.
+ m_excepAltISA = ((currByte & 0x40) == 0x40) ? 1 : 0;
+ m_gotExcepBytes = true;
+ m_numExcepBytes++;
+ bDone = true;
+ }
+ }
+ else
+ bBytesAvail = false;
+ }
+
+ // analyse the bytes to create the packet
+ if(bDone)
+ {
+ // ISA for the packet
+ if(m_addrPktIsa == ocsd_isa_unknown) // unchanged by trace packet
+ m_addrPktIsa = m_curr_packet.getISA(); // same as prev
+
+ if(m_gotExcepBytes) // may adjust according to alt ISA in exception packet
+ {
+ if((m_addrPktIsa == ocsd_isa_tee) && (m_excepAltISA == 0))
+ m_addrPktIsa = ocsd_isa_thumb2;
+ else if((m_addrPktIsa == ocsd_isa_thumb2) && (m_excepAltISA == 1))
+ m_addrPktIsa = ocsd_isa_tee;
+ }
+ m_curr_packet.UpdateISA(m_addrPktIsa); // mark ISA in packet (update changes current and prev to dectect an ISA change).
+
+ uint8_t total_bits = 0;
+ uint32_t addr_val = extractAddress(1,total_bits);
+ m_curr_packet.UpdateAddress(addr_val,total_bits);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktIgnore()
+{
+ m_process_state = SEND_PKT; // no payload
+}
+
+void TrcPktProcPtm::pktCtxtID()
+{
+ int pktIndex = m_currPacketData.size() - 1;
+
+ // if at the header, determine how many more bytes we need.
+ if(pktIndex == 0)
+ {
+ m_numCtxtIDBytes = m_config->CtxtIDBytes();
+ m_gotCtxtIDBytes = 0;
+ }
+
+ // read the necessary ctxtID bytes from the stream
+ bool bGotBytes = false, bytesAvail = true;
+ uint32_t ctxtID = 0;
+
+ bGotBytes = m_numCtxtIDBytes == m_gotCtxtIDBytes;
+ while(!bGotBytes & bytesAvail)
+ {
+ bytesAvail = readByte();
+ if(bytesAvail)
+ m_gotCtxtIDBytes++;
+ bGotBytes = m_numCtxtIDBytes == m_gotCtxtIDBytes;
+ }
+
+ if(bGotBytes)
+ {
+ if(m_numCtxtIDBytes)
+ {
+ extractCtxtID(1,ctxtID);
+ }
+ m_curr_packet.UpdateContextID(ctxtID);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktVMID()
+{
+ uint8_t currByte;
+
+ // just need a single payload byte...
+ if(readByte(currByte))
+ {
+ m_curr_packet.UpdateVMID(currByte);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktAtom()
+{
+ uint8_t pHdr = m_currPacketData[0];
+
+ if(!m_config->enaCycleAcc())
+ {
+ m_curr_packet.SetAtomFromPHdr(pHdr);
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ bool bGotAllPktBytes = false, byteAvail = true;
+ uint8_t currByte = 0; // cycle accurate tracing -> atom + cycle count
+
+ if(!(pHdr & 0x40))
+ {
+ // only the header byte present
+ bGotAllPktBytes = true;
+ }
+ else
+ {
+ // up to 4 additional bytes of count data.
+ while(byteAvail && !bGotAllPktBytes)
+ {
+ if(readByte(currByte))
+ {
+ if(!(currByte & 0x80) || (m_currPacketData.size() == 5))
+ bGotAllPktBytes = true;
+ }
+ else
+ byteAvail = false;
+ }
+ }
+
+ // we have all the bytes for a cycle accurate packet.
+ if(bGotAllPktBytes)
+ {
+ uint32_t cycleCount = 0;
+ extractCycleCount(0,cycleCount);
+ m_curr_packet.SetCycleCount(cycleCount);
+ m_curr_packet.SetCycleAccAtomFromPHdr(pHdr);
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcPtm::pktTimeStamp()
+{
+ uint8_t currByte = 0;
+ int pktIndex = m_currPacketData.size() - 1;
+ bool bGotBytes = false, byteAvail = true;
+
+ if(pktIndex == 0)
+ {
+ m_gotTSBytes = false;
+ m_needCycleCount = m_config->enaCycleAcc();
+ m_gotCCBytes = 0;
+
+ // max byte buffer size for full ts packet
+ m_tsByteMax = m_config->TSPkt64() ? 10 : 8;
+ }
+
+ while(byteAvail && !bGotBytes)
+ {
+ if(readByte(currByte))
+ {
+ if(!m_gotTSBytes)
+ {
+ if(((currByte & 0x80) == 0) || (m_currPacketData.size() == (unsigned)m_tsByteMax))
+ {
+ m_gotTSBytes = true;
+ if(!m_needCycleCount)
+ bGotBytes = true;
+ }
+ }
+ else
+ {
+ uint8_t cc_cont_mask = 0x80;
+ // got TS bytes, collect cycle count
+ if(m_gotCCBytes == 0)
+ cc_cont_mask = 0x40;
+ if((currByte & cc_cont_mask) == 0)
+ bGotBytes = true;
+ m_gotCCBytes++;
+ if(m_gotCCBytes == 5)
+ bGotBytes = true;
+ }
+ }
+ else
+ byteAvail = false;
+ }
+
+ if(bGotBytes)
+ {
+ uint64_t tsVal = 0;
+ uint32_t cycleCount = 0;
+ uint8_t tsUpdateBits = 0;
+ int ts_end_idx = extractTS(tsVal,tsUpdateBits);
+ if(m_needCycleCount)
+ {
+ extractCycleCount(ts_end_idx,cycleCount);
+ m_curr_packet.SetCycleCount(cycleCount);
+ }
+ m_curr_packet.UpdateTimestamp(tsVal,tsUpdateBits);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktExceptionRet()
+{
+ m_process_state = SEND_PKT; // no payload
+}
+
+void TrcPktProcPtm::pktBranchAddr()
+{
+ uint8_t currByte = m_currPacketData[0];
+ bool bDone = false;
+ bool bBytesAvail = true;
+ int byteIdx = 0;
+
+ if(m_currPacketData.size() == 1)
+ {
+ m_gotAddrBytes = false; // flag to indicate got all needed address bytes
+ m_numAddrBytes = 1; // number of address bytes so far
+
+ m_needCycleCount = m_config->enaCycleAcc(); // check if we have a cycle count
+ m_gotCCBytes = 0; // number of cc bytes read in so far.
+
+ m_gotExcepBytes = false; // mark as not got all required exception bytes thus far
+ m_numExcepBytes = 0; // 0 read in
+
+ m_addrPktIsa = ocsd_isa_unknown; // not set by this packet as yet
+
+ // header is also 1st address byte
+ if((currByte & 0x80) == 0) // could be single byte packet
+ {
+ m_gotAddrBytes = true;
+ if(!m_needCycleCount)
+ bDone = true; // all done if no cycle count
+ m_gotExcepBytes = true; // cannot have exception bytes following single byte packet
+ }
+
+ }
+
+ // collect all the bytes needed
+ while(!bDone && bBytesAvail)
+ {
+ if(readByte(currByte))
+ {
+ byteIdx = m_currPacketData.size() - 1;
+ if(!m_gotAddrBytes)
+ {
+ if(byteIdx < 4)
+ {
+ // address bytes 2 - 4;
+ // ISA stays the same
+ if((currByte & 0x80) == 0x00)
+ {
+ // no further bytes
+ if((currByte & 0x40) == 0x00)
+ m_gotExcepBytes = true; // no exception bytes - mark as done
+ m_gotAddrBytes = true;
+ bDone = m_gotExcepBytes && !m_needCycleCount;
+ }
+ }
+ else
+ {
+ // 5th address byte - determine ISA from this.
+ if((currByte & 0x40) == 0x00)
+ m_gotExcepBytes = true; // no exception bytes - mark as done
+ m_gotAddrBytes = true;
+ bDone = m_gotExcepBytes && !m_needCycleCount;
+
+ m_addrPktIsa = ocsd_isa_arm; // assume ARM, but then check
+ if((currByte & 0x20) == 0x20) // bit 5 == 1'b1 - jazelle, bits 4 & 3 part of address.
+ m_addrPktIsa = ocsd_isa_jazelle;
+ else if((currByte & 0x30) == 0x10) // bit [5:4] == 2'b01 - thumb, bit 3 part of address.
+ m_addrPktIsa = ocsd_isa_thumb2;
+ }
+ m_numAddrBytes++;
+ }
+ else if(!m_gotExcepBytes)
+ {
+ // may need exception bytes
+ if(m_numExcepBytes == 0)
+ {
+ if((currByte & 0x80) == 0x00)
+ m_gotExcepBytes = true;
+ m_excepAltISA = ((currByte & 0x40) == 0x40) ? 1 : 0;
+ }
+ else
+ m_gotExcepBytes = true;
+ m_numExcepBytes++;
+
+ if(m_gotExcepBytes && !m_needCycleCount)
+ bDone = true;
+
+ }
+ else if(m_needCycleCount)
+ {
+ // not done after exception bytes, collect cycle count
+ if(m_gotCCBytes == 0)
+ {
+ bDone = ((currByte & 0x40) == 0x00 );
+ }
+ else
+ {
+ // done if no more or 5th byte
+ bDone = (((currByte & 0x80) == 0x00 ) || (m_gotCCBytes == 4));
+ }
+ m_gotCCBytes++;
+ }
+ else
+ // this should never be reached.
+ throwMalformedPacketErr("sequencing error analysing branch packet");
+ }
+ else
+ bBytesAvail = false;
+ }
+
+ // analyse the bytes to create the packet
+ if(bDone)
+ {
+ // ISA for the packet
+ if(m_addrPktIsa == ocsd_isa_unknown) // unchanged by trace packet
+ m_addrPktIsa = m_curr_packet.getISA(); // same as prev
+
+ if(m_gotExcepBytes) // may adjust according to alt ISA in exception packet
+ {
+ if((m_addrPktIsa == ocsd_isa_tee) && (m_excepAltISA == 0))
+ m_addrPktIsa = ocsd_isa_thumb2;
+ else if((m_addrPktIsa == ocsd_isa_thumb2) && (m_excepAltISA == 1))
+ m_addrPktIsa = ocsd_isa_tee;
+ }
+ m_curr_packet.UpdateISA(m_addrPktIsa); // mark ISA in packet (update changes current and prev to dectect an ISA change).
+
+
+
+ // we know the ISA, we can correctly interpret the address.
+ uint8_t total_bits = 0;
+ uint32_t addr_val = extractAddress(0,total_bits);
+ m_curr_packet.UpdateAddress(addr_val,total_bits);
+
+ if(m_numExcepBytes > 0)
+ {
+ uint8_t E1 = m_currPacketData[m_numAddrBytes];
+ uint16_t ENum = (E1 >> 1) & 0xF;
+ ocsd_armv7_exception excep = Excp_Reserved;
+
+ m_curr_packet.UpdateNS(E1 & 0x1);
+ if(m_numExcepBytes > 1)
+ {
+ uint8_t E2 = m_currPacketData[m_numAddrBytes+1];
+ m_curr_packet.UpdateHyp((E2 >> 5) & 0x1);
+ ENum |= ((uint16_t)(E2 & 0x1F) << 4);
+ }
+
+ if(ENum <= 0xF)
+ {
+ static ocsd_armv7_exception v7ARExceptions[16] = {
+ Excp_NoException, Excp_DebugHalt, Excp_SMC, Excp_Hyp,
+ Excp_AsyncDAbort, Excp_ThumbEECheckFail, Excp_Reserved, Excp_Reserved,
+ Excp_Reset, Excp_Undef, Excp_SVC, Excp_PrefAbort,
+ Excp_SyncDataAbort, Excp_Generic, Excp_IRQ, Excp_FIQ
+ };
+ excep = v7ARExceptions[ENum];
+ }
+ m_curr_packet.SetException(excep,ENum);
+ }
+
+ if(m_needCycleCount)
+ {
+ int countIdx = m_numAddrBytes + m_numExcepBytes;
+ uint32_t cycleCount = 0;
+ extractCycleCount(countIdx,cycleCount);
+ m_curr_packet.SetCycleCount(cycleCount);
+ }
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktReserved()
+{
+ m_process_state = SEND_PKT; // no payload
+}
+
+void TrcPktProcPtm::extractCtxtID(int idx, uint32_t &ctxtID)
+{
+ ctxtID = 0;
+ int shift = 0;
+ for(int i=0; i < m_numCtxtIDBytes; i++)
+ {
+ if((size_t)idx+i >= m_currPacketData.size())
+ throwMalformedPacketErr("Insufficient packet bytes for Context ID value.");
+ ctxtID |= ((uint32_t)m_currPacketData[idx+i]) << shift;
+ shift+=8;
+ }
+}
+
+void TrcPktProcPtm::extractCycleCount(int offset, uint32_t &cycleCount)
+{
+ bool bCont = true;
+ cycleCount = 0;
+ int by_idx = 0;
+ uint8_t currByte;
+ int shift = 4;
+
+ while(bCont)
+ {
+ if((size_t)by_idx+offset >= m_currPacketData.size())
+ throwMalformedPacketErr("Insufficient packet bytes for Cycle Count value.");
+
+ currByte = m_currPacketData[offset+by_idx];
+ if(by_idx == 0)
+ {
+ bCont = (currByte & 0x40) != 0;
+ cycleCount = (currByte >> 2) & 0xF;
+ }
+ else
+ {
+
+ bCont = (currByte & 0x80) != 0;
+ if(by_idx == 4)
+ bCont = false;
+ cycleCount |= (((uint32_t)(currByte & 0x7F)) << shift);
+ shift += 7;
+ }
+ by_idx++;
+ }
+}
+
+int TrcPktProcPtm::extractTS(uint64_t &tsVal,uint8_t &tsUpdateBits)
+{
+ bool bCont = true;
+ int tsIdx = 1; // start index;
+ uint8_t byteVal;
+ bool b64BitVal = m_config->TSPkt64();
+ int shift = 0;
+
+ tsVal = 0;
+ tsUpdateBits = 0;
+
+ while(bCont)
+ {
+ if((size_t)tsIdx >= m_currPacketData.size())
+ throwMalformedPacketErr("Insufficient packet bytes for Timestamp value.");
+
+ byteVal = m_currPacketData[tsIdx];
+
+ if(b64BitVal)
+ {
+ if(tsIdx < 9)
+ {
+ bCont = ((byteVal & 0x80) == 0x80);
+ byteVal &= 0x7F;
+ tsUpdateBits += 7;
+ }
+ else
+ {
+ bCont = false;
+ tsUpdateBits += 8;
+ }
+ }
+ else
+ {
+ if(tsIdx < 7)
+ {
+ bCont = ((byteVal & 0x80) == 0x80);
+ byteVal &= 0x7F;
+ tsUpdateBits += 7;
+ }
+ else
+ {
+ byteVal &=0x3F;
+ bCont = false;
+ tsUpdateBits += 6;
+ }
+ }
+ tsVal |= (((uint64_t)byteVal) << shift);
+ tsIdx++;
+ shift += 7;
+ }
+ return tsIdx; // return next byte index in packet.
+}
+
+uint32_t TrcPktProcPtm::extractAddress(const int offset, uint8_t &total_bits)
+{
+ // we know the ISA, we can correctly interpret the address.
+ uint32_t addr_val = 0;
+ uint8_t mask = 0x7E; // first byte mask (always);
+ uint8_t num_bits = 0x7; // number of bits in the 1st byte (thumb);
+ int shift = 0;
+ int next_shift = 0;
+
+ total_bits = 0;
+
+ for(int i = 0; i < m_numAddrBytes; i++)
+ {
+ if(i == 4)
+ {
+ // 5th byte mask
+ mask = 0x0f; // thumb mask;
+ num_bits = 4;
+ if(m_addrPktIsa == ocsd_isa_jazelle)
+ {
+ mask = 0x1F;
+ num_bits = 5;
+ }
+ else if(m_addrPktIsa == ocsd_isa_arm)
+ {
+ mask = 0x07;
+ num_bits = 3;
+ }
+ }
+ else if(i > 0)
+ {
+ mask = 0x7F;
+ num_bits = 7;
+ // check for last byte but not 1st or 5th byte mask
+ if(i == m_numAddrBytes-1)
+ {
+ mask = 0x3F;
+ num_bits = 6;
+ }
+ }
+
+ // extract data
+ shift = next_shift;
+ addr_val |= ((uint32_t)(m_currPacketData[i+offset] & mask) << shift);
+ total_bits += num_bits;
+
+ // how much we shift the next value
+ if(i == 0)
+ {
+ if(m_addrPktIsa == ocsd_isa_jazelle)
+ {
+ addr_val >>= 1;
+ next_shift = 6;
+ total_bits--; // adjust bits for jazelle offset
+ }
+ else
+ {
+ next_shift = 7;
+ }
+ }
+ else
+ {
+ next_shift += 7;
+ }
+ }
+
+ if(m_addrPktIsa == ocsd_isa_arm)
+ {
+ addr_val <<= 1; // shift one extra bit for ARM address alignment.
+ total_bits++;
+ }
+ return addr_val;
+}
+
+
+void TrcPktProcPtm::BuildIPacketTable()
+{
+ // initialise all to branch, atom or reserved packet header
+ for(unsigned i = 0; i < 256; i++)
+ {
+ // branch address packets all end in 8'bxxxxxxx1
+ if((i & 0x01) == 0x01)
+ {
+ m_i_table[i].pkt_type = PTM_PKT_BRANCH_ADDRESS;
+ m_i_table[i].pptkFn = &TrcPktProcPtm::pktBranchAddr;
+ }
+ // atom packets are 8'b1xxxxxx0
+ else if((i & 0x81) == 0x80)
+ {
+ m_i_table[i].pkt_type = PTM_PKT_ATOM;
+ m_i_table[i].pptkFn = &TrcPktProcPtm::pktAtom;
+ }
+ else
+ {
+ // set all the others to reserved for now
+ m_i_table[i].pkt_type = PTM_PKT_RESERVED;
+ m_i_table[i].pptkFn = &TrcPktProcPtm::pktReserved;
+ }
+ }
+
+ // pick out the other packet types by individual codes.
+
+ // A-sync 8'b00000000
+ m_i_table[0x00].pkt_type = PTM_PKT_A_SYNC;
+ m_i_table[0x00].pptkFn = &TrcPktProcPtm::pktASync;
+
+ // I-sync 8'b00001000
+ m_i_table[0x08].pkt_type = PTM_PKT_I_SYNC;
+ m_i_table[0x08].pptkFn = &TrcPktProcPtm::pktISync;
+
+ // waypoint update 8'b01110010
+ m_i_table[0x72].pkt_type = PTM_PKT_WPOINT_UPDATE;
+ m_i_table[0x72].pptkFn = &TrcPktProcPtm::pktWPointUpdate;
+
+ // trigger 8'b00001100
+ m_i_table[0x0C].pkt_type = PTM_PKT_TRIGGER;
+ m_i_table[0x0C].pptkFn = &TrcPktProcPtm::pktTrigger;
+
+ // context ID 8'b01101110
+ m_i_table[0x6E].pkt_type = PTM_PKT_CONTEXT_ID;
+ m_i_table[0x6E].pptkFn = &TrcPktProcPtm::pktCtxtID;
+
+ // VMID 8'b00111100
+ m_i_table[0x3C].pkt_type = PTM_PKT_VMID;
+ m_i_table[0x3C].pptkFn = &TrcPktProcPtm::pktVMID;
+
+ // Timestamp 8'b01000x10
+ m_i_table[0x42].pkt_type = PTM_PKT_TIMESTAMP;
+ m_i_table[0x42].pptkFn = &TrcPktProcPtm::pktTimeStamp;
+ m_i_table[0x46].pkt_type = PTM_PKT_TIMESTAMP;
+ m_i_table[0x46].pptkFn = &TrcPktProcPtm::pktTimeStamp;
+
+ // Exception return 8'b01110110
+ m_i_table[0x76].pkt_type = PTM_PKT_EXCEPTION_RET;
+ m_i_table[0x76].pptkFn = &TrcPktProcPtm::pktExceptionRet;
+
+ // Ignore 8'b01100110
+ m_i_table[0x66].pkt_type = PTM_PKT_IGNORE;
+ m_i_table[0x66].pptkFn = &TrcPktProcPtm::pktIgnore;
+}
+
+/* End of File trc_pkt_proc_ptm.cpp */
diff --git a/decoder/source/stm/trc_pkt_decode_stm.cpp b/decoder/source/stm/trc_pkt_decode_stm.cpp
new file mode 100644
index 0000000..1bb8d73
--- /dev/null
+++ b/decoder/source/stm/trc_pkt_decode_stm.cpp
@@ -0,0 +1,303 @@
+/*
+ * \file trc_pkt_decode_stm.cpp
+ * \brief OpenCSD : STM packet decoder - output generic SW trace packets.
+ *
+ * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opencsd/stm/trc_pkt_decode_stm.h"
+#define DCD_NAME "DCD_STM"
+
+TrcPktDecodeStm::TrcPktDecodeStm()
+ : TrcPktDecodeBase(DCD_NAME)
+{
+ initDecoder();
+}
+
+TrcPktDecodeStm::TrcPktDecodeStm(int instIDNum)
+ : TrcPktDecodeBase(DCD_NAME, instIDNum)
+{
+ initDecoder();
+}
+
+TrcPktDecodeStm::~TrcPktDecodeStm()
+{
+ if(m_payload_buffer)
+ delete [] m_payload_buffer;
+ m_payload_buffer = 0;
+}
+
+/* implementation packet decoding interface */
+ocsd_datapath_resp_t TrcPktDecodeStm::processPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool bPktDone = false;
+
+ m_decode_pass1 = true;
+
+ while(!bPktDone)
+ {
+ switch(m_curr_state)
+ {
+ case NO_SYNC:
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC);
+ m_output_elem.setUnSyncEOTReason(m_unsync_info);
+ resp = outputTraceElement(m_output_elem);
+ m_curr_state = WAIT_SYNC;
+ break;
+
+ case WAIT_SYNC:
+ if(m_curr_packet_in->getPktType() == STM_PKT_ASYNC)
+ m_curr_state = DECODE_PKTS;
+ bPktDone = true;
+ break;
+
+ case DECODE_PKTS:
+ resp = decodePacket(bPktDone);
+ break;
+ }
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeStm::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE);
+ m_output_elem.setUnSyncEOTReason(UNSYNC_EOT);
+ resp = outputTraceElement(m_output_elem);
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeStm::onReset()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_unsync_info = UNSYNC_RESET_DECODER;
+ resetDecoder();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeStm::onFlush()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ // don't currently save unsent packets so nothing to flush
+ return resp;
+}
+
+ocsd_err_t TrcPktDecodeStm::onProtocolConfig()
+{
+ if(m_config == 0)
+ return OCSD_ERR_NOT_INIT;
+
+ // static config - copy of CSID for easy reference
+ m_CSID = m_config->getTraceID();
+ return OCSD_OK;
+}
+
+void TrcPktDecodeStm::initDecoder()
+{
+ m_payload_buffer = 0;
+ m_num_pkt_correlation = 1; // fixed at single packet payload correlation - add feature later
+ m_CSID = 0;
+
+ // base decoder state - STM requires no memory and instruction decode.
+ setUsesMemAccess(false);
+ setUsesIDecode(false);
+ m_unsync_info = UNSYNC_INIT_DECODER;
+ resetDecoder();
+}
+
+void TrcPktDecodeStm::resetDecoder()
+{
+ m_curr_state = NO_SYNC;
+ m_payload_size = 0;
+ m_payload_used = 0;
+ m_payload_odd_nibble = false;
+ m_output_elem.init();
+ m_swt_packet_info.swt_flag_bits = 0; // zero out everything
+ initPayloadBuffer();
+}
+
+void TrcPktDecodeStm::initPayloadBuffer()
+{
+ // set up the payload buffer. If we are correlating indentical packets then
+ // need a buffer that is a multiple of 64bit packets.
+ // otherwise a single packet length will do.
+ if(m_payload_buffer)
+ delete [] m_payload_buffer;
+ m_payload_buffer = new (std::nothrow) uint8_t[m_num_pkt_correlation * sizeof(uint64_t)];
+}
+
+ocsd_datapath_resp_t TrcPktDecodeStm::decodePacket(bool &bPktDone)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool bSendPacket = false; // flag to indicate output required.
+
+ bPktDone = true; // assume complete unless 2nd pass required.
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_SWTRACE);
+ clearSWTPerPcktInfo();
+
+ switch (m_curr_packet_in->getPktType())
+ {
+ case STM_PKT_BAD_SEQUENCE: /**< Incorrect protocol sequence */
+ case STM_PKT_RESERVED:
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ case STM_PKT_NOTSYNC:
+ resetDecoder();
+ break;
+
+ case STM_PKT_VERSION: /**< Version packet - not relevant to generic (versionless) o/p */
+ case STM_PKT_ASYNC: /**< Alignment synchronisation packet */
+ case STM_PKT_INCOMPLETE_EOT: /**< Incomplete packet flushed at end of trace. */
+ // no action required.
+ break;
+
+/* markers for valid packets*/
+ case STM_PKT_NULL: /**< Null packet */
+ if(m_curr_packet_in->isTSPkt())
+ bSendPacket = true; // forward NULL packet if associated timestamp.
+ break;
+
+ case STM_PKT_FREQ: /**< Frequency packet */
+ m_swt_packet_info.swt_frequency = 1;
+ updatePayload(bSendPacket);
+ break;
+
+ case STM_PKT_TRIG: /**< Trigger event packet. */
+ m_swt_packet_info.swt_trigger_event = 1;
+ updatePayload(bSendPacket);
+ break;
+
+ case STM_PKT_GERR: /**< Global error packet - protocol error but unknown which master had error */
+ m_swt_packet_info.swt_master_id = m_curr_packet_in->getMaster();
+ m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel();
+ m_swt_packet_info.swt_global_err = 1;
+ m_swt_packet_info.swt_id_valid = 0;
+ updatePayload(bSendPacket);
+ break;
+
+ case STM_PKT_MERR: /**< Master error packet - current master detected an error (e.g. dropped trace) */
+ m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel();
+ m_swt_packet_info.swt_master_err = 1;
+ updatePayload(bSendPacket);
+ break;
+
+ case STM_PKT_M8: /**< Set current master */
+ m_swt_packet_info.swt_master_id = m_curr_packet_in->getMaster();
+ m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); // forced to 0
+ m_swt_packet_info.swt_id_valid = 1;
+ break;
+
+ case STM_PKT_C8: /**< Set lower 8 bits of current channel - packet proc hadnles this */
+ case STM_PKT_C16: /**< Set current channel */
+ m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel();
+ break;
+
+ case STM_PKT_FLAG: /**< Flag packet */
+ m_swt_packet_info.swt_marker_packet = 1;
+ bSendPacket = true; // send 0 payload marker packet./
+ break;
+
+
+ case STM_PKT_D4: /**< 4 bit data payload packet */
+ case STM_PKT_D8: /**< 8 bit data payload packet */
+ case STM_PKT_D16: /**< 16 bit data payload packet */
+ case STM_PKT_D32: /**< 32 bit data payload packet */
+ case STM_PKT_D64: /**< 64 bit data payload packet */
+ updatePayload(bSendPacket);
+ break;
+
+ }
+
+ if(bSendPacket)
+ {
+ if(m_curr_packet_in->isTSPkt())
+ {
+ m_output_elem.setTS(m_curr_packet_in->getTSVal());
+ m_swt_packet_info.swt_has_timestamp = 1;
+ }
+ m_output_elem.setSWTInfo(m_swt_packet_info);
+ resp = outputTraceElement(m_output_elem);
+ }
+
+ return resp;
+}
+
+void TrcPktDecodeStm::clearSWTPerPcktInfo()
+{
+ m_swt_packet_info.swt_flag_bits &= (uint32_t)(0x0 | SWT_ID_VALID_MASK); // clear flags and current payload size (save id valid flag).
+}
+
+void TrcPktDecodeStm::updatePayload(bool &bSendPacket)
+{
+ // without buffering similar packets - this function is quite simple
+ bSendPacket = true;
+ m_swt_packet_info.swt_payload_num_packets = 1;
+
+ switch(m_curr_packet_in->getPktType())
+ {
+ case STM_PKT_D4: /**< 4 bit data payload packet */
+ m_swt_packet_info.swt_payload_pkt_bitsize = 4;
+ *(uint8_t *)m_payload_buffer = m_curr_packet_in->getD4Val();
+ break;
+
+ case STM_PKT_D8: /**< 8 bit data payload packet */
+ case STM_PKT_TRIG: /**< Trigger event packet - 8 bits. */
+ case STM_PKT_GERR: /**< error packet - 8 bits. */
+ case STM_PKT_MERR: /**< error packet - 8 bits. */
+ m_swt_packet_info.swt_payload_pkt_bitsize = 8;
+ *(uint8_t *)m_payload_buffer = m_curr_packet_in->getD8Val();
+ break;
+
+ case STM_PKT_D16: /**< 16 bit data payload packet */
+ m_swt_packet_info.swt_payload_pkt_bitsize = 16;
+ *(uint16_t *)m_payload_buffer = m_curr_packet_in->getD16Val();
+ break;
+
+ case STM_PKT_D32: /**< 32 bit data payload packet */
+ case STM_PKT_FREQ: /**< Frequency packet */
+ m_swt_packet_info.swt_payload_pkt_bitsize = 32;
+ *(uint32_t *)m_payload_buffer = m_curr_packet_in->getD32Val();
+ break;
+
+
+ case STM_PKT_D64: /**< 64 bit data payload packet */
+ m_swt_packet_info.swt_payload_pkt_bitsize = 64;
+ *(uint64_t *)m_payload_buffer = m_curr_packet_in->getD64Val();
+ break;
+ }
+ m_output_elem.setExtendedDataPtr(m_payload_buffer);
+ if (m_curr_packet_in->isMarkerPkt())
+ m_swt_packet_info.swt_marker_packet = 1;
+
+}
+
+/* End of File trc_pkt_decode_stm.cpp */
diff --git a/decoder/source/stm/trc_pkt_elem_stm.cpp b/decoder/source/stm/trc_pkt_elem_stm.cpp
new file mode 100644
index 0000000..d9adaf6
--- /dev/null
+++ b/decoder/source/stm/trc_pkt_elem_stm.cpp
@@ -0,0 +1,314 @@
+/*
+ * \file trc_pkt_elem_stm.cpp
+ * \brief OpenCSD : STM decode - packet class
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sstream>
+#include <iomanip>
+#include "opencsd/stm/trc_pkt_elem_stm.h"
+
+StmTrcPacket::StmTrcPacket()
+{
+ initStartState();
+}
+
+StmTrcPacket &StmTrcPacket::operator =(const ocsd_stm_pkt *p_pkt)
+{
+ *dynamic_cast<ocsd_stm_pkt *>(this) = *p_pkt;
+ return *this;
+}
+
+void StmTrcPacket::initStartState()
+{
+ master = 0;
+ channel = 0;
+ timestamp = 0;
+ ts_type = STM_TS_UNKNOWN;
+ type = STM_PKT_NOTSYNC;
+ initNextPacket();
+}
+
+void StmTrcPacket::initNextPacket()
+{
+ err_type = STM_PKT_NO_ERR_TYPE;
+ pkt_ts_bits = 0;
+ pkt_has_marker = 0;
+ pkt_has_ts = 0;
+}
+
+void StmTrcPacket::setTS(const uint64_t ts_val, const uint8_t updatedBits)
+{
+ if(updatedBits == 64)
+ {
+ timestamp = ts_val;
+ }
+ else
+ {
+ uint64_t mask = (0x1ULL << updatedBits) - 1;
+ timestamp &= ~mask;
+ timestamp |= ts_val & mask;
+ }
+ pkt_ts_bits = updatedBits; // mark number of bits
+ pkt_has_ts = 1;
+}
+
+// printing
+void StmTrcPacket::toString(std::string &str) const
+{
+ std::string name, desc;
+ std::ostringstream oss;
+
+ pktTypeName(type,name, desc);
+ str = name + ":" + desc;
+
+ // extended information
+ switch(type)
+ {
+ case STM_PKT_INCOMPLETE_EOT:
+ case STM_PKT_BAD_SEQUENCE:
+ pktTypeName(err_type,name, desc);
+ str+= "[" + name + "]";
+ break;
+
+ case STM_PKT_VERSION:
+ oss << "; Ver=" << (uint16_t)payload.D8;
+ str+= oss.str();
+ break;
+
+ case STM_PKT_FREQ:
+ oss << "; Freq=" << std::dec << payload.D32 << "Hz";
+ str+= oss.str();
+ break;
+
+ case STM_PKT_TRIG:
+ oss << "; TrigData=0x" << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)payload.D8;
+ str+= oss.str();
+ break;
+
+ case STM_PKT_M8:
+ oss << "; Master=0x" << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)master;
+ str+= oss.str();
+ break;
+
+ case STM_PKT_C8:
+ case STM_PKT_C16:
+ oss << "; Chan=0x" << std::hex << std::setw(4) << std::setfill('0') << channel;
+ str+= oss.str();
+ break;
+
+ case STM_PKT_D4:
+ oss << "; Data=0x" << std::hex << std::setw(1) << (uint16_t)(payload.D8 & 0xF);
+ str+= oss.str();
+ break;
+
+ case STM_PKT_D8:
+ oss << "; Data=0x" << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)payload.D8;
+ str+= oss.str();
+ break;
+
+ case STM_PKT_D16:
+ oss << "; Data=0x" << std::hex << std::setw(4) << std::setfill('0') << payload.D16;
+ str+= oss.str();
+ break;
+
+ case STM_PKT_D32:
+ oss << "; Data=0x" << std::hex << std::setw(8) << std::setfill('0') << payload.D32;
+ str+= oss.str();
+ break;
+
+ case STM_PKT_D64:
+ oss << "; Data=0x" << std::hex << std::setw(16) << std::setfill('0') << payload.D64;
+ str+= oss.str();
+ break;
+ }
+
+ if(isTSPkt())
+ {
+ std::string valStr;
+ trcPrintableElem::getValStr(valStr,64,64,timestamp,true,pkt_ts_bits);
+ str += "; TS=" + valStr;
+ }
+}
+
+void StmTrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const
+{
+ // no formatting for now.
+ toString(str);
+}
+
+void StmTrcPacket::pktTypeName(const ocsd_stm_pkt_type pkt_type, std::string &name, std::string &desc) const
+{
+ std::ostringstream oss_name;
+ std::ostringstream oss_desc;
+ bool addMarkerTS = false;
+
+
+ switch(pkt_type)
+ {
+ case STM_PKT_RESERVED:
+ oss_name << "RESERVED";
+ oss_desc << "Reserved Packet Header";
+ break;
+
+ case STM_PKT_NOTSYNC:
+ oss_name << "NOTSYNC";
+ oss_desc << "STM not synchronised";
+ break;
+
+ case STM_PKT_INCOMPLETE_EOT:
+ oss_name << "INCOMPLETE_EOT";
+ oss_desc << "Incomplete packet flushed at end of trace";
+ break;
+
+ case STM_PKT_NO_ERR_TYPE:
+ oss_name << "NO_ERR_TYPE";
+ oss_desc << "Error type not set";
+ break;
+
+ case STM_PKT_BAD_SEQUENCE:
+ oss_name << "BAD_SEQUENCE";
+ oss_desc << "Invalid sequence in packet";
+ break;
+
+ case STM_PKT_ASYNC:
+ oss_name << "ASYNC";
+ oss_desc << "Alignment synchronisation packet";
+ break;
+
+ case STM_PKT_VERSION:
+ oss_name << "VERSION";
+ oss_desc << "Version packet";
+ break;
+
+ case STM_PKT_FREQ:
+ oss_name << "FREQ";
+ oss_desc << "Frequency packet";
+ break;
+
+ case STM_PKT_NULL:
+ oss_name << "NULL";
+ oss_desc << "Null packet";
+ break;
+
+ case STM_PKT_TRIG:
+ oss_name << "TRIG";
+ oss_desc << "Trigger packet";
+ addMarkerTS = true;
+ break;
+
+ case STM_PKT_GERR:
+ oss_name << "GERR";
+ oss_desc << "Global Error";
+ break;
+
+ case STM_PKT_MERR:
+ oss_name << "MERR";
+ oss_desc << "Master Error";
+ break;
+
+ case STM_PKT_M8:
+ oss_name << "M8";
+ oss_desc << "Set current master";
+ break;
+
+ case STM_PKT_C8:
+ oss_name << "C8";
+ oss_desc << "Set current channel";
+ break;
+
+ case STM_PKT_C16:
+ oss_name << "C16";
+ oss_desc << "Set current channel";
+ break;
+
+ case STM_PKT_FLAG:
+ oss_name << "FLAG";
+ oss_desc << "Flag packet";
+ addMarkerTS = true;
+ break;
+
+ case STM_PKT_D4:
+ oss_name << "D4";
+ oss_desc << "4 bit data";
+ addMarkerTS = true;
+ break;
+
+ case STM_PKT_D8:
+ oss_name << "D8";
+ oss_desc << "8 bit data";
+ addMarkerTS = true;
+ break;
+
+ case STM_PKT_D16:
+ oss_name << "D16";
+ oss_desc << "16 bit data";
+ addMarkerTS = true;
+ break;
+
+ case STM_PKT_D32:
+ oss_name << "D32";
+ oss_desc << "32 bit data";
+ addMarkerTS = true;
+ break;
+
+ case STM_PKT_D64:
+ oss_name << "D64";
+ oss_desc << "64 bit data";
+ addMarkerTS = true;
+ break;
+
+ default:
+ oss_name << "UNKNOWN";
+ oss_desc << "ERROR: unknown packet type";
+ break;
+ }
+
+ if(addMarkerTS)
+ {
+ if(isMarkerPkt())
+ {
+ oss_name << "M";
+ oss_desc << " + marker";
+ }
+
+ if(isTSPkt())
+ {
+ oss_name << "TS";
+ oss_desc << " + timestamp";
+ }
+ }
+ desc = oss_desc.str();
+ name = oss_name.str();
+}
+
+
+/* End of File trc_pkt_elem_stm.cpp */
diff --git a/decoder/source/stm/trc_pkt_proc_stm.cpp b/decoder/source/stm/trc_pkt_proc_stm.cpp
new file mode 100644
index 0000000..b39a053
--- /dev/null
+++ b/decoder/source/stm/trc_pkt_proc_stm.cpp
@@ -0,0 +1,1043 @@
+/*
+ * \file trc_pkt_proc_stm.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opencsd/stm/trc_pkt_proc_stm.h"
+
+
+// processor object construction
+// ************************
+
+#ifdef __GNUC__
+// G++ doesn't like the ## pasting
+#define STM_PKTS_NAME "PKTP_STM"
+#else
+#define STM_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_STM"
+#endif
+
+static const uint32_t STM_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON;
+
+TrcPktProcStm::TrcPktProcStm() : TrcPktProcBase(STM_PKTS_NAME)
+{
+ initObj();
+}
+
+TrcPktProcStm::TrcPktProcStm(int instIDNum) : TrcPktProcBase(STM_PKTS_NAME, instIDNum)
+{
+ initObj();
+}
+
+TrcPktProcStm::~TrcPktProcStm()
+{
+ getRawPacketMonAttachPt()->set_notifier(0);
+}
+
+void TrcPktProcStm::initObj()
+{
+ m_supported_op_flags = STM_SUPPORTED_OP_FLAGS;
+ initProcessorState();
+ getRawPacketMonAttachPt()->set_notifier(&mon_in_use);
+ buildOpTables();
+}
+
+// implementation packet processing interface overrides
+// ************************
+ocsd_datapath_resp_t TrcPktProcStm::processData( const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_p_data_in = pDataBlock;
+ m_data_in_size = dataBlockSize;
+ m_data_in_used = 0;
+
+ // while there is data and a continue response on the data path
+ while( dataToProcess() && OCSD_DATA_RESP_IS_CONT(resp) )
+ {
+ try
+ {
+ switch(m_proc_state)
+ {
+ case WAIT_SYNC:
+ waitForSync(index);
+ break;
+
+ case PROC_HDR:
+ m_packet_index = index + m_data_in_used;
+ if(readNibble())
+ {
+ m_proc_state = PROC_DATA; // read the header nibble, next if any has to be data
+ m_pCurrPktFn = m_1N_ops[m_nibble]; // set packet function and fall through
+ }
+ else
+ break;
+
+ case PROC_DATA:
+ (this->*m_pCurrPktFn)();
+
+ // if we have enough to send, fall through, otherwise stop
+ if(m_proc_state != SEND_PKT)
+ break;
+
+ case SEND_PKT:
+ resp = outputPacket();
+ break;
+ }
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ if( ((err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) ||
+ (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)) &&
+ !(getComponentOpMode() & OCSD_OPFLG_PKTPROC_ERR_BAD_PKTS))
+ {
+ // send invalid packets up the pipe to let the next stage decide what to do.
+ resp = outputPacket();
+ if(getComponentOpMode() & OCSD_OPFLG_PKTPROC_UNSYNC_ON_BAD_PKTS)
+ m_proc_state = WAIT_SYNC;
+ }
+ else
+ {
+ // bail out on any other error.
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+ }
+ catch(...)
+ {
+ /// vv bad at this point.
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+ ocsdError fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_config->getTraceID());
+ fatal.setMessage("Unknown System Error decoding trace.");
+ LogError(fatal);
+ }
+ }
+
+ *numBytesProcessed = m_data_in_used;
+ return resp;
+
+}
+
+ocsd_datapath_resp_t TrcPktProcStm::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ if(m_num_nibbles > 0) // there is a partial packet in flight
+ {
+ m_curr_packet.updateErrType(STM_PKT_INCOMPLETE_EOT); // re mark as incomplete
+ resp = outputPacket();
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcStm::onReset()
+{
+ initProcessorState();
+ return OCSD_RESP_CONT;
+}
+
+ocsd_datapath_resp_t TrcPktProcStm::onFlush()
+{
+ // packet processor never holds on to flushable data (may have partial packet,
+ // but any full packets are immediately sent)
+ return OCSD_RESP_CONT;
+}
+
+ocsd_err_t TrcPktProcStm::onProtocolConfig()
+{
+ return OCSD_OK; // nothing to do on config for this processor
+}
+
+const bool TrcPktProcStm::isBadPacket() const
+{
+ return m_curr_packet.isBadPacket();
+}
+
+ocsd_datapath_resp_t TrcPktProcStm::outputPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ resp = outputOnAllInterfaces(m_packet_index,&m_curr_packet,&m_curr_packet.type,m_packet_data);
+ m_packet_data.clear();
+ initNextPacket();
+ if(m_nibble_2nd_valid)
+ savePacketByte(m_nibble_2nd << 4); // put the unused nibble back on to the data stack and pad for output next time.
+ m_proc_state = m_bStreamSync ? PROC_HDR : WAIT_SYNC;
+ return resp;
+}
+
+void TrcPktProcStm::throwBadSequenceError(const char *pszMessage /*= ""*/)
+{
+ m_curr_packet.updateErrType(STM_PKT_BAD_SEQUENCE);
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,this->m_config->getTraceID(),pszMessage);
+}
+
+void TrcPktProcStm::throwReservedHdrError(const char *pszMessage /*= ""*/)
+{
+ m_curr_packet.setPacketType(STM_PKT_RESERVED,false);
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,this->m_config->getTraceID(),pszMessage);
+}
+
+// processor / packet init
+// ************************
+
+void TrcPktProcStm::initProcessorState()
+{
+ // clear any state that persists between packets
+ setProcUnsynced();
+ clearSyncCount();
+ m_curr_packet.initStartState();
+ m_nibble_2nd_valid = false;
+ initNextPacket();
+ m_bWaitSyncSaveSuppressed = false;
+
+ m_packet_data.clear();
+}
+
+void TrcPktProcStm::initNextPacket()
+{
+ // clear state that is unique to each packet
+ m_bNeedsTS = false;
+ m_bIsMarker = false;
+ m_num_nibbles = 0;
+ m_num_data_nibbles = 0;
+ m_curr_packet.initNextPacket();
+}
+
+// search remaining buffer for a start of sync or full sync packet
+void TrcPktProcStm::waitForSync(const ocsd_trc_index_t blk_st_index)
+{
+ bool bGotData = true;
+ uint32_t start_offset = m_data_in_used; // record the offset into the buffer at start of this fn.
+
+ // input conditions:
+ // out of sync - either at start of input stream, or due to bad packet.
+ // m_data_in_used -> bytes already processed
+ // m_sync_start -> seen potential start of sync in current stream
+
+ // set a packet index for the start of the data
+ m_packet_index = blk_st_index + m_data_in_used;
+ m_num_nibbles = m_is_sync ? m_num_F_nibbles + 1 : m_num_F_nibbles; // sending unsync data may have cleared down num_nibbles.
+
+ m_bWaitSyncSaveSuppressed = true; // no need to save bytes until we want to send data.
+
+ while(bGotData && !m_is_sync)
+ {
+ bGotData = readNibble(); // read until we have a sync or run out of data
+ }
+
+ m_bWaitSyncSaveSuppressed = false;
+
+ // no data from first attempt to read
+ if(m_num_nibbles == 0)
+ return;
+
+ // we have found a sync or run out of data
+ // five possible scenarios
+ // a) all data none sync data.
+ // b) some none sync data + start of sync sequence
+ // c) some none sync data + full sync sequence in this frame
+ // d) full sync sequence @ start of this frame followed by ???
+ // e) completion of sync sequence in this frame (from b)).
+
+ if(!bGotData || m_num_nibbles > 22)
+ {
+ // for a), b), c) send the none sync data then re-enter
+ // if out of data, or sync with some previous data, this is sent as unsynced.
+
+ m_curr_packet.setPacketType(STM_PKT_NOTSYNC,false);
+ if(mon_in_use.usingMonitor())
+ {
+ uint8_t nibbles_to_send = m_num_nibbles - (m_is_sync ? 22 : m_num_F_nibbles);
+ uint8_t bytes_to_send = (nibbles_to_send / 2) + (nibbles_to_send % 2);
+ for(uint8_t i = 0; i < bytes_to_send; i++)
+ savePacketByte(m_p_data_in[start_offset+i]);
+ }
+
+ // if we have found a sync then we will re-enter this function with no pre data,
+ // but the found flags set.
+ }
+ else
+ {
+ // send the async packet
+ m_curr_packet.setPacketType(STM_PKT_ASYNC,false);
+ m_bStreamSync = true; // mark the stream as synchronised
+ clearSyncCount();
+ m_packet_index = m_sync_index;
+ if(mon_in_use.usingMonitor())
+ {
+ // we may not have the full sync packet still in the local buffer so synthesise it.
+ for(int i = 0; i < 10; i++)
+ savePacketByte(0xFF);
+ savePacketByte(0x0F);
+ }
+ }
+ sendPacket(); // mark packet for sending
+}
+
+// packet processing routines
+// ************************
+// 1 nibble opcodes
+void TrcPktProcStm::stmPktReserved()
+{
+ uint16_t bad_opcode = (uint16_t)m_nibble;
+ m_curr_packet.setD16Payload(bad_opcode);
+ throwReservedHdrError("STM: Unsupported or Reserved STPv2 Header");
+}
+
+void TrcPktProcStm::stmPktNull()
+{
+ m_curr_packet.setPacketType(STM_PKT_NULL,false);
+ if(m_bNeedsTS)
+ {
+ m_pCurrPktFn = &TrcPktProcStm::stmExtractTS;
+ (this->*m_pCurrPktFn)();
+ }
+ else
+ {
+ sendPacket();
+ }
+}
+
+void TrcPktProcStm::stmPktNullTS()
+{
+ pktNeedsTS();
+ m_pCurrPktFn = &TrcPktProcStm::stmPktNull;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktM8()
+{
+ if(m_num_nibbles == 1) // 1st nibble - header - set type
+ m_curr_packet.setPacketType(STM_PKT_M8,false);
+
+ stmExtractVal8(3);
+ if(m_num_nibbles == 3)
+ {
+ m_curr_packet.setMaster(m_val8);
+ sendPacket();
+ }
+}
+
+void TrcPktProcStm::stmPktMERR()
+{
+ if(m_num_nibbles == 1) // 1st nibble - header - set type
+ m_curr_packet.setPacketType(STM_PKT_MERR,false);
+
+ stmExtractVal8(3);
+ if(m_num_nibbles == 3)
+ {
+ m_curr_packet.setChannel(0,false); // MERR resets channel for current master to 0.
+ m_curr_packet.setD8Payload(m_val8);
+ sendPacket();
+ }
+
+}
+
+void TrcPktProcStm::stmPktC8()
+{
+ if(m_num_nibbles == 1) // 1st nibble - header - set type
+ m_curr_packet.setPacketType(STM_PKT_C8,false);
+ stmExtractVal8(3);
+ if(m_num_nibbles == 3)
+ {
+ m_curr_packet.setChannel((uint16_t)m_val8,true);
+ sendPacket();
+ }
+}
+
+void TrcPktProcStm::stmPktD4()
+{
+ if(m_num_nibbles == 1) // 1st nibble - header - set type
+ {
+ m_curr_packet.setPacketType(STM_PKT_D4,m_bIsMarker);
+ m_num_data_nibbles = 2; // need 2 nibbles to complete data
+ }
+
+ if(m_num_nibbles != m_num_data_nibbles)
+ {
+ if(readNibble())
+ {
+ m_curr_packet.setD4Payload(m_nibble);
+ if(m_bNeedsTS)
+ {
+ m_pCurrPktFn = &TrcPktProcStm::stmExtractTS;
+ (this->*m_pCurrPktFn)();
+ }
+ else
+ sendPacket();
+ }
+ }
+}
+
+void TrcPktProcStm::stmPktD8()
+{
+ if(m_num_nibbles == 1) // 1st nibble - header - set type
+ {
+ m_curr_packet.setPacketType(STM_PKT_D8,m_bIsMarker);
+ m_num_data_nibbles = 3; // need 3 nibbles in total to complete data
+ }
+
+ stmExtractVal8(m_num_data_nibbles);
+ if(m_num_nibbles == m_num_data_nibbles)
+ {
+ m_curr_packet.setD8Payload(m_val8);
+ if(m_bNeedsTS)
+ {
+ m_pCurrPktFn = &TrcPktProcStm::stmExtractTS;
+ (this->*m_pCurrPktFn)();
+ }
+ else
+ {
+ sendPacket();
+ }
+ }
+}
+
+void TrcPktProcStm::stmPktD16()
+{
+ if(m_num_nibbles == 1) // 1st nibble - header - set type
+ {
+ m_curr_packet.setPacketType(STM_PKT_D16,m_bIsMarker);
+ m_num_data_nibbles = 5;
+ }
+
+ stmExtractVal16(m_num_data_nibbles);
+ if(m_num_nibbles == m_num_data_nibbles)
+ {
+ m_curr_packet.setD16Payload(m_val16);
+ if(m_bNeedsTS)
+ {
+ m_pCurrPktFn = &TrcPktProcStm::stmExtractTS;
+ (this->*m_pCurrPktFn)();
+ }
+ else
+ {
+ sendPacket();
+ }
+ }
+}
+
+void TrcPktProcStm::stmPktD32()
+{
+ if(m_num_nibbles == 1) // 1st nibble - header - set type
+ {
+ m_curr_packet.setPacketType(STM_PKT_D32,m_bIsMarker);
+ m_num_data_nibbles = 9;
+ }
+
+ stmExtractVal32(m_num_data_nibbles);
+ if(m_num_nibbles == m_num_data_nibbles)
+ {
+ m_curr_packet.setD32Payload(m_val32);
+ if(m_bNeedsTS)
+ {
+ m_pCurrPktFn = &TrcPktProcStm::stmExtractTS;
+ (this->*m_pCurrPktFn)();
+ }
+ else
+ {
+ sendPacket();
+ }
+ }
+}
+
+void TrcPktProcStm::stmPktD64()
+{
+ if(m_num_nibbles == 1) // 1st nibble - header - set type
+ {
+ m_curr_packet.setPacketType(STM_PKT_D64,m_bIsMarker);
+ m_num_data_nibbles = 17;
+ }
+
+ stmExtractVal64(m_num_data_nibbles);
+ if(m_num_nibbles == m_num_data_nibbles)
+ {
+ m_curr_packet.setD64Payload(m_val64);
+ if(m_bNeedsTS)
+ {
+ m_pCurrPktFn = &TrcPktProcStm::stmExtractTS;
+ (this->*m_pCurrPktFn)();
+ }
+ else
+ {
+ sendPacket();
+ }
+ }
+}
+
+void TrcPktProcStm::stmPktD4MTS()
+{
+ pktNeedsTS();
+ m_bIsMarker = true;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD4;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD8MTS()
+{
+ pktNeedsTS();
+ m_bIsMarker = true;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD8;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD16MTS()
+{
+ pktNeedsTS();
+ m_bIsMarker = true;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD16;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD32MTS()
+{
+ pktNeedsTS();
+ m_bIsMarker = true;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD32;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD64MTS()
+{
+ pktNeedsTS();
+ m_bIsMarker = true;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD64;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktFlagTS()
+{
+ pktNeedsTS();
+ m_curr_packet.setPacketType(STM_PKT_FLAG,false);
+ m_pCurrPktFn = &TrcPktProcStm::stmExtractTS;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktFExt()
+{
+ // no type, look at the next nibble
+ if(readNibble())
+ {
+ // switch in 2N function
+ m_pCurrPktFn = m_2N_ops[m_nibble];
+ (this->*m_pCurrPktFn)();
+ }
+}
+
+// ************************
+// 2 nibble opcodes 0xFn
+void TrcPktProcStm::stmPktReservedFn()
+{
+ uint16_t bad_opcode = 0x00F;
+ bad_opcode |= ((uint16_t)m_nibble) << 4;
+ m_curr_packet.setD16Payload(bad_opcode);
+ throwReservedHdrError("STM: Unsupported or Reserved STPv2 Header");
+}
+
+void TrcPktProcStm::stmPktF0Ext()
+{
+ // no type yet, look at the next nibble
+ if(readNibble())
+ {
+ // switch in 3N function
+ m_pCurrPktFn = m_3N_ops[m_nibble];
+ (this->*m_pCurrPktFn)();
+ }
+}
+
+void TrcPktProcStm::stmPktGERR()
+{
+ if(m_num_nibbles == 2) // 2nd nibble - header - set type
+ m_curr_packet.setPacketType(STM_PKT_GERR,false);
+ stmExtractVal8(4);
+ if(m_num_nibbles == 4)
+ {
+ m_curr_packet.setD8Payload(m_val8);
+ m_curr_packet.setMaster(0); // GERR sets current master to 0.
+ sendPacket();
+ }
+}
+
+void TrcPktProcStm::stmPktC16()
+{
+ if(m_num_nibbles == 2) // 2nd nibble - header - set type
+ m_curr_packet.setPacketType(STM_PKT_C16,false);
+ stmExtractVal16(6);
+ if(m_num_nibbles == 6)
+ {
+ m_curr_packet.setChannel(m_val16,false);
+ sendPacket();
+ }
+}
+
+void TrcPktProcStm::stmPktD4TS()
+{
+ pktNeedsTS();
+ m_curr_packet.setPacketType(STM_PKT_D4,false); // 2nd nibble, set type here
+ m_num_data_nibbles = 3; // one more nibble for data
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD4;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD8TS()
+{
+ pktNeedsTS();
+ m_curr_packet.setPacketType(STM_PKT_D8,false); // 2nd nibble, set type here
+ m_num_data_nibbles = 4;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD8;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD16TS()
+{
+ pktNeedsTS();
+ m_curr_packet.setPacketType(STM_PKT_D16,false); // 2nd nibble, set type here
+ m_num_data_nibbles = 6;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD16;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD32TS()
+{
+ pktNeedsTS();
+ m_curr_packet.setPacketType(STM_PKT_D32,false); // 2nd nibble, set type here
+ m_num_data_nibbles = 10;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD32;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD64TS()
+{
+ pktNeedsTS();
+ m_curr_packet.setPacketType(STM_PKT_D64,false); // 2nd nibble, set type here
+ m_num_data_nibbles = 18;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD64;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD4M()
+{
+ m_curr_packet.setPacketType(STM_PKT_D4,true); // 2nd nibble, set type here
+ m_num_data_nibbles = 3; // one more nibble for data
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD4;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD8M()
+{
+ m_curr_packet.setPacketType(STM_PKT_D8,true); // 2nd nibble, set type here
+ m_num_data_nibbles = 4;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD8;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD16M()
+{
+ m_curr_packet.setPacketType(STM_PKT_D16,true);
+ m_num_data_nibbles = 6;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD16;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD32M()
+{
+ m_curr_packet.setPacketType(STM_PKT_D32,true);
+ m_num_data_nibbles = 10;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD32;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktD64M()
+{
+ m_curr_packet.setPacketType(STM_PKT_D64,true);
+ m_num_data_nibbles = 18;
+ m_pCurrPktFn = &TrcPktProcStm::stmPktD64;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktFlag()
+{
+ m_curr_packet.setPacketType(STM_PKT_FLAG,false);
+ sendPacket();
+}
+
+// ************************
+// 3 nibble opcodes 0xF0n
+void TrcPktProcStm::stmPktReservedF0n()
+{
+ uint16_t bad_opcode = 0x00F;
+ bad_opcode |= ((uint16_t)m_nibble) << 8;
+ m_curr_packet.setD16Payload(bad_opcode);
+ throwReservedHdrError("STM: Unsupported or Reserved STPv2 Header");
+}
+
+void TrcPktProcStm::stmPktVersion()
+{
+ if(m_num_nibbles == 3)
+ m_curr_packet.setPacketType(STM_PKT_VERSION,false);
+
+ if(readNibble())
+ {
+ m_curr_packet.setD8Payload(m_nibble); // record the version number
+ switch(m_nibble)
+ {
+ case 3:
+ m_curr_packet.onVersionPkt(STM_TS_NATBINARY); break;
+ case 4:
+ m_curr_packet.onVersionPkt(STM_TS_GREY); break;
+ default:
+ // not a version we support.
+ throwBadSequenceError("STM VERSION packet : unrecognised version number.");
+ }
+ sendPacket();
+ }
+}
+
+void TrcPktProcStm::stmPktTrigger()
+{
+ if(m_num_nibbles == 3)
+ m_curr_packet.setPacketType(STM_PKT_TRIG,false);
+ stmExtractVal8(5);
+ if(m_num_nibbles == 5)
+ {
+ m_curr_packet.setD8Payload(m_val8);
+ if(m_bNeedsTS)
+ {
+ m_pCurrPktFn = &TrcPktProcStm::stmExtractTS;
+ (this->*m_pCurrPktFn)();
+ }
+ else
+ {
+ sendPacket();
+ }
+ }
+}
+
+void TrcPktProcStm::stmPktTriggerTS()
+{
+ pktNeedsTS();
+ m_pCurrPktFn = &TrcPktProcStm::stmPktTrigger;
+ (this->*m_pCurrPktFn)();
+}
+
+void TrcPktProcStm::stmPktFreq()
+{
+ if(m_num_nibbles == 3)
+ {
+ m_curr_packet.setPacketType(STM_PKT_FREQ,false);
+ m_val32 = 0;
+ }
+ stmExtractVal32(11);
+ if(m_num_nibbles == 11)
+ {
+ m_curr_packet.setD32Payload(m_val32);
+ sendPacket();
+ }
+}
+
+void TrcPktProcStm::stmPktASync()
+{
+ // 2 nibbles - 0xFF - must be an async or error.
+ bool bCont = true;
+ while(bCont)
+ {
+ bCont = readNibble();
+ if(bCont)
+ {
+ if(m_is_sync)
+ {
+ bCont = false; // stop reading nibbles
+ m_bStreamSync = true; // mark stream in sync
+ m_curr_packet.setPacketType(STM_PKT_ASYNC,false);
+ clearSyncCount();
+ sendPacket();
+ }
+ else if(!m_sync_start) // no longer valid sync packet
+ {
+ throwBadSequenceError("STM: Invalid ASYNC sequence");
+ }
+ }
+ }
+}
+
+// ************************
+// general data processing
+
+// return false if no more data
+// in an STM byte, 3:0 is 1st nibble in protocol order, 7:4 is 2nd nibble.
+bool TrcPktProcStm::readNibble()
+{
+ bool dataFound = true;
+ if(m_nibble_2nd_valid)
+ {
+ m_nibble = m_nibble_2nd;
+ m_nibble_2nd_valid = false;
+ m_num_nibbles++;
+ checkSyncNibble();
+ }
+ else if(m_data_in_used < m_data_in_size )
+ {
+ m_nibble = m_p_data_in[m_data_in_used++];
+ savePacketByte(m_nibble);
+ m_nibble_2nd = (m_nibble >> 4) & 0xF;
+ m_nibble_2nd_valid = true;
+ m_nibble &= 0xF;
+ m_num_nibbles++;
+ checkSyncNibble();
+ }
+ else
+ dataFound = false; // no data available
+ return dataFound;
+}
+
+void TrcPktProcStm::pktNeedsTS()
+{
+ m_bNeedsTS = true;
+ m_req_ts_nibbles = 0;
+ m_curr_ts_nibbles = 0;
+ m_ts_update_value = 0;
+ m_ts_req_set = false;
+}
+
+void TrcPktProcStm::stmExtractTS()
+{
+ if(!m_ts_req_set)
+ {
+ if(readNibble())
+ {
+ m_req_ts_nibbles = m_nibble;
+ if(m_nibble == 0xD)
+ m_req_ts_nibbles = 14;
+ else if(m_nibble == 0xE)
+ m_req_ts_nibbles = 16;
+
+ if(m_nibble == 0xF)
+ throwBadSequenceError("STM: Invalid timestamp size 0xF");
+ m_ts_req_set = true;
+ }
+ }
+
+ if(m_ts_req_set)
+ {
+ // if we do not have all the nibbles for the TS, get some...
+ if(m_req_ts_nibbles != m_curr_ts_nibbles)
+ {
+ // extract the correct amount of nibbles for the ts value.
+ bool bCont = true;
+ while(bCont && (m_curr_ts_nibbles < m_req_ts_nibbles))
+ {
+ bCont = readNibble();
+ if(bCont)
+ {
+ m_ts_update_value <<= 4;
+ m_ts_update_value |= m_nibble;
+ m_curr_ts_nibbles++;
+ }
+ }
+ }
+
+ // at this point we have the correct amount of nibbles, or have run out of data to process.
+ if(m_req_ts_nibbles == m_curr_ts_nibbles)
+ {
+ uint8_t new_bits = m_req_ts_nibbles * 4;
+ if(m_curr_packet.getTSType() == STM_TS_GREY)
+ {
+ uint64_t gray_val = bin_to_gray(m_curr_packet.getTSVal());
+ if(new_bits == 64)
+ {
+ gray_val = m_ts_update_value;
+ }
+ else
+ {
+ uint64_t mask = (0x1ULL << new_bits) - 1;
+ gray_val &= ~mask;
+ gray_val |= m_ts_update_value & mask;
+ }
+ m_curr_packet.setTS(gray_to_bin(gray_val),new_bits);
+ }
+ else if(m_curr_packet.getTSType() == STM_TS_NATBINARY)
+ {
+ m_curr_packet.setTS(m_ts_update_value, new_bits);
+ }
+ else
+ throwBadSequenceError("STM: unknown timestamp encoding");
+
+ sendPacket();
+ }
+ }
+}
+
+// pass in number of nibbles needed to extract the value
+void TrcPktProcStm::stmExtractVal8(uint8_t nibbles_to_val)
+{
+ bool bCont = true;
+ while(bCont && (m_num_nibbles < nibbles_to_val))
+ {
+ bCont = readNibble();
+ if(bCont) // got a nibble
+ {
+ m_val8 <<= 4;
+ m_val8 |= m_nibble;
+ }
+ }
+}
+
+void TrcPktProcStm::stmExtractVal16(uint8_t nibbles_to_val)
+{
+ bool bCont = true;
+ while(bCont && (m_num_nibbles < nibbles_to_val))
+ {
+ bCont = readNibble();
+ if(bCont) // got a nibble
+ {
+ m_val16 <<= 4;
+ m_val16 |= m_nibble;
+ }
+ }
+}
+
+void TrcPktProcStm::stmExtractVal32(uint8_t nibbles_to_val)
+{
+ bool bCont = true;
+ while(bCont && (m_num_nibbles < nibbles_to_val))
+ {
+ bCont = readNibble();
+ if(bCont) // got a nibble
+ {
+ m_val32 <<= 4;
+ m_val32 |= m_nibble;
+ }
+ }
+}
+
+void TrcPktProcStm::stmExtractVal64(uint8_t nibbles_to_val)
+{
+ bool bCont = true;
+ while(bCont && (m_num_nibbles < nibbles_to_val))
+ {
+ bCont = readNibble();
+ if(bCont) // got a nibble
+ {
+ m_val64 <<= 4;
+ m_val64 |= m_nibble;
+ }
+ }
+}
+
+uint64_t TrcPktProcStm::bin_to_gray(uint64_t bin_value)
+{
+ uint64_t gray_value = 0;
+ gray_value = (1ull << 63) & bin_value;
+ int i = 62;
+ for (; i >= 0; i--) {
+ uint64_t gray_arg_1 = ((1ull << (i+1)) & bin_value) >> (i+1);
+ uint64_t gray_arg_2 = ((1ull << i) & bin_value) >> i;
+ gray_value |= ((gray_arg_1 ^ gray_arg_2) << i);
+ }
+ return gray_value;
+}
+
+uint64_t TrcPktProcStm::gray_to_bin(uint64_t gray_value)
+{
+ uint64_t bin_value = 0;
+ int bin_bit = 0;
+ for (; bin_bit < 64; bin_bit++) {
+ uint8_t bit_tmp = ((1ull << bin_bit) & gray_value) >> bin_bit;
+ uint8_t gray_bit = bin_bit + 1;
+ for (; gray_bit < 64; gray_bit++)
+ bit_tmp ^= (((1ull << gray_bit) & gray_value) >> gray_bit);
+
+ bin_value |= (bit_tmp << bin_bit);
+ }
+
+ return bin_value;
+}
+
+
+void TrcPktProcStm::buildOpTables()
+{
+ // init all reserved
+ for(int i = 0; i < 0x10; i++)
+ {
+ m_1N_ops[i] = &TrcPktProcStm::stmPktReserved;
+ m_2N_ops[i] = &TrcPktProcStm::stmPktReservedFn;
+ m_3N_ops[i] = &TrcPktProcStm::stmPktReservedF0n;
+ }
+
+ // set the 1N operations
+ m_1N_ops[0x0] = &TrcPktProcStm::stmPktNull;
+ m_1N_ops[0x1] = &TrcPktProcStm::stmPktM8;
+ m_1N_ops[0x2] = &TrcPktProcStm::stmPktMERR;
+ m_1N_ops[0x3] = &TrcPktProcStm::stmPktC8;
+ m_1N_ops[0x4] = &TrcPktProcStm::stmPktD8;
+ m_1N_ops[0x5] = &TrcPktProcStm::stmPktD16;
+ m_1N_ops[0x6] = &TrcPktProcStm::stmPktD32;
+ m_1N_ops[0x7] = &TrcPktProcStm::stmPktD64;
+ m_1N_ops[0x8] = &TrcPktProcStm::stmPktD8MTS;
+ m_1N_ops[0x9] = &TrcPktProcStm::stmPktD16MTS;
+ m_1N_ops[0xA] = &TrcPktProcStm::stmPktD32MTS;
+ m_1N_ops[0xB] = &TrcPktProcStm::stmPktD64MTS;
+ m_1N_ops[0xC] = &TrcPktProcStm::stmPktD4;
+ m_1N_ops[0xD] = &TrcPktProcStm::stmPktD4MTS;
+ m_1N_ops[0xE] = &TrcPktProcStm::stmPktFlagTS;
+ m_1N_ops[0xF] = &TrcPktProcStm::stmPktFExt;
+
+ // set the 2N operations 0xFn
+ m_2N_ops[0x0] = &TrcPktProcStm::stmPktF0Ext;
+ // 0x1 unused in CS STM
+ m_2N_ops[0x2] = &TrcPktProcStm::stmPktGERR;
+ m_2N_ops[0x3] = &TrcPktProcStm::stmPktC16;
+ m_2N_ops[0x4] = &TrcPktProcStm::stmPktD8TS;
+ m_2N_ops[0x5] = &TrcPktProcStm::stmPktD16TS;
+ m_2N_ops[0x6] = &TrcPktProcStm::stmPktD32TS;
+ m_2N_ops[0x7] = &TrcPktProcStm::stmPktD64TS;
+ m_2N_ops[0x8] = &TrcPktProcStm::stmPktD8M;
+ m_2N_ops[0x9] = &TrcPktProcStm::stmPktD16M;
+ m_2N_ops[0xA] = &TrcPktProcStm::stmPktD32M;
+ m_2N_ops[0xB] = &TrcPktProcStm::stmPktD64M;
+ m_2N_ops[0xC] = &TrcPktProcStm::stmPktD4TS;
+ m_2N_ops[0xD] = &TrcPktProcStm::stmPktD4M;
+ m_2N_ops[0xE] = &TrcPktProcStm::stmPktFlag;
+ m_2N_ops[0xF] = &TrcPktProcStm::stmPktASync;
+
+ // set the 3N operations 0xF0n
+ m_3N_ops[0x0] = &TrcPktProcStm::stmPktVersion;
+ m_3N_ops[0x1] = &TrcPktProcStm::stmPktNullTS;
+ // 0x2 .. 0x5 not used by CS STM
+ m_3N_ops[0x6] = &TrcPktProcStm::stmPktTrigger;
+ m_3N_ops[0x7] = &TrcPktProcStm::stmPktTriggerTS;
+ m_3N_ops[0x8] = &TrcPktProcStm::stmPktFreq;
+ // 0x9 .. 0xF not used by CS STM
+
+}
+
+/* End of File trc_pkt_proc_stm.cpp */
diff --git a/decoder/source/trc_component.cpp b/decoder/source/trc_component.cpp
new file mode 100644
index 0000000..dae92d4
--- /dev/null
+++ b/decoder/source/trc_component.cpp
@@ -0,0 +1,155 @@
+/*
+ * \file trc_component.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/trc_component.h"
+
+class errLogAttachMonitor : public IComponentAttachNotifier
+{
+public:
+ errLogAttachMonitor()
+ {
+ m_pComp = 0;
+ };
+ virtual ~ errLogAttachMonitor()
+ {
+ if (m_pComp)
+ m_pComp->getErrorLogAttachPt()->set_notifier(0);
+ m_pComp = 0;
+
+ };
+ virtual void attachNotify(const int num_attached)
+ {
+ if(m_pComp)
+ m_pComp->do_attach_notify(num_attached);
+ }
+ void Init(TraceComponent *pComp)
+ {
+ m_pComp = pComp;
+ if(m_pComp)
+ m_pComp->getErrorLogAttachPt()->set_notifier(this);
+ }
+private:
+ TraceComponent *m_pComp;
+};
+
+TraceComponent::TraceComponent(const std::string &name)
+{
+ Init(name);
+}
+
+TraceComponent::TraceComponent(const std::string &name, int instIDNum)
+{
+ std::string name_combined = name;
+ char num_buffer[32];
+ sprintf(num_buffer,"_%04d",instIDNum);
+ name_combined += (std::string)num_buffer;
+ Init(name_combined);
+}
+
+TraceComponent::~TraceComponent()
+{
+ if (m_pErrAttachMon)
+ delete m_pErrAttachMon;
+}
+
+void TraceComponent::Init(const std::string &name)
+{
+ m_errLogHandle = OCSD_INVALID_HANDLE;
+ m_errVerbosity = OCSD_ERR_SEV_NONE;
+ m_name = name;
+
+ m_supported_op_flags = 0;
+ m_op_flags = 0;
+ m_assocComp = 0;
+
+ m_pErrAttachMon = new (std::nothrow) errLogAttachMonitor();
+ if(m_pErrAttachMon)
+ m_pErrAttachMon->Init(this);
+}
+
+void TraceComponent::LogError(const ocsdError &Error)
+{
+ if((m_errLogHandle != OCSD_INVALID_HANDLE) &&
+ isLoggingErrorLevel(Error.getErrorSeverity()))
+ {
+ // ensure we have not disabled the attachPt
+ if(m_error_logger.first())
+ m_error_logger.first()->LogError(m_errLogHandle,&Error);
+ }
+}
+
+void TraceComponent::LogMessage(const ocsd_err_severity_t filter_level, const std::string &msg)
+{
+ if ((m_errLogHandle != OCSD_INVALID_HANDLE) &&
+ isLoggingErrorLevel(filter_level))
+ {
+ // ensure we have not disabled the attachPt
+ if (m_error_logger.first())
+ m_error_logger.first()->LogMessage(this->m_errLogHandle, filter_level, msg);
+ }
+
+}
+
+void TraceComponent::do_attach_notify(const int num_attached)
+{
+ if(num_attached)
+ {
+ // ensure we have not disabled the attachPt
+ if(m_error_logger.first())
+ {
+ m_errLogHandle = m_error_logger.first()->RegisterErrorSource(m_name);
+ m_errVerbosity = m_error_logger.first()->GetErrorLogVerbosity();
+ }
+ }
+ else
+ {
+ m_errLogHandle = OCSD_INVALID_HANDLE;
+ }
+}
+
+void TraceComponent::updateErrorLogLevel()
+{
+ if(m_error_logger.first())
+ {
+ m_errVerbosity = m_error_logger.first()->GetErrorLogVerbosity();
+ }
+}
+
+ocsd_err_t TraceComponent::setComponentOpMode(uint32_t op_flags)
+{
+ m_op_flags = op_flags & m_supported_op_flags;
+ return OCSD_OK;
+}
+
+/* End of File trc_component.cpp */
diff --git a/decoder/source/trc_core_arch_map.cpp b/decoder/source/trc_core_arch_map.cpp
new file mode 100644
index 0000000..f25ab1e
--- /dev/null
+++ b/decoder/source/trc_core_arch_map.cpp
@@ -0,0 +1,177 @@
+/*
+ * \file trc_core_arch_map.cpp
+ * \brief OpenCSD : Map core names to architecture profiles
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/trc_core_arch_map.h"
+
+typedef struct _ap_map_elements {
+ const char *name;
+ ocsd_arch_profile_t ap;
+} ap_map_elem_t;
+
+static ap_map_elem_t ap_map_array[] =
+{
+ { "Cortex-A77", { ARCH_V8r3, profile_CortexA } },
+ { "Cortex-A76", { ARCH_V8r3, profile_CortexA } },
+ { "Cortex-A75", { ARCH_V8r3, profile_CortexA } },
+ { "Cortex-A73", { ARCH_V8, profile_CortexA } },
+ { "Cortex-A72", { ARCH_V8, profile_CortexA } },
+ { "Cortex-A65", { ARCH_V8r3, profile_CortexA } },
+ { "Cortex-A57", { ARCH_V8, profile_CortexA } },
+ { "Cortex-A55", { ARCH_V8r3, profile_CortexA } },
+ { "Cortex-A53", { ARCH_V8, profile_CortexA } },
+ { "Cortex-A35", { ARCH_V8, profile_CortexA } },
+ { "Cortex-A32", { ARCH_V8, profile_CortexA } },
+ { "Cortex-A17", { ARCH_V7, profile_CortexA } },
+ { "Cortex-A15", { ARCH_V7, profile_CortexA } },
+ { "Cortex-A12", { ARCH_V7, profile_CortexA } },
+ { "Cortex-A9", { ARCH_V7, profile_CortexA } },
+ { "Cortex-A8", { ARCH_V7, profile_CortexA } },
+ { "Cortex-A7", { ARCH_V7, profile_CortexA } },
+ { "Cortex-A5", { ARCH_V7, profile_CortexA } },
+ { "Cortex-R52", { ARCH_V8, profile_CortexR } },
+ { "Cortex-R8", { ARCH_V7, profile_CortexR } },
+ { "Cortex-R7", { ARCH_V7, profile_CortexR } },
+ { "Cortex-R5", { ARCH_V7, profile_CortexR } },
+ { "Cortex-R4", { ARCH_V7, profile_CortexR } },
+ { "Cortex-M33", { ARCH_V8, profile_CortexM } },
+ { "Cortex-M23", { ARCH_V8, profile_CortexM } },
+ { "Cortex-M0", { ARCH_V7, profile_CortexM } },
+ { "Cortex-M0+", { ARCH_V7, profile_CortexM } },
+ { "Cortex-M3", { ARCH_V7, profile_CortexM } },
+ { "Cortex-M4", { ARCH_V7, profile_CortexM } }
+};
+
+CoreArchProfileMap::CoreArchProfileMap()
+{
+ unsigned i;
+ for (i = 0; i < sizeof(ap_map_array) / sizeof(_ap_map_elements); i++)
+ {
+ core_profiles[ap_map_array[i].name] = ap_map_array[i].ap;
+ }
+}
+
+ocsd_arch_profile_t CoreArchProfileMap::getArchProfile(const std::string &coreName)
+{
+ ocsd_arch_profile_t ap = { ARCH_UNKNOWN, profile_Unknown };
+ bool bFound = false;
+
+ std::map<std::string, ocsd_arch_profile_t>::const_iterator it;
+
+ /* match against the core name map. */
+ it = core_profiles.find(coreName);
+ if (it != core_profiles.end())
+ {
+ ap = it->second;
+ bFound = true;
+ }
+
+ /* try a pattern match on core name - pick up ARMvM[.m]-P and ARM-{aa|AA}64[-P] */
+ if (!bFound)
+ ap = getPatternMatchCoreName(coreName);
+
+ return ap;
+}
+ocsd_arch_profile_t CoreArchProfileMap::getPatternMatchCoreName(const std::string &coreName)
+{
+ ocsd_arch_profile_t ap = { ARCH_UNKNOWN, profile_Unknown };
+ size_t pos;
+
+ /* look for ARMvM[.m]-P */
+ pos = coreName.find("ARMv");
+ if (pos == 0)
+ {
+ int majver = coreName[4] - '0';
+ int minver = 0;
+ int dotoffset = 0;
+
+ pos = coreName.find_first_of(".");
+ if (pos == 5) {
+ minver = coreName[6] - '0';
+ dotoffset = 2;
+ }
+ else if (pos != std::string::npos)
+ return ap;
+
+ if (majver == 7)
+ ap.arch = ARCH_V7;
+ else if (majver >= 8) {
+ ap.arch = ARCH_AA64; /* default to 8.3+*/
+ if (majver == 8) {
+ if (minver < 3)
+ ap.arch = ARCH_V8;
+ else if (minver == 3)
+ ap.arch = ARCH_V8r3;
+ }
+ }
+ else
+ return ap; /* no valid version - return unknown */
+
+ if (coreName.find_first_of("-", 4) == (size_t)(5 + dotoffset)) {
+ int profile_idx = 6 + dotoffset;
+ if (coreName[profile_idx] == 'A')
+ ap.profile = profile_CortexA;
+ else if (coreName[profile_idx] == 'R')
+ ap.profile = profile_CortexR;
+ else if (coreName[profile_idx] == 'M')
+ ap.profile = profile_CortexM;
+ else
+ ap.arch = ARCH_UNKNOWN; /*reset arch, return unknown*/
+ }
+ else
+ ap.arch = ARCH_UNKNOWN; /*reset arch, return unknown*/
+ return ap;
+ }
+
+ /* look for ARM-{AA|aa}64[-P] */
+ pos = coreName.find("ARM-");
+ if (pos == 0)
+ {
+ pos = coreName.find("aa64");
+ if (pos != 4)
+ pos = coreName.find("AA64");
+ if (pos == 4)
+ {
+ ap.arch = ARCH_AA64;
+ ap.profile = profile_CortexA;
+ if (coreName.find_first_of("-", 7) == 8) {
+ if (coreName[9] == 'R')
+ ap.profile = profile_CortexR;
+ else if (coreName[9] == 'M')
+ ap.profile = profile_CortexM;
+ }
+ }
+ }
+ return ap;
+}
+/* End of File trc_core_arch_map.cpp */
diff --git a/decoder/source/trc_frame_deformatter.cpp b/decoder/source/trc_frame_deformatter.cpp
new file mode 100644
index 0000000..3b2aead
--- /dev/null
+++ b/decoder/source/trc_frame_deformatter.cpp
@@ -0,0 +1,970 @@
+/*
+ * \file trc_frame_deformatter.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <cstring>
+
+#include "common/trc_frame_deformatter.h"
+#include "trc_frame_deformatter_impl.h"
+
+/***************************************************************/
+/* Implementation */
+/***************************************************************/
+
+#ifdef __GNUC__
+// G++ doesn't like the ## pasting
+#define DEFORMATTER_NAME "DFMT_CSFRAMES"
+#else
+// VC is fine
+#define DEFORMATTER_NAME OCSD_CMPNAME_PREFIX_FRAMEDEFORMATTER##"_CSFRAMES"
+#endif
+
+TraceFmtDcdImpl::TraceFmtDcdImpl() : TraceComponent(DEFORMATTER_NAME),
+ m_cfgFlags(0),
+ m_force_sync_idx(0),
+ m_use_force_sync(false),
+ m_alignment(16), // assume frame aligned data as default.
+ m_b_output_packed_raw(false),
+ m_b_output_unpacked_raw(false),
+ m_pStatsBlock(0)
+
+{
+ resetStateParams();
+ setRawChanFilterAll(true);
+}
+
+TraceFmtDcdImpl::TraceFmtDcdImpl(int instNum) : TraceComponent(DEFORMATTER_NAME, instNum),
+ m_cfgFlags(0),
+ m_force_sync_idx(0),
+ m_use_force_sync(false),
+ m_alignment(16)
+{
+ resetStateParams();
+ setRawChanFilterAll(true);
+}
+
+TraceFmtDcdImpl::~TraceFmtDcdImpl()
+{
+}
+
+ocsd_datapath_resp_t TraceFmtDcdImpl::TraceDataIn(
+ const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_FATAL_INVALID_OP;
+ InitCollateDataPathResp();
+
+ m_b_output_packed_raw = m_RawTraceFrame.num_attached() && ((m_cfgFlags & OCSD_DFRMTR_PACKED_RAW_OUT) != 0);
+ m_b_output_unpacked_raw = m_RawTraceFrame.num_attached() && ((m_cfgFlags & OCSD_DFRMTR_UNPACKED_RAW_OUT) != 0);
+
+ switch(op)
+ {
+ case OCSD_OP_RESET:
+ resp = Reset();
+ break;
+
+ case OCSD_OP_FLUSH:
+ resp = Flush();
+ break;
+
+ case OCSD_OP_EOT:
+ // local 'flush' here?
+ // pass on EOT to connected ID streams
+ resp = executeNoneDataOpAllIDs(OCSD_OP_EOT);
+ break;
+
+ case OCSD_OP_DATA:
+ if((dataBlockSize <= 0) || ( pDataBlock == 0) || (numBytesProcessed == 0))
+ resp = OCSD_RESP_FATAL_INVALID_PARAM;
+ else
+ resp = processTraceData(index,dataBlockSize, pDataBlock, numBytesProcessed);
+ break;
+
+ default:
+ break;
+ }
+
+ return resp;
+}
+
+/* enable / disable ID streams - default as all enabled */
+ocsd_err_t TraceFmtDcdImpl::OutputFilterIDs(std::vector<uint8_t> &id_list, bool bEnable)
+{
+ ocsd_err_t err = OCSD_OK;
+ std::vector<uint8_t>::iterator iter = id_list.begin();
+ uint8_t id = 0;
+
+ while((iter < id_list.end()) && (err == OCSD_OK))
+ {
+ id = *iter;
+ if(id > 128)
+ err = OCSD_ERR_INVALID_ID;
+ else
+ {
+ m_IDStreams[id].set_enabled(bEnable);
+ m_raw_chan_enable[id] = bEnable;
+ }
+ iter++;
+ }
+ return err;
+}
+
+ocsd_err_t TraceFmtDcdImpl::OutputFilterAllIDs(bool bEnable)
+{
+ for(uint8_t id = 0; id < 128; id++)
+ {
+ m_IDStreams[id].set_enabled(bEnable);
+ }
+ setRawChanFilterAll(bEnable);
+ return OCSD_OK;
+}
+
+void TraceFmtDcdImpl::setRawChanFilterAll(bool bEnable)
+{
+ for(int i=0; i<128; i++)
+ {
+ m_raw_chan_enable[i] = bEnable;
+ }
+}
+
+const bool TraceFmtDcdImpl::rawChanEnabled(const uint8_t id) const
+{
+ if(id < 128)
+ return m_raw_chan_enable[id];
+ return false;
+}
+
+/* decode control */
+ocsd_datapath_resp_t TraceFmtDcdImpl::Reset()
+{
+ resetStateParams();
+ InitCollateDataPathResp();
+ return executeNoneDataOpAllIDs(OCSD_OP_RESET);
+}
+
+ocsd_datapath_resp_t TraceFmtDcdImpl::Flush()
+{
+ executeNoneDataOpAllIDs(OCSD_OP_FLUSH); // flush any upstream data.
+ if(dataPathCont())
+ outputFrame(); // try to flush any partial frame data remaining
+ return highestDataPathResp();
+}
+
+ocsd_datapath_resp_t TraceFmtDcdImpl::executeNoneDataOpAllIDs(ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index /* = 0*/)
+{
+ ITrcDataIn *pTrcComp = 0;
+ for(uint8_t id = 0; id < 128; id++)
+ {
+ if(m_IDStreams[id].num_attached())
+ {
+ pTrcComp = m_IDStreams[id].first();
+ while(pTrcComp)
+ {
+ CollateDataPathResp(pTrcComp->TraceDataIn(op,index,0,0,0));
+ pTrcComp = m_IDStreams[id].next();
+ }
+ }
+ }
+
+ if( m_RawTraceFrame.num_attached())
+ {
+ if(m_RawTraceFrame.first())
+ m_RawTraceFrame.first()->TraceRawFrameIn(op,0,OCSD_FRM_NONE,0,0,0);
+ }
+ return highestDataPathResp();
+}
+
+void TraceFmtDcdImpl::outputRawMonBytes(const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const ocsd_rawframe_elem_t frame_element,
+ const int dataBlockSize,
+ const uint8_t *pDataBlock,
+ const uint8_t traceID)
+{
+ if( m_RawTraceFrame.num_attached())
+ {
+ if(m_RawTraceFrame.first())
+ m_RawTraceFrame.first()->TraceRawFrameIn(op,index,frame_element,dataBlockSize, pDataBlock,traceID);
+ }
+}
+
+void TraceFmtDcdImpl::CollateDataPathResp(const ocsd_datapath_resp_t resp)
+{
+ // simple most severe error across multiple IDs.
+ if(resp > m_highestResp) m_highestResp = resp;
+}
+
+ocsd_datapath_resp_t TraceFmtDcdImpl::processTraceData(
+ const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed
+ )
+{
+ try {
+
+ if(!m_first_data) // is this the initial data block?
+ {
+ m_trc_curr_idx = index;
+ }
+ else
+ {
+ if(m_trc_curr_idx != index) // none continuous trace data - throw an error.
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_DFMTR_NOTCONTTRACE,index);
+ }
+
+ // record the incoming block for extraction routines to use.
+ m_in_block_base = pDataBlock;
+ m_in_block_size = dataBlockSize;
+ m_in_block_processed = 0;
+
+ if(dataBlockSize % m_alignment) // must be correctly aligned data
+ {
+ ocsdError err(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PARAM_VAL);
+ char msg_buffer[64];
+ sprintf(msg_buffer,"Input block incorrect size, must be %d byte multiple", m_alignment);
+ err.setMessage(msg_buffer);
+ throw ocsdError(&err);
+ }
+
+ // processing loop...
+ if(checkForSync())
+ {
+ bool bProcessing = true;
+ while(bProcessing)
+ {
+ bProcessing = extractFrame(); // will stop on end of input data.
+ if(bProcessing)
+ bProcessing = unpackFrame();
+ if(bProcessing)
+ bProcessing = outputFrame(); // will stop on data path halt.
+ }
+ }
+ }
+ catch(const ocsdError &err) {
+ LogError(err);
+ CollateDataPathResp(OCSD_RESP_FATAL_INVALID_DATA);
+ }
+ catch(...) {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_FAIL));
+ CollateDataPathResp(OCSD_RESP_FATAL_SYS_ERR);
+ }
+
+ if(!m_first_data)
+ m_first_data = true;
+
+ // update the outputs.
+ *numBytesProcessed = m_in_block_processed;
+
+ return highestDataPathResp();
+}
+
+ocsd_err_t TraceFmtDcdImpl::DecodeConfigure(uint32_t flags)
+{
+ const char *pszErrMsg = "";
+ ocsd_err_t err = OCSD_OK;
+
+ if((flags & ~OCSD_DFRMTR_VALID_MASK) != 0)
+ {
+ err = OCSD_ERR_INVALID_PARAM_VAL;
+ pszErrMsg = "Unknown Config Flags";
+ }
+
+ if((flags & OCSD_DFRMTR_VALID_MASK) == 0)
+ {
+ err = OCSD_ERR_INVALID_PARAM_VAL;
+ pszErrMsg = "No Config Flags Set";
+ }
+
+ if((flags & (OCSD_DFRMTR_HAS_FSYNCS | OCSD_DFRMTR_HAS_HSYNCS)) &&
+ (flags & OCSD_DFRMTR_FRAME_MEM_ALIGN)
+ )
+ {
+ err = OCSD_ERR_INVALID_PARAM_VAL;
+ pszErrMsg = "Invalid Config Flag Combination Set";
+ }
+
+ if(err != OCSD_OK)
+ {
+ ocsdError errObj(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL);
+ errObj.setMessage(pszErrMsg);
+ LogError(errObj);
+ }
+ else
+ {
+ // alightment is the multiple of bytes the buffer size must be.
+ m_cfgFlags = flags;
+
+ // using memory aligned buffers, the formatter always outputs 16 byte frames so enforce
+ // this on the input
+ m_alignment = 16;
+ // if we have HSYNCS then always align to 2 byte buffers
+ if(flags & OCSD_DFRMTR_HAS_HSYNCS)
+ m_alignment = 2;
+ // otherwise FSYNCS only can have 4 byte aligned buffers.
+ else if(flags & OCSD_DFRMTR_HAS_FSYNCS)
+ m_alignment = 4;
+ }
+ return err;
+}
+
+void TraceFmtDcdImpl::resetStateParams()
+{
+ // overall dynamic state - intra frame
+ m_trc_curr_idx = OCSD_BAD_TRC_INDEX; /* source index of current trace data */
+ m_frame_synced = false;
+ m_first_data = false;
+ m_curr_src_ID = OCSD_BAD_CS_SRC_ID;
+
+ // current frame processing
+ m_ex_frm_n_bytes = 0;
+ m_b_fsync_start_eob = false;
+ m_trc_curr_idx_sof = OCSD_BAD_TRC_INDEX;
+}
+
+bool TraceFmtDcdImpl::checkForSync()
+{
+ // we can sync on:-
+ // 16 byte alignment - standard input buffers such as ETB
+ // FSYNC packets in the stream
+ // forced index programmed into the object.
+ uint32_t unsynced_bytes = 0;
+
+ if(!m_frame_synced)
+ {
+ if(m_use_force_sync)
+ {
+ // is the force sync point in this block?
+ if((m_force_sync_idx >= m_trc_curr_idx) && (m_force_sync_idx < (m_trc_curr_idx + m_in_block_size)))
+ {
+ unsynced_bytes = m_force_sync_idx - m_trc_curr_idx;
+ m_frame_synced = true;
+ }
+ else
+ {
+ unsynced_bytes = m_in_block_size;
+ }
+ }
+ else if( m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) // memory aligned data
+ {
+ unsynced_bytes = findfirstFSync();
+
+ }
+ else
+ {
+ // OCSD_DFRMTR_FRAME_MEM_ALIGN - this has guaranteed 16 byte frame size and alignment.
+ m_frame_synced = true;
+ }
+
+ if(unsynced_bytes)
+ {
+ outputUnsyncedBytes(unsynced_bytes);
+ m_in_block_processed = unsynced_bytes;
+ m_trc_curr_idx += unsynced_bytes;
+ }
+ }
+ return m_frame_synced;
+}
+
+uint32_t TraceFmtDcdImpl::findfirstFSync()
+{
+ uint32_t processed = 0;
+ const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC
+ const uint8_t *dataPtr = m_in_block_base;
+
+ while (processed < (m_in_block_size - 3))
+ {
+ if (*((uint32_t *)(dataPtr)) == FSYNC_PATTERN)
+ {
+ m_frame_synced = true;
+ break;
+ }
+ processed++;
+ dataPtr++;
+ }
+ return processed;
+}
+
+void TraceFmtDcdImpl::outputUnsyncedBytes(uint32_t /*num_bytes*/)
+{
+ //**TBD:
+}
+
+ocsd_err_t TraceFmtDcdImpl::checkForResetFSyncPatterns(uint32_t &f_sync_bytes)
+{
+ const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC
+ bool check_for_fsync = true;
+ int num_fsyncs = 0;
+ uint32_t bytes_processed = m_in_block_processed;
+ const uint8_t *dataPtr = m_in_block_base + bytes_processed;
+ ocsd_err_t err = OCSD_OK;
+
+ while (check_for_fsync && (bytes_processed < m_in_block_size))
+ {
+ // look for consecutive fsyncs as padding or for reset downstream - both cases will reset downstream....
+ if (*((uint32_t *)(dataPtr)) == FSYNC_PATTERN)
+ {
+ dataPtr += sizeof(uint32_t);
+ num_fsyncs++;
+ bytes_processed += sizeof(uint32_t);
+ }
+ else
+ check_for_fsync = false;
+ }
+
+ if (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
+ {
+ err = OCSD_ERR_DFMTR_BAD_FHSYNC;
+ }
+ }
+ f_sync_bytes += num_fsyncs * 4;
+ return err;
+}
+
+/* Extract a single frame from the input buffer. */
+bool TraceFmtDcdImpl::extractFrame()
+{
+ const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC
+ const uint16_t HSYNC_PATTERN = 0x7FFF; // LE host pattern for HSYNC
+ const uint16_t FSYNC_START = 0xFFFF; // LE host pattern for start 2 bytes of fsync
+
+ ocsd_err_t err;
+ uint32_t f_sync_bytes = 0; // skipped f sync bytes
+ uint32_t h_sync_bytes = 0; // skipped h sync bytes
+ uint32_t ex_bytes = 0; // extracted this pass (may be filling out part frame)
+ uint32_t buf_left = m_in_block_size - m_in_block_processed; // bytes remaining in buffer this pass.
+
+ // last call was end of input block - but carried on to process full frame.
+ // exit early here.
+ if (!buf_left)
+ return false;
+
+ // memory aligned input data is forced to be always multiples of 16 byte frames, aligned to start.
+ if( m_cfgFlags & OCSD_DFRMTR_FRAME_MEM_ALIGN)
+ {
+ // some linux drivers (e.g. for perf) will insert FSYNCS to pad or differentiate
+ // between blocks of aligned data, always in frame aligned complete 16 byte frames.
+ // we need to skip past these frames, resetting as we go.
+ if (m_cfgFlags & OCSD_DFRMTR_RESET_ON_4X_FSYNC)
+ {
+ err = checkForResetFSyncPatterns(f_sync_bytes);
+
+ /* in this case the FSYNC pattern is output on both packed and unpacked cases */
+ if (f_sync_bytes && (m_b_output_packed_raw || m_b_output_unpacked_raw))
+ {
+ outputRawMonBytes(OCSD_OP_DATA,
+ m_trc_curr_idx,
+ OCSD_FRM_FSYNC,
+ f_sync_bytes,
+ m_in_block_base + m_in_block_processed,
+ 0);
+ }
+
+ // throw processing error, none frame size block of fsyncs
+ if (err)
+ throw ocsdError(OCSD_ERR_SEV_ERROR, err, m_trc_curr_idx, "Incorrect FSYNC frame reset pattern");
+
+ buf_left -= f_sync_bytes;
+ }
+
+ if (buf_left)
+ {
+ // always a complete frame - the input data has to be 16 byte multiple alignment.
+ m_ex_frm_n_bytes = OCSD_DFRMTR_FRAME_SIZE;
+ memcpy(m_ex_frm_data, m_in_block_base + m_in_block_processed + f_sync_bytes, m_ex_frm_n_bytes);
+ m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes;
+ ex_bytes = OCSD_DFRMTR_FRAME_SIZE;
+ }
+ }
+ else
+ {
+ // extract data accounting for frame syncs and hsyncs if present.
+ // we know we are aligned at this point - could be FSYNC or HSYNCs here.
+ // HSYNC present, library forces input to be aligned 2 byte multiples
+ // FSYNC - w/o HSYNCs, forces input to be aligned 4 byte multiples.
+
+ // check what we a looking for
+ bool hasFSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) == OCSD_DFRMTR_HAS_FSYNCS);
+ bool hasHSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_HSYNCS) == OCSD_DFRMTR_HAS_HSYNCS);
+
+ const uint8_t* dataPtr = m_in_block_base + m_in_block_processed;
+ uint16_t data_pair_val;
+
+ // can have FSYNCS at start of frame (in middle is an error).
+ if (hasFSyncs && (m_ex_frm_n_bytes == 0))
+ {
+ // was there an fsync start at the end of the last buffer?
+ if (m_b_fsync_start_eob) {
+ // last 2 of FSYNC look like HSYNC
+ if (*(uint16_t*)(dataPtr) != HSYNC_PATTERN)
+ {
+ // this means 0xFFFF followed by something else - invalid ID + ????
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC pattern before frame or invalid ID.(0x7F)");
+ }
+ else
+ {
+ f_sync_bytes += 2;
+ buf_left -= 2;
+ dataPtr += 2;
+ }
+ m_b_fsync_start_eob = false;
+ }
+
+ // regular fsync checks
+ while ((buf_left >= 4) && (*((uint32_t*)(dataPtr)) == FSYNC_PATTERN))
+ {
+ f_sync_bytes += 4;
+ dataPtr += 4;
+ buf_left -= 4;
+ }
+
+ // handle possible part fsync at the end of a buffer
+ if (buf_left == 2)
+ {
+ if (*(uint16_t*)(dataPtr) == FSYNC_START)
+ {
+ f_sync_bytes += 2;
+ buf_left -= 2;
+ dataPtr += 2;
+ m_b_fsync_start_eob = true;
+ }
+ }
+ }
+
+ // process remaining data in pairs of bytes
+ while ((m_ex_frm_n_bytes < OCSD_DFRMTR_FRAME_SIZE) && buf_left)
+ {
+ // mark start of frame after FSyncs
+ if (m_ex_frm_n_bytes == 0)
+ 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];
+
+ data_pair_val = *((uint16_t*)(dataPtr));
+
+ // check pair is not HSYNC
+ if (data_pair_val == HSYNC_PATTERN)
+ {
+ if (hasHSyncs)
+ {
+ h_sync_bytes += 2;
+ }
+ else
+ {
+ // throw illegal HSYNC error.
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad HSYNC in frame.");
+ }
+ }
+ // can't have a start of FSYNC here / illegal trace ID
+ else if (data_pair_val == FSYNC_START)
+ {
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC start in frame or invalid ID (0x7F).");
+ }
+ else
+ {
+ m_ex_frm_n_bytes += 2;
+ ex_bytes += 2;
+ }
+
+ buf_left -= 2;
+ dataPtr += 2;
+ }
+ }
+
+ // 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) || (buf_left == 0)) && m_b_output_packed_raw)
+ {
+ outputRawMonBytes( OCSD_OP_DATA,
+ m_trc_curr_idx,
+ OCSD_FRM_PACKED,
+ total_processed,
+ m_in_block_base+m_in_block_processed,
+ 0);
+ }
+
+ // update the processed count for the buffer
+ m_in_block_processed += total_processed;
+
+ // update index past the processed data
+ m_trc_curr_idx += total_processed;
+
+ // update any none trace data byte stats
+ addToFrameStats((uint64_t)(f_sync_bytes + h_sync_bytes));
+
+ // if we are exiting with a full frame then signal processing to continue
+ return (bool)(m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE);
+}
+
+bool TraceFmtDcdImpl::unpackFrame()
+{
+ // unpack cannot fail as never called on incomplete frame.
+ uint8_t frameFlagBit = 0x1;
+ uint8_t newSrcID = OCSD_BAD_CS_SRC_ID;
+ bool PrevIDandIDChange = false;
+ uint64_t noneDataBytes = 0;
+
+ // init output processing
+ m_out_data_idx = 0;
+ m_out_processed = 0;
+
+ // set up first out data packet...
+ m_out_data[m_out_data_idx].id = m_curr_src_ID;
+ m_out_data[m_out_data_idx].valid = 0;
+ m_out_data[m_out_data_idx].index = m_trc_curr_idx_sof;
+ m_out_data[m_out_data_idx].used = 0;
+
+ // work on byte pairs - bytes 0 - 13.
+ for(int i = 0; i < 14; i+=2)
+ {
+ PrevIDandIDChange = false;
+
+ // it's an ID + data
+ if(m_ex_frm_data[i] & 0x1)
+ {
+ newSrcID = (m_ex_frm_data[i] >> 1) & 0x7f;
+ if(newSrcID != m_curr_src_ID) // ID change
+ {
+ PrevIDandIDChange = ((frameFlagBit & m_ex_frm_data[15]) != 0);
+
+ // following byte for old id?
+ if(PrevIDandIDChange)
+ // 2nd byte always data
+ m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i+1];
+
+ // change ID
+ m_curr_src_ID = newSrcID;
+
+ // if we already have data in this buffer
+ if(m_out_data[m_out_data_idx].valid > 0)
+ {
+ m_out_data_idx++; // move to next buffer
+ m_out_data[m_out_data_idx].valid = 0;
+ m_out_data[m_out_data_idx].used = 0;
+ m_out_data[m_out_data_idx].index = m_trc_curr_idx_sof + i;
+ }
+
+ // set new ID on buffer
+ m_out_data[m_out_data_idx].id = m_curr_src_ID;
+
+ /// TBD - ID indexing in here.
+ }
+ noneDataBytes++;
+ }
+ else
+ // it's just data
+ {
+ m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0);
+ }
+
+ // 2nd byte always data
+ if(!PrevIDandIDChange) // output only if we didn't for an ID change + prev ID.
+ m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i+1];
+
+ frameFlagBit <<= 1;
+ }
+
+ // unpack byte 14;
+
+ // it's an ID
+ if(m_ex_frm_data[14] & 0x1)
+ {
+ // no matter if change or not, no associated data in byte 15 anyway so just set.
+ m_curr_src_ID = (m_ex_frm_data[14] >> 1) & 0x7f;
+ noneDataBytes++;
+ }
+ // it's data
+ else
+ {
+ m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[14] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0);
+ }
+ m_ex_frm_n_bytes = 0; // mark frame as empty;
+
+ noneDataBytes++; // byte 15 is always non-data.
+ addToFrameStats(noneDataBytes); // update the non data byte stats.
+ return true;
+}
+
+// output data to channels.
+bool TraceFmtDcdImpl::outputFrame()
+{
+ bool cont_processing = true;
+ ITrcDataIn *pDataIn = 0;
+ uint32_t bytes_used;
+
+ // output each valid ID within the frame - stopping if we get a wait or error
+ while((m_out_processed < (m_out_data_idx + 1)) && cont_processing)
+ {
+
+ // may have data prior to a valid ID appearing
+ if(m_out_data[m_out_processed].id != OCSD_BAD_CS_SRC_ID)
+ {
+ if((pDataIn = m_IDStreams[m_out_data[m_out_processed].id].first()) != 0)
+ {
+ // log the stuff we are about to put out early so as to make it visible before interpretation
+ // however, don't re-output if only part used first time round.
+ if(m_b_output_unpacked_raw && (m_out_data[m_out_processed].used == 0) && rawChanEnabled( m_out_data[m_out_processed].id))
+ {
+ outputRawMonBytes( OCSD_OP_DATA,
+ m_out_data[m_out_processed].index,
+ OCSD_FRM_ID_DATA,
+ m_out_data[m_out_processed].valid,
+ m_out_data[m_out_processed].data,
+ m_out_data[m_out_processed].id);
+ }
+
+ // output to the connected packet process
+ CollateDataPathResp(pDataIn->TraceDataIn(OCSD_OP_DATA,
+ m_out_data[m_out_processed].index + m_out_data[m_out_processed].used,
+ m_out_data[m_out_processed].valid - m_out_data[m_out_processed].used,
+ m_out_data[m_out_processed].data + m_out_data[m_out_processed].used,
+ &bytes_used));
+
+ addToIDStats((uint64_t)bytes_used);
+
+ if(!dataPathCont())
+ {
+ cont_processing = false;
+ m_out_data[m_out_processed].used += bytes_used;
+ if(m_out_data[m_out_processed].used == m_out_data[m_out_processed].valid)
+ m_out_processed++; // we have used up all this data.
+ }
+ else
+ {
+ m_out_processed++; // we have sent this data;
+ }
+ }
+ else
+ {
+ // optional raw output for debugging / monitor tools
+ if(m_b_output_unpacked_raw && rawChanEnabled( m_out_data[m_out_processed].id))
+ {
+ outputRawMonBytes( OCSD_OP_DATA,
+ m_out_data[m_out_processed].index,
+ OCSD_FRM_ID_DATA,
+ m_out_data[m_out_processed].valid,
+ m_out_data[m_out_processed].data,
+ m_out_data[m_out_processed].id);
+ }
+
+ if (isReservedID(m_out_data[m_out_processed].id))
+ addToReservedIDStats((uint64_t)m_out_data[m_out_processed].valid);
+ else
+ addToNoIDStats((uint64_t)m_out_data[m_out_processed].valid);
+ m_out_processed++; // skip past this data.
+ }
+ }
+ else
+ {
+ // optional raw output for debugging / monitor tools of unknown src ID data
+ if(m_b_output_unpacked_raw)
+ {
+ outputRawMonBytes( OCSD_OP_DATA,
+ m_out_data[m_out_processed].index,
+ OCSD_FRM_ID_DATA,
+ m_out_data[m_out_processed].valid,
+ m_out_data[m_out_processed].data,
+ m_out_data[m_out_processed].id);
+ }
+ addToUnknownIDStats((uint64_t)m_out_data[m_out_processed].valid);
+ m_out_processed++; // skip past this data.
+ }
+ }
+ return cont_processing;
+}
+
+void TraceFmtDcdImpl::addToIDStats(uint64_t val)
+{
+ if (m_pStatsBlock)
+ m_pStatsBlock->valid_id_bytes += val;
+}
+
+void TraceFmtDcdImpl::addToNoIDStats(uint64_t val)
+{
+ if (m_pStatsBlock)
+ m_pStatsBlock->no_id_bytes += val;
+}
+
+void TraceFmtDcdImpl::addToFrameStats(uint64_t val)
+{
+ if (m_pStatsBlock)
+ m_pStatsBlock->frame_bytes += val;
+}
+
+void TraceFmtDcdImpl::addToUnknownIDStats(uint64_t val)
+{
+ if (m_pStatsBlock)
+ m_pStatsBlock->unknown_id_bytes += val;
+}
+
+void TraceFmtDcdImpl::addToReservedIDStats(uint64_t val)
+{
+ if (m_pStatsBlock)
+ m_pStatsBlock->reserved_id_bytes += val;
+}
+
+/***************************************************************/
+/* interface */
+/***************************************************************/
+TraceFormatterFrameDecoder::TraceFormatterFrameDecoder() : m_pDecoder(0)
+{
+ m_instNum = -1;
+}
+
+TraceFormatterFrameDecoder::TraceFormatterFrameDecoder(int instNum) : m_pDecoder(0)
+{
+ m_instNum = instNum;
+}
+
+TraceFormatterFrameDecoder::~TraceFormatterFrameDecoder()
+{
+ if(m_pDecoder)
+ {
+ delete m_pDecoder;
+ m_pDecoder = 0;
+ }
+}
+
+ /* the data input interface from the reader / source */
+ocsd_datapath_resp_t TraceFormatterFrameDecoder::TraceDataIn( const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed);
+}
+
+/* attach a data processor to a stream ID output */
+componentAttachPt<ITrcDataIn> *TraceFormatterFrameDecoder::getIDStreamAttachPt(uint8_t ID)
+{
+ componentAttachPt<ITrcDataIn> *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<ITrcRawFrameIn> *TraceFormatterFrameDecoder::getTrcRawFrameAttachPt()
+{
+ return (m_pDecoder != 0) ? &m_pDecoder->m_RawTraceFrame : 0;
+}
+
+
+componentAttachPt<ITrcSrcIndexCreator> *TraceFormatterFrameDecoder::getTrcSrcIndexAttachPt()
+{
+ return (m_pDecoder != 0) ? &m_pDecoder->m_SrcIndexer : 0;
+}
+
+componentAttachPt<ITraceErrorLog> *TraceFormatterFrameDecoder::getErrLogAttachPt()
+{
+ return (m_pDecoder != 0) ? m_pDecoder->getErrorLogAttachPt() : 0;
+}
+
+ocsd_err_t TraceFormatterFrameDecoder::Init()
+{
+ 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;
+ }
+ return OCSD_OK;
+}
+
+/* configuration - set operational mode for incoming stream (has FSYNCS etc) */
+ocsd_err_t TraceFormatterFrameDecoder::Configure(uint32_t cfg_flags)
+{
+ if (!m_pDecoder)
+ return OCSD_ERR_NOT_INIT;
+ return m_pDecoder->DecodeConfigure(cfg_flags);
+}
+
+const uint32_t TraceFormatterFrameDecoder::getConfigFlags() const
+{
+ uint32_t flags = 0;
+ if(m_pDecoder)
+ flags = m_pDecoder->m_cfgFlags;
+ return flags;
+}
+
+
+/* enable / disable ID streams - default as all enabled */
+ocsd_err_t TraceFormatterFrameDecoder::OutputFilterIDs(std::vector<uint8_t> &id_list, bool bEnable)
+{
+ return (m_pDecoder == 0) ? OCSD_ERR_NOT_INIT : m_pDecoder->OutputFilterIDs(id_list,bEnable);
+}
+
+ocsd_err_t TraceFormatterFrameDecoder::OutputFilterAllIDs(bool bEnable)
+{
+ return (m_pDecoder == 0) ? OCSD_ERR_NOT_INIT : m_pDecoder->OutputFilterAllIDs(bEnable);
+}
+
+/* decode control */
+ocsd_datapath_resp_t TraceFormatterFrameDecoder::Reset()
+{
+ return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Reset();
+}
+
+ocsd_datapath_resp_t TraceFormatterFrameDecoder::Flush()
+{
+ return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Flush();
+}
+
+void TraceFormatterFrameDecoder::SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock)
+{
+ if (m_pDecoder)
+ m_pDecoder->SetDemuxStatsBlock(pStatsBlock);
+}
+
+/* End of File trc_frame_deformatter.cpp */
diff --git a/decoder/source/trc_frame_deformatter_impl.h b/decoder/source/trc_frame_deformatter_impl.h
new file mode 100644
index 0000000..3571d5f
--- /dev/null
+++ b/decoder/source/trc_frame_deformatter_impl.h
@@ -0,0 +1,185 @@
+/*
+ * \file trc_frame_decoder_impl.h
+ * \brief OpenCSD : Trace Deformatter implementation.
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ARM_TRC_FRAME_DECODER_IMPL_H_INCLUDED
+#define ARM_TRC_FRAME_DECODER_IMPL_H_INCLUDED
+
+#include "opencsd/ocsd_if_types.h"
+#include "common/comp_attach_pt_t.h"
+#include "interfaces/trc_data_raw_in_i.h"
+#include "interfaces/trc_data_rawframe_in_i.h"
+#include "interfaces/trc_indexer_src_i.h"
+#include "common/trc_component.h"
+
+//! output data fragment from the current frame - collates bytes associated with an ID.
+typedef struct _out_chan_data {
+ ocsd_trc_index_t index; //!< trace source index for start of these bytes
+ uint8_t id; //!< Id for these bytes
+ uint8_t data[15]; //!< frame data bytes for this ID
+ uint32_t valid; //!< Valid data bytes.
+ uint32_t used; //!< Data bytes output (used by attached processor).
+} out_chan_data;
+
+class TraceFmtDcdImpl : public TraceComponent, ITrcDataIn
+{
+private:
+ TraceFmtDcdImpl();
+ TraceFmtDcdImpl(int instNum);
+ virtual ~TraceFmtDcdImpl();
+
+ /* the data input interface from the reader */
+ virtual ocsd_datapath_resp_t TraceDataIn( const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed);
+
+ /* enable / disable ID streams - default as all enabled */
+ ocsd_err_t OutputFilterIDs(std::vector<uint8_t> &id_list, bool bEnable);
+ ocsd_err_t OutputFilterAllIDs(bool bEnable);
+
+ /* decode control */
+ ocsd_datapath_resp_t Reset(); /* reset the decode to the start state, drop partial data - propogate to attached components */
+ ocsd_datapath_resp_t Flush();
+ ocsd_err_t DecodeConfigure(uint32_t flags);
+ ocsd_err_t SetForcedSyncIndex(ocsd_trc_index_t index, bool bSet);
+
+ void SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock) { m_pStatsBlock = pStatsBlock; };
+
+private:
+ ocsd_datapath_resp_t executeNoneDataOpAllIDs(ocsd_datapath_op_t op, const ocsd_trc_index_t index = 0);
+ ocsd_datapath_resp_t processTraceData(const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed);
+ // process phases
+ bool checkForSync(); // find the sync point in the incoming block
+ bool extractFrame(); // extract the frame data from incoming stream
+ bool unpackFrame(); // process a complete frame.
+ bool outputFrame(); // output data to channels.
+
+
+ // managing data path responses.
+ void InitCollateDataPathResp() { m_highestResp = OCSD_RESP_CONT; };
+ void CollateDataPathResp(const ocsd_datapath_resp_t resp);
+ const ocsd_datapath_resp_t highestDataPathResp() const { return m_highestResp; };
+ const bool dataPathCont() const { return (bool)(m_highestResp < OCSD_RESP_WAIT); };
+
+ // deformat state
+ void resetStateParams();
+
+ // synchronisation
+ uint32_t findfirstFSync();
+ void outputUnsyncedBytes(uint32_t num_bytes); // output bytes as unsynced from current buffer position.
+
+ // output bytes to raw frame monitor
+ void outputRawMonBytes(const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index,
+ const ocsd_rawframe_elem_t frame_element,
+ const int dataBlockSize,
+ const uint8_t *pDataBlock,
+ const uint8_t traceID);
+
+
+ void setRawChanFilterAll(bool bEnable);
+ const bool rawChanEnabled(const uint8_t id) const;
+
+ ocsd_err_t checkForResetFSyncPatterns(uint32_t &f_sync_bytes);
+
+ friend class TraceFormatterFrameDecoder;
+
+ // stats updates
+ void addToIDStats(uint64_t val);
+ void addToNoIDStats(uint64_t val);
+ void addToFrameStats(uint64_t val);
+ void addToUnknownIDStats(uint64_t val);
+ void addToReservedIDStats(uint64_t val);
+
+ bool isReservedID(uint8_t ID) { return ((ID == 0) || (ID >= 0x70)); };
+
+ // attachment points
+ componentAttachPt<ITrcDataIn> m_IDStreams[128];
+ componentAttachPt<ITrcRawFrameIn> m_RawTraceFrame;
+
+ componentAttachPt<ITrcSrcIndexCreator> m_SrcIndexer;
+
+
+ ocsd_datapath_resp_t m_highestResp;
+
+ /* static configuration */
+ uint32_t m_cfgFlags; /* configuration flags */
+ ocsd_trc_index_t m_force_sync_idx;
+ bool m_use_force_sync;
+ uint32_t m_alignment;
+
+ /* dynamic state */
+ ocsd_trc_index_t m_trc_curr_idx; /* index of current trace data */
+ bool m_frame_synced;
+ bool m_first_data;
+ uint8_t m_curr_src_ID;
+
+ // incoming frame buffer
+ uint8_t m_ex_frm_data[OCSD_DFRMTR_FRAME_SIZE]; // buffer the current frame in case we have to stop part way through
+ int m_ex_frm_n_bytes; // number of valid bytes in the current frame (extraction)
+ bool m_b_fsync_start_eob; // flag to indicate that the end of the last buffer was a pair of bytes
+ // (0xffff) that could only validly be the start and FSYNC.
+ ocsd_trc_index_t m_trc_curr_idx_sof; // trace source index at start of frame.
+
+ /* channel output data - can never be more than a frame of data for a single ID.
+ * 8 possible ID changes per frame. Although the final one can have no associated data, a pathological
+ * case exists with 7 ID changes, all data associated with a previous frame, except for last
+ * ID / data byte which is data. Not possible with normal hardware but guard against corrupt input.
+ */
+ out_chan_data m_out_data[8]; // output data for a given ID
+ int m_out_data_idx; // number of out_chan_data frames used.
+ int m_out_processed; // number of complete out_chan_data frames output.
+
+ /* local copy of input buffer pointers*/
+ const uint8_t *m_in_block_base;
+ uint32_t m_in_block_size;
+ uint32_t m_in_block_processed;
+
+ /* raw output options */
+ bool m_b_output_packed_raw;
+ bool m_b_output_unpacked_raw;
+
+ bool m_raw_chan_enable[128];
+
+ ocsd_demux_stats_t *m_pStatsBlock;
+};
+
+
+#endif // ARM_TRC_FRAME_DECODER_IMPL_H_INCLUDED
+
+/* End of File trc_frame_decoder_impl.h */
diff --git a/decoder/source/trc_gen_elem.cpp b/decoder/source/trc_gen_elem.cpp
new file mode 100644
index 0000000..b2e6772
--- /dev/null
+++ b/decoder/source/trc_gen_elem.cpp
@@ -0,0 +1,311 @@
+/*
+ * \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 <string>
+#include <sstream>
+#include <iomanip>
+
+static const char *s_elem_descs[][2] =
+{
+ {"OCSD_GEN_TRC_ELEM_UNKNOWN","Unknown trace element - default value or indicate error in stream to client."},
+ {"OCSD_GEN_TRC_ELEM_NO_SYNC","Waiting for sync - either at start of decode, or after overflow / bad packet"},
+ {"OCSD_GEN_TRC_ELEM_TRACE_ON","Start of trace - beginning of elements or restart after discontinuity (overflow, trace filtering)."},
+ {"OCSD_GEN_TRC_ELEM_EO_TRACE","End of the available trace in the buffer."},
+ {"OCSD_GEN_TRC_ELEM_PE_CONTEXT","PE status update / change (arch, ctxtid, vmid etc)."},
+ {"OCSD_GEN_TRC_ELEM_INSTR_RANGE","Traced N consecutive instructions from addr (no intervening events or data elements), may have data assoc key"},
+ {"OCSD_GEN_TRC_ELEM_I_RANGE_NOPATH","Traced N instructions in a range, but incomplete information as to program execution path from start to end of range"},
+ {"OCSD_GEN_TRC_ELEM_ADDR_NACC","Tracing in inaccessible memory area."},
+ {"OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN","Tracing unknown address area."},
+ {"OCSD_GEN_TRC_ELEM_EXCEPTION","Exception"},
+ {"OCSD_GEN_TRC_ELEM_EXCEPTION_RET","Exception return"},
+ {"OCSD_GEN_TRC_ELEM_TIMESTAMP","Timestamp - preceding elements happeded before this time."},
+ {"OCSD_GEN_TRC_ELEM_CYCLE_COUNT","Cycle count - cycles since last cycle count value - associated with a preceding instruction range."},
+ {"OCSD_GEN_TRC_ELEM_EVENT","Event - numbered event or trigger"},
+ {"OCSD_GEN_TRC_ELEM_SWTRACE","Software trace packet - may contain data payload."},
+ {"OCSD_GEN_TRC_ELEM_SYNC_MARKER","Synchronisation marker - marks position in stream of an element that is output later."},
+ {"OCSD_GEN_TRC_ELEM_MEMTRANS","Trace indication of transactional memory operations."},
+ {"OCSD_GEN_TRC_ELEM_CUSTOM","Fully custom packet type."}
+};
+
+static const char *instr_type[] = {
+ "--- ",
+ "BR ",
+ "iBR ",
+ "ISB ",
+ "DSB.DMB",
+ "WFI.WFE",
+ "TSTART"
+};
+
+#define T_SIZE (sizeof(instr_type) / sizeof(const char *))
+
+static const char *instr_sub_type[] = {
+ "--- ",
+ "b+link ",
+ "A64:ret ",
+ "A64:eret ",
+ "V7:impl ret",
+};
+
+#define ST_SIZE (sizeof(instr_sub_type) / sizeof(const char *))
+
+static const char *s_trace_on_reason[] = {
+ "begin or filter",
+ "overflow",
+ "debug restart"
+};
+
+
+static const char *s_isa_str[] = {
+ "A32", /**< V7 ARM 32, V8 AArch32 */
+ "T32", /**< Thumb2 -> 16/32 bit instructions */
+ "A64", /**< V8 AArch64 */
+ "TEE", /**< Thumb EE - unsupported */
+ "Jaz", /**< Jazelle - unsupported in trace */
+ "Cst", /**< ISA custom */
+ "Unk" /**< ISA not yet known */
+};
+
+static const char *s_unsync_reason[] = {
+ "undefined", // UNSYNC_UNKNOWN - unknown /undefined
+ "init-decoder", // UNSYNC_INIT_DECODER - decoder intialisation - start of trace.
+ "reset-decoder", // UNSYNC_RESET_DECODER - decoder reset.
+ "overflow", // UNSYNC_OVERFLOW - overflow packet - need to re-sync
+ "discard", // UNSYNC_DISCARD - specl trace discard - need to re-sync
+ "bad-packet", // UNSYNC_BAD_PACKET - bad packet at input - resync to restart.
+ "end-of-trace", // UNSYNC_EOT - end of trace info.
+};
+static const char *s_transaction_type[] = {
+ "Init",
+ "Start",
+ "Commit",
+ "Fail"
+};
+
+static const char *s_marker_t[] = {
+ "Timestamp marker", // ELEM_MARKER_TS
+};
+
+void OcsdTraceElement::toString(std::string &str) const
+{
+ std::ostringstream oss;
+ int num_str = sizeof(s_elem_descs) / sizeof(s_elem_descs[0]);
+ int typeIdx = (int)this->elem_type;
+ if(typeIdx < num_str)
+ {
+ oss << s_elem_descs[typeIdx][0] << "(";
+ switch(elem_type)
+ {
+ case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
+ oss << "exec range=0x" << std::hex << st_addr << ":[0x" << en_addr << "] ";
+ oss << "num_i(" << std::dec << num_instr_range << ") ";
+ oss << "last_sz(" << last_instr_sz << ") ";
+ oss << "(ISA=" << s_isa_str[(int)isa] << ") ";
+ oss << ((last_instr_exec == 1) ? "E " : "N ");
+ if((int)last_i_type < T_SIZE)
+ oss << instr_type[last_i_type];
+ if((last_i_subtype != OCSD_S_INSTR_NONE) && ((int)last_i_subtype < ST_SIZE))
+ oss << instr_sub_type[last_i_subtype];
+ if (last_instr_cond)
+ oss << " <cond>";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_ADDR_NACC:
+ oss << " 0x" << std::hex << st_addr << " ";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_I_RANGE_NOPATH:
+ oss << "first 0x" << std::hex << st_addr << ":[next 0x" << en_addr << "] ";
+ oss << "num_i(" << std::dec << num_instr_range << ") ";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_EXCEPTION:
+ if (excep_ret_addr == 1)
+ {
+ oss << "pref ret addr:0x" << std::hex << en_addr;
+ if (excep_ret_addr_br_tgt)
+ {
+ oss << " [addr also prev br tgt]";
+ }
+ oss << "; ";
+ }
+ oss << "excep num (0x" << std::setfill('0') << std::setw(2) << std::hex << exception_number << ") ";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
+ oss << "(ISA=" << s_isa_str[(int)isa] << ") ";
+ if((context.exception_level > ocsd_EL_unknown) && (context.el_valid))
+ {
+ oss << "EL" << std::dec << (int)(context.exception_level);
+ }
+ switch (context.security_level)
+ {
+ case ocsd_sec_secure: oss << "S; "; break;
+ case ocsd_sec_nonsecure: oss << "N; "; break;
+ case ocsd_sec_root: oss << "Root; "; break;
+ case ocsd_sec_realm: oss << "Realm; "; break;
+ }
+ oss << (context.bits64 ? "64-bit; " : "32-bit; ");
+ if(context.vmid_valid)
+ oss << "VMID=0x" << std::hex << context.vmid << "; ";
+ if(context.ctxt_id_valid)
+ oss << "CTXTID=0x" << std::hex << context.context_id << "; ";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_TRACE_ON:
+ oss << " [" << s_trace_on_reason[trace_on_reason] << "]";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_TIMESTAMP:
+ oss << " [ TS=0x" << std::setfill('0') << std::setw(12) << std::hex << timestamp << "]; ";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_SWTRACE:
+ printSWInfoPkt(oss);
+ break;
+
+ case OCSD_GEN_TRC_ELEM_EVENT:
+ if(trace_event.ev_type == EVENT_TRIGGER)
+ oss << " Trigger; ";
+ else if(trace_event.ev_type == EVENT_NUMBERED)
+ oss << " Numbered:" << std::dec << trace_event.ev_number << "; ";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_EO_TRACE:
+ case OCSD_GEN_TRC_ELEM_NO_SYNC:
+ if (unsync_eot_info <= UNSYNC_EOT)
+ oss << " [" << s_unsync_reason[unsync_eot_info] << "]";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_SYNC_MARKER:
+ oss << " [" << s_marker_t[sync_marker.type] << "(0x" << std::setfill('0') << std::setw(8) << std::hex << sync_marker.value << ")]";
+ break;
+
+ case OCSD_GEN_TRC_ELEM_MEMTRANS:
+ if (mem_trans <= OCSD_MEM_TRANS_FAIL)
+ oss << s_transaction_type[mem_trans];
+ break;
+
+ 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<ocsd_generic_trace_elem*>(this) = *p_elem;
+ return *this;
+}
+
+
+void OcsdTraceElement::printSWInfoPkt(std::ostringstream & oss) const
+{
+ if (!sw_trace_info.swt_global_err)
+ {
+ if (sw_trace_info.swt_id_valid)
+ {
+ oss << " (Ma:0x" << std::setfill('0') << std::setw(2) << std::hex << sw_trace_info.swt_master_id << "; ";
+ oss << "Ch:0x" << std::setfill('0') << std::setw(2) << std::hex << sw_trace_info.swt_channel_id << ") ";
+ }
+ else
+ oss << "(Ma:0x??; Ch:0x??" << ") ";
+
+ if (sw_trace_info.swt_payload_pkt_bitsize > 0)
+ {
+ oss << "0x" << std::setfill('0') << std::hex;
+ if (sw_trace_info.swt_payload_pkt_bitsize == 4)
+ {
+ oss << std::setw(1);
+ oss << (uint16_t)(((uint8_t *)ptr_extended_data)[0] & 0xF);
+ }
+ else
+ {
+ switch (sw_trace_info.swt_payload_pkt_bitsize)
+ {
+ case 8:
+ // force uint8 to uint16 so oss 'sees' them as something to be stringised, rather than absolute char values
+ oss << std::setw(2) << (uint16_t)((uint8_t *)ptr_extended_data)[0];
+ break;
+ case 16:
+ oss << std::setw(4) << ((uint16_t *)ptr_extended_data)[0];
+ break;
+ case 32:
+ oss << std::setw(8) << ((uint32_t *)ptr_extended_data)[0];
+ break;
+ case 64:
+ oss << std::setw(16) << ((uint64_t *)ptr_extended_data)[0];
+ break;
+ default:
+ oss << "{Data Error : unsupported bit width.}";
+ break;
+ }
+ }
+ oss << "; ";
+ }
+ if (sw_trace_info.swt_marker_packet)
+ oss << "+Mrk ";
+ if (sw_trace_info.swt_trigger_event)
+ oss << "Trig ";
+ if (sw_trace_info.swt_has_timestamp)
+ oss << " [ TS=0x" << std::setfill('0') << std::setw(12) << std::hex << timestamp << "]; ";
+ if (sw_trace_info.swt_frequency)
+ oss << "Freq";
+ if (sw_trace_info.swt_master_err)
+ oss << "{Master Error.}";
+ }
+ else
+ {
+ oss << "{Global Error.}";
+ }
+}
+
+/*
+void OcsdTraceElement::toString(const ocsd_generic_trace_elem *p_elem, std::string &str)
+{
+ OcsdTraceElement elem;
+ elem = p_elem;
+ elem.toString(str);
+}
+*/
+/* End of File trc_gen_elem.cpp */
diff --git a/decoder/source/trc_printable_elem.cpp b/decoder/source/trc_printable_elem.cpp
new file mode 100644
index 0000000..2b60c03
--- /dev/null
+++ b/decoder/source/trc_printable_elem.cpp
@@ -0,0 +1,121 @@
+/*
+ * \file trc_printable_elem.cpp
+ * \brief OpenCSD :
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "common/trc_printable_elem.h"
+#include <cassert>
+#include <cstring>
+#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 <cinttypes>
+#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));
+
+ valStr = "0x";
+
+ if(asHex)
+ {
+ int numHexChars = valTotalBitSize / 4;
+ numHexChars += ((valTotalBitSize % 4) > 0) ? 1 : 0;
+
+ int validChars = valValidBits / 4;
+ if((valValidBits % 4) > 0) validChars++;
+ if (validChars < numHexChars)
+ {
+ int QM = numHexChars - validChars;
+ while (QM)
+ {
+ QM--;
+ valStr += "?";
+ }
+ }
+ if(valValidBits > 32)
+ {
+ sprintf(szFormatBuffer,"%%0%dllX",validChars); // create the format
+ sprintf(szStrBuffer,szFormatBuffer,value); // fill the buffer
+ }
+ else
+ {
+ sprintf(szFormatBuffer,"%%0%dlX",validChars); // create the format
+ sprintf(szStrBuffer,szFormatBuffer,(uint32_t)value); // fill the buffer
+ }
+ valStr+=szStrBuffer;
+ if(valValidBits < valTotalBitSize)
+ {
+ sprintf(szStrBuffer," (%d:0)", valValidBits-1);
+ valStr+=szStrBuffer;
+ }
+
+ if(updateBits)
+ {
+ uint64_t updateMask = ~0ULL;
+ updateMask >>= 64-updateBits;
+ sprintf(szStrBuffer," ~[0x%" PRIX64 "]",value & updateMask);
+ valStr+=szStrBuffer;
+ }
+ }
+ else
+ {
+ valStr = "";
+ if(valValidBits < valTotalBitSize)
+ valStr += "??";
+ if(valValidBits > 32)
+ {
+ sprintf(szStrBuffer,"%" PRIu64 ,value);
+ }
+ else
+ {
+ sprintf(szStrBuffer,"%" PRIu32 ,(uint32_t)value);
+ }
+ valStr += szStrBuffer;
+ if(valValidBits < valTotalBitSize)
+ {
+ sprintf(szStrBuffer," (%d:0)", valValidBits-1);
+ valStr+=szStrBuffer;
+ }
+ }
+}
+
+
+/* End of File trc_printable_elem.cpp */
diff --git a/decoder/source/trc_ret_stack.cpp b/decoder/source/trc_ret_stack.cpp
new file mode 100644
index 0000000..a56c6e6
--- /dev/null
+++ b/decoder/source/trc_ret_stack.cpp
@@ -0,0 +1,149 @@
+/*
+* \file trc_ret_stack.cpp
+* \brief OpenCSD : trace decoder return stack feature.
+*
+* \copyright Copyright (c) 2017, ARM Limited. All Rights Reserved.
+*/
+
+/*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its contributors
+* may be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common/trc_ret_stack.h"
+
+#ifdef TRC_RET_STACK_DEBUG
+#include <sstream>
+#include <iostream>
+#include "common/trc_component.h"
+
+#define LOG_POP(A,O,I) LogOp("Pop",A,O,I)
+#define LOG_PUSH(A,O,I) LogOp("Push",A,O,I)
+#define LOG_FLUSH() LogOp("Flush",0,-1000,(const ocsd_isa)0)
+
+// uncomment for forced std::cout log, bypassing normal library debug logger.
+// useful perhaps when perf is decoding w/o printing.
+// #define FORCE_STD_COUT
+
+#else
+#define LOG_POP(A,O,I)
+#define LOG_PUSH(A,O,I)
+#define LOG_FLUSH()
+#endif
+
+TrcAddrReturnStack::TrcAddrReturnStack() :
+ m_active(false),
+ m_pop_pending(false),
+ head_idx(0),
+ num_entries(0)
+{
+#ifdef TRC_RET_STACK_DEBUG
+ m_p_debug_logger = 0;
+#endif
+}
+
+void TrcAddrReturnStack::push(const ocsd_vaddr_t addr, const ocsd_isa isa)
+{
+ if (is_active())
+ {
+ head_idx++;
+ head_idx &= 0xF;
+ m_stack[head_idx].ret_addr = addr;
+ m_stack[head_idx].ret_isa = isa;
+ num_entries++;
+ if (num_entries > 16)
+ num_entries = 16;
+ LOG_PUSH(addr,0,isa);
+ m_pop_pending = false;
+ }
+}
+
+ocsd_vaddr_t TrcAddrReturnStack::pop(ocsd_isa &isa)
+{
+ ocsd_vaddr_t addr = (ocsd_vaddr_t)-1;
+ if (is_active())
+ {
+ if (num_entries > 0)
+ {
+ addr = m_stack[head_idx].ret_addr;
+ isa = m_stack[head_idx].ret_isa;
+ head_idx--;
+ head_idx &= 0xF;
+ }
+ num_entries--;
+ LOG_POP(addr,1,isa);
+ m_pop_pending = false;
+ }
+ return addr;
+}
+
+
+void TrcAddrReturnStack::flush()
+{
+ num_entries = 0;
+ m_pop_pending = false;
+ LOG_FLUSH();
+}
+
+#ifdef TRC_RET_STACK_DEBUG
+void TrcAddrReturnStack::LogOp(const char * pszOpString, ocsd_vaddr_t addr, int head_off, ocsd_isa isa)
+{
+ static const char *isa_names[] =
+ {
+ "A32", /**< V7 ARM 32, V8 AArch32 */
+ "T32", /**< Thumb2 -> 16/32 bit instructions */
+ "A64", /**< V8 AArch64 */
+ "TEE", /**< Thumb EE - unsupported */
+ "JZL", /**< Jazelle - unsupported in trace */
+ "custom", /**< Instruction set - custom arch decoder */
+ "unknown" /**< ISA not yet known */
+ };
+
+ if (m_p_debug_logger)
+ {
+ std::ostringstream oss;
+ if(head_off == -1000)
+ {
+ oss << "Return stack " << pszOpString << "\n";
+ }
+ else
+ {
+ int name_idx = (int)isa;
+ if (name_idx > 6)
+ name_idx = 6;
+ oss << "Return stack " << pszOpString << "[" << std::dec << (head_idx+head_off) << "](0x" << std::hex << addr << "), " << isa_names[name_idx] << ";";
+ oss << "current entries = " << std::dec << num_entries << ";";
+ oss << "new head idx = " << head_idx << ";";
+ oss << "pop pend (pre op) = " << (m_pop_pending ? "true\n" : "false\n");
+ }
+#ifdef FORCE_STD_COUT
+ std::cout << oss.str();
+ std::cout.flush();
+#endif
+ m_p_debug_logger->LogDefMessage(oss.str());
+ }
+}
+#endif
+
+/* End of File trc_ret_stack.cpp */