1 1.1 jkunz /* 2 1.1 jkunz * File: SRecordSourceFile.cpp 3 1.1 jkunz * 4 1.1 jkunz * Copyright (c) Freescale Semiconductor, Inc. All rights reserved. 5 1.1 jkunz * See included license file for license details. 6 1.1 jkunz */ 7 1.1 jkunz 8 1.1 jkunz #include "SRecordSourceFile.h" 9 1.1 jkunz #include "Logging.h" 10 1.1 jkunz #include "smart_ptr.h" 11 1.1 jkunz #include <assert.h> 12 1.1 jkunz #include <string.h> 13 1.1 jkunz enum 14 1.1 jkunz { 15 1.1 jkunz //! Size in bytes of the buffer used to collect S-record data records 16 1.1 jkunz //! before adding them to the executable image. Currently 64KB. 17 1.1 jkunz COLLECTION_BUFFER_SIZE = 64 * 1024 18 1.1 jkunz }; 19 1.1 jkunz 20 1.1 jkunz using namespace elftosb; 21 1.1 jkunz 22 1.1 jkunz SRecordSourceFile::SRecordSourceFile(const std::string & path) 23 1.1 jkunz : SourceFile(path), m_image(0), m_hasEntryRecord(false) 24 1.1 jkunz { 25 1.1 jkunz } 26 1.1 jkunz 27 1.1 jkunz bool SRecordSourceFile::isSRecordFile(std::istream & stream) 28 1.1 jkunz { 29 1.1 jkunz StSRecordFile srec(stream); 30 1.1 jkunz return srec.isSRecordFile(); 31 1.1 jkunz } 32 1.1 jkunz 33 1.1 jkunz void SRecordSourceFile::open() 34 1.1 jkunz { 35 1.1 jkunz SourceFile::open(); 36 1.1 jkunz 37 1.1 jkunz // create file parser and examine file 38 1.1 jkunz m_file = new StSRecordFile(*m_stream); 39 1.1 jkunz m_file->parse(); 40 1.1 jkunz 41 1.1 jkunz // build an image of the file 42 1.1 jkunz m_image = new StExecutableImage(); 43 1.1 jkunz buildMemoryImage(); 44 1.1 jkunz 45 1.1 jkunz // dispose of file parser object 46 1.1 jkunz delete m_file; 47 1.1 jkunz m_file = 0; 48 1.1 jkunz } 49 1.1 jkunz 50 1.1 jkunz void SRecordSourceFile::close() 51 1.1 jkunz { 52 1.1 jkunz assert(m_image); 53 1.1 jkunz 54 1.1 jkunz SourceFile::close(); 55 1.1 jkunz 56 1.1 jkunz // dispose of memory image 57 1.1 jkunz delete m_image; 58 1.1 jkunz m_image = 0; 59 1.1 jkunz } 60 1.1 jkunz 61 1.1 jkunz //! \pre The file must be open before this method can be called. 62 1.1 jkunz //! 63 1.1 jkunz DataSource * SRecordSourceFile::createDataSource() 64 1.1 jkunz { 65 1.1 jkunz assert(m_image); 66 1.1 jkunz return new MemoryImageDataSource(m_image); 67 1.1 jkunz } 68 1.1 jkunz 69 1.1 jkunz //! \retval true The file has an S7, S8, or S9 record. 70 1.1 jkunz //! \retval false No entry point is available. 71 1.1 jkunz bool SRecordSourceFile::hasEntryPoint() 72 1.1 jkunz { 73 1.1 jkunz return m_hasEntryRecord; 74 1.1 jkunz } 75 1.1 jkunz 76 1.1 jkunz //! If no entry point is available then 0 is returned instead. The method scans 77 1.1 jkunz //! the records in the file looking for S7, S8, or S9 records. Thus, 16-bit, 78 1.1 jkunz //! 24-bit, and 32-bit entry point records are supported. 79 1.1 jkunz //! 80 1.1 jkunz //! \return Entry point address. 81 1.1 jkunz //! \retval 0 No entry point is available. 82 1.1 jkunz uint32_t SRecordSourceFile::getEntryPointAddress() 83 1.1 jkunz { 84 1.1 jkunz if (m_hasEntryRecord) 85 1.1 jkunz { 86 1.1 jkunz // the address in the record is the entry point 87 1.1 jkunz Log::log(Logger::DEBUG2, "entry point address is 0x%08x\n", m_entryRecord.m_address); 88 1.1 jkunz return m_entryRecord.m_address; 89 1.1 jkunz } 90 1.1 jkunz 91 1.1 jkunz return 0; 92 1.1 jkunz } 93 1.1 jkunz 94 1.1 jkunz //! Scans the S-records of the file looking for data records. These are S3, S2, or 95 1.1 jkunz //! S1 records. The contents of these records are added to an StExecutableImage 96 1.1 jkunz //! object, which coalesces the individual records into contiguous regions of 97 1.1 jkunz //! memory. 98 1.1 jkunz //! 99 1.1 jkunz //! Also looks for S7, S8, or S9 records that contain the entry point. The first 100 1.1 jkunz //! match of one of these records is saved off into the #m_entryRecord member. 101 1.1 jkunz //! 102 1.1 jkunz //! \pre The #m_file member must be valid. 103 1.1 jkunz //! \pre The #m_image member variable must have been instantiated. 104 1.1 jkunz void SRecordSourceFile::buildMemoryImage() 105 1.1 jkunz { 106 1.1 jkunz assert(m_file); 107 1.1 jkunz assert(m_image); 108 1.1 jkunz 109 1.1 jkunz // Clear the entry point related members. 110 1.1 jkunz m_hasEntryRecord = false; 111 1.1 jkunz memset(&m_entryRecord, 0, sizeof(m_entryRecord)); 112 1.1 jkunz 113 1.1 jkunz // Allocate buffer to hold data before adding it to the executable image. 114 1.1 jkunz // Contiguous records are added to this buffer. When overflowed or when a 115 1.1 jkunz // non-contiguous record is encountered the buffer is added to the executable 116 1.1 jkunz // image where it will be coalesced further. We don't add records individually 117 1.1 jkunz // to the image because coalescing record by record is very slow. 118 1.1 jkunz smart_array_ptr<uint8_t> buffer = new uint8_t[COLLECTION_BUFFER_SIZE]; 119 1.1 jkunz unsigned startAddress; 120 1.1 jkunz unsigned nextAddress; 121 1.1 jkunz unsigned dataLength = 0; 122 1.1 jkunz 123 1.1 jkunz // process SRecords 124 1.1 jkunz StSRecordFile::const_iterator it = m_file->getBegin(); 125 1.1 jkunz for (; it != m_file->getEnd(); it++) 126 1.1 jkunz { 127 1.1 jkunz const StSRecordFile::SRecord & theRecord = *it; 128 1.1 jkunz 129 1.1 jkunz // only handle S3,2,1 records 130 1.1 jkunz bool isDataRecord = theRecord.m_type == 3 || theRecord.m_type == 2 || theRecord.m_type == 1; 131 1.1 jkunz bool hasData = theRecord.m_data && theRecord.m_dataCount; 132 1.1 jkunz if (isDataRecord && hasData) 133 1.1 jkunz { 134 1.1 jkunz // If this record's data would overflow the collection buffer, or if the 135 1.1 jkunz // record is not contiguous with the rest of the data in the collection 136 1.1 jkunz // buffer, then flush the buffer to the executable image and restart. 137 1.1 jkunz if (dataLength && ((dataLength + theRecord.m_dataCount > COLLECTION_BUFFER_SIZE) || (theRecord.m_address != nextAddress))) 138 1.1 jkunz { 139 1.1 jkunz m_image->addTextRegion(startAddress, buffer, dataLength); 140 1.1 jkunz 141 1.1 jkunz dataLength = 0; 142 1.1 jkunz } 143 1.1 jkunz 144 1.1 jkunz // Capture addresses when starting an empty buffer. 145 1.1 jkunz if (dataLength == 0) 146 1.1 jkunz { 147 1.1 jkunz startAddress = theRecord.m_address; 148 1.1 jkunz nextAddress = startAddress; 149 1.1 jkunz } 150 1.1 jkunz 151 1.1 jkunz // Copy record data into place in the collection buffer and update 152 1.1 jkunz // size and address. 153 1.1 jkunz memcpy(&buffer[dataLength], theRecord.m_data, theRecord.m_dataCount); 154 1.1 jkunz dataLength += theRecord.m_dataCount; 155 1.1 jkunz nextAddress += theRecord.m_dataCount; 156 1.1 jkunz } 157 1.1 jkunz else if (!m_hasEntryRecord) 158 1.1 jkunz { 159 1.1 jkunz // look for S7,8,9 records 160 1.1 jkunz bool isEntryPointRecord = theRecord.m_type == 7 || theRecord.m_type == 8 || theRecord.m_type == 9; 161 1.1 jkunz if (isEntryPointRecord) 162 1.1 jkunz { 163 1.1 jkunz // save off the entry point record so we don't have to scan again 164 1.1 jkunz memcpy(&m_entryRecord, &theRecord, sizeof(m_entryRecord)); 165 1.1 jkunz m_hasEntryRecord = true; 166 1.1 jkunz } 167 1.1 jkunz } 168 1.1 jkunz } 169 1.1 jkunz 170 1.1 jkunz // Add any leftover data in the collection buffer to the executable image. 171 1.1 jkunz if (dataLength) 172 1.1 jkunz { 173 1.1 jkunz m_image->addTextRegion(startAddress, buffer, dataLength); 174 1.1 jkunz } 175 1.1 jkunz } 176 1.1 jkunz 177