1 // compLoader.cxx - object file loader component. -*- C++ -*-
3 // Copyright (C) 1999, 2000, 2003, 2004, 2005 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
9 #include <sidcomputil.h>
10 #include <sidattrutil.h>
11 #include <sidpinutil.h>
12 #include <sidbusutil.h>
13 #include <sidcpuutil.h>
15 #include <sidmiscutil.h>
41 using sid::host_int_1;
42 using sid::little_int_1;
43 using sid::host_int_4;
44 using sid::host_int_8;
45 using sid::component_library;
46 using sid::COMPONENT_LIBRARY_MAGIC;
48 using sidutil::fixed_bus_map_component;
49 using sidutil::fixed_attribute_map_component;
50 using sidutil::fixed_pin_map_component;
51 using sidutil::fixed_accessor_map_component;
52 using sidutil::no_relation_component;
53 using sidutil::configurable_component;
54 using sidutil::output_pin;
55 using sidutil::callback_pin;
56 using sidutil::string2stream;
57 using sidutil::stream2string;
58 using sidutil::make_attribute;
59 using sidutil::make_numeric_attribute;
60 using sidutil::parse_attribute;
61 using sidutil::std_error_string;
63 // ----------------------------------------------------------------------------
65 // A bus for allowing the loader to perform random checks against reads and writes
66 // to memory. For example writing to a code area. Default implementation
67 class loader_probe_bus: public sidutil::passthrough_bus
70 loader_probe_bus (sid::bus **t, output_pin *p) :
71 sidutil::passthrough_bus (t),
72 write_to_code_address_pin (p),
77 ~loader_probe_bus() throw() {}
79 void set_section_table (const struct TextSection *s) { section_table = s; }
81 void probe_address (sid::host_int_4 addr)
83 if (write_to_code_address_pin && textSectionAddress (addr, section_table))
84 write_to_code_address_pin->drive (addr);
87 // Some macros to make manufacturing of the cartesian-product
89 #define SID_GB_WRITE(dtype) \
90 sid::bus::status write(sid::host_int_4 addr, dtype data) throw ()\
91 { if (LIKELY(*target)) \
93 probe_address (addr); \
94 return (*target)->write(addr, data); \
96 else return sid::bus::unpermitted; \
99 SID_GB_WRITE(sid::little_int_1)
100 SID_GB_WRITE(sid::big_int_1)
101 SID_GB_WRITE(sid::little_int_2)
102 SID_GB_WRITE(sid::big_int_2)
103 SID_GB_WRITE(sid::little_int_4)
104 SID_GB_WRITE(sid::big_int_4)
105 SID_GB_WRITE(sid::little_int_8)
106 SID_GB_WRITE(sid::big_int_8)
110 output_pin *write_to_code_address_pin;
111 const struct TextSection *section_table;
114 class generic_loader: public virtual component,
115 protected fixed_bus_map_component,
116 protected virtual fixed_attribute_map_component,
117 protected virtual fixed_pin_map_component,
118 protected fixed_accessor_map_component,
119 protected no_relation_component,
120 protected virtual configurable_component
123 callback_pin<generic_loader> doit_pin;
126 // entry point address
127 output_pin start_pc_pin;
128 // endianness as specified in ELF header.
129 // The value is one of sidutil::endian_*.
130 output_pin endian_pin;
131 // eflags as specified in ELF header.
132 output_pin eflags_pin;
134 // Provide address of write attempt to code section
135 output_pin write_to_code_address_pin;
137 // Signal this if something went wrong.
138 output_pin error_pin;
140 // Attribute settings
143 // loadable file names
147 bus* load_accessor_insn;
148 bus* load_accessor_data;
150 loader_probe_bus probe_upstream;
151 bus *probe_downstream;
152 callback_pin<generic_loader> probe_pin;
154 void handle_probe_pin (sid::host_int_4 v)
156 probe_upstream.probe_address (v);
159 // The load pin was triggered.
160 virtual void load_it (host_int_4) = 0;
163 friend ostream& operator << (ostream& o, const generic_loader& it);
164 friend istream& operator >> (istream& i, generic_loader& it);
165 string save_state() { return make_attribute(*this); }
166 sid::component::status restore_state(const string& state)
167 { return parse_attribute(state, *this); }
169 virtual void configure (const string &config);
173 doit_pin(this, & generic_loader::load_it),
175 load_file("/dev/null"),
176 load_accessor_insn(0),
177 load_accessor_data(0),
178 probe_upstream (& probe_downstream, & this->write_to_code_address_pin),
180 probe_pin (this, & generic_loader::handle_probe_pin)
182 add_pin("load!", & this->doit_pin);
183 add_pin("start-pc-set", & this->start_pc_pin);
184 add_pin("endian-set", & this->endian_pin);
185 add_pin("eflags-set", &this->eflags_pin);
186 add_pin("error", & this->error_pin);
187 add_pin("write-to-code-address", & this->write_to_code_address_pin);
188 add_accessor("load-accessor-insn", & this->load_accessor_insn);
189 add_accessor("load-accessor-data", & this->load_accessor_data);
190 add_attribute("file", & this->load_file, "setting");
191 add_bus ("probe-upstream", & this->probe_upstream);
192 add_accessor ("probe-downstream", & this->probe_downstream);
193 add_pin ("probe", & this->probe_pin);
194 add_attribute("verbose?", & this->verbose_p, "setting");
195 add_attribute_virtual ("state-snapshot", this,
196 & generic_loader::save_state,
197 & generic_loader::restore_state);
199 ~generic_loader() throw() { }
204 generic_loader::configure (const string &config)
206 // Call up to the base class first
207 configurable_component::configure (config);
209 // Now handle relevent configuration for us.
210 if (config.size () < 12)
212 if (config.substr (0, 8) == "verbose=")
214 verbose_p = (config.substr (8) == "true");
220 operator << (ostream& out, const generic_loader& it)
222 out << "loader-state "
223 << string2stream(it.load_file) << " "
231 operator >> (istream& in, generic_loader& it)
235 if (coding == "loader-state")
237 in >> stream2string(it.load_file)
242 in.setstate(ios::badbit);
248 // ----------------------------------------------------------------------------
250 class elf_loader: public generic_loader
256 current_function (""),
257 check_function_pin (this, &elf_loader::check_function_pin_handler)
259 add_pin ("function?", &check_function_pin);
260 add_attribute ("current-function", & current_function);
262 ~elf_loader () throw () {}
265 // static pointer to active instance (XXX: concurrency?)
266 static elf_loader* freeloader;
268 // callback function from C code in elfload.c
269 static int load_function(host_int_8 dest_addr, char* host_addr, host_int_8 file_offset, host_int_8 bytes, int insn_space);
270 static int verbose_function(char* s);
272 // stream for current file
275 void load_it (host_int_4)
277 if (this->load_accessor_insn == 0 || this->load_accessor_data == 0)
279 cerr << "loader: error - target accessors not configured!" << endl;
280 this->error_pin.drive (0);
286 cout << "loader: reading program " << this->load_file << endl;
289 assert(elf_loader::freeloader == 0);
290 this->file = new ifstream(this->load_file.c_str(), ios::binary | ios::in);
291 if (! this->file->good())
293 cerr << "loader: error opening " << load_file << ": "
294 << std_error_string() << endl;
298 elf_loader::freeloader = this;
299 unsigned entry_point;
303 const struct TextSection *section_table;
304 int success_p = readElfFile(& elf_loader::load_function,
305 & entry_point, & little_endian_p,
306 & eflags, & section_table, & symbol_table);
307 probe_upstream.set_section_table (section_table);
308 elf_loader::freeloader = 0;
312 // Tell anyone who's listening things we learned about the elf file.
313 this->start_pc_pin.drive((host_int_4) entry_point);
315 this->endian_pin.drive(sidutil::endian_little);
317 this->endian_pin.drive(sidutil::endian_big);
318 this->eflags_pin.drive((host_int_4) eflags);
321 cout << "loader: starting "
322 << (little_endian_p ? "little-" : "big-") << "endian"
324 << make_numeric_attribute (entry_point, ios::hex | ios::showbase)
329 cerr << "loader: error loading " << load_file << endl;
330 this->error_pin.drive (0);
338 callback_pin<elf_loader> check_function_pin;
339 void check_function_pin_handler (host_int_4 addr);
341 const struct Symbol *symbol_table;
342 string current_function;
346 elf_loader* elf_loader::freeloader = 0;
350 elf_loader::load_function(host_int_8 dest_addr, char *host_addr, host_int_8 file_offset, host_int_8 bytes, int insn_space)
352 elf_loader& l = * elf_loader::freeloader;
353 string who = insn_space ? "instruction" : "data";
358 cout << "loader: reading "
359 << make_numeric_attribute (bytes, ios::hex | ios::showbase)
360 << " bytes from file offset "
361 << make_numeric_attribute (file_offset, ios::hex | ios::showbase)
362 << " into target " << who << " memory at "
363 << make_numeric_attribute (dest_addr, ios::hex | ios::showbase)
367 ifstream& f = * l.file;
371 b = l.load_accessor_insn;
373 b = l.load_accessor_data;
376 // go to proper offset in file
377 f.seekg(file_offset);
379 // fetch lots of characters
380 for (int n = 0; n < bytes; n++)
386 cerr << "loader: error reading byte " << file_offset+n
387 << " from file " << l.load_file << endl;
391 if (host_addr) // read into host buffer
393 // cerr << "H:" << (void*)host_addr << ":" << hex << (int)c << dec << endl;
396 else // read into target memory
398 host_int_8 a = dest_addr++;
399 little_int_1 data = c;
402 bus::status s = b->write(addr, data);
404 if (s != bus::ok) // abort on error
406 cerr << "loader: write to " << who << " accessor failed at address "
407 << make_numeric_attribute (addr, ios::hex | ios::showbase)
413 // cerr << "T:" << addr << ":" << data << endl;
420 elf_loader::check_function_pin_handler (host_int_4 addr)
422 // Find the function corresponding to the given address in the symbol
423 // table, if any, and set current_function to that name. If a function is
424 // found, set current_function to a string representing the address.
427 unsigned closest = 0;
428 host_int_8 min_difference = ~(host_int_8)0;
430 for (ix = 0; symbol_table[ix].name; ++ix)
432 // Don't consider unnamed symbols.
433 if (! symbol_table[ix].name[0])
435 host_int_8 sym_addr = symbol_table[ix].addr;
436 host_int_8 sym_size = symbol_table[ix].size;
437 if (addr == sym_addr)
439 if (addr > sym_addr && addr < (sym_addr + sym_size))
441 if (addr - sym_addr < min_difference)
443 min_difference = addr - sym_addr;
447 if (symbol_table[ix].name)
449 current_function = symbol_table[ix].name;
454 current_function = symbol_table[closest].name;
458 current_function = "";
461 // ----------------------------------------------------------------------------
465 compLoaderListTypes()
467 vector<string> types;
468 types.push_back("sw-load-elf");
474 compLoaderCreate(const string& typeName)
476 if (typeName == "sw-load-elf")
477 return new elf_loader();
484 compLoaderDelete(component* c)
486 delete dynamic_cast<elf_loader*>(c);
490 DLLEXPORT extern const component_library loader_component_library;
492 const component_library loader_component_library =
494 COMPONENT_LIBRARY_MAGIC,
495 & compLoaderListTypes,