Merge ad713764c0a067d21d2227146f969055719cd326 on remote branch

Change-Id: I81f279930d9505b239d301ffc9c89b9fd907e9f9
diff --git a/Android.bp b/Android.bp
index 448a8b4..6e8884c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -75,6 +75,7 @@
         "decoder/source/*.cpp",
         "decoder/source/etmv3/*.cpp",
         "decoder/source/etmv4/*.cpp",
+        "decoder/source/ete/*.cpp",
         "decoder/source/i_dec/*.cpp",
         "decoder/source/mem_acc/*.cpp",
         "decoder/source/pkt_printers/*.cpp",
diff --git a/METADATA b/METADATA
index 800b1e7..256f7cb 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
     type: GIT
     value: "https://github.com/Linaro/OpenCSD.git"
   }
-  version: "v1.1.0"
+  version: "v1.2.0"
   license_type: RESTRICTED
   last_upgrade_date {
     year: 2021
-    month: 5
-    day: 26
+    month: 10
+    day: 13
   }
 }
diff --git a/README.md b/README.md
index b697843..97b32ed 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@
 CoreSight Trace Component Support.
 ----------------------------------
 
-_Current Version 1.1.0_
+_Current Version 1.2.0_
 
 ### Current support:
 
@@ -247,6 +247,17 @@
     - __Bugfix__: Add Pull request #36 from github (Ross Burton)
     - __Bugfix__: Add Pull request #37 from github (Ian Rogers)
 
+- _Version 1.1.1_:
+    - __Bugfix__: Fix include and install for ETE decoder headers.
+
+- _Version 1.2.0_:
+    - __Update__: Add API for counting packet decode statistics, and Frame debmux statistics.
+    - __Update__: Update test scripts to allow additional command line options to be passed.
+    - __Bugfix__: Fix various build warnings.
+    - __Bugfix__: Remove unused variable (github issue #38 from Yi Kong)
+    - __Bugfix__: Remove noisy printf (James Clark)
+    - __Bugfix__: Fix documentation issues (github issues #39 & #40 from rbresalier)
+
 Licence Information
 ===================
 
diff --git a/decoder/build/linux/rctdl_c_api_lib/makefile b/decoder/build/linux/rctdl_c_api_lib/makefile
index a0bd5a3..7b4055d 100644
--- a/decoder/build/linux/rctdl_c_api_lib/makefile
+++ b/decoder/build/linux/rctdl_c_api_lib/makefile
@@ -113,6 +113,8 @@
 	$(INSTALL) --mode=0644 $(INST_INC_SRC)/etmv3/trc_pkt_types_etmv3.h $(INST_INC_DST)/etmv3/
 	$(INSTALL) -d --mode=0755 $(INST_INC_DST)/etmv4
 	$(INSTALL) --mode=0644 $(INST_INC_SRC)/etmv4/trc_pkt_types_etmv4.h $(INST_INC_DST)/etmv4/
+	$(INSTALL) -d --mode=0755 $(INST_INC_DST)/ete
+	$(INSTALL) --mode=0644 $(INST_INC_SRC)/ete/trc_pkt_types_ete.h $(INST_INC_DST)/ete/
 	$(INSTALL) -d --mode=0755 $(INST_INC_DST)/c_api
 	$(INSTALL) --mode=0644 $(INST_INC_SRC)/c_api/ocsd_c_api_types.h $(INST_INC_DST)/c_api/
 	$(INSTALL) --mode=0644 $(INST_INC_SRC)/c_api/opencsd_c_api.h $(INST_INC_DST)/c_api/
diff --git a/decoder/docs/doxygen_config.dox b/decoder/docs/doxygen_config.dox
index 2deb050..6d2f02c 100644
--- a/decoder/docs/doxygen_config.dox
+++ b/decoder/docs/doxygen_config.dox
@@ -38,7 +38,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.1.0
+PROJECT_NUMBER         = 1.2.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/decoder/docs/prog_guide/prog_guide_main.md b/decoder/docs/prog_guide/prog_guide_main.md
index d0e2e7c..9504bdc 100644
--- a/decoder/docs/prog_guide/prog_guide_main.md
+++ b/decoder/docs/prog_guide/prog_guide_main.md
@@ -138,9 +138,17 @@
 error, or other error messages, out to screen or logging file. Errors can be filtered according to a severity rating,
 defined by @ref ocsd_err_severity_t.
 
-The DecodeTree will use a default error logger from the library - with a message logger
-that will output to `stderr`. Client applications can adjust the configuration of this error logger and 
-message logger, or provide their own configured error logger / message logger pair. 
+The DecodeTree can use a default error logger from the library - with a message logger that will output to `stderr`. 
+
+Client applications can create and adjust the configuration of this error logger and message logger by getting and intialising
+ the logger. 
+
+~~~{.cpp}
+	// ** Initialise default error logger.
+	DecodeTree::getDefaultErrorLogger()->initErrorLogger(verbosity,true);
+~~~	
+
+Alternatively clients may provide their own configured error logger / message logger pair.
 
 The test program `trc_pkt_lister` provides a customised version of an `ocsdMsgLogger` / `ocsdDefaultErrorLogger` pair
 to ensure that messages and errors are logged to the screen and a file of its choice. This logger is eventually
@@ -301,15 +309,19 @@
 
 ~~~{.cpp}
 	class DecodeTree {
-		///...
+		// ...
+		ocsd_err_t createMemAccMapper(memacc_mapper_t type = MEMACC_MAP_GLOBAL);
+		// ...
 		ocsd_err_t addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length);
 		ocsd_err_t addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath);
 		ocsd_err_t addBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath);     */
 		ocsd_err_t addCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context); 
