aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Leach <mike.leach@linaro.org>2019-07-04 13:56:26 +0100
committerMike Leach <mike.leach@linaro.org>2019-07-31 16:26:16 +0100
commit0e2a34a9c972b3c535561f41ec24080b177970d4 (patch)
treeaf27d6aa0591ecc91e64bca0356f46f1184736c9
parentcf7e5da856254d863fc1093919ac014acc8174c0 (diff)
downloadOpenCSD-0e2a34a9c972b3c535561f41ec24080b177970d4.tar.gz
opencsd: etmv4: Fix exception trace issue where exception at branch target.
Where an exception occurs at the target address of a taken branch, this can result in no code being executed at the branch target address. In this case, the address supplied in the exception packet can also form the address of the branch target, and contain an optional context element to indicate a context change due to the branch. The exception handling code for this case was incorrect. This has been fixed. A context element is now correctly emitted prior to the exception element if indicated in the exception packets. Additionally a flag to indicate to clients that the preferred return address is also a branch target address has been added to the generic output packets. This could be implied from the packet flow, but is explicitly flagged to make detection easier. Signed-off-by: Mike Leach <mike.leach@linaro.org>
-rw-r--r--decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h12
-rw-r--r--decoder/include/opencsd/trc_gen_elem_types.h1
-rw-r--r--decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp118
-rw-r--r--decoder/source/trc_gen_elem.cpp9
4 files changed, 80 insertions, 60 deletions
diff --git a/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h b/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h
index e996878..1c06e5d 100644
--- a/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h
+++ b/decoder/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h
@@ -154,13 +154,17 @@ private:
EXCEP_POP, // start of processing read exception packets off the stack and analyze
EXCEP_RANGE, // output a range element
EXCEP_NACC, // output a nacc element
+ EXCEP_CTXT, // output a ctxt element
EXCEP_EXCEP, // output an ecxeption element.
} excep_proc_state_t;
- excep_proc_state_t m_excep_proc; //!< state of exception processing
- etmv4_addr_val_t m_excep_addr; //!< excetion return address.
- uint32_t m_excep_number; //!< exception number.
- ocsd_trc_index_t m_excep_index; //!< trace index for exception element
+ struct {
+ excep_proc_state_t proc; //!< state of exception processing
+ etmv4_addr_val_t addr; //!< excetion return address.
+ uint32_t number; //!< exception number.
+ ocsd_trc_index_t index; //!< trace index for exception element
+ bool addr_b_tgt; //!< return address is also branch tgt address.
+ } m_excep_info; //!< exception info when processing exception packets
ocsd_instr_info m_instr_info; //!< instruction info for code follower - in address is the next to be decoded.
diff --git a/decoder/include/opencsd/trc_gen_elem_types.h b/decoder/include/opencsd/trc_gen_elem_types.h
index 0cf94cf..1d77b53 100644
--- a/decoder/include/opencsd/trc_gen_elem_types.h
+++ b/decoder/include/opencsd/trc_gen_elem_types.h
@@ -98,6 +98,7 @@ typedef struct _ocsd_generic_trace_elem {
uint32_t extended_data:1; /**< 1 if the packet extended data pointer is valid. Allows packet extensions for custom decoders, or additional data payloads for data trace. */
uint32_t has_ts:1; /**< 1 if the packet has an associated timestamp - e.g. SW/STM trace TS+Payload as a single packet */
uint32_t last_instr_cond:1; /**< 1 if the last instruction was conditional */
+ uint32_t excep_ret_addr_br_tgt:1; /**< 1 if exception return address (en_addr) is also the target of a taken branch addr from the previous range. */
};
uint32_t flag_bits;
};
diff --git a/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
index e4c0db4..42427b9 100644
--- a/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
+++ b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
@@ -128,7 +128,7 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onFlush()
ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
// continue exception processing (can't go through processPacket as elements no longer on stack)
- if(m_excep_proc != EXCEP_POP)
+ if(m_excep_info.proc != EXCEP_POP)
resp = processException();
// continue ongoing output operations on comitted elements.
else if(m_curr_state == COMMIT_ELEM)
@@ -234,7 +234,7 @@ void TrcPktDecodeEtmV4I::resetDecoder()
m_prev_overflow = false;
m_P0_stack.delete_all();
m_output_elem.init();
- m_excep_proc = EXCEP_POP;
+ m_excep_info.proc = EXCEP_POP;
m_flush_EOT = false;
}
@@ -629,7 +629,7 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::commitElements(bool &Complete)
if ((resp = returnStackPop()) != OCSD_RESP_CONT)
break;
- m_excep_proc = EXCEP_POP; // set state in case we need to stop part way through
+ m_excep_info.proc = EXCEP_POP; // set state in case we need to stop part way through
resp = processException(); // output trace + exception elements.
m_P0_commit--;
break;
@@ -902,11 +902,13 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom, bo
ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processException()
{
ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
- bool excep_implied_P0 = false; //!< exception implies P0
+ TrcStackElemExcept *pExceptElem;
- if(m_excep_proc == EXCEP_POP)
+ m_excep_info.addr_b_tgt = false;
+
+ if(m_excep_info.proc == EXCEP_POP)
{
- TrcStackElemExcept *pExceptElem = dynamic_cast<TrcStackElemExcept *>(m_P0_stack.back()); // get the exception element
+ pExceptElem = dynamic_cast<TrcStackElemExcept *>(m_P0_stack.back()); // get the exception element
TrcStackElemAddr *pAddressElem = 0;
TrcStackElemCtxt *pCtxtElem = 0;
TrcStackElem *pElem = 0;
@@ -931,32 +933,52 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processException()
// extract address
pAddressElem = static_cast<TrcStackElemAddr *>(pElem);
- m_excep_addr = pAddressElem->getAddr();
-
- // if we have context, get that.
- if(pCtxtElem)
- updateContext(pCtxtElem);
-
- // record the exception number
- m_excep_number = pExceptElem->getExcepNum();
+ // fill in exception info for use later
+ m_excep_info.addr = pAddressElem->getAddr();
+ m_excep_info.number = pExceptElem->getExcepNum();
+ m_excep_info.index = pExceptElem->getRootIndex();
+ m_excep_info.addr_b_tgt = pExceptElem->getPrevSame();
- // see if there is an implied P0 element on the exception.
- excep_implied_P0 = pExceptElem->getPrevSame();
-
- // save the trace index.
- m_excep_index = pExceptElem->getRootIndex();
+ // see if there is an address + optional context element implied
+ // prior to the exception.
+ if (m_excep_info.addr_b_tgt)
+ {
+ // this was a branch target address - update current setting
+ bool b64bit = m_instr_info.isa == ocsd_isa_aarch64;
+ if (pCtxtElem) {
+ b64bit = pCtxtElem->getContext().SF;
+ }
+ m_instr_info.instr_addr = m_excep_info.addr.val;
+ m_instr_info.isa = (m_excep_info.addr.isa == 0) ?
+ (b64bit ? ocsd_isa_aarch64 : ocsd_isa_arm) : ocsd_isa_thumb2;
+ m_need_addr = false;
+ }
// figure out next move
- if(m_excep_addr.val == m_instr_info.instr_addr)
- m_excep_proc = EXCEP_EXCEP;
+ if (pCtxtElem) {
+ m_excep_info.proc = EXCEP_CTXT;
+ updateContext(pCtxtElem);
+ }
+ else if(m_excep_info.addr.val == m_instr_info.instr_addr)
+ m_excep_info.proc = EXCEP_EXCEP;
else
- m_excep_proc = EXCEP_RANGE;
+ m_excep_info.proc = EXCEP_RANGE;
}
m_P0_stack.delete_popped();
}
+ // output a context element
+ if (m_excep_info.proc == EXCEP_CTXT)
+ {
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+ resp = outputTraceElementIdx(m_excep_info.index, m_output_elem);
+ m_excep_info.proc = EXCEP_EXCEP;
+ if (!OCSD_DATA_RESP_IS_CONT(resp))
+ return resp;
+ }
+
// output a range element
- if(m_excep_proc == EXCEP_RANGE)
+ if(m_excep_info.proc == EXCEP_RANGE)
{
bool bWPFound = false;
ocsd_err_t err;
@@ -964,8 +986,8 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processException()
// last instr_info address is the start address
m_output_elem.st_addr = m_instr_info.instr_addr;
- // look for either a WP or match to return address.
- err = traceInstrToWP(bWPFound,!excep_implied_P0,m_excep_addr.val);
+ // look for match to return address.
+ err = traceInstrToWP(bWPFound,true,m_excep_info.addr.val);
if(err != OCSD_OK)
{
@@ -973,34 +995,21 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processException()
{
m_need_addr = true;
m_need_ctxt = true;
- LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_excep_index,m_CSID,"Warning: unsupported instruction set processing exception packet."));
+ LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_excep_info.index,m_CSID,"Warning: unsupported instruction set processing exception packet."));
}
else
{
resp = OCSD_RESP_FATAL_INVALID_DATA;
- LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_excep_index,m_CSID,"Error processing exception packet."));
- m_excep_proc = EXCEP_POP; // nothing more to do, reset to start of exception handling
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_excep_info.index,m_CSID,"Error processing exception packet."));
+ m_excep_info.proc = EXCEP_POP; // nothing more to do, reset to start of exception handling
}
}
if(bWPFound)
{
- // action according to waypoint type and atom value
- if(excep_implied_P0)
- {
- switch(m_instr_info.type)
- {
- case OCSD_INSTR_BR:
- m_instr_info.instr_addr = m_instr_info.branch_addr;
- break;
-
- case OCSD_INSTR_BR_INDIRECT:
- m_instr_info.instr_addr = m_excep_addr.val;
- break;
- }
- }
- resp = outputTraceRange(true, m_excep_index);
- m_excep_proc = EXCEP_EXCEP;
+ // waypoint address found - output range
+ resp = outputTraceRange(true, m_excep_info.index);
+ m_excep_info.proc = EXCEP_EXCEP;
}
else
{
@@ -1010,32 +1019,33 @@ ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processException()
if(m_output_elem.st_addr != m_output_elem.en_addr)
{
// some trace before we were out of memory access range
- resp = outputTraceRange(true, m_excep_index);
+ resp = outputTraceRange(true, m_excep_info.index);
}
- m_excep_proc = m_mem_nacc_pending ? EXCEP_NACC : EXCEP_EXCEP;
+ m_excep_info.proc = m_mem_nacc_pending ? EXCEP_NACC : EXCEP_EXCEP;
}
}
- if((m_excep_proc == EXCEP_NACC) && OCSD_DATA_RESP_IS_CONT(resp))
+ if((m_excep_info.proc == EXCEP_NACC) && OCSD_DATA_RESP_IS_CONT(resp))
{
m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
m_output_elem.st_addr = m_nacc_addr;
- resp = outputTraceElementIdx(m_excep_index,m_output_elem);
- m_excep_proc = EXCEP_EXCEP;
+ resp = outputTraceElementIdx(m_excep_info.index,m_output_elem);
+ m_excep_info.proc = EXCEP_EXCEP;
m_mem_nacc_pending = false;
}
- if((m_excep_proc == EXCEP_EXCEP) && OCSD_DATA_RESP_IS_CONT(resp))
+ if((m_excep_info.proc == EXCEP_EXCEP) && OCSD_DATA_RESP_IS_CONT(resp))
{
// output element.
m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
// add end address as preferred return address to end addr in element
- m_output_elem.en_addr = m_excep_addr.val;
+ m_output_elem.en_addr = m_excep_info.addr.val;
m_output_elem.excep_ret_addr = 1;
- m_output_elem.exception_number = m_excep_number;
- resp = outputTraceElementIdx(m_excep_index,m_output_elem);
- m_excep_proc = EXCEP_POP;
+ m_output_elem.excep_ret_addr_br_tgt = m_excep_info.addr_b_tgt;
+ m_output_elem.exception_number = m_excep_info.number;
+ resp = outputTraceElementIdx(m_excep_info.index,m_output_elem);
+ m_excep_info.proc = EXCEP_POP;
}
return resp;
}
diff --git a/decoder/source/trc_gen_elem.cpp b/decoder/source/trc_gen_elem.cpp
index 063e94a..b3ec75f 100644
--- a/decoder/source/trc_gen_elem.cpp
+++ b/decoder/source/trc_gen_elem.cpp
@@ -123,9 +123,14 @@ void OcsdTraceElement::toString(std::string &str) const
break;
case OCSD_GEN_TRC_ELEM_EXCEPTION:
- if(excep_ret_addr == 1)
+ if (excep_ret_addr == 1)
{
- oss << "pref ret addr:0x" << std::hex << en_addr << "; ";
+ oss << "pref ret addr:0x" << std::hex << en_addr;
+ if (excep_ret_addr_br_tgt)
+ {
+ oss << " [addr also prev br tgt]";
+ }
+ oss << "; ";
}
oss << "excep num (0x" << std::setfill('0') << std::setw(2) << std::hex << exception_number << ") ";
break;