/* * \file trc_mem_acc_file.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 "mem_acc/trc_mem_acc_file.h" #include #include /***************************************************/ /* protected construction and reference counting */ /***************************************************/ TrcMemAccessorFile::TrcMemAccessorFile() : TrcMemAccessorBase(MEMACC_FILE) { m_ref_count = 0; m_base_range_set = false; m_has_access_regions = false; m_file_size = 0; } TrcMemAccessorFile::~TrcMemAccessorFile() { if(m_mem_file.is_open()) m_mem_file.close(); if(m_access_regions.size()) { std::list::iterator it; it = m_access_regions.begin(); while(it != m_access_regions.end()) { delete (*it); it++; } m_access_regions.clear(); } } ocsd_err_t TrcMemAccessorFile::initAccessor(const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset, size_t size) { ocsd_err_t err = OCSD_OK; bool init = false; m_mem_file.open(pathToFile.c_str(), std::ifstream::binary | std::ifstream::ate); if(m_mem_file.is_open()) { m_file_size = (ocsd_vaddr_t)m_mem_file.tellg() & ((ocsd_vaddr_t)~0x1); m_mem_file.seekg(0, m_mem_file.beg); // adding an offset of 0, sets the base range. if((offset == 0) && (size == 0)) { init = AddOffsetRange(startAddr, ((size_t)m_file_size)-offset, offset); } else if((offset + size) <= m_file_size) { // if offset != 0, size must by != 0 init = AddOffsetRange(startAddr, size, offset); } m_file_path = pathToFile; } else err = OCSD_ERR_MEM_ACC_FILE_NOT_FOUND; if(!init) err = OCSD_ERR_NOT_INIT; return err; } FileRegionMemAccessor *TrcMemAccessorFile::getRegionForAddress(const ocsd_vaddr_t startAddr) const { FileRegionMemAccessor *p_region = 0; if(m_has_access_regions) { std::list::const_iterator it; it = m_access_regions.begin(); while((it != m_access_regions.end()) && (p_region == 0)) { if((*it)->addrInRange(startAddr)) p_region = *it; it++; } } return p_region; } /***************************************************/ /* static object creation */ /***************************************************/ std::map TrcMemAccessorFile::s_FileAccessorMap; // return existing or create new accessor ocsd_err_t TrcMemAccessorFile::createFileAccessor(TrcMemAccessorFile **p_acc, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset /*= 0*/, size_t size /*= 0*/) { ocsd_err_t err = OCSD_OK; TrcMemAccessorFile * acc = 0; std::map::iterator it = s_FileAccessorMap.find(pathToFile); if(it != s_FileAccessorMap.end()) { acc = it->second; if(acc->addrStartOfRange(startAddr)) acc->IncRefCount(); else { err = OCSD_ERR_MEM_ACC_FILE_DIFF_RANGE; acc = 0; } } else { acc = new (std::nothrow) TrcMemAccessorFile(); if(acc != 0) { if((err = acc->initAccessor(pathToFile,startAddr, offset,size)) == OCSD_OK) { acc->IncRefCount(); s_FileAccessorMap.insert(std::pair(pathToFile,acc)); } else { delete acc; acc = 0; } } else err = OCSD_ERR_MEM; } *p_acc = acc; return err; } void TrcMemAccessorFile::destroyFileAccessor(TrcMemAccessorFile *p_accessor) { if(p_accessor != 0) { p_accessor->DecRefCount(); if(p_accessor->getRefCount() == 0) { std::map::iterator it = s_FileAccessorMap.find(p_accessor->getFilePath()); if(it != s_FileAccessorMap.end()) { s_FileAccessorMap.erase(it); } delete p_accessor; } } } const bool TrcMemAccessorFile::isExistingFileAccessor(const std::string &pathToFile) { bool bExists = false; std::map::const_iterator it = s_FileAccessorMap.find(pathToFile); if(it != s_FileAccessorMap.end()) bExists = true; return bExists; } TrcMemAccessorFile * TrcMemAccessorFile::getExistingFileAccessor(const std::string &pathToFile) { TrcMemAccessorFile * p_acc = 0; std::map::iterator it = s_FileAccessorMap.find(pathToFile); if(it != s_FileAccessorMap.end()) p_acc = it->second; return p_acc; } /***************************************************/ /* accessor instance functions */ /***************************************************/ const uint32_t TrcMemAccessorFile::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint32_t reqBytes, uint8_t *byteBuffer) { if(!m_mem_file.is_open()) return 0; uint32_t bytesRead = 0; if(m_base_range_set) { bytesRead = TrcMemAccessorBase::bytesInRange(address,reqBytes); // get avialable bytes in range. if(bytesRead) { ocsd_vaddr_t addr_pos = (ocsd_vaddr_t)m_mem_file.tellg(); if((address - m_startAddress) != addr_pos) m_mem_file.seekg(address - m_startAddress); m_mem_file.read((char *)byteBuffer,bytesRead); } } if((bytesRead == 0) && m_has_access_regions) { bytesRead = bytesInRange(address,reqBytes); if(bytesRead) { FileRegionMemAccessor *p_region = getRegionForAddress(address); ocsd_vaddr_t addr_pos = (ocsd_vaddr_t)m_mem_file.tellg(); if((address - p_region->regionStartAddress() + p_region->getOffset()) != addr_pos) m_mem_file.seekg(address - p_region->regionStartAddress() + p_region->getOffset()); m_mem_file.read((char *)byteBuffer,bytesRead); } } return bytesRead; } bool TrcMemAccessorFile::AddOffsetRange(const ocsd_vaddr_t startAddr, const size_t size, const size_t offset) { bool addOK = false; if(m_file_size == 0) // must have set the file size return false; if(addrInRange(startAddr) || addrInRange(startAddr+size-1)) // cannot be overlapping return false; // now either set the base range or an offset range if(offset == 0) { if(!m_base_range_set) { setRange(startAddr, startAddr+size-1); m_base_range_set = true; addOK = true; } } else { if((offset + size) <= m_file_size) { FileRegionMemAccessor *frmacc = new (std::nothrow) FileRegionMemAccessor(); if(frmacc) { frmacc->setOffset(offset); frmacc->setRange(startAddr,startAddr+size-1); m_access_regions.push_back(frmacc); m_access_regions.sort(); // may need to trim the 0 offset base range... if(m_base_range_set) { std::list::iterator it; it = m_access_regions.begin(); size_t first_range_offset = (*it)->getOffset(); if((m_startAddress + first_range_offset - 1) > m_endAddress) m_endAddress = m_startAddress + first_range_offset - 1; } addOK = true; m_has_access_regions = true; } } } return addOK; } const bool TrcMemAccessorFile::addrInRange(const ocsd_vaddr_t s_address) const { bool bInRange = false; if(m_base_range_set) bInRange = TrcMemAccessorBase::addrInRange(s_address); if(!bInRange && m_has_access_regions) { if(getRegionForAddress(s_address) != 0) bInRange = true; } return bInRange; } const bool TrcMemAccessorFile::addrStartOfRange(const ocsd_vaddr_t s_address) const { bool bInRange = false; if(m_base_range_set) bInRange = TrcMemAccessorBase::addrStartOfRange(s_address); if(!bInRange && m_has_access_regions) { FileRegionMemAccessor *pRegion = getRegionForAddress(s_address); if(pRegion) bInRange = (pRegion->regionStartAddress() == s_address); } return bInRange; } /* validate ranges */ const bool TrcMemAccessorFile::validateRange() { bool bRangeValid = true; if(m_base_range_set) bRangeValid = TrcMemAccessorBase::validateRange(); if(m_has_access_regions && bRangeValid) { std::list::const_iterator it; it = m_access_regions.begin(); while((it != m_access_regions.end()) && bRangeValid) { bRangeValid = (*it)->validateRange(); it++; } } return bRangeValid; } const uint32_t TrcMemAccessorFile::bytesInRange(const ocsd_vaddr_t s_address, const uint32_t reqBytes) const { uint32_t bytesInRange = 0; if(m_base_range_set) bytesInRange = TrcMemAccessorBase::bytesInRange(s_address,reqBytes); if((bytesInRange == 0) && (m_has_access_regions)) { FileRegionMemAccessor *p_region = getRegionForAddress(s_address); bytesInRange = p_region->bytesInRange(s_address,reqBytes); } return bytesInRange; } const bool TrcMemAccessorFile::overLapRange(const TrcMemAccessorBase *p_test_acc) const { bool bOverLapRange = false; if(m_base_range_set) bOverLapRange = TrcMemAccessorBase::overLapRange(p_test_acc); if(!bOverLapRange && (m_has_access_regions)) { std::list::const_iterator it; it = m_access_regions.begin(); while((it != m_access_regions.end()) && !bOverLapRange) { bOverLapRange = (*it)->overLapRange(p_test_acc); it++; } } return bOverLapRange; } /*! Override to handle ranges and offset accessors plus add in file name. */ void TrcMemAccessorFile::getMemAccString(std::string &accStr) const { std::ostringstream oss; accStr = ""; if(m_base_range_set) { TrcMemAccessorBase::getMemAccString(accStr); } if(m_has_access_regions) { std::string addStr; std::list::const_iterator it; it = m_access_regions.begin(); while(it != m_access_regions.end()) { (*it)->getMemAccString(addStr); if(accStr.length()) accStr += "\n"; accStr += addStr; it++; } } accStr += (std::string)"\nFilename=" + m_file_path; } /* End of File trc_mem_acc_file.cpp */