-		///...
+		// ...
 	}	
 ~~~
 
+The `createMemAccMapper()` function must be called to create the mapper, before the `add...MemAcc()` calls are used.
+
 It is further possible to differentiate between memory image access objects by the memory space for which they are valid. If it is known that a certain code image 
 is present in secure EL3, then an image can be associated with the @ref ocsd_mem_space_acc_t type value @ref OCSD_MEM_SPACE_EL3, which will allow another image to be 
 present at the same address but a different exception level.  However, for the majority of systems, such detailed knowledge of the code is not available, or 
@@ -324,6 +336,7 @@
 	OCSD_C_API ocsd_err_t ocsd_dt_add_callback_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context); 
 ~~~
 
+Note that the C-API will automatically create a default mapper when the first memory access object is added.
 
 ### Adding the output callbacks ###
 
diff --git a/decoder/include/common/ocsd_dcd_tree.h b/decoder/include/common/ocsd_dcd_tree.h
index e4e74f2..b1c3dc6 100644
--- a/decoder/include/common/ocsd_dcd_tree.h
+++ b/decoder/include/common/ocsd_dcd_tree.h
@@ -168,6 +168,30 @@
      */
     ocsd_err_t removeDecoder(const uint8_t CSID);
 
+    /*!
+    * Get the stats block for the channel indicated.
+    * Caller must check p_stats_block->version to esure that the block
+    * is filled in a compatible manner.
+    *
+    * @param CSID : Configured CoreSight trace ID for the decoder.
+    * @param p_stats_block: block pointer to set to reference the stats block.
+    *
+    * @return ocsd_err_t  : Library error code -  OCSD_OK if valid block pointer returned,
+    *                      OCSD_ERR_NOTINIT if decoder does not support stats counting.
+    */
+    ocsd_err_t getDecoderStats(const uint8_t CSID, ocsd_decode_stats_t **p_stats_block);
+    
+    /*!
+    * Reset the stats block for the chosens decode channel.
+    * stats block is reset independently of the decoder reset to allow counts across
+    * multiple decode runs.
+    *
+    * @param handle : Handle to decode tree.
+    * @param CSID : Configured CoreSight trace ID for the decoder.
+    *
+    * @return ocsd_err_t  : Library error code -  OCSD_OK if successful.
+    */
+    ocsd_err_t resetDecoderStats(const uint8_t CSID);
 
 /* get decoder elements currently in use  */
 
@@ -387,7 +411,7 @@
     void destroyMemAccMapper();
     ocsd_err_t initCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, 
         const ocsd_mem_space_acc_t mem_space, void *p_cb_func, bool IDfn, const void *p_context);
-
+    TrcPktProcI *getPktProcI(const uint8_t CSID);
 
     ocsd_dcd_tree_src_t m_dcd_tree_type;
 
@@ -417,6 +441,9 @@
 
     /**! default instruction decoder */
     static TrcIDecode s_instruction_decoder;
+
+    /**! demux stats block */
+    ocsd_demux_stats_t m_demux_stats;
 };
 
 /** @}*/
diff --git a/decoder/include/common/trc_frame_deformatter.h b/decoder/include/common/trc_frame_deformatter.h
index e4297a4..b6476a2 100644
--- a/decoder/include/common/trc_frame_deformatter.h
+++ b/decoder/include/common/trc_frame_deformatter.h
@@ -85,9 +85,13 @@
     ocsd_datapath_resp_t Reset();    /* reset the decode to the start state, drop partial data - propogate to attached components */
     ocsd_datapath_resp_t Flush();    /* flush existing data if possible, retain state - propogate to attached components */
 
+    /* demux stats */
+    void SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock);
+
 private:
     TraceFmtDcdImpl *m_pDecoder;
     int m_instNum;
+   
 };
 
 /** @}*/
diff --git a/decoder/include/common/trc_pkt_proc_base.h b/decoder/include/common/trc_pkt_proc_base.h
index 3098a3d..8ed7d83 100644
--- a/decoder/include/common/trc_pkt_proc_base.h
+++ b/decoder/include/common/trc_pkt_proc_base.h
@@ -43,6 +43,7 @@
 
 #include "trc_component.h"
 #include "comp_attach_pt_t.h"
+#include "opencsd/ocsd_if_version.h"
 
 /** @defgroup ocsd_pkt_proc  OpenCSD Library : Packet Processors.
     @brief Classes providing Protocol Packet Processing capability.
@@ -76,6 +77,8 @@
                                                 const uint8_t *pDataBlock,
                                                 uint32_t *numBytesProcessed) = 0;
 
+    virtual ocsd_err_t getStatsBlock(ocsd_decode_stats_t **pp_stats) = 0;
+    virtual void resetStats() = 0;
 protected:
 
     /* implementation packet processing interface */
@@ -155,6 +158,10 @@
     //!< Get the configuration for the decoder.
     virtual const Pc *getProtocolConfig() const { return m_config; };
 
+/*  stats block access - derived class must init stats for the block to be returned. */
+    virtual ocsd_err_t getStatsBlock(ocsd_decode_stats_t **pp_stats);
+    virtual void resetStats();  /* reset the counts - operates separately from decoder reset. */
+
 protected:
 
     /* data output functions */
@@ -183,6 +190,14 @@
 
     const bool checkInit(); // return true if init (configured and at least one output sink attached), false otherwise.
 
