| /* | |
| * \file ocsd_dcd_tree.cpp | |
| * \brief OpenCSD : | |
| * | |
| * \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. | |
| */ | |
| #include <new> | |
| #include "common/ocsd_dcd_tree.h" | |
| #include "common/ocsd_lib_dcd_register.h" | |
| #include "mem_acc/trc_mem_acc_mapper.h" | |
| /***************************************************************/ | |
| ITraceErrorLog *DecodeTree::s_i_error_logger = &DecodeTree::s_error_logger; | |
| std::list<DecodeTree *> DecodeTree::s_trace_dcd_trees; /**< list of pointers to decode tree objects */ | |
| ocsdDefaultErrorLogger DecodeTree::s_error_logger; /**< The library default error logger */ | |
| TrcIDecode DecodeTree::s_instruction_decoder; /**< default instruction decode library */ | |
| DecodeTree *DecodeTree::CreateDecodeTree(const ocsd_dcd_tree_src_t src_type, uint32_t formatterCfgFlags) | |
| { | |
| DecodeTree *dcd_tree = new (std::nothrow) DecodeTree(); | |
| if(dcd_tree != 0) | |
| { | |
| if(dcd_tree->initialise(src_type, formatterCfgFlags)) | |
| { | |
| s_trace_dcd_trees.push_back(dcd_tree); | |
| s_instruction_decoder.envSetAA64_errOnBadOpcode(); | |
| } | |
| else | |
| { | |
| delete dcd_tree; | |
| dcd_tree = 0; | |
| } | |
| } | |
| return dcd_tree; | |
| } | |
| void DecodeTree::DestroyDecodeTree(DecodeTree *p_dcd_tree) | |
| { | |
| std::list<DecodeTree *>::iterator it; | |
| bool bDestroyed = false; | |
| it = s_trace_dcd_trees.begin(); | |
| while(!bDestroyed && (it != s_trace_dcd_trees.end())) | |
| { | |
| if(*it == p_dcd_tree) | |
| { | |
| s_trace_dcd_trees.erase(it); | |
| delete p_dcd_tree; | |
| bDestroyed = true; | |
| } | |
| else | |
| it++; | |
| } | |
| } | |
| void DecodeTree::setAlternateErrorLogger(ITraceErrorLog *p_error_logger) | |
| { | |
| if(p_error_logger) | |
| s_i_error_logger = p_error_logger; | |
| else | |
| s_i_error_logger = &s_error_logger; | |
| // set debug error logger on the decoder. | |
| TrcIDecode::setErrLogger(getCurrentErrorLogI()); | |
| } | |
| /***************************************************************/ | |
| DecodeTree::DecodeTree() : | |
| m_i_instr_decode(&s_instruction_decoder), | |
| m_i_mem_access(0), | |
| m_i_gen_elem_out(0), | |
| m_i_decoder_root(0), | |
| m_frame_deformatter_root(0), | |
| m_decode_elem_iter(0), | |
| m_default_mapper(0), | |
| m_created_mapper(false) | |
| { | |
| 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() | |
| { | |
| destroyMemAccessors(); | |
| destroyMemAccMapper(); | |
| for(uint8_t i = 0; i < 0x80; i++) | |
| { | |
| destroyDecodeElement(i); | |
| } | |
| PktPrinterFact::destroyAllPrinters(m_printer_list); | |
| delete m_frame_deformatter_root; | |
| } | |
| ocsd_datapath_resp_t DecodeTree::TraceDataIn( const ocsd_datapath_op_t op, | |
| const ocsd_trc_index_t index, | |
| const uint32_t dataBlockSize, | |
| const uint8_t *pDataBlock, | |
| uint32_t *numBytesProcessed) | |
| { | |
| if(m_i_decoder_root) | |
| return m_i_decoder_root->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed); | |
| *numBytesProcessed = 0; | |
| return OCSD_RESP_FATAL_NOT_INIT; | |
| } | |
| /* set key interfaces - attach / replace on any existing tree components */ | |
| void DecodeTree::setInstrDecoder(IInstrDecode *i_instr_decode) | |
| { | |
| uint8_t elemID; | |
| DecodeTreeElement *pElem = 0; | |
| pElem = getFirstElement(elemID); | |
| while(pElem != 0) | |
| { | |
| pElem->getDecoderMngr()->attachInstrDecoder(pElem->getDecoderHandle(),i_instr_decode); | |
| pElem = getNextElement(elemID); | |
| } | |
| } | |
| void DecodeTree::setMemAccessI(ITargetMemAccess *i_mem_access) | |
| { | |
| uint8_t elemID; | |
| DecodeTreeElement *pElem = 0; | |
| pElem = getFirstElement(elemID); | |
| while(pElem != 0) | |
| { | |
| pElem->getDecoderMngr()->attachMemAccessor(pElem->getDecoderHandle(),i_mem_access); | |
| pElem = getNextElement(elemID); | |
| } | |
| m_i_mem_access = i_mem_access; | |
| } | |
| void DecodeTree::setGenTraceElemOutI(ITrcGenElemIn *i_gen_trace_elem) | |
| { | |
| uint8_t elemID; | |
| DecodeTreeElement *pElem = 0; | |
| pElem = getFirstElement(elemID); | |
| while(pElem != 0) | |
| { | |
| pElem->getDecoderMngr()->attachOutputSink(pElem->getDecoderHandle(),i_gen_trace_elem); | |
| pElem = getNextElement(elemID); | |
| } | |
| /* set local copy of interface to return in getGenTraceElemOutI */ | |
| m_i_gen_elem_out = i_gen_trace_elem; | |
| } | |
| ocsd_err_t DecodeTree::createMemAccMapper(memacc_mapper_t type /* = MEMACC_MAP_GLOBAL*/ ) | |
| { | |
| // clean up any old one | |
| destroyMemAccMapper(); | |
| // make a new one | |
| switch(type) | |
| { | |
| default: | |
| case MEMACC_MAP_GLOBAL: | |
| m_default_mapper = new (std::nothrow) TrcMemAccMapGlobalSpace(); | |
| break; | |
| } | |
| // set the access interface | |
| if(m_default_mapper) | |
| { | |
| bool enableCaching; | |
| int cachePageSize, cachePageNum; | |
| m_created_mapper = true; | |
| setMemAccessI(m_default_mapper); | |
| m_default_mapper->setErrorLog(s_i_error_logger); | |
| TrcMemAccCache::getenvMemaccCacheSizes(enableCaching, cachePageSize, cachePageNum); | |
| if ((m_default_mapper->setCacheSizes(cachePageSize, cachePageNum) != OCSD_OK) || | |
| (m_default_mapper->enableCaching(enableCaching) != OCSD_OK)) | |
| destroyMemAccMapper(); | |
| } | |
| return (m_default_mapper != 0) ? OCSD_OK : OCSD_ERR_MEM; | |
| } | |
| void DecodeTree::setExternMemAccMapper(TrcMemAccMapper* pMapper) | |
| { | |
| destroyMemAccMapper(); // destroy any existing mapper - if decode tree created it. | |
| m_default_mapper = pMapper; | |
| } | |
| void DecodeTree::destroyMemAccMapper() | |
| { | |
| if(m_default_mapper && m_created_mapper) | |
| { | |
| m_default_mapper->RemoveAllAccessors(); | |
| delete m_default_mapper; | |
| m_default_mapper = 0; | |
| m_created_mapper = false; | |
| } | |
| } | |
| void DecodeTree::addMemAccessorToList(TrcMemAccessorBase* p_accessor) | |
| { | |
| m_mem_accessors.push_back(p_accessor); | |
| } | |
| // destroy mem accessors in use by this object | |
| void DecodeTree::destroyMemAccessors() | |
| { | |
| std::list<TrcMemAccessorBase*>::iterator it; | |
| it = m_mem_accessors.begin(); | |
| while (it != m_mem_accessors.end()) | |
| { | |
| TrcMemAccFactory::DestroyAccessor(*it); | |
| it++; | |
| } | |
| m_mem_accessors.clear(); | |
| } | |
| void DecodeTree::logMappedRanges() | |
| { | |
| if(m_default_mapper) | |
| m_default_mapper->logMappedRanges(); | |
| } | |
| ocsd_err_t DecodeTree::setMemAccCacheing(const bool enable, const uint16_t page_size, const int nr_pages) | |
| { | |
| ocsd_err_t err = OCSD_OK; | |
| if (!m_default_mapper) | |
| return OCSD_ERR_NOT_INIT; | |
| if (enable) | |
| { | |
| // set cache sizes - error if params out of limits | |
| err = m_default_mapper->setCacheSizes(page_size, nr_pages, true); | |
| if (err == OCSD_OK) | |
| err = m_default_mapper->enableCaching(true); | |
| } | |
| else | |
| err = m_default_mapper->enableCaching(false); | |
| return err; | |
| } | |
| /* Memory accessor creation - all on default mem accessor using the 0 CSID for global core space. */ | |
| ocsd_err_t DecodeTree::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) | |
| { | |
| if(!hasMemAccMapper()) | |
| return OCSD_ERR_NOT_INIT; | |
| // need a valid memory buffer, and a least enough bytes for one opcode. | |
| if((p_mem_buffer == 0) || (mem_length < 4)) | |
| return OCSD_ERR_INVALID_PARAM_VAL; | |
| TrcMemAccessorBase *p_accessor; | |
| ocsd_err_t err = TrcMemAccFactory::CreateBufferAccessor(&p_accessor, address, p_mem_buffer, mem_length); | |
| if(err == OCSD_OK) | |
| { | |
| TrcMemAccBufPtr *pMBuffAcc = dynamic_cast<TrcMemAccBufPtr *>(p_accessor); | |
| if(pMBuffAcc) | |
| { | |
| pMBuffAcc->setMemSpace(mem_space); | |
| err = m_default_mapper->AddAccessor(p_accessor,0); | |
| } | |
| else | |
| err = OCSD_ERR_MEM; // wrong type of object - treat as mem error | |
| if (err != OCSD_OK) | |
| TrcMemAccFactory::DestroyAccessor(p_accessor); | |
| else | |
| addMemAccessorToList(p_accessor); | |
| } | |
| return err; | |
| } | |
| ocsd_err_t DecodeTree::addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath) | |
| { | |
| if(!hasMemAccMapper()) | |
| return OCSD_ERR_NOT_INIT; | |
| if(filepath.length() == 0) | |
| return OCSD_ERR_INVALID_PARAM_VAL; | |
| TrcMemAccessorBase *p_accessor; | |
| ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,address); | |
| if(err == OCSD_OK) | |
| { | |
| TrcMemAccessorFile *pAcc = dynamic_cast<TrcMemAccessorFile *>(p_accessor); | |
| if(pAcc) | |
| { | |
| pAcc->setMemSpace(mem_space); | |
| err = m_default_mapper->AddAccessor(pAcc,0); | |
| } | |
| else | |
| err = OCSD_ERR_MEM; // wrong type of object - treat as mem error | |
| if (err != OCSD_OK) | |
| TrcMemAccFactory::DestroyAccessor(p_accessor); | |
| else | |
| addMemAccessorToList(p_accessor); | |
| } | |
| return err; | |
| } | |
| ocsd_err_t DecodeTree::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) | |
| { | |
| if(!hasMemAccMapper()) | |
| return OCSD_ERR_NOT_INIT; | |
| if((region_array == 0) || (num_regions == 0) || (filepath.length() == 0)) | |
| return OCSD_ERR_INVALID_PARAM_VAL; | |
| TrcMemAccessorBase *p_accessor; | |
| int curr_region_idx = 0; | |
| // add first region during the creation of the file accessor. | |
| ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,region_array[curr_region_idx].start_address,region_array[curr_region_idx].file_offset, region_array[curr_region_idx].region_size); | |
| if(err == OCSD_OK) | |
| { | |
| TrcMemAccessorFile *pAcc = dynamic_cast<TrcMemAccessorFile *>(p_accessor); | |
| if(pAcc) | |
| { | |
| // add additional regions to the file accessor. | |
| curr_region_idx++; | |
| while(curr_region_idx < num_regions) | |
| { | |
| pAcc->AddOffsetRange(region_array[curr_region_idx].start_address, | |
| region_array[curr_region_idx].region_size, | |
| region_array[curr_region_idx].file_offset); | |
| curr_region_idx++; | |
| } | |
| pAcc->setMemSpace(mem_space); | |
| // add the accessor to the map. | |
| err = m_default_mapper->AddAccessor(pAcc,0); | |
| } | |
| else | |
| err = OCSD_ERR_MEM; // wrong type of object - treat as mem error | |
| if (err != OCSD_OK) | |
| TrcMemAccFactory::DestroyAccessor(p_accessor); | |
| else | |
| addMemAccessorToList(p_accessor); | |
| } | |
| return err; | |
| } | |
| ocsd_err_t DecodeTree::updateBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath) | |
| { | |
| if (!hasMemAccMapper()) | |
| return OCSD_ERR_NOT_INIT; | |
| if ((region_array == 0) || (num_regions == 0) || (filepath.length() == 0)) | |
| return OCSD_ERR_INVALID_PARAM_VAL; | |
| TrcMemAccessorFile *pAcc = TrcMemAccessorFile::getExistingFileAccessor(filepath); | |
| if (!pAcc) | |
| return OCSD_ERR_INVALID_PARAM_VAL; | |
| int curr_region_idx = 0; | |
| while (curr_region_idx < num_regions) | |
| { | |
| // check "new" range | |
| if (!pAcc->addrStartOfRange(region_array[curr_region_idx].start_address)) | |
| { | |
| // ensure adds cleanly | |
| if (!pAcc->AddOffsetRange(region_array[curr_region_idx].start_address, | |
| region_array[curr_region_idx].region_size, | |
| region_array[curr_region_idx].file_offset)) | |
| return OCSD_ERR_INVALID_PARAM_VAL; // otherwise bail out | |
| } | |
| curr_region_idx++; | |
| } | |
| return OCSD_OK; | |
| } | |
| ocsd_err_t DecodeTree::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) | |
| { | |
| if(!hasMemAccMapper()) | |
| return OCSD_ERR_NOT_INIT; | |
| if(p_cb_func == 0) | |
| return OCSD_ERR_INVALID_PARAM_VAL; | |
| TrcMemAccessorBase *p_accessor; | |
| ocsd_err_t err = TrcMemAccFactory::CreateCBAccessor(&p_accessor, st_address, en_address, mem_space); | |
| if(err == OCSD_OK) | |
| { | |
| TrcMemAccCB *pCBAcc = dynamic_cast<TrcMemAccCB *>(p_accessor); | |
| if(pCBAcc) | |
| { | |
| if (IDfn) | |
| pCBAcc->setCBIDIfFn((Fn_MemAccID_CB)p_cb_func, p_context); | |
| else | |
| pCBAcc->setCBIfFn((Fn_MemAcc_CB)p_cb_func, p_context); | |
| err = m_default_mapper->AddAccessor(p_accessor,0); | |
| } | |
| else | |
| err = OCSD_ERR_MEM; // wrong type of object - treat as mem error | |
| if (err != OCSD_OK) | |
| TrcMemAccFactory::DestroyAccessor(p_accessor); | |
| else | |
| addMemAccessorToList(p_accessor); | |
| } | |
| return err; | |
| } | |
| ocsd_err_t DecodeTree::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) | |
| { | |
| return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, false, p_context); | |
| } | |
| ocsd_err_t DecodeTree::addCallbackIDMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAccID_CB p_cb_func, const void *p_context) | |
| { | |
| return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, true, p_context); | |
| } | |
| ocsd_err_t DecodeTree::removeMemAccByAddress(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space) | |
| { | |
| if(!hasMemAccMapper()) | |
| return OCSD_ERR_NOT_INIT; | |
| return m_default_mapper->RemoveAccessorByAddress(address,mem_space,0); | |
| } | |
| ocsd_err_t DecodeTree::createDecoder(const std::string &decoderName, const int createFlags, const CSConfig *pConfig) | |
| { | |
| ocsd_err_t err = OCSD_OK; | |
| IDecoderMngr *pDecoderMngr = 0; | |
| TraceComponent *pTraceComp = 0; | |
| int crtFlags = createFlags; | |
| uint8_t CSID = 0; // default for single stream decoder (no deformatter) - we ignore the ID | |
| if(usingFormatter()) | |
| { | |
| CSID = pConfig->getTraceID(); | |
| crtFlags |= OCSD_CREATE_FLG_INST_ID; | |
| } | |
| // check for the aa64 check. | |
| if (createFlags & ETM4_OPFLG_PKTDEC_AA64_OPCODE_CHK) | |
| s_instruction_decoder.setAA64_errOnBadOpcode(true); | |
| // create the decode element to attach to the channel. | |
| if((err = createDecodeElement(CSID)) != OCSD_OK) | |
| return err; | |
| // get the libary decoder register. | |
| OcsdLibDcdRegister * lib_reg = OcsdLibDcdRegister::getDecoderRegister(); | |
| if(lib_reg == 0) | |
| return OCSD_ERR_NOT_INIT; | |
| // find the named decoder | |
| if((err = lib_reg->getDecoderMngrByName(decoderName,&pDecoderMngr)) != OCSD_OK) | |
| return err; | |
| // got the decoder... | |
| if((err = pDecoderMngr->createDecoder(crtFlags,(int)CSID,pConfig,&pTraceComp)) != OCSD_OK) | |
| return err; | |
| m_decode_elements[CSID]->SetDecoderElement(decoderName, pDecoderMngr, pTraceComp, true); | |
| // always attach an error logger | |
| if(err == OCSD_OK) | |
| err = pDecoderMngr->attachErrorLogger(pTraceComp,DecodeTree::s_i_error_logger); | |
| // if we created a packet decoder it may need additional components. | |
| if(crtFlags & OCSD_CREATE_FLG_FULL_DECODER) | |
| { | |
| if(m_i_instr_decode && (err == OCSD_OK)) | |
| err = pDecoderMngr->attachInstrDecoder(pTraceComp,m_i_instr_decode); | |
| if(err == OCSD_ERR_DCD_INTERFACE_UNUSED) // ignore if instruction decoder refused | |
| err = OCSD_OK; | |
| if(m_i_mem_access && (err == OCSD_OK)) | |
| err = pDecoderMngr->attachMemAccessor(pTraceComp,m_i_mem_access); | |
| if(err == OCSD_ERR_DCD_INTERFACE_UNUSED) // ignore if mem accessor refused | |
| err = OCSD_OK; | |
| if( m_i_gen_elem_out && (err == OCSD_OK)) | |
| err = pDecoderMngr->attachOutputSink(pTraceComp,m_i_gen_elem_out); | |
| } | |
| // finally attach the packet processor input to the demux output channel | |
| if(err == OCSD_OK) | |
| { | |
| ITrcDataIn *pDataIn = 0; | |
| if((err = pDecoderMngr->getDataInputI(pTraceComp,&pDataIn)) == OCSD_OK) | |
| { | |
| // got the interface -> attach to demux, or direct to input of decode tree | |
| if(usingFormatter()) | |
| err = m_frame_deformatter_root->getIDStreamAttachPt(CSID)->attach(pDataIn); | |
| else | |
| m_i_decoder_root = pDataIn; | |
| } | |
| } | |
| if(err != OCSD_OK) | |
| { | |
| destroyDecodeElement(CSID); // will destroy decoder as well. | |
| } | |
| return err; | |
| } | |
| ocsd_err_t DecodeTree::removeDecoder(const uint8_t CSID) | |
| { | |
| ocsd_err_t err = OCSD_OK; | |
| uint8_t localID = CSID; | |
| if(!usingFormatter()) | |
| localID = 0; | |
| if(usingFormatter() && !OCSD_IS_VALID_CS_SRC_ID(CSID)) | |
| err = OCSD_ERR_INVALID_ID; | |
| else | |
| { | |
| destroyDecodeElement(localID); | |
| } | |
| 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; | |
| if(usingFormatter() && OCSD_IS_VALID_CS_SRC_ID(CSID)) | |
| { | |
| ret_elem = m_decode_elements[CSID]; | |
| } | |
| else | |
| ret_elem = m_decode_elements[0]; // ID 0 is used if single leaf tree. | |
| return ret_elem; | |
| } | |
| DecodeTreeElement *DecodeTree::getFirstElement(uint8_t &elemID) | |
| { | |
| m_decode_elem_iter = 0; | |
| return getNextElement(elemID); | |
| } | |
| DecodeTreeElement *DecodeTree::getNextElement(uint8_t &elemID) | |
| { | |
| DecodeTreeElement *ret_elem = 0; | |
| if(m_decode_elem_iter < 0x80) | |
| { | |
| // find a none zero entry or end of range | |
| while((m_decode_elem_iter < 0x80) && (m_decode_elements[m_decode_elem_iter] == 0)) | |
| m_decode_elem_iter++; | |
| // return entry unless end of range | |
| if(m_decode_elem_iter < 0x80) | |
| { | |
| ret_elem = m_decode_elements[m_decode_elem_iter]; | |
| elemID = m_decode_elem_iter; | |
| m_decode_elem_iter++; | |
| } | |
| } | |
| return ret_elem; | |
| } | |
| bool DecodeTree::initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCfgFlags) | |
| { | |
| ocsd_err_t err; | |
| m_dcd_tree_type = type; | |
| if(type == OCSD_TRC_SRC_FRAME_FORMATTED) | |
| { | |
| // frame formatted - we want to create the deformatter and hook it up | |
| m_frame_deformatter_root = new (std::nothrow) TraceFormatterFrameDecoder(); | |
| if(m_frame_deformatter_root) | |
| { | |
| if (m_frame_deformatter_root->Init() != OCSD_OK) | |
| return false; | |
| m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger); | |
| err = m_frame_deformatter_root->Configure(formatterCfgFlags); | |
| if (err != OCSD_OK) | |
| return false; | |
| m_i_decoder_root = dynamic_cast<ITrcDataIn*>(m_frame_deformatter_root); | |
| m_frame_deformatter_root->SetDemuxStatsBlock(&m_demux_stats); | |
| } | |
| else | |
| return false; | |
| } | |
| // set debug error logger on the decoder. | |
| TrcIDecode::setErrLogger(getCurrentErrorLogI()); | |
| return true; | |
| } | |
| void DecodeTree::setSingleRoot(TrcPktProcI *pComp) | |
| { | |
| m_i_decoder_root = static_cast<ITrcDataIn*>(pComp); | |
| } | |
| ocsd_err_t DecodeTree::createDecodeElement(const uint8_t CSID) | |
| { | |
| ocsd_err_t err = OCSD_ERR_INVALID_ID; | |
| if(CSID < 0x80) | |
| { | |
| if(m_decode_elements[CSID] == 0) | |
| { | |
| m_decode_elements[CSID] = new (std::nothrow) DecodeTreeElement(); | |
| if(m_decode_elements[CSID] == 0) | |
| err = OCSD_ERR_MEM; | |
| else | |
| err = OCSD_OK; | |
| } | |
| else | |
| err = OCSD_ERR_ATTACH_TOO_MANY; | |
| } | |
| return err; | |
| } | |
| void DecodeTree::destroyDecodeElement(const uint8_t CSID) | |
| { | |
| if(CSID < 0x80) | |
| { | |
| if(m_decode_elements[CSID] != 0) | |
| { | |
| m_decode_elements[CSID]->DestroyElem(); | |
| delete m_decode_elements[CSID]; | |
| m_decode_elements[CSID] = 0; | |
| } | |
| } | |
| } | |
| ocsd_err_t DecodeTree::setIDFilter(std::vector<uint8_t> &ids) | |
| { | |
| ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER; | |
| if(usingFormatter()) | |
| { | |
| err = m_frame_deformatter_root->OutputFilterAllIDs(false); | |
| if(err == OCSD_OK) | |
| err = m_frame_deformatter_root->OutputFilterIDs(ids,true); | |
| } | |
| return err; | |
| } | |
| ocsd_err_t DecodeTree::clearIDFilter() | |
| { | |
| ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER; | |
| if(usingFormatter()) | |
| { | |
| err = m_frame_deformatter_root->OutputFilterAllIDs(true); | |
| } | |
| return err; | |
| } | |
| /** add a protocol packet printer */ | |
| ocsd_err_t DecodeTree::addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter **ppPrinter) | |
| { | |
| ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL; | |
| DecodeTreeElement *pElement = getDecoderElement(CSID); | |
| if (pElement) | |
| { | |
| ocsd_trace_protocol_t protocol = pElement->getProtocol(); | |
| ItemPrinter *pPrinter; | |
| pPrinter = PktPrinterFact::createProtocolPrinter(getPrinterList(), protocol, CSID); | |
| if (pPrinter) | |
| { | |
| pPrinter->setMessageLogger(getCurrentErrorLogI()->getOutputLogger()); | |
| switch (protocol) | |
| { | |
| case OCSD_PROTOCOL_ETMV4I: | |
| case OCSD_PROTOCOL_ETE: | |
| { | |
| PacketPrinter<EtmV4ITrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV4ITrcPacket> *>(pPrinter); | |
| if (bMonitor) | |
| err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<EtmV4ITrcPacket> *)pTPrinter); | |
| else | |
| err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<EtmV4ITrcPacket> *)pTPrinter); | |
| } | |
| break; | |
| case OCSD_PROTOCOL_ETMV3: | |
| { | |
| PacketPrinter<EtmV3TrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV3TrcPacket> *>(pPrinter); | |
| if (bMonitor) | |
| err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<EtmV3TrcPacket> *)pTPrinter); | |
| else | |
| err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<EtmV3TrcPacket> *)pTPrinter); | |
| } | |
| break; | |
| case OCSD_PROTOCOL_PTM: | |
| { | |
| PacketPrinter<PtmTrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<PtmTrcPacket> *>(pPrinter); | |
| if (bMonitor) | |
| err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<PtmTrcPacket> *)pTPrinter); | |
| else | |
| err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<PtmTrcPacket> *)pTPrinter); | |
| } | |
| break; | |
| case OCSD_PROTOCOL_STM: | |
| { | |
| PacketPrinter<StmTrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<StmTrcPacket> *>(pPrinter); | |
| if (bMonitor) | |
| err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<StmTrcPacket> *)pTPrinter); | |
| else | |
| err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<StmTrcPacket> *)pTPrinter); | |
| } | |
| break; | |
| case OCSD_PROTOCOL_ITM: | |
| { | |
| PacketPrinter<ItmTrcPacket>* pTPrinter = dynamic_cast<PacketPrinter<ItmTrcPacket> *>(pPrinter); | |
| if (bMonitor) | |
| err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<ItmTrcPacket> *)pTPrinter); | |
| else | |
| err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<ItmTrcPacket> *)pTPrinter); | |
| } | |
| break; | |
| default: | |
| err = OCSD_ERR_NO_PROTOCOL; | |
| break; | |
| } | |
| if (err == OCSD_OK) | |
| { | |
| if (ppPrinter) | |
| *ppPrinter = pPrinter; | |
| } | |
| else | |
| PktPrinterFact::destroyPrinter(getPrinterList(), pPrinter); | |
| } | |
| } | |
| return err; | |
| } | |
| /** add a raw frame printer */ | |
| ocsd_err_t DecodeTree::addRawFramePrinter(RawFramePrinter **ppPrinter, uint32_t flags) | |
| { | |
| ocsd_err_t err = OCSD_ERR_MEM; | |
| RawFramePrinter *pPrinter = PktPrinterFact::createRawFramePrinter(getPrinterList()); | |
| if (pPrinter) | |
| { | |
| pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger())); | |
| TraceFormatterFrameDecoder *pFrameDecoder = getFrameDeformatter(); | |
| uint32_t cfgFlags = pFrameDecoder->getConfigFlags(); | |
| cfgFlags |= ((uint32_t)flags & (OCSD_DFRMTR_PACKED_RAW_OUT | OCSD_DFRMTR_UNPACKED_RAW_OUT)); | |
| pFrameDecoder->Configure(cfgFlags); | |
| err = pFrameDecoder->getTrcRawFrameAttachPt()->attach(pPrinter); | |
| if (ppPrinter && (err==OCSD_OK)) | |
| *ppPrinter = pPrinter; | |
| } | |
| return err; | |
| } | |
| /** add a generic element output printer */ | |
| ocsd_err_t DecodeTree::addGenElemPrinter(TrcGenericElementPrinter **ppPrinter) | |
| { | |
| ocsd_err_t err = OCSD_ERR_MEM; | |
| TrcGenericElementPrinter *pPrinter = PktPrinterFact::createGenElemPrinter(getPrinterList()); | |
| if (pPrinter) | |
| { | |
| pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger())); | |
| setGenTraceElemOutI(pPrinter); | |
| err = OCSD_OK; | |
| if (ppPrinter) | |
| *ppPrinter = pPrinter; | |
| } | |
| return err; | |
| } | |
| /* End of File ocsd_dcd_tree.cpp */ |