summaryrefslogtreecommitdiffstats
path: root/common/SourceFile.cpp
blob: 947ae17fd124528da0b2ab55551128ff0360ea64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * File:	SourceFile.cpp
 *
 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
 * See included license file for license details.
 */

#include "SourceFile.h"
#include "ELFSourceFile.h"
#include "SRecordSourceFile.h"
#include <assert.h>
#include "format_string.h"
#include "SearchPath.h"

using namespace elftosb;

//! The supported file types are currently:
//!		- ELF files
//!		- Motorola S-record files
//!		- Binary files
//!
//! Any file that is not picked up by the other subclasses will result in a
//! an instance of BinaryDataFile.
//!
//! \return An instance of the correct subclass of SourceFile for the given path.
//!
//! \exception std::runtime_error Thrown if the file cannot be opened.
//!
//! \see elftosb::ELFSourceFile
//! \see elftosb::SRecordSourceFile
//! \see elftosb::BinarySourceFile
SourceFile * SourceFile::openFile(const std::string & path)
{
	// Search for file using search paths
	std::string actualPath;
	bool found = PathSearcher::getGlobalSearcher().search(path, PathSearcher::kFindFile, true, actualPath);
	if (!found)
	{
		throw std::runtime_error(format_string("unable to find file %s\n", path.c_str()));
	}

	std::ifstream testStream(actualPath.c_str(), std::ios_base::in | std::ios_base::binary);
	if (!testStream.is_open())
	{
		throw std::runtime_error(format_string("failed to open file: %s", actualPath.c_str()));
	}
	
	// catch exceptions so we can close the file stream
	try
	{
		if (ELFSourceFile::isELFFile(testStream))
		{
			testStream.close();
			return new ELFSourceFile(actualPath);
		}
		else if (SRecordSourceFile::isSRecordFile(testStream))
		{
			testStream.close();
			return new SRecordSourceFile(actualPath);
		}
		
		// treat it as a binary file
		testStream.close();
		return new BinarySourceFile(actualPath);
	}
	catch (...)
	{
		testStream.close();
		throw;
	}
}

SourceFile::SourceFile(const std::string & path)
:	m_path(path), m_stream()
{
}

//! The file is closed if it had been left opened.
//!
SourceFile::~SourceFile()
{
	if (isOpen())
	{
		m_stream->close();
	}
}

//! \exception std::runtime_error Raised if the file could not be opened successfully.
void SourceFile::open()
{
	assert(!isOpen());
	m_stream = new std::ifstream(m_path.c_str(), std::ios_base::in | std::ios_base::binary);
	if (!m_stream->is_open())
	{
		throw std::runtime_error(format_string("failed to open file: %s", m_path.c_str()));
	}
}

void SourceFile::close()
{
	assert(isOpen());
	
	m_stream->close();
	m_stream.safe_delete();
}

unsigned SourceFile::getSize()
{
	bool wasOpen = isOpen();
	std::ifstream::pos_type oldPosition;
	
	if (!wasOpen)
	{
		open();
	}
	
	assert(m_stream);
	oldPosition = m_stream->tellg();
	m_stream->seekg(0, std::ios_base::end);
	unsigned resultSize = m_stream->tellg();
	m_stream->seekg(oldPosition);
	
	if (!wasOpen)
	{
		close();
	}
	
	return resultSize;
}

//! If the file does not support named sections, or if there is not a
//! section with the given name, this method may return NULL.
//!
//! This method is just a small wrapper that creates an
//! FixedMatcher string matcher instance and uses the createDataSource()
//! that takes a reference to a StringMatcher.
DataSource * SourceFile::createDataSource(const std::string & section)
{
	FixedMatcher matcher(section);
	return createDataSource(matcher);
}

DataTarget * SourceFile::createDataTargetForEntryPoint()
{
	if (!hasEntryPoint())
	{
		return NULL;
	}
	
	return new ConstantDataTarget(getEntryPointAddress());
}

DataSource * BinarySourceFile::createDataSource()
{
	std::istream * fileStream = getStream();
	assert(fileStream);
	
	// get stream size
	fileStream->seekg(0, std::ios_base::end);
	int length = fileStream->tellg();
	
	// allocate buffer
	smart_array_ptr<uint8_t> data = new uint8_t[length];
//	if (!data)
//	{
//	    throw std::bad_alloc();
//	}
	
	// read entire file into the buffer
	fileStream->seekg(0, std::ios_base::beg);
	if (fileStream->read((char *)data.get(), length).bad())
	{
		throw std::runtime_error(format_string("unexpected end of file: %s", m_path.c_str()));
	}
	
	// create the data source. the buffer is copied, so we can dispose of it.
	return new UnmappedDataSource(data, length);
}