/* * \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 "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::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); } else { delete dcd_tree; dcd_tree = 0; } } return dcd_tree; } void DecodeTree::DestroyDecodeTree(DecodeTree *p_dcd_tree) { std::list::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; } /***************************************************************/ 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; } DecodeTree::~DecodeTree() { 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); } } 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) { m_created_mapper = true; setMemAccessI(m_default_mapper); m_default_mapper->setErrorLog(s_i_error_logger); } 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::logMappedRanges() { if(m_default_mapper) m_default_mapper->logMappedRanges(); } /* 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(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); } 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(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); } 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(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); } 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(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); } 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; } // 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; } 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_elements[m_decode_elem_iter] == 0) && (m_decode_elem_iter < 0x80)) 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) { bool initOK = true; 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) { m_frame_deformatter_root->Configure(formatterCfgFlags); m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger); m_i_decoder_root = dynamic_cast(m_frame_deformatter_root); } else initOK = false; } return initOK; } void DecodeTree::setSingleRoot(TrcPktProcI *pComp) { m_i_decoder_root = static_cast(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 &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: { PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); if (bMonitor) err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); else err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); } break; case OCSD_PROTOCOL_ETMV3: { PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); if (bMonitor) err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); else err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); } break; case OCSD_PROTOCOL_PTM: { PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); if (bMonitor) err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); else err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)pTPrinter); } break; case OCSD_PROTOCOL_STM: { PacketPrinter *pTPrinter = dynamic_cast *>(pPrinter); if (bMonitor) err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon *)pTPrinter); else err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn *)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 */