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 
43 TrcMemAccessorFile::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 
51 TrcMemAccessorFile::~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 
68 ocsd_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 
98 FileRegionMemAccessor *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 
120 std::map<std::string, TrcMemAccessorFile *> TrcMemAccessorFile::s_FileAccessorMap;
121 
122 // return existing or create new accessor
123 ocsd_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 
162 void 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 
179 const 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 
188 TrcMemAccessorFile * 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 /***************************************************/
202 const 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 
235 bool 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 
281 const 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 
295 const 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 */
311 const 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 
330 const 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 
345 const 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. */
365 void 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