1 /*
2 * \file c_api_pkt_print_test.c
3 * \brief OpenCSD : C-API test program
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 /*
36 * Example of using the library with the C-API. Used to validate that the C-API
37 * functions work.
38 *
39 * Simple test program to print packets from a single trace ID source stream.
40 * Hard coded configuration based on the Juno r1-1 test snapshot for ETMv4 and
41 * STM, TC2 test snapshot for ETMv3, PTM.
42 *
43 * The test source can be set from the command line, but will default to the
44 * ETMv4 trace for trace ID 0x10 on the juno r1-1 test snapshot.
45 * This example uses the updated C-API functionality from library version 0.4.0 onwards.
46 * Test values are hardcoded from the same values in the snapshots as we do not
47 * explicitly read the snapshot metadata in this example program.
48 */
49
50 #include <stdio.h>
51 #include <string.h>
52 #include <stdint.h>
53 #include <stdlib.h>
54
55 /* include the C-API library header */
56 #include "opencsd/c_api/opencsd_c_api.h"
57
58 /* include the test external decoder factory and decoder types headers
59 - separate from the main library includes by definition as external decoder.
60 */
61 #include "ext_dcd_echo_test_fact.h"
62 #include "ext_dcd_echo_test.h"
63
64 /* path to test snapshots, relative to tests/bin/<plat>/<dbg|rel> build output dir */
65 #ifdef _WIN32
66 const char *default_base_snapshot_path="..\\..\\..\\snapshots";
67 const char *juno_snapshot = "\\juno_r1_1\\";
68 const char *tc2_snapshot = "\\TC2\\";
69 #else
70 const char *default_base_snapshot_path = "../../snapshots";
71 const char *juno_snapshot = "/juno_r1_1/";
72 const char *tc2_snapshot = "/TC2/";
73 #endif
74 static const char *selected_snapshot;
75 static const char *usr_snapshot_path = 0;
76 #define MAX_TRACE_FILE_PATH_LEN 512
77
78 /* trace data and memory file dump names and values - taken from snapshot metadata */
79 const char *trace_data_filename = "cstrace.bin";
80 const char *stmtrace_data_filename = "cstraceitm.bin";
81 const char *memory_dump_filename = "kernel_dump.bin";
82 ocsd_vaddr_t mem_dump_address=0xFFFFFFC000081000;
83 const ocsd_vaddr_t mem_dump_address_tc2=0xC0008000;
84
85 /* test variables - set by command line to feature test API */
86 static int using_mem_acc_cb = 0; /* test the memory access callback function */
87 static int use_region_file = 0; /* test multi region memory files */
88 static int using_mem_acc_cb_id = 0; /* test the mem acc callback with trace ID parameter */
89
90 /* buffer to handle a packet string */
91 #define PACKET_STR_LEN 1024
92 static char packet_str[PACKET_STR_LEN];
93
94 /* decide if we decode & monitor, decode only or packet print */
95 typedef enum _test_op {
96 TEST_PKT_PRINT, // process trace input into discrete packets and print.
97 TEST_PKT_DECODE, // process and decode trace packets, printing discrete packets and generic output.
98 TEST_PKT_DECODEONLY // process and decode trace packets, printing generic output packets only.
99 } test_op_t;
100
101 // Default test operations
102 static test_op_t op = TEST_PKT_PRINT; // default operation is to packet print
103 static ocsd_trace_protocol_t test_protocol = OCSD_PROTOCOL_ETMV4I; // ETMV4 protocl
104 static uint8_t test_trc_id_override = 0x00; // no trace ID override.
105
106 /* external decoder testing */
107 static int test_extern_decoder = 0; /* test the external decoder infrastructure. */
108 static ocsd_extern_dcd_fact_t *p_ext_fact; /* external decoder factory */
109 #define EXT_DCD_NAME "ext_echo"
110
111 /* raw packet printing test */
112 static int frame_raw_unpacked = 0;
113 static int frame_raw_packed = 0;
114 static int test_printstr = 0;
115
116 /* test the library printer API */
117 static int test_lib_printers = 0;
118
119 /* test the last error / error code api */
120 static int test_error_api = 0;
121
122 /* log statistics */
123 static int stats = 0;
124
125 /* Process command line options - choose the operation to use for the test. */
process_cmd_line(int argc,char * argv[])126 static int process_cmd_line(int argc, char *argv[])
127 {
128 int idx = 1;
129 int len = 0;
130
131 while(idx < argc)
132 {
133 if (strcmp(argv[idx], "-decode_only") == 0)
134 {
135 op = TEST_PKT_DECODEONLY;
136 }
137 else if (strcmp(argv[idx], "-decode") == 0)
138 {
139 op = TEST_PKT_DECODE;
140 }
141 else if (strcmp(argv[idx], "-id") == 0)
142 {
143 idx++;
144 if (idx < argc)
145 {
146 test_trc_id_override = (uint8_t)(strtoul(argv[idx], 0, 0));
147 printf("ID override = 0x%02X\n", test_trc_id_override);
148 }
149 }
150 else if (strcmp(argv[idx], "-etmv3") == 0)
151 {
152 test_protocol = OCSD_PROTOCOL_ETMV3;
153 selected_snapshot = tc2_snapshot;
154 mem_dump_address = mem_dump_address_tc2;
155 }
156 else if (strcmp(argv[idx], "-ptm") == 0)
157 {
158 test_protocol = OCSD_PROTOCOL_PTM;
159 selected_snapshot = tc2_snapshot;
160 mem_dump_address = mem_dump_address_tc2;
161 }
162 else if (strcmp(argv[idx], "-stm") == 0)
163 {
164 test_protocol = OCSD_PROTOCOL_STM;
165 trace_data_filename = stmtrace_data_filename;
166 }
167 else if (strcmp(argv[idx], "-test_cb") == 0)
168 {
169 using_mem_acc_cb = 1;
170 use_region_file = 0;
171 }
172 else if (strcmp(argv[idx], "-test_cb_id") == 0)
173 {
174 using_mem_acc_cb = 1;
175 use_region_file = 0;
176 using_mem_acc_cb_id = 1;
177 }
178 else if (strcmp(argv[idx], "-test_region_file") == 0)
179 {
180 use_region_file = 1;
181 using_mem_acc_cb = 0;
182 }
183 else if (strcmp(argv[idx], "-extern") == 0)
184 {
185 test_extern_decoder = 1;
186 }
187 else if (strcmp(argv[idx], "-raw") == 0)
188 {
189 frame_raw_unpacked = 1;
190 }
191 else if (strcmp(argv[idx], "-stats") == 0)
192 {
193 stats = 1;
194 }
195 else if (strcmp(argv[idx], "-raw_packed") == 0)
196 {
197 frame_raw_packed = 1;
198 }
199 else if (strcmp(argv[idx], "-test_printstr") == 0)
200 {
201 test_printstr = 1;
202 }
203 else if (strcmp(argv[idx], "-test_libprint") == 0)
204 {
205 test_lib_printers = 1;
206 }
207 else if (strcmp(argv[idx], "-ss_path") == 0)
208 {
209 idx++;
210 if ((idx >= argc) || (strlen(argv[idx]) == 0))
211 {
212 printf("-ss_path: Missing path parameter or zero length\n");
213 return -1;
214 }
215 else
216 {
217 len = strlen(argv[idx]);
218 if (len > (MAX_TRACE_FILE_PATH_LEN - 32))
219 {
220 printf("-ss_path: path too long\n");
221 return -1;
222 }
223 usr_snapshot_path = argv[idx];
224 }
225
226 }
227 else if (strcmp(argv[idx], "-test_err_api") == 0)
228 {
229 test_error_api = 1;
230 }
231 else if(strcmp(argv[idx],"-help") == 0)
232 {
233 return -1;
234 }
235 else
236 printf("Ignored unknown argument %s\n", argv[idx]);
237 idx++;
238 }
239 return 0;
240 }
241
print_cmd_line_help()242 static void print_cmd_line_help()
243 {
244 printf("Usage:\n-etmv3|-stm|-ptm|-extern : choose protocol (one only, default etmv4)\n");
245 printf("-id <ID> : decode source for id <ID> (default 0x10)\n");
246 printf("-decode | -decode_only : full decode + trace packets / full decode packets only (default trace packets only)\n");
247 printf("-raw / -raw_packed: print raw unpacked / packed data;\n");
248 printf("-test_printstr | -test_libprint : ttest lib printstr callback | test lib based packet printers\n");
249 printf("-test_region_file | -test_cb | -test_cb_id : mem accessor - test multi region file API | test callback API [with trcid] (default single memory file)\n\n");
250 printf("-ss_path <path> : path from cwd to /snapshots/ directory. Test prog will append required test subdir\n");
251 }
252
253 /************************************************************************/
254 /* Memory accessor functionality */
255 /************************************************************************/
256
257 static FILE *dump_file = NULL; /* pointer to the file providing the opcode memory */
258 static ocsd_mem_space_acc_t dump_file_mem_space = OCSD_MEM_SPACE_ANY; /* memory space used by the dump file */
259 static long mem_file_size = 0; /* size of the memory file */
260 static ocsd_vaddr_t mem_file_en_address = 0; /* end address last inclusive address in file. */
261
262 /* log the memacc output */
263 /* #define LOG_MEMACC_CB */
264
265 /* decode memory access using a CallBack function
266 * tests CB API and add / remove mem acc API.
267 */
do_mem_acc_cb(const void * p_context,const ocsd_vaddr_t address,const ocsd_mem_space_acc_t mem_space,const uint8_t trc_id,const uint32_t reqBytes,uint8_t * byteBuffer)268 static uint32_t do_mem_acc_cb(const void *p_context, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trc_id, const uint32_t reqBytes, uint8_t *byteBuffer)
269 {
270 uint32_t read_bytes = 0;
271 size_t file_read_bytes;
272
273 if(dump_file == NULL)
274 return 0;
275
276 /* bitwise & the incoming mem space and supported mem space to confirm coverage */
277 if(((uint8_t)mem_space & (uint8_t)dump_file_mem_space ) == 0)
278 return 0;
279
280 /* calculate the bytes that can be read */
281 if((address >= mem_dump_address) && (address <= mem_file_en_address))
282 {
283 /* some bytes in our range */
284 read_bytes = reqBytes;
285
286 if((address + reqBytes - 1) > mem_file_en_address)
287 {
288 /* more than are available - just read the available */
289 read_bytes = (uint32_t)(mem_file_en_address - (address - 1));
290 }
291 }
292
293 /* read some bytes if more than 0 to read. */
294 if(read_bytes != 0)
295 {
296 fseek(dump_file,(long)(address-mem_dump_address),SEEK_SET);
297 file_read_bytes = fread(byteBuffer,sizeof(uint8_t),read_bytes,dump_file);
298 if(file_read_bytes < read_bytes)
299 read_bytes = file_read_bytes;
300 }
301 #ifdef LOG_MEMACC_CB
302 sprintf(packet_str, "mem_acc_cb(addr 0x%08llX, size %d, trcID 0x%02X)\n", address, reqBytes, trc_id);
303 ocsd_def_errlog_msgout(packet_str);
304 #endif
305 return read_bytes;
306 }
307
mem_acc_cb(const void * p_context,const ocsd_vaddr_t address,const ocsd_mem_space_acc_t mem_space,const uint32_t reqBytes,uint8_t * byteBuffer)308 static uint32_t mem_acc_cb(const void *p_context, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer)
309 {
310 return do_mem_acc_cb(p_context, address, mem_space, 0xff, reqBytes, byteBuffer);
311 }
312
mem_acc_id_cb(const void * p_context,const ocsd_vaddr_t address,const ocsd_mem_space_acc_t mem_space,const uint8_t trc_id,const uint32_t reqBytes,uint8_t * byteBuffer)313 static uint32_t mem_acc_id_cb(const void *p_context, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trc_id, const uint32_t reqBytes, uint8_t *byteBuffer)
314 {
315 return do_mem_acc_cb(p_context, address, mem_space, trc_id, reqBytes, byteBuffer);
316 }
317
318
319 /* Create the memory accessor using the callback function and attach to decode tree */
create_mem_acc_cb(dcd_tree_handle_t dcd_tree_h,const char * mem_file_path)320 static ocsd_err_t create_mem_acc_cb(dcd_tree_handle_t dcd_tree_h, const char *mem_file_path)
321 {
322 ocsd_err_t err = OCSD_OK;
323 dump_file = fopen(mem_file_path,"rb");
324 if(dump_file != NULL)
325 {
326 fseek(dump_file,0,SEEK_END);
327 mem_file_size = ftell(dump_file);
328 mem_file_en_address = mem_dump_address + mem_file_size - 1;
329
330 if (using_mem_acc_cb_id)
331 err = ocsd_dt_add_callback_trcid_mem_acc(dcd_tree_h, mem_dump_address,
332 mem_file_en_address, dump_file_mem_space, &mem_acc_id_cb, 0);
333 else
334 err = ocsd_dt_add_callback_mem_acc(dcd_tree_h, mem_dump_address,
335 mem_file_en_address, dump_file_mem_space, &mem_acc_cb, 0);
336 if(err != OCSD_OK)
337 {
338 fclose(dump_file);
339 dump_file = NULL;
340 }
341 }
342 else
343 err = OCSD_ERR_MEM_ACC_FILE_NOT_FOUND;
344 return err;
345 }
346
347 /* remove the callback memory accessor from decode tree */
destroy_mem_acc_cb(dcd_tree_handle_t dcd_tree_h)348 static void destroy_mem_acc_cb(dcd_tree_handle_t dcd_tree_h)
349 {
350 if(dump_file != NULL)
351 {
352 ocsd_dt_remove_mem_acc(dcd_tree_h,mem_dump_address,dump_file_mem_space);
353 fclose(dump_file);
354 dump_file = NULL;
355 }
356 }
357
358 /* create and attach the memory accessor according to required test parameters */
create_test_memory_acc(dcd_tree_handle_t handle)359 static ocsd_err_t create_test_memory_acc(dcd_tree_handle_t handle)
360 {
361 ocsd_err_t ret = OCSD_OK;
362 char mem_file_path[MAX_TRACE_FILE_PATH_LEN];
363 uint32_t i0adjust = 0x100;
364 int i = 0;
365
366 /* region list to test multi region memory file API */
367 ocsd_file_mem_region_t region_list[4];
368
369 /* path to the file containing the memory image traced - raw binary data in the snapshot */
370 if(usr_snapshot_path != 0)
371 strcpy(mem_file_path,usr_snapshot_path);
372 else
373 strcpy(mem_file_path,default_base_snapshot_path);
374 strcat(mem_file_path,selected_snapshot);
375 strcat(mem_file_path,memory_dump_filename);
376
377 /*
378 * decide how to handle the file - test the normal memory accessor (contiguous binary file),
379 * a callback accessor or a multi-region file (e.g. similar to using the code region in a .so)
380 *
381 * The same memory dump file is used in each case, we just present it differently
382 * to test the API functions.
383 */
384
385 /* memory access callback */
386 if(using_mem_acc_cb)
387 {
388 ret = create_mem_acc_cb(handle,mem_file_path);
389 }
390 /* multi region file */
391 else if(use_region_file)
392 {
393
394 dump_file = fopen(mem_file_path,"rb");
395 if(dump_file != NULL)
396 {
397 fseek(dump_file,0,SEEK_END);
398 mem_file_size = ftell(dump_file);
399 fclose(dump_file);
400
401 /* populate the region list - split existing file into four regions */
402 for(i = 0; i < 4; i++)
403 {
404 if(i != 0)
405 i0adjust = 0;
406 region_list[i].start_address = mem_dump_address + (i * mem_file_size/4) + i0adjust;
407 region_list[i].region_size = (mem_file_size/4) - i0adjust;
408 region_list[i].file_offset = (i * mem_file_size/4) + i0adjust;
409 }
410
411 /* create a memory file accessor - full binary file */
412 ret = ocsd_dt_add_binfile_region_mem_acc(handle,®ion_list[0],4,OCSD_MEM_SPACE_ANY,mem_file_path);
413 }
414 else
415 ret = OCSD_ERR_MEM_ACC_FILE_NOT_FOUND;
416 }
417 /* create a memory file accessor - simple contiguous full binary file */
418 else
419 {
420 ret = ocsd_dt_add_binfile_mem_acc(handle,mem_dump_address,OCSD_MEM_SPACE_ANY,mem_file_path);
421 }
422 return ret;
423 }
424
425 /************************************************************************/
426 /** Packet printers */
427 /************************************************************************/
428
429 /*
430 * Callback function to process the packets in the packet processor output stream -
431 * simply print them out in this case to the library message/error logger.
432 */
packet_handler(void * context,const ocsd_datapath_op_t op,const ocsd_trc_index_t index_sop,const void * p_packet_in)433 ocsd_datapath_resp_t packet_handler(void *context, const ocsd_datapath_op_t op, const ocsd_trc_index_t index_sop, const void *p_packet_in)
434 {
435 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
436 int offset = 0;
437
438 switch(op)
439 {
440 case OCSD_OP_DATA:
441 sprintf(packet_str,"Idx:%" OCSD_TRC_IDX_STR "; ", index_sop);
442 offset = strlen(packet_str);
443
444 /*
445 * got a packet - convert to string and use the libraries' message output to print to file and stdoout
446 * Since the test always prints a single ID, we know the protocol type.
447 */
448 if(ocsd_pkt_str(test_protocol,p_packet_in,packet_str+offset,PACKET_STR_LEN-offset) == OCSD_OK)
449 {
450 /* add in <CR> */
451 if(strlen(packet_str) == PACKET_STR_LEN - 1) /* maximum length */
452 packet_str[PACKET_STR_LEN-2] = '\n';
453 else
454 strcat(packet_str,"\n");
455
456 /* print it using the library output logger. */
457 ocsd_def_errlog_msgout(packet_str);
458 }
459 else
460 resp = OCSD_RESP_FATAL_INVALID_PARAM; /* mark fatal error */
461 break;
462
463 case OCSD_OP_EOT:
464 sprintf(packet_str,"**** END OF TRACE ****\n");
465 ocsd_def_errlog_msgout(packet_str);
466 break;
467
468 default: break;
469 }
470
471 return resp;
472 }
473
474 /* print an array of hex data - used by the packet monitor to print hex data from packet.*/
print_data_array(const uint8_t * p_array,const int array_size,char * p_buffer,int buf_size)475 static int print_data_array(const uint8_t *p_array, const int array_size, char *p_buffer, int buf_size)
476 {
477 int chars_printed = 0;
478 int bytes_processed;
479 p_buffer[0] = 0;
480
481 if(buf_size > 9)
482 {
483 /* set up the header */
484 strcat(p_buffer,"[ ");
485 chars_printed+=2;
486
487 for(bytes_processed = 0; bytes_processed < array_size; bytes_processed++)
488 {
489 sprintf(p_buffer+chars_printed,"0x%02X ", p_array[bytes_processed]);
490 chars_printed += 5;
491 if((chars_printed + 5) > buf_size)
492 break;
493 }
494
495 strcat(p_buffer,"];");
496 chars_printed+=2;
497 }
498 else if(buf_size >= 4)
499 {
500 sprintf(p_buffer,"[];");
501 chars_printed+=3;
502 }
503 return chars_printed;
504 }
505
506 /*
507 * Callback function to process packets and packet data from the monitor output of the
508 * packet processor. Again print them to the library error logger.
509 */
packet_monitor(void * context,const ocsd_datapath_op_t op,const ocsd_trc_index_t index_sop,const void * p_packet_in,const uint32_t size,const uint8_t * p_data)510 void packet_monitor( void *context,
511 const ocsd_datapath_op_t op,
512 const ocsd_trc_index_t index_sop,
513 const void *p_packet_in,
514 const uint32_t size,
515 const uint8_t *p_data)
516 {
517 int offset = 0;
518
519 switch(op)
520 {
521 default: break;
522 case OCSD_OP_DATA:
523 sprintf(packet_str,"Idx:%" OCSD_TRC_IDX_STR ";", index_sop);
524 offset = strlen(packet_str);
525 offset+= print_data_array(p_data,size,packet_str+offset,PACKET_STR_LEN-offset);
526
527 /* got a packet - convert to string and use the libraries' message output to print to file and stdoout */
528 if(ocsd_pkt_str(test_protocol,p_packet_in,packet_str+offset,PACKET_STR_LEN-offset) == OCSD_OK)
529 {
530 /* add in <CR> */
531 if(strlen(packet_str) == PACKET_STR_LEN - 1) /* maximum length */
532 packet_str[PACKET_STR_LEN-2] = '\n';
533 else
534 strcat(packet_str,"\n");
535
536 /* print it using the library output logger. */
537 ocsd_def_errlog_msgout(packet_str);
538 }
539 break;
540
541 case OCSD_OP_EOT:
542 sprintf(packet_str,"**** END OF TRACE ****\n");
543 ocsd_def_errlog_msgout(packet_str);
544 break;
545 }
546 }
547
548
549 /*
550 * printer for the generic trace elements when decoder output is being processed
551 */
gen_trace_elem_print(const void * p_context,const ocsd_trc_index_t index_sop,const uint8_t trc_chan_id,const ocsd_generic_trace_elem * elem)552 ocsd_datapath_resp_t gen_trace_elem_print(const void *p_context, const ocsd_trc_index_t index_sop, const uint8_t trc_chan_id, const ocsd_generic_trace_elem *elem)
553 {
554 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
555 int offset = 0;
556
557 sprintf(packet_str,"Idx:%" OCSD_TRC_IDX_STR "; TrcID:0x%02X; ", index_sop, trc_chan_id);
558 offset = strlen(packet_str);
559
560 if(ocsd_gen_elem_str(elem, packet_str+offset,PACKET_STR_LEN - offset) == OCSD_OK)
561 {
562 /* add in <CR> */
563 if(strlen(packet_str) == PACKET_STR_LEN - 1) /* maximum length */
564 packet_str[PACKET_STR_LEN-2] = '\n';
565 else
566 strcat(packet_str,"\n");
567 }
568 else
569 {
570 strcat(packet_str,"Unable to create element string\n");
571 }
572
573 /* print it using the library output logger. */
574 ocsd_def_errlog_msgout(packet_str);
575
576 return resp;
577 }
578
579 /************************************************************************/
580 /** decoder creation **/
581
582 /*** generic ***/
create_generic_decoder(dcd_tree_handle_t handle,const char * p_name,const void * p_cfg,const void * p_context)583 static ocsd_err_t create_generic_decoder(dcd_tree_handle_t handle, const char *p_name, const void *p_cfg, const void *p_context)
584 {
585 ocsd_err_t ret = OCSD_OK;
586 uint8_t CSID = 0;
587
588 if(op == TEST_PKT_PRINT) /* test operation set to packet printing only */
589 {
590 /*
591 * Create a packet processor on the decode tree for the configuration we have.
592 * We need to supply the configuration
593 */
594 ret = ocsd_dt_create_decoder(handle,p_name,OCSD_CREATE_FLG_PACKET_PROC,p_cfg,&CSID);
595 if(ret == OCSD_OK)
596 {
597 /* Attach the packet handler to the output of the packet processor - referenced by CSID */
598 if (test_lib_printers)
599 ret = ocsd_dt_set_pkt_protocol_printer(handle, CSID, 0);
600 else
601 ret = ocsd_dt_attach_packet_callback(handle,CSID, OCSD_C_API_CB_PKT_SINK,&packet_handler,p_context);
602 if(ret != OCSD_OK)
603 ocsd_dt_remove_decoder(handle,CSID); /* if the attach failed then destroy the decoder. */
604 }
605 }
606 else
607 {
608 /* Full decode - need decoder, and memory dump */
609
610 /* create the packet decoder and packet processor pair from the supplied name */
611 ret = ocsd_dt_create_decoder(handle,p_name,OCSD_CREATE_FLG_FULL_DECODER,p_cfg,&CSID);
612 if(ret == OCSD_OK)
613 {
614 if((op != TEST_PKT_DECODEONLY) && (ret == OCSD_OK))
615 {
616 /*
617 * print the packets as well as the decode - use the packet processors monitor
618 * output this time, as the main output is attached to the packet decoder.
619 */
620 if (test_lib_printers)
621 ret = ocsd_dt_set_pkt_protocol_printer(handle, CSID, 1);
622 else
623 ret = ocsd_dt_attach_packet_callback(handle,CSID,OCSD_C_API_CB_PKT_MON,packet_monitor,p_context);
624 }
625
626 /* attach a memory accessor */
627 if(ret == OCSD_OK)
628 ret = create_test_memory_acc(handle);
629
630 /* if the attach failed then destroy the decoder. */
631 if(ret != OCSD_OK)
632 ocsd_dt_remove_decoder(handle,CSID);
633 }
634 }
635 return ret;
636 }
637
638 /*** ETMV4 specific settings ***/
create_decoder_etmv4(dcd_tree_handle_t dcd_tree_h)639 static ocsd_err_t create_decoder_etmv4(dcd_tree_handle_t dcd_tree_h)
640 {
641 ocsd_etmv4_cfg trace_config;
642
643 /*
644 * populate the ETMv4 configuration structure with
645 * hard coded values from snapshot .ini files.
646 */
647
648 trace_config.arch_ver = ARCH_V8;
649 trace_config.core_prof = profile_CortexA;
650
651 trace_config.reg_configr = 0x000000C1;
652 trace_config.reg_traceidr = 0x00000010; /* this is the trace ID -> 0x10, change this to analyse other streams in snapshot.*/
653
654 if(test_trc_id_override != 0)
655 {
656 trace_config.reg_traceidr = (uint32_t)test_trc_id_override;
657 }
658 test_trc_id_override = trace_config.reg_traceidr; /* remember what ID we actually used */
659
660 trace_config.reg_idr0 = 0x28000EA1;
661 trace_config.reg_idr1 = 0x4100F403;
662 trace_config.reg_idr2 = 0x00000488;
663 trace_config.reg_idr8 = 0x0;
664 trace_config.reg_idr9 = 0x0;
665 trace_config.reg_idr10 = 0x0;
666 trace_config.reg_idr11 = 0x0;
667 trace_config.reg_idr12 = 0x0;
668 trace_config.reg_idr13 = 0x0;
669
670 /* create an ETMV4 decoder - no context needed as we have a single stream to a single handler. */
671 return create_generic_decoder(dcd_tree_h,OCSD_BUILTIN_DCD_ETMV4I,(void *)&trace_config,0);
672 }
673
674 /*** ETMV3 specific settings ***/
create_decoder_etmv3(dcd_tree_handle_t dcd_tree_h)675 static ocsd_err_t create_decoder_etmv3(dcd_tree_handle_t dcd_tree_h)
676 {
677 ocsd_etmv3_cfg trace_config_etmv3;
678
679 /*
680 * populate the ETMv3 configuration structure with
681 * hard coded values from snapshot .ini files.
682 */
683
684 trace_config_etmv3.arch_ver = ARCH_V7;
685 trace_config_etmv3.core_prof = profile_CortexA;
686 trace_config_etmv3.reg_ccer = 0x344008F2;
687 trace_config_etmv3.reg_ctrl = 0x10001860;
688 trace_config_etmv3.reg_idr = 0x410CF250;
689 trace_config_etmv3.reg_trc_id = 0x010;
690 if(test_trc_id_override != 0)
691 {
692 trace_config_etmv3.reg_trc_id = (uint32_t)test_trc_id_override;
693 }
694 test_trc_id_override = trace_config_etmv3.reg_trc_id; /* remember what ID we actually used */
695
696 /* create an ETMV3 decoder - no context needed as we have a single stream to a single handler. */
697 return create_generic_decoder(dcd_tree_h,OCSD_BUILTIN_DCD_ETMV3,(void *)&trace_config_etmv3,0);
698 }
699
700 /*** PTM specific settings ***/
create_decoder_ptm(dcd_tree_handle_t dcd_tree_h)701 static ocsd_err_t create_decoder_ptm(dcd_tree_handle_t dcd_tree_h)
702 {
703 ocsd_ptm_cfg trace_config_ptm;
704
705 /*
706 * populate the PTM configuration structure with
707 * hard coded values from snapshot .ini files.
708 */
709
710 trace_config_ptm.arch_ver = ARCH_V7;
711 trace_config_ptm.core_prof = profile_CortexA;
712 trace_config_ptm.reg_ccer = 0x34C01AC2;
713 trace_config_ptm.reg_ctrl = 0x10001000;
714 trace_config_ptm.reg_idr = 0x411CF312;
715 trace_config_ptm.reg_trc_id = 0x013;
716 if(test_trc_id_override != 0)
717 {
718 trace_config_ptm.reg_trc_id = (uint32_t)test_trc_id_override;
719 }
720 test_trc_id_override = trace_config_ptm.reg_trc_id; /* remember what ID we actually used */
721
722 /* create an PTM decoder - no context needed as we have a single stream to a single handler. */
723 return create_generic_decoder(dcd_tree_h,OCSD_BUILTIN_DCD_PTM,(void *)&trace_config_ptm,0);
724
725 }
726
727 /*** STM specific settings ***/
create_decoder_stm(dcd_tree_handle_t dcd_tree_h)728 static ocsd_err_t create_decoder_stm(dcd_tree_handle_t dcd_tree_h)
729 {
730 ocsd_stm_cfg trace_config_stm;
731
732 /*
733 * populate the STM configuration structure with
734 * hard coded values from snapshot .ini files.
735 */
736 #define STMTCSR_TRC_ID_MASK 0x007F0000
737 #define STMTCSR_TRC_ID_SHIFT 16
738
739 trace_config_stm.reg_tcsr = 0x00A00005;
740 if(test_trc_id_override != 0)
741 {
742 trace_config_stm.reg_tcsr &= ~STMTCSR_TRC_ID_MASK;
743 trace_config_stm.reg_tcsr |= ((((uint32_t)test_trc_id_override) << STMTCSR_TRC_ID_SHIFT) & STMTCSR_TRC_ID_MASK);
744 }
745 trace_config_stm.reg_feat3r = 0x10000; /* channel default */
746 trace_config_stm.reg_devid = 0xFF; /* master default */
747
748 /* not using hw event trace decode */
749 trace_config_stm.reg_hwev_mast = 0;
750 trace_config_stm.reg_feat1r = 0;
751 trace_config_stm.hw_event = HwEvent_Unknown_Disabled;
752
753 /* create a STM decoder - no context needed as we have a single stream to a single handler. */
754 return create_generic_decoder(dcd_tree_h, OCSD_BUILTIN_DCD_STM, (void *)&trace_config_stm, 0);
755 }
756
create_decoder_extern(dcd_tree_handle_t dcd_tree_h)757 static ocsd_err_t create_decoder_extern(dcd_tree_handle_t dcd_tree_h)
758 {
759 echo_dcd_cfg_t trace_cfg_ext;
760
761 /* setup the custom configuration */
762 trace_cfg_ext.cs_id = 0x010;
763 if (test_trc_id_override != 0)
764 {
765 trace_cfg_ext.cs_id = (uint32_t)test_trc_id_override;
766 }
767 test_trc_id_override = trace_cfg_ext.cs_id;
768
769 /* create an external decoder - no context needed as we have a single stream to a single handler. */
770 return create_generic_decoder(dcd_tree_h, EXT_DCD_NAME, (void *)&trace_cfg_ext, 0);
771 }
772
attach_raw_printers(dcd_tree_handle_t dcd_tree_h)773 static ocsd_err_t attach_raw_printers(dcd_tree_handle_t dcd_tree_h)
774 {
775 ocsd_err_t err = OCSD_OK;
776 int flags = 0;
777 if (frame_raw_unpacked)
778 flags |= OCSD_DFRMTR_UNPACKED_RAW_OUT;
779 if (frame_raw_packed)
780 flags |= OCSD_DFRMTR_PACKED_RAW_OUT;
781 if (flags)
782 {
783 err = ocsd_dt_set_raw_frame_printer(dcd_tree_h, flags);
784 }
785 return err;
786 }
787
print_output_str(const void * p_context,const char * psz_msg_str,const int str_len)788 static void print_output_str(const void *p_context, const char *psz_msg_str, const int str_len)
789 {
790 printf("** CUST_PRNTSTR: %s", psz_msg_str);
791 }
792
test_printstr_cb(dcd_tree_handle_t dcd_tree_h)793 static ocsd_err_t test_printstr_cb(dcd_tree_handle_t dcd_tree_h)
794 {
795 ocsd_err_t err = OCSD_OK;
796 if (test_printstr)
797 err = ocsd_def_errlog_set_strprint_cb(dcd_tree_h, 0, print_output_str);
798 return err;
799 }
800 /************************************************************************/
801
register_extern_decoder()802 ocsd_err_t register_extern_decoder()
803 {
804 ocsd_err_t err = OCSD_ERR_NO_PROTOCOL;
805
806 p_ext_fact = ext_echo_get_dcd_fact();
807 if (p_ext_fact)
808 {
809 err = ocsd_register_custom_decoder(EXT_DCD_NAME, p_ext_fact);
810 if (err == OCSD_OK)
811 test_protocol = p_ext_fact->protocol_id;
812 else
813 printf("External Decoder Registration: Failed to register decoder.");
814 }
815 else
816 printf("External Decoder Registration: Failed to get decoder factory.");
817
818 return err;
819 }
820
821 /* create a decoder according to options */
create_decoder(dcd_tree_handle_t dcd_tree_h)822 static ocsd_err_t create_decoder(dcd_tree_handle_t dcd_tree_h)
823 {
824 ocsd_err_t err = OCSD_OK;
825
826 /* extended for the external decoder testing*/
827 if (test_extern_decoder)
828 err = register_extern_decoder();
829 if (err != OCSD_OK)
830 return err;
831
832 switch(test_protocol)
833 {
834 case OCSD_PROTOCOL_ETMV4I:
835 err = create_decoder_etmv4(dcd_tree_h);
836 break;
837
838 case OCSD_PROTOCOL_ETMV3:
839 err = create_decoder_etmv3(dcd_tree_h);
840 break;
841
842 case OCSD_PROTOCOL_STM:
843 err = create_decoder_stm(dcd_tree_h);
844 break;
845
846 case OCSD_PROTOCOL_PTM:
847 err = create_decoder_ptm(dcd_tree_h);
848 break;
849
850 /* we only register a single external decoder in this test,
851 so it will always be assigned the first custom protocol ID */
852 case OCSD_PROTOCOL_CUSTOM_0:
853 err = create_decoder_extern(dcd_tree_h);
854 break;
855
856 default:
857 err = OCSD_ERR_NO_PROTOCOL;
858 break;
859 }
860 return err;
861 }
862
863 #define INPUT_BLOCK_SIZE 1024
864
865 /* process buffer until done or error */
process_data_block(dcd_tree_handle_t dcd_tree_h,int block_index,uint8_t * p_block,const int block_size)866 ocsd_err_t process_data_block(dcd_tree_handle_t dcd_tree_h, int block_index, uint8_t *p_block, const int block_size)
867 {
868 ocsd_err_t ret = OCSD_OK;
869 uint32_t bytes_done = 0;
870 ocsd_datapath_resp_t dp_ret = OCSD_RESP_CONT;
871 uint32_t bytes_this_time = 0;
872
873 while((bytes_done < (uint32_t)block_size) && (ret == OCSD_OK))
874 {
875 if(OCSD_DATA_RESP_IS_CONT(dp_ret))
876 {
877 dp_ret = ocsd_dt_process_data(dcd_tree_h,
878 OCSD_OP_DATA,
879 block_index+bytes_done,
880 block_size-bytes_done,
881 ((uint8_t *)p_block)+bytes_done,
882 &bytes_this_time);
883 bytes_done += bytes_this_time;
884 }
885 else if(OCSD_DATA_RESP_IS_WAIT(dp_ret))
886 {
887 dp_ret = ocsd_dt_process_data(dcd_tree_h, OCSD_OP_FLUSH,0,0,NULL,NULL);
888 }
889 else
890 ret = OCSD_ERR_DATA_DECODE_FATAL; /* data path responded with an error - stop processing */
891 }
892 return ret;
893 }
894
print_statistics(dcd_tree_handle_t dcdtree_handle)895 void print_statistics(dcd_tree_handle_t dcdtree_handle)
896 {
897 ocsd_decode_stats_t *p_stats = 0;
898 ocsd_err_t err;
899
900 sprintf(packet_str, "\nReading packet decoder statistics for ID:0x%02x...\n", test_trc_id_override);
901 ocsd_def_errlog_msgout(packet_str);
902
903 err = ocsd_dt_get_decode_stats(dcdtree_handle, test_trc_id_override, &p_stats);
904 if (!err && p_stats)
905 {
906 sprintf(packet_str, "Total Bytes %ld; Unsynced Bytes: %ld\nBad Header Errors: %d; Bad sequence errors: %d\n", (long)p_stats->channel_total,
907 (long)p_stats->channel_unsynced, p_stats->bad_header_errs, p_stats->bad_sequence_errs);
908 ocsd_dt_reset_decode_stats(dcdtree_handle, test_trc_id_override);
909 }
910 else
911 {
912 sprintf(packet_str, "Not available for this ID.\n");
913 }
914 ocsd_def_errlog_msgout(packet_str);
915 }
916
process_trace_data(FILE * pf)917 int process_trace_data(FILE *pf)
918 {
919 ocsd_err_t ret = OCSD_OK;
920 dcd_tree_handle_t dcdtree_handle = C_API_INVALID_TREE_HANDLE;
921 uint8_t data_buffer[INPUT_BLOCK_SIZE];
922 ocsd_trc_index_t index = 0;
923 size_t data_read;
924
925
926 /* Create a decode tree for this source data.
927 source data is frame formatted, memory aligned from an ETR (no frame syncs) so create tree accordingly
928 */
929 dcdtree_handle = ocsd_create_dcd_tree(OCSD_TRC_SRC_FRAME_FORMATTED, OCSD_DFRMTR_FRAME_MEM_ALIGN);
930
931 if(dcdtree_handle != C_API_INVALID_TREE_HANDLE)
932 {
933
934 ret = create_decoder(dcdtree_handle);
935 ocsd_tl_log_mapped_mem_ranges(dcdtree_handle);
936
937 if (ret == OCSD_OK)
938 {
939 /* attach the generic trace element output callback */
940 if (test_lib_printers)
941 ret = ocsd_dt_set_gen_elem_printer(dcdtree_handle);
942 else
943 ret = ocsd_dt_set_gen_elem_outfn(dcdtree_handle, gen_trace_elem_print, 0);
944 }
945
946
947 /* raw print and str print cb options tested in their init functions */
948 if (ret == OCSD_OK)
949 ret = test_printstr_cb(dcdtree_handle);
950
951 if (ret == OCSD_OK)
952 ret = attach_raw_printers(dcdtree_handle);
953
954
955 /* now push the trace data through the packet processor */
956 while(!feof(pf) && (ret == OCSD_OK))
957 {
958 /* read from file */
959 data_read = fread(data_buffer,1,INPUT_BLOCK_SIZE,pf);
960 if(data_read > 0)
961 {
962 /* process a block of data - any packets from the trace stream
963 we have configured will appear at the callback
964 */
965 ret = process_data_block(dcdtree_handle,
966 index,
967 data_buffer,
968 data_read);
969 index += data_read;
970 }
971 else if(ferror(pf))
972 ret = OCSD_ERR_FILE_ERROR;
973 }
974
975 /* no errors - let the data path know we are at end of trace */
976 if(ret == OCSD_OK)
977 ocsd_dt_process_data(dcdtree_handle, OCSD_OP_EOT, 0,0,NULL,NULL);
978
979 if (stats) {
980 print_statistics(dcdtree_handle);
981 }
982 /* shut down the mem acc CB if in use. */
983 if(using_mem_acc_cb)
984 {
985 destroy_mem_acc_cb(dcdtree_handle);
986 }
987
988 /* dispose of the decode tree - which will dispose of any packet processors we created
989 */
990 ocsd_destroy_dcd_tree(dcdtree_handle);
991 }
992 else
993 {
994 printf("Failed to create trace decode tree\n");
995 ret = OCSD_ERR_NOT_INIT;
996 }
997 return (int)ret;
998 }
999
1000 #define ERR_BUFFER_SIZE 256
test_err_api()1001 int test_err_api()
1002 {
1003 dcd_tree_handle_t dcdtree_handle = C_API_INVALID_TREE_HANDLE;
1004 ocsd_err_t ret = OCSD_OK, err_test;
1005 ocsd_trc_index_t index = 0, err_index = 0;
1006 uint8_t cs_id;
1007 char err_buffer[ERR_BUFFER_SIZE];
1008
1009 /* Create a decode tree for this source data.
1010 source data is frame formatted, memory aligned from an ETR (no frame syncs) so create tree accordingly
1011 */
1012 dcdtree_handle = ocsd_create_dcd_tree(OCSD_TRC_SRC_SINGLE, OCSD_DFRMTR_FRAME_MEM_ALIGN);
1013
1014 if (dcdtree_handle != C_API_INVALID_TREE_HANDLE)
1015 {
1016
1017 ret = create_decoder(dcdtree_handle);
1018 if (ret == OCSD_OK)
1019 {
1020 /* attach the generic trace element output callback */
1021 if (test_lib_printers)
1022 ret = ocsd_dt_set_gen_elem_printer(dcdtree_handle);
1023 else
1024 ret = ocsd_dt_set_gen_elem_outfn(dcdtree_handle, gen_trace_elem_print, 0);
1025 }
1026
1027
1028 /* raw print and str print cb options tested in their init functions */
1029 if (ret == OCSD_OK)
1030 ret = test_printstr_cb(dcdtree_handle);
1031
1032 if (ret == OCSD_OK)
1033 ret = attach_raw_printers(dcdtree_handle);
1034
1035 /* feed some duff data into a decoder to provoke an error! */
1036 uint8_t trace_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1037 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x60, 0x71 };
1038
1039 if (ret == OCSD_OK)
1040 ret = process_data_block(dcdtree_handle, index, trace_data, sizeof(trace_data));
1041
1042 ocsd_err_str(ret, err_buffer, ERR_BUFFER_SIZE);
1043 printf("testing error API for code %d: %s\n", ret, err_buffer);
1044 err_test = ocsd_get_last_err(&err_index, &cs_id, err_buffer, ERR_BUFFER_SIZE);
1045 printf("get last error:\ncode = 0x%02x; trace index %d; cs_id 0x%02x;\nstring: %s\n", err_test, err_index, cs_id, err_buffer);
1046
1047 }
1048 return ret;
1049 }
1050
main(int argc,char * argv[])1051 int main(int argc, char *argv[])
1052 {
1053 FILE *trace_data;
1054 char trace_file_path[MAX_TRACE_FILE_PATH_LEN];
1055 int ret = 0, i, len;
1056 char message[512];
1057
1058 /* default to juno */
1059 selected_snapshot = juno_snapshot;
1060
1061 /* command line params */
1062 if(process_cmd_line(argc,argv) != 0)
1063 {
1064 print_cmd_line_help();
1065 return -2;
1066 }
1067
1068 /* trace data file path */
1069 if(usr_snapshot_path != 0)
1070 strcpy(trace_file_path,usr_snapshot_path);
1071 else
1072 strcpy(trace_file_path,default_base_snapshot_path);
1073 strcat(trace_file_path,selected_snapshot);
1074 strcat(trace_file_path,trace_data_filename);
1075 printf("opening %s trace data file\n",trace_file_path);
1076 trace_data = fopen(trace_file_path,"rb");
1077
1078 if(trace_data != NULL)
1079 {
1080 /* set up the logging in the library - enable the error logger, with an output printer*/
1081 ret = ocsd_def_errlog_init(OCSD_ERR_SEV_INFO,1);
1082
1083 /* set up the output - to file and stdout, set custom logfile name */
1084 if(ret == 0)
1085 ret = ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_FILE | C_API_MSGLOGOUT_FLG_STDOUT, "c_api_test.log");
1086
1087 /* print sign-on message in log */
1088 sprintf(message, "C-API packet print test\nLibrary Version %s\n\n",ocsd_get_version_str());
1089 ocsd_def_errlog_msgout(message);
1090
1091 /* print command line used */
1092 message[0] = 0;
1093 len = 0;
1094 for (i = 0; i < argc; i++)
1095 {
1096 len += strlen(argv[i]) + 1;
1097 if (len < 512)
1098 {
1099 strcat(message, argv[i]);
1100 strcat(message, " ");
1101 }
1102 }
1103 if((len + 2) < 512)
1104 strcat(message, "\n\n");
1105 ocsd_def_errlog_msgout(message);
1106
1107 /* process the trace data */
1108 if (ret == 0) {
1109 if (test_error_api)
1110 ret = test_err_api();
1111 else
1112 ret = process_trace_data(trace_data);
1113 }
1114 /* close the data file */
1115 fclose(trace_data);
1116 }
1117 else
1118 {
1119 printf("Unable to open file %s to process trace data\n", trace_file_path);
1120 ret = -1;
1121 }
1122 return ret;
1123 }
1124 /* End of File simple_pkt_c_api.c */
1125