/* * \file trc_pkt_elem_ptm.cpp * \brief OpenCSD : * * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "opencsd/ptm/trc_pkt_elem_ptm.h" PtmTrcPacket::PtmTrcPacket() { } PtmTrcPacket::~PtmTrcPacket() { } PtmTrcPacket &PtmTrcPacket::operator =(const ocsd_ptm_pkt* p_pkt) { *dynamic_cast(this) = *p_pkt; return *this; } void PtmTrcPacket::Clear() { err_type = PTM_PKT_NOERROR; cycle_count = 0; cc_valid = 0; context.updated = 0; context.updated_c = 0; context.updated_v = 0; ts_update_bits = 0; atom.En_bits = 0; exception.bits.present = 0; prev_isa = curr_isa; // mark ISA as not changed } void PtmTrcPacket::ResetState() { type = PTM_PKT_NOTSYNC; context.ctxtID = 0; context.VMID = 0; context.curr_alt_isa = 0; context.curr_Hyp = 0; context.curr_NS = 0; addr.valid_bits = 0; addr.size = VA_32BIT; addr.val = 0; prev_isa = curr_isa = ocsd_isa_unknown; timestamp = 0; Clear(); } void PtmTrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits) { ocsd_vaddr_t validMask = OCSD_VA_MASK; validMask >>= OCSD_MAX_VA_BITSIZE-updateBits; addr.pkt_bits = updateBits; addr.val &= ~validMask; addr.val |= (partAddrVal & validMask); if(updateBits > addr.valid_bits) addr.valid_bits = updateBits; } void PtmTrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits) { uint64_t validMask = ~0ULL; validMask >>= 64-updateBits; timestamp &= ~validMask; timestamp |= (tsVal & validMask); ts_update_bits = updateBits; } void PtmTrcPacket::SetCycleAccAtomFromPHdr(const uint8_t pHdr) { atom.num = 1; atom.En_bits = (pHdr & 0x2) ? 0x0 : 0x1; } void PtmTrcPacket::SetAtomFromPHdr(const uint8_t pHdr) { // how many atoms uint8_t atom_fmt_id = pHdr & 0xF0; if(atom_fmt_id == 0x80) { // format 1 or 2 if((pHdr & 0x08) == 0x08) atom.num = 2; else atom.num = 1; } else if(atom_fmt_id == 0x90) { atom.num = 3; } else { if((pHdr & 0xE0) == 0xA0) atom.num = 4; else atom.num = 5; } // extract the E/N bits uint8_t atom_mask = 0x2; // start @ bit 1 - newest instruction atom.En_bits = 0; for(int i = 0; i < atom.num; i++) { atom.En_bits <<= 1; if(!(atom_mask & pHdr)) // 0 bit is an E in PTM -> a one in the standard atom bit type atom.En_bits |= 0x1; atom_mask <<= 1; } } // printing void PtmTrcPacket::toString(std::string &str) const { std::string temp1, temp2; std::ostringstream oss; packetTypeName(type, temp1,temp2); oss << temp1 << " : " << temp2 << "; "; // some packets require additional data. switch(type) { case PTM_PKT_BAD_SEQUENCE: packetTypeName(err_type, temp1,temp2); oss << "[" << temp1 << "]; "; break; case PTM_PKT_ATOM: getAtomStr(temp1); oss << temp1; break; case PTM_PKT_CONTEXT_ID: oss << "CtxtID=0x" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; "; break; case PTM_PKT_VMID: oss << "VMID=0x" << std::hex << std::setw(2) << std::setfill('0') << context.VMID << "; "; break; case PTM_PKT_WPOINT_UPDATE: case PTM_PKT_BRANCH_ADDRESS: getBranchAddressStr(temp1); oss << temp1; break; case PTM_PKT_I_SYNC: getISyncStr(temp1); oss << temp1; break; case PTM_PKT_TIMESTAMP: getTSStr(temp1); oss << temp1; break; } str = oss.str(); } void PtmTrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const { toString(str); } void PtmTrcPacket::getAtomStr(std::string &valStr) const { std::ostringstream oss; uint32_t bitpattern = atom.En_bits; // arranged LSBit oldest, MSbit newest if(cc_valid) // cycle accurate trace - single atom { std::string subStr; oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest oss << "; "; getCycleCountStr(subStr); oss << subStr; } else { // none cycle count for(int i = 0; i < atom.num; i++) { oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest bitpattern >>= 1; } oss << "; "; } valStr = oss.str(); } void PtmTrcPacket::getBranchAddressStr(std::string &valStr) const { std::ostringstream oss; std::string subStr; // print address. trcPrintableElem::getValStr(subStr,32,addr.valid_bits,addr.val,true,addr.pkt_bits); oss << "Addr=" << subStr << "; "; // current ISA if changed. if(curr_isa != prev_isa) { getISAStr(subStr); oss << subStr; } // S / NS etc if changed. if(context.updated) { oss << (context.curr_NS ? "NS; " : "S; "); oss << (context.curr_Hyp ? "Hyp; " : ""); } // exception? if(exception.bits.present) { getExcepStr(subStr); oss << subStr; } if(cc_valid) { getCycleCountStr(subStr); oss << subStr; } valStr = oss.str(); } void PtmTrcPacket::getISAStr(std::string &isaStr) const { std::ostringstream oss; oss << "ISA="; switch(curr_isa) { case ocsd_isa_arm: oss << "ARM(32); "; break; case ocsd_isa_thumb2: oss << "Thumb2; "; break; case ocsd_isa_aarch64: oss << "AArch64; "; break; case ocsd_isa_tee: oss << "ThumbEE; "; break; case ocsd_isa_jazelle: oss << "Jazelle; "; break; default: case ocsd_isa_unknown: oss << "Unknown; "; break; } isaStr = oss.str(); } void PtmTrcPacket::getExcepStr(std::string &excepStr) const { static const char *ARv7Excep[] = { "No Exception", "Debug Halt", "SMC", "Hyp", "Async Data Abort", "Jazelle", "Reserved", "Reserved", "PE Reset", "Undefined Instr", "SVC", "Prefetch Abort", "Data Fault", "Generic", "IRQ", "FIQ" }; std::ostringstream oss; oss << "Excep="; if(exception.number < 16) oss << ARv7Excep[exception.number]; else oss << "Unknown"; oss << " [" << std::hex << std::setw(2) << std::setfill('0') << exception.number << "]; "; excepStr = oss.str(); } void PtmTrcPacket::getISyncStr(std::string &valStr) const { std::ostringstream oss; std::string tmpStr; static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" }; // reason. oss << "(" << reason[(int)i_sync_reason] << "); "; // full address. oss << "Addr=0x" << std::hex << std::setfill('0') << std::setw(8) << (uint32_t)addr.val << "; "; oss << (context.curr_NS ? "NS; " : "S; "); oss << (context.curr_Hyp ? "Hyp; " : " "); if(context.updated_c) { oss << "CtxtID=" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; "; } getISAStr(tmpStr); oss << tmpStr; if(cc_valid) { getCycleCountStr(tmpStr); oss << tmpStr; } valStr = oss.str(); } void PtmTrcPacket::getTSStr(std::string &valStr) const { std::string tmpStr; std::ostringstream oss; trcPrintableElem::getValStr(tmpStr,64,64,timestamp,true,ts_update_bits); oss << "TS=" << tmpStr + "(" << std::dec << timestamp << "); "; if(cc_valid) { getCycleCountStr(tmpStr); oss << tmpStr; } valStr = oss.str(); } void PtmTrcPacket::getCycleCountStr(std::string &subStr) const { std::ostringstream oss; oss << "Cycles=" << std::dec << cycle_count << "; "; subStr = oss.str(); } void PtmTrcPacket::packetTypeName(const ocsd_ptm_pkt_type pkt_type, std::string &name, std::string &desc) const { switch(pkt_type) { case PTM_PKT_NOTSYNC: //!< no sync found yet name = "NOTSYNC"; desc = "PTM Not Synchronised"; break; case PTM_PKT_INCOMPLETE_EOT: name = "INCOMPLETE_EOT"; desc = "Incomplete packet flushed at end of trace"; break; case PTM_PKT_NOERROR: name = "NO_ERROR"; desc = "Error type not set"; break; case PTM_PKT_BAD_SEQUENCE: name = "BAD_SEQUENCE"; desc = "Invalid sequence in packet"; break; case PTM_PKT_RESERVED: name = "RESERVED"; desc = "Reserved Packet Header"; break; case PTM_PKT_BRANCH_ADDRESS: name = "BRANCH_ADDRESS"; desc = "Branch address packet"; break; case PTM_PKT_A_SYNC: name = "ASYNC"; desc = "Alignment Synchronisation Packet"; break; case PTM_PKT_I_SYNC: name = "ISYNC"; desc = "Instruction Synchronisation packet"; break; case PTM_PKT_TRIGGER: name = "TRIGGER"; desc = "Trigger Event packet"; break; case PTM_PKT_WPOINT_UPDATE: name = "WP_UPDATE"; desc = "Waypoint update packet"; break; case PTM_PKT_IGNORE: name = "IGNORE"; desc = "Ignore packet"; break; case PTM_PKT_CONTEXT_ID: name = "CTXTID"; desc = "Context ID packet"; break; case PTM_PKT_VMID: name = "VMID"; desc = "VM ID packet"; break; case PTM_PKT_ATOM: name = "ATOM"; desc = "Atom packet"; break; case PTM_PKT_TIMESTAMP: name = "TIMESTAMP"; desc = "Timestamp packet"; break; case PTM_PKT_EXCEPTION_RET: name = "ERET"; desc = "Exception return packet"; break; default: name = "UNKNOWN"; desc = "Unknown packet type"; break; //PTM_PKT_BRANCH_OR_BYPASS_EOT, //PTM_PKT_TPIU_PAD_EOB, } } /* End of File trc_pkt_elem_ptm.cpp */