OpenCSD - CoreSight Trace Decode Library  1.3.3
prog_guide/prog_guide_main.md
Go to the documentation of this file.
1 OpenCSD Library - Programmers Guide {#prog_guide}
2 ===================================
3 
4 @brief A guide to programming the OpenCSD library.
5 
6 Introduction and review of Coresight Hardware
7 ---------------------------------------------
8 
9 The OpenCSD trace decode library is designed to allow programmers to decode ARM CoreSight trace
10 data. This guide will describe the various stages of configuring and programming a decoder instance
11 for a given CoreSight system.
12 
13 The diagram below shows a typical Coresight trace hardware arrangement
14 
15 ![Example CoreSight Trace Capture Hardware](cs_trace_hw.jpg)
16 
17 The design shown has four Cortex cores, each with an ETM, along with a system STM all of which generate trace into the
18 trace funnel. The output of the funnel is fed into a trace sink, which might be an ETB or ETR, saving the trace
19 which is multiplexed into CoreSight trace frames in the trace sink memory. The colours represent the sources
20 of trace data, each of which will be tagged with a CoreSight Trace ID.
21 
22 ### CoreSight Trace ID ###
23 The CoreSight Trace ID - also referred to as the Trace Source Channel ID - is a unique 8 bit number programmed
24 into each trace source in a system (ETM,PTM,STM) which identifies the source to both the hardware components
25 downstream and the software trace decoders. This ID is used
26 
27 Overview of Configuration and Decode
28 ------------------------------------
29 
30 The OpenCSD library will take the trace data from the trace sink, and when correctly configured and programmed, will
31 demultiplex and decode each of the trace sources.
32 
33 The library supports ETMV3, PTM, ETMv4 and STM trace protocols. The decode occurs in three stages:
34 - __Demultiplex__ - the combined trace streams in CoreSight trace frame format are split into their constituent streams according to the CoreSight trace ID.
35 - __Packet Processing__ - the individual trace ID streams are resolved into discrete trace packets.
36 - __Packet Decode__ - the trace packets are interpreted to produce a decoded representation of instructions executed.
37 
38 There are input configuration requirements for each stage of the decode process - these allow the decode process to correctly
39 interpret the incoming byte stream.
40 - __Demultiplex__ - Input flags are set to indicate if the frames are 16 byte aligned or if the stream contains alignment
41 bytes between frames.
42 - __Packet Processing__ - The hardware configuration of the trace source must be provided. This consists of a sub-set of the
43 hardware register values for the source. Each protocol has differing requirements, represented by an input structure of the
44 register values.
45 - __Packet Decode__ - For ETM/PTM packet decode, this stage requires the memory images of the code executed in order
46 to determine the path through the code. These are provided either as memory dumps, or as links to binary code files.
47 
48 _Note_ : STM, being a largely software generated data trace, does not require memory images to recover the data written by the source
49 processors.
50 
51 The diagram below shows the basic stages of decode for the library when used in a client application:
52 
53 ![Example Library Usage for Trace Decode](lib_usage.jpg)
54 
55 The DecodeTree object is a representation of the structure of the CoreSight hardware, but in reverse in that the data is pushed into the
56 tree, through the demultiplexor and then along the individual trace stream decode paths till the output decode packets are produced.
57 
58 These outpup packets are referred to as Generic Trace packets, and are at this stage protocol independent. They consist primarily of
59 PE context information and address ranges representing the instructions processed.
60 
61 ### Decode Tree ###
62 
63 The DecodeTree is the principal wrapper for all the decoders the library supports. This provides a programming
64 API which allows the creation of protocol packet processors and decoders.
65 
66 The API allows the client application to configure the de-multiplexor, create and connect packet processors and
67 packet decoders to the trace data streams and collect the output generic decoded trace packets. The DecodeTree
68 provides a built in instruction decoder to allow correct trace decode, and an additional API through a memory
69 access handler to allow the client applications to provide the images of the traced code in file or memory dump
70 format.
71 
72 Once a DecodeTree is configured, then it can be re-used for multiple sets of captured trace data where the same
73 set of applications has been traced, or by changing only the supplied memory images, different traced applications
74 on the same hardware configuration.
75 
76 The process for programming a decode tree for a specific set of trace hardware is as follows;-
77 1. Create the decode tree and specify the de-multiplexor options.
78 2. For each trace protocol of interest, use the API to create a decoder, providing the hardware configuration,
79 including the CoreSight trace ID for that trace stream. Specify packet processing only, or full decode. Client
80 program must know the correct protocol to use for each trace stream.
81 3. Attach callback(s) to receive the decoded generic trace output (ITrcGenElemIn).
82 4. Provide the memory images if using full decode.
83 
84 The DecodeTree can now be used to process the trace data by pushing the captured trace data through the trace
85  data input API call (ITrcDataIn) and analyzing as required the resulting decoded trace (ITrcGenElemIn).
86 
87  The objects and connections used for a single trace stream are shown below.
88 
89  ![Decode Tree objects - single trace stream](dt_components.jpg)
90 
91  All these components can be created and used outside of a DecodeTree, but that is beyond the scope of this
92  guide and expected to be used for custom implementations only.
93 
94 Programming Examples - decoder configuration.
95 ---------------------------------------------
96 
97 The remainder of this programming guide will provide programming exceprts for each of the required stages
98 to get a working decode tree, capable of processing trace data.
99 
100 The guide will be based on an ETMv4 system, similar to the example above, using the C++ interface, but
101 equivalent calls from the C-API wrapper library will also be provided.
102 
103 The source code for the two test applications `trc_pkt_lister` and `c_api_pkt_print_test` may be used as
104 further programming guidance.
105 
106 ### Create the decode tree ###
107 
108 The first step is to create the decode tree. Key choices here are the flags defining expected trace data
109 input format and de-mux operations.
110 
111 ~~~{.cpp}
112  uint32_t formatterCfgFlags = OCSD_DFRMTR_FRAME_MEM_ALIGN; /* basic operational mode for on-chip captured trace */
113  DecodeTree *pTree = DecodeTree::CreateDecodeTree(OCSD_TRC_SRC_FRAME_FORMATTED, formatterCfgFlags);
114 ~~~
115 
116 This creates a decode tree that is usable in the majority of cases - that is for trace captured in on chip
117 RAM via ETB or ETR. Additional flags are available if a TPIU is used that will indicate to the frame de-mux
118 that additional frame synchronisation data is present.
119 
120 In limited cases where the hardware has a single trace source, or only a single source is being used, then
121 it is possible to switch off the hardware frame formatter in the ETB/ETR/TPIU. In this case @ref OCSD_TRC_SRC_SINGLE
122  (from enum @ref ocsd_dcd_tree_src_t) may be defined as the first parameter to the function.
123 
124 C-API version of above code:
125 ~~~{.c}
126  dcd_tree_handle_t dcdtree_handle = ocsd_create_dcd_tree(OCSD_TRC_SRC_FRAME_FORMATTED, OCSD_DFRMTR_FRAME_MEM_ALIGN);
127 ~~~
128 
129 ### Error loggers and printers ###
130 
131 The library defines a standard error logging interface ITraceErrorLog which many of the key components can register
132 with to output errors. The process of registering the source means that errors can be tied to a particular component,
133 or CoreSight Trace ID. The library provides a standard error logger object - ocsdDefaultErrorLogger - which
134 keeps a copy of the last error logged, plus a copy of the last error logged for each data stream associated
135 with a CoreSight trace ID.
136 
137 The error logger can be attached to an output logger - ocsdMsgLogger - which can print text versions of the
138 error, or other error messages, out to screen or logging file. Errors can be filtered according to a severity rating,
139 defined by @ref ocsd_err_severity_t.
140 
141 The DecodeTree can use a default error logger from the library - with a message logger that will output to `stderr`.
142 
143 Client applications can create and adjust the configuration of this error logger and message logger by getting and intialising
144  the logger.
145 
146 ~~~{.cpp}
147  // ** Initialise default error logger.
148  DecodeTree::getDefaultErrorLogger()->initErrorLogger(verbosity,true);
149 ~~~
150 
151 Alternatively clients may provide their own configured error logger / message logger pair.
152 
153 The test program `trc_pkt_lister` provides a customised version of an `ocsdMsgLogger` / `ocsdDefaultErrorLogger` pair
154 to ensure that messages and errors are logged to the screen and a file of its choice. This logger is eventually
155 passed through to the decode tree.
156 
157 Code excerpts below (trc_pkt_lister.cpp):
158 
159 ~~~{.cpp}
160  static ocsdMsgLogger logger;
161  static int logOpts = ocsdMsgLogger::OUT_STDOUT | ocsdMsgLogger::OUT_FILE;
162  static std::string logfileName = "trc_pkt_lister.ppl";
163 
164  // ** other vars
165 
166  main() {
167 
168  // ** some init code
169 
170  logger.setLogOpts(logOpts);
171  logger.setLogFileName(logfileName.c_str());
172 
173 
174  ocsdDefaultErrorLogger err_log;
175  err_log.initErrorLogger(OCSD_ERR_SEV_INFO);
176  err_log.setOutputLogger(&logger);
177 
178  // pass err_log reference into snapshot library code
179  SnapShotReader ss_reader;
180  ss_reader.setErrorLogger(&err_log);
181 
182  // ** rest of program
183  }
184 ~~~
185 
186 In the library code for the snapshot reader (ss_to_dcd_tree.cpp):
187 
188 ~~~{.cpp}
189  bool CreateDcdTreeFromSnapShot::createDecodeTree()
190  {
191  // ** create a decode tree
192 
193  // use our error logger - don't use the tree default.
194  m_pDecodeTree->setAlternateErrorLogger(m_pErrLogInterface);
195  }
196 
197 ~~~
198 
199 __Note__: The Snapshot reader library is test code designed to allow the test application read trace snapshots
200 which are in the form defined by the open specification in `./decoder/docs/specs/ARM Trace and Debug Snapshot file format 0v2.pdf`
201 
202 This format is used in ARM's DS-5 debugger, and the open source CoreSight Access Library (CSAL).
203 
204 ### Configuring decoders ###
205 
206 The next task is to configure the requried decoders. The client program must know the type of ETM/PTM in use
207 to correctly set the decoder configuration.
208 
209 Each class of trace source has a specific set of register values that the decoder requires to correctly interpret the
210 raw trace data and convert it to packets then fully decode.
211 
212 Configuration of an ETMv4 decoder requires initialisation of the EtmV4Config class, which is achieved by filling in a
213 @ref ocsd_etmv4_cfg structure:-
214 
215 ~~~{.c}
216  typedef struct _ocsd_etmv4_cfg
217  {
218  uint32_t reg_idr0; /**< ID0 register */
219  uint32_t reg_idr1; /**< ID1 register */
220  uint32_t reg_idr2; /**< ID2 register */
221  uint32_t reg_idr8;
222  uint32_t reg_idr9;
223  uint32_t reg_idr10;
224  uint32_t reg_idr11;
225  uint32_t reg_idr12;
226  uint32_t reg_idr13;
227  uint32_t reg_configr; /**< Config Register */
228  uint32_t reg_traceidr; /**< Trace Stream ID register */
229  ocsd_arch_version_t arch_ver; /**< Architecture version */
230  ocsd_core_profile_t core_prof; /**< Core Profile */
231  } ocsd_etmv4_cfg;
232 ~~~
233 
234 The structure contains a number of read-only ID registers, and key programmable control registers that define
235 the trace output features - such as if the ETM will output timestamps or cycle counts - and the CoreSight Trace ID.
236 
237 Once this structure is filled in then the decoder can be configured in the decode tree:-
238 
239 ~~~{.cpp}
240  ocsd_etmv4_cfg config;
241 
242  // ...
243  // code to fill in config from programmed registers and id registers
244  // ...
245 
246  EtmV4Config configObj(&config); // initialise decoder config class
247  std::string decoderName(OCSD_BUILTIN_DCD_ETMV4I); // use built in ETMv4 instruction decoder.
248  int decoderCreateFlags = OCSD_CREATE_FLG_FULL_DECODER; // decoder type to create - OCSD_CREATE_FLG_PACKET_PROC for packet processor only
249  ocsd_err_t err = pDecodeTree->createDecoder(decoderName, decoderCreateFlags,&configObj);
250 ~~~
251 
252 This code creates a full trace decoder for an ETMv4 source, which consists of a packet processor and packet decoder pair. The decoder is automatically associated with the
253 CoreSight Trace ID programmed into the register provided in the `config` structure.
254 
255 It is also possible to create a packet processor only decoder if the `OCSD_CREATE_FLG_PACKET_PROC` flag is
256 used instead. These packet only decoders can be used to create a dump of the raw trace as discrete trace packets.
257 
258 All decoders a registered with the library using a name - the standard ARM protocols are considered built in
259 decoders and are registered automatically. The library contains defined names for these decoders - `OCSD_BUILTIN_DCD_ETMV4I`
260  being the name used for ETMv4 protocol.
261 
262 The C-API uses the call create_generic_decoder() with the same configuration structure:-
263 
264 ~~~{.c}
265  ocsd_etmv4_cfg config;
266 
267  // ...
268  // code to fill in config from programmed registers and id registers
269  // ...
270 
271  const char * decoderName = OCSD_BUILTIN_DCD_ETMV4I); // use built in ETMv4 instruction decoder.
272  int decoderCreateFlags = OCSD_CREATE_FLG_FULL_DECODER; // decoder type to create - OCSD_CREATE_FLG_PACKET_PROC for packet processor only
273  void *p_context = // <some_client_context>
274  ocsd_err_t err = create_generic_decoder(dcdtree_handle,decoderName,(void *)&config,p_context);
275 ~~~
276 
277 The configuration must be completed for each trace source in the decode tree which requires decoding.
278 
279 The different trace source types have different configuration structures, classes and names
280 
281 | protocol | config struct | class | name define |
282 |:----------|:--------------------|:------------|:-----------------------------|
283 | __ETE__ | @ref ocsd_ete_cfg | ETEConfig | @ref OCSD_BUILTIN_DCD_ETE |
284 | __ETMv4__ | @ref ocsd_etmv4_cfg | EtmV4Config | @ref OCSD_BUILTIN_DCD_ETMV4I |
285 | __ETMv3__ | @ref ocsd_etmv3_cfg | EtmV3Config | @ref OCSD_BUILTIN_DCD_ETMV3 |
286 | __PTM__ | @ref ocsd_ptm_cfg | PtmConfig | @ref OCSD_BUILTIN_DCD_PTM |
287 | __STM__ | @ref ocsd_stm_cfg | STMConfig | @ref OCSD_BUILTIN_DCD_STM |
288 
289 ### Adding in Memory Images ###
290 
291 Memory images are needed when a full trace decode is required. Memory images consist of a base address and length, and
292 contain instruction opcodes that may be executed during the operation of the traced program. The images are used by
293 the decoder to follow the path of the traced program by interpreting the information contained within the trace that
294 defines which program branches are taken and the target addresses of those branches.
295 
296 The library defined memory image accessor objects, which can be simple memory buffers, files containing the binary
297 code image, or a callback that allows the client to handle memory accesses directly. When files are used, the
298  object may contain a set of base addresses and lengths, with offsets into the file - allowing the decoder
299  to directly access multiple code segments in executable image files.
300 
301 Memory image objects are collated by a memory mapper. This interfaces to the decoder through the ITargetMemAccess interface,
302 and selects the correct image object for the address requested by the decoder. The memory mapper will also validate image
303 objects as they are added to the decoder, and will not permit overlapping images.
304 
305 ![Memory Mapper and Memory Images](memacc_objs.jpg)
306 
307 The client can add memory images to the decoder via API calls to the decode tree. These methods add memory image accessors of various
308 types to be managed by a memory access mapper:-
309 
310 ~~~{.cpp}
311  class DecodeTree {
312  // ...
313  ocsd_err_t createMemAccMapper(memacc_mapper_t type = MEMACC_MAP_GLOBAL);
314  // ...
315  ocsd_err_t addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length);
316  ocsd_err_t addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath);
317  ocsd_err_t addBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath); */
318  ocsd_err_t addCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context);
319  // ...
320  }
321 ~~~
322 
323 The `createMemAccMapper()` function must be called to create the mapper, before the `add...MemAcc()` calls are used.
324 
325 It is further possible to differentiate between memory image access objects by the memory space for which they are valid. If it is known that a certain code image
326 is present in secure EL3, then an image can be associated with the @ref ocsd_mem_space_acc_t type value @ref OCSD_MEM_SPACE_EL3, which will allow another image to be
327 present at the same address but a different exception level. However, for the majority of systems, such detailed knowledge of the code is not available, or
328 overlaps across memory spaces do not occur. In these cases, and for general use (including Linux trace decode), @ref OCSD_MEM_SPACE_ANY should be used.
329 
330 The C-API contains a similar set of calls to set up memory access objects:-
331 
332 ~~~{.c}
333  OCSD_C_API ocsd_err_t ocsd_dt_add_buffer_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length);
334  OCSD_C_API ocsd_err_t ocsd_dt_add_binfile_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const char *filepath);
335  OCSD_C_API ocsd_err_t ocsd_dt_add_binfile_region_mem_acc(const dcd_tree_handle_t handle, const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const char *filepath);
336  OCSD_C_API ocsd_err_t ocsd_dt_add_callback_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context);
337 ~~~
338 
339 Note that the C-API will automatically create a default mapper when the first memory access object is added.
340 
341 ### Adding the output callbacks ###
342 
343 The decoded trace output ia collect by the client application through callback functions registered with the library.
344 
345 Depending on the decode configuration chosen, this can be in the form of the fully decoded trace output as generic trace
346 packets, or discrete trace packets for each trace stream ID.
347 
348 __Full Decode__
349 
350 When full decode is chosen then all output is via the generic packet interface:
351 
352 ~~~{.cpp}
353  class ITrcGenElemIn
354  {
355  ///...
356 
357  virtual ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop,
358  const uint8_t trc_chan_id,
359  const OcsdTraceElement &el);
360  }
361 ~~~
362 
363 The client application registers a callback class or function with this signature.
364 
365 For each output packet the libary calls the registered function, providing the byte index into the raw trace for the first
366 byte of the trace protocol packet that resulted in its generation, plus the CoreSight trace ID of the source stream,
367 #and the output packet itself.
368 
369 The client callback must process the packet before returning the call - the reference to the packet data is only
370 valid for the duration of the call. This means that the client will either have to copy and buffer packets for later
371 processing if required, process immediately, or use an appropriate combination, dependent on the requirements of the
372 client.
373 
374 The client callback provides a ocsd_datapath_resp_t response code to indicate to the input side of the library if decoding is to continue.
375 
376 ~~~{.cpp}
377  DecodeTree *pTree;
378  TrcGenericElementPrinter genElemPrinter; // derived from ITrcGenElemIn, overrides TraceElemIn() to print incoming packet to logger.
379 
380  ///...
381 
382  pTree->setGenTraceElemOutI(genElemPrinter);
383 
384 ~~~
385 
386 Alternatively in C-API, the callback function pointer type is defined:-
387 
388 ~~~{.c}
389  typedef ocsd_datapath_resp_t (* FnTraceElemIn)( const void *p_context,
390  const ocsd_trc_index_t index_sop,
391  const uint8_t trc_chan_id,
392  const ocsd_generic_trace_elem *elem);
393 ~~~
394 
395 giving API calls to set up:-
396 
397 ~~~{.c}
398  FnTraceElemIn gen_pkt_fn = &gen_trace_elem_analyze; // set to function matching signature.
399  dcd_tree_handle_t dcdtree_handle;
400 
401  // ...
402 
403  ret = ocsd_dt_set_gen_elem_outfn(dcdtree_handle, gen_pkt_fn, 0);
404 ~~~
405 
406 The output packets and their intepretatation are described here [prog_guide_generic_pkts.md](@ref generic_pkts).
407 
408 __Packet Process only, or Monitor packets in Full Decode__
409 
410 The client can set up the library for packet processing only, in which case the library output is
411 the trace packets only, so these packets need a sink callback for each channel being output.
412 
413 When full decode is in operation, then the principle output is the generic packets that are output for
414 all channels in operation to the single callback mentioned above. Additional callbacks can be added to
415 each of the trace channels to monitor the packet processing stage as it happens at point that the packets
416 are passed to the full decoder.
417 
418 Both methods of processing the discrete trace packets require callbacks to be registered on a
419 per Trace ID / channel basis. The specifics of the callback and the resulting packet will vary according to
420 the protocol of the trace source.
421 
422 The .cpp interface registers a packet sink / packet monitor object with the relevant decoder object.
423 
424 This sink object is based on the tempated IPktDataIn interface.
425 
426 ~~~{.cpp}
427 template<class P> class IPktDataIn : public ITrcTypedBase {
428  // ...
429  virtual ocsd_datapath_resp_t PacketDataIn( const ocsd_datapath_op_t op,
430  const ocsd_trc_index_t index_sop,
431  const P *p_packet_in) = 0;
432 }
433 ~~~
434 
435 The template type parameter will be the protocol type for the trace source in question - e.g. EtmV4ITrcPacket.
436 This interface contains a method that will be called with trace packets.
437 
438 The monitor object must be based on the IPktRawDataMon class, with a similarly typed template parameter and callback
439 function.
440 
441 ~~~{.cpp}
442 template<class P> class IPktRawDataMon : public ITrcTypedBase {
443  // ...
444  virtual void RawPacketDataMon( const ocsd_datapath_op_t op,
445  const ocsd_trc_index_t index_sop,
446  const P *pkt,
447  const uint32_t size,
448  const uint8_t *p_data) = 0;
449 }
450 ~~~
451 
452 Given a suitable callback object the process for attaching to the decode is as follows:-
453 
454 ~~~{.cpp}
455  // client custom packet sink for ETMv4 - derived from IPktDataIn
456  class MyTracePacketSinkETMv4 : public IPktDataIn<EtmV4ITrcPacket> {
457  // ...
458  };
459 
460  uint8_t CSID;
461  DecodeTree *pTree; // pointer to decode tree
462  MyTracePacketSinkETMv4 *pSink;
463 
464  // ... obtain CSID and decode tree object
465 
466  // decode trees manage decode elements using a tree element object, registered against CSID.
467  DecodeTreeElement *pElement = pTree->getDecoderElement(CSID);
468  pSink = new MyTracePacketSinkETMv4();
469  if (pElement && pSink)
470  err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), pSink);
471 
472 ~~~
473 
474 The decode tree object is used to obtain the decode tree element associated with the Coresight trace ID.
475 The IDecoderMngr interface on this object is used to attach the packet sink object to the required decoder.
476 
477 For monitor objects use an attachPktMonitor() call with a suitably derived monitor sink object.
478 
479 The key difference between the packet sink, and the packet monitor is that the monitor is not in the trace decode
480 data path, so does not return ocsd_datapath_resp_t values. The monitor callback also provides the raw trace byte
481 data for the packet.
482 
483 Device tree call for registering a callback in C-API and the function signatures for each type of shown below..
484 The C-API code contains underlying managment code that connects the callback with the correct packet decoder object.
485 
486 ~~~{.c}
487 OCSD_C_API ocsd_err_t ocsd_dt_attach_packet_callback( const dcd_tree_handle_t handle, // decode tree handle
488  const unsigned char CSID, // trace channel ID
489  const ocsd_c_api_cb_types callback_type, // defines packet only processing sink or monitor function signature.
490  void *p_fn_callback_data, // pointer to the callback function for the packet data.
491  const void *p_context); // opaque context to use inside the callback.
492 ~~~
493 
494 Callback definition for packet only sink callback type:
495 ~~~{.c}
496 /** function pointer type for packet processor packet output sink, packet analyser/decoder input - generic declaration */
497 typedef ocsd_datapath_resp_t (* FnDefPktDataIn)(const void *p_context,
498  const ocsd_datapath_op_t op,
499  const ocsd_trc_index_t index_sop,
500  const void *p_packet_in
501  );
502 ~~~
503 
504 Callback definition for packet monitor callback type
505 ~~~{.c}
506 /** function pointer type for packet processor packet monitor sink, raw packet monitor / display input - generic declaration */
507 typedef void (* FnDefPktDataMon)(const void *p_context,
508  const ocsd_datapath_op_t op,
509  const ocsd_trc_index_t index_sop,
510  const void *p_packet_in,
511  const uint32_t size,
512  const uint8_t *p_data
513  );
514 ~~~
515 
516 As with the `.cpp` code, the monitor callback does not have a return value, but also has the raw trace bytes for the packet as part of
517 the monitor.
518 
519 In both cases in the C-API, the `void *p_packet_in` must be cast to packet structure appropriate to the trace protocol associated with the
520 CSID value. e.g. for ETMv4 this would be @ref ocsd_etmv4_i_pkt.
521 
522 
523 Programming Examples - using the configured Decode Tree.
524 --------------------------------------------------------
525 
526 Once the decode tree has been configured then data raw trace data can be processed through the decode tree.
527 
528 The client program will require two functions to use the library. The first is on the input side of the library
529 which must be driven with raw data, until the data is complete, or an error occurs. This processing routine must
530 check the library returns and respond appropriately.
531 
532 The second consists of output callback(s) which process the decoded generic packets, or trace packets.
533 This routine will return response codes according to the needs of the client.
534 
535 ![Trace Data call and response path](decode_data_path_resp.jpg)
536 
537 The diagram shows the data input and response path. The data is driven into the decoding library by the client raw data input
538 routine on the left. Processed packets are received by the client packet callback(s) on the right, and push response codes back
539 through the library.
540 
541 The raw data input routine calls the standard ITrcDataIn interface with an operation code, and if appropriate some raw
542 trace data. The input operation code will define how the library treats the input parameters.
543 
544 
545 | Operation | Description | Trace Data provided |
546 |:-------------------|:-----------------------------------------------------------------|:--------------------|
547 | @ref OCSD_OP_DATA | Process data provided by data pointer parameters. | Yes |
548 | @ref OCSD_OP_FLUSH | Call after prior wait response - finish processing previous data | No |
549 | @ref OCSD_OP_EOT | End of trace data. Library will complete any pending decode. | No |
550 | @ref OCSD_OP_RESET | Hard reset of decoder state - use current config for new data | No |
551 
552 A set of standard responses is used to indicate to the raw data input whether it should continue to push data through the library,
553 pause and then flush, or if a fatal processing error has occurred.
554 
555 The response codes can come from the internal library decoder, or from the part of the client that is handling the processing of the
556 output packets on the right of the diagram.
557 
558 _Response Codes_: The are contained in the @ref _ocsd_datapath_resp_t enum.
559 
560 - __OCSD_RESP_CONT, OCSD_RESP_CONT_xxx__: Indicates that processing is to continue. Generated either internally by the library if more data
561  is needed to generate an output packet, or by the output packet processors to indicate processing
562  is to continue.
563 - __OCSD_RESP_WAIT, OCSD_RESP_WAIT_xxx:__ Sent by the client processors to pause processing. This will freeze the internal state of the library
564  and cause the WAIT response to be propogated through to the input side, with an indication of the number
565  of bytes processed. After a WAIT, the input side must respond with flush operations, until a CONT is
566  seen again and further data can then be input into the library.
567 - __OCSR_RESP_FATAL_xxx__: Fatal processing error. No further processing can take place. See error response logger for reason.
568  Normally the result of corrupt or incorrect trace data.
569 
570 The user should note that the client program controls routines on both the input and output side of the library. The output routine may be buffering
571 output packets, and when the buffer is full, returns a WAIT ressponse. This will be propgated through to the input routine. This should now terminate
572 data processing, saving state and the client will run a routine to empty / process the full packet buffer. Once the necessary processing is done,
573 then the input routine can be restarted, but __must__ follow the FLUSH operational rule described above.
574 
575 Excerpts from the data input routine used by the `trc_pkt_lister` program are shown below:
576 
577 ~~~{.cpp}
578  // process the current buffer load until buffer done, or fatal error occurs
579  while((nBuffProcessed < nBuffRead) && !OCSD_DATA_RESP_IS_FATAL(dataPathResp))
580  {
581  if(OCSD_DATA_RESP_IS_CONT(dataPathResp))
582  {
583  dataPathResp = dcd_tree->TraceDataIn(
584  OCSD_OP_DATA,
585  trace_index,
586  (uint32_t)(nBuffRead - nBuffProcessed),
587  &(trace_buffer[0])+nBuffProcessed,
588  &nUsedThisTime);
589 
590  nBuffProcessed += nUsedThisTime;
591  trace_index += nUsedThisTime;
592 
593  }
594  else // last response was _WAIT
595  {
596  // may need to acknowledge a wait from the gen elem printer
597  if(genElemPrinter->needAckWait())
598  genElemPrinter->ackWait();
599 
600  // dataPathResp not continue or fatal so must be wait...
601  dataPathResp = dcd_tree->TraceDataIn(OCSD_OP_FLUSH,0,0,0,0);
602  }
603  }
604 
605 ~~~
606 
607 _Note_: in this test program, the WAIT response is an artificial test condition, so the input routine does not terminate on seeing it - it is cleared down
608 and FLUSH is immediately sent. Normal client routines would most likely drop out of the processing loop, take actions to clear the WAIT condition, then
609 resume processing with a FLUSH.
610 
611 See the `trc_pkt_lister` and `c_api_pkt_print_test` test program source code for further examples of driving data through the library.