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