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
openFile(const std::string & path)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 
SourceFile(const std::string & path)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 //!
~SourceFile()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.
open()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 
close()99 void SourceFile::close()
100 {
101           assert(isOpen());
102 
103           m_stream->close();
104           m_stream.safe_delete();
105 }
106 
getSize()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.
createDataSource(const std::string & section)137 DataSource * SourceFile::createDataSource(const std::string & section)
138 {
139           FixedMatcher matcher(section);
140           return createDataSource(matcher);
141 }
142 
createDataTargetForEntryPoint()143 DataTarget * SourceFile::createDataTargetForEntryPoint()
144 {
145           if (!hasEntryPoint())
146           {
147                     return NULL;
148           }
149 
150           return new ConstantDataTarget(getEntryPointAddress());
151 }
152 
createDataSource()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