FileLoader.cc Source File

Back to the index.

FileLoader.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008-2018 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <assert.h>
29 #include <string.h>
30 #include <fstream>
31 
32 using std::ifstream;
33 
34 #include "AddressDataBus.h"
35 #include "Component.h"
36 #include "FileLoader.h"
37 #include "FileLoader_aout.h"
38 #include "FileLoader_bout.h"
39 #include "FileLoader_ELF.h"
40 #include "FileLoader_raw.h"
41 
42 
43 FileLoader::FileLoader(const string& filename)
44  : m_filename(filename)
45 {
46  m_fileLoaders.push_back(new FileLoader_aout(filename));
47  m_fileLoaders.push_back(new FileLoader_bout(filename));
48  m_fileLoaders.push_back(new FileLoader_ELF(filename));
49  m_fileLoaders.push_back(new FileLoader_raw(filename));
50 }
51 
52 
53 const string& FileLoader::GetFilename() const
54 {
55  return m_filename;
56 }
57 
58 
60 {
61  loader = NULL;
62 
63  // TODO: Disk images?
64 
65  ifstream file(m_filename.c_str());
66 
67  unsigned char buf[512];
68  memset(buf, 0, sizeof(buf));
69  size_t amountRead = 0;
70  if (file.is_open()) {
71  file.read((char *)buf, sizeof(buf));
72  amountRead = file.gcount();
73  }
74 
75  // Ask all file loaders about how well they handle the format. Return
76  // the format string from the loader that had the highest score.
77  float bestMatch = 0.0;
78  string bestFormat = "Unknown";
79  FileLoaderImplVector::const_iterator it = m_fileLoaders.begin();
80  for (; it != m_fileLoaders.end(); ++it) {
81  float match;
82  string format = (*it)->DetectFileType(buf, amountRead, match);
83  if (match > bestMatch) {
84  bestMatch = match;
85  bestFormat = format;
86  loader = *it;
87  }
88  }
89 
90  if (bestMatch == 0.0 && !file.is_open())
91  return "Not accessible";
92 
93  return bestFormat;
94 }
95 
96 
97 bool FileLoader::Load(refcount_ptr<Component> component, ostream& messages) const
98 {
99  AddressDataBus * bus = component->AsAddressDataBus();
100  if (bus == NULL) {
101  // We cannot load into something that isn't an AddressDataBus.
102  messages << "Error: " << component->GenerateShortestPossiblePath()
103  << " is not an AddressDataBus.\n";
104  return false;
105  }
106 
108  string fileFormat = DetectFileFormat(loaderImpl);
109 
110  if (!loaderImpl.IsNULL())
111  return loaderImpl->LoadIntoComponent(component, messages);
112 
113  messages << "Error: File format '" <<
114  fileFormat << "' not yet implemented. TODO\n";
115 
116  return false;
117 }
118 
119 
120 /*****************************************************************************/
121 
122 
123 #ifdef WITHUNITTESTS
124 
125 #include "ComponentFactory.h"
126 
127 static void Test_FileLoader_Constructor()
128 {
129  FileLoader fileLoader("test/FileLoader_ELF_MIPS");
130  UnitTest::Assert("filename mismatch?",
131  fileLoader.GetFilename(), "test/FileLoader_ELF_MIPS");
132 }
133 
134 static void Test_FileLoader_Constructor_NonExistingFile()
135 {
136  FileLoader fileLoader("test/Nonexisting");
137  UnitTest::Assert("filename mismatch?",
138  fileLoader.GetFilename(), "test/Nonexisting");
139 }
140 
141 static void Test_FileLoader_DetectFileFormat_NonexistingFile()
142 {
143  FileLoader fileLoader("test/Nonexisting");
145  UnitTest::Assert("file format detection failure?",
146  fileLoader.DetectFileFormat(loaderImpl), "Not accessible");
147 }
148 
149 static void Test_FileLoader_DetectFileFormat_NonsenseFile()
150 {
151  FileLoader fileLoader("test/FileLoader_NonsenseFile");
153  UnitTest::Assert("file format detection failure?",
154  fileLoader.DetectFileFormat(loaderImpl), "Unknown");
155 }
156 
157 static void Test_FileLoader_DetectFileFormat_ELF32()
158 {
159  FileLoader fileLoader("test/FileLoader_ELF_MIPS");
161  UnitTest::Assert("file format detection failure?",
162  fileLoader.DetectFileFormat(loaderImpl), "ELF32");
163 }
164 
165 static void Test_FileLoader_DetectFileFormat_ELF64()
166 {
167  FileLoader fileLoader("test/FileLoader_ELF_SH5");
169  UnitTest::Assert("file format detection failure?",
170  fileLoader.DetectFileFormat(loaderImpl), "ELF64");
171 }
172 
173 static void Test_FileLoader_DetectFileFormat_aout_88K()
174 {
175  FileLoader fileLoader("test/FileLoader_A.OUT_M88K");
177  UnitTest::Assert("file format detection failure?",
178  fileLoader.DetectFileFormat(loaderImpl), "a.out_M88K_fromBeginning");
179 }
180 
181 static void Test_FileLoader_DetectFileFormat_bout_i960()
182 {
183  FileLoader fileLoader("test/FileLoader_B.OUT_i960");
185  UnitTest::Assert("file format detection failure?",
186  fileLoader.DetectFileFormat(loaderImpl), "b.out_i960_little");
187 }
188 
189 static refcount_ptr<Component> SetupTestMachineAndLoad(
190  string machineName, string fileName)
191 {
192  FileLoader fileLoader(fileName);
195 
196  machine->SetVariableValue("name", "\"machine\"");
197  refcount_ptr<Component> component =
198  machine->LookupPath("machine.mainbus0.cpu0");
199  UnitTest::Assert("could not look up CPU to load into?",
200  !component.IsNULL());
201 
202  stringstream messages;
203  UnitTest::Assert("could not load the file " + fileName + " for"
204  " machine " + machineName, fileLoader.Load(component, messages));
205 
206  return machine;
207 }
208 
209 static void Test_FileLoader_Load_ELF32()
210 {
212  SetupTestMachineAndLoad("testmips", "test/FileLoader_ELF_MIPS");
213 
214  // Read from CPU, to make sure the file was loaded:
216  machine->LookupPath("machine.mainbus0.cpu0");
217  AddressDataBus * bus = cpu->AsAddressDataBus();
218  bus->AddressSelect((int32_t)0x80010000);
219  uint32_t word = 0x12345678;
220  bus->ReadData(word, BigEndian);
221  UnitTest::Assert("memory (CPU) wasn't filled with data from the file?",
222  word, 0x8f8b8008);
223 
224  // Read directly from RAM too, to make sure the file was loaded:
226  machine->LookupPath("machine.mainbus0.ram0");
227  AddressDataBus * ramBus = ram->AsAddressDataBus();
228  ramBus->AddressSelect(0x1000c);
229  uint32_t word2 = 0x12345678;
230  ramBus->ReadData(word2, BigEndian);
231  UnitTest::Assert("memory (RAM) wasn't filled with data from the file?",
232  word2, 0x006b7021);
233 }
234 
235 static void Test_FileLoader_Load_aout()
236 {
238  SetupTestMachineAndLoad("testm88k", "test/FileLoader_A.OUT_M88K");
239 
240  // Read from CPU, to make sure the file was loaded:
242  machine->LookupPath("machine.mainbus0.cpu0");
243  AddressDataBus * bus = cpu->AsAddressDataBus();
244  bus->AddressSelect((int32_t)0x12b8);
245  uint32_t word = 0x12345678;
246  bus->ReadData(word, BigEndian);
247  UnitTest::Assert("memory (CPU) wasn't filled with data from the file?",
248  word, 0x67ff0020);
249 
250  // Read directly from RAM too, to make sure the file was loaded:
252  machine->LookupPath("machine.mainbus0.ram0");
253  AddressDataBus * ramBus = ram->AsAddressDataBus();
254  ramBus->AddressSelect(0x12e0);
255  uint32_t word2 = 0xfdecba98;
256  ramBus->ReadData(word2, BigEndian);
257  UnitTest::Assert("memory (RAM) wasn't filled with data from the file?",
258  word2, 0xf6c05802);
259 }
260 
262 {
263  UNITTEST(Test_FileLoader_Constructor);
264  UNITTEST(Test_FileLoader_Constructor_NonExistingFile);
265 
266  UNITTEST(Test_FileLoader_DetectFileFormat_NonexistingFile);
267  UNITTEST(Test_FileLoader_DetectFileFormat_NonsenseFile);
268  UNITTEST(Test_FileLoader_DetectFileFormat_ELF32);
269  UNITTEST(Test_FileLoader_DetectFileFormat_ELF64);
270  UNITTEST(Test_FileLoader_DetectFileFormat_aout_88K);
271  UNITTEST(Test_FileLoader_DetectFileFormat_bout_i960);
272 
273  UNITTEST(Test_FileLoader_Load_ELF32);
274  UNITTEST(Test_FileLoader_Load_aout);
275 }
276 
277 #endif
static refcount_ptr< Component > CreateComponent(const string &componentNameAndOptionalArgs, GXemul *gxemul=NULL)
Creates a component given a short component name.
const string & GetFilename() const
Retrieves the filename of this FileLoader.
Definition: FileLoader.cc:53
b.out binary loader.
ELF binary loader.
string GenerateShortestPossiblePath() const
Generates a short string representation of the path to the Component.
Definition: Component.cc:721
An interface for implementing components that read/write data via an address bus. ...
#define UNITTESTS(class)
Helper for unit test case execution.
Definition: UnitTest.h:184
A class used to load binary files into emulated memory.
Definition: FileLoader.h:53
Raw binary loader (no specific format).
virtual bool ReadData(uint8_t &data, Endianness endianness=BigEndian)=0
Reads 8-bit data from the currently selected address.
Definition: cpu.h:326
string DetectFileFormat(refcount_ptr< const FileLoaderImpl > &loader) const
Attempt to detect the file format of the file.
Definition: FileLoader.cc:59
static void Assert(const string &strFailMessage, bool condition)
Asserts that a boolean condition is correct.
Definition: UnitTest.cc:40
virtual void AddressSelect(uint64_t address)=0
Place an address on the bus.
bool SetVariableValue(const string &name, const string &expression)
Sets a variable to a new value.
Definition: Component.cc:1030
virtual AddressDataBus * AsAddressDataBus()
Returns the component&#39;s AddressDataBus interface, if any.
Definition: Component.cc:367
bool Load(refcount_ptr< Component > component, ostream &messages) const
Loads the file into a CPU or an AddressDataBus.
Definition: FileLoader.cc:97
virtual bool LoadIntoComponent(refcount_ptr< Component > component, ostream &messages) const =0
Loads the file into a Component.
FileLoader(const string &filename)
Constructs a FileLoader object.
Definition: FileLoader.cc:43
const refcount_ptr< Component > LookupPath(string path) const
Looks up a path from this Component, and returns a pointer to the found Component, if any.
Definition: Component.cc:778
a.out binary loader.
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217
bool IsNULL() const
Checks whether or not an object is referenced by the reference counted pointer.
Definition: refcount_ptr.h:216

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13