1 /*
2  * \file       trc_pkt_decode_ptm.cpp
3  * \brief      OpenCSD : PTM packet decoder.
4  *
5  * \copyright  Copyright (c) 2016, ARM Limited. All Rights Reserved.
6  */
7 
8 /*
9  * Redistribution and use in source and binary forms, with or without modification,
10  * are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sstream>
36 #include "opencsd/ptm/trc_pkt_decode_ptm.h"
37 
38 #define DCD_NAME "DCD_PTM"
39 
40 TrcPktDecodePtm::TrcPktDecodePtm()
41     : TrcPktDecodeBase(DCD_NAME)
42 {
43     initDecoder();
44 }
45 
46 TrcPktDecodePtm::TrcPktDecodePtm(int instIDNum)
47     : TrcPktDecodeBase(DCD_NAME,instIDNum)
48 {
49     initDecoder();
50 }
51 
52 TrcPktDecodePtm::~TrcPktDecodePtm()
53 {
54 }
55 
56 /*********************** implementation packet decoding interface */
57 
58 ocsd_datapath_resp_t TrcPktDecodePtm::processPacket()
59 {
60     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
61     bool bPktDone = false;
62 
63     while(!bPktDone)
64     {
65         switch(m_curr_state)
66         {
67         case NO_SYNC:
68             // no sync - output a no sync packet then transition to wait sync.
69             m_output_elem.elem_type = OCSD_GEN_TRC_ELEM_NO_SYNC;
70             m_output_elem.unsync_eot_info = m_unsync_info;
71             resp = outputTraceElement(m_output_elem);
72             m_curr_state = (m_curr_packet_in->getType() == PTM_PKT_A_SYNC) ? WAIT_ISYNC : WAIT_SYNC;
73             bPktDone = true;
74             break;
75 
76         case WAIT_SYNC:
77             if(m_curr_packet_in->getType() == PTM_PKT_A_SYNC)
78                 m_curr_state = WAIT_ISYNC;
79             bPktDone = true;
80             break;
81 
82         case WAIT_ISYNC:
83             if(m_curr_packet_in->getType() == PTM_PKT_I_SYNC)
84                 m_curr_state = DECODE_PKTS;
85             else
86                 bPktDone = true;
87             break;
88 
89         case DECODE_PKTS:
90             resp = decodePacket();
91             bPktDone = true;
92             break;
93 
94         default:
95              // should only see these after a _WAIT resp - in flush handler
96         case CONT_ISYNC:
97         case CONT_ATOM:
98             bPktDone = true;
99             // throw a decoder error
100             break;
101         }
102     }
103     return resp;
104 }
105 
106 ocsd_datapath_resp_t TrcPktDecodePtm::onEOT()
107 {
108     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
109     // shouldn't be any packets left to be processed - flush shoudl have done this.
110     // just output the end of trace marker
111     m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE);
112     m_output_elem.setUnSyncEOTReason(UNSYNC_EOT);
113     resp = outputTraceElement(m_output_elem);
114     return resp;
115 }
116 
117 ocsd_datapath_resp_t TrcPktDecodePtm::onReset()
118 {
119     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
120     m_unsync_info = UNSYNC_RESET_DECODER;
121     resetDecoder();
122     return resp;
123 }
124 
125 ocsd_datapath_resp_t TrcPktDecodePtm::onFlush()
126 {
127     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
128     resp = contProcess();
129     return resp;
130 }
131 
132 // atom and isync packets can have multiple ouput packets that can be _WAITed mid stream.
133 ocsd_datapath_resp_t TrcPktDecodePtm::contProcess()
134 {
135     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
136     switch(m_curr_state)
137     {
138     case CONT_ISYNC:
139         resp = processIsync();
140         break;
141 
142     case CONT_ATOM:
143         resp = processAtom();
144         break;
145 
146     case CONT_WPUP:
147         resp = processWPUpdate();
148         break;
149 
150     case CONT_BRANCH:
151         resp = processBranch();
152         break;
153 
154     default: break; // not a state that requires further processing
155     }
156 
157     if(OCSD_DATA_RESP_IS_CONT(resp) && processStateIsCont())
158         m_curr_state = DECODE_PKTS; // continue packet processing - assuming we have not degraded into an unsynced state.
159 
160     return resp;
161 }
162 
163 ocsd_err_t TrcPktDecodePtm::onProtocolConfig()
164 {
165     ocsd_err_t err = OCSD_OK;
166     if(m_config == 0)
167         return OCSD_ERR_NOT_INIT;
168 
169     // static config - copy of CSID for easy reference
170     m_CSID = m_config->getTraceID();
171 
172     // handle return stack implementation
173     if (m_config->hasRetStack())
174     {
175         m_return_stack.set_active(m_config->enaRetStack());
176 #ifdef TRC_RET_STACK_DEBUG
177         m_return_stack.set_dbg_logger(this);
178 #endif
179     }
180 
181     // config options affecting decode
182     m_instr_info.pe_type.profile = m_config->coreProfile();
183     m_instr_info.pe_type.arch = m_config->archVersion();
184     m_instr_info.dsb_dmb_waypoints = m_config->dmsbWayPt() ? 1 : 0;
185     m_instr_info.wfi_wfe_branch = 0;
186     return err;
187 }
188 
189 /****************** local decoder routines */
190 
191 void TrcPktDecodePtm::initDecoder()
192 {
193     m_CSID = 0;
194     m_instr_info.pe_type.profile = profile_Unknown;
195     m_instr_info.pe_type.arch = ARCH_UNKNOWN;
196     m_instr_info.dsb_dmb_waypoints = 0;
197     m_unsync_info = UNSYNC_INIT_DECODER;
198     resetDecoder();
199 }
200 
201 void TrcPktDecodePtm::resetDecoder()
202 {
203     m_curr_state = NO_SYNC;
204     m_need_isync = true;    // need context to start.
205 
206     m_instr_info.isa = ocsd_isa_unknown;
207     m_mem_nacc_pending = false;
208 
209     m_pe_context.ctxt_id_valid = 0;
210     m_pe_context.bits64 = 0;
211     m_pe_context.vmid_valid = 0;
212     m_pe_context.exception_level = ocsd_EL_unknown;
213     m_pe_context.security_level = ocsd_sec_secure;
214     m_pe_context.el_valid = 0;
215 
216     m_curr_pe_state.instr_addr = 0x0;
217     m_curr_pe_state.isa = ocsd_isa_unknown;
218     m_curr_pe_state.valid = false;
219 
220     m_atoms.clearAll();
221     m_output_elem.init();
222 }
223 
224 ocsd_datapath_resp_t TrcPktDecodePtm::decodePacket()
225 {
226     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
227     switch(m_curr_packet_in->getType())
228     {
229         // ignore these from trace o/p point of veiw
230     case PTM_PKT_NOTSYNC:
231     case PTM_PKT_INCOMPLETE_EOT:
232     case PTM_PKT_NOERROR:
233         break;
234 
235         // bad / reserved packet - need to wait for next sync point
236     case PTM_PKT_BAD_SEQUENCE:
237     case PTM_PKT_RESERVED:
238         m_curr_state = WAIT_SYNC;
239         m_need_isync = true;    // need context to re-start.
240         m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC);
241         resp = outputTraceElement(m_output_elem);
242         break;
243 
244         // packets we can ignore if in sync
245     case PTM_PKT_A_SYNC:
246     case PTM_PKT_IGNORE:
247         break;
248 
249         //
250     case PTM_PKT_I_SYNC:
251         resp = processIsync();
252         break;
253 
254     case PTM_PKT_BRANCH_ADDRESS:
255         resp = processBranch();
256         break;
257 
258     case PTM_PKT_TRIGGER:
259         m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT);
260         m_output_elem.setEvent(EVENT_TRIGGER, 0);
261         resp = outputTraceElement(m_output_elem);
262         break;
263 
264     case PTM_PKT_WPOINT_UPDATE:
265         resp = processWPUpdate();
266         break;
267 
268     case PTM_PKT_CONTEXT_ID:
269         {
270             bool bUpdate = true;
271             // see if this is a change
272             if((m_pe_context.ctxt_id_valid) && (m_pe_context.context_id == m_curr_packet_in->context.ctxtID))
273                 bUpdate = false;
274             if(bUpdate)
275             {
276                 m_pe_context.context_id = m_curr_packet_in->context.ctxtID;
277                 m_pe_context.ctxt_id_valid = 1;
278                 m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
279                 m_output_elem.setContext(m_pe_context);
280                 resp = outputTraceElement(m_output_elem);
281             }
282         }
283         break;
284 
285     case PTM_PKT_VMID:
286         {
287             bool bUpdate = true;
288             // see if this is a change
289             if((m_pe_context.vmid_valid) && (m_pe_context.vmid == m_curr_packet_in->context.VMID))
290                 bUpdate = false;
291             if(bUpdate)
292             {
293                 m_pe_context.vmid = m_curr_packet_in->context.VMID;
294                 m_pe_context.vmid_valid = 1;
295                 m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
296                 m_output_elem.setContext(m_pe_context);
297                 resp = outputTraceElement(m_output_elem);
298             }
299         }
300         break;
301 
302     case PTM_PKT_ATOM:
303         if(m_curr_pe_state.valid)
304         {
305             m_atoms.initAtomPkt(m_curr_packet_in->getAtom(),m_index_curr_pkt);
306             resp = processAtom();
307         }
308         break;
309 
310     case PTM_PKT_TIMESTAMP:
311         m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP);
312         m_output_elem.timestamp = m_curr_packet_in->timestamp;
313         if(m_curr_packet_in->cc_valid)
314             m_output_elem.setCycleCount(m_curr_packet_in->cycle_count);
315         resp = outputTraceElement(m_output_elem);
316         break;
317 
318     case PTM_PKT_EXCEPTION_RET:
319         m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
320         resp = outputTraceElement(m_output_elem);
321         break;
322 
323     }
324     return resp;
325 }
326 
327 ocsd_datapath_resp_t TrcPktDecodePtm::processIsync()
328 {
329     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
330 
331     // extract the I-Sync data if not re-entering after a _WAIT
332     if(m_curr_state == DECODE_PKTS)
333     {
334         m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal();
335         m_curr_pe_state.isa = m_curr_packet_in->getISA();
336         m_curr_pe_state.valid = true;
337 
338         m_i_sync_pe_ctxt = m_curr_packet_in->ISAChanged();
339         if(m_curr_packet_in->CtxtIDUpdated())
340         {
341             m_pe_context.context_id = m_curr_packet_in->getCtxtID();
342             m_pe_context.ctxt_id_valid = 1;
343             m_i_sync_pe_ctxt = true;
344         }
345 
346         if(m_curr_packet_in->VMIDUpdated())
347         {
348             m_pe_context.vmid = m_curr_packet_in->getVMID();
349             m_pe_context.vmid_valid = 1;
350             m_i_sync_pe_ctxt = true;
351         }
352         m_pe_context.security_level = m_curr_packet_in->getNS() ? ocsd_sec_nonsecure : ocsd_sec_secure;
353 
354         if(m_need_isync || (m_curr_packet_in->iSyncReason() != iSync_Periodic))
355         {
356             m_output_elem.setType(OCSD_GEN_TRC_ELEM_TRACE_ON);
357             m_output_elem.trace_on_reason = TRACE_ON_NORMAL;
358             if(m_curr_packet_in->iSyncReason() == iSync_TraceRestartAfterOverflow)
359                 m_output_elem.trace_on_reason = TRACE_ON_OVERFLOW;
360             else if(m_curr_packet_in->iSyncReason() == iSync_DebugExit)
361                 m_output_elem.trace_on_reason = TRACE_ON_EX_DEBUG;
362             if(m_curr_packet_in->hasCC())
363                 m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
364             resp = outputTraceElement(m_output_elem);
365         }
366         else
367         {
368             // periodic - no output
369             m_i_sync_pe_ctxt = false;
370         }
371         m_need_isync = false;   // got 1st Isync - can continue to process data.
372         m_return_stack.flush();
373     }
374 
375     if(m_i_sync_pe_ctxt && OCSD_DATA_RESP_IS_CONT(resp))
376     {
377         m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
378         m_output_elem.setContext(m_pe_context);
379         m_output_elem.setISA(m_curr_pe_state.isa);
380         resp = outputTraceElement(m_output_elem);
381         m_i_sync_pe_ctxt = false;
382     }
383 
384     // if wait and still stuff to process....
385     if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_i_sync_pe_ctxt))
386         m_curr_state = CONT_ISYNC;
387 
388     return resp;
389 }
390 
391 // change of address and/or exception in program flow.
392 // implies E atom before the branch if none exception.
393 ocsd_datapath_resp_t TrcPktDecodePtm::processBranch()
394 {
395     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
396 
397     // initial pass - decoding packet.
398     if(m_curr_state == DECODE_PKTS)
399     {
400         // specific behviour if this is an exception packet.
401         if(m_curr_packet_in->isBranchExcepPacket())
402         {
403             // exception - record address and output exception packet.
404             m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
405             m_output_elem.exception_number = m_curr_packet_in->excepNum();
406             m_output_elem.excep_ret_addr = 0;
407             if(m_curr_pe_state.valid)
408             {
409                 m_output_elem.excep_ret_addr = 1;
410                 m_output_elem.en_addr = m_curr_pe_state.instr_addr;
411             }
412             // could be an associated cycle count
413             if(m_curr_packet_in->hasCC())
414                 m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
415 
416             // output the element
417             resp = outputTraceElement(m_output_elem);
418         }
419         else
420         {
421             // branch address only - implies E atom - need to output a range element based on the atom.
422             if(m_curr_pe_state.valid)
423                 resp = processAtomRange(ATOM_E,"BranchAddr");
424         }
425 
426         // now set the branch address for the next time.
427         m_curr_pe_state.isa = m_curr_packet_in->getISA();
428         m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal();
429         m_curr_pe_state.valid = true;
430     }
431 
432     // atom range may return with NACC pending
433     checkPendingNacc(resp);
434 
435     // if wait and still stuff to process....
436     if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending))
437         m_curr_state = CONT_BRANCH;
438 
439     return resp;
440 }
441 
442 // effectively completes a range prior to exception or after many bytes of trace (>4096)
443 //
444 ocsd_datapath_resp_t TrcPktDecodePtm::processWPUpdate()
445 {
446     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
447 
448     // if we need an address to run from then the WPUpdate will not form a range as
449     // we do not have a start point - still waiting for branch or other address packet
450     if(m_curr_pe_state.valid)
451     {
452         // WP update implies atom - use E, we cannot be sure if the instruction passed its condition codes
453         // - though it doesn't really matter as it is not a branch so cannot change flow.
454         resp = processAtomRange(ATOM_E,"WP update",TRACE_TO_ADDR_INCL,m_curr_packet_in->getAddrVal());
455     }
456 
457     // atom range may return with NACC pending
458     checkPendingNacc(resp);
459 
460     // if wait and still stuff to process....
461     if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending))
462         m_curr_state = CONT_WPUP;
463 
464     return resp;
465 }
466 
467 // a single atom packet can result in multiple range outputs...need to be re-entrant in case we get a wait response.
468 // also need to handle nacc response from instruction walking routine
469 //
470 ocsd_datapath_resp_t TrcPktDecodePtm::processAtom()
471 {
472     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
473 
474     // loop to process all the atoms in the packet
475     while(m_atoms.numAtoms() && m_curr_pe_state.valid && OCSD_DATA_RESP_IS_CONT(resp))
476     {
477         resp = processAtomRange(m_atoms.getCurrAtomVal(),"atom");
478         if(!m_curr_pe_state.valid)
479             m_atoms.clearAll();
480         else
481             m_atoms.clearAtom();
482     }
483 
484     // bad address may mean a nacc needs sending
485     checkPendingNacc(resp);
486 
487     // if wait and still stuff to process....
488     if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending || m_atoms.numAtoms()))
489         m_curr_state = CONT_ATOM;
490 
491     return resp;
492 }
493 
494  void TrcPktDecodePtm::checkPendingNacc(ocsd_datapath_resp_t &resp)
495  {
496     if(m_mem_nacc_pending && OCSD_DATA_RESP_IS_CONT(resp))
497     {
498         m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
499         m_output_elem.st_addr = m_nacc_addr;
500         resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
501         m_mem_nacc_pending = false;
502     }
503  }
504 
505 // given an atom element - walk the code and output a range or mark nacc.
506 ocsd_datapath_resp_t TrcPktDecodePtm::processAtomRange(const ocsd_atm_val A, const char *pkt_msg, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/)
507 {
508     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
509     bool bWPFound = false;
510     std::ostringstream oss;
511     ocsd_err_t err = OCSD_OK;
512 
513     m_instr_info.instr_addr = m_curr_pe_state.instr_addr;
514     m_instr_info.isa = m_curr_pe_state.isa;
515 
516     // set type (which resets out-elem) before traceInstrToWP modifies out-elem values
517     m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
518 
519     err = traceInstrToWP(bWPFound,traceWPOp,nextAddrMatch);
520     if(err != OCSD_OK)
521     {
522         if(err == OCSD_ERR_UNSUPPORTED_ISA)
523         {
524                 m_curr_pe_state.valid = false; // need a new address packet
525                 oss << "Warning: unsupported instruction set processing " << pkt_msg << " packet.";
526                 LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_index_curr_pkt,m_CSID,oss.str()));
527                 // wait for next address
528                 return OCSD_RESP_WARN_CONT;
529         }
530         else
531         {
532             resp = OCSD_RESP_FATAL_INVALID_DATA;
533             oss << "Error processing " << pkt_msg << " packet.";
534             LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_index_curr_pkt,m_CSID,oss.str()));
535             return resp;
536         }
537     }
538 
539     if(bWPFound)
540     {
541         //  save recorded next instuction address
542         ocsd_vaddr_t nextAddr = m_instr_info.instr_addr;
543 
544         // action according to waypoint type and atom value
545         switch(m_instr_info.type)
546         {
547         case OCSD_INSTR_BR:
548             if (A == ATOM_E)
549             {
550                 m_instr_info.instr_addr = m_instr_info.branch_addr;
551                 if (m_instr_info.is_link)
552                     m_return_stack.push(nextAddr,m_instr_info.isa);
553             }
554             break;
555 
556             // For PTM -> branch addresses imply E atom, N atom does not need address (return stack will require this)
557         case OCSD_INSTR_BR_INDIRECT:
558             if (A == ATOM_E)
559             {
560                 // atom on indirect branch - either implied E from a branch address packet, or return stack if active.
561 
562                 // indirect branch taken - need new address -if the current packet is a branch address packet this will be sorted.
563                 m_curr_pe_state.valid = false;
564 
565                 // if return stack and the incoming packet is an atom.
566                 if (m_return_stack.is_active() && (m_curr_packet_in->getType() == PTM_PKT_ATOM))
567                 {
568                     // we have an E atom packet and return stack value - set address from return stack
569                     m_instr_info.instr_addr = m_return_stack.pop(m_instr_info.next_isa);
570 
571                     if (m_return_stack.overflow())
572                     {
573                         resp = OCSD_RESP_FATAL_INVALID_DATA;
574                         oss << "Return stack error processing " << pkt_msg << " packet.";
575                         LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_RET_STACK_OVERFLOW, m_index_curr_pkt, m_CSID, oss.str()));
576                         return resp;
577                     }
578                     else
579                         m_curr_pe_state.valid = true;
580                 }
581                 if(m_instr_info.is_link)
582                     m_return_stack.push(nextAddr, m_instr_info.isa);
583             }
584             break;
585         }
586 
587         m_output_elem.setLastInstrInfo((A == ATOM_E),m_instr_info.type, m_instr_info.sub_type,m_instr_info.instr_size);
588         m_output_elem.setISA(m_curr_pe_state.isa);
589         if(m_curr_packet_in->hasCC())
590             m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
591         m_output_elem.setLastInstrCond(m_instr_info.is_conditional);
592         resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
593 
594         m_curr_pe_state.instr_addr = m_instr_info.instr_addr;
595         m_curr_pe_state.isa = m_instr_info.next_isa;
596     }
597     else
598     {
599         // no waypoint - likely inaccessible memory range.
600         m_curr_pe_state.valid = false; // need an address update
601 
602         if(m_output_elem.st_addr != m_output_elem.en_addr)
603         {
604             // some trace before we were out of memory access range
605             m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type,m_instr_info.instr_size);
606             m_output_elem.setISA(m_curr_pe_state.isa);
607             m_output_elem.setLastInstrCond(m_instr_info.is_conditional);
608             resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
609         }
610     }
611     return resp;
612 }
613 
614 ocsd_err_t TrcPktDecodePtm::traceInstrToWP(bool &bWPFound, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/)
615 {
616     uint32_t opcode;
617     uint32_t bytesReq;
618     ocsd_err_t err = OCSD_OK;
619     ocsd_vaddr_t curr_op_address;
620 
621     ocsd_mem_space_acc_t mem_space = (m_pe_context.security_level == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N;
622 
623     m_output_elem.st_addr = m_output_elem.en_addr = m_instr_info.instr_addr;
624     m_output_elem.num_instr_range = 0;
625 
626     bWPFound = false;
627 
628     while(!bWPFound && !m_mem_nacc_pending)
629     {
630         // start off by reading next opcode;
631         bytesReq = 4;
632         curr_op_address = m_instr_info.instr_addr;  // save the start address for the current opcode
633         err = accessMemory(m_instr_info.instr_addr,mem_space,&bytesReq,(uint8_t *)&opcode);
634         if(err != OCSD_OK) break;
635 
636         if(bytesReq == 4) // got data back
637         {
638             m_instr_info.opcode = opcode;
639             err = instrDecode(&m_instr_info);
640             if(err != OCSD_OK) break;
641 
642             // increment address - may be adjusted by direct branch value later
643             m_instr_info.instr_addr += m_instr_info.instr_size;
644 
645             // update the range decoded address in the output packet.
646             m_output_elem.en_addr = m_instr_info.instr_addr;
647             m_output_elem.num_instr_range++;
648 
649             m_output_elem.last_i_type = m_instr_info.type;
650             // either walking to match the next instruction address or a real waypoint
651             if(traceWPOp != TRACE_WAYPOINT)
652             {
653                 if(traceWPOp == TRACE_TO_ADDR_EXCL)
654                     bWPFound = (m_output_elem.en_addr == nextAddrMatch);
655                 else
656                     bWPFound = (curr_op_address == nextAddrMatch);
657             }
658             else
659                 bWPFound = (m_instr_info.type != OCSD_INSTR_OTHER);
660         }
661         else
662         {
663             // not enough memory accessible.
664             m_mem_nacc_pending = true;
665             m_nacc_addr = m_instr_info.instr_addr;
666         }
667     }
668     return err;
669 }
670 
671 /* End of File trc_pkt_decode_ptm.cpp */
672