summaryrefslogtreecommitdiffstats
path: root/decoder/tests/source
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:24:57 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:24:57 +0000
commit070852d8604cece0c31f28ff3eb8d21d9ba415fb (patch)
tree9097175a6a5b8b7e37af9a96269ac0b61a0189cd /decoder/tests/source
parentInitial commit. (diff)
downloadlibopencsd-upstream.tar.xz
libopencsd-upstream.zip
Adding upstream version 1.3.3.upstream/1.3.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'decoder/tests/source')
-rw-r--r--decoder/tests/source/c_api_pkt_print_test.c1124
-rw-r--r--decoder/tests/source/frame_demux_test.cpp524
-rw-r--r--decoder/tests/source/mem_buff_demo.cpp421
-rw-r--r--decoder/tests/source/trc_pkt_lister.cpp767
4 files changed, 2836 insertions, 0 deletions
diff --git a/decoder/tests/source/c_api_pkt_print_test.c b/decoder/tests/source/c_api_pkt_print_test.c
new file mode 100644
index 0000000..b930e05
--- /dev/null
+++ b/decoder/tests/source/c_api_pkt_print_test.c
@@ -0,0 +1,1124 @@
+/*
+ * \file c_api_pkt_print_test.c
+ * \brief OpenCSD : C-API test program
+ *
+ * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Example of using the library with the C-API. Used to validate that the C-API
+ * functions work.
+ *
+ * Simple test program to print packets from a single trace ID source stream.
+ * Hard coded configuration based on the Juno r1-1 test snapshot for ETMv4 and
+ * STM, TC2 test snapshot for ETMv3, PTM.
+ *
+ * The test source can be set from the command line, but will default to the
+ * ETMv4 trace for trace ID 0x10 on the juno r1-1 test snapshot.
+ * This example uses the updated C-API functionality from library version 0.4.0 onwards.
+ * Test values are hardcoded from the same values in the snapshots as we do not
+ * explicitly read the snapshot metadata in this example program.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* include the C-API library header */
+#include "opencsd/c_api/opencsd_c_api.h"
+
+/* include the test external decoder factory and decoder types headers
+ - separate from the main library includes by definition as external decoder.
+*/
+#include "ext_dcd_echo_test_fact.h"
+#include "ext_dcd_echo_test.h"
+
+/* path to test snapshots, relative to tests/bin/<plat>/<dbg|rel> build output dir */
+#ifdef _WIN32
+const char *default_base_snapshot_path="..\\..\\..\\snapshots";
+const char *juno_snapshot = "\\juno_r1_1\\";
+const char *tc2_snapshot = "\\TC2\\";
+#else
+const char *default_base_snapshot_path = "../../snapshots";
+const char *juno_snapshot = "/juno_r1_1/";
+const char *tc2_snapshot = "/TC2/";
+#endif
+static const char *selected_snapshot;
+static const char *usr_snapshot_path = 0;
+#define MAX_TRACE_FILE_PATH_LEN 512
+
+/* trace data and memory file dump names and values - taken from snapshot metadata */
+const char *trace_data_filename = "cstrace.bin";
+const char *stmtrace_data_filename = "cstraceitm.bin";
+const char *memory_dump_filename = "kernel_dump.bin";
+ocsd_vaddr_t mem_dump_address=0xFFFFFFC000081000;
+const ocsd_vaddr_t mem_dump_address_tc2=0xC0008000;
+
+/* test variables - set by command line to feature test API */
+static int using_mem_acc_cb = 0; /* test the memory access callback function */
+static int use_region_file = 0; /* test multi region memory files */
+static int using_mem_acc_cb_id = 0; /* test the mem acc callback with trace ID parameter */
+
+/* buffer to handle a packet string */
+#define PACKET_STR_LEN 1024
+static char packet_str[PACKET_STR_LEN];
+
+/* decide if we decode & monitor, decode only or packet print */
+typedef enum _test_op {
+ TEST_PKT_PRINT, // process trace input into discrete packets and print.
+ TEST_PKT_DECODE, // process and decode trace packets, printing discrete packets and generic output.
+ TEST_PKT_DECODEONLY // process and decode trace packets, printing generic output packets only.
+} test_op_t;
+
+// Default test operations
+static test_op_t op = TEST_PKT_PRINT; // default operation is to packet print
+static ocsd_trace_protocol_t test_protocol = OCSD_PROTOCOL_ETMV4I; // ETMV4 protocl
+static uint8_t test_trc_id_override = 0x00; // no trace ID override.
+
+/* external decoder testing */
+static int test_extern_decoder = 0; /* test the external decoder infrastructure. */
+static ocsd_extern_dcd_fact_t *p_ext_fact; /* external decoder factory */
+#define EXT_DCD_NAME "ext_echo"
+
+/* raw packet printing test */
+static int frame_raw_unpacked = 0;
+static int frame_raw_packed = 0;
+static int test_printstr = 0;
+
+/* test the library printer API */
+static int test_lib_printers = 0;
+
+/* test the last error / error code api */
+static int test_error_api = 0;
+
+/* log statistics */
+static int stats = 0;
+
+/* Process command line options - choose the operation to use for the test. */
+static int process_cmd_line(int argc, char *argv[])
+{
+ int idx = 1;
+ int len = 0;
+
+ while(idx < argc)
+ {
+ if (strcmp(argv[idx], "-decode_only") == 0)
+ {
+ op = TEST_PKT_DECODEONLY;
+ }
+ else if (strcmp(argv[idx], "-decode") == 0)
+ {
+ op = TEST_PKT_DECODE;
+ }
+ else if (strcmp(argv[idx], "-id") == 0)
+ {
+ idx++;
+ if (idx < argc)
+ {
+ test_trc_id_override = (uint8_t)(strtoul(argv[idx], 0, 0));
+ printf("ID override = 0x%02X\n", test_trc_id_override);
+ }
+ }
+ else if (strcmp(argv[idx], "-etmv3") == 0)
+ {
+ test_protocol = OCSD_PROTOCOL_ETMV3;
+ selected_snapshot = tc2_snapshot;
+ mem_dump_address = mem_dump_address_tc2;
+ }
+ else if (strcmp(argv[idx], "-ptm") == 0)
+ {
+ test_protocol = OCSD_PROTOCOL_PTM;
+ selected_snapshot = tc2_snapshot;
+ mem_dump_address = mem_dump_address_tc2;
+ }
+ else if (strcmp(argv[idx], "-stm") == 0)
+ {
+ test_protocol = OCSD_PROTOCOL_STM;
+ trace_data_filename = stmtrace_data_filename;
+ }
+ else if (strcmp(argv[idx], "-test_cb") == 0)
+ {
+ using_mem_acc_cb = 1;
+ use_region_file = 0;
+ }
+ else if (strcmp(argv[idx], "-test_cb_id") == 0)
+ {
+ using_mem_acc_cb = 1;
+ use_region_file = 0;
+ using_mem_acc_cb_id = 1;
+ }
+ else if (strcmp(argv[idx], "-test_region_file") == 0)
+ {
+ use_region_file = 1;
+ using_mem_acc_cb = 0;
+ }
+ else if (strcmp(argv[idx], "-extern") == 0)
+ {
+ test_extern_decoder = 1;
+ }
+ else if (strcmp(argv[idx], "-raw") == 0)
+ {
+ frame_raw_unpacked = 1;
+ }
+ else if (strcmp(argv[idx], "-stats") == 0)
+ {
+ stats = 1;
+ }
+ else if (strcmp(argv[idx], "-raw_packed") == 0)
+ {
+ frame_raw_packed = 1;
+ }
+ else if (strcmp(argv[idx], "-test_printstr") == 0)
+ {
+ test_printstr = 1;
+ }
+ else if (strcmp(argv[idx], "-test_libprint") == 0)
+ {
+ test_lib_printers = 1;
+ }
+ else if (strcmp(argv[idx], "-ss_path") == 0)
+ {
+ idx++;
+ if ((idx >= argc) || (strlen(argv[idx]) == 0))
+ {
+ printf("-ss_path: Missing path parameter or zero length\n");
+ return -1;
+ }
+ else
+ {
+ len = strlen(argv[idx]);
+ if (len > (MAX_TRACE_FILE_PATH_LEN - 32))
+ {
+ printf("-ss_path: path too long\n");
+ return -1;
+ }
+ usr_snapshot_path = argv[idx];
+ }
+
+ }
+ else if (strcmp(argv[idx], "-test_err_api") == 0)
+ {
+ test_error_api = 1;
+ }
+ else if(strcmp(argv[idx],"-help") == 0)
+ {
+ return -1;
+ }
+ else
+ printf("Ignored unknown argument %s\n", argv[idx]);
+ idx++;
+ }
+ return 0;
+}
+
+static void print_cmd_line_help()
+{
+ printf("Usage:\n-etmv3|-stm|-ptm|-extern : choose protocol (one only, default etmv4)\n");
+ printf("-id <ID> : decode source for id <ID> (default 0x10)\n");
+ printf("-decode | -decode_only : full decode + trace packets / full decode packets only (default trace packets only)\n");
+ printf("-raw / -raw_packed: print raw unpacked / packed data;\n");
+ printf("-test_printstr | -test_libprint : ttest lib printstr callback | test lib based packet printers\n");
+ 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");
+ printf("-ss_path <path> : path from cwd to /snapshots/ directory. Test prog will append required test subdir\n");
+}
+
+/************************************************************************/
+/* Memory accessor functionality */
+/************************************************************************/
+
+static FILE *dump_file = NULL; /* pointer to the file providing the opcode memory */
+static ocsd_mem_space_acc_t dump_file_mem_space = OCSD_MEM_SPACE_ANY; /* memory space used by the dump file */
+static long mem_file_size = 0; /* size of the memory file */
+static ocsd_vaddr_t mem_file_en_address = 0; /* end address last inclusive address in file. */
+
+/* log the memacc output */
+/* #define LOG_MEMACC_CB */
+
+/* decode memory access using a CallBack function
+* tests CB API and add / remove mem acc API.
+*/
+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)
+{
+ uint32_t read_bytes = 0;
+ size_t file_read_bytes;
+
+ if(dump_file == NULL)
+ return 0;
+
+ /* bitwise & the incoming mem space and supported mem space to confirm coverage */
+ if(((uint8_t)mem_space & (uint8_t)dump_file_mem_space ) == 0)
+ return 0;
+
+ /* calculate the bytes that can be read */
+ if((address >= mem_dump_address) && (address <= mem_file_en_address))
+ {
+ /* some bytes in our range */
+ read_bytes = reqBytes;
+
+ if((address + reqBytes - 1) > mem_file_en_address)
+ {
+ /* more than are available - just read the available */
+ read_bytes = (uint32_t)(mem_file_en_address - (address - 1));
+ }
+ }
+
+ /* read some bytes if more than 0 to read. */
+ if(read_bytes != 0)
+ {
+ fseek(dump_file,(long)(address-mem_dump_address),SEEK_SET);
+ file_read_bytes = fread(byteBuffer,sizeof(uint8_t),read_bytes,dump_file);
+ if(file_read_bytes < read_bytes)
+ read_bytes = file_read_bytes;
+ }
+#ifdef LOG_MEMACC_CB
+ sprintf(packet_str, "mem_acc_cb(addr 0x%08llX, size %d, trcID 0x%02X)\n", address, reqBytes, trc_id);
+ ocsd_def_errlog_msgout(packet_str);
+#endif
+ return read_bytes;
+}
+
+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)
+{
+ return do_mem_acc_cb(p_context, address, mem_space, 0xff, reqBytes, byteBuffer);
+}
+
+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)
+{
+ return do_mem_acc_cb(p_context, address, mem_space, trc_id, reqBytes, byteBuffer);
+}
+
+
+/* Create the memory accessor using the callback function and attach to decode tree */
+static ocsd_err_t create_mem_acc_cb(dcd_tree_handle_t dcd_tree_h, const char *mem_file_path)
+{
+ ocsd_err_t err = OCSD_OK;
+ dump_file = fopen(mem_file_path,"rb");
+ if(dump_file != NULL)
+ {
+ fseek(dump_file,0,SEEK_END);
+ mem_file_size = ftell(dump_file);
+ mem_file_en_address = mem_dump_address + mem_file_size - 1;
+
+ if (using_mem_acc_cb_id)
+ err = ocsd_dt_add_callback_trcid_mem_acc(dcd_tree_h, mem_dump_address,
+ mem_file_en_address, dump_file_mem_space, &mem_acc_id_cb, 0);
+ else
+ err = ocsd_dt_add_callback_mem_acc(dcd_tree_h, mem_dump_address,
+ mem_file_en_address, dump_file_mem_space, &mem_acc_cb, 0);
+ if(err != OCSD_OK)
+ {
+ fclose(dump_file);
+ dump_file = NULL;
+ }
+ }
+ else
+ err = OCSD_ERR_MEM_ACC_FILE_NOT_FOUND;
+ return err;
+}
+
+/* remove the callback memory accessor from decode tree */
+static void destroy_mem_acc_cb(dcd_tree_handle_t dcd_tree_h)
+{
+ if(dump_file != NULL)
+ {
+ ocsd_dt_remove_mem_acc(dcd_tree_h,mem_dump_address,dump_file_mem_space);
+ fclose(dump_file);
+ dump_file = NULL;
+ }
+}
+
+/* create and attach the memory accessor according to required test parameters */
+static ocsd_err_t create_test_memory_acc(dcd_tree_handle_t handle)
+{
+ ocsd_err_t ret = OCSD_OK;
+ char mem_file_path[MAX_TRACE_FILE_PATH_LEN];
+ uint32_t i0adjust = 0x100;
+ int i = 0;
+
+ /* region list to test multi region memory file API */
+ ocsd_file_mem_region_t region_list[4];
+
+ /* path to the file containing the memory image traced - raw binary data in the snapshot */
+ if(usr_snapshot_path != 0)
+ strcpy(mem_file_path,usr_snapshot_path);
+ else
+ strcpy(mem_file_path,default_base_snapshot_path);
+ strcat(mem_file_path,selected_snapshot);
+ strcat(mem_file_path,memory_dump_filename);
+
+ /*
+ * decide how to handle the file - test the normal memory accessor (contiguous binary file),
+ * a callback accessor or a multi-region file (e.g. similar to using the code region in a .so)
+ *
+ * The same memory dump file is used in each case, we just present it differently
+ * to test the API functions.
+ */
+
+ /* memory access callback */
+ if(using_mem_acc_cb)
+ {
+ ret = create_mem_acc_cb(handle,mem_file_path);
+ }
+ /* multi region file */
+ else if(use_region_file)
+ {
+
+ dump_file = fopen(mem_file_path,"rb");
+ if(dump_file != NULL)
+ {
+ fseek(dump_file,0,SEEK_END);
+ mem_file_size = ftell(dump_file);
+ fclose(dump_file);
+
+ /* populate the region list - split existing file into four regions */
+ for(i = 0; i < 4; i++)
+ {
+ if(i != 0)
+ i0adjust = 0;
+ region_list[i].start_address = mem_dump_address + (i * mem_file_size/4) + i0adjust;
+ region_list[i].region_size = (mem_file_size/4) - i0adjust;
+ region_list[i].file_offset = (i * mem_file_size/4) + i0adjust;
+ }
+
+ /* create a memory file accessor - full binary file */
+ ret = ocsd_dt_add_binfile_region_mem_acc(handle,&region_list[0],4,OCSD_MEM_SPACE_ANY,mem_file_path);
+ }
+ else
+ ret = OCSD_ERR_MEM_ACC_FILE_NOT_FOUND;
+ }
+ /* create a memory file accessor - simple contiguous full binary file */
+ else
+ {
+ ret = ocsd_dt_add_binfile_mem_acc(handle,mem_dump_address,OCSD_MEM_SPACE_ANY,mem_file_path);
+ }
+ return ret;
+}
+
+/************************************************************************/
+/** Packet printers */
+/************************************************************************/
+
+/*
+* Callback function to process the packets in the packet processor output stream -
+* simply print them out in this case to the library message/error logger.
+*/
+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)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ int offset = 0;
+
+ switch(op)
+ {
+ case OCSD_OP_DATA:
+ sprintf(packet_str,"Idx:%" OCSD_TRC_IDX_STR "; ", index_sop);
+ offset = strlen(packet_str);
+
+ /*
+ * got a packet - convert to string and use the libraries' message output to print to file and stdoout
+ * Since the test always prints a single ID, we know the protocol type.
+ */
+ if(ocsd_pkt_str(test_protocol,p_packet_in,packet_str+offset,PACKET_STR_LEN-offset) == OCSD_OK)
+ {
+ /* add in <CR> */
+ if(strlen(packet_str) == PACKET_STR_LEN - 1) /* maximum length */
+ packet_str[PACKET_STR_LEN-2] = '\n';
+ else
+ strcat(packet_str,"\n");
+
+ /* print it using the library output logger. */
+ ocsd_def_errlog_msgout(packet_str);
+ }
+ else
+ resp = OCSD_RESP_FATAL_INVALID_PARAM; /* mark fatal error */
+ break;
+
+ case OCSD_OP_EOT:
+ sprintf(packet_str,"**** END OF TRACE ****\n");
+ ocsd_def_errlog_msgout(packet_str);
+ break;
+
+ default: break;
+ }
+
+ return resp;
+}
+
+/* print an array of hex data - used by the packet monitor to print hex data from packet.*/
+static int print_data_array(const uint8_t *p_array, const int array_size, char *p_buffer, int buf_size)
+{
+ int chars_printed = 0;
+ int bytes_processed;
+ p_buffer[0] = 0;
+
+ if(buf_size > 9)
+ {
+ /* set up the header */
+ strcat(p_buffer,"[ ");
+ chars_printed+=2;
+
+ for(bytes_processed = 0; bytes_processed < array_size; bytes_processed++)
+ {
+ sprintf(p_buffer+chars_printed,"0x%02X ", p_array[bytes_processed]);
+ chars_printed += 5;
+ if((chars_printed + 5) > buf_size)
+ break;
+ }
+
+ strcat(p_buffer,"];");
+ chars_printed+=2;
+ }
+ else if(buf_size >= 4)
+ {
+ sprintf(p_buffer,"[];");
+ chars_printed+=3;
+ }
+ return chars_printed;
+}
+
+/*
+* Callback function to process packets and packet data from the monitor output of the
+* packet processor. Again print them to the library error logger.
+*/
+void 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)
+{
+ int offset = 0;
+
+ switch(op)
+ {
+ default: break;
+ case OCSD_OP_DATA:
+ sprintf(packet_str,"Idx:%" OCSD_TRC_IDX_STR ";", index_sop);
+ offset = strlen(packet_str);
+ offset+= print_data_array(p_data,size,packet_str+offset,PACKET_STR_LEN-offset);
+
+ /* got a packet - convert to string and use the libraries' message output to print to file and stdoout */
+ if(ocsd_pkt_str(test_protocol,p_packet_in,packet_str+offset,PACKET_STR_LEN-offset) == OCSD_OK)
+ {
+ /* add in <CR> */
+ if(strlen(packet_str) == PACKET_STR_LEN - 1) /* maximum length */
+ packet_str[PACKET_STR_LEN-2] = '\n';
+ else
+ strcat(packet_str,"\n");
+
+ /* print it using the library output logger. */
+ ocsd_def_errlog_msgout(packet_str);
+ }
+ break;
+
+ case OCSD_OP_EOT:
+ sprintf(packet_str,"**** END OF TRACE ****\n");
+ ocsd_def_errlog_msgout(packet_str);
+ break;
+ }
+}
+
+
+/*
+* printer for the generic trace elements when decoder output is being processed
+*/
+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)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ int offset = 0;
+
+ sprintf(packet_str,"Idx:%" OCSD_TRC_IDX_STR "; TrcID:0x%02X; ", index_sop, trc_chan_id);
+ offset = strlen(packet_str);
+
+ if(ocsd_gen_elem_str(elem, packet_str+offset,PACKET_STR_LEN - offset) == OCSD_OK)
+ {
+ /* add in <CR> */
+ if(strlen(packet_str) == PACKET_STR_LEN - 1) /* maximum length */
+ packet_str[PACKET_STR_LEN-2] = '\n';
+ else
+ strcat(packet_str,"\n");
+ }
+ else
+ {
+ strcat(packet_str,"Unable to create element string\n");
+ }
+
+ /* print it using the library output logger. */
+ ocsd_def_errlog_msgout(packet_str);
+
+ return resp;
+}
+
+/************************************************************************/
+/** decoder creation **/
+
+/*** generic ***/
+static ocsd_err_t create_generic_decoder(dcd_tree_handle_t handle, const char *p_name, const void *p_cfg, const void *p_context)
+{
+ ocsd_err_t ret = OCSD_OK;
+ uint8_t CSID = 0;
+
+ if(op == TEST_PKT_PRINT) /* test operation set to packet printing only */
+ {
+ /*
+ * Create a packet processor on the decode tree for the configuration we have.
+ * We need to supply the configuration
+ */
+ ret = ocsd_dt_create_decoder(handle,p_name,OCSD_CREATE_FLG_PACKET_PROC,p_cfg,&CSID);
+ if(ret == OCSD_OK)
+ {
+ /* Attach the packet handler to the output of the packet processor - referenced by CSID */
+ if (test_lib_printers)
+ ret = ocsd_dt_set_pkt_protocol_printer(handle, CSID, 0);
+ else
+ ret = ocsd_dt_attach_packet_callback(handle,CSID, OCSD_C_API_CB_PKT_SINK,&packet_handler,p_context);
+ if(ret != OCSD_OK)
+ ocsd_dt_remove_decoder(handle,CSID); /* if the attach failed then destroy the decoder. */
+ }
+ }
+ else
+ {
+ /* Full decode - need decoder, and memory dump */
+
+ /* create the packet decoder and packet processor pair from the supplied name */
+ ret = ocsd_dt_create_decoder(handle,p_name,OCSD_CREATE_FLG_FULL_DECODER,p_cfg,&CSID);
+ if(ret == OCSD_OK)
+ {
+ if((op != TEST_PKT_DECODEONLY) && (ret == OCSD_OK))
+ {
+ /*
+ * print the packets as well as the decode - use the packet processors monitor
+ * output this time, as the main output is attached to the packet decoder.
+ */
+ if (test_lib_printers)
+ ret = ocsd_dt_set_pkt_protocol_printer(handle, CSID, 1);
+ else
+ ret = ocsd_dt_attach_packet_callback(handle,CSID,OCSD_C_API_CB_PKT_MON,packet_monitor,p_context);
+ }
+
+ /* attach a memory accessor */
+ if(ret == OCSD_OK)
+ ret = create_test_memory_acc(handle);
+
+ /* if the attach failed then destroy the decoder. */
+ if(ret != OCSD_OK)
+ ocsd_dt_remove_decoder(handle,CSID);
+ }
+ }
+ return ret;
+}
+
+/*** ETMV4 specific settings ***/
+static ocsd_err_t create_decoder_etmv4(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_etmv4_cfg trace_config;
+
+ /*
+ * populate the ETMv4 configuration structure with
+ * hard coded values from snapshot .ini files.
+ */
+
+ trace_config.arch_ver = ARCH_V8;
+ trace_config.core_prof = profile_CortexA;
+
+ trace_config.reg_configr = 0x000000C1;
+ trace_config.reg_traceidr = 0x00000010; /* this is the trace ID -> 0x10, change this to analyse other streams in snapshot.*/
+
+ if(test_trc_id_override != 0)
+ {
+ trace_config.reg_traceidr = (uint32_t)test_trc_id_override;
+ }
+ test_trc_id_override = trace_config.reg_traceidr; /* remember what ID we actually used */
+
+ trace_config.reg_idr0 = 0x28000EA1;
+ trace_config.reg_idr1 = 0x4100F403;
+ trace_config.reg_idr2 = 0x00000488;
+ trace_config.reg_idr8 = 0x0;
+ trace_config.reg_idr9 = 0x0;
+ trace_config.reg_idr10 = 0x0;
+ trace_config.reg_idr11 = 0x0;
+ trace_config.reg_idr12 = 0x0;
+ trace_config.reg_idr13 = 0x0;
+
+ /* create an ETMV4 decoder - no context needed as we have a single stream to a single handler. */
+ return create_generic_decoder(dcd_tree_h,OCSD_BUILTIN_DCD_ETMV4I,(void *)&trace_config,0);
+}
+
+/*** ETMV3 specific settings ***/
+static ocsd_err_t create_decoder_etmv3(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_etmv3_cfg trace_config_etmv3;
+
+ /*
+ * populate the ETMv3 configuration structure with
+ * hard coded values from snapshot .ini files.
+ */
+
+ trace_config_etmv3.arch_ver = ARCH_V7;
+ trace_config_etmv3.core_prof = profile_CortexA;
+ trace_config_etmv3.reg_ccer = 0x344008F2;
+ trace_config_etmv3.reg_ctrl = 0x10001860;
+ trace_config_etmv3.reg_idr = 0x410CF250;
+ trace_config_etmv3.reg_trc_id = 0x010;
+ if(test_trc_id_override != 0)
+ {
+ trace_config_etmv3.reg_trc_id = (uint32_t)test_trc_id_override;
+ }
+ test_trc_id_override = trace_config_etmv3.reg_trc_id; /* remember what ID we actually used */
+
+ /* create an ETMV3 decoder - no context needed as we have a single stream to a single handler. */
+ return create_generic_decoder(dcd_tree_h,OCSD_BUILTIN_DCD_ETMV3,(void *)&trace_config_etmv3,0);
+}
+
+/*** PTM specific settings ***/
+static ocsd_err_t create_decoder_ptm(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_ptm_cfg trace_config_ptm;
+
+ /*
+ * populate the PTM configuration structure with
+ * hard coded values from snapshot .ini files.
+ */
+
+ trace_config_ptm.arch_ver = ARCH_V7;
+ trace_config_ptm.core_prof = profile_CortexA;
+ trace_config_ptm.reg_ccer = 0x34C01AC2;
+ trace_config_ptm.reg_ctrl = 0x10001000;
+ trace_config_ptm.reg_idr = 0x411CF312;
+ trace_config_ptm.reg_trc_id = 0x013;
+ if(test_trc_id_override != 0)
+ {
+ trace_config_ptm.reg_trc_id = (uint32_t)test_trc_id_override;
+ }
+ test_trc_id_override = trace_config_ptm.reg_trc_id; /* remember what ID we actually used */
+
+ /* create an PTM decoder - no context needed as we have a single stream to a single handler. */
+ return create_generic_decoder(dcd_tree_h,OCSD_BUILTIN_DCD_PTM,(void *)&trace_config_ptm,0);
+
+}
+
+/*** STM specific settings ***/
+static ocsd_err_t create_decoder_stm(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_stm_cfg trace_config_stm;
+
+ /*
+ * populate the STM configuration structure with
+ * hard coded values from snapshot .ini files.
+ */
+ #define STMTCSR_TRC_ID_MASK 0x007F0000
+ #define STMTCSR_TRC_ID_SHIFT 16
+
+ trace_config_stm.reg_tcsr = 0x00A00005;
+ if(test_trc_id_override != 0)
+ {
+ trace_config_stm.reg_tcsr &= ~STMTCSR_TRC_ID_MASK;
+ trace_config_stm.reg_tcsr |= ((((uint32_t)test_trc_id_override) << STMTCSR_TRC_ID_SHIFT) & STMTCSR_TRC_ID_MASK);
+ }
+ trace_config_stm.reg_feat3r = 0x10000; /* channel default */
+ trace_config_stm.reg_devid = 0xFF; /* master default */
+
+ /* not using hw event trace decode */
+ trace_config_stm.reg_hwev_mast = 0;
+ trace_config_stm.reg_feat1r = 0;
+ trace_config_stm.hw_event = HwEvent_Unknown_Disabled;
+
+ /* create a STM decoder - no context needed as we have a single stream to a single handler. */
+ return create_generic_decoder(dcd_tree_h, OCSD_BUILTIN_DCD_STM, (void *)&trace_config_stm, 0);
+}
+
+static ocsd_err_t create_decoder_extern(dcd_tree_handle_t dcd_tree_h)
+{
+ echo_dcd_cfg_t trace_cfg_ext;
+
+ /* setup the custom configuration */
+ trace_cfg_ext.cs_id = 0x010;
+ if (test_trc_id_override != 0)
+ {
+ trace_cfg_ext.cs_id = (uint32_t)test_trc_id_override;
+ }
+ test_trc_id_override = trace_cfg_ext.cs_id;
+
+ /* create an external decoder - no context needed as we have a single stream to a single handler. */
+ return create_generic_decoder(dcd_tree_h, EXT_DCD_NAME, (void *)&trace_cfg_ext, 0);
+}
+
+static ocsd_err_t attach_raw_printers(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_err_t err = OCSD_OK;
+ int flags = 0;
+ if (frame_raw_unpacked)
+ flags |= OCSD_DFRMTR_UNPACKED_RAW_OUT;
+ if (frame_raw_packed)
+ flags |= OCSD_DFRMTR_PACKED_RAW_OUT;
+ if (flags)
+ {
+ err = ocsd_dt_set_raw_frame_printer(dcd_tree_h, flags);
+ }
+ return err;
+}
+
+static void print_output_str(const void *p_context, const char *psz_msg_str, const int str_len)
+{
+ printf("** CUST_PRNTSTR: %s", psz_msg_str);
+}
+
+static ocsd_err_t test_printstr_cb(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_err_t err = OCSD_OK;
+ if (test_printstr)
+ err = ocsd_def_errlog_set_strprint_cb(dcd_tree_h, 0, print_output_str);
+ return err;
+}
+/************************************************************************/
+
+ocsd_err_t register_extern_decoder()
+{
+ ocsd_err_t err = OCSD_ERR_NO_PROTOCOL;
+
+ p_ext_fact = ext_echo_get_dcd_fact();
+ if (p_ext_fact)
+ {
+ err = ocsd_register_custom_decoder(EXT_DCD_NAME, p_ext_fact);
+ if (err == OCSD_OK)
+ test_protocol = p_ext_fact->protocol_id;
+ else
+ printf("External Decoder Registration: Failed to register decoder.");
+ }
+ else
+ printf("External Decoder Registration: Failed to get decoder factory.");
+
+ return err;
+}
+
+/* create a decoder according to options */
+static ocsd_err_t create_decoder(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_err_t err = OCSD_OK;
+
+ /* extended for the external decoder testing*/
+ if (test_extern_decoder)
+ err = register_extern_decoder();
+ if (err != OCSD_OK)
+ return err;
+
+ switch(test_protocol)
+ {
+ case OCSD_PROTOCOL_ETMV4I:
+ err = create_decoder_etmv4(dcd_tree_h);
+ break;
+
+ case OCSD_PROTOCOL_ETMV3:
+ err = create_decoder_etmv3(dcd_tree_h);
+ break;
+
+ case OCSD_PROTOCOL_STM:
+ err = create_decoder_stm(dcd_tree_h);
+ break;
+
+ case OCSD_PROTOCOL_PTM:
+ err = create_decoder_ptm(dcd_tree_h);
+ break;
+
+ /* we only register a single external decoder in this test,
+ so it will always be assigned the first custom protocol ID */
+ case OCSD_PROTOCOL_CUSTOM_0:
+ err = create_decoder_extern(dcd_tree_h);
+ break;
+
+ default:
+ err = OCSD_ERR_NO_PROTOCOL;
+ break;
+ }
+ return err;
+}
+
+#define INPUT_BLOCK_SIZE 1024
+
+/* process buffer until done or error */
+ocsd_err_t process_data_block(dcd_tree_handle_t dcd_tree_h, int block_index, uint8_t *p_block, const int block_size)
+{
+ ocsd_err_t ret = OCSD_OK;
+ uint32_t bytes_done = 0;
+ ocsd_datapath_resp_t dp_ret = OCSD_RESP_CONT;
+ uint32_t bytes_this_time = 0;
+
+ while((bytes_done < (uint32_t)block_size) && (ret == OCSD_OK))
+ {
+ if(OCSD_DATA_RESP_IS_CONT(dp_ret))
+ {
+ dp_ret = ocsd_dt_process_data(dcd_tree_h,
+ OCSD_OP_DATA,
+ block_index+bytes_done,
+ block_size-bytes_done,
+ ((uint8_t *)p_block)+bytes_done,
+ &bytes_this_time);
+ bytes_done += bytes_this_time;
+ }
+ else if(OCSD_DATA_RESP_IS_WAIT(dp_ret))
+ {
+ dp_ret = ocsd_dt_process_data(dcd_tree_h, OCSD_OP_FLUSH,0,0,NULL,NULL);
+ }
+ else
+ ret = OCSD_ERR_DATA_DECODE_FATAL; /* data path responded with an error - stop processing */
+ }
+ return ret;
+}
+
+void print_statistics(dcd_tree_handle_t dcdtree_handle)
+{
+ ocsd_decode_stats_t *p_stats = 0;
+ ocsd_err_t err;
+
+ sprintf(packet_str, "\nReading packet decoder statistics for ID:0x%02x...\n", test_trc_id_override);
+ ocsd_def_errlog_msgout(packet_str);
+
+ err = ocsd_dt_get_decode_stats(dcdtree_handle, test_trc_id_override, &p_stats);
+ if (!err && p_stats)
+ {
+ sprintf(packet_str, "Total Bytes %ld; Unsynced Bytes: %ld\nBad Header Errors: %d; Bad sequence errors: %d\n", (long)p_stats->channel_total,
+ (long)p_stats->channel_unsynced, p_stats->bad_header_errs, p_stats->bad_sequence_errs);
+ ocsd_dt_reset_decode_stats(dcdtree_handle, test_trc_id_override);
+ }
+ else
+ {
+ sprintf(packet_str, "Not available for this ID.\n");
+ }
+ ocsd_def_errlog_msgout(packet_str);
+}
+
+int process_trace_data(FILE *pf)
+{
+ ocsd_err_t ret = OCSD_OK;
+ dcd_tree_handle_t dcdtree_handle = C_API_INVALID_TREE_HANDLE;
+ uint8_t data_buffer[INPUT_BLOCK_SIZE];
+ ocsd_trc_index_t index = 0;
+ size_t data_read;
+
+
+ /* Create a decode tree for this source data.
+ source data is frame formatted, memory aligned from an ETR (no frame syncs) so create tree accordingly
+ */
+ dcdtree_handle = ocsd_create_dcd_tree(OCSD_TRC_SRC_FRAME_FORMATTED, OCSD_DFRMTR_FRAME_MEM_ALIGN);
+
+ if(dcdtree_handle != C_API_INVALID_TREE_HANDLE)
+ {
+
+ ret = create_decoder(dcdtree_handle);
+ ocsd_tl_log_mapped_mem_ranges(dcdtree_handle);
+
+ if (ret == OCSD_OK)
+ {
+ /* attach the generic trace element output callback */
+ if (test_lib_printers)
+ ret = ocsd_dt_set_gen_elem_printer(dcdtree_handle);
+ else
+ ret = ocsd_dt_set_gen_elem_outfn(dcdtree_handle, gen_trace_elem_print, 0);
+ }
+
+
+ /* raw print and str print cb options tested in their init functions */
+ if (ret == OCSD_OK)
+ ret = test_printstr_cb(dcdtree_handle);
+
+ if (ret == OCSD_OK)
+ ret = attach_raw_printers(dcdtree_handle);
+
+
+ /* now push the trace data through the packet processor */
+ while(!feof(pf) && (ret == OCSD_OK))
+ {
+ /* read from file */
+ data_read = fread(data_buffer,1,INPUT_BLOCK_SIZE,pf);
+ if(data_read > 0)
+ {
+ /* process a block of data - any packets from the trace stream
+ we have configured will appear at the callback
+ */
+ ret = process_data_block(dcdtree_handle,
+ index,
+ data_buffer,
+ data_read);
+ index += data_read;
+ }
+ else if(ferror(pf))
+ ret = OCSD_ERR_FILE_ERROR;
+ }
+
+ /* no errors - let the data path know we are at end of trace */
+ if(ret == OCSD_OK)
+ ocsd_dt_process_data(dcdtree_handle, OCSD_OP_EOT, 0,0,NULL,NULL);
+
+ if (stats) {
+ print_statistics(dcdtree_handle);
+ }
+ /* shut down the mem acc CB if in use. */
+ if(using_mem_acc_cb)
+ {
+ destroy_mem_acc_cb(dcdtree_handle);
+ }
+
+ /* dispose of the decode tree - which will dispose of any packet processors we created
+ */
+ ocsd_destroy_dcd_tree(dcdtree_handle);
+ }
+ else
+ {
+ printf("Failed to create trace decode tree\n");
+ ret = OCSD_ERR_NOT_INIT;
+ }
+ return (int)ret;
+}
+
+#define ERR_BUFFER_SIZE 256
+int test_err_api()
+{
+ dcd_tree_handle_t dcdtree_handle = C_API_INVALID_TREE_HANDLE;
+ ocsd_err_t ret = OCSD_OK, err_test;
+ ocsd_trc_index_t index = 0, err_index = 0;
+ uint8_t cs_id;
+ char err_buffer[ERR_BUFFER_SIZE];
+
+ /* Create a decode tree for this source data.
+ source data is frame formatted, memory aligned from an ETR (no frame syncs) so create tree accordingly
+ */
+ dcdtree_handle = ocsd_create_dcd_tree(OCSD_TRC_SRC_SINGLE, OCSD_DFRMTR_FRAME_MEM_ALIGN);
+
+ if (dcdtree_handle != C_API_INVALID_TREE_HANDLE)
+ {
+
+ ret = create_decoder(dcdtree_handle);
+ if (ret == OCSD_OK)
+ {
+ /* attach the generic trace element output callback */
+ if (test_lib_printers)
+ ret = ocsd_dt_set_gen_elem_printer(dcdtree_handle);
+ else
+ ret = ocsd_dt_set_gen_elem_outfn(dcdtree_handle, gen_trace_elem_print, 0);
+ }
+
+
+ /* raw print and str print cb options tested in their init functions */
+ if (ret == OCSD_OK)
+ ret = test_printstr_cb(dcdtree_handle);
+
+ if (ret == OCSD_OK)
+ ret = attach_raw_printers(dcdtree_handle);
+
+ /* feed some duff data into a decoder to provoke an error! */
+ uint8_t trace_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x60, 0x71 };
+
+ if (ret == OCSD_OK)
+ ret = process_data_block(dcdtree_handle, index, trace_data, sizeof(trace_data));
+
+ ocsd_err_str(ret, err_buffer, ERR_BUFFER_SIZE);
+ printf("testing error API for code %d: %s\n", ret, err_buffer);
+ err_test = ocsd_get_last_err(&err_index, &cs_id, err_buffer, ERR_BUFFER_SIZE);
+ 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);
+
+ }
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *trace_data;
+ char trace_file_path[MAX_TRACE_FILE_PATH_LEN];
+ int ret = 0, i, len;
+ char message[512];
+
+ /* default to juno */
+ selected_snapshot = juno_snapshot;
+
+ /* command line params */
+ if(process_cmd_line(argc,argv) != 0)
+ {
+ print_cmd_line_help();
+ return -2;
+ }
+
+ /* trace data file path */
+ if(usr_snapshot_path != 0)
+ strcpy(trace_file_path,usr_snapshot_path);
+ else
+ strcpy(trace_file_path,default_base_snapshot_path);
+ strcat(trace_file_path,selected_snapshot);
+ strcat(trace_file_path,trace_data_filename);
+ printf("opening %s trace data file\n",trace_file_path);
+ trace_data = fopen(trace_file_path,"rb");
+
+ if(trace_data != NULL)
+ {
+ /* set up the logging in the library - enable the error logger, with an output printer*/
+ ret = ocsd_def_errlog_init(OCSD_ERR_SEV_INFO,1);
+
+ /* set up the output - to file and stdout, set custom logfile name */
+ if(ret == 0)
+ ret = ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_FILE | C_API_MSGLOGOUT_FLG_STDOUT, "c_api_test.log");
+
+ /* print sign-on message in log */
+ sprintf(message, "C-API packet print test\nLibrary Version %s\n\n",ocsd_get_version_str());
+ ocsd_def_errlog_msgout(message);
+
+ /* print command line used */
+ message[0] = 0;
+ len = 0;
+ for (i = 0; i < argc; i++)
+ {
+ len += strlen(argv[i]) + 1;
+ if (len < 512)
+ {
+ strcat(message, argv[i]);
+ strcat(message, " ");
+ }
+ }
+ if((len + 2) < 512)
+ strcat(message, "\n\n");
+ ocsd_def_errlog_msgout(message);
+
+ /* process the trace data */
+ if (ret == 0) {
+ if (test_error_api)
+ ret = test_err_api();
+ else
+ ret = process_trace_data(trace_data);
+ }
+ /* close the data file */
+ fclose(trace_data);
+ }
+ else
+ {
+ printf("Unable to open file %s to process trace data\n", trace_file_path);
+ ret = -1;
+ }
+ return ret;
+}
+/* End of File simple_pkt_c_api.c */
diff --git a/decoder/tests/source/frame_demux_test.cpp b/decoder/tests/source/frame_demux_test.cpp
new file mode 100644
index 0000000..69856cc
--- /dev/null
+++ b/decoder/tests/source/frame_demux_test.cpp
@@ -0,0 +1,524 @@
+/*
+* \file frame_demux_test.cpp
+* \brief OpenCSD: Test the frame demux code for robustness with correct and invalid data.
+*
+* \copyright Copyright (c) 2022, ARM Limited. All Rights Reserved.
+*/
+
+/*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its contributors
+* may be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Runs sets of test data through the frame demuxer to ensure that it is robust for valid and
+ * invalid inputs
+ */
+
+#include <cstdio>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <cstring>
+
+#include "opencsd.h" // the library
+
+ /* Decode tree is the main decoder framework - contains the frame demuxer
+ and will have an output printer attached to the raw output */
+static DecodeTree* pDecoder = 0;
+static const uint32_t base_cfg = OCSD_DFRMTR_FRAME_MEM_ALIGN |
+ OCSD_DFRMTR_PACKED_RAW_OUT | OCSD_DFRMTR_UNPACKED_RAW_OUT;
+static ocsdDefaultErrorLogger err_log;
+static ocsdMsgLogger logger;
+
+/* test data */
+#define ID_BYTE_ID(id) ((uint8_t)(id) << 1 | 0x01)
+#define ID_BYTE_DATA(data) ((uint8_t)(data & 0xFE))
+#define FLAGS_BYTE(id0, id1, id2, id3, id4, id5, id6, id7) ((uint8_t) ( \
+ ((id7 & 0x1) << 7) | ((id6 & 0x1) << 6) | ((id5 & 0x1) << 5) | ((id4 & 0x1) << 4) | \
+ ((id3 & 0x1) << 3) | ((id2 & 0x1) << 2) | ((id1 & 0x1) << 1) | (id0 & 0x1) ))
+#define HSYNC_BYTES() 0xff, 0x7f
+#define FSYNC_BYTES() 0xff, 0xff, 0xff, 0x7f
+#define DATASIZE(array) static const size_t array##_sz = sizeof(array) / sizeof(array[0])
+
+
+static const uint8_t buf_hsync_fsync[] = {
+ FSYNC_BYTES(),
+ ID_BYTE_ID(0x10), 0x01, ID_BYTE_DATA(0x2), 0x03,
+ HSYNC_BYTES(), ID_BYTE_ID(0x20), 0x4, ID_BYTE_DATA(0x5), 0x6,
+ ID_BYTE_DATA(0x7), 0x08, HSYNC_BYTES(), ID_BYTE_DATA(0x9), 0xA,
+ ID_BYTE_ID(0x10), 0x0B, ID_BYTE_DATA(0xC),
+ FLAGS_BYTE(0, 0, 0, 1, 1, 1, 1, 0),
+};
+DATASIZE(buf_hsync_fsync);
+
+static const uint8_t buf_mem_align[] = {
+ ID_BYTE_ID(0x10), 0x01, ID_BYTE_DATA(0x02), 0x03,
+ ID_BYTE_DATA(0x04), 0x05, ID_BYTE_DATA(0x06), 0x07,
+ ID_BYTE_ID(0x20), 0x08, ID_BYTE_DATA(0x09), 0x0A,
+ ID_BYTE_DATA(0x0B), 0x0C, ID_BYTE_DATA(0x0D),
+ FLAGS_BYTE(0, 0, 0, 0, 0, 1, 1, 1),
+ ID_BYTE_DATA(0x0E), 0x0F, ID_BYTE_ID(0x30), 0x10,
+ ID_BYTE_DATA(0x11), 0x12, ID_BYTE_DATA(0x13), 0x14,
+ ID_BYTE_DATA(0x15), 0x16, ID_BYTE_ID(0x10), 0x17,
+ ID_BYTE_DATA(0x18), 0x19, ID_BYTE_DATA(0x20),
+ FLAGS_BYTE(0, 0, 1, 1, 1, 1, 0, 0),
+};
+DATASIZE(buf_mem_align);
+
+static const uint8_t buf_mem_align_8id[] = {
+ ID_BYTE_ID(0x10), 0x01, ID_BYTE_DATA(0x02), 0x03,
+ ID_BYTE_DATA(0x04), 0x05, ID_BYTE_DATA(0x06), 0x07,
+ ID_BYTE_ID(0x20), 0x08, ID_BYTE_DATA(0x09), 0x0A,
+ ID_BYTE_DATA(0x0B), 0x0C, ID_BYTE_DATA(0x0D),
+ FLAGS_BYTE(0, 0, 0, 0, 0, 1, 1, 1),
+ // 8 IDs, all with prev flag
+ ID_BYTE_ID(0x01), 0x0E, ID_BYTE_ID(0x02), 0x0F,
+ ID_BYTE_ID(0x03), 0x10, ID_BYTE_ID(0x04), 0x11,
+ ID_BYTE_ID(0x05), 0x12, ID_BYTE_ID(0x06), 0x13,
+ ID_BYTE_ID(0x07), 0x14, ID_BYTE_DATA(0x50),
+ FLAGS_BYTE(1, 1, 1, 1, 1, 1, 1, 1),
+ ID_BYTE_DATA(0x15), 0x16, ID_BYTE_DATA(0x17), 0x18,
+ ID_BYTE_DATA(0x19), 0x1A, ID_BYTE_DATA(0x1B), 0x1C,
+ ID_BYTE_ID(0x20), 0x1D, ID_BYTE_DATA(0x1E), 0x1F,
+ ID_BYTE_DATA(0x20), 0x21, ID_BYTE_DATA(0x22),
+ FLAGS_BYTE(1, 1, 1, 1, 0, 0, 0, 0),
+};
+DATASIZE(buf_mem_align_8id);
+
+static const uint8_t buf_mem_align_st_rst[] = {
+ FSYNC_BYTES(), FSYNC_BYTES(), FSYNC_BYTES(), FSYNC_BYTES(),
+ ID_BYTE_ID(0x10), 0x01, ID_BYTE_DATA(0x02), 0x03,
+ ID_BYTE_DATA(0x04), 0x05, ID_BYTE_DATA(0x06), 0x07,
+ ID_BYTE_ID(0x20), 0x08, ID_BYTE_DATA(0x09), 0x0A,
+ ID_BYTE_DATA(0x0B), 0x0C, ID_BYTE_DATA(0x0D),
+ FLAGS_BYTE(0, 0, 0, 0, 0, 1, 1, 1),
+ ID_BYTE_DATA(0x0E), 0x0F, ID_BYTE_ID(0x30), 0x10,
+ ID_BYTE_DATA(0x11), 0x12, ID_BYTE_DATA(0x13), 0x14,
+ ID_BYTE_DATA(0x15), 0x16, ID_BYTE_ID(0x10), 0x17,
+ ID_BYTE_DATA(0x18), 0x19, ID_BYTE_DATA(0x20),
+ FLAGS_BYTE(0, 0, 1, 1, 1, 1, 0, 0),
+};
+DATASIZE(buf_mem_align_st_rst);
+
+static const uint8_t buf_mem_align_mid_rst[] = {
+ ID_BYTE_ID(0x10), 0x01, ID_BYTE_DATA(0x02), 0x03,
+ ID_BYTE_DATA(0x04), 0x05, ID_BYTE_DATA(0x06), 0x07,
+ ID_BYTE_ID(0x20), 0x08, ID_BYTE_DATA(0x09), 0x0A,
+ ID_BYTE_DATA(0x0B), 0x0C, ID_BYTE_DATA(0x0D),
+ FLAGS_BYTE(0, 0, 0, 0, 0, 1, 1, 1),
+ FSYNC_BYTES(), FSYNC_BYTES(), FSYNC_BYTES(), FSYNC_BYTES(),
+ ID_BYTE_DATA(0x0E), 0x0F, ID_BYTE_ID(0x30), 0x10,
+ ID_BYTE_DATA(0x11), 0x12, ID_BYTE_DATA(0x13), 0x14,
+ ID_BYTE_DATA(0x15), 0x16, ID_BYTE_ID(0x10), 0x17,
+ ID_BYTE_DATA(0x18), 0x19, ID_BYTE_DATA(0x20),
+ FLAGS_BYTE(0, 0, 1, 1, 1, 1, 0, 0),
+};
+DATASIZE(buf_mem_align_mid_rst);
+
+static const uint8_t buf_mem_align_en_rst[] = {
+ ID_BYTE_ID(0x10), 0x01, ID_BYTE_DATA(0x02), 0x03,
+ ID_BYTE_DATA(0x04), 0x05, ID_BYTE_DATA(0x06), 0x07,
+ ID_BYTE_ID(0x20), 0x08, ID_BYTE_DATA(0x09), 0x0A,
+ ID_BYTE_DATA(0x0B), 0x0C, ID_BYTE_DATA(0x0D),
+ FLAGS_BYTE(0, 0, 0, 0, 0, 1, 1, 1),
+ ID_BYTE_DATA(0x0E), 0x0F, ID_BYTE_ID(0x30), 0x10,
+ ID_BYTE_DATA(0x11), 0x12, ID_BYTE_DATA(0x13), 0x14,
+ ID_BYTE_DATA(0x15), 0x16, ID_BYTE_ID(0x10), 0x17,
+ ID_BYTE_DATA(0x18), 0x19, ID_BYTE_DATA(0x20),
+ FLAGS_BYTE(0, 0, 1, 1, 1, 1, 0, 0),
+ FSYNC_BYTES(), FSYNC_BYTES(), FSYNC_BYTES(), FSYNC_BYTES(),
+};
+DATASIZE(buf_mem_align_en_rst);
+
+static const uint8_t buf_bad_data[] = {
+0xff, 0xff, 0xff, 0x7f, 0x30, 0xff, 0x53, 0x54, 0x4d, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0, 0x36, 0xff, 0xb1, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x2b,
+0x36, 0x36, 0x3a, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
+0, 0x2c, 0, 0, 0, 0x32, 0x1, 0,
+};
+DATASIZE(buf_bad_data);
+
+static ocsd_err_t initDecoder(int init_opts)
+{
+ pDecoder = DecodeTree::CreateDecodeTree(OCSD_TRC_SRC_FRAME_FORMATTED, init_opts);
+ if (!pDecoder)
+ return OCSD_ERR_MEM;
+ return OCSD_OK;
+}
+
+static void destroyDecoder()
+{
+ delete pDecoder;
+ pDecoder = 0;
+}
+
+static void printTestHeaderStr(const char* hdr_str)
+{
+ std::ostringstream oss;
+
+ oss << "\n---------------------------------------------------------\n";
+ oss << hdr_str;
+ oss << "\n---------------------------------------------------------\n";
+ logger.LogMsg(oss.str());
+}
+
+static void printSubTestName(const int test_num, const char* name)
+{
+ std::ostringstream oss;
+
+ oss << "\n..Sub Test " << test_num << " : " << name << "\n";
+ logger.LogMsg(oss.str());
+}
+
+static ocsd_err_t setConfig(uint32_t flags)
+{
+ TraceFormatterFrameDecoder* pFmt = pDecoder->getFrameDeformatter();
+ return pFmt->Configure(flags);
+
+}
+
+// fail and print on none RESP_CONT response.
+static ocsd_datapath_resp_t checkDataPathValue(ocsd_datapath_resp_t resp, int& failed_count)
+{
+ if (resp == OCSD_RESP_CONT)
+ return resp;
+
+ std::ostringstream oss;
+ oss << "\nTest Datapath error response: " << ocsdDataRespStr(resp).getStr() << "\n";
+ logger.LogMsg(oss.str());
+ failed_count++;
+ return resp;
+}
+
+static void resetDecoder(int& failed)
+{
+ checkDataPathValue(pDecoder->TraceDataIn(OCSD_OP_RESET, 0, 0, 0, 0), failed);
+}
+
+
+static void checkInOutSizes(const char *test, size_t in, size_t out, int& failed)
+{
+ if (in != out) {
+ failed++;
+ std::ostringstream oss;
+ oss << test << " test failed - mismatch between processed and input sizes:";
+ oss << " In=" << in << "; Out=" << out;
+ logger.LogMsg(oss.str());
+ }
+}
+
+static int checkResult(int failed)
+{
+ std::ostringstream oss;
+ oss << "\nTEST : " << ((failed) ? "FAIL" : "PASS") << "\n";
+ logger.LogMsg(oss.str());
+ return failed;
+}
+static int testDemuxInit()
+{
+ ocsd_err_t err;
+ std::ostringstream oss;
+ int failed = 0;
+
+ printTestHeaderStr("Demux Init Tests - check bad input rejected");
+
+ // init with invalid no flags
+ oss.str("");
+ oss << "\nCheck 0 flag error: ";
+ err = initDecoder(0);
+ if (err) {
+ err = err_log.GetLastError()->getErrorCode();
+ }
+ if (err != OCSD_ERR_INVALID_PARAM_VAL) {
+ oss << "FAIL: expected error code not returned\n";
+ failed++;
+ }
+ else
+ oss << "PASS\n";
+ logger.LogMsg(oss.str());
+
+ // init with invalid unknown flags
+ oss.str("");
+ oss << "\nCheck unknown flag error: ";
+ err = initDecoder(0x80 | OCSD_DFRMTR_FRAME_MEM_ALIGN);
+ if (err) {
+ err = err_log.GetLastError()->getErrorCode();
+ }
+ if (err != OCSD_ERR_INVALID_PARAM_VAL) {
+ oss << "FAIL: expected error code not returned\n";
+ failed++;
+ }
+ else
+ oss << "PASS\n";
+ logger.LogMsg(oss.str());
+
+ // init with bad combo
+ oss.str("");
+ oss << "\nCheck bad combination flag error: ";
+ err = initDecoder(OCSD_DFRMTR_FRAME_MEM_ALIGN | OCSD_DFRMTR_HAS_FSYNCS);
+ if (err) {
+ err = err_log.GetLastError()->getErrorCode();
+ }
+ if (err != OCSD_ERR_INVALID_PARAM_VAL) {
+ oss << "FAIL: expected error code not returned\n";
+ failed++;
+ }
+ else
+ oss << "PASS\n";
+ logger.LogMsg(oss.str());
+
+ return failed;
+}
+
+static int runDemuxBadDataTest()
+{
+
+ int failed = 0;
+ uint32_t processed = 0;
+ std::ostringstream oss;
+ ocsd_datapath_resp_t resp;
+
+ printTestHeaderStr("Demux Bad Data Test - arbitrary test data input");
+
+ setConfig(base_cfg | OCSD_DFRMTR_RESET_ON_4X_FSYNC);
+
+ // reset the decoder.
+ resetDecoder(failed);
+ resp = checkDataPathValue(pDecoder->TraceDataIn(OCSD_OP_DATA, 0, buf_bad_data_sz, buf_bad_data, &processed), failed);
+ if ((resp == OCSD_RESP_FATAL_INVALID_DATA) &&
+ (err_log.GetLastError()->getErrorCode() == OCSD_ERR_DFMTR_BAD_FHSYNC))
+ {
+ failed--; // cancel the fail - we require that the error happens for bad input
+ oss << "Got correct error response for invalid input\n";
+ }
+ else
+ {
+ oss << "Expected error code not returned\n";
+ }
+ logger.LogMsg(oss.str());
+
+ setConfig(base_cfg);
+ return checkResult(failed);
+}
+
+static int runHSyncFSyncTest()
+{
+ uint32_t cfg_flags = base_cfg;
+ uint32_t processed = 0, total = 0;
+ ocsd_trc_index_t index = 0;
+ int failed = 0;
+ ocsd_datapath_resp_t resp;
+ std::ostringstream oss;
+
+ printTestHeaderStr("FSYNC & HSYNC tests: check hander code for TPIU captures works.");
+
+ // set for hsync / fsync operation
+ cfg_flags &= ~OCSD_DFRMTR_FRAME_MEM_ALIGN; // clear mem align
+ cfg_flags |= OCSD_DFRMTR_HAS_HSYNCS | OCSD_DFRMTR_HAS_FSYNCS;
+ setConfig(cfg_flags);
+
+ // straight frame test with fsync + hsync
+ printSubTestName(1, "HSyncFSync frame");
+ resetDecoder(failed);
+ checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, index, buf_hsync_fsync_sz, buf_hsync_fsync, &processed),
+ failed);
+ checkInOutSizes("HSyncFSync frame", buf_hsync_fsync_sz, processed, failed);
+
+ // test fsync broken across 2 input blocks
+ printSubTestName(2, "HSyncFSync split frame");
+ resetDecoder(failed);
+ checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, index, 2, buf_hsync_fsync, &processed),
+ failed);
+ total += processed;
+ index += processed;
+ checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, index, buf_hsync_fsync_sz - processed, buf_hsync_fsync + processed, &processed),
+ failed);
+ total += processed;
+ checkInOutSizes("HSyncFSync split frame", buf_hsync_fsync_sz, total, failed);
+
+ // check bad input data is rejected.
+ printSubTestName(3, "HSyncFSync bad input data");
+ resetDecoder(failed);
+ resp = checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, index, buf_bad_data_sz, buf_bad_data, &processed),
+ failed);
+ if ((resp == OCSD_RESP_FATAL_INVALID_DATA) &&
+ (err_log.GetLastError()->getErrorCode() == OCSD_ERR_DFMTR_BAD_FHSYNC))
+ {
+ failed--; // cancel the fail - we require that the error happens for bad input
+ oss << "Got correct error response for invalid input\n";
+ }
+ else
+ {
+ oss << "Expected error code not returned\n";
+ }
+ logger.LogMsg(oss.str());
+
+
+ setConfig(base_cfg);
+ return checkResult(failed);
+}
+
+static int runMemAlignTest()
+{
+ uint32_t processed = 0;
+ int failed = 0;
+
+ printTestHeaderStr("MemAligned Buffer tests: exercise the 16 byte frame buffer handler");
+
+ // default decoder set to mem align so just run the test.
+
+ // straight frame pair
+ printSubTestName(1, "MemAlignFrame");
+ resetDecoder(failed);
+ checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, 0, buf_mem_align_sz, buf_mem_align, &processed),
+ failed);
+ checkInOutSizes("MemAlignFrame", buf_mem_align_sz, processed, failed);
+
+ // frame with 8 id test
+ printSubTestName(2, "MemAlignFrame-8-ID");
+ resetDecoder(failed);
+ checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, 0, buf_mem_align_8id_sz, buf_mem_align_8id, &processed),
+ failed);
+ checkInOutSizes("MemAlignFrame-8-ID", buf_mem_align_8id_sz, processed, failed);
+
+ // check reset FSYNC frame handling
+ setConfig(base_cfg | OCSD_DFRMTR_RESET_ON_4X_FSYNC);
+ printSubTestName(3, "MemAlignFrame-rst_st");
+ resetDecoder(failed);
+ checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, 0, buf_mem_align_st_rst_sz, buf_mem_align_st_rst, &processed),
+ failed);
+ checkInOutSizes("MemAlignFrame-rst_st", buf_mem_align_st_rst_sz, processed, failed);
+
+ printSubTestName(4, "MemAlignFrame-rst_mid");
+ resetDecoder(failed);
+ checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, 0, buf_mem_align_mid_rst_sz, buf_mem_align_mid_rst, &processed),
+ failed);
+ checkInOutSizes("MemAlignFrame-rst_mid", buf_mem_align_mid_rst_sz, processed, failed);
+
+ printSubTestName(5, "MemAlignFrame-rst_en");
+ resetDecoder(failed);
+ checkDataPathValue(
+ pDecoder->TraceDataIn(OCSD_OP_DATA, 0, buf_mem_align_en_rst_sz, buf_mem_align_en_rst, &processed),
+ failed);
+ checkInOutSizes("MemAlignFrame-rst_en", buf_mem_align_en_rst_sz, processed, failed);
+
+ setConfig(base_cfg);
+ return checkResult(failed);
+}
+
+int main(int argc, char* argv[])
+{
+ int failed = 0;
+ ocsd_err_t err;
+ std::ostringstream moss;
+ RawFramePrinter* framePrinter = 0;
+
+ /* initialise logger */
+
+ static const int logOpts = ocsdMsgLogger::OUT_STDOUT | ocsdMsgLogger::OUT_FILE;
+
+ logger.setLogOpts(logOpts);
+ logger.setLogFileName("frame_demux_test.ppl");
+ moss << "---------------------------------------------------------\n";
+ moss << "Trace Demux Frame Test - check CoreSight frame processing\n";
+ moss << "---------------------------------------------------------\n\n";
+ moss << "** Library Version : " << ocsdVersion::vers_str() << "\n\n";
+ logger.LogMsg(moss.str());
+
+ /* initialise error logger */
+ err_log.initErrorLogger(OCSD_ERR_SEV_INFO);
+ err_log.setOutputLogger(&logger);
+ DecodeTree::setAlternateErrorLogger(&err_log);
+
+ /* run the init tests */
+ failed += testDemuxInit();
+
+ /* create a decoder for the remainder of the tests */
+ err = initDecoder(base_cfg);
+ moss.str("");
+ moss << "Creating Decoder for active Demux testing\n";
+ if (!err && pDecoder) {
+ err = pDecoder->addRawFramePrinter(&framePrinter, OCSD_DFRMTR_PACKED_RAW_OUT | OCSD_DFRMTR_UNPACKED_RAW_OUT);
+ if (err)
+ moss << "Failed to add Frame printer\n";
+ }
+ if (err || !pDecoder) {
+
+ moss << "Failed to initialise decoder for remainder of the tests\nSkipping active demux tests\n";
+ failed++;
+ }
+
+ /* remainder of the tests that need an active decoder */
+ if (!err) {
+ try {
+ failed += runMemAlignTest();
+ failed += runHSyncFSyncTest();
+ failed += runDemuxBadDataTest();
+ }
+ catch (ocsdError& err) {
+ moss.str("");
+ moss << "*** TEST ERROR: Unhandled error from tests. Aborting test run ***\n";
+ moss << err.getErrorString(err) << "\n";
+ logger.LogMsg(moss.str());
+ failed++;
+ }
+ }
+
+ /* testing done */
+ moss.str("");
+ moss << "\n\n---------------------------------------------------------\n";
+ moss << "Trace Demux Testing Complete\n";
+ if (failed)
+ moss << "FAILED: recorded " << failed << " errors or failures.\n";
+ else
+ moss << "PASSED ALL tests\n";
+ moss << "\n\n---------------------------------------------------------\n";
+
+ logger.LogMsg(moss.str());
+
+ if (pDecoder)
+ destroyDecoder();
+
+ return failed ? -1 : 0;
+}
diff --git a/decoder/tests/source/mem_buff_demo.cpp b/decoder/tests/source/mem_buff_demo.cpp
new file mode 100644
index 0000000..052870f
--- /dev/null
+++ b/decoder/tests/source/mem_buff_demo.cpp
@@ -0,0 +1,421 @@
+/*
+* \file mem_buff_demo.cpp
+* \brief OpenCSD: using the library with memory buffers for data.
+*
+* \copyright Copyright (c) 2018, ARM Limited. All Rights Reserved.
+*/
+
+/*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its contributors
+* may be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Example showing techniques to drive library using only memory buffers as input data
+ * and image data, avoiding file i/o in main processing routines. (File I/O used to
+ * initially populate buffers but this can be replaced if data is generated by a client
+ * environment running live.)
+ */
+
+#include <cstdio>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <cstring>
+
+#include "opencsd.h" // the library
+
+// uncomment below to use callback function for program memory image
+// #define EXAMPLE_USE_MEM_CALLBACK
+
+/* Input trace buffer */
+static uint8_t *input_trace_data = 0;
+static uint32_t input_trace_data_size = 0;
+
+/* program memory image for decode */
+static uint8_t *program_image_buffer = 0; // buffer for image data.
+static uint32_t program_image_size = 0; // size of program image data.
+static ocsd_vaddr_t program_image_address = 0; // load address on target of program image.
+
+/* a message logger to pass to the error logger / decoder. */
+static ocsdMsgLogger logger;
+
+/* logger callback function - print out error strings */
+class logCallback : public ocsdMsgLogStrOutI
+{
+public:
+ logCallback() {};
+ virtual ~logCallback() {};
+ virtual void printOutStr(const std::string &outStr)
+ {
+ std::cout << outStr.c_str();
+ }
+};
+static logCallback logCB;
+
+/* Decode tree is the main decoder framework - contains the frame unpacker,
+ packet and trace stream decoders, plus memory image references */
+static DecodeTree *pDecoder = 0;
+
+/* an error logger - Decode tree registers all components with the error logger
+so that errors can be correctly attributed and printed if required
+*/
+static ocsdDefaultErrorLogger err_log;
+
+/* callbacks used by the library */
+#ifdef EXAMPLE_USE_MEM_CALLBACK
+// program memory image callback definition
+uint32_t mem_access_callback_fn(const void *p_context, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer);
+#endif
+
+// callback for the decoder output elements
+class DecoderOutputProcessor : public ITrcGenElemIn
+{
+public:
+ DecoderOutputProcessor() {};
+ virtual ~DecoderOutputProcessor() {};
+
+ virtual ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop,
+ const uint8_t trc_chan_id,
+ const OcsdTraceElement &elem)
+ {
+ // must fully process or make a copy of data in here.
+ // element reference only valid for scope of call.
+
+ // for the example program we will stringise and print -
+ // but this is a client program implmentation dependent.
+ std::string elemStr;
+ std::ostringstream oss;
+ oss << "Idx:" << index_sop << "; ID:" << std::hex << (uint32_t)trc_chan_id << "; ";
+ elem.toString(elemStr);
+ oss << elemStr << std::endl;
+ logger.LogMsg(oss.str());
+ return OCSD_RESP_CONT;
+ }
+};
+static DecoderOutputProcessor output;
+
+/* for test purposes we are initialising from files, but this could be generated test data as
+ part of a larger program and / or compiled in memory images.
+
+ We have hardcoded in one of the snapshots supplied with the library
+ */
+static int initDataBuffers()
+{
+ FILE *fp;
+ std::string filename;
+ long size;
+ size_t bytes_read;
+
+ /* the file names to create the data buffers */
+#ifdef _WIN32
+ static const char *default_base_snapshot_path = "..\\..\\..\\snapshots";
+ static const char *juno_snapshot = "\\juno_r1_1\\";
+#else
+ static const char *default_base_snapshot_path = "../../../snapshots";
+ static const char *juno_snapshot = "/juno_r1_1/";
+#endif
+
+ /* trace data and memory file dump names and values - taken from snapshot metadata */
+ static const char *trace_data_filename = "cstrace.bin";
+ static const char *memory_dump_filename = "kernel_dump.bin";
+ static ocsd_vaddr_t mem_dump_address = 0xFFFFFFC000081000;
+
+ /* load up the trace data */
+ filename = default_base_snapshot_path;
+ filename += (std::string)juno_snapshot;
+ filename += (std::string)trace_data_filename;
+
+ fp = fopen(filename.c_str(), "rb");
+ if (!fp)
+ return OCSD_ERR_FILE_ERROR;
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ input_trace_data_size = (uint32_t)size;
+ input_trace_data = new (std::nothrow) uint8_t[input_trace_data_size];
+ if (!input_trace_data) {
+ fclose(fp);
+ return OCSD_ERR_MEM;
+ }
+ rewind(fp);
+ bytes_read = fread(input_trace_data, 1, input_trace_data_size, fp);
+ fclose(fp);
+ if (bytes_read < (size_t)input_trace_data_size)
+ return OCSD_ERR_FILE_ERROR;
+
+ /* load up a memory image */
+ filename = default_base_snapshot_path;
+ filename += (std::string)juno_snapshot;
+ filename += (std::string)memory_dump_filename;
+
+ fp = fopen(filename.c_str(), "rb");
+ if (!fp)
+ return OCSD_ERR_FILE_ERROR;
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ program_image_size = (uint32_t)size;
+ program_image_buffer = new (std::nothrow) uint8_t[program_image_size];
+ if (!program_image_buffer) {
+ fclose(fp);
+ return OCSD_ERR_MEM;
+ }
+ rewind(fp);
+ bytes_read = fread(program_image_buffer, 1, program_image_size, fp);
+ fclose(fp);
+ if (bytes_read < (size_t)program_image_size)
+ return OCSD_ERR_FILE_ERROR;
+ program_image_address = mem_dump_address;
+ return OCSD_OK;
+}
+
+static ocsd_err_t createETMv4StreamDecoder()
+{
+ ocsd_etmv4_cfg trace_config;
+ ocsd_err_t err = OCSD_OK;
+ EtmV4Config *pCfg = 0;
+
+ /*
+ * populate the ETMv4 configuration structure with
+ * hard coded values from snapshot .ini files.
+ */
+
+ trace_config.arch_ver = ARCH_V8;
+ trace_config.core_prof = profile_CortexA;
+
+ trace_config.reg_configr = 0x000000C1;
+ trace_config.reg_traceidr = 0x00000010; /* this is the trace ID -> 0x10, change this to analyse other streams in snapshot.*/
+ trace_config.reg_idr0 = 0x28000EA1;
+ trace_config.reg_idr1 = 0x4100F403;
+ trace_config.reg_idr2 = 0x00000488;
+ trace_config.reg_idr8 = 0x0;
+ trace_config.reg_idr9 = 0x0;
+ trace_config.reg_idr10 = 0x0;
+ trace_config.reg_idr11 = 0x0;
+ trace_config.reg_idr12 = 0x0;
+ trace_config.reg_idr13 = 0x0;
+
+ pCfg = new (std::nothrow) EtmV4Config(&trace_config);
+ if (!pCfg)
+ return OCSD_ERR_MEM;
+
+ err = pDecoder->createDecoder(OCSD_BUILTIN_DCD_ETMV4I, /* etm v4 decoder */
+ OCSD_CREATE_FLG_FULL_DECODER, /* full trace decode */
+ pCfg);
+ delete pCfg;
+ return err;
+}
+
+/* Create the decode tree and add the error logger, stream decoder, memory image data to it.
+ Also register the output callback that processes the decoded trace packets. */
+static ocsd_err_t initialiseDecoder()
+{
+ ocsd_err_t ret = OCSD_OK;
+
+ /* use the creation function to get the type of decoder we want
+ either OCSD_TRC_SRC_SINGLE : single trace source - not frame formatted
+ OCSD_TRC_SRC_FRAME_FORMATTED :multi source - CoreSight trace frame
+ and set the config flags for operation
+ OCSD_DFRMTR_FRAME_MEM_ALIGN: input data mem aligned -> no syncs
+
+ For this test we create a decode that can unpack frames and is not expecting sync packets.
+ */
+ pDecoder = DecodeTree::CreateDecodeTree(OCSD_TRC_SRC_FRAME_FORMATTED, OCSD_DFRMTR_FRAME_MEM_ALIGN);
+ if (!pDecoder)
+ return OCSD_ERR_MEM;
+
+ /* set up decoder logging - the message logger for output, and the error logger for the library */
+ logger.setLogOpts(ocsdMsgLogger::OUT_STR_CB); /* no IO from the logger, just a string callback. */
+ logger.setStrOutFn(&logCB); /* set the callback - in this example it will go to stdio but this is up to the implementor. */
+
+ // for debugging - stdio and file
+// logger.setLogOpts(ocsdMsgLogger::OUT_FILE | ocsdMsgLogger::OUT_STDOUT);
+
+ err_log.initErrorLogger(OCSD_ERR_SEV_INFO);
+ err_log.setOutputLogger(&logger); /* pass the output logger to the error logger. */
+
+ pDecoder->setAlternateErrorLogger(&err_log); /* pass the error logger to the decoder, do not use the library version. */
+
+ /* now set up the elements that the decoder needs */
+
+ /* we will decode one of the streams in this example
+ create a Full decode ETMv4 stream decoder */
+ ret = createETMv4StreamDecoder();
+ if (ret != OCSD_OK)
+ return ret;
+
+ /* as this has full decode we must supply a memory image. */
+
+ ret = pDecoder->createMemAccMapper(); // the mapper is needed to add code images to.
+ if (ret != OCSD_OK)
+ return ret;
+
+#ifdef EXAMPLE_USE_MEM_CALLBACK
+ // in this example we have a single buffer so we demonstrate how to use a callback.
+ // we are passing the buffer pointer as context as we only have one buffer, but this
+ // could be a structure that is a list of memory image buffers. Context is entirely
+ // client defined.
+ // Always use OCSD_MEM_SPACE_ANY unless there is a reason to restrict the image to a specific
+ // memory space.
+ pDecoder->addCallbackMemAcc(program_image_address, program_image_address + program_image_size-1,
+ OCSD_MEM_SPACE_ANY,mem_access_callback_fn, program_image_buffer);
+#else
+ // or we can use the built in memory buffer interface - split our one buffer into two to
+ // demonstrate the addition of multiple regions
+ ocsd_vaddr_t block1_st, block2_st;
+ uint32_t block1_sz, block2_sz;
+ uint8_t *p_block1, *p_block2;
+
+ // break our single buffer into 2 buffers for demo purposes
+ block1_sz = program_image_size / 2;
+ block1_sz &= ~0x3; // align
+ block2_sz = program_image_size - block1_sz;
+ block1_st = program_image_address; // loaded program memory start address of program
+ block2_st = program_image_address + block1_sz;
+ p_block1 = program_image_buffer;
+ p_block2 = program_image_buffer + block1_sz;
+
+ /* how to add 2 "separate" buffers to the decoder */
+ // Always use OCSD_MEM_SPACE_ANY unless there is a reason to restrict the image to a specific
+ // memory space.
+ ret = pDecoder->addBufferMemAcc(block1_st, OCSD_MEM_SPACE_ANY, p_block1, block1_sz);
+ if (ret != OCSD_OK)
+ return ret;
+
+ ret = pDecoder->addBufferMemAcc(block2_st, OCSD_MEM_SPACE_ANY, p_block2, block2_sz);
+ if (ret != OCSD_OK)
+ return ret;
+#endif
+
+ /* finally we need to provide an output callback to recieve the decoded information */
+ pDecoder->setGenTraceElemOutI(&output);
+ return ret;
+}
+
+/* get rid of the objects we created */
+static void destroyDecoder()
+{
+ delete pDecoder;
+ delete [] input_trace_data;
+ delete [] program_image_buffer;
+}
+
+#ifdef EXAMPLE_USE_MEM_CALLBACK
+/* if we set up to use a callback to access memory image then this is what will be called. */
+/* In this case the client must do all the work in determining if the requested address is in the
+ memory area. */
+uint32_t mem_access_callback_fn(const void *p_context, const ocsd_vaddr_t address,
+ const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer)
+{
+ ocsd_vaddr_t buf_end_address = program_image_address + program_image_size - 1;
+ uint32_t read_bytes = reqBytes;
+
+ /* context should be our memory image buffer - if not return 0 bytes read */
+ if (p_context != program_image_buffer)
+ return 0;
+
+ /* not concerned with memory spaces - assume all global */
+ if ((address < program_image_address) || (address > buf_end_address))
+ return 0; // requested address not in our buffer.
+
+ // if requested bytes from address more than we have, only read to end of buffer
+ if ((address + reqBytes - 1) > buf_end_address)
+ read_bytes = (uint32_t)(buf_end_address - (address - 1));
+
+ // copy the requested data.
+ memcpy(byteBuffer, program_image_buffer + (address - program_image_address), read_bytes);
+
+ return read_bytes;
+}
+#endif
+
+/* use the decoder to process the global trace data buffer */
+static ocsd_datapath_resp_t processTraceData(uint32_t *bytes_done)
+{
+ /* process in blocks of fixed size. */
+ #define DATA_CHUNK_SIZE 2048
+
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ uint32_t block_size, buff_offset, bytes_to_do = input_trace_data_size, bytes_processed;
+ ocsd_trc_index_t index = 0;
+
+ /* process the data in chunks, until either all done or
+ * error occurs.
+ */
+ while ((resp == OCSD_RESP_CONT) && (bytes_to_do))
+ {
+ /* size up a block of input data */
+ block_size = (bytes_to_do >= DATA_CHUNK_SIZE) ? DATA_CHUNK_SIZE : bytes_to_do;
+ buff_offset = input_trace_data_size - bytes_to_do;
+
+ /* push it through the decoder */
+ resp = pDecoder->TraceDataIn(OCSD_OP_DATA, index, block_size,
+ input_trace_data + buff_offset, &bytes_processed);
+
+ /* adjust counter per bytes processed */
+ bytes_to_do -= bytes_processed;
+ index += bytes_processed;
+ }
+
+ /* if all done then signal end of trace - flushes out any remaining data */
+ if (!bytes_to_do)
+ resp = pDecoder->TraceDataIn(OCSD_OP_EOT, 0, 0, 0, 0);
+
+ /* return amount processed */
+ *bytes_done = input_trace_data_size - bytes_to_do;
+ return resp;
+}
+
+/* main routine - init input data, decode, finish ... */
+int main(int argc, char* argv[])
+{
+ int ret = OCSD_OK;
+ ocsd_datapath_resp_t retd;
+ char msg[256];
+ uint32_t bytes_done;
+
+ /* initialise all the data needed for decode */
+ if ((ret = initDataBuffers()) != OCSD_OK)
+ {
+ logger.LogMsg("Failed to create trace data buffers\n");
+ return ret;
+ }
+ /* initialise a decoder object */
+ if ((ret = initialiseDecoder()) == OCSD_OK)
+ {
+ retd = processTraceData(&bytes_done);
+ if (!OCSD_DATA_RESP_IS_CONT(retd))
+ {
+ ret = OCSD_ERR_DATA_DECODE_FATAL;
+ logger.LogMsg("Processing failed with data error\n");
+ }
+
+ /* get rid of the decoder and print a brief result. */
+ destroyDecoder();
+ sprintf(msg, "Processed %u bytes out of %u\n", bytes_done, input_trace_data_size);
+ logger.LogMsg(msg);
+ }
+ else
+ logger.LogMsg("Failed to create decoder for trace processing\n");
+ return ret;
+}
diff --git a/decoder/tests/source/trc_pkt_lister.cpp b/decoder/tests/source/trc_pkt_lister.cpp
new file mode 100644
index 0000000..9760351
--- /dev/null
+++ b/decoder/tests/source/trc_pkt_lister.cpp
@@ -0,0 +1,767 @@
+/*
+ * \file trc_pkt_lister.cpp
+ * \brief OpenCSD : Trace Packet Lister Test program
+ *
+ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
+ */
+
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Test program / utility - list trace packets in supplied snapshot. */
+
+#include <cstdio>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <cstring>
+
+#include "opencsd.h" // the library
+#include "trace_snapshots.h" // the snapshot reading test library
+
+static bool process_cmd_line_opts( int argc, char* argv[]);
+static void ListTracePackets(ocsdDefaultErrorLogger &err_logger, SnapShotReader &reader, const std::string &trace_buffer_name);
+static bool process_cmd_line_logger_opts(int argc, char* argv[]);
+static void log_cmd_line_opts(int argc, char* argv[]);
+
+ // default path
+#ifdef WIN32
+static std::string ss_path = ".\\";
+#else
+static std::string ss_path = "./";
+#endif
+
+static std::string source_buffer_name = ""; // source name - used if more than one source
+static bool all_source_ids = true; // output all IDs in source.
+static std::vector<uint8_t> id_list; // output specific IDs in source
+
+static ocsdMsgLogger logger;
+static int logOpts = ocsdMsgLogger::OUT_STDOUT | ocsdMsgLogger::OUT_FILE;
+static std::string logfileName = "trc_pkt_lister.ppl";
+static bool outRawPacked = false;
+static bool outRawUnpacked = false;
+static bool ss_verbose = false;
+static bool decode = false;
+static bool no_undecoded_packets = false;
+static bool pkt_mon = false;
+static int test_waits = 0;
+static bool dstream_format = false;
+static bool tpiu_format = false;
+static bool has_hsync = false;
+static bool src_addr_n = false;
+static bool stats = false;
+
+int main(int argc, char* argv[])
+{
+ std::ostringstream moss;
+
+ if(process_cmd_line_logger_opts(argc,argv))
+ {
+ printf("Bad logger command line options\nProgram Exiting\n");
+ return -2;
+ }
+
+ logger.setLogOpts(logOpts);
+ logger.setLogFileName(logfileName.c_str());
+
+ moss << "Trace Packet Lister: CS Decode library testing\n";
+ moss << "-----------------------------------------------\n\n";
+ moss << "** Library Version : " << ocsdVersion::vers_str() << "\n\n";
+ logger.LogMsg(moss.str());
+
+ log_cmd_line_opts(argc,argv);
+
+ ocsdDefaultErrorLogger err_log;
+ err_log.initErrorLogger(OCSD_ERR_SEV_INFO);
+ err_log.setOutputLogger(&logger);
+
+ if(!process_cmd_line_opts(argc, argv))
+ return -1;
+
+ moss.str("");
+ moss << "Trace Packet Lister : reading snapshot from path " << ss_path << "\n";
+ logger.LogMsg(moss.str());
+
+ SnapShotReader ss_reader;
+ ss_reader.setSnapshotDir(ss_path);
+ ss_reader.setErrorLogger(&err_log);
+ ss_reader.setVerboseOutput(ss_verbose);
+
+ if(ss_reader.snapshotFound())
+ {
+ if(ss_reader.readSnapShot())
+ {
+ std::vector<std::string> sourceBuffList;
+ if(ss_reader.getSourceBufferNameList(sourceBuffList))
+ {
+ bool bValidSourceName = false;
+ // check source name list
+ if(source_buffer_name.size() == 0)
+ {
+ // default to first in the list
+ source_buffer_name = sourceBuffList[0];
+ bValidSourceName = true;
+ }
+ else
+ {
+ for(size_t i = 0; i < sourceBuffList.size(); i++)
+ {
+ if(sourceBuffList[i] == source_buffer_name)
+ {
+ bValidSourceName = true;
+ break;
+ }
+ }
+ }
+
+ if(bValidSourceName)
+ {
+ std::ostringstream oss;
+ oss << "Using " << source_buffer_name << " as trace source\n";
+ logger.LogMsg(oss.str());
+ ListTracePackets(err_log,ss_reader,source_buffer_name);
+ }
+ else
+ {
+ std::ostringstream oss;
+ oss << "Trace Packet Lister : Trace source name " << source_buffer_name << " not found\n";
+ logger.LogMsg(oss.str());
+ oss.str("");
+ oss << "Valid source names are:-\n";
+ for(size_t i = 0; i < sourceBuffList.size(); i++)
+ {
+ oss << sourceBuffList[i] << "\n";
+ }
+ logger.LogMsg(oss.str());
+ }
+
+ }
+ else
+ logger.LogMsg("Trace Packet Lister : No trace source buffer names found\n");
+ }
+ else
+ logger.LogMsg("Trace Packet Lister : Failed to read snapshot\n");
+ }
+ else
+ {
+ std::ostringstream oss;
+ oss << "Trace Packet Lister : Snapshot path" << ss_path << " not found\n";
+ logger.LogMsg(oss.str());
+ }
+
+ return 0;
+}
+
+void print_help()
+{
+ std::ostringstream oss;
+ oss << "Trace Packet Lister - commands\n\n";
+ oss << "Snapshot:\n\n";
+ oss << "-ss_dir <dir> Set the directory path to a trace snapshot\n";
+ oss << "-ss_verbose Verbose output when reading the snapshot\n";
+ oss << "\nDecode:\n\n";
+ oss << "-id <n> Set an ID to list (may be used multiple times) - default if no id set is for all IDs to be printed\n";
+ oss << "-src_name <name> List packets from a given snapshot source name (defaults to first source found)\n";
+ oss << "-dstream_format Input is DSTREAM framed.\n";
+ oss << "-tpiu Input from TPIU - sync by FSYNC.\n";
+ oss << "-tpiu_hsync Input from TPIU - sync by FSYNC and HSYNC.\n";
+ oss << "-decode Full decode of the packets from the trace snapshot (default is to list undecoded packets only\n";
+ oss << "-decode_only Does not list the undecoded packets, just the trace decode.\n";
+ oss << "-o_raw_packed Output raw packed trace frames\n";
+ oss << "-o_raw_unpacked Output raw unpacked trace data per ID\n";
+ oss << "-test_waits <N> Force wait from packet printer for N packets - test the wait/flush mechanisms for the decoder\n";
+ oss << "-src_addr_n ETE protocol: Split source address ranges on N atoms\n";
+ oss << "-stats Output packet processing statistics (if available).\n";
+ oss << "\nOutput:\n";
+ oss << " Setting any of these options cancels the default output to file & stdout,\n using _only_ the options supplied.\n\n";
+ oss << "-logstdout Output to stdout -> console.\n";
+ oss << "-logstderr Output to stderr.\n";
+ oss << "-logfile Output to default file - " << logfileName << "\n";
+ oss << "-logfilename <name> Output to file <name> \n";
+
+
+ logger.LogMsg(oss.str());
+}
+
+void log_cmd_line_opts(int argc, char* argv[])
+{
+ std::ostringstream oss;
+ oss << "Test Command Line:-\n";
+ oss << argv[0] << " ";
+ for(int i = 1; i < argc; i++)
+ {
+ oss << argv[i] << " ";
+ }
+ oss << "\n\n";
+ logger.LogMsg(oss.str());
+}
+
+// true if element ID filtered out
+bool element_filtered(uint8_t elemID)
+{
+ bool filtered = false;
+ if(!all_source_ids)
+ {
+ filtered = true;
+ std::vector<uint8_t>::const_iterator it;
+ it = id_list.begin();
+ while((it != id_list.end()) && filtered)
+ {
+ if(*it == elemID)
+ filtered = false;
+ it++;
+ }
+ }
+ return filtered;
+}
+
+bool process_cmd_line_logger_opts(int argc, char* argv[])
+{
+ bool badLoggerOpts = false;
+ bool bChangingOptFlags = false;
+ int newlogOpts = ocsdMsgLogger::OUT_NONE;
+ std::string opt;
+ if(argc > 1)
+ {
+ int options_to_process = argc - 1;
+ int optIdx = 1;
+ while(options_to_process > 0)
+ {
+ opt = argv[optIdx];
+ if(opt == "-logstdout")
+ {
+ newlogOpts |= ocsdMsgLogger::OUT_STDOUT;
+ bChangingOptFlags = true;
+ }
+ else if(opt == "-logstderr")
+ {
+ newlogOpts |= ocsdMsgLogger::OUT_STDERR;
+ bChangingOptFlags = true;
+ }
+ else if(opt == "-logfile")
+ {
+ newlogOpts |= ocsdMsgLogger::OUT_FILE;
+ bChangingOptFlags = true;
+ }
+ else if(opt == "-logfilename")
+ {
+ options_to_process--;
+ optIdx++;
+ if(options_to_process)
+ {
+ logfileName = argv[optIdx];
+ newlogOpts |= ocsdMsgLogger::OUT_FILE;
+ bChangingOptFlags = true;
+ }
+ else
+ {
+ badLoggerOpts = true;
+ }
+ }
+ options_to_process--;
+ optIdx++;
+ }
+ }
+ if(bChangingOptFlags)
+ logOpts = newlogOpts;
+ return badLoggerOpts;
+}
+
+bool process_cmd_line_opts(int argc, char* argv[])
+{
+ bool bOptsOK = true;
+ std::string opt;
+ if(argc > 1)
+ {
+ int options_to_process = argc - 1;
+ int optIdx = 1;
+ while((options_to_process > 0) && bOptsOK)
+ {
+ opt = argv[optIdx];
+ if(opt == "-ss_dir")
+ {
+ options_to_process--;
+ optIdx++;
+ if(options_to_process)
+ ss_path = argv[optIdx];
+ else
+ {
+ logger.LogMsg("Trace Packet Lister : Error: Missing directory string on -ss_dir option\n");
+ bOptsOK = false;
+ }
+ }
+ else if(opt == "-id")
+ {
+ options_to_process--;
+ optIdx++;
+ if(options_to_process)
+ {
+ uint8_t Id = (uint8_t)strtoul(argv[optIdx],0,0);
+ if((Id == 0) || (Id >= 0x70))
+ {
+ std::ostringstream iderrstr;
+ iderrstr << "Trace Packet Lister : Error: invalid ID number 0x" << std::hex << (uint32_t)Id << " on -id option" << std::endl;
+ logger.LogMsg(iderrstr.str());
+ bOptsOK = false;
+ }
+ else
+ {
+ all_source_ids = false;
+ id_list.push_back(Id);
+ }
+ }
+ else
+ {
+ logger.LogMsg("Trace Packet Lister : Error: No ID number on -id option\n");
+ bOptsOK = false;
+ }
+ }
+ else if(strcmp(argv[optIdx], "-src_name") == 0)
+ {
+ options_to_process--;
+ optIdx++;
+ if(options_to_process)
+ source_buffer_name = argv[optIdx];
+ else
+ {
+ logger.LogMsg("Trace Packet Lister : Error: Missing source name string on -src_name option\n");
+ bOptsOK = false;
+ }
+ }
+ else if(strcmp(argv[optIdx], "-test_waits") == 0)
+ {
+ options_to_process--;
+ optIdx++;
+ if(options_to_process)
+ {
+ test_waits = (int)strtol(argv[optIdx],0,0);
+ if(test_waits < 0)
+ test_waits = 0;
+ }
+ else
+ {
+ logger.LogMsg("Trace Packet Lister : Error: wait count value on -test_waits option\n");
+ bOptsOK = false;
+ }
+ }
+ else if(strcmp(argv[optIdx], "-o_raw_packed") == 0)
+ {
+ outRawPacked = true;
+ }
+ else if(strcmp(argv[optIdx], "-o_raw_unpacked") == 0)
+ {
+ outRawUnpacked = true;
+ }
+ else if(strcmp(argv[optIdx], "-ss_verbose") == 0)
+ {
+ ss_verbose = true;
+ }
+ else if(strcmp(argv[optIdx], "-decode") == 0)
+ {
+ decode = true;
+ }
+ else if(strcmp(argv[optIdx], "-pkt_mon") == 0)
+ {
+ pkt_mon = true;
+ }
+ else if(strcmp(argv[optIdx], "-decode_only") == 0)
+ {
+ no_undecoded_packets = true;
+ decode = true;
+ }
+ else if (strcmp(argv[optIdx], "-src_addr_n") == 0)
+ {
+ src_addr_n = true;
+ }
+ else if (strcmp(argv[optIdx], "-stats") == 0)
+ {
+ stats = true;
+ }
+ else if((strcmp(argv[optIdx], "-help") == 0) || (strcmp(argv[optIdx], "--help") == 0) || (strcmp(argv[optIdx], "-h") == 0))
+ {
+ print_help();
+ bOptsOK = false;
+ }
+ else if((opt == "-logstdout") || (opt == "-logstderr") ||
+ (opt == "-logfile") || (opt == "-logfilename"))
+ {
+ // skip all these as processed earlier
+
+ // also additionally skip any filename parameter
+ if(opt == "-logfilename")
+ {
+ options_to_process--;
+ optIdx++;
+ }
+ }
+ else if (strcmp(argv[optIdx], "-dstream_format") == 0)
+ {
+ dstream_format = true;
+ }
+ else if (strcmp(argv[optIdx], "-tpiu") == 0)
+ {
+ tpiu_format = true;
+ }
+ else if (strcmp(argv[optIdx], "-tpiu_hsync") == 0)
+ {
+ has_hsync = true;
+ tpiu_format = true;
+ }
+ else
+ {
+ std::ostringstream errstr;
+ errstr << "Trace Packet Lister : Warning: Ignored unknown option " << argv[optIdx] << "." << std::endl;
+ logger.LogMsg(errstr.str());
+ }
+ options_to_process--;
+ optIdx++;
+ }
+
+ }
+ return bOptsOK;
+}
+
+//
+// if decoding the gen elem printer will be injecting waits, but we may ge a cont from the packet processors if a complete packet is not available.
+// if packet processing only, then waits will be coming from there until the count is extinguished
+// wait testing with packet processor only really works correctly if we are doing a single source as there is no way at this
+// point to know which source has sent the _WAIT. with multi packet processor waiting may get false warnings once the _WAITs run out.
+bool ExpectingPPrintWaitResp(DecodeTree *dcd_tree, TrcGenericElementPrinter &genElemPrinter)
+{
+ bool ExpectingWaits = false;
+ std::vector<ItemPrinter *> &printers = dcd_tree->getPrinterList();
+ if(test_waits > 0)
+ {
+ // see if last response was from the Gen elem printer expecting a wait
+ ExpectingWaits = genElemPrinter.needAckWait();
+
+ // now see if any of the active packet printers are returing wait responses.
+ if(!ExpectingWaits)
+ {
+ std::vector<ItemPrinter *>::iterator it;
+ it = printers.begin();
+ while((it != printers.end()) && !ExpectingWaits)
+ {
+ ExpectingWaits = (bool)((*it)->getTestWaits() != 0);
+ it++;
+ }
+ }
+
+ // nothing waiting - and no outstanding wait cycles in the Gen elem printer.
+ if(!ExpectingWaits && (genElemPrinter.getTestWaits() == 0))
+ test_waits = 0; // zero out the input value if none of the printers currently have waits scheduled.
+ }
+ return ExpectingWaits;
+}
+
+void AttachPacketPrinters( DecodeTree *dcd_tree)
+{
+ uint8_t elemID;
+ std::ostringstream oss;
+
+ // attach packet printers to each trace source in the tree
+ DecodeTreeElement *pElement = dcd_tree->getFirstElement(elemID);
+ while(pElement && !no_undecoded_packets)
+ {
+ if(!element_filtered(elemID))
+ {
+ oss.str("");
+
+ ItemPrinter *pPrinter;
+ ocsd_err_t err = dcd_tree->addPacketPrinter(elemID, (bool)(decode || pkt_mon),&pPrinter);
+ if (err == OCSD_OK)
+ {
+ // if not decoding or monitor only
+ if((!(decode || pkt_mon)) && test_waits)
+ pPrinter->setTestWaits(test_waits);
+
+ oss << "Trace Packet Lister : Protocol printer " << pElement->getDecoderTypeName() << " on Trace ID 0x" << std::hex << (uint32_t)elemID << "\n";
+ }
+ else
+ oss << "Trace Packet Lister : Failed to Protocol printer " << pElement->getDecoderTypeName() << " on Trace ID 0x" << std::hex << (uint32_t)elemID << "\n";
+ logger.LogMsg(oss.str());
+
+ }
+ pElement = dcd_tree->getNextElement(elemID);
+ }
+
+}
+
+void ConfigureFrameDeMux(DecodeTree *dcd_tree, RawFramePrinter **framePrinter)
+{
+ // configure the frame deformatter, and attach a frame printer to the frame deformatter if needed
+ TraceFormatterFrameDecoder *pDeformatter = dcd_tree->getFrameDeformatter();
+ if(pDeformatter != 0)
+ {
+ // configuration - memory alinged buffer
+ uint32_t configFlags = pDeformatter->getConfigFlags();
+
+ // check for TPIU FSYNC & HSYNC
+ if (tpiu_format) configFlags |= OCSD_DFRMTR_HAS_FSYNCS;
+ if (has_hsync) configFlags |= OCSD_DFRMTR_HAS_HSYNCS;
+ // if FSYNC (& HSYNC) - cannot be mem frame aligned.
+ if (tpiu_format) configFlags &= ~OCSD_DFRMTR_FRAME_MEM_ALIGN;
+
+ if (!configFlags)
+ {
+ configFlags = OCSD_DFRMTR_FRAME_MEM_ALIGN;
+ }
+ pDeformatter->Configure(configFlags);
+
+ if (outRawPacked || outRawUnpacked)
+ {
+ if (outRawPacked) configFlags |= OCSD_DFRMTR_PACKED_RAW_OUT;
+ if (outRawUnpacked) configFlags |= OCSD_DFRMTR_UNPACKED_RAW_OUT;
+ dcd_tree->addRawFramePrinter(framePrinter, configFlags);
+ }
+ }
+}
+
+void PrintDecodeStats(DecodeTree *dcd_tree)
+{
+ uint8_t elemID;
+ std::ostringstream oss;
+ ocsd_decode_stats_t *pStats = 0;
+ ocsd_err_t err;
+ bool gotDemuxStats = false;
+ ocsd_demux_stats_t demux_stats;
+
+ oss << "\nReading packet decoder statistics....\n\n";
+ logger.LogMsg(oss.str());
+
+ DecodeTreeElement *pElement = dcd_tree->getFirstElement(elemID);
+ while (pElement)
+ {
+ oss.str("");
+ err = dcd_tree->getDecoderStats(elemID, &pStats);
+ if (!err && pStats)
+ {
+ oss << "Decode stats ID 0x" << std::hex << (uint32_t)elemID << "\n";
+ oss << "Total Bytes: " << std::dec << pStats->channel_total << "; Unsynced Bytes: " << std::dec << pStats->channel_unsynced << "\n";
+ oss << "Bad Header Errors: " << std::dec << pStats->bad_header_errs << "; Bad Sequence Errors: " << std::dec << pStats->bad_sequence_errs << "\n";
+
+ // demux stats same for all IDs - grab them at the first opportunity..
+ if (!gotDemuxStats) {
+ memcpy(&demux_stats, &pStats->demux, sizeof(ocsd_demux_stats_t));
+ gotDemuxStats = true;
+ }
+
+ }
+ else
+ oss << "Decode stats unavailable on Trace ID 0x" << std::hex << (uint32_t)elemID << "\n";
+
+
+ logger.LogMsg(oss.str());
+ pElement = dcd_tree->getNextElement(elemID);
+ }
+
+ // if we have copied over the stats and there is at least 1 frame byte (impossible for there to be 0 if demuxing)
+ if (gotDemuxStats && demux_stats.frame_bytes) {
+ uint64_t total = demux_stats.valid_id_bytes + demux_stats.no_id_bytes + demux_stats.unknown_id_bytes +
+ demux_stats.reserved_id_bytes + demux_stats.frame_bytes;
+ oss.str("");
+ oss << "\nFrame Demux Stats\n";
+ oss << "Trace data bytes sent to registered ID decoders: " << std::dec << demux_stats.valid_id_bytes << "\n";
+ oss << "Trace data bytes without registered ID decoders: " << std::dec << demux_stats.no_id_bytes << "\n";
+ oss << "Trace data bytes with unknown ID: " << std::dec << demux_stats.unknown_id_bytes << "\n";
+ oss << "Trace data bytes with reserved ID: " << std::dec << demux_stats.reserved_id_bytes << "\n";
+ oss << "Frame demux bytes, ID bytes and sync bytes: " << std::dec << demux_stats.frame_bytes << "\n";
+ oss << "Total bytes processed by frame demux: " << std::dec << total << "\n\n";
+ logger.LogMsg(oss.str());
+ }
+}
+
+void ListTracePackets(ocsdDefaultErrorLogger &err_logger, SnapShotReader &reader, const std::string &trace_buffer_name)
+{
+ CreateDcdTreeFromSnapShot tree_creator;
+
+ tree_creator.initialise(&reader, &err_logger);
+
+ if(tree_creator.createDecodeTree(trace_buffer_name, (decode == false), src_addr_n ? ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS : 0))
+ {
+ DecodeTree *dcd_tree = tree_creator.getDecodeTree();
+ dcd_tree->setAlternateErrorLogger(&err_logger);
+
+ RawFramePrinter *framePrinter = 0;
+ TrcGenericElementPrinter *genElemPrinter = 0;
+
+ AttachPacketPrinters(dcd_tree);
+
+ ConfigureFrameDeMux(dcd_tree, &framePrinter);
+
+ // if decoding set the generic element printer to the output interface on the tree.
+ if(decode)
+ {
+ std::ostringstream oss;
+ //dcd_tree->setGenTraceElemOutI(genElemPrinter);
+ dcd_tree->addGenElemPrinter(&genElemPrinter);
+ oss << "Trace Packet Lister : Set trace element decode printer\n";
+ logger.LogMsg(oss.str());
+ genElemPrinter->setTestWaits(test_waits);
+ }
+
+ if(decode)
+ dcd_tree->logMappedRanges(); // print out the mapped ranges
+
+ // check if we have attached at least one printer
+ if(decode || (PktPrinterFact::numPrinters(dcd_tree->getPrinterList()) > 0))
+ {
+ // set up the filtering at the tree level (avoid pushing to processors with no attached printers)
+ if(!all_source_ids)
+ dcd_tree->setIDFilter(id_list);
+ else
+ dcd_tree->clearIDFilter();
+
+ // need to push the data through the decode tree.
+ std::ifstream in;
+ in.open(tree_creator.getBufferFileName(),std::ifstream::in | std::ifstream::binary);
+ if(in.is_open())
+ {
+ ocsd_datapath_resp_t dataPathResp = OCSD_RESP_CONT;
+ static const int bufferSize = 1024;
+ uint8_t trace_buffer[bufferSize]; // temporary buffer to load blocks of data from the file
+ uint32_t trace_index = 0; // index into the overall trace buffer (file).
+
+ // process the file, a buffer load at a time
+ while(!in.eof() && !OCSD_DATA_RESP_IS_FATAL(dataPathResp))
+ {
+ if (dstream_format)
+ {
+ in.read((char *)&trace_buffer[0], 512 - 8);
+ }
+ else
+ in.read((char *)&trace_buffer[0],bufferSize); // load a block of data into the buffer
+
+ std::streamsize nBuffRead = in.gcount(); // get count of data loaded.
+ std::streamsize nBuffProcessed = 0; // amount processed in this buffer.
+ uint32_t nUsedThisTime = 0;
+
+ // process the current buffer load until buffer done, or fatal error occurs
+ while((nBuffProcessed < nBuffRead) && !OCSD_DATA_RESP_IS_FATAL(dataPathResp))
+ {
+ if(OCSD_DATA_RESP_IS_CONT(dataPathResp))
+ {
+ dataPathResp = dcd_tree->TraceDataIn(
+ OCSD_OP_DATA,
+ trace_index,
+ (uint32_t)(nBuffRead - nBuffProcessed),
+ &(trace_buffer[0])+nBuffProcessed,
+ &nUsedThisTime);
+
+ nBuffProcessed += nUsedThisTime;
+ trace_index += nUsedThisTime;
+
+ // test printers can inject _WAIT responses - see if we are expecting one...
+ if(ExpectingPPrintWaitResp(dcd_tree, *genElemPrinter))
+ {
+ if(OCSD_DATA_RESP_IS_CONT(dataPathResp))
+ {
+ // not wait or fatal - log a warning here.
+ std::ostringstream oss;
+ oss << "Trace Packet Lister : WARNING : Data in; data Path expected WAIT response\n";
+ logger.LogMsg(oss.str());
+ }
+ }
+ }
+ else // last response was _WAIT
+ {
+ // may need to acknowledge a wait from the gen elem printer
+ if(genElemPrinter->needAckWait())
+ genElemPrinter->ackWait();
+
+ // dataPathResp not continue or fatal so must be wait...
+ dataPathResp = dcd_tree->TraceDataIn(OCSD_OP_FLUSH,0,0,0,0);
+ }
+ }
+
+ /* dump dstream footers */
+ if (dstream_format) {
+ in.read((char *)&trace_buffer[0], 8);
+ if (outRawPacked)
+ {
+ std::ostringstream oss;
+ oss << "DSTREAM footer [";
+ for (int i = 0; i < 8; i++)
+ {
+ oss << "0x" << std::hex << (int)trace_buffer[i] << " ";
+ }
+ oss << "]\n";
+ logger.LogMsg(oss.str());
+ }
+ }
+ }
+
+ // fatal error - no futher processing
+ if(OCSD_DATA_RESP_IS_FATAL(dataPathResp))
+ {
+ std::ostringstream oss;
+ oss << "Trace Packet Lister : Data Path fatal error\n";
+ logger.LogMsg(oss.str());
+ ocsdError *perr = err_logger.GetLastError();
+ if(perr != 0)
+ logger.LogMsg(ocsdError::getErrorString(perr));
+
+ }
+ else
+ {
+ // mark end of trace into the data path
+ dcd_tree->TraceDataIn(OCSD_OP_EOT,0,0,0,0);
+ }
+
+ // close the input file.
+ in.close();
+
+ std::ostringstream oss;
+ oss << "Trace Packet Lister : Trace buffer done, processed " << trace_index << " bytes.\n";
+ logger.LogMsg(oss.str());
+ if (stats)
+ PrintDecodeStats(dcd_tree);
+ }
+ else
+ {
+ std::ostringstream oss;
+ oss << "Trace Packet Lister : Error : Unable to open trace buffer.\n";
+ logger.LogMsg(oss.str());
+ }
+
+ }
+ else
+ {
+ std::ostringstream oss;
+ oss << "Trace Packet Lister : No supported protocols found.\n";
+ logger.LogMsg(oss.str());
+ }
+
+ // clean up
+
+ // get rid of the decode tree.
+ tree_creator.destroyDecodeTree();
+ }
+}
+
+/* End of File trc_pkt_lister.cpp */