+    /* stats block updates - called by derived protocol specific decoder */
+    void statsAddTotalCount(const uint64_t count) { m_stats.channel_total += count; };
+    void statsAddUnsyncCount(const uint64_t count) { m_stats.channel_unsynced += count; };
+    void statsAddBadSeqCount(const uint32_t count) { m_stats.bad_sequence_errs += count; };
+    void statsAddBadHdrCount(const uint32_t count) { m_stats.bad_header_errs += count; };
+    void statsInit() { m_stats_init = true; };  /* mark stats as in use */
+
+ 
 private:
     /* decode control */
     ocsd_datapath_resp_t Reset(const ocsd_trc_index_t index);
@@ -195,20 +210,29 @@
     componentAttachPt<ITrcPktIndexer<Pt>> m_pkt_indexer_i;
 
     bool m_b_is_init;
+    
+    /* decode statistics block */
+    ocsd_decode_stats_t m_stats;
+    bool m_stats_init; /*< true if the specific decoder is using the stats */
+
 };
 
 template<class P,class Pt, class Pc> TrcPktProcBase<P, Pt, Pc>::TrcPktProcBase(const char *component_name) : 
     TrcPktProcI(component_name),
     m_config(0),
-    m_b_is_init(false)
+    m_b_is_init(false),
+    m_stats_init(false)
 {
+    resetStats();
 }
 
 template<class P,class Pt, class Pc> TrcPktProcBase<P, Pt, Pc>::TrcPktProcBase(const char *component_name, int instIDNum) : 
     TrcPktProcI(component_name, instIDNum),
     m_config(0),
-    m_b_is_init(false)
+    m_b_is_init(false),
+    m_stats_init(false)
 {
+    resetStats();
 }
 
 template<class P,class Pt, class Pc> TrcPktProcBase<P, Pt, Pc>::~TrcPktProcBase()
@@ -405,6 +429,26 @@
     return m_b_is_init;
 }
 
+template<class P,class Pt, class Pc> ocsd_err_t TrcPktProcBase<P, Pt, Pc>::getStatsBlock(ocsd_decode_stats_t **pp_stats)
+{
+    
+    *pp_stats = &m_stats;
+    return m_stats_init ? OCSD_OK : OCSD_ERR_NOT_INIT;
+}
+
+template<class P,class Pt, class Pc> void TrcPktProcBase<P, Pt, Pc>::resetStats()
+{
+    m_stats.version = OCSD_VER_NUM;
+    m_stats.revision = OCSD_STATS_REVISION;
+    m_stats.channel_total = 0;
+    m_stats.channel_unsynced = 0;
+    m_stats.bad_header_errs = 0;
+    m_stats.bad_sequence_errs = 0;
+    m_stats.demux.frame_bytes = 0;
+    m_stats.demux.no_id_bytes = 0;
+    m_stats.demux.valid_id_bytes = 0;
+} 
+
 /** @}*/
 
 #endif // ARM_TRC_PKT_PROC_BASE_H_INCLUDED
diff --git a/decoder/include/opencsd/c_api/ocsd_c_api_types.h b/decoder/include/opencsd/c_api/ocsd_c_api_types.h
index cde351f..7f9b4ba 100644
--- a/decoder/include/opencsd/c_api/ocsd_c_api_types.h
+++ b/decoder/include/opencsd/c_api/ocsd_c_api_types.h
@@ -46,6 +46,7 @@
 #include "opencsd/etmv4/trc_pkt_types_etmv4.h"
 #include "opencsd/ptm/trc_pkt_types_ptm.h"
 #include "opencsd/stm/trc_pkt_types_stm.h"
+#include "opencsd/ete/trc_pkt_types_ete.h"
 
 /** @ingroup lib_c_api
 @{*/
diff --git a/decoder/include/opencsd/c_api/opencsd_c_api.h b/decoder/include/opencsd/c_api/opencsd_c_api.h
index 25e9487..ebbba87 100644
--- a/decoder/include/opencsd/c_api/opencsd_c_api.h
+++ b/decoder/include/opencsd/c_api/opencsd_c_api.h
@@ -210,10 +210,36 @@
                                                 const void *p_context);
 
 
-
-
+/*!
+ * Get the stats block for the channel indicated. 
+ * Caller must check p_stats_block->version to esure that the block
+ * is filled in a compatible manner.
+ * 
+ * @param handle : Handle to decode tree.
+ * @param CSID : Configured CoreSight trace ID for the decoder.
+ * @param p_stats_block: block pointer to set to reference the stats block.
+ * 
+ * @return ocsd_err_t  : Library error code -  OCSD_OK if valid block pointer returned, 
+ *                      OCSD_ERR_NOTINIT if decoder does not support stats counting.
+ */
+OCSD_C_API ocsd_err_t ocsd_dt_get_decode_stats( const dcd_tree_handle_t handle,
+                                                const unsigned char CSID,
+                                                ocsd_decode_stats_t **p_stats_block);
  
