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
TrcPktDecodePtm()40 TrcPktDecodePtm::TrcPktDecodePtm()
41 : TrcPktDecodeBase(DCD_NAME)
42 {
43 initDecoder();
44 }
45
TrcPktDecodePtm(int instIDNum)46 TrcPktDecodePtm::TrcPktDecodePtm(int instIDNum)
47 : TrcPktDecodeBase(DCD_NAME,instIDNum)
48 {
49 initDecoder();
50 }
51
~TrcPktDecodePtm()52 TrcPktDecodePtm::~TrcPktDecodePtm()
53 {
54 }
55
56 /*********************** implementation packet decoding interface */
57
processPacket()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
onEOT()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
onReset()115 ocsd_datapath_resp_t TrcPktDecodePtm::onReset()
116 {
117 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
118 resetDecoder();
119 return resp;
120 }
121
onFlush()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.
contProcess()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
onProtocolConfig()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
initDecoder()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
resetDecoder()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
decodePacket()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
processIsync()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.
processBranch()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 //
processWPUpdate()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 //
processAtom()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
checkPendingNacc(ocsd_datapath_resp_t & resp)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.
processAtomRange(const ocsd_atm_val A,const char * pkt_msg,const waypoint_trace_t traceWPOp,const ocsd_vaddr_t nextAddrMatch)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
traceInstrToWP(bool & bWPFound,const waypoint_trace_t traceWPOp,const ocsd_vaddr_t nextAddrMatch)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