1/*
2 * \file       trc_mem_acc_file.cpp
3 * \brief      OpenCSD :
4 *
5 * \copyright  Copyright (c) 2015, ARM Limited. All Rights Reserved.
6 */
7/*
8 * Redistribution and use in source and binary forms, with or without modification,
9 * are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its contributors
19 * may be used to endorse or promote products derived from this software without
20 * specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "mem_acc/trc_mem_acc_file.h"
35
36#include <sstream>
37#include <iomanip>
38
39/***************************************************/
40/* protected construction and reference counting   */
41/***************************************************/
42
43TrcMemAccessorFile::TrcMemAccessorFile() : TrcMemAccessorBase(MEMACC_FILE)
44{
45    m_ref_count = 0;
46    m_base_range_set = false;
47    m_has_access_regions = false;
48    m_file_size = 0;
49}
50
51TrcMemAccessorFile::~TrcMemAccessorFile()
52{
53    if(m_mem_file.is_open())
54        m_mem_file.close();
55    if(m_access_regions.size())
56    {
57        std::list<FileRegionMemAccessor *>::iterator it;
58        it = m_access_regions.begin();
59        while(it != m_access_regions.end())
60        {
61            delete (*it);
62            it++;
63        }
64        m_access_regions.clear();
65    }
66}
67
68ocsd_err_t TrcMemAccessorFile::initAccessor(const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset, size_t size)
69{
70    ocsd_err_t err = OCSD_OK;
71    bool init = false;
72
73    m_mem_file.open(pathToFile.c_str(), std::ifstream::binary | std::ifstream::ate);
74    if(m_mem_file.is_open())
75    {
76        m_file_size = (ocsd_vaddr_t)m_mem_file.tellg() & ((ocsd_vaddr_t)~0x1);
77        m_mem_file.seekg(0, m_mem_file.beg);
78        // adding an offset of 0, sets the base range.
79        if((offset == 0) && (size == 0))
80        {
81            init = AddOffsetRange(startAddr, ((size_t)m_file_size)-offset, offset);
82        }
83        else if((offset + size) <= m_file_size)
84        {
85            // if offset != 0, size must by != 0
86            init = AddOffsetRange(startAddr, size, offset);
87        }
88        m_file_path = pathToFile;
89    }
90    else
91        err = OCSD_ERR_MEM_ACC_FILE_NOT_FOUND;
92    if(!init)
93        err = OCSD_ERR_NOT_INIT;
94    return err;
95}
96
97
98FileRegionMemAccessor *TrcMemAccessorFile::getRegionForAddress(const ocsd_vaddr_t startAddr) const
99{
100    FileRegionMemAccessor *p_region = 0;
101    if(m_has_access_regions)
102    {
103        std::list<FileRegionMemAccessor *>::const_iterator it;
104        it = m_access_regions.begin();
105        while((it != m_access_regions.end()) && (p_region == 0))
106        {
107            if((*it)->addrInRange(startAddr))
108                p_region = *it;
109            it++;
110        }
111    }
112    return p_region;
113}
114
115
116/***************************************************/
117/* static object creation                          */
118/***************************************************/
119
120std::map<std::string, TrcMemAccessorFile *> TrcMemAccessorFile::s_FileAccessorMap;
121
122// return existing or create new accessor
123ocsd_err_t TrcMemAccessorFile::createFileAccessor(TrcMemAccessorFile **p_acc, const std::string &pathToFile, ocsd_vaddr_t startAddr, size_t offset /*= 0*/, size_t size /*= 0*/)
124{
125    ocsd_err_t err = OCSD_OK;
126    TrcMemAccessorFile * acc = 0;
127    std::map<std::string, TrcMemAccessorFile *>::iterator it = s_FileAccessorMap.find(pathToFile);
128    if(it != s_FileAccessorMap.end())
129    {
130        acc = it->second;
131        if(acc->addrStartOfRange(startAddr))
132            acc->IncRefCount();
133        else
134        {
135            err = OCSD_ERR_MEM_ACC_FILE_DIFF_RANGE;
136            acc = 0;
137        }
138    }
139    else
140    {
141        acc = new (std::nothrow) TrcMemAccessorFile();
142        if(acc != 0)
143        {
144            if((err = acc->initAccessor(pathToFile,startAddr, offset,size)) == OCSD_OK)
145            {
146                acc->IncRefCount();
147                s_FileAccessorMap.insert(std::pair<std::string, TrcMemAccessorFile *>(pathToFile,acc));
148            }
149            else
150            {
151                delete acc;
152                acc = 0;
153            }
154        }
155        else
156            err = OCSD_ERR_MEM;
157    }
158    *p_acc = acc;
159    return err;
160}
161
162void TrcMemAccessorFile::destroyFileAccessor(TrcMemAccessorFile *p_accessor)
163{
164    if(p_accessor != 0)
165    {
166        p_accessor->DecRefCount();
167        if(p_accessor->getRefCount() == 0)
168        {
169            std::map<std::string, TrcMemAccessorFile *>::iterator it = s_FileAccessorMap.find(p_accessor->getFilePath());
170            if(it != s_FileAccessorMap.end())
171            {
172                s_FileAccessorMap.erase(it);
173            }
174            delete p_accessor;
175        }
176    }
177}
178
179const bool TrcMemAccessorFile::isExistingFileAccessor(const std::string &pathToFile)
180{
181    bool bExists = false;
182    std::map<std::string, TrcMemAccessorFile *>::const_iterator it = s_FileAccessorMap.find(pathToFile);
183    if(it != s_FileAccessorMap.end())
184        bExists = true;
185    return bExists;
186}
187
188TrcMemAccessorFile * TrcMemAccessorFile::getExistingFileAccessor(const std::string &pathToFile)
189{
190    TrcMemAccessorFile * p_acc = 0;
191    std::map<std::string, TrcMemAccessorFile *>::iterator it = s_FileAccessorMap.find(pathToFile);
192    if(it != s_FileAccessorMap.end())
193        p_acc = it->second;
194    return p_acc;
195}
196
197
198
199/***************************************************/
200/* accessor instance functions                     */
201/***************************************************/
202const uint32_t TrcMemAccessorFile::readBytes(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trcID, const uint32_t reqBytes, uint8_t *byteBuffer)
203{
204    if(!m_mem_file.is_open())
205        return 0;
206    uint32_t bytesRead = 0;
207
208    if(m_base_range_set)
209    {
210        bytesRead = TrcMemAccessorBase::bytesInRange(address,reqBytes);    // get avialable bytes in range.
211        if(bytesRead)
212        {
213            ocsd_vaddr_t addr_pos = (ocsd_vaddr_t)m_mem_file.tellg();
214            if((address - m_startAddress) != addr_pos)
215                m_mem_file.seekg(address - m_startAddress);
216            m_mem_file.read((char *)byteBuffer,bytesRead);
217        }
218    }
219
220    if((bytesRead == 0) && m_has_access_regions)
221    {
222        bytesRead = bytesInRange(address,reqBytes);
223        if(bytesRead)
224        {
225            FileRegionMemAccessor *p_region = getRegionForAddress(address);
226            ocsd_vaddr_t addr_pos = (ocsd_vaddr_t)m_mem_file.tellg();
227            if((address - p_region->regionStartAddress() + p_region->getOffset()) != addr_pos)
228                m_mem_file.seekg(address - p_region->regionStartAddress() + p_region->getOffset());
229             m_mem_file.read((char *)byteBuffer,bytesRead);
230        }
231    }
232    return bytesRead;
233}
234
235bool TrcMemAccessorFile::AddOffsetRange(const ocsd_vaddr_t startAddr, const size_t size, const size_t offset)
236{
237    bool addOK = false;
238    if(m_file_size == 0)    // must have set the file size
239        return false;
240    if(addrInRange(startAddr) || addrInRange(startAddr+size-1))  // cannot be overlapping
241        return false;
242
243    // now either set the base range or an offset range
244    if(offset == 0)
245    {
246        if(!m_base_range_set)
247        {
248            setRange(startAddr, startAddr+size-1);
249            m_base_range_set = true;
250            addOK = true;
251        }
252    }
253    else
254    {
255        if((offset + size) <= m_file_size)
256        {
257            FileRegionMemAccessor *frmacc = new (std::nothrow) FileRegionMemAccessor();
258            if(frmacc)
259            {
260                frmacc->setOffset(offset);
261                frmacc->setRange(startAddr,startAddr+size-1);
262                m_access_regions.push_back(frmacc);
263                m_access_regions.sort();
264                // may need to trim the 0 offset base range...
265                if(m_base_range_set)
266                {
267                    std::list<FileRegionMemAccessor *>::iterator it;
268                    it = m_access_regions.begin();
269                    size_t first_range_offset = (*it)->getOffset();
270                    if((m_startAddress + first_range_offset - 1) > m_endAddress)
271                        m_endAddress = m_startAddress + first_range_offset - 1;
272                }
273                addOK = true;
274                m_has_access_regions = true;
275            }
276        }
277    }
278    return addOK;
279}
280
281const bool TrcMemAccessorFile::addrInRange(const ocsd_vaddr_t s_address) const
282{
283    bool bInRange = false;
284    if(m_base_range_set)
285        bInRange = TrcMemAccessorBase::addrInRange(s_address);
286
287    if(!bInRange && m_has_access_regions)
288    {
289        if(getRegionForAddress(s_address) != 0)
290            bInRange = true;
291    }
292    return bInRange;
293}
294
295const bool TrcMemAccessorFile::addrStartOfRange(const ocsd_vaddr_t s_address) const
296{
297    bool bInRange = false;
298    if(m_base_range_set)
299        bInRange = TrcMemAccessorBase::addrStartOfRange(s_address);
300    if(!bInRange && m_has_access_regions)
301    {
302        FileRegionMemAccessor *pRegion = getRegionForAddress(s_address);
303        if(pRegion)
304            bInRange = (pRegion->regionStartAddress() == s_address);
305    }
306    return bInRange;
307}
308
309
310    /* validate ranges */
311const bool TrcMemAccessorFile::validateRange()
312{
313    bool bRangeValid = true;
314    if(m_base_range_set)
315        bRangeValid = TrcMemAccessorBase::validateRange();
316
317    if(m_has_access_regions && bRangeValid)
318    {
319        std::list<FileRegionMemAccessor *>::const_iterator it;
320        it = m_access_regions.begin();
321        while((it != m_access_regions.end()) && bRangeValid)
322        {
323            bRangeValid = (*it)->validateRange();
324            it++;
325        }
326    }
327    return bRangeValid;
328}
329
330const uint32_t TrcMemAccessorFile::bytesInRange(const ocsd_vaddr_t s_address, const uint32_t reqBytes) const
331{
332    uint32_t bytesInRange = 0;
333    if(m_base_range_set)
334        bytesInRange = TrcMemAccessorBase::bytesInRange(s_address,reqBytes);
335
336    if((bytesInRange == 0) && (m_has_access_regions))
337    {
338        FileRegionMemAccessor *p_region = getRegionForAddress(s_address);
339        bytesInRange = p_region->bytesInRange(s_address,reqBytes);
340    }
341
342    return bytesInRange;
343}
344
345const bool TrcMemAccessorFile::overLapRange(const TrcMemAccessorBase *p_test_acc) const
346{
347    bool bOverLapRange = false;
348    if(m_base_range_set)
349        bOverLapRange = TrcMemAccessorBase::overLapRange(p_test_acc);
350
351    if(!bOverLapRange && (m_has_access_regions))
352    {
353        std::list<FileRegionMemAccessor *>::const_iterator it;
354        it = m_access_regions.begin();
355        while((it != m_access_regions.end()) && !bOverLapRange)
356        {
357            bOverLapRange = (*it)->overLapRange(p_test_acc);
358            it++;
359        }
360    }
361    return bOverLapRange;
362}
363
364    /*! Override to handle ranges and offset accessors plus add in file name. */
365void TrcMemAccessorFile::getMemAccString(std::string &accStr) const
366{
367    std::ostringstream oss;
368    accStr = "";
369    if(m_base_range_set)
370    {
371        TrcMemAccessorBase::getMemAccString(accStr);
372    }
373
374    if(m_has_access_regions)
375    {
376        std::string addStr;
377        std::list<FileRegionMemAccessor *>::const_iterator it;
378        it = m_access_regions.begin();
379        while(it != m_access_regions.end())
380        {
381            (*it)->getMemAccString(addStr);
382            if(accStr.length())
383                accStr += "\n";
384            accStr += addStr;
385            it++;
386        }
387    }
388    accStr += (std::string)"\nFilename=" + m_file_path;
389}
390
391/* End of File trc_mem_acc_file.cpp */
392