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 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
onEOT()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
onReset()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
onFlush()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.
contProcess()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
onProtocolConfig()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
initDecoder()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
resetDecoder()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
decodePacket()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
processIsync()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.
processBranch()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 //
processWPUpdate()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 //
processAtom()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
checkPendingNacc(ocsd_datapath_resp_t & resp)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.
processAtomRange(const ocsd_atm_val A,const char * pkt_msg,const waypoint_trace_t traceWPOp,const ocsd_vaddr_t nextAddrMatch)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
traceInstrToWP(bool & bWPFound,const waypoint_trace_t traceWPOp,const ocsd_vaddr_t nextAddrMatch)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