2 * File: SRecordSourceFile.cpp
4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5 * See included license file for license details.
8 #include "SRecordSourceFile.h"
10 #include "smart_ptr.h"
15 //! Size in bytes of the buffer used to collect S-record data records
16 //! before adding them to the executable image. Currently 64KB.
17 COLLECTION_BUFFER_SIZE = 64 * 1024
20 using namespace elftosb;
22 SRecordSourceFile::SRecordSourceFile(const std::string & path)
23 : SourceFile(path), m_image(0), m_hasEntryRecord(false)
27 bool SRecordSourceFile::isSRecordFile(std::istream & stream)
29 StSRecordFile srec(stream);
30 return srec.isSRecordFile();
33 void SRecordSourceFile::open()
37 // create file parser and examine file
38 m_file = new StSRecordFile(*m_stream);
41 // build an image of the file
42 m_image = new StExecutableImage();
45 // dispose of file parser object
50 void SRecordSourceFile::close()
56 // dispose of memory image
61 //! \pre The file must be open before this method can be called.
63 DataSource * SRecordSourceFile::createDataSource()
66 return new MemoryImageDataSource(m_image);
69 //! \retval true The file has an S7, S8, or S9 record.
70 //! \retval false No entry point is available.
71 bool SRecordSourceFile::hasEntryPoint()
73 return m_hasEntryRecord;
76 //! If no entry point is available then 0 is returned instead. The method scans
77 //! the records in the file looking for S7, S8, or S9 records. Thus, 16-bit,
78 //! 24-bit, and 32-bit entry point records are supported.
80 //! \return Entry point address.
81 //! \retval 0 No entry point is available.
82 uint32_t SRecordSourceFile::getEntryPointAddress()
86 // the address in the record is the entry point
87 Log::log(Logger::DEBUG2, "entry point address is 0x%08x\n", m_entryRecord.m_address);
88 return m_entryRecord.m_address;
94 //! Scans the S-records of the file looking for data records. These are S3, S2, or
95 //! S1 records. The contents of these records are added to an StExecutableImage
96 //! object, which coalesces the individual records into contiguous regions of
99 //! Also looks for S7, S8, or S9 records that contain the entry point. The first
100 //! match of one of these records is saved off into the #m_entryRecord member.
102 //! \pre The #m_file member must be valid.
103 //! \pre The #m_image member variable must have been instantiated.
104 void SRecordSourceFile::buildMemoryImage()
109 // Clear the entry point related members.
110 m_hasEntryRecord = false;
111 memset(&m_entryRecord, 0, sizeof(m_entryRecord));
113 // Allocate buffer to hold data before adding it to the executable image.
114 // Contiguous records are added to this buffer. When overflowed or when a
115 // non-contiguous record is encountered the buffer is added to the executable
116 // image where it will be coalesced further. We don't add records individually
117 // to the image because coalescing record by record is very slow.
118 smart_array_ptr<uint8_t> buffer = new uint8_t[COLLECTION_BUFFER_SIZE];
119 unsigned startAddress;
120 unsigned nextAddress;
121 unsigned dataLength = 0;
124 StSRecordFile::const_iterator it = m_file->getBegin();
125 for (; it != m_file->getEnd(); it++)
127 const StSRecordFile::SRecord & theRecord = *it;
129 // only handle S3,2,1 records
130 bool isDataRecord = theRecord.m_type == 3 || theRecord.m_type == 2 || theRecord.m_type == 1;
131 bool hasData = theRecord.m_data && theRecord.m_dataCount;
132 if (isDataRecord && hasData)
134 // If this record's data would overflow the collection buffer, or if the
135 // record is not contiguous with the rest of the data in the collection
136 // buffer, then flush the buffer to the executable image and restart.
137 if (dataLength && ((dataLength + theRecord.m_dataCount > COLLECTION_BUFFER_SIZE) || (theRecord.m_address != nextAddress)))
139 m_image->addTextRegion(startAddress, buffer, dataLength);
144 // Capture addresses when starting an empty buffer.
147 startAddress = theRecord.m_address;
148 nextAddress = startAddress;
151 // Copy record data into place in the collection buffer and update
153 memcpy(&buffer[dataLength], theRecord.m_data, theRecord.m_dataCount);
154 dataLength += theRecord.m_dataCount;
155 nextAddress += theRecord.m_dataCount;
157 else if (!m_hasEntryRecord)
159 // look for S7,8,9 records
160 bool isEntryPointRecord = theRecord.m_type == 7 || theRecord.m_type == 8 || theRecord.m_type == 9;
161 if (isEntryPointRecord)
163 // save off the entry point record so we don't have to scan again
164 memcpy(&m_entryRecord, &theRecord, sizeof(m_entryRecord));
165 m_hasEntryRecord = true;
170 // Add any leftover data in the collection buffer to the executable image.
173 m_image->addTextRegion(startAddress, buffer, dataLength);