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