-    
+
+/*!
+ * Reset the stats block for the chosens decode channel. 
+ * stats block is reset independently of the decoder reset to allow counts across
+ * multiple decode runs.
+ *
+ * @param handle : Handle to decode tree.
+ * @param CSID : Configured CoreSight trace ID for the decoder.
+ *
+ * @return ocsd_err_t  : Library error code -  OCSD_OK if successful.
+ */
+OCSD_C_API ocsd_err_t ocsd_dt_reset_decode_stats( const dcd_tree_handle_t handle,
+                                                  const unsigned char CSID);
+
 /** @}*/
 /*---------------------- Memory Access for traced opcodes ----------------------------------------------------------------------------------*/
 /** @name Library Memory Accessor configuration on decode tree.
diff --git a/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h b/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h
index e46b71d..223dbda 100644
--- a/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h
+++ b/decoder/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h
@@ -153,6 +153,7 @@
     const bool enabledCCI() const;
     const bool enabledCID() const;
     const bool enabledVMID() const;
+    const bool enabledVMIDOpt() const;
 
     typedef enum {
         COND_TR_DIS,
@@ -436,6 +437,20 @@
     return ((m_cfg.reg_configr & (0x1 << 7)) != 0);
 }
 
+inline const bool EtmV4Config::enabledVMIDOpt() const
+{
+    bool vmidOptVal = ((m_cfg.reg_configr & (0x1 << 15)) != 0);
+    /* TRIDR2.VMIDOPT[30:29] determine value used */
+    if (!vmidOpt()) { /* [29] = 1'b0 */
+        vmidOptVal = false; /* res0 */
+        if (FullVersion() >= 0x45) {
+            /* umless version > 4.5 in which case [30] determines res val */
+            vmidOptVal = ((m_cfg.reg_idr2 & (0x1 << 30)) != 0);
+        }
+    }
+    return vmidOptVal;
+}
+
 inline const EtmV4Config::CondITrace_t EtmV4Config::enabledCondITrace()
 {
     if(!m_condTraceCalc)
diff --git a/decoder/include/opencsd/ocsd_if_types.h b/decoder/include/opencsd/ocsd_if_types.h
index 2550f96..5628fec 100644
--- a/decoder/include/opencsd/ocsd_if_types.h
+++ b/decoder/include/opencsd/ocsd_if_types.h
@@ -633,6 +633,56 @@
 
 /** @}*/
 
+/** @name Demux Statistics 
+ 
+    Contains statistics for the CoreSight frame demultiplexor. 
+
+    Counts total bytes sent to decoders registered against a trace ID, bytes in the input stream that are
+    associated with a trace ID that has no registered decoder, and frame bytes that are not trace data, but
+    are used to decode the frames - ID bytes, sync bytes etc.
+@{*/
+
+typedef struct _ocsd_demux_stats {
+    uint64_t valid_id_bytes;  /**< number of bytes associated with an ID that has a registered decoder */
+    uint64_t no_id_bytes; /**< number of bytes associated with an ID that has no decoder */
+    uint64_t reserved_id_bytes; /**< number of bytes associated with reserved IDs */
+    uint64_t unknown_id_bytes; /**< bytes processed before ID seen in input frames */
+    uint64_t frame_bytes; /**< number of non-data bytes used for frame de-mux - ID bytes, sync etc */    
+} ocsd_demux_stats_t;
+
+/** @}*/
+
+/** @name Decode statistics
+
+    Contains statistics for bytes decoded by the packet decoder, if statistics are supported.
+
+    Stats block instantiated in the base class - derived protocol specific decoder must initialise and
+    use as required.
+
+    The single channel block contains the stats for the requested channel via the API call.
+
+    The global demux block contains the totals for all channels and non-data bytes used in CoreSight
+    frame demux. This block will show identical data for every requested channel via the API.
+
+@{*/
+
+typedef struct _ocsd_decode_stats {
+    uint32_t version;           /**< library version number */
+    uint16_t revision;          /**< revision number - defines the structure version for the stats. */
+   /* single channel block */
+    uint64_t channel_total;     /**< total bytes processed for this channel */
+    uint64_t channel_unsynced;  /**< number of unsynced bytes processed on this channel */
+    uint32_t bad_header_errs;   /**< number of bad packet header errors */
+    uint32_t bad_sequence_errs; /**< number of bad packet sequence errors */
+    
+    ocsd_demux_stats_t demux;   /**< global demux stats block */
+} ocsd_decode_stats_t;
+
+#define OCSD_STATS_REVISION 0x1
+
+/** @}*/
+
+
 /** @}*/
 #endif // ARM_OCSD_IF_TYPES_H_INCLUDED
 
diff --git a/decoder/include/opencsd/ocsd_if_version.h b/decoder/include/opencsd/ocsd_if_version.h
index a06dd6c..d6f5849 100644
--- a/decoder/include/opencsd/ocsd_if_version.h
+++ b/decoder/include/opencsd/ocsd_if_version.h
@@ -43,7 +43,7 @@
 /** @name Library Versioning
 @{*/
 #define OCSD_VER_MAJOR 0x1 /**< Library Major Version */
-#define OCSD_VER_MINOR 0x1 /**< Library Minor Version */
+#define OCSD_VER_MINOR 0x2 /**< Library Minor Version */
 #define OCSD_VER_PATCH 0x0 /**< Library Patch Version */
 
 /** Library version number - MMMMnnpp format.
@@ -53,7 +53,7 @@
 */
 #define OCSD_VER_NUM ((OCSD_VER_MAJOR << 16) | (OCSD_VER_MINOR << 8) | OCSD_VER_PATCH) 
 
-#define OCSD_VER_STRING "1.1.0"    /**< Library Version string */
+#define OCSD_VER_STRING "1.2.0"    /**< Library Version string */
 #define OCSD_LIB_NAME "OpenCSD Library"  /**< Library name string */
 #define OCSD_LIB_SHORT_NAME "OCSD"    /**< Library Short name string */
 /** @}*/
diff --git a/decoder/source/c_api/ocsd_c_api.cpp b/decoder/source/c_api/ocsd_c_api.cpp
index 66bfce8..750c847 100644
--- a/decoder/source/c_api/ocsd_c_api.cpp
+++ b/decoder/source/c_api/ocsd_c_api.cpp
@@ -234,8 +234,24 @@
     return err;
 }
 
-/*** Decode tree set element output */
+OCSD_C_API ocsd_err_t ocsd_dt_get_decode_stats(const dcd_tree_handle_t handle,
+                                               const unsigned char CSID,                                               
+                                               ocsd_decode_stats_t **p_stats_block)
+{
+    DecodeTree *pDT = static_cast<DecodeTree *>(handle);
+    
+    return pDT->getDecoderStats(CSID, p_stats_block);
+}
 
