diff options
author | Mike Leach <mike.leach@linaro.org> | 2019-07-04 13:56:26 +0100 |
---|---|---|
committer | Mike Leach <mike.leach@linaro.org> | 2019-07-31 16:26:16 +0100 |
commit | 0e2a34a9c972b3c535561f41ec24080b177970d4 (patch) | |
tree | af27d6aa0591ecc91e64bca0356f46f1184736c9 | |
parent | cf7e5da856254d863fc1093919ac014acc8174c0 (diff) | |
download | OpenCSD-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.h | 12 | ||||
-rw-r--r-- | decoder/include/opencsd/trc_gen_elem_types.h | 1 | ||||
-rw-r--r-- | decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp | 118 | ||||
-rw-r--r-- | decoder/source/trc_gen_elem.cpp | 9 |
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; |