aboutsummaryrefslogtreecommitdiff
path: root/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp')
-rw-r--r--decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp1224
1 files changed, 1224 insertions, 0 deletions
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 0000000000000..fc39a5eda7d3e
--- /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 */