+OCSD_C_API ocsd_err_t ocsd_dt_reset_decode_stats(const dcd_tree_handle_t handle,
+                                                 const unsigned char CSID)
+{
+    DecodeTree *pDT = static_cast<DecodeTree *>(handle);
+
+    return pDT->resetDecoderStats(CSID);
+}
+
+/*** Decode tree set element output */
 OCSD_C_API ocsd_err_t ocsd_dt_set_gen_elem_outfn(const dcd_tree_handle_t handle, FnTraceElemIn pFn, const void *p_context)
 {
 
diff --git a/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp
index 4c92d9e..07b372c 100644
--- a/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp
+++ b/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp
@@ -75,6 +75,7 @@
     BuildIPacketTable();    // packet table based on config
     m_curr_packet.setProtocolVersion(m_config.FullVersion());
     m_isInit = true;
+    statsInit();
     return OCSD_OK;
 }
 
@@ -156,6 +157,10 @@
                 (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR))
             {
                 // send invalid packets up the pipe to let the next stage decide what to do.
+                if (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)
+                    statsAddBadHdrCount(1);
+                else
+                    statsAddBadSeqCount(1);
                 m_process_state = SEND_PKT; 
                 done = false;
             }
@@ -175,6 +180,7 @@
         }
     } while (!done);
 
+    statsAddTotalCount(m_trcIn.processed());
     *numBytesProcessed = m_trcIn.processed();
     return resp;
 }
@@ -245,8 +251,8 @@
 {
     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
     
-
-   outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]);
+    statsAddUnsyncCount(m_dump_unsynced_bytes);
+    outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]);
         
     if(!m_sent_notsync_packet)
     {        
diff --git a/decoder/source/ocsd_dcd_tree.cpp b/decoder/source/ocsd_dcd_tree.cpp
index b8c27a0..b423f7d 100644
--- a/decoder/source/ocsd_dcd_tree.cpp
+++ b/decoder/source/ocsd_dcd_tree.cpp
@@ -101,6 +101,13 @@
 {
     for(int i = 0; i < 0x80; i++)
         m_decode_elements[i] = 0;
+
+     // reset the global demux stats.
+    m_demux_stats.frame_bytes = 0;
+    m_demux_stats.no_id_bytes = 0;
+    m_demux_stats.valid_id_bytes = 0;  
+    m_demux_stats.unknown_id_bytes = 0;
+    m_demux_stats.reserved_id_bytes = 0;     
 }
 
 DecodeTree::~DecodeTree()
@@ -486,6 +493,62 @@
     return err;
 }
 
+ocsd_err_t DecodeTree::getDecoderStats(const uint8_t CSID, ocsd_decode_stats_t **p_stats_block)
+{
+    ocsd_err_t err = OCSD_OK;
+    TrcPktProcI *pPktProc = getPktProcI(CSID);
+    if (!pPktProc)
+        return OCSD_ERR_INVALID_PARAM_VAL;
+    err = pPktProc->getStatsBlock(p_stats_block);
+    if (err == OCSD_OK) {
+        // copy in the global demux stats.
+        (*p_stats_block)->demux.frame_bytes = m_demux_stats.frame_bytes;
+        (*p_stats_block)->demux.no_id_bytes = m_demux_stats.no_id_bytes;
+        (*p_stats_block)->demux.valid_id_bytes = m_demux_stats.valid_id_bytes;
+        (*p_stats_block)->demux.unknown_id_bytes = m_demux_stats.unknown_id_bytes;
+        (*p_stats_block)->demux.reserved_id_bytes = m_demux_stats.reserved_id_bytes;
+    }
+    return err;
+}
+
+ocsd_err_t DecodeTree::resetDecoderStats(const uint8_t CSID)
+{
+    TrcPktProcI *pPktProc = getPktProcI(CSID);
+    if (!pPktProc)
+        return OCSD_ERR_INVALID_PARAM_VAL;
+    pPktProc->resetStats();
+
+    // reset the global demux stats.
+    m_demux_stats.frame_bytes = 0;
+    m_demux_stats.no_id_bytes = 0;
+    m_demux_stats.valid_id_bytes = 0;  
+    m_demux_stats.unknown_id_bytes = 0;
+    m_demux_stats.reserved_id_bytes = 0;
+    return OCSD_OK;
+}
+
+TrcPktProcI *DecodeTree::getPktProcI(const uint8_t CSID)
+{
+    TrcPktProcI *pPktProc = 0;
+    TraceComponent *pComp, *pAssoc;
+    DecodeTreeElement *pElem = getDecoderElement(CSID);
+    
+    if (pElem) 
+    {
+        pComp = pElem->getDecoderHandle();
+        if (pComp)
+        {
+            /* if this is a full decoder then the associated component is the packet processor */
+            pAssoc = pComp->getAssocComponent();
+            if (pAssoc)
+                pPktProc = dynamic_cast<TrcPktProcI *>(pAssoc);
+            else
+                pPktProc = dynamic_cast<TrcPktProcI *>(pComp);
+        }
+    }
+    return pPktProc;
+}
+
 DecodeTreeElement * DecodeTree::getDecoderElement(const uint8_t CSID) const
 {
     DecodeTreeElement *ret_elem = 0;
@@ -538,6 +601,7 @@
             m_frame_deformatter_root->Configure(formatterCfgFlags);
             m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger);
             m_i_decoder_root = dynamic_cast<ITrcDataIn*>(m_frame_deformatter_root);
