opencsd: etmv4: ete: Add checks for bad program image
Check for inconsistencies in decode that could indicate
that the client has supplied an incorrect program image.
Checks for non-conditional branches associated with N atoms.
Check for inconsistencies in range addresses
Signed-off-by: Mike Leach <mike.leach@linaro.org>
diff --git a/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h b/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h
index 9b6f531..3b87497 100644
--- a/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h
+++ b/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h
@@ -111,8 +111,11 @@
// sequencing error on packet processing - optionally continue
ocsd_err_t handlePacketSeqErr(ocsd_err_t err, ocsd_trc_index_t index, const char *reason);
+ // inconsistent image for decode - optionally reset and continue
+ ocsd_err_t handleBadImageError(ocsd_trc_index_t index, const char* reason);
+
// common packet error routine
- ocsd_err_t handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason);
+ ocsd_err_t handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason, const unsync_info_t unsync_reason);
ocsd_err_t addElemCC(TrcStackElemParam *pParamElem);
ocsd_err_t addElemTS(TrcStackElemParam *pParamElem, bool withCC);
@@ -251,6 +254,34 @@
TrcAddrReturnStack m_return_stack; //!< the address return stack.
+ // range address check to look for possible incorrect input code memory images.
+ struct {
+ ocsd_vaddr_t next_st_addr; // expected address for next range
+ bool valid;
+ } m_next_range_check;
+
+ void nextRangeCheckClear() {
+ m_next_range_check.valid = false;
+ };
+
+ void nextRangeCheckSet(const ocsd_vaddr_t addr) {
+ m_next_range_check.valid = true;
+ m_next_range_check.next_st_addr = addr;
+ };
+
+ bool nextRangeCheckOK(const ocsd_vaddr_t addr) {
+ if (m_next_range_check.valid) {
+ return (bool)(m_next_range_check.next_st_addr == addr);
+ }
+ // no check info - just return OK
+ return true;
+ };
+
+ // consistency check flags
+ bool m_direct_br_chk;
+ bool m_strict_br_chk;
+ bool m_range_cont_chk;
+
//** output element handling
OcsdGenElemStack m_out_elem; //!< output element stack.
OcsdTraceElement &outElem() { return m_out_elem.getCurrElem(); }; //!< current out element
diff --git a/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h b/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h
index 2a03b08..b2c17a5 100644
--- a/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h
+++ b/decoder/include/opencsd/etmv4/trc_pkt_types_etmv4.h
@@ -387,7 +387,10 @@
#define ETE_ARCH_VERSION 0x5
-#define ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS 0x00010000 /**< Split source address output ranges for N-atoms */
+#define ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS 0x00010000 /**< Split source address output ranges for N-atoms */
+#define ETM4_OPFLG_PKTDEC_AA64_OPCODE_CHK 0x00020000 /**< check for invalid AA64 opcodes. (MSW == 0x0000) */
+
+#define ETE_ETM4_OPFLG_MASK (ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS | ETM4_OPFLG_PKTDEC_AA64_OPCODE_CHK)
/** @}*/
/** @}*/
diff --git a/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
index c557998..3c786c6 100644
--- a/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
+++ b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
@@ -39,8 +39,9 @@
#define DCD_NAME "DCD_ETMV4"
-static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS = OCSD_OPFLG_PKTDEC_COMMON |
- ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS;
+static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS =
+ OCSD_OPFLG_PKTDEC_COMMON | /* common op flags */
+ ETE_ETM4_OPFLG_MASK; /* ete - etm4 op flags */
TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I()
: TrcPktDecodeBase(DCD_NAME)
@@ -118,13 +119,18 @@
err = decodePacket();
if (err)
{
-#ifdef OCSD_WARN_UNSUPPORTED
- if (err == OCSD_ERR_UNSUPP_DECODE_PKT)
- resp = OCSD_RESP_WARN_CONT;
+ // may want to continue through bad packets
+ if ((err == OCSD_ERR_BAD_DECODE_PKT) || (err == OCSD_ERR_UNSUPP_DECODE_PKT))
+ {
+ if (getComponentOpMode() & OCSD_OPFLG_PKTDEC_HALT_BAD_PKTS)
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ else if (getComponentOpMode() & OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS)
+ resp = OCSD_RESP_ERR_CONT;
+ else
+ resp = OCSD_RESP_WARN_CONT;
+ }
else
-#else
- resp = OCSD_RESP_FATAL_INVALID_DATA;
-#endif
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
bPktDone = true;
}
@@ -227,6 +233,12 @@
err = OCSD_ERR_HW_CFG_UNSUPP;
LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace on conditional non-branch elements not supported."));
}
+
+ // set consistency check flags
+ m_direct_br_chk = (bool)(getComponentOpMode() & OCSD_OPFLG_N_UNCOND_DIR_BR_CHK);
+ m_strict_br_chk = (bool)(getComponentOpMode() & OCSD_OPFLG_STRICT_N_UNCOND_BR_CHK);
+ m_range_cont_chk = (bool)(getComponentOpMode() & OCSD_OPFLG_CHK_RANGE_CONTINUE);
+
return err;
}
@@ -285,6 +297,7 @@
m_last_IS = 0;
clearElemRes();
m_ete_first_ts_marker = false;
+ nextRangeCheckClear();
// elements associated with data trace
#ifdef DATA_TRACE_SUPPORTED
@@ -604,20 +617,7 @@
case ETM4_PKT_I_NUM_DS_MKR:
case ETM4_PKT_I_UNNUM_DS_MKR:
// all currently unsupported
- {
- ocsd_err_severity_t sev = OCSD_ERR_SEV_ERROR;
-#ifdef OCSD_WARN_UNSUPPORTED
- sev = OCSD_ERR_SEV_WARN;
- //resp = OCSD_RESP_WARN_CONT;
-#else
- //resp = OCSD_RESP_FATAL_INVALID_DATA;
-#endif
- err = OCSD_ERR_UNSUPP_DECODE_PKT;
- if (sev == OCSD_ERR_SEV_WARN)
- LogError(ocsdError(sev, err, "Data trace related, unsupported packet type."));
- else
- err = handlePacketSeqErr(err, m_index_curr_pkt, "Data trace related, unsupported packet type.");
- }
+ err = handlePacketSeqErr(OCSD_ERR_UNSUPP_DECODE_PKT, m_index_curr_pkt, "Data trace related, unsupported packet type.");
break;
default:
@@ -698,8 +698,13 @@
err = discardElements();
}
- if (err != OCSD_OK)
- resp = OCSD_RESP_FATAL_INVALID_DATA;
+ if (err != OCSD_OK) {
+ // has the error reset the decoder?
+ if (m_curr_state == NO_SYNC)
+ resp = OCSD_RESP_ERR_CONT;
+ else
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
}
// break out on error or wait request.
@@ -746,6 +751,7 @@
{
// indicates a trace restart - beginning of trace or discontinuiuty
case P0_TRC_ON:
+ nextRangeCheckClear();
err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_TRACE_ON);
if (!err)
{
@@ -814,17 +820,20 @@
{
ocsd_atm_val atom = pAtomElem->commitOldest();
- // check if prev atom left us an indirect address target on the return stack
+ // check if prev atom was indirect branch - may need address from return stack
if ((err = returnStackPop()) != OCSD_OK)
break;
// if address and context do instruction trace follower.
// otherwise skip atom and reduce committed elements
+ // allow for insufficient program image.
if (!m_need_ctxt && !m_need_addr)
{
- err = processAtom(atom);
+ if ((err = processAtom(atom)) != OCSD_OK)
+ break;
}
- m_elem_res.P0_commit--; // mark committed
+ if (m_elem_res.P0_commit)
+ m_elem_res.P0_commit--; // mark committed
}
if (!pAtomElem->isEmpty())
bPopElem = false; // don't remove if still atoms to process.
@@ -837,11 +846,13 @@
if ((err = returnStackPop()) != OCSD_OK)
break;
+ nextRangeCheckClear();
err = processException(); // output trace + exception elements.
m_elem_res.P0_commit--;
break;
case P0_EXCEP_RET:
+ nextRangeCheckClear();
err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
if (!err)
{
@@ -858,11 +869,13 @@
break;
case P0_SRC_ADDR:
+ nextRangeCheckClear();
err = processSourceAddress();
m_elem_res.P0_commit--;
break;
case P0_Q:
+ nextRangeCheckClear();
err = processQElement();
m_elem_res.P0_commit--;
break;
@@ -873,6 +886,7 @@
case P0_TRANS_COMMIT:
case P0_TRANS_FAIL:
case P0_TRANS_TRACE_INIT:
+ nextRangeCheckClear();
err = processTransElem(pElem);
break;
@@ -1352,6 +1366,20 @@
m_return_stack.push(nextAddr, m_instr_info.isa);
}
+ else if (m_direct_br_chk || m_strict_br_chk) // consistency checks on N atoms?
+ {
+ // N atom - but direct branch instruction not conditional - bad input image?
+ if (!m_instr_info.is_conditional)
+ {
+ // Some ETM IP incorrectly trace a taken branch to next instruction as N
+ // look for branch where it is not next instruction if direct branch checks only
+ if (((m_instr_info.branch_addr != nextAddr) && m_direct_br_chk) || m_strict_br_chk)
+ {
+ err = handleBadImageError(pElem->getRootIndex(), "Bad program image - N Atom on unconditional direct BR.\n");
+ return err;
+ }
+ }
+ }
break;
case OCSD_INSTR_BR_INDIRECT:
@@ -1360,17 +1388,45 @@
m_need_addr = true; // indirect branch taken - need new address.
if (m_instr_info.is_link)
m_return_stack.push(nextAddr,m_instr_info.isa);
- m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen
+
+ // mark last atom as BR indirect - if no address next need addr from return stack.
+ m_return_stack.set_pop_pending();
/* ETE does not have ERET trace packets - however to maintain the illusion if we see an ERET
output a gen elem ERET packet */
if (isETEConfig() && (m_instr_info.sub_type == OCSD_S_INSTR_V8_ERET))
ETE_ERET = true;
}
+ else if (m_strict_br_chk) // consistency checks on N atoms?
+ {
+ // N atom - check if conditional - only in strict check mode.
+ if (!m_instr_info.is_conditional)
+ {
+ err = handleBadImageError(pElem->getRootIndex(), "Bad program image - N Atom on unconditional indirect BR.\n");
+ return err;
+ }
+ }
break;
}
setElemTraceRange(outElem(), addr_range, (atom == ATOM_E), pElem->getRootIndex());
+ // check for discontinuity in address ranges where incorrect memory images supplied to decoder.
+ if (m_range_cont_chk)
+ {
+ // do the previous range chack.
+ if (!nextRangeCheckOK(addr_range.st_addr))
+ {
+ err = handleBadImageError(pElem->getRootIndex(), "Discontinuous ranges - Inconsistent program image for decode\n");
+ return err;
+ }
+
+ if (atom == ATOM_N)
+ // branch not taken - expect next range to be continuous
+ nextRangeCheckSet(nextAddr);
+ else
+ nextRangeCheckClear(); // branch taken - not continuous
+ }
+
if (ETE_ERET)
{
err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
@@ -1382,6 +1438,7 @@
{
// no waypoint - likely inaccessible memory range.
m_need_addr = true; // need an address update
+ nextRangeCheckClear();
if(addr_range.st_addr != addr_range.en_addr)
{
@@ -1970,15 +2027,20 @@
if (getComponentOpMode() & OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS)
sev = OCSD_ERR_SEV_ERROR;
- return handlePacketErr(OCSD_ERR_BAD_DECODE_PKT, sev, index, reason);
+ return handlePacketErr(OCSD_ERR_BAD_DECODE_PKT, sev, index, reason, UNSYNC_BAD_PACKET);
}
ocsd_err_t TrcPktDecodeEtmV4I::handlePacketSeqErr(ocsd_err_t err, ocsd_trc_index_t index, const char *reason)
{
- return handlePacketErr(err, OCSD_ERR_SEV_ERROR, index, reason);
+ return handlePacketErr(err, OCSD_ERR_SEV_ERROR, index, reason, UNSYNC_BAD_PACKET);
}
-ocsd_err_t TrcPktDecodeEtmV4I::handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason)
+ocsd_err_t TrcPktDecodeEtmV4I::handleBadImageError(ocsd_trc_index_t index, const char* reason)
+{
+ return handlePacketErr(OCSD_ERR_BAD_DECODE_IMAGE, OCSD_ERR_SEV_ERROR, index, reason, UNSYNC_BAD_IMAGE);
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason, const unsync_info_t unsync_reason)
{
bool resetOnBadPackets = true;
@@ -1992,8 +2054,8 @@
// switch to unsync - clear decode state
resetDecoder();
m_curr_state = NO_SYNC;
- m_unsync_eot_info = UNSYNC_BAD_PACKET;
- err = OCSD_OK;
+ m_unsync_eot_info = unsync_reason;
+ //err = OCSD_OK;
}
return err;
diff --git a/decoder/source/ocsd_dcd_tree.cpp b/decoder/source/ocsd_dcd_tree.cpp
index 9b1cae5..79aabbc 100644
--- a/decoder/source/ocsd_dcd_tree.cpp
+++ b/decoder/source/ocsd_dcd_tree.cpp
@@ -444,6 +444,10 @@
crtFlags |= OCSD_CREATE_FLG_INST_ID;
}
+ // check for the aa64 check.
+ if (createFlags & ETM4_OPFLG_PKTDEC_AA64_OPCODE_CHK)
+ s_instruction_decoder.setAA64_errOnBadOpcode(true);
+
// create the decode element to attach to the channel.
if((err = createDecodeElement(CSID)) != OCSD_OK)
return err;