diff options
Diffstat (limited to 'decoder/source')
22 files changed, 1439 insertions, 280 deletions
diff --git a/decoder/source/c_api/ocsd_c_api.cpp b/decoder/source/c_api/ocsd_c_api.cpp index 4824c427e3d1..750c847e78c8 100644 --- a/decoder/source/c_api/ocsd_c_api.cpp +++ b/decoder/source/c_api/ocsd_c_api.cpp @@ -234,8 +234,24 @@ OCSD_C_API ocsd_err_t ocsd_dt_attach_packet_callback( const dcd_tree_handle_t h return err; } -/*** Decode tree set element output */ +OCSD_C_API ocsd_err_t ocsd_dt_get_decode_stats(const dcd_tree_handle_t handle, + const unsigned char CSID, + ocsd_decode_stats_t **p_stats_block) +{ + DecodeTree *pDT = static_cast<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) { @@ -470,6 +486,39 @@ OCSD_C_API ocsd_err_t ocsd_dt_set_pkt_protocol_printer(const dcd_tree_handle_t h 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 */ /*******************************************************************************/ 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 000000000000..474cb2f7914a --- /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_pkt_elem_etmv3.cpp b/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp index f1e411f72423..74034c3c3e8f 100644 --- a/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp +++ b/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp @@ -659,7 +659,7 @@ void EtmV3TrcPacket::getExcepStr(std::string &excepStr) const "IRQ4", "IRQ5", "IRQ6", "IRQ7", "IRQ0","usage Fault","NMI","SVC", "DebugMonitor", "Mem Manage","PendSV","SysTick", - "Reserved","PE Reset","Reserved","HardFault" + "Reserved","PE Reset","Reserved","HardFault", "Reserved","BusFault","Reserved","Reserved" }; diff --git a/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp b/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp index 9f5b37396b46..6f8bf790d293 100644 --- a/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp +++ b/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp @@ -98,7 +98,7 @@ void EtmV4Config::CalcVMIDSize() uint32_t vmidszF = (m_cfg.reg_idr2 >> 10) & 0x1F; if(vmidszF == 1) m_VMIDSize = 8; - else if(MinVersion() > 0) + else if(FullVersion() > 0x40) { if(vmidszF == 2) m_VMIDSize = 16; diff --git a/decoder/source/etmv4/trc_etmv4_stack_elem.cpp b/decoder/source/etmv4/trc_etmv4_stack_elem.cpp index 8e9ba9ac43ca..a5d889413eb2 100644 --- a/decoder/source/etmv4/trc_etmv4_stack_elem.cpp +++ b/decoder/source/etmv4/trc_etmv4_stack_elem.cpp @@ -128,6 +128,40 @@ TrcStackQElem *EtmV4P0Stack::createQElem(const ocsd_etmv4_i_pkt_type root_pkt, c return pElem; } +TrcStackElemMarker *EtmV4P0Stack::createMarkerElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const trace_marker_payload_t &marker) +{ + TrcStackElemMarker *pElem = new (std::nothrow) TrcStackElemMarker(root_pkt, root_index); + if (pElem) + { + pElem->setMarker(marker); + push_front(pElem); + } + return pElem; +} + +TrcStackElemAddr *EtmV4P0Stack::createSrcAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val) +{ + TrcStackElemAddr *pElem = new (std::nothrow) TrcStackElemAddr(root_pkt, root_index, true); + if (pElem) + { + pElem->setAddr(addr_val); + push_front(pElem); + } + return pElem; +} + +TrcStackElemITE *EtmV4P0Stack::createITEElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const trace_sw_ite_t &ite) +{ + TrcStackElemITE *pElem = new (std::nothrow) TrcStackElemITE(root_pkt, root_index); + if (pElem) + { + pElem->setITE(ite); + push_front(pElem); + } + return pElem; +} + + // iteration functions void EtmV4P0Stack::from_front_init() { @@ -150,6 +184,10 @@ void EtmV4P0Stack::erase_curr_from_front() erase_iter = m_iter; erase_iter--; m_P0_stack.erase(erase_iter); + + // explicitly delete the item here as the caller can no longer reference it. + // fixes memory leak from github issue #52 + delete *erase_iter; } diff --git a/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp index 393046ba23d1..89c45052868c 100644 --- a/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp +++ b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp @@ -39,7 +39,8 @@ #define DCD_NAME "DCD_ETMV4" -static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS = OCSD_OPFLG_PKTDEC_COMMON; +static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS = OCSD_OPFLG_PKTDEC_COMMON | + ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS; TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I() : TrcPktDecodeBase(DCD_NAME) @@ -101,6 +102,14 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processPacket() 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; @@ -261,6 +270,7 @@ void TrcPktDecodeEtmV4I::resetDecoder() m_out_elem.resetElemStack(); m_last_IS = 0; clearElemRes(); + m_ete_first_ts_marker = false; // elements associated with data trace #ifdef DATA_TRACE_SUPPORTED @@ -358,7 +368,25 @@ ocsd_err_t TrcPktDecodeEtmV4I::decodePacket() if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) bAllocErr = true; - is_addr = true; + is_addr = true; // may be waiting for target address from indirect branch + } + break; + + case ETE_PKT_I_SRC_ADDR_MATCH: + case ETE_PKT_I_SRC_ADDR_S_IS0: + case ETE_PKT_I_SRC_ADDR_S_IS1: + case ETE_PKT_I_SRC_ADDR_L_32IS0: + case ETE_PKT_I_SRC_ADDR_L_32IS1: + case ETE_PKT_I_SRC_ADDR_L_64IS0: + case ETE_PKT_I_SRC_ADDR_L_64IS1: + { + etmv4_addr_val_t addr; + + addr.val = m_curr_packet_in->getAddrVal(); + addr.isa = m_curr_packet_in->getAddrIS(); + if (m_P0_stack.createSrcAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) + bAllocErr = true; + m_curr_spec_depth++; } break; @@ -438,16 +466,26 @@ ocsd_err_t TrcPktDecodeEtmV4I::decodePacket() } break; + case ETE_PKT_I_TS_MARKER: + { + trace_marker_payload_t marker; + marker.type = ELEM_MARKER_TS; + marker.value = 0; + if (m_P0_stack.createMarkerElem(m_curr_packet_in->getType(), m_index_curr_pkt, marker) == 0) + bAllocErr = true; + } + break; + case ETM4_PKT_I_BAD_SEQUENCE: - err = handleBadPacket("Bad byte sequence in packet."); + err = handleBadPacket("Bad byte sequence in packet.", m_index_curr_pkt); break; case ETM4_PKT_I_BAD_TRACEMODE: - err = handleBadPacket("Invalid packet type for trace mode."); + err = handleBadPacket("Invalid packet type for trace mode.", m_index_curr_pkt); break; case ETM4_PKT_I_RESERVED: - err = handleBadPacket("Reserved packet header"); + err = handleBadPacket("Reserved packet header", m_index_curr_pkt); break; // speculation @@ -502,8 +540,44 @@ ocsd_err_t TrcPktDecodeEtmV4I::decodePacket() } break; + /* transactional memory packets */ + case ETE_PKT_I_TRANS_ST: + { + if (m_P0_stack.createParamElemNoParam(P0_TRANS_START, m_config->commTransP0(), m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + if (m_config->commTransP0()) + m_curr_spec_depth++; + } + break; + + case ETE_PKT_I_TRANS_COMMIT: + { + if (m_P0_stack.createParamElemNoParam(P0_TRANS_COMMIT, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + } + break; + + case ETE_PKT_I_TRANS_FAIL: + { + if (m_P0_stack.createParamElemNoParam(P0_TRANS_FAIL, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) + bAllocErr = true; + } + break; + + /* PE Instrumentation packet */ + case ETE_PKT_I_ITE: + { + trace_sw_ite_t ite_pkt; + + ite_pkt.el = m_curr_packet_in->getITE_EL(); + ite_pkt.value = m_curr_packet_in->getITE_value(); + if (m_P0_stack.createITEElem(m_curr_packet_in->getType(), m_index_curr_pkt, ite_pkt) == 0) + bAllocErr = true; + } + break; + /*** presently unsupported packets ***/ - /* conditional instruction tracing */ + /* conditional instruction tracing */ case ETM4_PKT_I_COND_FLUSH: case ETM4_PKT_I_COND_I_F1: case ETM4_PKT_I_COND_I_F2: @@ -525,14 +599,16 @@ ocsd_err_t TrcPktDecodeEtmV4I::decodePacket() //resp = OCSD_RESP_FATAL_INVALID_DATA; #endif err = OCSD_ERR_UNSUPP_DECODE_PKT; - LogError(ocsdError(sev, err, "Data trace releated, unsupported packet type.")); + if (sev == OCSD_ERR_SEV_WARN) + LogError(ocsdError(sev, err, "Data trace related, unsupported packet type.")); + else + err = handlePacketSeqErr(err, m_index_curr_pkt, "Data trace related, unsupported packet type."); } break; default: // any other packet - bad packet error - err = OCSD_ERR_BAD_DECODE_PKT; - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,"Unknown packet type.")); + err = handleBadPacket("Unknown packet type.", m_index_curr_pkt); break; } @@ -566,6 +642,9 @@ 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 @@ -592,14 +671,18 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::resolveElements() if (m_elem_res.P0_commit) err = commitElements(); - if (!err && m_elem_res.P0_cancel) - err = cancelElements(); + // allow for early flush on context element + if (!m_elem_res.P0_commit) { - if (!err && m_elem_res.mispredict) - err = mispredictAtom(); - - if (!err && m_elem_res.discard) - err = discardElements(); + if (!err && m_elem_res.P0_cancel) + err = cancelElements(); + + if (!err && m_elem_res.mispredict) + err = mispredictAtom(); + + if (!err && m_elem_res.discard) + err = discardElements(); + } if (err != OCSD_OK) resp = OCSD_RESP_FATAL_INVALID_DATA; @@ -634,10 +717,11 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() int num_commit_req = m_elem_res.P0_commit; ocsd_trc_index_t err_idx = 0; TrcStackElem *pElem = 0; // stacked element pointer + bool contextFlush = false; err = m_out_elem.resetElemStack(); - while(m_elem_res.P0_commit && !err) + while(m_elem_res.P0_commit && !err && !contextFlush) { if (m_P0_stack.size() > 0) { @@ -646,7 +730,7 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() switch (pElem->getP0Type()) { - // indicates a trace restart - beginning of trace or discontinuiuty + // indicates a trace restart - beginning of trace or discontinuiuty case P0_TRC_ON: err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_TRACE_ON); if (!err) @@ -661,7 +745,7 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() { 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) + if (pAddrElem) { SetInstrInfoInAddrISA(pAddrElem->getAddr().val, pAddrElem->getAddr().isa); m_need_addr = false; @@ -672,15 +756,24 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() case P0_CTXT: { TrcStackElemCtxt *pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem); - if(pCtxtElem) + if (pCtxtElem) { etmv4_context_t ctxt = pCtxtElem->getContext(); // check this is an updated context if(ctxt.updated) { err = m_out_elem.addElem(pElem->getRootIndex()); - if (!err) + if (!err) { updateContext(pCtxtElem, outElem()); + + // updated context - need to force this to be output to the client so correct memory + // context can be used. + contextFlush = true; + + // invalidate memory accessor cacheing - force next memory access out to client to + // ensure that the correct memory context is in play when decoding subsequent atoms. + invalidateMemAccCache(); + } } } } @@ -693,11 +786,15 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() err = processTS_CC_EventElem(pElem); break; + case P0_MARKER: + err = processMarkerElem(pElem); + break; + case P0_ATOM: { TrcStackElemAtom *pAtomElem = dynamic_cast<TrcStackElemAtom *>(pElem); - if(pAtomElem) + if (pAtomElem) { while(!pAtomElem->isEmpty() && m_elem_res.P0_commit && !err) { @@ -709,13 +806,13 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() // if address and context do instruction trace follower. // otherwise skip atom and reduce committed elements - if(!m_need_ctxt && !m_need_addr) + if (!m_need_ctxt && !m_need_addr) { err = processAtom(atom); } m_elem_res.P0_commit--; // mark committed } - if(!pAtomElem->isEmpty()) + if (!pAtomElem->isEmpty()) bPopElem = false; // don't remove if still atoms to process. } } @@ -746,9 +843,27 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() m_elem_res.P0_commit--; break; + case P0_SRC_ADDR: + err = processSourceAddress(); + m_elem_res.P0_commit--; + break; + case P0_Q: err = processQElement(); m_elem_res.P0_commit--; + break; + + case P0_TRANS_START: + if (m_config->commTransP0()) + m_elem_res.P0_commit--; + case P0_TRANS_COMMIT: + case P0_TRANS_FAIL: + case P0_TRANS_TRACE_INIT: + err = processTransElem(pElem); + break; + + case P0_ITE: + err = processITEElem(pElem); break; } @@ -757,9 +872,8 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElements() } else { - // too few elements for commit operation - decode error. - err = OCSD_ERR_COMMIT_PKT_OVERRUN; - LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_COMMIT_PKT_OVERRUN,err_idx,m_CSID,"Not enough elements to commit")); + // too few elements for commit operation - decode error. + err = handlePacketSeqErr(OCSD_ERR_COMMIT_PKT_OVERRUN, err_idx, "Not enough elements to commit"); } } @@ -779,7 +893,7 @@ ocsd_err_t TrcPktDecodeEtmV4I::returnStackPop() if (m_return_stack.overflow()) { err = OCSD_ERR_RET_STACK_OVERFLOW; - LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, "Trace Return Stack Overflow.")); + err = handlePacketSeqErr(err, OCSD_BAD_TRC_INDEX, "Trace Return Stack Overflow."); } else { @@ -824,6 +938,25 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElemOnEOT() 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: @@ -831,6 +964,14 @@ ocsd_err_t TrcPktDecodeEtmV4I::commitElemOnEOT() case P0_TS_CC: err = processTS_CC_EventElem(pElem); break; + + case P0_MARKER: + err = processMarkerElem(pElem); + break; + + case P0_ITE: + err = processITEElem(pElem); + break; } m_P0_stack.delete_back(); } @@ -886,6 +1027,8 @@ ocsd_err_t TrcPktDecodeEtmV4I::cancelElements() case P0_TS: case P0_CC: case P0_TS_CC: + case P0_MARKER: + case P0_ITE: m_P0_stack.pop_front(false); temp.push_back(pElem); break; @@ -895,6 +1038,8 @@ ocsd_err_t TrcPktDecodeEtmV4I::cancelElements() break; } } + if (m_P0_stack.size() == 0) + P0StackDone = true; } } // may have some unseen elements @@ -908,21 +1053,23 @@ ocsd_err_t TrcPktDecodeEtmV4I::cancelElements() { // too few elements for commit operation - decode error. err = OCSD_ERR_COMMIT_PKT_OVERRUN; - LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, m_index_curr_pkt, m_CSID, "Not enough elements to cancel")); + err = handlePacketSeqErr(err, m_index_curr_pkt, "Not enough elements to cancel"); m_elem_res.P0_cancel = 0; break; } - - if (temp.size()) + } + + /* restore any saved elements that are unaffected by cancel. */ + if (temp.size()) + { + while (temp.size()) { - while (temp.size()) - { - pElem = temp.back(); - m_P0_stack.push_front(pElem); - temp.pop_back(false); - } + pElem = temp.back(); + m_P0_stack.push_front(pElem); + temp.pop_back(false); } } + m_curr_spec_depth -= num_cancel_req - m_elem_res.P0_cancel; return err; } @@ -964,7 +1111,8 @@ ocsd_err_t TrcPktDecodeEtmV4I::mispredictAtom() if (!bFoundAtom && !m_unseen_spec_elem) { err = OCSD_ERR_COMMIT_PKT_OVERRUN; - LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, m_index_curr_pkt, m_CSID, "Not found mispredict atom")); + err = handlePacketSeqErr(err, m_index_curr_pkt, "Not found mispredict atom"); + //LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, m_index_curr_pkt, m_CSID, "Not found mispredict atom")); } m_elem_res.mispredict = false; return err; @@ -980,7 +1128,12 @@ ocsd_err_t TrcPktDecodeEtmV4I::discardElements() while ((m_P0_stack.size() > 0) && !err) { pElem = m_P0_stack.back(); - err = processTS_CC_EventElem(pElem); + if (pElem->getP0Type() == P0_MARKER) + err = processMarkerElem(pElem); + else if (pElem->getP0Type() == P0_MARKER) + err = processITEElem(pElem); + else + err = processTS_CC_EventElem(pElem); m_P0_stack.delete_back(); } @@ -1002,6 +1155,8 @@ ocsd_err_t TrcPktDecodeEtmV4I::discardElements() 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()) { @@ -1016,7 +1171,7 @@ ocsd_err_t TrcPktDecodeEtmV4I::processTS_CC_EventElem(TrcStackElem *pElem) case P0_TS: { TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); - if (pParamElem) + if (pParamElem && bPermitTS) err = addElemTS(pParamElem, false); } break; @@ -1032,7 +1187,7 @@ ocsd_err_t TrcPktDecodeEtmV4I::processTS_CC_EventElem(TrcStackElem *pElem) case P0_TS_CC: { TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); - if (pParamElem) + if (pParamElem && bPermitTS) err = addElemTS(pParamElem, true); } break; @@ -1041,6 +1196,46 @@ ocsd_err_t TrcPktDecodeEtmV4I::processTS_CC_EventElem(TrcStackElem *pElem) } +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::processITEElem(TrcStackElem *pElem) +{ + ocsd_err_t err = OCSD_OK; + TrcStackElemITE *pITEElem = dynamic_cast<TrcStackElemITE *>(pElem); + + err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_INSTRUMENTATION); + if (!err) { + outElem().setITEInfo(pITEElem->getITE()); + } + return err; +} + ocsd_err_t TrcPktDecodeEtmV4I::addElemCC(TrcStackElemParam *pParamElem) { ocsd_err_t err = OCSD_OK; @@ -1078,16 +1273,22 @@ ocsd_err_t TrcPktDecodeEtmV4I::addElemEvent(TrcStackElemParam *pParamElem) return err; } -void TrcPktDecodeEtmV4I::setElemTraceRange(OcsdTraceElement &elemIn, const instr_range_t &addr_range, - const bool executed, ocsd_trc_index_t index) +void TrcPktDecodeEtmV4I::setElemTraceRange(OcsdTraceElement &elemIn, const instr_range_t &addr_range, + const bool executed, ocsd_trc_index_t index) +{ + setElemTraceRangeInstr(elemIn, addr_range, executed, index, m_instr_info); +} + +void TrcPktDecodeEtmV4I::setElemTraceRangeInstr(OcsdTraceElement &elemIn, const instr_range_t &addr_range, + const bool executed, ocsd_trc_index_t index, ocsd_instr_info &instr) { elemIn.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); - elemIn.setLastInstrInfo(executed, m_instr_info.type, m_instr_info.sub_type, m_instr_info.instr_size); - elemIn.setISA(m_instr_info.isa); - elemIn.setLastInstrCond(m_instr_info.is_conditional); + elemIn.setLastInstrInfo(executed, instr.type, instr.sub_type, instr.instr_size); + elemIn.setISA(instr.isa); + elemIn.setLastInstrCond(instr.is_conditional); elemIn.setAddrRange(addr_range.st_addr, addr_range.en_addr, addr_range.num_instr); if (executed) - m_instr_info.isa = m_instr_info.next_isa; + instr.isa = instr.next_isa; } ocsd_err_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom) @@ -1096,6 +1297,7 @@ ocsd_err_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom) 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) @@ -1114,7 +1316,8 @@ ocsd_err_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom) } else { - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet.")); + err = handlePacketSeqErr(err, pElem->getRootIndex(), "Error processing atom packet."); + //LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet.")); return err; } } @@ -1144,10 +1347,22 @@ ocsd_err_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom) 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 { @@ -1182,55 +1397,64 @@ ocsd_err_t TrcPktDecodeEtmV4I::processException() TrcStackElemAddr *pAddressElem = 0; TrcStackElemCtxt *pCtxtElem = 0; bool branch_target = false; // exception address implies prior branch target address - ocsd_vaddr_t excep_ret_addr; + ocsd_vaddr_t excep_ret_addr = 0; ocsd_trc_index_t excep_pkt_index; WP_res_t WPRes = WP_NOT_FOUND; + bool ETE_resetPkt = false; // grab the exception element off the stack pExceptElem = dynamic_cast<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 - pElem = m_P0_stack.back(); // look at next element. - if(pElem->getP0Type() == P0_CTXT) + // ETE reset has no follow up address, the rest of the exceptions do.... + if (!ETE_resetPkt) { - pCtxtElem = dynamic_cast<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. - LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ, excep_pkt_index,m_CSID,"Address missing in exception packet.")); - return OCSD_ERR_BAD_PACKET_SEQ; - } - else - { - // extract address - pAddressElem = static_cast<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) + pElem = m_P0_stack.back(); // look at next element. + if (pElem->getP0Type() == P0_CTXT) { - // this was a branch target address - update current setting - bool b64bit = m_instr_info.isa == ocsd_isa_aarch64; - if (pCtxtElem) { - b64bit = pCtxtElem->getContext().SF; - } + pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem); + m_P0_stack.pop_back(); // remove the context element + pElem = m_P0_stack.back(); // next one should be an address element + } - // as the exception address was also a branch target address then update the - // current maintained address value. This also means that there is no range to - // output before the exception packet. - m_instr_info.instr_addr = excep_ret_addr; - m_instr_info.isa = (pAddressElem->getAddr().isa == 0) ? + if (pElem->getP0Type() != P0_ADDR) + { + // no following address element - indicate processing error. + + err = handlePacketSeqErr(OCSD_ERR_BAD_PACKET_SEQ, m_index_curr_pkt, "Address missing in exception packet."); + //LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_BAD_PACKET_SEQ, excep_pkt_index, m_CSID, "Address missing in exception packet.")); + return err; + } + else + { + // extract address + pAddressElem = static_cast<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; + m_need_addr = false; + } } - } + } // need to output something - set up an element if ((err = m_out_elem.addElem(excep_pkt_index))) @@ -1246,69 +1470,72 @@ ocsd_err_t TrcPktDecodeEtmV4I::processException() return err; } - // if the preferred return address is not the end of the last output range... - if (m_instr_info.instr_addr != excep_ret_addr) - { - bool range_out = false; - instr_range_t addr_range; + if (!ETE_resetPkt) + { + // if the preferred return address is not the end of the last output range... + if (m_instr_info.instr_addr != excep_ret_addr) + { + bool range_out = false; + instr_range_t addr_range; - // look for match to return address. - err = traceInstrToWP(addr_range, WPRes, true, excep_ret_addr); + // look for match to return address. + err = traceInstrToWP(addr_range, WPRes, true, excep_ret_addr); - if(err != OCSD_OK) - { - if(err == OCSD_ERR_UNSUPPORTED_ISA) + if (err != OCSD_OK) { - m_need_addr = true; - m_need_ctxt = true; - LogError(ocsdError(OCSD_ERR_SEV_WARN,err, excep_pkt_index,m_CSID,"Warning: unsupported instruction set processing exception packet.")); + if (err == OCSD_ERR_UNSUPPORTED_ISA) + { + m_need_addr = true; + m_need_ctxt = true; + LogError(ocsdError(OCSD_ERR_SEV_WARN, err, excep_pkt_index, m_CSID, "Warning: unsupported instruction set processing exception packet.")); + } + else + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, excep_pkt_index, m_CSID, "Error processing exception packet.")); + } + return err; + } + + if (WPFound(WPRes)) + { + // waypoint address found - output range + setElemTraceRange(outElem(), addr_range, true, excep_pkt_index); + range_out = true; } else { - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err, excep_pkt_index,m_CSID,"Error processing exception packet.")); + // no waypoint - likely inaccessible memory range. + m_need_addr = true; // need an address update + + if (addr_range.st_addr != addr_range.en_addr) + { + // some trace before we were out of memory access range + setElemTraceRange(outElem(), addr_range, true, excep_pkt_index); + range_out = true; + } } - return err; - } - if(WPFound(WPRes)) - { - // waypoint address found - output range - setElemTraceRange(outElem(), addr_range, true, excep_pkt_index); - range_out = true; - } - else - { - // no waypoint - likely inaccessible memory range. - m_need_addr = true; // need an address update - - if(addr_range.st_addr != addr_range.en_addr) + // used the element need another for NACC or EXCEP. + if (range_out) { - // some trace before we were out of memory access range - setElemTraceRange(outElem(), addr_range, true, excep_pkt_index); - range_out = true; + if ((err = m_out_elem.addElem(excep_pkt_index))) + return err; } } - // used the element need another for NACC or EXCEP. - if (range_out) + // watchpoint walk resulted in inaccessible memory call... + if (WPNacc(WPRes)) { + + outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + outElem().st_addr = m_instr_info.instr_addr; + + // used the element - need another for the final exception packet. if ((err = m_out_elem.addElem(excep_pkt_index))) return err; } } - - // watchpoint walk resulted in inaccessible memory call... - if (WPNacc(WPRes)) - { - - outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); - outElem().st_addr = m_instr_info.instr_addr; - // used the element - need another for the final exception packet. - if ((err = m_out_elem.addElem(excep_pkt_index))) - return err; - } - // output exception element. outElem().setType(OCSD_GEN_TRC_ELEM_EXCEPTION); @@ -1453,6 +1680,163 @@ ocsd_err_t TrcPktDecodeEtmV4I::processQElement() 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; @@ -1518,7 +1902,10 @@ void TrcPktDecodeEtmV4I::updateContext(TrcStackElemCtxt *pCtxtElem, OcsdTraceEle m_is_64bit = (ctxt.SF != 0); elem.context.bits64 = ctxt.SF; m_is_secure = (ctxt.NS == 0); - elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure; + if (ctxt.NSE) + elem.context.security_level = ctxt.NS ? ocsd_sec_realm : ocsd_sec_root; + else + elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure; elem.context.exception_level = (ocsd_ex_level)ctxt.EL; elem.context.el_valid = 1; if(ctxt.updated_c) @@ -1537,27 +1924,42 @@ void TrcPktDecodeEtmV4I::updateContext(TrcStackElemCtxt *pCtxtElem, OcsdTraceEle m_need_ctxt = false; } -ocsd_err_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason) +ocsd_err_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason, ocsd_trc_index_t index /* = OCSD_BAD_TRC_INDEX */) { - ocsd_err_t err = OCSD_OK; + ocsd_err_severity_t sev = OCSD_ERR_SEV_WARN; + if (getComponentOpMode() & OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) + sev = OCSD_ERR_SEV_ERROR; - if(getComponentOpMode() & OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) - { - // error out - stop decoding - err = OCSD_ERR_BAD_DECODE_PKT; - LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,reason)); - } - else + return handlePacketErr(OCSD_ERR_BAD_DECODE_PKT, sev, index, reason); +} + +ocsd_err_t TrcPktDecodeEtmV4I::handlePacketSeqErr(ocsd_err_t err, ocsd_trc_index_t index, const char *reason) +{ + return handlePacketErr(err, OCSD_ERR_SEV_ERROR, index, reason); +} + +ocsd_err_t TrcPktDecodeEtmV4I::handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason) +{ + bool resetOnBadPackets = true; + + if(getComponentOpMode() & OCSD_OPFLG_PKTDEC_HALT_BAD_PKTS) + resetOnBadPackets = false; + + LogError(ocsdError(sev, err, index, getCoreSightTraceID(), reason)); + + if (resetOnBadPackets) { - LogError(ocsdError(OCSD_ERR_SEV_WARN, OCSD_ERR_BAD_DECODE_PKT, reason)); // switch to unsync - clear decode state resetDecoder(); m_curr_state = NO_SYNC; m_unsync_eot_info = UNSYNC_BAD_PACKET; + err = OCSD_OK; } return err; + } + inline ocsd_mem_space_acc_t TrcPktDecodeEtmV4I::getCurrMemSpace() { static ocsd_mem_space_acc_t SMemSpace[] = { diff --git a/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp index 853fde499a1b..825b5f79e41b 100644 --- a/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp +++ b/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp @@ -38,6 +38,7 @@ EtmV4ITrcPacket::EtmV4ITrcPacket() { + protocol_version = 0x42; // min protocol version. } EtmV4ITrcPacket::~EtmV4ITrcPacket() @@ -101,6 +102,8 @@ void EtmV4ITrcPacket::toString(std::string &str) const 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; @@ -110,6 +113,8 @@ void EtmV4ITrcPacket::toString(std::string &str) const 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; @@ -121,11 +126,14 @@ void EtmV4ITrcPacket::toString(std::string &str) const 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); @@ -161,7 +169,10 @@ void EtmV4ITrcPacket::toString(std::string &str) const { std::ostringstream oss; oss << "; INFO=" << std::hex << "0x" << trace_info.val; - oss << " { CC." << std::dec << trace_info.bits.cc_enabled << " }"; + oss << " { CC." << std::dec << trace_info.bits.cc_enabled; + if (isETE()) + oss << ", TSTATE." << std::dec << trace_info.bits.in_trans_state; + oss << " }"; if (trace_info.bits.cc_enabled) oss << "; CC_THRESHOLD=" << std::hex << "0x" << cc_threshold; str += oss.str(); @@ -264,6 +275,14 @@ void EtmV4ITrcPacket::toString(std::string &str) const } } break; + + case ETE_PKT_I_ITE: + { + std::ostringstream oss; + oss << "; EL" << std::dec << (int)ite_pkt.el << "; Payload=0x" << std::hex << ite_pkt.value; + str += oss.str(); + } + break; } } @@ -349,6 +368,16 @@ const char *EtmV4ITrcPacket::packetTypeName(const ocsd_etmv4_i_pkt_type type, co pName = "I_EXCEPT_RTN"; pDesc = "Exception Return."; break; + + case ETE_PKT_I_TRANS_ST: + pName = "I_TRANS_ST"; + pDesc = "Transaction Start."; + break; + + case ETE_PKT_I_TRANS_COMMIT: + pName = "I_TRANS_COMMIT"; + pDesc = "Transaction Commit."; + break; case ETM4_PKT_I_CCNT_F1: pName = "I_CCNT_F1"; @@ -481,6 +510,11 @@ const char *EtmV4ITrcPacket::packetTypeName(const ocsd_etmv4_i_pkt_type type, co 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."; @@ -521,6 +555,41 @@ const char *EtmV4ITrcPacket::packetTypeName(const ocsd_etmv4_i_pkt_type type, co 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."; @@ -566,6 +635,21 @@ const char *EtmV4ITrcPacket::packetTypeName(const ocsd_etmv4_i_pkt_type type, co pDesc = "Overflow."; break; + case ETE_PKT_I_PE_RESET: + pName = "I_PE_RESET"; + pDesc = "PE Reset."; + break; + + case ETE_PKT_I_TRANS_FAIL: + pName = "I_TRANS_FAIL"; + pDesc = "Transaction Fail."; + break; + + case ETE_PKT_I_ITE: + pName = "I_ITE"; + pDesc = "Instrumentation"; + break; + default: break; } diff --git a/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp index d8c7d84667d1..d767bdc85643 100644 --- a/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp +++ b/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp @@ -45,6 +45,9 @@ 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), @@ -70,7 +73,9 @@ 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; } @@ -152,6 +157,10 @@ ocsd_datapath_resp_t TrcPktProcEtmV4I::processData( const ocsd_trc_index_t inde (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; } @@ -171,6 +180,7 @@ ocsd_datapath_resp_t TrcPktProcEtmV4I::processData( const ocsd_trc_index_t inde } } while (!done); + statsAddTotalCount(m_trcIn.processed()); *numBytesProcessed = m_trcIn.processed(); return resp; } @@ -241,8 +251,8 @@ ocsd_datapath_resp_t TrcPktProcEtmV4I::outputUnsyncedRawPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; - - outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]); + statsAddUnsyncCount(m_dump_unsynced_bytes); + outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]); if(!m_sent_notsync_packet) { @@ -290,6 +300,7 @@ void TrcPktProcEtmV4I::iPktNoPayload(const uint8_t lastByte) 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; @@ -307,6 +318,8 @@ void TrcPktProcEtmV4I::iPktNoPayload(const uint8_t lastByte) 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; } @@ -437,6 +450,8 @@ void TrcPktProcEtmV4I::iPktTraceInfo(const uint8_t lastByte) 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? @@ -469,6 +484,11 @@ void TrcPktProcEtmV4I::iPktTraceInfo(const uint8_t lastByte) 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; } @@ -502,8 +522,11 @@ void TrcPktProcEtmV4I::iPktTimestamp(const uint8_t lastByte) { int idx = 1; uint64_t tsVal; - int ts_bytes = extractContField64(m_currPacketData, idx, tsVal); - int ts_bits = ts_bytes < 7 ? ts_bytes * 7 : 64; + int ts_bytes = extractTSField64(m_currPacketData, idx, tsVal); + int ts_bits; + + // if ts_bytes 8 or less, then cont bits on each byte, otherwise full 64 bit value for 9 bytes + ts_bits = ts_bytes < 9 ? ts_bytes * 7 : 64; if(!m_curr_packet.pkt_valid.bits.ts_valid && m_first_trace_info) ts_bits = 64; // after trace info, missing bits are all 0. @@ -534,6 +557,13 @@ void TrcPktProcEtmV4I::iPktException(const uint8_t lastByte) 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; } @@ -553,6 +583,18 @@ void TrcPktProcEtmV4I::iPktException(const uint8_t lastByte) 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. } } @@ -833,7 +875,7 @@ void TrcPktProcEtmV4I::extractAndSetContextInfo(const std::vector<uint8_t> &buff // on input, buffer index points at the info byte - always present uint8_t infoByte = m_currPacketData[st_idx]; - m_curr_packet.setContextInfo(true, (infoByte & 0x3), (infoByte >> 5) & 0x1, (infoByte >> 4) & 0x1); + m_curr_packet.setContextInfo(true, (infoByte & 0x3), (infoByte >> 5) & 0x1, (infoByte >> 4) & 0x1, (infoByte >> 3) & 0x1); // see if there are VMID and CID bytes, and how many. int nVMID_bytes = ((infoByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0; @@ -937,7 +979,8 @@ void TrcPktProcEtmV4I::iPktShortAddr(const uint8_t lastByte) { m_addr_done = false; m_addrIS = 0; - if (lastByte == ETM4_PKT_I_ADDR_S_IS1) + if ((lastByte == ETM4_PKT_I_ADDR_S_IS1) || + (lastByte == ETE_PKT_I_SRC_ADDR_S_IS1)) m_addrIS = 1; } else if(!m_addr_done) @@ -988,14 +1031,18 @@ void TrcPktProcEtmV4I::iPktLongAddr(const uint8_t lastByte) 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; @@ -1203,6 +1250,23 @@ void TrcPktProcEtmV4I::iAtom(const uint8_t lastByte) m_process_state = SEND_PKT; } +void TrcPktProcEtmV4I::iPktITE(const uint8_t /* lastByte */) +{ + uint64_t value; + int shift = 0; + + /* packet is always 10 bytes, Header, EL info byte, 8 bytes payload */ + if (m_currPacketData.size() == 10) { + value = 0; + for (int i = 2; i < 10; i++) { + value |= ((uint64_t)m_currPacketData[i]) << shift; + shift += 8; + } + m_curr_packet.setITE(m_currPacketData[1], value); + m_process_state = SEND_PKT; + } +} + // header byte processing is table driven. void TrcPktProcEtmV4I::BuildIPacketTable() { @@ -1247,7 +1311,35 @@ void TrcPktProcEtmV4I::BuildIPacketTable() // b0000 0111 - exception return m_i_table[0x07].pkt_type = ETM4_PKT_I_EXCEPT_RTN; - m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + if (m_config.MajVersion() >= 0x5) // not valid for ETE + { +#ifdef ETE_TRACE_ERET_AS_IGNORE + m_i_table[0x07].pkt_type = ETM4_PKT_I_IGNORE; + m_i_table[0x07].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload; +#else + m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg; +#endif + } + else + m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + + // b00001010, b00001011 ETE TRANS packets + // b00001001 - ETE sw instrumentation packet + if (m_config.MajVersion() >= 0x5) + { + m_i_table[0x0A].pkt_type = ETE_PKT_I_TRANS_ST; + m_i_table[0x0A].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + + m_i_table[0x0B].pkt_type = ETE_PKT_I_TRANS_COMMIT; + m_i_table[0x0B].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload; + + // FEAT_ITE - sw instrumentation packet + if (m_config.MinVersion() >= 0x3) + { + m_i_table[0x09].pkt_type = ETE_PKT_I_ITE; + m_i_table[0x09].pptkFn = &TrcPktProcEtmV4I::iPktITE; + } + } // b0000 110x - cycle count f2 // b0000 111x - cycle count f1 @@ -1443,6 +1535,12 @@ void TrcPktProcEtmV4I::BuildIPacketTable() 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++) { @@ -1492,6 +1590,30 @@ void TrcPktProcEtmV4I::BuildIPacketTable() } } + // 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 { @@ -1559,20 +1681,33 @@ void TrcPktProcEtmV4I::BuildIPacketTable() return idx; } -unsigned TrcPktProcEtmV4I::extractContField64(const std::vector<uint8_t> &buffer, const unsigned st_idx, uint64_t &value, const unsigned byte_limit /*= 9*/) +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 && (idx < byte_limit)) // max 9 bytes for 64 bit value; + while(!lastByte) // max 9 bytes for 64 bit value; { if(buffer.size() > (st_idx + idx)) { // each byte has seven bits + cont bit byteVal = buffer[(st_idx + idx)]; - lastByte = (byteVal & 0x80) != 0x80; - value |= ((uint64_t)(byteVal & 0x7F)) << (idx * 7); + + /* detect the final byte - which uses full 8 bits as value */ + if (idx == max_byte_idx) + { + byteValMask = 0xFF; /* last byte of 9, no cont bit */ + lastByte = true; + } + else + lastByte = (byteVal & 0x80) != 0x80; + + value |= ((uint64_t)(byteVal & byteValMask)) << (idx * 7); idx++; } else @@ -1580,6 +1715,7 @@ unsigned TrcPktProcEtmV4I::extractContField64(const std::vector<uint8_t> &buffer throwBadSequenceError("Invalid 64 bit continuation fields in packet"); } } + // index is the count of bytes used here. return idx; } diff --git a/decoder/source/i_dec/trc_i_decode.cpp b/decoder/source/i_dec/trc_i_decode.cpp index 614fc1d8b45c..0e0589512002 100644 --- a/decoder/source/i_dec/trc_i_decode.cpp +++ b/decoder/source/i_dec/trc_i_decode.cpp @@ -42,7 +42,7 @@ ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info) struct decode_info info; info.instr_sub_type = OCSD_S_INSTR_NONE; - info.arch_version = (uint16_t)(instr_info->pe_type.arch); + info.arch_version = instr_info->pe_type.arch; switch(instr_info->isa) { @@ -136,14 +136,12 @@ ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info, struct decode_info if(inst_A64_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info)) { instr_info->type = OCSD_INSTR_BR_INDIRECT; -// instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); } else if(inst_A64_is_direct_branch_link(instr_info->opcode, &instr_info->is_link, info)) { inst_A64_branch_destination(instr_info->instr_addr,instr_info->opcode,&branchAddr); instr_info->type = OCSD_INSTR_BR; instr_info->branch_addr = (ocsd_vaddr_t)branchAddr; -// instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); } else if((barrier = inst_A64_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) { @@ -160,12 +158,15 @@ ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info, struct decode_info break; } } - else if (instr_info->wfi_wfe_branch) + else if (instr_info->wfi_wfe_branch && + inst_A64_wfiwfe(instr_info->opcode, info)) { - if (inst_A64_wfiwfe(instr_info->opcode)) - { - instr_info->type = OCSD_INSTR_WFI_WFE; - } + instr_info->type = OCSD_INSTR_WFI_WFE; + } + else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64)) + { + if (inst_A64_Tstart(instr_info->opcode)) + instr_info->type = OCSD_INSTR_TSTART; } instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode); diff --git a/decoder/source/i_dec/trc_idec_arminst.cpp b/decoder/source/i_dec/trc_idec_arminst.cpp index 3652e84921f3..76951fd38183 100644 --- a/decoder/source/i_dec/trc_idec_arminst.cpp +++ b/decoder/source/i_dec/trc_idec_arminst.cpp @@ -244,8 +244,9 @@ int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link, struct decod int is_direct_branch = 1; if ((inst & 0x7c000000) == 0x34000000) { /* CB, TB */ - } else if ((inst & 0xff000010) == 0x54000000) { + } 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) { @@ -258,11 +259,26 @@ int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link, struct decod return is_direct_branch; } -int inst_A64_wfiwfe(uint32_t inst) +int inst_A64_wfiwfe(uint32_t inst, struct decode_info *info) { /* WFI, WFE may be traced as branches in etm 4.3++ */ if ((inst & 0xffffffdf) == 0xd503205f) return 1; + + /* new feature introduced post v8.3 */ + if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64)) + { + /* WFIT / WFET for later archs */ + if ((inst & 0xffffffc0) == 0xd5031000) + return 1; + } + return 0; +} + +int inst_A64_Tstart(uint32_t inst) +{ + if ((inst & 0xffffffe0) == 0xd5233060) + return 1; return 0; } @@ -288,7 +304,7 @@ int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct dec } else if ((inst & 0xffffffff) == 0xd69f03e0) { /* ERET */ info->instr_sub_type = OCSD_S_INSTR_V8_ERET; - } else if (info->arch_version >= 0x0803) { + } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) { /* new pointer auth instr for v8.3 arch */ if ((inst & 0xffdff800) == 0xd71f0800) { /* BRAA, BRAB, BLRAA, BLRBB */ @@ -399,8 +415,9 @@ int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc) { uint64_t npc; int is_direct_branch = 1; - if ((inst & 0xff000010) == 0x54000000) { + if ((inst & 0xff000000) == 0x54000000) { /* B<cond> */ + /* BC<cond> */ npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11); } else if ((inst & 0x7c000000) == 0x14000000) { /* B, BL imm */ @@ -484,7 +501,7 @@ int inst_A64_is_branch_and_link(uint32_t inst, struct decode_info *info) } else if ((inst & 0xfc000000) == 0x94000000) { /* BL */ info->instr_sub_type = OCSD_S_INSTR_BR_LINK; - } else if (info->arch_version >= 0x0803) { + } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) { /* new pointer auth instr for v8.3 arch */ if ((inst & 0xfffff800) == 0xd73f0800) { /* BLRAA, BLRBB */ @@ -553,8 +570,9 @@ int inst_A64_is_conditional(uint32_t inst) if ((inst & 0x7c000000) == 0x34000000) { /* CB, TB */ return 1; - } else if ((inst & 0xff000010) == 0x54000000) { + } else if ((inst & 0xff000000) == 0x54000000) { /* B.cond */ + /* BC.cond */ return 1; } return 0; diff --git a/decoder/source/mem_acc/trc_mem_acc_mapper.cpp b/decoder/source/mem_acc/trc_mem_acc_mapper.cpp index 53edfe1a1616..dc07a1ed5a25 100644 --- a/decoder/source/mem_acc/trc_mem_acc_mapper.cpp +++ b/decoder/source/mem_acc/trc_mem_acc_mapper.cpp @@ -119,6 +119,14 @@ ocsd_err_t TrcMemAccMapper::ReadTargetMemory(const ocsd_vaddr_t address, const u 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; diff --git a/decoder/source/ocsd_dcd_tree.cpp b/decoder/source/ocsd_dcd_tree.cpp index be15e36e9cb3..8e29269d1690 100644 --- a/decoder/source/ocsd_dcd_tree.cpp +++ b/decoder/source/ocsd_dcd_tree.cpp @@ -101,6 +101,13 @@ DecodeTree::DecodeTree() : { 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() @@ -486,6 +493,62 @@ ocsd_err_t DecodeTree::removeDecoder(const uint8_t CSID) 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; @@ -511,7 +574,7 @@ DecodeTreeElement *DecodeTree::getNextElement(uint8_t &elemID) if(m_decode_elem_iter < 0x80) { // find a none zero entry or end of range - while((m_decode_elements[m_decode_elem_iter] == 0) && (m_decode_elem_iter < 0x80)) + while((m_decode_elem_iter < 0x80) && (m_decode_elements[m_decode_elem_iter] == 0)) m_decode_elem_iter++; // return entry unless end of range @@ -527,7 +590,7 @@ DecodeTreeElement *DecodeTree::getNextElement(uint8_t &elemID) bool DecodeTree::initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCfgFlags) { - bool initOK = true; + ocsd_err_t err; m_dcd_tree_type = type; if(type == OCSD_TRC_SRC_FRAME_FORMATTED) { @@ -535,14 +598,19 @@ bool DecodeTree::initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCf m_frame_deformatter_root = new (std::nothrow) TraceFormatterFrameDecoder(); if(m_frame_deformatter_root) { - m_frame_deformatter_root->Configure(formatterCfgFlags); + if (m_frame_deformatter_root->Init() != OCSD_OK) + return false; m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger); + err = m_frame_deformatter_root->Configure(formatterCfgFlags); + if (err != OCSD_OK) + return false; m_i_decoder_root = dynamic_cast<ITrcDataIn*>(m_frame_deformatter_root); + m_frame_deformatter_root->SetDemuxStatsBlock(&m_demux_stats); } else - initOK = false; + return false; } - return initOK; + return true; } void DecodeTree::setSingleRoot(TrcPktProcI *pComp) @@ -621,6 +689,7 @@ ocsd_err_t DecodeTree::addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter switch (protocol) { case OCSD_PROTOCOL_ETMV4I: + case OCSD_PROTOCOL_ETE: { PacketPrinter<EtmV4ITrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV4ITrcPacket> *>(pPrinter); if (bMonitor) diff --git a/decoder/source/ocsd_error.cpp b/decoder/source/ocsd_error.cpp index 74e9e4977f60..ee01064a3476 100644 --- a/decoder/source/ocsd_error.cpp +++ b/decoder/source/ocsd_error.cpp @@ -229,4 +229,25 @@ void ocsdError::appendErrorDetails(std::string &errStr, const ocsdError &error) 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_gen_elem_stack.cpp b/decoder/source/ocsd_gen_elem_stack.cpp index bb758427a9b8..66fe75d9899a 100644 --- a/decoder/source/ocsd_gen_elem_stack.cpp +++ b/decoder/source/ocsd_gen_elem_stack.cpp @@ -42,6 +42,7 @@ OcsdGenElemStack::OcsdGenElemStack() : m_curr_elem_idx(0), m_send_elem_idx(0), m_CSID(0), + m_sendIf(NULL), m_is_init(false) { diff --git a/decoder/source/ocsd_lib_dcd_register.cpp b/decoder/source/ocsd_lib_dcd_register.cpp index adb042dcadff..0233c89eaa06 100644 --- a/decoder/source/ocsd_lib_dcd_register.cpp +++ b/decoder/source/ocsd_lib_dcd_register.cpp @@ -39,13 +39,15 @@ #include "opencsd/etmv3/trc_dcd_mngr_etmv3.h" #include "opencsd/ptm/trc_dcd_mngr_ptm.h" #include "opencsd/stm/trc_dcd_mngr_stm.h" +#include "opencsd/ete/trc_dcd_mngr_ete.h" // create array of built-in decoders to register with library static built_in_decoder_info_t sBuiltInArray[] = { CREATE_BUILTIN_ENTRY(DecoderMngrEtmV4I,OCSD_BUILTIN_DCD_ETMV4I), CREATE_BUILTIN_ENTRY(DecoderMngrEtmV3, OCSD_BUILTIN_DCD_ETMV3), CREATE_BUILTIN_ENTRY(DecoderMngrPtm, OCSD_BUILTIN_DCD_PTM), - CREATE_BUILTIN_ENTRY(DecoderMngrStm, OCSD_BUILTIN_DCD_STM) + CREATE_BUILTIN_ENTRY(DecoderMngrStm, OCSD_BUILTIN_DCD_STM), + CREATE_BUILTIN_ENTRY(DecoderMngrETE, OCSD_BUILTIN_DCD_ETE) //{ 0, 0, 0} }; @@ -90,7 +92,6 @@ OcsdLibDcdRegister::~OcsdLibDcdRegister() m_pLastTypedDecoderMngr = 0; } - const ocsd_err_t OcsdLibDcdRegister::registerDecoderTypeByName(const std::string &name, IDecoderMngr *p_decoder_fact) { if(isRegisteredDecoder(name)) diff --git a/decoder/source/pkt_printers/trc_print_fact.cpp b/decoder/source/pkt_printers/trc_print_fact.cpp index 52dcb6b3e1ac..6b5df1f472e0 100644 --- a/decoder/source/pkt_printers/trc_print_fact.cpp +++ b/decoder/source/pkt_printers/trc_print_fact.cpp @@ -55,8 +55,9 @@ ItemPrinter *PktPrinterFact::createProtocolPrinter(std::vector<ItemPrinter *> &p { 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: diff --git a/decoder/source/ptm/trc_pkt_proc_ptm.cpp b/decoder/source/ptm/trc_pkt_proc_ptm.cpp index 7c90b62e6413..668a14b73df0 100644 --- a/decoder/source/ptm/trc_pkt_proc_ptm.cpp +++ b/decoder/source/ptm/trc_pkt_proc_ptm.cpp @@ -224,6 +224,7 @@ void TrcPktProcPtm::InitProcessorState() m_waitASyncSOPkt = false; m_bAsyncRawOp = false; m_bOPNotSyncPkt = false; + m_excepAltISA = 0; m_curr_packet.ResetState(); InitPacketState(); @@ -559,7 +560,7 @@ void TrcPktProcPtm::pktWPointUpdate() m_gotExcepBytes = false; // mark as not got all required exception bytes thus far m_numExcepBytes = 0; // 0 read in - m_addrPktIsa = ocsd_isa_unknown; // not set by this packet as yet + m_addrPktIsa = ocsd_isa_unknown; // not set by this packet as yet } // collect all the bytes needed @@ -567,10 +568,12 @@ void TrcPktProcPtm::pktWPointUpdate() { if(readByte(currByte)) { + byteIdx = m_currPacketData.size() - 1; if(!m_gotAddrBytes) { - if(byteIdx < 4) + // byteIdx for address byte will run from 1 to 5 - first 4 my have continuation or not. + if(byteIdx <= 4) { // address bytes 1 - 4; // ISA stays the same diff --git a/decoder/source/trc_core_arch_map.cpp b/decoder/source/trc_core_arch_map.cpp index a26f79db996e..f25ab1e5ddfa 100644 --- a/decoder/source/trc_core_arch_map.cpp +++ b/decoder/source/trc_core_arch_map.cpp @@ -72,17 +72,6 @@ static ap_map_elem_t ap_map_array[] = { "Cortex-M4", { ARCH_V7, profile_CortexM } } }; -static ap_map_elem_t arch_map_array[] = -{ - { "ARMv7-A", { ARCH_V7, profile_CortexA } }, - { "ARMv7-R", { ARCH_V7, profile_CortexR } }, - { "ARMv7-M", { ARCH_V7, profile_CortexM } }, - { "ARMv8-A", { ARCH_V8, profile_CortexA } }, - { "ARMv8.3-A", { ARCH_V8r3, profile_CortexA } }, - { "ARMv8-R", { ARCH_V8, profile_CortexR } }, - { "ARMv8-M", { ARCH_V8, profile_CortexM } }, -}; - CoreArchProfileMap::CoreArchProfileMap() { unsigned i; @@ -90,10 +79,99 @@ CoreArchProfileMap::CoreArchProfileMap() { core_profiles[ap_map_array[i].name] = ap_map_array[i].ap; } - for (i = 0; i < sizeof(arch_map_array) / sizeof(_ap_map_elements); i++) +} + +ocsd_arch_profile_t CoreArchProfileMap::getArchProfile(const std::string &coreName) +{ + ocsd_arch_profile_t ap = { ARCH_UNKNOWN, profile_Unknown }; + bool bFound = false; + + std::map<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()) { - arch_profiles[arch_map_array[i].name] = arch_map_array[i].ap; + ap = it->second; + bFound = true; } + + /* try a pattern match on core name - pick up ARMvM[.m]-P and ARM-{aa|AA}64[-P] */ + if (!bFound) + ap = getPatternMatchCoreName(coreName); + + return ap; } +ocsd_arch_profile_t CoreArchProfileMap::getPatternMatchCoreName(const std::string &coreName) +{ + ocsd_arch_profile_t ap = { ARCH_UNKNOWN, profile_Unknown }; + size_t pos; + /* look for ARMvM[.m]-P */ + pos = coreName.find("ARMv"); + if (pos == 0) + { + int majver = coreName[4] - '0'; + int minver = 0; + int dotoffset = 0; + + pos = coreName.find_first_of("."); + if (pos == 5) { + minver = coreName[6] - '0'; + dotoffset = 2; + } + else if (pos != std::string::npos) + return ap; + + if (majver == 7) + ap.arch = ARCH_V7; + else if (majver >= 8) { + ap.arch = ARCH_AA64; /* default to 8.3+*/ + if (majver == 8) { + if (minver < 3) + ap.arch = ARCH_V8; + else if (minver == 3) + ap.arch = ARCH_V8r3; + } + } + else + return ap; /* no valid version - return unknown */ + + if (coreName.find_first_of("-", 4) == (size_t)(5 + dotoffset)) { + int profile_idx = 6 + dotoffset; + if (coreName[profile_idx] == 'A') + ap.profile = profile_CortexA; + else if (coreName[profile_idx] == 'R') + ap.profile = profile_CortexR; + else if (coreName[profile_idx] == 'M') + ap.profile = profile_CortexM; + else + ap.arch = ARCH_UNKNOWN; /*reset arch, return unknown*/ + } + else + ap.arch = ARCH_UNKNOWN; /*reset arch, return unknown*/ + return ap; + } + + /* look for ARM-{AA|aa}64[-P] */ + pos = coreName.find("ARM-"); + if (pos == 0) + { + pos = coreName.find("aa64"); + if (pos != 4) + pos = coreName.find("AA64"); + if (pos == 4) + { + ap.arch = ARCH_AA64; + ap.profile = profile_CortexA; + if (coreName.find_first_of("-", 7) == 8) { + if (coreName[9] == 'R') + ap.profile = profile_CortexR; + else if (coreName[9] == 'M') + ap.profile = profile_CortexM; + } + } + } + return ap; +} /* End of File trc_core_arch_map.cpp */ diff --git a/decoder/source/trc_frame_deformatter.cpp b/decoder/source/trc_frame_deformatter.cpp index 4d46854a655b..3b2aead875ca 100644 --- a/decoder/source/trc_frame_deformatter.cpp +++ b/decoder/source/trc_frame_deformatter.cpp @@ -54,7 +54,8 @@ TraceFmtDcdImpl::TraceFmtDcdImpl() : TraceComponent(DEFORMATTER_NAME), m_use_force_sync(false), m_alignment(16), // assume frame aligned data as default. m_b_output_packed_raw(false), - m_b_output_unpacked_raw(false) + m_b_output_unpacked_raw(false), + m_pStatsBlock(0) { resetStateParams(); @@ -244,7 +245,12 @@ ocsd_datapath_resp_t TraceFmtDcdImpl::processTraceData( 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); @@ -254,11 +260,6 @@ ocsd_datapath_resp_t TraceFmtDcdImpl::processTraceData( throw ocsdError(&err); } - // record the incoming block for extraction routines to use. - m_in_block_base = pDataBlock; - m_in_block_size = dataBlockSize; - m_in_block_processed = 0; - // processing loop... if(checkForSync()) { @@ -324,12 +325,18 @@ ocsd_err_t TraceFmtDcdImpl::DecodeConfigure(uint32_t flags) } else { + // alightment is the multiple of bytes the buffer size must be. m_cfgFlags = flags; + + // using memory aligned buffers, the formatter always outputs 16 byte frames so enforce + // this on the input m_alignment = 16; - if(flags & OCSD_DFRMTR_HAS_FSYNCS) - m_alignment = 4; - else if(flags & OCSD_DFRMTR_HAS_HSYNCS) + // if we have HSYNCS then always align to 2 byte buffers + if(flags & OCSD_DFRMTR_HAS_HSYNCS) m_alignment = 2; + // otherwise FSYNCS only can have 4 byte aligned buffers. + else if(flags & OCSD_DFRMTR_HAS_FSYNCS) + m_alignment = 4; } return err; } @@ -344,6 +351,7 @@ void TraceFmtDcdImpl::resetStateParams() // current frame processing m_ex_frm_n_bytes = 0; + m_b_fsync_start_eob = false; m_trc_curr_idx_sof = OCSD_BAD_TRC_INDEX; } @@ -415,20 +423,23 @@ void TraceFmtDcdImpl::outputUnsyncedBytes(uint32_t /*num_bytes*/) //**TBD: } -int TraceFmtDcdImpl::checkForResetFSyncPatterns() +ocsd_err_t TraceFmtDcdImpl::checkForResetFSyncPatterns(uint32_t &f_sync_bytes) { const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC bool check_for_fsync = true; int num_fsyncs = 0; - const uint8_t *dataPtr = m_in_block_base + m_in_block_processed; + uint32_t bytes_processed = m_in_block_processed; + const uint8_t *dataPtr = m_in_block_base + bytes_processed; + ocsd_err_t err = OCSD_OK; - while (check_for_fsync && (m_in_block_processed < m_in_block_size)) + while (check_for_fsync && (bytes_processed < m_in_block_size)) { // look for consecutive fsyncs as padding or for reset downstream - both cases will reset downstream.... if (*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) { dataPtr += sizeof(uint32_t); - num_fsyncs++; + num_fsyncs++; + bytes_processed += sizeof(uint32_t); } else check_for_fsync = false; @@ -436,7 +447,6 @@ int TraceFmtDcdImpl::checkForResetFSyncPatterns() if (num_fsyncs) { - printf("Frame deformatter: Found %d FSYNCS\n",num_fsyncs); if ((num_fsyncs % 4) == 0) { // reset the upstream decoders @@ -449,32 +459,40 @@ int TraceFmtDcdImpl::checkForResetFSyncPatterns() } else { - // TBD: throw processing error, none frame size block of fsyncs + err = OCSD_ERR_DFMTR_BAD_FHSYNC; } } - return num_fsyncs * 4; + f_sync_bytes += num_fsyncs * 4; + return err; } - +/* Extract a single frame from the input buffer. */ bool TraceFmtDcdImpl::extractFrame() { const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC const uint16_t HSYNC_PATTERN = 0x7FFF; // LE host pattern for HSYNC + const uint16_t FSYNC_START = 0xFFFF; // LE host pattern for start 2 bytes of fsync - - bool cont_process = true; // continue processing after extraction. + ocsd_err_t err; uint32_t f_sync_bytes = 0; // skipped f sync bytes uint32_t h_sync_bytes = 0; // skipped h sync bytes uint32_t ex_bytes = 0; // extracted this pass (may be filling out part frame) + uint32_t buf_left = m_in_block_size - m_in_block_processed; // bytes remaining in buffer this pass. - // memory aligned sources are always multiples of frames, aligned to start. + // last call was end of input block - but carried on to process full frame. + // exit early here. + if (!buf_left) + return false; + + // memory aligned input data is forced to be always multiples of 16 byte frames, aligned to start. if( m_cfgFlags & OCSD_DFRMTR_FRAME_MEM_ALIGN) { // some linux drivers (e.g. for perf) will insert FSYNCS to pad or differentiate - // between blocks of aligned data, always in frame aligned complete 16 byte frames. + // between blocks of aligned data, always in frame aligned complete 16 byte frames. + // we need to skip past these frames, resetting as we go. if (m_cfgFlags & OCSD_DFRMTR_RESET_ON_4X_FSYNC) { - f_sync_bytes = checkForResetFSyncPatterns(); + err = checkForResetFSyncPatterns(f_sync_bytes); /* in this case the FSYNC pattern is output on both packed and unpacked cases */ if (f_sync_bytes && (m_b_output_packed_raw || m_b_output_unpacked_raw)) @@ -486,77 +504,96 @@ bool TraceFmtDcdImpl::extractFrame() m_in_block_base + m_in_block_processed, 0); } + + // throw processing error, none frame size block of fsyncs + if (err) + throw ocsdError(OCSD_ERR_SEV_ERROR, err, m_trc_curr_idx, "Incorrect FSYNC frame reset pattern"); + + buf_left -= f_sync_bytes; } - if((m_in_block_processed+f_sync_bytes) == m_in_block_size) + if (buf_left) { - m_ex_frm_n_bytes = 0; - cont_process = false; // end of input data. - } - else - { - // always a complete frame. - m_ex_frm_n_bytes = OCSD_DFRMTR_FRAME_SIZE; - memcpy(m_ex_frm_data, m_in_block_base + m_in_block_processed + f_sync_bytes, m_ex_frm_n_bytes); - m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; - ex_bytes = OCSD_DFRMTR_FRAME_SIZE; + // always a complete frame - the input data has to be 16 byte multiple alignment. + m_ex_frm_n_bytes = OCSD_DFRMTR_FRAME_SIZE; + memcpy(m_ex_frm_data, m_in_block_base + m_in_block_processed + f_sync_bytes, m_ex_frm_n_bytes); + m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; + ex_bytes = OCSD_DFRMTR_FRAME_SIZE; } } else { // extract data accounting for frame syncs and hsyncs if present. // we know we are aligned at this point - could be FSYNC or HSYNCs here. + // HSYNC present, library forces input to be aligned 2 byte multiples + // FSYNC - w/o HSYNCs, forces input to be aligned 4 byte multiples. // check what we a looking for - bool hasFSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) == OCSD_DFRMTR_HAS_FSYNCS); - bool hasHSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_HSYNCS) == OCSD_DFRMTR_HAS_HSYNCS); + bool hasFSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) == OCSD_DFRMTR_HAS_FSYNCS); + bool hasHSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_HSYNCS) == OCSD_DFRMTR_HAS_HSYNCS); + + const uint8_t* dataPtr = m_in_block_base + m_in_block_processed; + uint16_t data_pair_val; - const uint8_t *dataPtr = m_in_block_base+m_in_block_processed; - const uint8_t *eodPtr = m_in_block_base+m_in_block_size; - - cont_process = (bool)(dataPtr < eodPtr); - // can have FSYNCS at start of frame (in middle is an error). - if(hasFSyncs && cont_process && (m_ex_frm_n_bytes == 0)) + if (hasFSyncs && (m_ex_frm_n_bytes == 0)) { - while((*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) && cont_process) + // was there an fsync start at the end of the last buffer? + if (m_b_fsync_start_eob) { + // last 2 of FSYNC look like HSYNC + if (*(uint16_t*)(dataPtr) != HSYNC_PATTERN) + { + // this means 0xFFFF followed by something else - invalid ID + ???? + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC pattern before frame or invalid ID.(0x7F)"); + } + else + { + f_sync_bytes += 2; + buf_left -= 2; + dataPtr += 2; + } + m_b_fsync_start_eob = false; + } + + // regular fsync checks + while ((buf_left >= 4) && (*((uint32_t*)(dataPtr)) == FSYNC_PATTERN)) { f_sync_bytes += 4; dataPtr += 4; - cont_process = (bool)(dataPtr < eodPtr); + buf_left -= 4; } - } - // not an FSYNC - while((m_ex_frm_n_bytes < OCSD_DFRMTR_FRAME_SIZE) && cont_process) - { - // check for illegal out of sequence FSYNC - if((m_ex_frm_n_bytes % 4) == 0) + // handle possible part fsync at the end of a buffer + if (buf_left == 2) { - if(*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) + if (*(uint16_t*)(dataPtr) == FSYNC_START) { - // throw an illegal FSYNC error - throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC in frame."); + f_sync_bytes += 2; + buf_left -= 2; + dataPtr += 2; + m_b_fsync_start_eob = true; } } + } + // process remaining data in pairs of bytes + while ((m_ex_frm_n_bytes < OCSD_DFRMTR_FRAME_SIZE) && buf_left) + { // mark start of frame after FSyncs - if(m_ex_frm_n_bytes == 0) + if (m_ex_frm_n_bytes == 0) m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; m_ex_frm_data[m_ex_frm_n_bytes] = dataPtr[0]; - m_ex_frm_data[m_ex_frm_n_bytes+1] = dataPtr[1]; - m_ex_frm_n_bytes+=2; - ex_bytes +=2; + m_ex_frm_data[m_ex_frm_n_bytes + 1] = dataPtr[1]; + + data_pair_val = *((uint16_t*)(dataPtr)); // check pair is not HSYNC - if(*((uint16_t *)(dataPtr)) == HSYNC_PATTERN) + if (data_pair_val == HSYNC_PATTERN) { - if(hasHSyncs) + if (hasHSyncs) { - m_ex_frm_n_bytes-=2; - ex_bytes -= 2; - h_sync_bytes+=2; + h_sync_bytes += 2; } else { @@ -564,22 +601,27 @@ bool TraceFmtDcdImpl::extractFrame() throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad HSYNC in frame."); } } + // can't have a start of FSYNC here / illegal trace ID + else if (data_pair_val == FSYNC_START) + { + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC start in frame or invalid ID (0x7F)."); + } + else + { + m_ex_frm_n_bytes += 2; + ex_bytes += 2; + } + buf_left -= 2; dataPtr += 2; - cont_process = (bool)(dataPtr < eodPtr); } - - // if we hit the end of data but still have a complete frame waiting, - // need to continue processing to allow it to be used. - if(!cont_process && (m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE)) - cont_process = true; } // total bytes processed this pass uint32_t total_processed = ex_bytes + f_sync_bytes + h_sync_bytes; // output raw data on raw frame channel - packed raw. - if (((m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE) || !cont_process) && m_b_output_packed_raw) + if (((m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE) || (buf_left == 0)) && m_b_output_packed_raw) { outputRawMonBytes( OCSD_OP_DATA, m_trc_curr_idx, @@ -595,7 +637,11 @@ bool TraceFmtDcdImpl::extractFrame() // update index past the processed data m_trc_curr_idx += total_processed; - return cont_process; + // update any none trace data byte stats + addToFrameStats((uint64_t)(f_sync_bytes + h_sync_bytes)); + + // if we are exiting with a full frame then signal processing to continue + return (bool)(m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE); } bool TraceFmtDcdImpl::unpackFrame() @@ -604,6 +650,7 @@ bool TraceFmtDcdImpl::unpackFrame() 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; @@ -650,6 +697,7 @@ bool TraceFmtDcdImpl::unpackFrame() /// TBD - ID indexing in here. } + noneDataBytes++; } else // it's just data @@ -671,6 +719,7 @@ bool TraceFmtDcdImpl::unpackFrame() { // 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 @@ -678,6 +727,9 @@ bool TraceFmtDcdImpl::unpackFrame() 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; } @@ -716,6 +768,8 @@ bool TraceFmtDcdImpl::outputFrame() 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; @@ -739,7 +793,12 @@ bool TraceFmtDcdImpl::outputFrame() 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. } } @@ -754,13 +813,44 @@ bool TraceFmtDcdImpl::outputFrame() 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 */ /***************************************************************/ @@ -819,21 +909,27 @@ componentAttachPt<ITraceErrorLog> *TraceFormatterFrameDecoder::getErrLogAttachPt return (m_pDecoder != 0) ? m_pDecoder->getErrorLogAttachPt() : 0; } -/* configuration - set operational mode for incoming stream (has FSYNCS etc) */ -ocsd_err_t TraceFormatterFrameDecoder::Configure(uint32_t cfg_flags) +ocsd_err_t TraceFormatterFrameDecoder::Init() { - if(!m_pDecoder) - { - if(m_instNum >= 0) + if (!m_pDecoder) + { + if (m_instNum >= 0) m_pDecoder = new (std::nothrow) TraceFmtDcdImpl(m_instNum); else m_pDecoder = new (std::nothrow) TraceFmtDcdImpl(); - if(!m_pDecoder) return OCSD_ERR_MEM; + if (!m_pDecoder) return OCSD_ERR_MEM; } - m_pDecoder->DecodeConfigure(cfg_flags); return OCSD_OK; } +/* configuration - set operational mode for incoming stream (has FSYNCS etc) */ +ocsd_err_t TraceFormatterFrameDecoder::Configure(uint32_t cfg_flags) +{ + if (!m_pDecoder) + return OCSD_ERR_NOT_INIT; + return m_pDecoder->DecodeConfigure(cfg_flags); +} + const uint32_t TraceFormatterFrameDecoder::getConfigFlags() const { uint32_t flags = 0; @@ -865,5 +961,10 @@ 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 index e1fc17ab259f..3571d5f2fc47 100644 --- a/decoder/source/trc_frame_deformatter_impl.h +++ b/decoder/source/trc_frame_deformatter_impl.h @@ -75,6 +75,8 @@ private: 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, @@ -113,12 +115,20 @@ private: void setRawChanFilterAll(bool bEnable); const bool rawChanEnabled(const uint8_t id) const; - int checkForResetFSyncPatterns(); + ocsd_err_t checkForResetFSyncPatterns(uint32_t &f_sync_bytes); friend class TraceFormatterFrameDecoder; - // attachment points + // stats updates + void addToIDStats(uint64_t val); + void addToNoIDStats(uint64_t val); + void addToFrameStats(uint64_t val); + void addToUnknownIDStats(uint64_t val); + void addToReservedIDStats(uint64_t val); + + bool isReservedID(uint8_t ID) { return ((ID == 0) || (ID >= 0x70)); }; + // attachment points componentAttachPt<ITrcDataIn> m_IDStreams[128]; componentAttachPt<ITrcRawFrameIn> m_RawTraceFrame; @@ -142,12 +152,18 @@ private: // incoming frame buffer uint8_t m_ex_frm_data[OCSD_DFRMTR_FRAME_SIZE]; // buffer the current frame in case we have to stop part way through int m_ex_frm_n_bytes; // number of valid bytes in the current frame (extraction) + bool m_b_fsync_start_eob; // flag to indicate that the end of the last buffer was a pair of bytes + // (0xffff) that could only validly be the start and FSYNC. ocsd_trc_index_t m_trc_curr_idx_sof; // trace source index at start of frame. - // channel output data - can never be more than a frame of data for a single ID. - out_chan_data m_out_data[7]; // can only be 8 ID changes in a frame, but last on has no associated data so 7 possible data blocks + /* channel output data - can never be more than a frame of data for a single ID. + * 8 possible ID changes per frame. Although the final one can have no associated data, a pathological + * case exists with 7 ID changes, all data associated with a previous frame, except for last + * ID / data byte which is data. Not possible with normal hardware but guard against corrupt input. + */ + out_chan_data m_out_data[8]; // output data for a given ID int m_out_data_idx; // number of out_chan_data frames used. - int m_out_processed; // number of complete out_chan_data frames output. + int m_out_processed; // number of complete out_chan_data frames output. /* local copy of input buffer pointers*/ const uint8_t *m_in_block_base; @@ -159,6 +175,8 @@ private: bool m_b_output_unpacked_raw; bool m_raw_chan_enable[128]; + + ocsd_demux_stats_t *m_pStatsBlock; }; diff --git a/decoder/source/trc_gen_elem.cpp b/decoder/source/trc_gen_elem.cpp index e1774203ebc5..c94c5a7c6848 100644 --- a/decoder/source/trc_gen_elem.cpp +++ b/decoder/source/trc_gen_elem.cpp @@ -54,7 +54,10 @@ static const char *s_elem_descs[][2] = {"OCSD_GEN_TRC_ELEM_TIMESTAMP","Timestamp - preceding elements happeded before this time."}, {"OCSD_GEN_TRC_ELEM_CYCLE_COUNT","Cycle count - cycles since last cycle count value - associated with a preceding instruction range."}, {"OCSD_GEN_TRC_ELEM_EVENT","Event - numbered event or trigger"}, - {"OCSD_GEN_TRC_ELEM_SWTRACE","Software trace packet - may contain data payload."}, + {"OCSD_GEN_TRC_ELEM_SWTRACE","Software trace packet - may contain data payload. STM / ITM hardware trace with channel protocol."}, + {"OCSD_GEN_TRC_ELEM_SYNC_MARKER","Synchronisation marker - marks position in stream of an element that is output later."}, + {"OCSD_GEN_TRC_ELEM_MEMTRANS","Trace indication of transactional memory operations."}, + {"OCSD_GEN_TRC_ELEM_INSTRUMENTATION", "PE instrumentation trace - PE generated SW trace, application dependent protocol."}, {"OCSD_GEN_TRC_ELEM_CUSTOM","Fully custom packet type."} }; @@ -64,7 +67,8 @@ static const char *instr_type[] = { "iBR ", "ISB ", "DSB.DMB", - "WFI.WFE" + "WFI.WFE", + "TSTART" }; #define T_SIZE (sizeof(instr_type) / sizeof(const char *)) @@ -105,6 +109,16 @@ static const char *s_unsync_reason[] = { "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 { @@ -158,7 +172,14 @@ void OcsdTraceElement::toString(std::string &str) const { oss << "EL" << std::dec << (int)(context.exception_level); } - oss << (context.security_level == ocsd_sec_secure ? "S; " : "N; ") << (context.bits64 ? "64-bit; " : "32-bit; "); + switch (context.security_level) + { + case ocsd_sec_secure: oss << "S; "; break; + case ocsd_sec_nonsecure: oss << "N; "; break; + case ocsd_sec_root: oss << "Root; "; break; + case ocsd_sec_realm: oss << "Realm; "; break; + } + oss << (context.bits64 ? "64-bit; " : "32-bit; "); if(context.vmid_valid) oss << "VMID=0x" << std::hex << context.vmid << "; "; if(context.ctxt_id_valid) @@ -190,6 +211,19 @@ void OcsdTraceElement::toString(std::string &str) const oss << " [" << s_unsync_reason[unsync_eot_info] << "]"; break; + case OCSD_GEN_TRC_ELEM_SYNC_MARKER: + oss << " [" << s_marker_t[sync_marker.type] << "(0x" << std::setfill('0') << std::setw(8) << std::hex << sync_marker.value << ")]"; + break; + + case OCSD_GEN_TRC_ELEM_MEMTRANS: + if (mem_trans <= OCSD_MEM_TRANS_FAIL) + oss << s_transaction_type[mem_trans]; + break; + + case OCSD_GEN_TRC_ELEM_INSTRUMENTATION: + oss << "EL" << std::dec << (int)sw_ite.el << "; 0x" << std::setfill('0') << std::setw(16) << std::hex << sw_ite.value; + break; + default: break; } if(has_cc) diff --git a/decoder/source/trc_printable_elem.cpp b/decoder/source/trc_printable_elem.cpp index 88c7bb226f41..2b60c030d53f 100644 --- a/decoder/source/trc_printable_elem.cpp +++ b/decoder/source/trc_printable_elem.cpp @@ -52,8 +52,6 @@ void trcPrintableElem::getValStr(std::string &valStr, const int valTotalBitSize, assert((valTotalBitSize >= 4) && (valTotalBitSize <= 64)); - uint64_t LimitMask = ~0ULL; - LimitMask >>= 64-valTotalBitSize; valStr = "0x"; if(asHex) |