+            m_frame_deformatter_root->SetDemuxStatsBlock(&m_demux_stats);
         }
         else 
             initOK = false;
diff --git a/decoder/source/trc_frame_deformatter.cpp b/decoder/source/trc_frame_deformatter.cpp
index 4d46854..dc12e3f 100644
--- a/decoder/source/trc_frame_deformatter.cpp
+++ b/decoder/source/trc_frame_deformatter.cpp
@@ -54,7 +54,8 @@
     m_use_force_sync(false),
     m_alignment(16), // assume frame aligned data as default.
     m_b_output_packed_raw(false),
-    m_b_output_unpacked_raw(false)
+    m_b_output_unpacked_raw(false),
+    m_pStatsBlock(0)
 
 {
     resetStateParams();
@@ -436,7 +437,6 @@
 
 	if (num_fsyncs)
 	{
-        printf("Frame deformatter: Found %d FSYNCS\n",num_fsyncs);
 		if ((num_fsyncs % 4) == 0)
         {
             // reset the upstream decoders            
@@ -595,6 +595,9 @@
     // update index past the processed data   
     m_trc_curr_idx += total_processed;
 
+    // update any none trace data byte stats
+    addToFrameStats((uint64_t)(f_sync_bytes + h_sync_bytes));
+
     return cont_process;
 }
 
@@ -604,6 +607,7 @@
     uint8_t frameFlagBit = 0x1;
     uint8_t newSrcID = OCSD_BAD_CS_SRC_ID;
     bool PrevIDandIDChange = false;
+    uint64_t noneDataBytes = 0;
 
     // init output processing
     m_out_data_idx = 0;   
@@ -650,6 +654,7 @@
 
                 /// TBD - ID indexing in here.
             }
+            noneDataBytes++;
         }
         else
         // it's just data
@@ -671,6 +676,7 @@
     {
         // no matter if change or not, no associated data in byte 15 anyway so just set.
         m_curr_src_ID = (m_ex_frm_data[14] >> 1) & 0x7f;
+        noneDataBytes++;
     }
     // it's data
     else
@@ -678,6 +684,9 @@
         m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[14] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0); 
     }
     m_ex_frm_n_bytes = 0;   // mark frame as empty;
+
+    noneDataBytes++;    // byte 15 is always non-data.
+    addToFrameStats(noneDataBytes); // update the non data byte stats. 
     return true;
 }
 
@@ -716,6 +725,8 @@
                     m_out_data[m_out_processed].data + m_out_data[m_out_processed].used,
                     &bytes_used));               
                 
+                addToIDStats((uint64_t)bytes_used);
+
                 if(!dataPathCont())
                 {
                     cont_processing = false;
@@ -739,7 +750,12 @@
                         m_out_data[m_out_processed].valid,
                         m_out_data[m_out_processed].data,
                         m_out_data[m_out_processed].id);
-                }                
+                }  
+
+                if (isReservedID(m_out_data[m_out_processed].id))
+                    addToReservedIDStats((uint64_t)m_out_data[m_out_processed].valid);
+                else
+                    addToNoIDStats((uint64_t)m_out_data[m_out_processed].valid);
                 m_out_processed++; // skip past this data.
             }
         }
@@ -754,13 +770,44 @@
                     m_out_data[m_out_processed].valid,
                     m_out_data[m_out_processed].data,
                     m_out_data[m_out_processed].id);
-            }             
+            } 
+            addToUnknownIDStats((uint64_t)m_out_data[m_out_processed].valid);            
             m_out_processed++; // skip past this data.
         }
     }
     return cont_processing;
 }
+    
+void TraceFmtDcdImpl::addToIDStats(uint64_t val)
+{
+    if (m_pStatsBlock)
+        m_pStatsBlock->valid_id_bytes += val;
+}
 
+void TraceFmtDcdImpl::addToNoIDStats(uint64_t val)
+{
+    if (m_pStatsBlock)
+        m_pStatsBlock->no_id_bytes += val;
+}
+
+void TraceFmtDcdImpl::addToFrameStats(uint64_t val)
+{
+    if (m_pStatsBlock)
+        m_pStatsBlock->frame_bytes += val;
+}
+
+void TraceFmtDcdImpl::addToUnknownIDStats(uint64_t val)
+{
+    if (m_pStatsBlock)
+        m_pStatsBlock->unknown_id_bytes += val;
+}
+
+void TraceFmtDcdImpl::addToReservedIDStats(uint64_t val)
+{
+    if (m_pStatsBlock)
+        m_pStatsBlock->reserved_id_bytes += val;
+}
+ 
 /***************************************************************/
 /* interface */
 /***************************************************************/
@@ -865,5 +912,10 @@
     return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Flush();
 }
 
+void TraceFormatterFrameDecoder::SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock)
+{
+    if (m_pDecoder)
+        m_pDecoder->SetDemuxStatsBlock(pStatsBlock);
+}
 
 /* End of File trc_frame_deformatter.cpp */
diff --git a/decoder/source/trc_frame_deformatter_impl.h b/decoder/source/trc_frame_deformatter_impl.h
index e1fc17a..8d19bdb 100644
--- a/decoder/source/trc_frame_deformatter_impl.h
+++ b/decoder/source/trc_frame_deformatter_impl.h
@@ -75,6 +75,8 @@
     ocsd_err_t DecodeConfigure(uint32_t flags);
     ocsd_err_t SetForcedSyncIndex(ocsd_trc_index_t index, bool bSet);
 
