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