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