+    void SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock) { m_pStatsBlock = pStatsBlock; };
+
 private:
     ocsd_datapath_resp_t executeNoneDataOpAllIDs(ocsd_datapath_op_t op, const ocsd_trc_index_t index = 0);
     ocsd_datapath_resp_t processTraceData(const ocsd_trc_index_t index, 
@@ -117,8 +119,16 @@
 
     friend class TraceFormatterFrameDecoder;
 
-    // attachment points
+    // stats updates
+    void addToIDStats(uint64_t val);
+    void addToNoIDStats(uint64_t val);
+    void addToFrameStats(uint64_t val);
+    void addToUnknownIDStats(uint64_t val);
+    void addToReservedIDStats(uint64_t val);
+    
+    bool isReservedID(uint8_t ID) { return ((ID == 0) || (ID >= 0x70)); };
 
+    // attachment points
     componentAttachPt<ITrcDataIn> m_IDStreams[128];
     componentAttachPt<ITrcRawFrameIn> m_RawTraceFrame;
 
@@ -159,6 +169,8 @@
     bool m_b_output_unpacked_raw;
 
     bool m_raw_chan_enable[128];
+
+    ocsd_demux_stats_t *m_pStatsBlock;
 };
 
 
diff --git a/decoder/source/trc_printable_elem.cpp b/decoder/source/trc_printable_elem.cpp
index 88c7bb2..2b60c03 100644
--- a/decoder/source/trc_printable_elem.cpp
+++ b/decoder/source/trc_printable_elem.cpp
@@ -52,8 +52,6 @@
 
     assert((valTotalBitSize >= 4) && (valTotalBitSize <= 64));
 
-    uint64_t LimitMask = ~0ULL;
-    LimitMask >>= 64-valTotalBitSize;
     valStr = "0x";
 
     if(asHex)
diff --git a/decoder/tests/run_pkt_decode_single.bash b/decoder/tests/run_pkt_decode_single.bash
index b4ca58f..3025240 100755
--- a/decoder/tests/run_pkt_decode_single.bash
+++ b/decoder/tests/run_pkt_decode_single.bash
@@ -34,10 +34,10 @@
 #################################################################################
 # Usage options:-
 # * default: run test on binary + libs in ./bin/linux64/rel
-# run_pkt_decode_tests.bash <test>
+# run_pkt_decode_tests.bash <test> <options>
 #
 # * use installed opencsd libraries & program
-# run_pkt_decode_tests.bash use-installed <test>
+# run_pkt_decode_tests.bash use-installed <test> <options>
 #
 #
 
@@ -56,6 +56,7 @@
 
 if [ "$1" != "" ]; then
     TEST=$1
+    shift
 fi
 
 echo "Running trc_pkt_lister on single snapshot ${TEST}"
@@ -70,7 +71,7 @@
 fi
 
 # === test the decode set ===
