1 /* 2 * File: SourceFile.cpp 3 * 4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved. 5 * See included license file for license details. 6 */ 7 8 #include "SourceFile.h" 9 #include "ELFSourceFile.h" 10 #include "SRecordSourceFile.h" 11 #include <assert.h> 12 #include "format_string.h" 13 #include "SearchPath.h" 14 15 using namespace elftosb; 16 17 //! The supported file types are currently: 18 //! - ELF files 19 //! - Motorola S-record files 20 //! - Binary files 21 //! 22 //! Any file that is not picked up by the other subclasses will result in a 23 //! an instance of BinaryDataFile. 24 //! 25 //! \return An instance of the correct subclass of SourceFile for the given path. 26 //! 27 //! \exception std::runtime_error Thrown if the file cannot be opened. 28 //! 29 //! \see elftosb::ELFSourceFile 30 //! \see elftosb::SRecordSourceFile 31 //! \see elftosb::BinarySourceFile 32 SourceFile * SourceFile::openFile(const std::string & path) 33 { 34 // Search for file using search paths 35 std::string actualPath; 36 bool found = PathSearcher::getGlobalSearcher().search(path, PathSearcher::kFindFile, true, actualPath); 37 if (!found) 38 { 39 throw std::runtime_error(format_string("unable to find file %s\n", path.c_str())); 40 } 41 42 std::ifstream testStream(actualPath.c_str(), std::ios_base::in | std::ios_base::binary); 43 if (!testStream.is_open()) 44 { 45 throw std::runtime_error(format_string("failed to open file: %s", actualPath.c_str())); 46 } 47 48 // catch exceptions so we can close the file stream 49 try 50 { 51 if (ELFSourceFile::isELFFile(testStream)) 52 { 53 testStream.close(); 54 return new ELFSourceFile(actualPath); 55 } 56 else if (SRecordSourceFile::isSRecordFile(testStream)) 57 { 58 testStream.close(); 59 return new SRecordSourceFile(actualPath); 60 } 61 62 // treat it as a binary file 63 testStream.close(); 64 return new BinarySourceFile(actualPath); 65 } 66 catch (...) 67 { 68 testStream.close(); 69 throw; 70 } 71 } 72 73 SourceFile::SourceFile(const std::string & path) 74 : m_path(path), m_stream() 75 { 76 } 77 78 //! The file is closed if it had been left opened. 79 //! 80 SourceFile::~SourceFile() 81 { 82 if (isOpen()) 83 { 84 m_stream->close(); 85 } 86 } 87 88 //! \exception std::runtime_error Raised if the file could not be opened successfully. 89 void SourceFile::open() 90 { 91 assert(!isOpen()); 92 m_stream = new std::ifstream(m_path.c_str(), std::ios_base::in | std::ios_base::binary); 93 if (!m_stream->is_open()) 94 { 95 throw std::runtime_error(format_string("failed to open file: %s", m_path.c_str())); 96 } 97 } 98 99 void SourceFile::close() 100 { 101 assert(isOpen()); 102 103 m_stream->close(); 104 m_stream.safe_delete(); 105 } 106 107 unsigned SourceFile::getSize() 108 { 109 bool wasOpen = isOpen(); 110 std::ifstream::pos_type oldPosition; 111 112 if (!wasOpen) 113 { 114 open(); 115 } 116 117 assert(m_stream); 118 oldPosition = m_stream->tellg(); 119 m_stream->seekg(0, std::ios_base::end); 120 unsigned resultSize = m_stream->tellg(); 121 m_stream->seekg(oldPosition); 122 123 if (!wasOpen) 124 { 125 close(); 126 } 127 128 return resultSize; 129 } 130 131 //! If the file does not support named sections, or if there is not a 132 //! section with the given name, this method may return NULL. 133 //! 134 //! This method is just a small wrapper that creates an 135 //! FixedMatcher string matcher instance and uses the createDataSource() 136 //! that takes a reference to a StringMatcher. 137 DataSource * SourceFile::createDataSource(const std::string & section) 138 { 139 FixedMatcher matcher(section); 140 return createDataSource(matcher); 141 } 142 143 DataTarget * SourceFile::createDataTargetForEntryPoint() 144 { 145 if (!hasEntryPoint()) 146 { 147 return NULL; 148 } 149 150 return new ConstantDataTarget(getEntryPointAddress()); 151 } 152 153 DataSource * BinarySourceFile::createDataSource() 154 { 155 std::istream * fileStream = getStream(); 156 assert(fileStream); 157 158 // get stream size 159 fileStream->seekg(0, std::ios_base::end); 160 int length = fileStream->tellg(); 161 162 // allocate buffer 163 smart_array_ptr<uint8_t> data = new uint8_t[length]; 164 // if (!data) 165 // { 166 // throw std::bad_alloc(); 167 // } 168 169 // read entire file into the buffer 170 fileStream->seekg(0, std::ios_base::beg); 171 if (fileStream->read((char *)data.get(), length).bad()) 172 { 173 throw std::runtime_error(format_string("unexpected end of file: %s", m_path.c_str())); 174 } 175 176 // create the data source. the buffer is copied, so we can dispose of it. 177 return new UnmappedDataSource(data, length); 178 } 179