| /* |
| * \file trc_mem_acc_file.cpp |
| * \brief Reference CoreSight Trace Decoder : |
| * |
| * \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 <sstream> |
| #include <iomanip> |
| |
| /***************************************************/ |
| /* 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<FileRegionMemAccessor *>::iterator it; |
| it = m_access_regions.begin(); |
| while(it != m_access_regions.end()) |
| { |
| delete (*it); |
| it++; |
| } |
| m_access_regions.clear(); |
| } |
| } |
| |
| rctdl_err_t TrcMemAccessorFile::initAccessor(const std::string &pathToFile, rctdl_vaddr_t startAddr, size_t offset, size_t size) |
| { |
| rctdl_err_t err = RCTDL_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 = (rctdl_vaddr_t)m_mem_file.tellg() & ((rctdl_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 = RCTDL_ERR_MEM_ACC_FILE_NOT_FOUND; |
| if(!init) |
| err = RCTDL_ERR_NOT_INIT; |
| return err; |
| } |
| |
| |
| FileRegionMemAccessor *TrcMemAccessorFile::getRegionForAddress(const rctdl_vaddr_t startAddr) const |
| { |
| FileRegionMemAccessor *p_region = 0; |
| if(m_has_access_regions) |
| { |
| std::list<FileRegionMemAccessor *>::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<std::string, TrcMemAccessorFile *> TrcMemAccessorFile::s_FileAccessorMap; |
| |
| // return existing or create new accessor |
| rctdl_err_t TrcMemAccessorFile::createFileAccessor(TrcMemAccessorFile **p_acc, const std::string &pathToFile, rctdl_vaddr_t startAddr, size_t offset /*= 0*/, size_t size /*= 0*/) |
| { |
| rctdl_err_t err = RCTDL_OK; |
| TrcMemAccessorFile * acc = 0; |
| std::map<std::string, TrcMemAccessorFile *>::iterator it = s_FileAccessorMap.find(pathToFile); |
| if(it != s_FileAccessorMap.end()) |
| { |
| acc = it->second; |
| if(acc->addrStartOfRange(startAddr)) |
| acc->IncRefCount(); |
| else |
| { |
| err = RCTDL_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)) == RCTDL_OK) |
| { |
| acc->IncRefCount(); |
| s_FileAccessorMap.insert(std::pair<std::string, TrcMemAccessorFile *>(pathToFile,acc)); |
| } |
| else |
| { |
| delete acc; |
| acc = 0; |
| } |
| } |
| else |
| err = RCTDL_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<std::string, TrcMemAccessorFile *>::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<std::string, TrcMemAccessorFile *>::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<std::string, TrcMemAccessorFile *>::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 rctdl_vaddr_t address, const rctdl_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) |
| { |
| rctdl_vaddr_t addr_pos = (rctdl_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); |
| rctdl_vaddr_t addr_pos = (rctdl_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 rctdl_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<FileRegionMemAccessor *>::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 rctdl_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 rctdl_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<FileRegionMemAccessor *>::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 rctdl_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<FileRegionMemAccessor *>::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<FileRegionMemAccessor *>::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 */ |