-${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/${TEST}" -decode -logfilename "${OUT_DIR}/${TEST}.ppl"
+${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/${TEST}" $@ -decode -logfilename "${OUT_DIR}/${TEST}.ppl"
 echo "Done : Return $?"
 
 
diff --git a/decoder/tests/run_pkt_decode_tests-ete.bash b/decoder/tests/run_pkt_decode_tests-ete.bash
index c00631e..1b8c762 100755
--- a/decoder/tests/run_pkt_decode_tests-ete.bash
+++ b/decoder/tests/run_pkt_decode_tests-ete.bash
@@ -84,8 +84,11 @@
 
 if [ "$1" == "use-installed" ]; then
     BIN_DIR=""
-elif [ "$1" != "" ]; then
-    BIN_DIR=$1
+    shift
+elif [ "$1" == "-bindir" ]; then
+    BIN_DIR=$2
+    shift
+    shift
 fi
 
 echo "Tests using BIN_DIR = ${BIN_DIR}"
@@ -99,13 +102,13 @@
 for test_dir in "${test_dirs_decode[@]}"
 do
     echo "Testing $test_dir..."
-    ${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/$test_dir" -decode -logfilename "${OUT_DIR}/$test_dir.ppl"
+    ${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/$test_dir" $@ -decode -logfilename "${OUT_DIR}/$test_dir.ppl"
     echo "Done : Return $?"
 done
 
 for test_dir_n in "${test_dirs_decode_src_addr_opt[@]}"
 do
     echo "Testing with -src_addr_n  $test_dir_n..."
-    ${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/$test_dir_n" -decode -src_addr_n -logfilename "${OUT_DIR}/${test_dir_n}_src_addr_N.ppl"
+    ${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/$test_dir_n" $@ -decode -src_addr_n -logfilename "${OUT_DIR}/${test_dir_n}_src_addr_N.ppl"
     echo "Done : Return $?"
 done
diff --git a/decoder/tests/run_pkt_decode_tests.bash b/decoder/tests/run_pkt_decode_tests.bash
index d9b7c8a..9ecb034 100755
--- a/decoder/tests/run_pkt_decode_tests.bash
+++ b/decoder/tests/run_pkt_decode_tests.bash
@@ -40,10 +40,10 @@
 # run_pkt_decode_tests.bash
 #
 # * use installed opencsd libraries & program
-# run_pkt_decode_tests.bash use-installed
+# run_pkt_decode_tests.bash use-installed <options>
 #
 # * use supplied path for binary + libs (must have trailing /)
-# run_pkt_decode_tests.bash <custom>/<path>/
+# run_pkt_decode_tests.bash -bindir <custom>/<path>/ <options>
 #
 
 OUT_DIR=./results
@@ -75,8 +75,11 @@
 
 if [ "$1" == "use-installed" ]; then
     BIN_DIR=""
-elif [ "$1" != "" ]; then
-    BIN_DIR=$1
+    shift
+elif [ "$1" == "-bindir" ]; then
+    BIN_DIR=$2
+    shift
+    shift
 fi
 
 echo "Tests using BIN_DIR = ${BIN_DIR}"
@@ -90,17 +93,17 @@
 for test_dir in "${test_dirs_decode[@]}"
 do
     echo "Testing $test_dir..."
-    ${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/$test_dir" -decode -logfilename "${OUT_DIR}/$test_dir.ppl"
+    ${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/$test_dir" $@ -decode -logfilename "${OUT_DIR}/$test_dir.ppl"
     echo "Done : Return $?"
 done
 
 # === test a packet only example ===
 echo "Testing init-short-addr..."
-${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/init-short-addr" -pkt_mon -logfilename "${OUT_DIR}/init-short-addr.ppl"
+${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/init-short-addr" $@ -pkt_mon -logfilename "${OUT_DIR}/init-short-addr.ppl"
 
 # === test the TPIU deformatter ===
 echo "Testing a55-test-tpiu..."
-${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/a55-test-tpiu" -dstream_format -o_raw_packed -o_raw_unpacked -logfilename "${OUT_DIR}/a55-test-tpiu.ppl"
+${BIN_DIR}trc_pkt_lister -ss_dir "${SNAPSHOT_DIR}/a55-test-tpiu" $@ -dstream_format -o_raw_packed -o_raw_unpacked -logfilename "${OUT_DIR}/a55-test-tpiu.ppl"
 echo "Done : Return $?"
 
 # === test the C-API lib - this test prog is not installed ===
diff --git a/decoder/tests/snapshot_parser_lib/include/snapshot_parser.h b/decoder/tests/snapshot_parser_lib/include/snapshot_parser.h
index 8b91712..9e5b371 100644
--- a/decoder/tests/snapshot_parser_lib/include/snapshot_parser.h
+++ b/decoder/tests/snapshot_parser_lib/include/snapshot_parser.h
@@ -135,9 +135,9 @@
     std::vector<std::string> GetBufferNameList(ParsedTrace &metadata);
 
 
-    static ITraceErrorLog *s_pErrorLogger = 0;
-    static ocsd_hndl_err_log_t s_errlog_handle = 0;
-    static bool s_verbose_logging = true;
+    //static ITraceErrorLog *s_pErrorLogger = 0;
+    //static ocsd_hndl_err_log_t s_errlog_handle = 0;
+    //static bool s_verbose_logging = true;
 
     void SetIErrorLogger(ITraceErrorLog *i_err_log);
     void SetVerboseLogging(bool verbose);
diff --git a/decoder/tests/snapshot_parser_lib/source/snapshot_parser.cpp b/decoder/tests/snapshot_parser_lib/source/snapshot_parser.cpp
index 6e62d1e..4570700 100644
--- a/decoder/tests/snapshot_parser_lib/source/snapshot_parser.cpp
+++ b/decoder/tests/snapshot_parser_lib/source/snapshot_parser.cpp
@@ -49,6 +49,10 @@
 
 #include "opencsd.h"
 
+static ITraceErrorLog *s_pErrorLogger = 0;
+static ocsd_hndl_err_log_t s_errlog_handle = 0;
+static bool s_verbose_logging = true;
+
 /*************************************************************************
  * Note, this file handles the parsring of the general (device specific) 
  * ini file and the (much smaller) device_list file
diff --git a/decoder/tests/source/c_api_pkt_print_test.c b/decoder/tests/source/c_api_pkt_print_test.c
index caa67e9..fa9f48d 100644
--- a/decoder/tests/source/c_api_pkt_print_test.c
+++ b/decoder/tests/source/c_api_pkt_print_test.c
@@ -119,6 +119,9 @@
 /* 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[])
 {
@@ -185,6 +188,10 @@
         {
             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;
@@ -648,6 +655,7 @@
     {
         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;
@@ -683,6 +691,7 @@
     {
         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);
@@ -708,6 +717,7 @@
     {
         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);
@@ -754,6 +764,7 @@
     {
         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);
@@ -881,6 +892,28 @@
     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", p_stats->channel_total,
+            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;
@@ -943,7 +976,9 @@
         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)
         {
@@ -1007,7 +1042,7 @@
         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 %ld; cs_id 0x%02x;\nstring: %s\n", err_test, err_index, cs_id, err_buffer);
+        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;
diff --git a/decoder/tests/source/mem_buff_demo.cpp b/decoder/tests/source/mem_buff_demo.cpp
index cacc227..052870f 100644
--- a/decoder/tests/source/mem_buff_demo.cpp
+++ b/decoder/tests/source/mem_buff_demo.cpp
@@ -126,6 +126,7 @@
     FILE *fp;
     std::string filename;
     long size;
+    size_t bytes_read;
 
     /* the file names to create the data buffers */
 #ifdef _WIN32
@@ -158,8 +159,10 @@
         return OCSD_ERR_MEM;
     } 
     rewind(fp);
-    fread(input_trace_data, 1, input_trace_data_size, 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;
@@ -178,8 +181,10 @@
         return OCSD_ERR_MEM;
     }
     rewind(fp);
-    fread(program_image_buffer, 1, program_image_size, 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;
 }
diff --git a/decoder/tests/source/trc_pkt_lister.cpp b/decoder/tests/source/trc_pkt_lister.cpp
index 6c8614e..9760351 100644
--- a/decoder/tests/source/trc_pkt_lister.cpp
+++ b/decoder/tests/source/trc_pkt_lister.cpp
@@ -74,6 +74,7 @@
 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[])
 {
@@ -195,6 +196,7 @@
     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";
@@ -396,6 +398,10 @@
             {
                 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();
@@ -536,6 +542,60 @@
     }
 }
 
+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;
@@ -679,7 +739,8 @@
                 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
             {