xref: /netbsd-src/external/bsd/elftosb/dist/common/SRecordSourceFile.cpp (revision 993229b6fea628ff8b1fa09146c80b0cfb2768eb)
1 /*
2  * File:	SRecordSourceFile.cpp
3  *
4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5  * See included license file for license details.
6  */
7 
8 #include "SRecordSourceFile.h"
9 #include "Logging.h"
10 #include "smart_ptr.h"
11 #include <assert.h>
12 #include <string.h>
13 enum
14 {
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
18 };
19 
20 using namespace elftosb;
21 
SRecordSourceFile(const std::string & path)22 SRecordSourceFile::SRecordSourceFile(const std::string & path)
23 :	SourceFile(path), m_image(0), m_hasEntryRecord(false)
24 {
25 }
26 
isSRecordFile(std::istream & stream)27 bool SRecordSourceFile::isSRecordFile(std::istream & stream)
28 {
29 	StSRecordFile srec(stream);
30 	return srec.isSRecordFile();
31 }
32 
open()33 void SRecordSourceFile::open()
34 {
35 	SourceFile::open();
36 
37 	// create file parser and examine file
38 	m_file = new StSRecordFile(*m_stream);
39 	m_file->parse();
40 
41 	// build an image of the file
42 	m_image = new StExecutableImage();
43 	buildMemoryImage();
44 
45 	// dispose of file parser object
46 	delete m_file;
47 	m_file = 0;
48 }
49 
close()50 void SRecordSourceFile::close()
51 {
52 	assert(m_image);
53 
54 	SourceFile::close();
55 
56 	// dispose of memory image
57 	delete m_image;
58 	m_image = 0;
59 }
60 
61 //! \pre The file must be open before this method can be called.
62 //!
createDataSource()63 DataSource * SRecordSourceFile::createDataSource()
64 {
65 	assert(m_image);
66 	return new MemoryImageDataSource(m_image);
67 }
68 
69 //! \retval true The file has an S7, S8, or S9 record.
70 //! \retval false No entry point is available.
hasEntryPoint()71 bool SRecordSourceFile::hasEntryPoint()
72 {
73 	return m_hasEntryRecord;
74 }
75 
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.
79 //!
80 //! \return Entry point address.
81 //! \retval 0 No entry point is available.
getEntryPointAddress()82 uint32_t SRecordSourceFile::getEntryPointAddress()
83 {
84 	if (m_hasEntryRecord)
85 	{
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;
89 	}
90 
91 	return 0;
92 }
93 
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
97 //! memory.
98 //!
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.
101 //!
102 //! \pre The #m_file member must be valid.
103 //! \pre The #m_image member variable must have been instantiated.
buildMemoryImage()104 void SRecordSourceFile::buildMemoryImage()
105 {
106 	assert(m_file);
107 	assert(m_image);
108 
109 	// Clear the entry point related members.
110 	m_hasEntryRecord = false;
111 	memset(&m_entryRecord, 0, sizeof(m_entryRecord));
112 
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;
122 
123 	// process SRecords
124     StSRecordFile::const_iterator it = m_file->getBegin();
125 	for (; it != m_file->getEnd(); it++)
126 	{
127         const StSRecordFile::SRecord & theRecord = *it;
128 
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)
133 		{
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)))
138 			{
139 				m_image->addTextRegion(startAddress, buffer, dataLength);
140 
141 				dataLength = 0;
142 			}
143 
144 			// Capture addresses when starting an empty buffer.
145 			if (dataLength == 0)
146 			{
147 				startAddress = theRecord.m_address;
148 				nextAddress = startAddress;
149 			}
150 
151 			// Copy record data into place in the collection buffer and update
152 			// size and address.
153 			memcpy(&buffer[dataLength], theRecord.m_data, theRecord.m_dataCount);
154 			dataLength += theRecord.m_dataCount;
155 			nextAddress += theRecord.m_dataCount;
156 		}
157 		else if (!m_hasEntryRecord)
158 		{
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)
162 			{
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;
166 			}
167 		}
168 	}
169 
170 	// Add any leftover data in the collection buffer to the executable image.
171 	if (dataLength)
172 	{
173 		m_image->addTextRegion(startAddress, buffer, dataLength);
174 	}
175 }
176 
177