/* * \file ocsd_c_api.cpp * \brief OpenCSD : "C" API libary implementation. * * \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 /* pull in the C++ decode library */ #include "opencsd.h" /* C-API and wrapper objects */ #include "opencsd/c_api/opencsd_c_api.h" #include "ocsd_c_api_obj.h" /** MSVC2010 unwanted export workaround */ #ifdef WIN32 #if (_MSC_VER == 1600) #include namespace std { const nothrow_t nothrow = nothrow_t(); } #endif #endif /*******************************************************************************/ /* C API internal helper function declarations */ /*******************************************************************************/ static ocsd_err_t ocsd_create_pkt_sink_cb(ocsd_trace_protocol_t protocol, FnDefPktDataIn pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ); static ocsd_err_t ocsd_create_pkt_mon_cb(ocsd_trace_protocol_t protocol, FnDefPktDataMon pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ); static ocsd_err_t ocsd_check_and_add_mem_acc_mapper(const dcd_tree_handle_t handle, DecodeTree **ppDT); /*******************************************************************************/ /* C library data - additional data on top of the C++ library objects */ /*******************************************************************************/ /* keep a list of interface objects for a decode tree for later disposal */ typedef struct _lib_dt_data_list { std::vector cb_objs; DefLogStrCBObj s_def_log_str_cb; } lib_dt_data_list; /* map lists to handles */ static std::map s_data_map; /*******************************************************************************/ /* C API functions */ /*******************************************************************************/ /** Get Library version. Return a 32 bit version in form MMMMnnpp - MMMM = major version, nn = minor version, pp = patch version */ OCSD_C_API uint32_t ocsd_get_version(void) { return ocsdVersion::vers_num(); } /** Get library version string */ OCSD_C_API const char * ocsd_get_version_str(void) { return ocsdVersion::vers_str(); } /*** Decode tree creation etc. */ OCSD_C_API dcd_tree_handle_t ocsd_create_dcd_tree(const ocsd_dcd_tree_src_t src_type, const uint32_t deformatterCfgFlags) { dcd_tree_handle_t handle = C_API_INVALID_TREE_HANDLE; handle = (dcd_tree_handle_t)DecodeTree::CreateDecodeTree(src_type,deformatterCfgFlags); if(handle != C_API_INVALID_TREE_HANDLE) { lib_dt_data_list *pList = new (std::nothrow) lib_dt_data_list; if(pList != 0) { s_data_map.insert(std::pair(handle,pList)); } else { ocsd_destroy_dcd_tree(handle); handle = C_API_INVALID_TREE_HANDLE; } } return handle; } OCSD_C_API void ocsd_destroy_dcd_tree(const dcd_tree_handle_t handle) { if(handle != C_API_INVALID_TREE_HANDLE) { GenTraceElemCBObj * pIf = (GenTraceElemCBObj *)(((DecodeTree *)handle)->getGenTraceElemOutI()); if(pIf != 0) delete pIf; /* need to clear any associated callback data. */ std::map::iterator it; it = s_data_map.find(handle); if(it != s_data_map.end()) { std::vector::iterator itcb; itcb = it->second->cb_objs.begin(); while(itcb != it->second->cb_objs.end()) { delete *itcb; itcb++; } it->second->cb_objs.clear(); delete it->second; s_data_map.erase(it); } DecodeTree::DestroyDecodeTree((DecodeTree *)handle); } } /*** Decode tree process data */ OCSD_C_API ocsd_datapath_resp_t ocsd_dt_process_data(const dcd_tree_handle_t handle, const ocsd_datapath_op_t op, const ocsd_trc_index_t index, const uint32_t dataBlockSize, const uint8_t *pDataBlock, uint32_t *numBytesProcessed) { ocsd_datapath_resp_t resp = OCSD_RESP_FATAL_NOT_INIT; if(handle != C_API_INVALID_TREE_HANDLE) resp = ((DecodeTree *)handle)->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed); return resp; } /*** Decode tree - decoder management */ OCSD_C_API ocsd_err_t ocsd_dt_create_decoder(const dcd_tree_handle_t handle, const char *decoder_name, const int create_flags, const void *decoder_cfg, unsigned char *pCSID ) { ocsd_err_t err = OCSD_OK; DecodeTree *dt = (DecodeTree *)handle; std::string dName = decoder_name; IDecoderMngr *pDcdMngr; err = OcsdLibDcdRegister::getDecoderRegister()->getDecoderMngrByName(dName,&pDcdMngr); if(err != OCSD_OK) return err; CSConfig *pConfig = 0; err = pDcdMngr->createConfigFromDataStruct(&pConfig,decoder_cfg); if(err != OCSD_OK) return err; err = dt->createDecoder(dName,create_flags,pConfig); if(err == OCSD_OK) *pCSID = pConfig->getTraceID(); delete pConfig; return err; } OCSD_C_API ocsd_err_t ocsd_dt_remove_decoder( const dcd_tree_handle_t handle, const unsigned char CSID) { return ((DecodeTree *)handle)->removeDecoder(CSID); } OCSD_C_API ocsd_err_t ocsd_dt_attach_packet_callback( const dcd_tree_handle_t handle, const unsigned char CSID, const ocsd_c_api_cb_types callback_type, void *p_fn_callback_data, const void *p_context) { ocsd_err_t err = OCSD_OK; DecodeTree *pDT = static_cast(handle); DecodeTreeElement *pElem = pDT->getDecoderElement(CSID); if(pElem == 0) return OCSD_ERR_INVALID_ID; // cannot find entry for that CSID ITrcTypedBase *pDataInSink = 0; // pointer to a sink callback object switch(callback_type) { case OCSD_C_API_CB_PKT_SINK: err = ocsd_create_pkt_sink_cb(pElem->getProtocol(),(FnDefPktDataIn)p_fn_callback_data,p_context,&pDataInSink); if(err == OCSD_OK) err = pElem->getDecoderMngr()->attachPktSink(pElem->getDecoderHandle(), pDataInSink); break; case OCSD_C_API_CB_PKT_MON: err = ocsd_create_pkt_mon_cb(pElem->getProtocol(),(FnDefPktDataMon)p_fn_callback_data,p_context,&pDataInSink); if (err == OCSD_OK) err = pElem->getDecoderMngr()->attachPktMonitor(pElem->getDecoderHandle(), pDataInSink); break; default: err = OCSD_ERR_INVALID_PARAM_VAL; } if(err == OCSD_OK) { if (err == OCSD_OK) { // save object pointer for destruction later. std::map::iterator it; it = s_data_map.find(handle); if (it != s_data_map.end()) it->second->cb_objs.push_back(pDataInSink); } else delete pDataInSink; } return err; } 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(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(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) { GenTraceElemCBObj * pCBObj = new (std::nothrow)GenTraceElemCBObj(pFn, p_context); if(pCBObj) { ((DecodeTree *)handle)->setGenTraceElemOutI(pCBObj); return OCSD_OK; } return OCSD_ERR_MEM; } /*** Default error logging */ OCSD_C_API ocsd_err_t ocsd_def_errlog_init(const ocsd_err_severity_t verbosity, const int create_output_logger) { if(DecodeTree::getDefaultErrorLogger()->initErrorLogger(verbosity,(bool)(create_output_logger != 0))) return OCSD_OK; return OCSD_ERR_NOT_INIT; } OCSD_C_API ocsd_err_t ocsd_def_errlog_config_output(const int output_flags, const char *log_file_name) { ocsdMsgLogger *pLogger = DecodeTree::getDefaultErrorLogger()->getOutputLogger(); if(pLogger) { pLogger->setLogOpts(output_flags & C_API_MSGLOGOUT_MASK); if(log_file_name != NULL) { pLogger->setLogFileName(log_file_name); } return OCSD_OK; } return OCSD_ERR_NOT_INIT; } OCSD_C_API ocsd_err_t ocsd_def_errlog_set_strprint_cb(const dcd_tree_handle_t handle, void *p_context, FnDefLoggerPrintStrCB p_str_print_cb) { ocsdMsgLogger *pLogger = DecodeTree::getDefaultErrorLogger()->getOutputLogger(); if (pLogger) { std::map::iterator it; it = s_data_map.find(handle); if (it != s_data_map.end()) { DefLogStrCBObj *pCBObj = &(it->second->s_def_log_str_cb); pCBObj->setCBFn(p_context, p_str_print_cb); pLogger->setStrOutFn(pCBObj); int logOpts = pLogger->getLogOpts(); logOpts |= (int)(ocsdMsgLogger::OUT_STR_CB); pLogger->setLogOpts(logOpts); return OCSD_OK; } } return OCSD_ERR_NOT_INIT; } OCSD_C_API void ocsd_def_errlog_msgout(const char *msg) { ocsdMsgLogger *pLogger = DecodeTree::getDefaultErrorLogger()->getOutputLogger(); if(pLogger) pLogger->LogMsg(msg); } /*** Convert packet to string */ OCSD_C_API ocsd_err_t ocsd_pkt_str(const ocsd_trace_protocol_t pkt_protocol, const void *p_pkt, char *buffer, const int buffer_size) { ocsd_err_t err = OCSD_OK; if((buffer == NULL) || (buffer_size < 2)) return OCSD_ERR_INVALID_PARAM_VAL; std::string pktStr = ""; buffer[0] = 0; switch(pkt_protocol) { case OCSD_PROTOCOL_ETMV4I: trcPrintElemToString(p_pkt, pktStr); break; case OCSD_PROTOCOL_ETMV3: trcPrintElemToString(p_pkt, pktStr); break; case OCSD_PROTOCOL_STM: trcPrintElemToString(p_pkt, pktStr); break; case OCSD_PROTOCOL_PTM: trcPrintElemToString(p_pkt, pktStr); break; default: if (OCSD_PROTOCOL_IS_CUSTOM(pkt_protocol)) err = ocsd_cust_protocol_to_str(pkt_protocol, p_pkt, buffer, buffer_size); else err = OCSD_ERR_NO_PROTOCOL; break; } if(pktStr.size() > 0) { strncpy(buffer,pktStr.c_str(),buffer_size-1); buffer[buffer_size-1] = 0; } return err; } OCSD_C_API ocsd_err_t ocsd_gen_elem_str(const ocsd_generic_trace_elem *p_pkt, char *buffer, const int buffer_size) { ocsd_err_t err = OCSD_OK; if((buffer == NULL) || (buffer_size < 2)) return OCSD_ERR_INVALID_PARAM_VAL; std::string str; trcPrintElemToString(p_pkt,str); if(str.size() > 0) { strncpy(buffer,str.c_str(),buffer_size -1); buffer[buffer_size-1] = 0; } return err; } /*** Decode tree -- memory accessor control */ OCSD_C_API ocsd_err_t ocsd_dt_add_binfile_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const char *filepath) { ocsd_err_t err = OCSD_OK; DecodeTree *pDT; err = ocsd_check_and_add_mem_acc_mapper(handle,&pDT); if(err == OCSD_OK) err = pDT->addBinFileMemAcc(address,mem_space,filepath); return err; } OCSD_C_API ocsd_err_t ocsd_dt_add_binfile_region_mem_acc(const dcd_tree_handle_t handle, const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const char *filepath) { ocsd_err_t err = OCSD_OK; DecodeTree *pDT; err = ocsd_check_and_add_mem_acc_mapper(handle,&pDT); if(err == OCSD_OK) err = pDT->addBinFileRegionMemAcc(region_array,num_regions,mem_space,filepath); return err; } OCSD_C_API ocsd_err_t ocsd_dt_add_buffer_mem_acc(const dcd_tree_handle_t handle, 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 err = OCSD_OK; DecodeTree *pDT; err = ocsd_check_and_add_mem_acc_mapper(handle,&pDT); if(err == OCSD_OK) err = pDT->addBufferMemAcc(address,mem_space,p_mem_buffer,mem_length); return err; } 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) { ocsd_err_t err = OCSD_OK; DecodeTree *pDT; err = ocsd_check_and_add_mem_acc_mapper(handle,&pDT); if(err == OCSD_OK) err = pDT->addCallbackMemAcc(st_address,en_address,mem_space,p_cb_func,p_context); return err; } OCSD_C_API ocsd_err_t ocsd_dt_add_callback_trcid_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_MemAccID_CB p_cb_func, const void *p_context) { ocsd_err_t err = OCSD_OK; DecodeTree *pDT; err = ocsd_check_and_add_mem_acc_mapper(handle, &pDT); if (err == OCSD_OK) err = pDT->addCallbackIDMemAcc(st_address, en_address, mem_space, p_cb_func, p_context); return err; } OCSD_C_API ocsd_err_t ocsd_dt_remove_mem_acc(const dcd_tree_handle_t handle, const ocsd_vaddr_t st_address, const ocsd_mem_space_acc_t mem_space) { ocsd_err_t err = OCSD_OK; if(handle != C_API_INVALID_TREE_HANDLE) { DecodeTree *pDT = static_cast(handle); err = pDT->removeMemAccByAddress(st_address,mem_space); } else err = OCSD_ERR_INVALID_PARAM_VAL; return err; } OCSD_C_API void ocsd_tl_log_mapped_mem_ranges(const dcd_tree_handle_t handle) { if(handle != C_API_INVALID_TREE_HANDLE) { DecodeTree *pDT = static_cast(handle); pDT->logMappedRanges(); } } OCSD_C_API void ocsd_gen_elem_init(ocsd_generic_trace_elem *p_pkt, const ocsd_gen_trc_elem_t elem_type) { p_pkt->elem_type = elem_type; p_pkt->flag_bits = 0; p_pkt->ptr_extended_data = 0; } OCSD_C_API ocsd_err_t ocsd_dt_set_raw_frame_printer(const dcd_tree_handle_t handle, int flags) { if (handle != C_API_INVALID_TREE_HANDLE) return ((DecodeTree *)handle)->addRawFramePrinter(0, (uint32_t)flags); return OCSD_ERR_NOT_INIT; } OCSD_C_API ocsd_err_t ocsd_dt_set_gen_elem_printer(const dcd_tree_handle_t handle) { if (handle != C_API_INVALID_TREE_HANDLE) return ((DecodeTree *)handle)->addGenElemPrinter(0); return OCSD_ERR_NOT_INIT; } OCSD_C_API ocsd_err_t ocsd_dt_set_pkt_protocol_printer(const dcd_tree_handle_t handle, uint8_t cs_id, int monitor) { ocsd_err_t err = OCSD_ERR_NOT_INIT; if (handle != C_API_INVALID_TREE_HANDLE) { DecodeTree *p_tree = (DecodeTree *)handle; err = p_tree->addPacketPrinter(cs_id, (bool)(monitor != 0), 0); } return err; } OCSD_C_API void ocsd_err_str(const ocsd_err_t err, char *buffer, const int buffer_size) { std::string err_str; err_str = ocsdError::getErrorString(ocsdError(OCSD_ERR_SEV_ERROR, err)); strncpy(buffer, err_str.c_str(), buffer_size - 1); buffer[buffer_size - 1] = 0; } OCSD_C_API ocsd_err_t ocsd_get_last_err(ocsd_trc_index_t *index, uint8_t *chan_id, char *message, const int message_len) { ocsdError *p_err; ocsd_err_t err = OCSD_OK; std::string err_str; p_err = DecodeTree::getDefaultErrorLogger()->GetLastError(); if (p_err) { *index = p_err->getErrorIndex(); *chan_id = p_err->getErrorChanID(); err_str = p_err->getErrorString(ocsdError(p_err)); strncpy(message, err_str.c_str(), message_len - 1); message[message_len - 1] = 0; err = p_err->getErrorCode(); } else { message[0] = 0; *index = OCSD_BAD_TRC_INDEX; *chan_id = OCSD_BAD_CS_SRC_ID; } return err; } /*******************************************************************************/ /* C API local fns */ /*******************************************************************************/ static ocsd_err_t ocsd_create_pkt_sink_cb(ocsd_trace_protocol_t protocol, FnDefPktDataIn pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ) { ocsd_err_t err = OCSD_OK; *ppCBObj = 0; switch(protocol) { case OCSD_PROTOCOL_ETMV4I: *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn,p_context); break; case OCSD_PROTOCOL_ETMV3: *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn,p_context); break; case OCSD_PROTOCOL_PTM: *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn,p_context); break; case OCSD_PROTOCOL_STM: *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn,p_context); break; default: if ((protocol >= OCSD_PROTOCOL_CUSTOM_0) && (protocol < OCSD_PROTOCOL_END)) { *ppCBObj = new (std::nothrow) PktCBObj(pPktInFn, p_context); } else err = OCSD_ERR_NO_PROTOCOL; break; } if((*ppCBObj == 0) && (err == OCSD_OK)) err = OCSD_ERR_MEM; return err; } static ocsd_err_t ocsd_create_pkt_mon_cb(ocsd_trace_protocol_t protocol, FnDefPktDataMon pPktInFn, const void *p_context, ITrcTypedBase **ppCBObj ) { ocsd_err_t err = OCSD_OK; *ppCBObj = 0; switch(protocol) { case OCSD_PROTOCOL_ETMV4I: *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn,p_context); break; case OCSD_PROTOCOL_ETMV3: *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn,p_context); break; case OCSD_PROTOCOL_PTM: *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn,p_context); break; case OCSD_PROTOCOL_STM: *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn,p_context); break; default: if ((protocol >= OCSD_PROTOCOL_CUSTOM_0) && (protocol < OCSD_PROTOCOL_END)) { *ppCBObj = new (std::nothrow) PktMonCBObj(pPktInFn, p_context); } else err = OCSD_ERR_NO_PROTOCOL; break; } if((*ppCBObj == 0) && (err == OCSD_OK)) err = OCSD_ERR_MEM; return err; } static ocsd_err_t ocsd_check_and_add_mem_acc_mapper(const dcd_tree_handle_t handle, DecodeTree **ppDT) { *ppDT = 0; if(handle == C_API_INVALID_TREE_HANDLE) return OCSD_ERR_INVALID_PARAM_VAL; *ppDT = static_cast(handle); if(!(*ppDT)->hasMemAccMapper()) return (*ppDT)->createMemAccMapper(); return OCSD_OK; } /*******************************************************************************/ /* C API Helper objects */ /*******************************************************************************/ /****************** Generic trace element output callback function ************/ GenTraceElemCBObj::GenTraceElemCBObj(FnTraceElemIn pCBFn, const void *p_context) : m_c_api_cb_fn(pCBFn), m_p_cb_context(p_context) { } ocsd_datapath_resp_t GenTraceElemCBObj::TraceElemIn(const ocsd_trc_index_t index_sop, const uint8_t trc_chan_id, const OcsdTraceElement &elem) { return m_c_api_cb_fn(m_p_cb_context, index_sop, trc_chan_id, &elem); } /* End of File ocsd_c_api.cpp */