diff options
Diffstat (limited to 'decoder/source/etmv3')
-rw-r--r-- | decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp | 65 | ||||
-rw-r--r-- | decoder/source/etmv3/trc_pkt_decode_etmv3.cpp | 681 | ||||
-rw-r--r-- | decoder/source/etmv3/trc_pkt_elem_etmv3.cpp | 688 | ||||
-rw-r--r-- | decoder/source/etmv3/trc_pkt_proc_etmv3.cpp | 122 | ||||
-rw-r--r-- | decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp | 1224 | ||||
-rw-r--r-- | decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h | 175 |
6 files changed, 2955 insertions, 0 deletions
diff --git a/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp b/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp new file mode 100644 index 0000000..f2556e4 --- /dev/null +++ b/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp @@ -0,0 +1,65 @@ +/* + * \file trc_cmp_cfg_etmv3.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + */ + + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h" + +EtmV3Config::EtmV3Config() +{ + // defaults set ETMv3.4, V7A, instruction only. + m_cfg.arch_ver = ARCH_V7; + m_cfg.core_prof = profile_CortexA; + m_cfg.reg_ccer = 0; + m_cfg.reg_idr = 0x4100F240; // default trace IDR value + m_cfg.reg_ctrl = 0; +} + +EtmV3Config::EtmV3Config(const ocsd_etmv3_cfg *cfg_regs) +{ + m_cfg = *cfg_regs; +} + +EtmV3Config::EtmTraceMode const EtmV3Config::GetTraceMode() const +{ + int mode = 0 + ( isDataValTrace() ? 1 : 0 ) + (isDataAddrTrace() ? 2 : 0) + (isInstrTrace() ? 0 : 3); + return (EtmTraceMode)mode; +} + +const int EtmV3Config::CtxtIDBytes() const +{ + int ctxtIdsizes[] = { 0, 1, 2, 4 }; + return ctxtIdsizes[(m_cfg.reg_ctrl >> 14) & 0x3]; +} + +/* End of File trc_cmp_cfg_etmv3.cpp */ diff --git a/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp b/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp new file mode 100644 index 0000000..e68a73f --- /dev/null +++ b/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp @@ -0,0 +1,681 @@ +/*! + * \file trc_pkt_decode_etmv3.cpp + * \brief OpenCSD : ETMv3 trace packet decode. + * + * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opencsd/etmv3/trc_pkt_decode_etmv3.h" + +#define DCD_NAME "DCD_ETMV3" + +TrcPktDecodeEtmV3::TrcPktDecodeEtmV3() : + TrcPktDecodeBase(DCD_NAME) +{ + initDecoder(); +} + +TrcPktDecodeEtmV3::TrcPktDecodeEtmV3(int instIDNum) : + TrcPktDecodeBase(DCD_NAME, instIDNum) +{ + initDecoder(); +} + +TrcPktDecodeEtmV3::~TrcPktDecodeEtmV3() +{ +} + + +/* implementation packet decoding interface */ +ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bPktDone = false; + + if(!m_config) + return OCSD_RESP_FATAL_NOT_INIT; + + // iterate round the state machine, waiting for sync, then decoding packets. + while(!bPktDone) + { + switch(m_curr_state) + { + case NO_SYNC: + // output the initial not synced packet to the sink + resp = sendUnsyncPacket(); + m_curr_state = WAIT_ASYNC; // immediate wait for ASync and actually check out the packet + break; + + case WAIT_ASYNC: + // if async, wait for ISync, but this packet done. + if(m_curr_packet_in->getType() == ETM3_PKT_A_SYNC) + m_curr_state = WAIT_ISYNC; + bPktDone = true; + break; + + case WAIT_ISYNC: + m_bWaitISync = true; // we are waiting for ISync + if((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC) || + (m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE)) + { + // process the ISync immediately as the first ISync seen. + resp = processISync((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE),true); + m_curr_state = SEND_PKTS; + m_bWaitISync = false; + } + // something like TS, CC, PHDR+CC, which after ASYNC may be valid prior to ISync + else if(preISyncValid(m_curr_packet_in->getType())) + { + // decode anything that might be valid - send will be set automatically + resp = decodePacket(bPktDone); + } + else + bPktDone = true; + break; + + case DECODE_PKTS: + resp = decodePacket(bPktDone); + break; + + case SEND_PKTS: + resp = m_outputElemList.sendElements(); + if(OCSD_DATA_RESP_IS_CONT(resp)) + m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS; + bPktDone = true; + break; + + default: + bPktDone = true; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,"Unknown Decoder State")); + resetDecoder(); // mark decoder as unsynced - dump any current state. + resp = OCSD_RESP_FATAL_SYS_ERR; + break; + } + } + + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + OcsdTraceElement *pElem = 0; + try { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EO_TRACE); + pElem->setUnSyncEOTReason(UNSYNC_EOT); + m_outputElemList.commitAllPendElem(); + m_curr_state = SEND_PKTS; + resp = m_outputElemList.sendElements(); + if(OCSD_DATA_RESP_IS_CONT(resp)) + m_curr_state = DECODE_PKTS; + } + catch(ocsdError &err) + { + LogError(err); + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::onReset() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + m_unsync_info = UNSYNC_RESET_DECODER; + resetDecoder(); + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::onFlush() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + if(m_curr_state == SEND_PKTS) + { + resp = m_outputElemList.sendElements(); + if(OCSD_DATA_RESP_IS_CONT(resp)) + m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS; + } + return resp; +} + +ocsd_err_t TrcPktDecodeEtmV3::onProtocolConfig() +{ + ocsd_err_t err = OCSD_OK; + if(m_config) + { + // set some static config elements + m_CSID = m_config->getTraceID(); + + // check config compatible with current decoder support level. + // at present no data trace; + if(m_config->GetTraceMode() != EtmV3Config::TM_INSTR_ONLY) + { + err = OCSD_ERR_HW_CFG_UNSUPP; + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv3 trace decoder : data trace decode not yet supported")); + } + + // need to set up core profile info in follower + ocsd_arch_profile_t arch_profile; + arch_profile.arch = m_config->getArchVersion(); + arch_profile.profile = m_config->getCoreProfile(); + m_code_follower.setArchProfile(arch_profile); + m_code_follower.setMemSpaceCSID(m_CSID); + m_outputElemList.initCSID(m_CSID); + } + else + err = OCSD_ERR_NOT_INIT; + return err; +} + +/* local decode methods */ + +// initialise on creation +void TrcPktDecodeEtmV3::initDecoder() +{ + m_CSID = 0; + resetDecoder(); + m_unsync_info = UNSYNC_INIT_DECODER; + m_code_follower.initInterfaces(getMemoryAccessAttachPt(),getInstrDecodeAttachPt()); + m_outputElemList.initSendIf(getTraceElemOutAttachPt()); +} + +// reset for first use / re-use. +void TrcPktDecodeEtmV3::resetDecoder() +{ + m_curr_state = NO_SYNC; // mark as not synced + m_bNeedAddr = true; + m_bSentUnknown = false; + m_bWaitISync = false; + m_outputElemList.reset(); +} + +OcsdTraceElement *TrcPktDecodeEtmV3::GetNextOpElem(ocsd_datapath_resp_t &resp) +{ + OcsdTraceElement *pElem = m_outputElemList.getNextElem(m_index_curr_pkt); + if(pElem == 0) + { + resp = OCSD_RESP_FATAL_NOT_INIT; + throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_MEM,m_index_curr_pkt,m_CSID,"Memory Allocation Error - fatal"); + } + return pElem; +} + +bool TrcPktDecodeEtmV3::preISyncValid(ocsd_etmv3_pkt_type pkt_type) +{ + bool bValid = false; + // its a timestamp + if((pkt_type == ETM3_PKT_TIMESTAMP) || + // or we are cycleacc and its a packet that can have CC in it + (m_config->isCycleAcc() && ((pkt_type == ETM3_PKT_CYCLE_COUNT) || (pkt_type == ETM3_PKT_P_HDR))) + ) + bValid = true; + return bValid; +} + +// simple packet transforms handled here, more complex processing passed on to specific routines. +ocsd_datapath_resp_t TrcPktDecodeEtmV3::decodePacket(bool &pktDone) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bISyncHasCC = false; + OcsdTraceElement *pElem = 0; + pktDone = false; + + // there may be pended packets that can now be committed. + // only the branch address with exception and cancel element can cancel + // if not one of those, commit immediately, otherwise defer to branch address handler. + if(m_curr_packet_in->getType() != ETM3_PKT_BRANCH_ADDRESS) + m_outputElemList.commitAllPendElem(); + + try { + + switch(m_curr_packet_in->getType()) + { + + case ETM3_PKT_NOTSYNC: + // mark as not synced - must have lost sync in the packet processor somehow + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Trace Packet Synchronisation Lost"); + break; + + // no action for these packets - ignore and continue + case ETM3_PKT_INCOMPLETE_EOT: + case ETM3_PKT_A_SYNC: + case ETM3_PKT_IGNORE: + break; + + // markers for valid packets + case ETM3_PKT_CYCLE_COUNT: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); + pElem->setCycleCount(m_curr_packet_in->getCycleCount()); + break; + + case ETM3_PKT_TRIGGER: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EVENT); + pElem->setEvent(EVENT_TRIGGER,0); + break; + + case ETM3_PKT_BRANCH_ADDRESS: + resp = processBranchAddr(); + break; + + case ETM3_PKT_I_SYNC_CYCLE: + bISyncHasCC = true; + case ETM3_PKT_I_SYNC: + resp = processISync(bISyncHasCC); + break; + + case ETM3_PKT_P_HDR: + resp = processPHdr(); + break; + + case ETM3_PKT_CONTEXT_ID: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID()); + pElem->setContext(m_PeContext); + break; + + case ETM3_PKT_VMID: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_PeContext.setVMID(m_curr_packet_in->getVMID()); + pElem->setContext(m_PeContext); + break; + + case ETM3_PKT_EXCEPTION_ENTRY: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION); + pElem->setExcepMarker(); // exception entries are always v7M data markers in ETMv3 trace. + break; + + case ETM3_PKT_EXCEPTION_EXIT: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); + pendExceptionReturn(); + break; + + case ETM3_PKT_TIMESTAMP: + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); + pElem->setTS(m_curr_packet_in->getTS()); + break; + + // data packets - data trace not supported at present + case ETM3_PKT_STORE_FAIL: + case ETM3_PKT_OOO_DATA: + case ETM3_PKT_OOO_ADDR_PLC: + case ETM3_PKT_NORM_DATA: + case ETM3_PKT_DATA_SUPPRESSED: + case ETM3_PKT_VAL_NOT_TRACED: + case ETM3_PKT_BAD_TRACEMODE: + resp = OCSD_RESP_FATAL_INVALID_DATA; + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_index_curr_pkt,m_CSID,"Invalid packet type : Data Tracing decode not supported."); + break; + + // packet errors + case ETM3_PKT_BAD_SEQUENCE: + resp = OCSD_RESP_FATAL_INVALID_DATA; + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Bad Packet sequence."); + break; + + default: + case ETM3_PKT_RESERVED: + resp = OCSD_RESP_FATAL_INVALID_DATA; + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Reserved or unknown packet ID."); + break; + } + m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; + pktDone = !m_outputElemList.elemToSend(); + } + catch(ocsdError &err) + { + LogError(err); + m_unsync_info = UNSYNC_BAD_PACKET; + resetDecoder(); // mark decoder as unsynced - dump any current state. + pktDone = true; + } + catch(...) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,m_CSID,"Bad Packet sequence.")); + resp = OCSD_RESP_FATAL_SYS_ERR; + m_unsync_info = UNSYNC_BAD_PACKET; + resetDecoder(); // mark decoder as unsynced - dump any current state. + pktDone = true; + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::sendUnsyncPacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + OcsdTraceElement *pElem = 0; + try { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_NO_SYNC); + pElem->setUnSyncEOTReason(m_unsync_info); + resp = m_outputElemList.sendElements(); + } + catch(ocsdError &err) + { + LogError(err); + m_unsync_info = UNSYNC_BAD_PACKET; + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + return resp; +} + +void TrcPktDecodeEtmV3::setNeedAddr(bool bNeedAddr) +{ + m_bNeedAddr = bNeedAddr; + m_bSentUnknown = false; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::processISync(const bool withCC, const bool firstSync /* = false */) +{ + // map ISync reason to generic reason codes. + static trace_on_reason_t on_map[] = { TRACE_ON_NORMAL, TRACE_ON_NORMAL, + TRACE_ON_OVERFLOW, TRACE_ON_EX_DEBUG }; + + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool ctxtUpdate = m_curr_packet_in->isCtxtUpdated(); + OcsdTraceElement *pElem = 0; + + try { + + pElem = GetNextOpElem(resp); + + if(firstSync || (m_curr_packet_in->getISyncReason() != iSync_Periodic)) + { + pElem->setType(OCSD_GEN_TRC_ELEM_TRACE_ON); + pElem->setTraceOnReason(on_map[(int)m_curr_packet_in->getISyncReason()]); + pElem = GetNextOpElem(resp); + } + + // look for context changes.... + if(ctxtUpdate || firstSync) + { + // if not first time out, read existing context in output element, + // otherwise we are setting it new. + if(firstSync) + m_PeContext.resetCtxt(); + + if(m_curr_packet_in->isCtxtIDUpdated()) + m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID()); + if(m_curr_packet_in->isVMIDUpdated()) + m_PeContext.setVMID(m_curr_packet_in->getVMID()); + if(m_curr_packet_in->isCtxtFlagsUpdated()) + { + m_PeContext.setEL(m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown); + m_PeContext.setSecLevel(m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure); + } + + // prepare the context packet + pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + pElem->setContext(m_PeContext); + pElem->setISA(m_curr_packet_in->ISA()); + + // with cycle count... + if(m_curr_packet_in->getISyncHasCC()) + pElem->setCycleCount(m_curr_packet_in->getCycleCount()); + + } + + // set ISync address - if it is a valid I address + if(!m_curr_packet_in->getISyncNoAddr()) + { + if(m_curr_packet_in->getISyncIsLSiPAddr()) + { + // TBD: handle extra data processing instruction for data trace + // need to output E atom relating to the data instruction + // rare - on start-up case. + + // main instruction address saved in data address for this packet type. + m_IAddr = m_curr_packet_in->getDataAddr(); + } + else + { + m_IAddr = m_curr_packet_in->getAddr(); + } + setNeedAddr(false); // ready to process atoms. + } + m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; + } + catch(ocsdError &err) + { + LogError(err); + m_unsync_info = UNSYNC_BAD_PACKET; + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + return resp; +} + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::processBranchAddr() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + OcsdTraceElement *pElem = 0; + bool bUpdatePEContext = false; + + // might need to cancel something ... if the last output was an instruction range or excep return + if(m_curr_packet_in->isExcepCancel()) + m_outputElemList.cancelPendElem(); + else + m_outputElemList.commitAllPendElem(); // otherwise commit any pending elements. + + // record the address + m_IAddr = m_curr_packet_in->getAddr(); + setNeedAddr(false); // no longer need an address. + + // exception packet - may need additional output + if(m_curr_packet_in->isExcepPkt()) + { + // exeception packet may have exception, context change, or both. + // check for context change + if(m_curr_packet_in->isCtxtUpdated()) + { + + ocsd_sec_level sec = m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure; + if(sec != m_PeContext.getSecLevel()) + { + m_PeContext.setSecLevel(sec); + bUpdatePEContext = true; + } + ocsd_ex_level pkt_el = m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown; + if(pkt_el != m_PeContext.getEL()) + { + m_PeContext.setEL(pkt_el); + bUpdatePEContext = true; + } + } + + // now decide if we need to send any packets out. + try { + + if(bUpdatePEContext) + { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + pElem->setContext(m_PeContext); + } + + // check for exception + if(m_curr_packet_in->excepNum() != 0) + { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION); + pElem->setExceptionNum(m_curr_packet_in->excepNum()); + } + + // finally - do we have anything to send yet? + m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; + } + catch(ocsdError &err) + { + LogError(err); + m_unsync_info = UNSYNC_BAD_PACKET; + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + } + return resp; +} + + +ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPHdr() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + OcsdTraceElement *pElem = 0; + ocsd_isa isa; + Etmv3Atoms atoms(m_config->isCycleAcc()); + + atoms.initAtomPkt(m_curr_packet_in,m_index_curr_pkt); + isa = m_curr_packet_in->ISA(); + m_code_follower.setMemSpaceAccess((m_PeContext.getSecLevel() == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N); + + try + { + do + { + // if we do not have a valid address then send any cycle count elements + // and stop processing + if(m_bNeedAddr) + { + // output unknown address packet or a cycle count packet + if(!m_bSentUnknown || m_config->isCycleAcc()) + { + pElem = GetNextOpElem(resp); + if(m_bSentUnknown || !atoms.numAtoms()) + pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); + else + pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN); + if(m_config->isCycleAcc()) + pElem->setCycleCount(atoms.getRemainCC()); + m_bSentUnknown = true; + } + atoms.clearAll(); // skip remaining atoms + } + else // have an address, can process atoms + { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); + + // cycle accurate may have a cycle count to use + if(m_config->isCycleAcc()) + { + // note: it is possible to have a CC only atom packet. + if(!atoms.numAtoms()) // override type if CC only + pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); + // set cycle count + pElem->setCycleCount(atoms.getAtomCC()); + } + + // now process the atom + if(atoms.numAtoms()) + { + m_code_follower.setISA(isa); + m_code_follower.followSingleAtom(m_IAddr,atoms.getCurrAtomVal()); + + // valid code range + if(m_code_follower.hasRange()) + { + pElem->setAddrRange(m_IAddr,m_code_follower.getRangeEn()); + pElem->setLastInstrInfo(atoms.getCurrAtomVal() == ATOM_E, + m_code_follower.getInstrType(), + m_code_follower.getInstrSubType(),m_code_follower.getInstrSize()); + pElem->setLastInstrCond(m_code_follower.isCondInstr()); + pElem->setISA(isa); + if(m_code_follower.hasNextAddr()) + m_IAddr = m_code_follower.getNextAddr(); + else + setNeedAddr(true); + } + + // next address has new ISA? + if(m_code_follower.ISAChanged()) + isa = m_code_follower.nextISA(); + + // there is a nacc + if(m_code_follower.isNacc()) + { + if(m_code_follower.hasRange()) + { + pElem = GetNextOpElem(resp); + pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + } + else + pElem->updateType(OCSD_GEN_TRC_ELEM_ADDR_NACC); + pElem->setAddrStart(m_code_follower.getNaccAddr()); + setNeedAddr(true); + m_code_follower.clearNacc(); // we have generated some code for the nacc. + } + } + + atoms.clearAtom(); // next atom + } + } + while(atoms.numAtoms()); + + // is tha last element an atom? + int numElem = m_outputElemList.getNumElem(); + if(numElem >= 1) + { + // if the last thing is an instruction range, pend it - could be cancelled later. + if(m_outputElemList.getElemType(numElem-1) == OCSD_GEN_TRC_ELEM_INSTR_RANGE) + m_outputElemList.pendLastNElem(1); + } + + // finally - do we have anything to send yet? + m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS; + } + catch(ocsdError &err) + { + LogError(err); + m_unsync_info = UNSYNC_BAD_PACKET; + resetDecoder(); // mark decoder as unsynced - dump any current state. + } + return resp; +} + +// if v7M -> pend only ERET, if V7A/R pend ERET and prev instr. +void TrcPktDecodeEtmV3::pendExceptionReturn() +{ + int pendElem = 1; + if(m_config->getCoreProfile() != profile_CortexM) + { + int nElem = m_outputElemList.getNumElem(); + if(nElem > 1) + { + if(m_outputElemList.getElemType(nElem - 2) == OCSD_GEN_TRC_ELEM_INSTR_RANGE) + pendElem = 2; // need to pend instr+eret for A/R + } + } + m_outputElemList.pendLastNElem(pendElem); +} + +/* End of File trc_pkt_decode_etmv3.cpp */ diff --git a/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp b/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp new file mode 100644 index 0000000..74034c3 --- /dev/null +++ b/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp @@ -0,0 +1,688 @@ +/* + * \file trc_pkt_elem_etmv3.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <cstring> +#include <sstream> +#include <iomanip> + +#include "opencsd/etmv3/trc_pkt_elem_etmv3.h" + +EtmV3TrcPacket::EtmV3TrcPacket() +{ + m_pkt_data.addr.size = VA_32BIT; // etm v3 only handles 32 bit addresses. +} + +EtmV3TrcPacket::~EtmV3TrcPacket() +{ +} + +// update interface - set packet values + +// clear this packet info +void EtmV3TrcPacket::Clear() +{ + // clear structure flags and counter elements etc, that work per packet. + // leave intra packet data unchanged + m_pkt_data.addr.pkt_bits = 0; + m_pkt_data.prev_isa = m_pkt_data.curr_isa; // mark ISA as not changed + m_pkt_data.exception.bits.present = 0; + m_pkt_data.atom.num = 0; + m_pkt_data.cycle_count = 0; + m_pkt_data.context.updated = 0; + m_pkt_data.context.updated_c = 0; + m_pkt_data.context.updated_v = 0; + m_pkt_data.data.ooo_tag = 0; + m_pkt_data.data.value = 0; + m_pkt_data.data.update_addr = 0; + m_pkt_data.data.update_be = 0; + m_pkt_data.data.update_dval = 0; + m_pkt_data.ts_update_bits = 0; + m_pkt_data.isync_info.has_cycle_count = 0; + m_pkt_data.isync_info.has_LSipAddress = 0; + m_pkt_data.isync_info.no_address = 0; +} + +// reset all state including intra packet +void EtmV3TrcPacket::ResetState() +{ + memset(&m_pkt_data,0,sizeof(ocsd_etmv3_pkt)); + m_pkt_data.curr_isa = m_pkt_data.prev_isa = ocsd_isa_unknown; +} + +void EtmV3TrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits) +{ + ocsd_vaddr_t validMask = OCSD_VA_MASK; + validMask >>= OCSD_MAX_VA_BITSIZE-updateBits; + m_pkt_data.addr.pkt_bits = updateBits; + m_pkt_data.addr.val &= ~validMask; + m_pkt_data.addr.val |= (partAddrVal & validMask); + if(updateBits > m_pkt_data.addr.valid_bits) + m_pkt_data.addr.valid_bits = updateBits; +} + +void EtmV3TrcPacket::UpdateDataAddress(const uint32_t value, const uint8_t valid_bits) +{ + // ETMv3 data addresses 32 bits. + uint32_t validMask = 0xFFFFFFFF; + validMask >>= 32-valid_bits; + m_pkt_data.addr.pkt_bits = valid_bits; + m_pkt_data.addr.val &= ~validMask; + m_pkt_data.addr.val |= (value & validMask); + if(valid_bits > m_pkt_data.addr.valid_bits) + m_pkt_data.addr.valid_bits = valid_bits; + m_pkt_data.data.update_addr = 1; +} + +void EtmV3TrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits) +{ + uint64_t validMask = ~0ULL; + validMask >>= 64-updateBits; + m_pkt_data.timestamp &= ~validMask; + m_pkt_data.timestamp |= (tsVal & validMask); + m_pkt_data.ts_update_bits = updateBits; +} + + + +void EtmV3TrcPacket::SetException( const ocsd_armv7_exception type, + const uint16_t number, + const bool cancel, + const bool cm_type, + const int irq_n /*= 0*/, + const int resume /* = 0*/) +{ + // initial data + m_pkt_data.exception.bits.cancel = cancel ? 1 : 0; + m_pkt_data.exception.bits.cm_irq_n = irq_n; + m_pkt_data.exception.bits.cm_resume = resume; + m_pkt_data.exception.bits.cm_type = cm_type ? 1 : 0; + m_pkt_data.exception.number = number; + m_pkt_data.exception.type = type; + + // mark as valid in this packet + m_pkt_data.exception.bits.present = 1; +} + +bool EtmV3TrcPacket::UpdateAtomFromPHdr(const uint8_t pHdr, const bool cycleAccurate) +{ + bool bValid = true; + uint8_t E = 0, N = 0; + if(!cycleAccurate) + { + if((pHdr & 0x3) == 0x0) + { + E = ((pHdr >> 2) & 0xF); + N = (pHdr & 0x40) ? 1 : 0; + m_pkt_data.atom.num = E+N; + m_pkt_data.atom.En_bits = (((uint32_t)0x1) << E) - 1; + m_pkt_data.p_hdr_fmt = 1; + } + else if((pHdr & 0x3) == 0x2) + { + m_pkt_data.atom.num = 2; + m_pkt_data.p_hdr_fmt = 2; + m_pkt_data.atom.En_bits = (pHdr & 0x8 ? 0 : 1) | (pHdr & 0x4 ? 0 : 0x2); + } + else + bValid = false; + } + else + { + uint8_t pHdr_code = pHdr & 0xA3; + switch(pHdr_code) + { + case 0x80: + m_pkt_data.p_hdr_fmt = 1; + E = ((pHdr >> 2) & 0x7); + N = (pHdr & 0x40) ? 1 : 0; + m_pkt_data.atom.num = E+N; + if(m_pkt_data.atom.num) + { + m_pkt_data.atom.En_bits = (((uint32_t)0x1) << E) - 1; + m_pkt_data.cycle_count = E+N; + } + else + bValid = false; // deprecated 8b'10000000 code + + break; + + case 0x82: + m_pkt_data.p_hdr_fmt = 2; + if(pHdr & 0x10) + { + m_pkt_data.p_hdr_fmt = 4; + m_pkt_data.atom.num = 1; + m_pkt_data.cycle_count = 0; + m_pkt_data.atom.En_bits = pHdr & 0x04 ? 0 : 1; + } + else + { + m_pkt_data.atom.num = 2; + m_pkt_data.cycle_count = 1; + m_pkt_data.atom.En_bits = (pHdr & 0x8 ? 0 : 1) | (pHdr & 0x4 ? 0 : 0x2); + } + break; + + case 0xA0: + m_pkt_data.p_hdr_fmt = 3; + m_pkt_data.cycle_count = ((pHdr >> 2) & 7) + 1; + E = pHdr & 0x40 ? 1 : 0; + m_pkt_data.atom.num = E; + m_pkt_data.atom.En_bits = E; + break; + + default: + bValid = false; + break; + + } + } + return bValid; +} + +EtmV3TrcPacket &EtmV3TrcPacket::operator =(const ocsd_etmv3_pkt* p_pkt) +{ + m_pkt_data = *p_pkt; + return *this; +} + + // printing +void EtmV3TrcPacket::toString(std::string &str) const +{ + const char *name; + const char *desc; + std::string valStr, ctxtStr = ""; + + name = packetTypeName(m_pkt_data.type, &desc); + str = name + (std::string)" : " + desc; + + switch(m_pkt_data.type) + { + // print the original header type for the bad sequences. + case ETM3_PKT_BAD_SEQUENCE: + case ETM3_PKT_BAD_TRACEMODE: + name = packetTypeName(m_pkt_data.err_type,0); + str += "[" + (std::string)name + "]"; + break; + + case ETM3_PKT_BRANCH_ADDRESS: + getBranchAddressStr(valStr); + str += "; " + valStr; + break; + + case ETM3_PKT_I_SYNC_CYCLE: + case ETM3_PKT_I_SYNC: + getISyncStr(valStr); + str += "; " + valStr; + break; + + case ETM3_PKT_P_HDR: + getAtomStr(valStr); + str += "; " + valStr; + break; + + case ETM3_PKT_CYCLE_COUNT: + { + std::ostringstream oss; + oss << "; Cycles=" << m_pkt_data.cycle_count; + str += oss.str(); + } + break; + + case ETM3_PKT_CONTEXT_ID: + { + std::ostringstream oss; + oss << "; CtxtID=" << std::hex << "0x" << m_pkt_data.context.ctxtID; + str += oss.str(); + } + break; + + case ETM3_PKT_VMID: + { + std::ostringstream oss; + oss << "; VMID=" << std::hex << "0x" << m_pkt_data.context.VMID; + str += oss.str(); + } + break; + + case ETM3_PKT_TIMESTAMP: + { + std::ostringstream oss; + oss << "; TS=" << std::hex << "0x" << m_pkt_data.timestamp << " (" << std::dec << m_pkt_data.timestamp << ") "; + str += oss.str(); + } + break; + + case ETM3_PKT_OOO_DATA: + { + std::ostringstream oss; + oss << "; Val=" << std::hex << "0x" << m_pkt_data.data.value; + oss << "; OO_Tag=" << std::hex << "0x" << m_pkt_data.data.ooo_tag; + str += oss.str(); + } + break; + + case ETM3_PKT_VAL_NOT_TRACED: + if(m_pkt_data.data.update_addr) + { + trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits, + m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits); + str += "; Addr=" + valStr; + } + break; + + case ETM3_PKT_OOO_ADDR_PLC: + if(m_pkt_data.data.update_addr) + { + trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits, + m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits); + str += "; Addr=" + valStr; + } + { + std::ostringstream oss; + oss << "; OO_Tag=" << std::hex << "0x" << m_pkt_data.data.ooo_tag; + str += oss.str(); + } + break; + + case ETM3_PKT_NORM_DATA: + if(m_pkt_data.data.update_addr) + { + trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits, + m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits); + str += "; Addr=" + valStr; + } + if(m_pkt_data.data.update_dval) + { + std::ostringstream oss; + oss << "; Val=" << std::hex << "0x" << m_pkt_data.data.value; + str += oss.str(); + } + break; + } +} + +void EtmV3TrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const +{ + // no formatting implemented at present. + toString(str); +} + +const char *EtmV3TrcPacket::packetTypeName(const ocsd_etmv3_pkt_type type, const char **ppDesc) const +{ + const char *pName = "I_RESERVED"; + const char *pDesc = "Reserved Packet Header"; + + switch(type) + { +// markers for unknown packets + // case ETM3_PKT_NOERROR:, //!< no error in packet - supplimentary data. + case ETM3_PKT_NOTSYNC: //!< no sync found yet + pName = "NOTSYNC"; + pDesc = "Trace Stream not synchronised"; + break; + + case ETM3_PKT_INCOMPLETE_EOT: //!< flushing incomplete/empty packet at end of trace. + pName = "INCOMPLETE_EOT."; + pDesc = "Incomplete packet at end of trace data."; + break; + +// markers for valid packets + case ETM3_PKT_BRANCH_ADDRESS: + pName = "BRANCH_ADDRESS"; + pDesc = "Branch address."; + break; + + case ETM3_PKT_A_SYNC: + pName = "A_SYNC"; + pDesc = "Alignment Synchronisation."; + break; + + case ETM3_PKT_CYCLE_COUNT: + pName = "CYCLE_COUNT"; + pDesc = "Cycle Count."; + break; + + case ETM3_PKT_I_SYNC: + pName = "I_SYNC"; + pDesc = "Instruction Packet synchronisation."; + break; + + case ETM3_PKT_I_SYNC_CYCLE: + pName = "I_SYNC_CYCLE"; + pDesc = "Instruction Packet synchronisation with cycle count."; + break; + + case ETM3_PKT_TRIGGER: + pName = "TRIGGER"; + pDesc = "Trace Trigger Event."; + break; + + case ETM3_PKT_P_HDR: + pName = "P_HDR"; + pDesc = "Atom P-header."; + break; + + case ETM3_PKT_STORE_FAIL: + pName = "STORE_FAIL"; + pDesc = "Data Store Failed."; + break; + + case ETM3_PKT_OOO_DATA: + pName = "OOO_DATA"; + pDesc = "Out of Order data value packet."; + break; + + case ETM3_PKT_OOO_ADDR_PLC: + pName = "OOO_ADDR_PLC"; + pDesc = "Out of Order data address placeholder."; + break; + + case ETM3_PKT_NORM_DATA: + pName = "NORM_DATA"; + pDesc = "Data trace packet."; + break; + + case ETM3_PKT_DATA_SUPPRESSED: + pName = "DATA_SUPPRESSED"; + pDesc = "Data trace suppressed."; + break; + + case ETM3_PKT_VAL_NOT_TRACED: + pName = "VAL_NOT_TRACED"; + pDesc = "Data trace value not traced."; + break; + + case ETM3_PKT_IGNORE: + pName = "IGNORE"; + pDesc = "Packet ignored."; + break; + + case ETM3_PKT_CONTEXT_ID: + pName = "CONTEXT_ID"; + pDesc = "Context ID change."; + break; + + case ETM3_PKT_VMID: + pName = "VMID"; + pDesc = "VMID change."; + break; + + case ETM3_PKT_EXCEPTION_ENTRY: + pName = "EXCEPTION_ENTRY"; + pDesc = "Exception entry data marker."; + break; + + case ETM3_PKT_EXCEPTION_EXIT: + pName = "EXCEPTION_EXIT"; + pDesc = "Exception return."; + break; + + case ETM3_PKT_TIMESTAMP: + pName = "TIMESTAMP"; + pDesc = "Timestamp Value."; + break; + +// internal processing types + // case ETM3_PKT_BRANCH_OR_BYPASS_EOT: not externalised + +// packet errors + case ETM3_PKT_BAD_SEQUENCE: + pName = "BAD_SEQUENCE"; + pDesc = "Invalid sequence for packet type."; + break; + + case ETM3_PKT_BAD_TRACEMODE: + pName = "BAD_TRACEMODE"; + pDesc = "Invalid packet type for this trace mode."; + break; + + // leave thest unchanged. + case ETM3_PKT_RESERVED: + default: + break; + + } + + if(ppDesc) *ppDesc = pDesc; + return pName; +} + +void EtmV3TrcPacket::getBranchAddressStr(std::string &valStr) const +{ + std::ostringstream oss; + std::string subStr; + + // print address. + trcPrintableElem::getValStr(subStr,32,m_pkt_data.addr.valid_bits, + m_pkt_data.addr.val,true,m_pkt_data.addr.pkt_bits); + oss << "Addr=" << subStr << "; "; + + // current ISA if changed. + if(m_pkt_data.curr_isa != m_pkt_data.prev_isa) + { + getISAStr(subStr); + oss << subStr; + } + + // S / NS etc if changed. + if(m_pkt_data.context.updated) + { + oss << (m_pkt_data.context.curr_NS ? "NS; " : "S; "); + oss << (m_pkt_data.context.curr_Hyp ? "Hyp; " : ""); + } + + // exception? + if(m_pkt_data.exception.bits.present) + { + getExcepStr(subStr); + oss << subStr; + } + valStr = oss.str(); +} + +void EtmV3TrcPacket::getAtomStr(std::string &valStr) const +{ + std::ostringstream oss; + uint32_t bitpattern = m_pkt_data.atom.En_bits; // arranged LSBit oldest, MSbit newest + + if(!m_pkt_data.cycle_count) + { + for(int i = 0; i < m_pkt_data.atom.num; i++) + { + oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest + bitpattern >>= 1; + } + } + else + { + switch(m_pkt_data.p_hdr_fmt) + { + case 1: + for(int i = 0; i < m_pkt_data.atom.num; i++) + { + oss << ((bitpattern & 0x1) ? "WE" : "WN"); // in spec read L->R, oldest->newest + bitpattern >>= 1; + } + break; + + case 2: + oss << "W"; + for(int i = 0; i < m_pkt_data.atom.num; i++) + { + oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest + bitpattern >>= 1; + } + break; + + case 3: + for(uint32_t i = 0; i < m_pkt_data.cycle_count; i++) + oss << "W"; + if(m_pkt_data.atom.num) + oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest + break; + } + oss << "; Cycles=" << m_pkt_data.cycle_count; + } + valStr = oss.str(); +} + +void EtmV3TrcPacket::getISyncStr(std::string &valStr) const +{ + std::ostringstream oss; + static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" }; + + // reason. + oss << "(" << reason[(int)m_pkt_data.isync_info.reason] << "); "; + + // full address. + if(!m_pkt_data.isync_info.no_address) + { + if(m_pkt_data.isync_info.has_LSipAddress) + oss << "Data Instr Addr=0x"; + else + oss << "Addr=0x"; + oss << std::hex << std::setfill('0') << std::setw(8) << m_pkt_data.addr.val << "; "; + } + + oss << (m_pkt_data.context.curr_NS ? "NS; " : "S; "); + oss << (m_pkt_data.context.curr_Hyp ? "Hyp; " : " "); + + if(m_pkt_data.context.updated_c) + { + oss << "CtxtID=" << std::hex << m_pkt_data.context.ctxtID << "; "; + } + + if(m_pkt_data.isync_info.no_address) + { + valStr = oss.str(); + return; // bail out at this point if a data only ISYNC + } + + std::string isaStr; + getISAStr(isaStr); + oss << isaStr; + + if(m_pkt_data.isync_info.has_cycle_count) + { + oss << "Cycles=" << std::dec << m_pkt_data.cycle_count << "; "; + } + + if(m_pkt_data.isync_info.has_LSipAddress) + { + std::string addrStr; + + // extract address updata. + trcPrintableElem::getValStr(addrStr,32,m_pkt_data.data.addr.valid_bits, + m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits); + oss << "Curr Instr Addr=" << addrStr << ";"; + } + valStr = oss.str(); +} + +void EtmV3TrcPacket::getISAStr(std::string &isaStr) const +{ + std::ostringstream oss; + oss << "ISA="; + switch(m_pkt_data.curr_isa) + { + case ocsd_isa_arm: + oss << "ARM(32); "; + break; + + case ocsd_isa_thumb2: + oss << "Thumb2; "; + break; + + case ocsd_isa_aarch64: + oss << "AArch64; "; + break; + + case ocsd_isa_tee: + oss << "ThumbEE; "; + break; + + case ocsd_isa_jazelle: + oss << "Jazelle; "; + break; + + default: + case ocsd_isa_unknown: + oss << "Unknown; "; + break; + } + isaStr = oss.str(); +} + +void EtmV3TrcPacket::getExcepStr(std::string &excepStr) const +{ + static const char *ARv7Excep[] = { + "No Exception", "Debug Halt", "SMC", "Hyp", + "Async Data Abort", "Jazelle", "Reserved", "Reserved", + "PE Reset", "Undefined Instr", "SVC", "Prefetch Abort", + "Data Fault", "Generic", "IRQ", "FIQ" + }; + + static const char *MExcep[] = { + "No Exception", "IRQ1", "IRQ2", "IRQ3", + "IRQ4", "IRQ5", "IRQ6", "IRQ7", + "IRQ0","usage Fault","NMI","SVC", + "DebugMonitor", "Mem Manage","PendSV","SysTick", + "Reserved","PE Reset","Reserved","HardFault", + "Reserved","BusFault","Reserved","Reserved" + }; + + std::ostringstream oss; + oss << "Exception="; + + if(m_pkt_data.exception.bits.cm_type) + { + if(m_pkt_data.exception.number < 0x18) + oss << MExcep[m_pkt_data.exception.number]; + else + oss << "IRQ" << std::dec << (m_pkt_data.exception.number - 0x10); + if(m_pkt_data.exception.bits.cm_resume) + oss << "; Resume=" << m_pkt_data.exception.bits.cm_resume; + if(m_pkt_data.exception.bits.cancel) + oss << "; Cancel prev instr"; + } + else + { + oss << ARv7Excep[m_pkt_data.exception.number] << "; "; + if(m_pkt_data.exception.bits.cancel) + oss << "; Cancel prev instr"; + } + excepStr = oss.str(); +} +/* End of File trc_pkt_elem_etmv3.cpp */ diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp b/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp new file mode 100644 index 0000000..7871619 --- /dev/null +++ b/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp @@ -0,0 +1,122 @@ +/* + * \file trc_pkt_proc_etmv3.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + */ + + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opencsd/etmv3/trc_pkt_proc_etmv3.h" +#include "trc_pkt_proc_etmv3_impl.h" +#include "common/ocsd_error.h" + +#ifdef __GNUC__ +// G++ doesn't like the ## pasting +#define ETMV3_PKTS_NAME "PKTP_ETMV3" +#else +#define ETMV3_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_"##OCSD_BUILTIN_DCD_ETMV3 +#endif + +static const uint32_t ETMV3_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON | + ETMV3_OPFLG_UNFORMATTED_SOURCE; + +TrcPktProcEtmV3::TrcPktProcEtmV3() : TrcPktProcBase(ETMV3_PKTS_NAME), + m_pProcessor(0) +{ + m_supported_op_flags = ETMV3_SUPPORTED_OP_FLAGS; +} + +TrcPktProcEtmV3::TrcPktProcEtmV3(int instIDNum) : TrcPktProcBase(ETMV3_PKTS_NAME, instIDNum), + m_pProcessor(0) +{ + m_supported_op_flags = ETMV3_SUPPORTED_OP_FLAGS; +} + +TrcPktProcEtmV3::~TrcPktProcEtmV3() +{ + if(m_pProcessor) + delete m_pProcessor; + m_pProcessor = 0; +} + +ocsd_err_t TrcPktProcEtmV3::onProtocolConfig() +{ + if(m_pProcessor == 0) + { + m_pProcessor = new (std::nothrow) EtmV3PktProcImpl(); + if(m_pProcessor == 0) + { + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM)); + return OCSD_ERR_MEM; + } + m_pProcessor->Initialise(this); + } + return m_pProcessor->Configure(m_config); +} + +ocsd_datapath_resp_t TrcPktProcEtmV3::processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + if(m_pProcessor) + return m_pProcessor->processData(index,dataBlockSize,pDataBlock,numBytesProcessed); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV3::onEOT() +{ + if(m_pProcessor) + return m_pProcessor->onEOT(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV3::onReset() +{ + if(m_pProcessor) + return m_pProcessor->onReset(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +ocsd_datapath_resp_t TrcPktProcEtmV3::onFlush() +{ + if(m_pProcessor) + return m_pProcessor->onFlush(); + return OCSD_RESP_FATAL_NOT_INIT; +} + +const bool TrcPktProcEtmV3::isBadPacket() const +{ + if(m_pProcessor) + return m_pProcessor->isBadPacket(); + return false; +} + +/* End of File trc_pkt_proc_etmv3.cpp */ diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp new file mode 100644 index 0000000..fc39a5e --- /dev/null +++ b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp @@ -0,0 +1,1224 @@ +/* + * \file trc_pkt_proc_etmv3_impl.cpp + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "trc_pkt_proc_etmv3_impl.h" + +EtmV3PktProcImpl::EtmV3PktProcImpl() : + m_isInit(false), + m_interface(0) +{ +} + +EtmV3PktProcImpl::~EtmV3PktProcImpl() +{ +} + +ocsd_err_t EtmV3PktProcImpl::Configure(const EtmV3Config *p_config) +{ + ocsd_err_t err = OCSD_OK; + if(p_config != 0) + { + m_config = *p_config; + m_chanIDCopy = m_config.getTraceID(); + } + else + { + err = OCSD_ERR_INVALID_PARAM_VAL; + if(m_isInit) + m_interface->LogError(ocsdError(OCSD_ERR_SEV_ERROR,err)); + } + return err; +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::processData(const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed) +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + m_bytesProcessed = 0; + + while( ( (m_bytesProcessed < dataBlockSize) || + ((m_bytesProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) ) + && OCSD_DATA_RESP_IS_CONT(resp)) + { + try + { + switch(m_process_state) + { + case WAIT_SYNC: + if(!m_bStartOfSync) + m_packet_index = index + m_bytesProcessed; + m_bytesProcessed += waitForSync(dataBlockSize-m_bytesProcessed,pDataBlock+m_bytesProcessed); + break; + + case PROC_HDR: + m_packet_index = index + m_bytesProcessed; + processHeaderByte(pDataBlock[m_bytesProcessed++]); + break; + + case PROC_DATA: + processPayloadByte(pDataBlock [m_bytesProcessed++]); + break; + + case SEND_PKT: + resp = outputPacket(); + break; + } + } + catch(ocsdError &err) + { + m_interface->LogError(err); + if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) || + (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)) + { + // send invalid packets up the pipe to let the next stage decide what to do. + m_process_state = SEND_PKT; + } + else + { + // bail out on any other error. + resp = OCSD_RESP_FATAL_INVALID_DATA; + } + } + catch(...) + { + /// vv bad at this point. + resp = OCSD_RESP_FATAL_SYS_ERR; + ocsdError fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_chanIDCopy); + fatal.setMessage("Unknown System Error decoding trace."); + m_interface->LogError(fatal); + } + } + + *numBytesProcessed = m_bytesProcessed; + return resp; +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::onEOT() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + // if we have a partial packet then send to attached sinks + if(m_currPacketData.size() != 0) + { + // TBD: m_curr_packet.updateErrType(ETM4_ETM3_PKT_I_INCOMPLETE_EOT); + resp = outputPacket(); + InitPacketState(); + } + return resp; +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::onReset() +{ + InitProcessorState(); + return OCSD_RESP_CONT; +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::onFlush() +{ + // packet processor never holds on to flushable data (may have partial packet, + // but any full packets are immediately sent) + return OCSD_RESP_CONT; +} + +void EtmV3PktProcImpl::Initialise(TrcPktProcEtmV3 *p_interface) +{ + if(p_interface) + { + m_interface = p_interface; + m_isInit = true; + + } + InitProcessorState(); + /* not using pattern matcher for sync at present + static const uint8_t a_sync[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }; + m_syncMatch.setPattern(a_sync, sizeof(a_sync));*/ +} + +void EtmV3PktProcImpl::InitProcessorState() +{ + m_bStreamSync = false; // not synced + m_process_state = WAIT_SYNC; // waiting for sync + m_bStartOfSync = false; // not seen start of sync packet + m_curr_packet.ResetState(); // reset intra packet state + InitPacketState(); // set curr packet state + m_bSendPartPkt = false; +} + +void EtmV3PktProcImpl::InitPacketState() +{ + m_bytesExpectedThisPkt = 0; + m_BranchPktNeedsException = false; + m_bIsync_got_cycle_cnt = false; + m_bIsync_get_LSiP_addr = false; + m_IsyncInfoIdx = false; + m_bExpectingDataAddress = false; + m_bFoundDataAddress = false; + m_currPacketData.clear(); + m_currPktIdx = 0; // index into processed bytes in current packet + m_curr_packet.Clear(); + +} + +ocsd_datapath_resp_t EtmV3PktProcImpl::outputPacket() +{ + ocsd_datapath_resp_t dp_resp = OCSD_RESP_FATAL_NOT_INIT; + if(m_isInit) + { + ocsd_etmv3_pkt_type type = m_curr_packet.getType(); + if(!m_bSendPartPkt) + { + dp_resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&type,m_currPacketData); + m_process_state = m_bStreamSync ? PROC_HDR : WAIT_SYNC; // need a header next time, or still waiting to sync. + m_currPacketData.clear(); + } + else + { + // sending part packet, still some data in the main packet + dp_resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&type,m_partPktData); + m_process_state = m_post_part_pkt_state; + m_packet_index += m_partPktData.size(); + m_bSendPartPkt = false; + m_curr_packet.SetType(m_post_part_pkt_type); + } + } + return dp_resp; +} + +void EtmV3PktProcImpl::setBytesPartPkt(int numBytes, process_state nextState, const ocsd_etmv3_pkt_type nextType) +{ + m_partPktData.clear(); + for(int i=0; i < numBytes; i++) + { + m_partPktData.push_back(m_currPacketData[i]); + } + m_currPacketData.erase(m_currPacketData.begin(), m_currPacketData.begin()+numBytes); + m_bSendPartPkt = true; + m_post_part_pkt_state = nextState; + m_post_part_pkt_type = nextType; +} + +uint32_t EtmV3PktProcImpl::waitForSync(const uint32_t dataBlockSize, const uint8_t *pDataBlock) +{ + uint8_t currByte; + uint32_t bytesProcessed = 0; + bool bSendBlock = false; + + // need to wait for the first sync packet + while(!bSendBlock && (bytesProcessed < dataBlockSize)) + { + currByte = pDataBlock[bytesProcessed++]; + // TBD: forced sync point + + if(m_bStartOfSync) + { + // need to handle consecutive 0 bytes followed by genuine A-SYNC. + + m_currPacketData.push_back(currByte); + if((currByte == 0x80) && (m_currPacketData.size() >= 6)) + { + // it is a sync packet possibly with leading zeros + bSendBlock = true; + if(m_currPacketData.size() > 6) + { + m_currPacketData.pop_back(); + bytesProcessed--; // return 0x80 to the input buffer to re-process next pass after stripping 0's + setBytesPartPkt(m_currPacketData.size()-5,WAIT_SYNC,ETM3_PKT_NOTSYNC); + } + else + { + m_bStreamSync = true; + m_curr_packet.SetType(ETM3_PKT_A_SYNC); + } + } + else if(currByte != 0x00) + { + m_bStartOfSync = false; // not a sync packet + } + else if(m_currPacketData.size() >= 13) // 13 0's, strip 8 of them... + { + setBytesPartPkt(8,WAIT_SYNC,ETM3_PKT_NOTSYNC); + bSendBlock = true; + } + } + else // not seen a start of sync candidate yet + { + if(currByte == 0x00) // could be the start of a-sync + { + if(m_currPacketData.size() == 0) + { + m_currPacketData.push_back(currByte); + m_bStartOfSync = true; + } + else + { + bytesProcessed--; + bSendBlock = true; // send none sync packet data, re-process this byte next time. + m_curr_packet.SetType(ETM3_PKT_NOTSYNC); // send unsynced data packet. + } + } + else + { + //save a byte - not start of a-sync + m_currPacketData.push_back(currByte); + + // done all data in this block, or got 16 unsynced bytes + if((bytesProcessed == dataBlockSize) || (m_currPacketData.size() == 16)) + { + bSendBlock = true; // send none sync packet block + m_curr_packet.SetType(ETM3_PKT_NOTSYNC); // send unsynced data packet. + } + } + } + } + if(bSendBlock) + SendPacket(); + return bytesProcessed; +} + +ocsd_err_t EtmV3PktProcImpl::processHeaderByte(uint8_t by) +{ + InitPacketState(); // new packet, clear old single packet state (retains intra packet state). + + // save byte + m_currPacketData.push_back(by); + + m_process_state = PROC_DATA; // assume next is data packet + + // check for branch address 0bCxxxxxxx1 + if((by & 0x01) == 0x01 ) { + m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS); + m_BranchPktNeedsException = false; + if((by & 0x80) != 0x80) { + // no continuation - 1 byte branch same in alt and std... + if((by == 0x01) && (m_interface->getComponentOpMode() & ETMV3_OPFLG_UNFORMATTED_SOURCE)) + { + // TBD: need to fix up for handling bypassed ETM stream at some point. + throwUnsupportedErr("Bypassed ETM stream not supported in this version of the decoder."); + // could be EOTrace marker from bypassed formatter + m_curr_packet.SetType(ETM3_PKT_BRANCH_OR_BYPASS_EOT); + } + else + { + OnBranchAddress(); + SendPacket(); // mark ready to send. + } + } + } + // check for p-header - 0b1xxxxxx0 + else if((by & 0x81) == 0x80) { + m_curr_packet.SetType(ETM3_PKT_P_HDR); + if(m_curr_packet.UpdateAtomFromPHdr(by,m_config.isCycleAcc())) + SendPacket(); + else + throwPacketHeaderErr("Invalid P-Header."); + } + // check 0b0000xx00 group + else if((by & 0xF3) == 0x00) { + + // A-Sync + if(by == 0x00) { + m_curr_packet.SetType(ETM3_PKT_A_SYNC); + } + // cycle count + else if(by == 0x04) { + m_curr_packet.SetType(ETM3_PKT_CYCLE_COUNT); + } + // I-Sync + else if(by == 0x08) { + m_curr_packet.SetType(ETM3_PKT_I_SYNC); + m_bIsync_got_cycle_cnt = false; + m_bIsync_get_LSiP_addr = false; + } + // trigger + else if(by == 0x0C) { + m_curr_packet.SetType(ETM3_PKT_TRIGGER); + // no payload - just send it. + SendPacket(); + } + } + // check remaining 0bxxxxxx00 codes + else if((by & 0x03 )== 0x00) { + // OoO data 0b0xx0xx00 + if((by & 0x93 )== 0x00) { + if(!m_config.isDataValTrace()) { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (out of order data) - not tracing data values."); + } + m_curr_packet.SetType(ETM3_PKT_OOO_DATA); + uint8_t size = ((by & 0x0C) >> 2); + // header contains a count of the data to follow + // size 3 == 4 bytes, other sizes == size bytes + if(size == 0) + { + m_curr_packet.SetDataOOOTag((by >> 5) & 0x3); + m_curr_packet.SetDataValue(0); + SendPacket(); + } + else + m_bytesExpectedThisPkt = (short)(1 + ((size == 3) ? 4 : size)); + } + // I-Sync + cycle count + else if(by == 0x70) { + m_curr_packet.SetType(ETM3_PKT_I_SYNC_CYCLE); + m_bIsync_got_cycle_cnt = false; + m_bIsync_get_LSiP_addr = false; + } + // store failed + else if(by == 0x50) { + if(!m_config.isDataValTrace()) + { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (store failed) - not tracing data values."); + } + m_curr_packet.SetType(ETM3_PKT_STORE_FAIL); + SendPacket(); + } + // OoO placeholder 0b01x1xx00 + else if((by & 0xD3 )== 0x50) { + m_curr_packet.SetType(ETM3_PKT_OOO_ADDR_PLC); + if(!m_config.isDataTrace()) + { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (out of order placeholder) - not tracing data."); + } + // expecting data address if flagged and address tracing enabled (flag can be set even if address tracing disabled) + m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace(); + m_bFoundDataAddress = false; + m_curr_packet.SetDataOOOTag((by >> 2) & 0x3); + if(!m_bExpectingDataAddress) { + SendPacket(); + } + } + // vmid 0b00111100 + else if(by == 0x3c) { + m_curr_packet.SetType(ETM3_PKT_VMID); + } + else + { + m_curr_packet.SetErrType(ETM3_PKT_RESERVED); + throwPacketHeaderErr("Packet header reserved encoding"); + } + } + // normal data 0b00x0xx10 + else if((by & 0xD3 )== 0x02) { + uint8_t size = ((by & 0x0C) >> 2); + if(!m_config.isDataTrace()) { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (normal data) - not tracing data."); + } + m_curr_packet.SetType(ETM3_PKT_NORM_DATA); + m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace(); + m_bFoundDataAddress = false; + + // set this with the data bytes expected this packet, plus the header byte. + m_bytesExpectedThisPkt = (short)( 1 + ((size == 3) ? 4 : size)); + if(!m_bExpectingDataAddress && (m_bytesExpectedThisPkt == 1)) { + // single byte data packet, value = 0; + m_curr_packet.SetDataValue(0); + SendPacket(); + } + + } + // data suppressed 0b01100010 + else if(by == 0x62) { + if(!m_config.isDataTrace()) + { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (data suppressed) - not tracing data."); + } + m_curr_packet.SetType(ETM3_PKT_DATA_SUPPRESSED); + SendPacket(); + } + // value not traced 0b011x1010 + else if((by & 0xEF )== 0x6A) { + if(!m_config.isDataTrace()) { + m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE); + throwPacketHeaderErr("Invalid data trace header (value not traced) - not tracing data."); + } + m_curr_packet.SetType(ETM3_PKT_VAL_NOT_TRACED); + m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace(); + m_bFoundDataAddress = false; + if(!m_bExpectingDataAddress) { + SendPacket(); + } + } + // ignore 0b01100110 + else if(by == 0x66) { + m_curr_packet.SetType(ETM3_PKT_IGNORE); + SendPacket(); + } + // context ID 0b01101110 + else if(by == 0x6E) { + m_curr_packet.SetType(ETM3_PKT_CONTEXT_ID); + m_bytesExpectedThisPkt = (short)(1 + m_config.CtxtIDBytes()); + } + // exception return 0b01110110 + else if(by == 0x76) { + m_curr_packet.SetType(ETM3_PKT_EXCEPTION_EXIT); + SendPacket(); + } + // exception entry 0b01111110 + else if(by == 0x7E) { + m_curr_packet.SetType(ETM3_PKT_EXCEPTION_ENTRY); + SendPacket(); + } + // timestamp packet 0b01000x10 + else if((by & 0xFB )== 0x42) + { + m_curr_packet.SetType(ETM3_PKT_TIMESTAMP); + } + else + { + m_curr_packet.SetErrType(ETM3_PKT_RESERVED); + throwPacketHeaderErr("Packet header reserved encoding."); + } + return OCSD_OK; +} + +ocsd_err_t EtmV3PktProcImpl::processPayloadByte(uint8_t by) +{ + bool bTopBitSet = false; + bool packetDone = false; + + // pop byte into buffer + m_currPacketData.push_back(by); + + switch(m_curr_packet.getType()) { + default: + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_PKT_INTERP_FAIL,m_packet_index,m_chanIDCopy,"Interpreter failed - cannot process payload for unexpected or unsupported packet."); + break; + + case ETM3_PKT_BRANCH_ADDRESS: + bTopBitSet = (bool)((by & 0x80) == 0x80); + if(m_config.isAltBranch()) // etm implements the alternative branch encoding + { + if(!bTopBitSet) // no continuation + { + if(!m_BranchPktNeedsException) + { + if((by & 0xC0) == 0x40) + m_BranchPktNeedsException = true; + else + packetDone = true; + } + else + packetDone = true; + } + } + else + { + // standard encoding < 5 bytes cannot be exception branch + // 5 byte packet + if(m_currPacketData.size() == 5) { + if((by & 0xC0) == 0x40) + // expecting follow up byte(s) + m_BranchPktNeedsException = true; + else + packetDone = true; + } + // waiting for exception packet + else if(m_BranchPktNeedsException){ + if(!bTopBitSet) + packetDone = true; + } + else { + // not exception - end of packets + if(!bTopBitSet) + packetDone = true; + } + } + + if(packetDone) + { + OnBranchAddress(); + SendPacket(); + } + break; + + case ETM3_PKT_BRANCH_OR_BYPASS_EOT: + /* + if((by != 0x00) || ( m_currPacketData.size() == ETM3_PKT_BUFF_SIZE)) { + if(by == 0x80 && ( m_currPacketData.size() == 7)) { + // branch 0 followed by A-sync! + m_currPacketData.size() = 1; + m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS; + SendPacket(); + memcpy(m_currPacketData, &m_currPacketData[1],6); + m_currPacketData.size() = 6; + m_curr_packet.SetType(ETM3_PKT_A_SYNC; + SendPacket(); + } + else if( m_currPacketData.size() == 2) { + // branch followed by another byte + m_currPacketData.size() = 1; + m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS; + SendPacket(); + ProcessHeaderByte(by); + } + else if(by == 0x00) { + // end of buffer...output something - incomplete / unknown. + SendPacket(); + } + else if(by == 0x01) { + // 0x01 - 0x00 x N - 0x1 + // end of buffer...output something + m_currPacketData.size()--; + SendPacket(); + ProcessHeaderByte(by); + } + else { + // branch followed by unknown sequence + int oldidx = m_currPacketData.size(); + m_currPacketData.size() = 1; + m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS; + SendPacket(); + oldidx--; + memcpy(m_currPacketData, &m_currPacketData[1],oldidx); + m_currPacketData.size() = oldidx; + SendBadPacket("ERROR : unknown sequence"); + } + }*/ + // just ignore zeros + break; + + + + case ETM3_PKT_A_SYNC: + if(by == 0x00) { + if( m_currPacketData.size() > 5) { + // extra 0, need to lose one + + // set error type + m_curr_packet.SetErrType(ETM3_PKT_BAD_SEQUENCE); + // mark extra 0 for sending, retain remaining, restart in A-SYNC processing mode. + setBytesPartPkt(1,PROC_DATA,ETM3_PKT_A_SYNC); + throwMalformedPacketErr("A-Sync ?: Extra 0x00 in sequence"); + } + } + else if((by == 0x80) && ( m_currPacketData.size() == 6)) { + SendPacket(); + m_bStreamSync = true; + } + else + { + m_curr_packet.SetErrType(ETM3_PKT_BAD_SEQUENCE); + m_bytesProcessed--; // remove the last byte from the number processed to re-try + m_currPacketData.pop_back(); // remove the last byte processed from the packet + throwMalformedPacketErr("A-Sync ? : Unexpected byte in sequence"); + } + break; + + case ETM3_PKT_CYCLE_COUNT: + bTopBitSet = ((by & 0x80) == 0x80); + if(!bTopBitSet || ( m_currPacketData.size() >= 6)) { + m_currPktIdx = 1; + m_curr_packet.SetCycleCount(extractCycleCount()); + SendPacket(); + } + break; + + case ETM3_PKT_I_SYNC_CYCLE: + if(!m_bIsync_got_cycle_cnt) { + if(((by & 0x80) != 0x80) || ( m_currPacketData.size() >= 6)) { + m_bIsync_got_cycle_cnt = true; + } + break; + } + // fall through when we have the first non-cycle count byte + case ETM3_PKT_I_SYNC: + if(m_bytesExpectedThisPkt == 0) { + int cycCountBytes = m_currPacketData.size() - 2; + int ctxtIDBytes = m_config.CtxtIDBytes(); + // bytes expected = header + n x ctxt id + info byte + 4 x addr; + if(m_config.isInstrTrace()) + m_bytesExpectedThisPkt = cycCountBytes + 6 + ctxtIDBytes; + else + m_bytesExpectedThisPkt = 2 + ctxtIDBytes; + m_IsyncInfoIdx = 1 + cycCountBytes + ctxtIDBytes; + } + if(( m_currPacketData.size() - 1) == (unsigned)m_IsyncInfoIdx) { + m_bIsync_get_LSiP_addr = ((m_currPacketData[m_IsyncInfoIdx] & 0x80) == 0x80); + } + + // if bytes collected >= bytes expected + if( m_currPacketData.size() >= m_bytesExpectedThisPkt) { + // if we still need the LSip Addr, then this is not part of the expected + // count as we have no idea how long it is + if(m_bIsync_get_LSiP_addr) { + if((by & 0x80) != 0x80) { + OnISyncPacket(); + } + } + else { + // otherwise, output now + OnISyncPacket(); + } + } + break; + + case ETM3_PKT_NORM_DATA: + if(m_bExpectingDataAddress && !m_bFoundDataAddress) { + // look for end of continuation bits + if((by & 0x80) != 0x80) { + m_bFoundDataAddress = true; + // add on the bytes we have found for the address to the expected data bytes + m_bytesExpectedThisPkt += ( m_currPacketData.size() - 1); + } + else + break; + } + // found any data address we were expecting + else if(m_bytesExpectedThisPkt == m_currPacketData.size()) { + m_currPktIdx = 1; + if(m_bExpectingDataAddress) + { + uint8_t bits = 0, beVal = 0; + bool updateBE = false; + uint32_t dataAddress = extractDataAddress(bits,updateBE,beVal); + m_curr_packet.UpdateDataAddress(dataAddress, bits); + if(updateBE) + m_curr_packet.UpdateDataEndian(beVal); + } + m_curr_packet.SetDataValue(extractDataValue((m_currPacketData[0] >> 2) & 0x3)); + SendPacket(); + } + break; + + case ETM3_PKT_OOO_DATA: + if(m_bytesExpectedThisPkt == m_currPacketData.size()) + { + m_currPktIdx = 1; + m_curr_packet.SetDataValue(extractDataValue((m_currPacketData[0] >> 2) & 0x3)); + m_curr_packet.SetDataOOOTag((m_currPacketData[0] >> 5) & 0x3); + SendPacket(); + } + if(m_bytesExpectedThisPkt < m_currPacketData.size()) + throwMalformedPacketErr("Malformed out of order data packet."); + break; + + // both these expect an address only. + case ETM3_PKT_VAL_NOT_TRACED: + case ETM3_PKT_OOO_ADDR_PLC: // we set the tag earlier. + if(m_bExpectingDataAddress) { + // look for end of continuation bits + if((by & 0x80) != 0x80) { + uint8_t bits = 0, beVal = 0; + bool updateBE = false; + m_currPktIdx = 1; + uint32_t dataAddress = extractDataAddress(bits,updateBE,beVal); + m_curr_packet.UpdateDataAddress(dataAddress, bits); + if(updateBE) + m_curr_packet.UpdateDataEndian(beVal); + SendPacket(); + } + } + break; + + case ETM3_PKT_CONTEXT_ID: + if(m_bytesExpectedThisPkt == m_currPacketData.size()) { + m_currPktIdx = 1; + m_curr_packet.UpdateContextID(extractCtxtID()); + SendPacket(); + } + if(m_bytesExpectedThisPkt < m_currPacketData.size()) + throwMalformedPacketErr("Malformed context id packet."); + break; + + case ETM3_PKT_TIMESTAMP: + if((by & 0x80) != 0x80) { + uint8_t tsBits = 0; + m_currPktIdx = 1; + uint64_t tsVal = extractTimestamp(tsBits); + m_curr_packet.UpdateTimestamp(tsVal,tsBits); + SendPacket(); + } + break; + + case ETM3_PKT_VMID: + // single byte payload + m_curr_packet.UpdateVMID(by); + SendPacket(); + break; + } + + return OCSD_OK; +} + +// extract branch address packet at current location in packet data. +void EtmV3PktProcImpl::OnBranchAddress() +{ + int validBits = 0; + ocsd_vaddr_t partAddr = 0; + + partAddr = extractBrAddrPkt(validBits); + m_curr_packet.UpdateAddress(partAddr,validBits); +} + +uint32_t EtmV3PktProcImpl::extractBrAddrPkt(int &nBitsOut) +{ + static int addrshift[] = { + 2, // ARM_ISA + 1, // thumb + 1, // thumb EE + 0 // jazelle + }; + + static uint8_t addrMask[] = { // byte 5 masks + 0x7, // ARM_ISA + 0xF, // thumb + 0xF, // thumb EE + 0x1F // jazelle + }; + + static int addrBits[] = { // address bits in byte 5 + 3, // ARM_ISA + 4, // thumb + 4, // thumb EE + 5 // jazelle + }; + + static ocsd_armv7_exception exceptionTypeARMdeprecated[] = { + Excp_Reset, + Excp_IRQ, + Excp_Reserved, + Excp_Reserved, + Excp_Jazelle, + Excp_FIQ, + Excp_AsyncDAbort, + Excp_DebugHalt + }; + + bool CBit = true; + int bytecount = 0; + int bitcount = 0; + int shift = 0; + int isa_idx = 0; + uint32_t value = 0; + uint8_t addrbyte; + bool byte5AddrUpdate = false; + + while(CBit && bytecount < 4) + { + checkPktLimits(); + addrbyte = m_currPacketData[m_currPktIdx++]; + CBit = (bool)((addrbyte & 0x80) != 0); + shift = bitcount; + if(bytecount == 0) + { + addrbyte &= ~0x81; + bitcount+=6; + addrbyte >>= 1; + } + else + { + // bytes 2-4, no continuation, alt format uses bit 6 to indicate following exception bytes + if(m_config.isAltBranch() && !CBit) + { + // last compressed address byte with exception + if((addrbyte & 0x40) == 0x40) + extractExceptionData(); + addrbyte &= 0x3F; + bitcount+=6; + } + else + { + addrbyte &= 0x7F; + bitcount+=7; + } + } + value |= ((uint32_t)addrbyte) << shift; + bytecount++; + } + + // byte 5 - indicates following exception bytes (or not!) + if(CBit) + { + checkPktLimits(); + addrbyte = m_currPacketData[m_currPktIdx++]; + + // deprecated original byte 5 encoding - ARM state exception only + if(addrbyte & 0x80) + { + uint8_t excep_num = (addrbyte >> 3) & 0x7; + m_curr_packet.UpdateISA(ocsd_isa_arm); + m_curr_packet.SetException(exceptionTypeARMdeprecated[excep_num], excep_num, (addrbyte & 0x40) ? true : false,m_config.isV7MArch()); + } + else + // normal 5 byte branch, or uses exception bytes. + { + // go grab the exception bits to correctly interpret the ISA state + if((addrbyte & 0x40) == 0x40) + extractExceptionData(); + + if((addrbyte & 0xB8) == 0x08) + m_curr_packet.UpdateISA(ocsd_isa_arm); + else if ((addrbyte & 0xB0) == 0x10) + m_curr_packet.UpdateISA(m_curr_packet.AltISA() ? ocsd_isa_tee : ocsd_isa_thumb2); + else if ((addrbyte & 0xA0) == 0x20) + m_curr_packet.UpdateISA(ocsd_isa_jazelle); + else + throwMalformedPacketErr("Malformed Packet - Unknown ISA."); + } + + byte5AddrUpdate = true; // need to update the address value from byte 5 + } + + // figure out the correct ISA shifts for the address bits + switch(m_curr_packet.ISA()) + { + case ocsd_isa_thumb2: isa_idx = 1; break; + case ocsd_isa_tee: isa_idx = 2; break; + case ocsd_isa_jazelle: isa_idx = 3; break; + default: break; + } + + if(byte5AddrUpdate) + { + value |= ((uint32_t)(addrbyte & addrMask[isa_idx])) << bitcount; + bitcount += addrBits[isa_idx]; + } + + // finally align according to ISA + shift = addrshift[isa_idx]; + value <<= shift; + bitcount += shift; + + nBitsOut = bitcount; + return value; +} + +// extract exception data from bytes after address. +void EtmV3PktProcImpl::extractExceptionData() +{ + static const ocsd_armv7_exception exceptionTypesStd[] = { + Excp_NoException, Excp_DebugHalt, Excp_SMC, Excp_Hyp, + Excp_AsyncDAbort, Excp_Jazelle, Excp_Reserved, Excp_Reserved, + Excp_Reset, Excp_Undef, Excp_SVC, Excp_PrefAbort, + Excp_SyncDataAbort, Excp_Generic, Excp_IRQ, Excp_FIQ + }; + + static const ocsd_armv7_exception exceptionTypesCM[] = { + Excp_NoException, Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn, + Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn, + Excp_CMIRQn, Excp_CMUsageFault, Excp_CMNMI, Excp_SVC, + Excp_CMDebugMonitor, Excp_CMMemManage, Excp_CMPendSV, Excp_CMSysTick, + Excp_Reserved, Excp_Reset, Excp_Reserved, Excp_CMHardFault, + Excp_Reserved, Excp_CMBusFault, Excp_Reserved, Excp_Reserved + }; + + uint16_t exceptionNum = 0; + ocsd_armv7_exception excep_type = Excp_Reserved; + int resume = 0; + int irq_n = 0; + bool cancel_prev_instr = 0; + bool Byte2 = false; + + checkPktLimits(); + + //**** exception info Byte 0 + uint8_t dataByte = m_currPacketData[m_currPktIdx++]; + + m_curr_packet.UpdateNS(dataByte & 0x1); + exceptionNum |= (dataByte >> 1) & 0xF; + cancel_prev_instr = (dataByte & 0x20) ? true : false; + m_curr_packet.UpdateAltISA(((dataByte & 0x40) != 0) ? 1 : 0); + + //** another byte? + if(dataByte & 0x80) + { + checkPktLimits(); + dataByte = m_currPacketData[m_currPktIdx++]; + + if(dataByte & 0x40) + Byte2 = true; //** immediate info byte 2, skipping 1 + else + { + //**** exception info Byte 1 + if(m_config.isV7MArch()) + { + exceptionNum |= ((uint16_t)(dataByte & 0x1F)) << 4; + } + m_curr_packet.UpdateHyp(dataByte & 0x20 ? 1 : 0); + + if(dataByte & 0x80) + { + checkPktLimits(); + dataByte = m_currPacketData[m_currPktIdx++]; + Byte2 = true; + } + } + //**** exception info Byte 2 + if(Byte2) + { + resume = dataByte & 0xF; + } + } + + // set the exception type - according to the number and core profile + if(m_config.isV7MArch()) + { + exceptionNum &= 0x1FF; + if(exceptionNum < 0x018) + excep_type= exceptionTypesCM[exceptionNum]; + else + excep_type = Excp_CMIRQn; + + if(excep_type == Excp_CMIRQn) + { + if(exceptionNum > 0x018) + irq_n = exceptionNum - 0x10; + else if(exceptionNum == 0x008) + irq_n = 0; + else + irq_n = exceptionNum; + } + } + else + { + exceptionNum &= 0xF; + excep_type = exceptionTypesStd[exceptionNum]; + } + m_curr_packet.SetException(excep_type, exceptionNum, cancel_prev_instr,m_config.isV7MArch(), irq_n,resume); +} + +void EtmV3PktProcImpl::checkPktLimits() +{ + // index running off the end of the packet means a malformed packet. + if(m_currPktIdx >= m_currPacketData.size()) + throwMalformedPacketErr("Malformed Packet - oversized packet."); +} + +uint32_t EtmV3PktProcImpl::extractCtxtID() +{ + uint32_t ctxtID = 0; + int size = m_config.CtxtIDBytes(); + + // check we have enough data + if((m_currPktIdx + size) > m_currPacketData.size()) + throwMalformedPacketErr("Too few bytes to extract context ID."); + + switch(size) + { + case 1: + ctxtID = (uint32_t)m_currPacketData[m_currPktIdx]; + m_currPktIdx++; + break; + + case 2: + ctxtID = (uint32_t)m_currPacketData[m_currPktIdx] + | ((uint32_t)m_currPacketData[m_currPktIdx+1]) << 8; + m_currPktIdx+=2; + break; + + case 4: + ctxtID = (uint32_t)m_currPacketData[m_currPktIdx] + | ((uint32_t)m_currPacketData[m_currPktIdx+1]) << 8 + | ((uint32_t)m_currPacketData[m_currPktIdx+2]) << 16 + | ((uint32_t)m_currPacketData[m_currPktIdx+3]) << 24; + m_currPktIdx+=4; + break; + } + return ctxtID; +} + +uint64_t EtmV3PktProcImpl::extractTimestamp(uint8_t &tsBits) +{ + uint64_t ts = 0; + unsigned tsMaxBytes = m_config.TSPkt64() ? 9 : 7; + unsigned tsCurrBytes = 0; + bool bCont = true; + uint8_t mask = 0x7F; + uint8_t last_mask = m_config.TSPkt64() ? 0xFF : 0x3F; + uint8_t ts_iter_bits = 7; + uint8_t ts_last_iter_bits = m_config.TSPkt64() ? 8 : 6; + uint8_t currByte; + tsBits = 0; + + while((tsCurrBytes < tsMaxBytes) && bCont) + { + if(m_currPacketData.size() < (m_currPktIdx + tsCurrBytes + 1)) + throwMalformedPacketErr("Insufficient bytes to extract timestamp."); + + currByte = m_currPacketData[m_currPktIdx+tsCurrBytes]; + ts |= ((uint64_t)(currByte & mask)) << (7 * tsCurrBytes); + tsCurrBytes++; + tsBits += ts_iter_bits; + bCont = ((0x80 & currByte) == 0x80); + if(tsCurrBytes == (tsMaxBytes - 1)) + { + mask = last_mask; + ts_iter_bits = ts_last_iter_bits; + } + } + m_currPktIdx += tsCurrBytes; + return ts; +} + + +uint32_t EtmV3PktProcImpl::extractDataAddress(uint8_t &bits, bool &updateBE, uint8_t &beVal) +{ + uint32_t dataAddr = 0; + int bytesIdx = 0; + bool bCont = true; + uint8_t currByte = 0; + + updateBE = false; + bits = 0; + + while(bCont) + { + checkPktLimits(); + currByte = m_currPacketData[m_currPktIdx++] & ((bytesIdx == 4) ? 0x0F : 0x7F); + dataAddr |= (((uint32_t)currByte) << (bytesIdx * 7)); + bCont = ((currByte & 0x80) == 0x80); + if(bytesIdx == 4) + { + bits += 4; + updateBE = true; + beVal = ((currByte >> 4) & 0x1); + bCont = false; + } + else + bits+=7; + bytesIdx++; + } + return dataAddr; +} + +uint32_t EtmV3PktProcImpl::extractDataValue(const int dataByteSize) +{ + static int bytesReqTable[] = { 0,1,2,4 }; + + uint32_t dataVal = 0; + int bytesUsed = 0; + int bytesReq = bytesReqTable[dataByteSize & 0x3]; + while(bytesUsed < bytesReq) + { + checkPktLimits(); + dataVal |= (((uint32_t)m_currPacketData[m_currPktIdx++]) << (bytesUsed * 8)); + bytesUsed++; + } + return dataVal; +} + + +uint32_t EtmV3PktProcImpl::extractCycleCount() +{ + uint32_t cycleCount = 0; + int byteIdx = 0; + uint8_t mask = 0x7F; + bool bCond = true; + uint8_t currByte = 0; + + while(bCond) + { + checkPktLimits(); + currByte = m_currPacketData[m_currPktIdx++]; + cycleCount |= ((uint32_t)(currByte & mask)) << (7 * byteIdx); + bCond = ((currByte & 0x80) == 0x80); + byteIdx++; + + if(byteIdx == 4) + mask = 0x0F; + + if(byteIdx == 5) + bCond = false; + } + return cycleCount; +} + +void EtmV3PktProcImpl::OnISyncPacket() +{ + uint8_t iSyncInfoByte = 0; + uint32_t instrAddr = 0, LSiPAddr = 0; + int LSiPBits = 0; + uint8_t T = 0, J = 0, AltISA = 0; + + m_currPktIdx = 1; + if(m_bIsync_got_cycle_cnt) + { + m_curr_packet.SetCycleCount(extractCycleCount()); + m_curr_packet.SetISyncHasCC(); + } + + if(m_config.CtxtIDBytes() != 0) + { + m_curr_packet.UpdateContextID(extractCtxtID()); + } + + // extract context info + iSyncInfoByte = m_currPacketData[m_currPktIdx++]; + m_curr_packet.SetISyncReason((ocsd_iSync_reason)((iSyncInfoByte >> 5) & 0x3)); + J = (iSyncInfoByte >> 4) & 0x1; + AltISA = m_config.MinorRev() >= 3 ? (iSyncInfoByte >> 2) & 0x1 : 0; + m_curr_packet.UpdateNS((iSyncInfoByte >> 3) & 0x1); + if(m_config.hasVirtExt()) + m_curr_packet.UpdateHyp((iSyncInfoByte >> 1) & 0x1); + + // main address value - full 32 bit address value + if(m_config.isInstrTrace()) + { + for(int i = 0; i < 4; i++) + instrAddr |= ((uint32_t)m_currPacketData[m_currPktIdx++]) << (8*i); + T = instrAddr & 0x1; // get the T bit. + instrAddr &= ~0x1; // remove from address. + m_curr_packet.UpdateAddress(instrAddr,32); + + // enough data now to set the instruction set. + ocsd_isa currISA = ocsd_isa_arm; + if(J) + currISA = ocsd_isa_jazelle; + else if(T) + currISA = AltISA ? ocsd_isa_tee : ocsd_isa_thumb2; + m_curr_packet.UpdateISA(currISA); + + // possible follow up address value - rarely uses unless trace enabled during + // load and store instruction executing on top of other instruction. + if(m_bIsync_get_LSiP_addr) + { + LSiPAddr = extractBrAddrPkt(LSiPBits); + // follow up address value is compressed relative to the main value + // we store this in the data address value temporarily. + m_curr_packet.UpdateDataAddress(instrAddr,32); + m_curr_packet.UpdateDataAddress(LSiPAddr,LSiPBits); + } + } + else + m_curr_packet.SetISyncNoAddr(); + + SendPacket(); // mark ready to send +} + +/* End of File trc_pkt_proc_etmv3_impl.cpp */ diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h new file mode 100644 index 0000000..a8e4fd1 --- /dev/null +++ b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h @@ -0,0 +1,175 @@ +/* + * \file trc_pkt_proc_etmv3_impl.h + * \brief OpenCSD : + * + * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. + */ + + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED +#define ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED + +#include "opencsd/etmv3/trc_pkt_proc_etmv3.h" +#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h" +#include "opencsd/etmv3/trc_pkt_elem_etmv3.h" + +#define MAX_PACKET_SIZE 32 +#define ASYNC_SIZE 6 + +class EtmV3PktProcImpl +{ +public: + EtmV3PktProcImpl(); + ~EtmV3PktProcImpl(); + + void Initialise(TrcPktProcEtmV3 *p_interface); + + ocsd_err_t Configure(const EtmV3Config *p_config); + + + ocsd_datapath_resp_t processData( const ocsd_trc_index_t index, + const uint32_t dataBlockSize, + const uint8_t *pDataBlock, + uint32_t *numBytesProcessed); + ocsd_datapath_resp_t onEOT(); + ocsd_datapath_resp_t onReset(); + ocsd_datapath_resp_t onFlush(); + const bool isBadPacket() const; + +protected: + typedef enum _process_state { + WAIT_SYNC, + PROC_HDR, + PROC_DATA, + SEND_PKT, + PROC_ERR, + } process_state; + + process_state m_process_state; + + + void InitPacketState(); // clear current packet state. + void InitProcessorState(); // clear all previous process state + + // byte processing + + uint32_t waitForSync(const uint32_t dataBlockSize, const uint8_t *pDataBlock); //!< look for sync, return none-sync bytes processed. + ocsd_err_t processHeaderByte(uint8_t by); + ocsd_err_t processPayloadByte(uint8_t by); + + // packet handling - main routines + void OnBranchAddress(); + void OnISyncPacket(); + uint32_t extractCtxtID(); + uint64_t extractTimestamp(uint8_t &tsBits); + uint32_t extractDataAddress(uint8_t &bits, bool &updateBE, uint8_t &beVal); + uint32_t extractDataValue(const int dataByteSize); + uint32_t extractCycleCount(); + + // packet handling - helper routines + uint32_t extractBrAddrPkt(int &nBitsOut); + void extractExceptionData(); + void checkPktLimits(); + void setBytesPartPkt(const int numBytes, const process_state nextState, const ocsd_etmv3_pkt_type nextType); // set first n bytes from current packet to be sent via alt packet. + + // packet output + void SendPacket(); // mark state for packet output + ocsd_datapath_resp_t outputPacket(); // output a packet + + // bad packets + void throwMalformedPacketErr(const char *pszErrMsg); + void throwPacketHeaderErr(const char *pszErrMsg); + void throwUnsupportedErr(const char *pszErrMsg); + + uint32_t m_bytesProcessed; // bytes processed by the process data routine (index into input buffer) + std::vector<uint8_t> m_currPacketData; // raw data + uint32_t m_currPktIdx; // index into packet when expanding + EtmV3TrcPacket m_curr_packet; // expanded packet + + std::vector<uint8_t> m_partPktData; // raw data when we need to split a packet. + bool m_bSendPartPkt; // mark the part packet as the one we send. + process_state m_post_part_pkt_state; // state to set after part packet set + ocsd_etmv3_pkt_type m_post_part_pkt_type; // reset the packet type. + + // process state + bool m_bStreamSync; //!< true if we have synced this stream + bool m_bStartOfSync; //!< true if we have a start of sync. + + // packet state + uint32_t m_bytesExpectedThisPkt; // used by some of the variable packet length types. + bool m_BranchPktNeedsException; + bool m_bIsync_got_cycle_cnt; + bool m_bIsync_get_LSiP_addr; + int m_IsyncInfoIdx; + bool m_bExpectingDataAddress; + bool m_bFoundDataAddress; + + ocsd_trc_index_t m_packet_index; // index of the start of the current packet + ocsd_trc_index_t m_packet_curr_byte_index; // index of the current byte. + + bool m_isInit; + TrcPktProcEtmV3 *m_interface; /**< The interface to the other decode components */ + + EtmV3Config m_config; + + uint8_t m_chanIDCopy; +}; + + +inline void EtmV3PktProcImpl::SendPacket() +{ + m_process_state = SEND_PKT; +} + +inline void EtmV3PktProcImpl::throwMalformedPacketErr(const char *pszErrMsg) +{ + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,m_chanIDCopy,pszErrMsg); +} + +inline void EtmV3PktProcImpl::throwPacketHeaderErr(const char *pszErrMsg) +{ + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,m_chanIDCopy,pszErrMsg); +} + +inline void EtmV3PktProcImpl::throwUnsupportedErr(const char *pszErrMsg) +{ + throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_packet_index,m_chanIDCopy,pszErrMsg); +} + + +inline const bool EtmV3PktProcImpl::isBadPacket() const +{ + return m_curr_packet.isBadPacket(); +} + + +#endif // ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED + +/* End of File trc_pkt_proc_etmv3_impl.h */ |