OSDN Git Service

Merge branch 'master' of git://github.com/monaka/binutils
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / loader / compLoader.cxx
1 // compLoader.cxx - object file loader component.  -*- C++ -*-
2
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.
6
7 #include <sidcomp.h>
8 #include <sidso.h>
9 #include <sidcomputil.h>
10 #include <sidattrutil.h>
11 #include <sidpinutil.h>
12 #include <sidbusutil.h>
13 #include <sidcpuutil.h>
14 #include <sidtypes.h>
15 #include <sidmiscutil.h>
16
17 #include <vector>
18 #include <string>
19 #include <cstdlib>
20 #include <ctime>
21 #include <cerrno>
22 #include <unistd.h>
23 #include <fstream>
24
25 extern "C" {
26 #include "elfload.h"
27 }
28
29 using std::vector;
30 using std::string;
31 using std::ostream;
32 using std::istream;
33 using std::ios;
34 using std::endl;
35 using std::cout;
36 using std::ifstream;
37 using std::cerr;
38
39 using sid::component;
40 using sid::bus;
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;
47
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;
62
63 // ----------------------------------------------------------------------------
64
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
68   {
69   public:
70     loader_probe_bus (sid::bus **t, output_pin *p) :
71       sidutil::passthrough_bus (t),
72       write_to_code_address_pin (p),
73       section_table (0)
74     {
75       assert (t);
76     }
77     ~loader_probe_bus() throw() {}
78     
79     void set_section_table (const struct TextSection *s) { section_table = s; }
80
81     void probe_address (sid::host_int_4 addr)
82       {
83         if (write_to_code_address_pin && textSectionAddress (addr, section_table))
84           write_to_code_address_pin->drive (addr);
85       }
86
87     // Some macros to make manufacturing of the cartesian-product
88     // calls simpler.
89 #define SID_GB_WRITE(dtype) \
90       sid::bus::status write(sid::host_int_4 addr, dtype data) throw ()\
91           { if (LIKELY(*target)) \
92               { \
93                 probe_address (addr); \
94                 return (*target)->write(addr, data); \
95               } \
96             else return sid::bus::unpermitted; \
97           }
98
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)
107
108 #undef SID_GB_WRITE
109
110     output_pin *write_to_code_address_pin;
111     const struct TextSection *section_table;
112   };
113
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
121 {
122 private:
123   callback_pin<generic_loader> doit_pin;
124
125 protected:
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;
133
134   // Provide address of write attempt to code section
135   output_pin write_to_code_address_pin;
136
137   // Signal this if something went wrong.
138   output_pin error_pin;
139
140   // Attribute settings
141   bool verbose_p;
142
143   // loadable file names
144   string load_file;
145
146   // accessors
147   bus* load_accessor_insn;
148   bus* load_accessor_data;
149
150   loader_probe_bus probe_upstream;
151   bus           *probe_downstream;
152   callback_pin<generic_loader> probe_pin;
153
154   void handle_probe_pin (sid::host_int_4 v)
155     {
156       probe_upstream.probe_address (v);
157     }
158
159   // The load pin was triggered.
160   virtual void load_it (host_int_4) = 0;
161
162   // state control
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); }
168
169   virtual void configure (const string &config);
170
171 public:
172   generic_loader(): 
173     doit_pin(this, & generic_loader::load_it), 
174     verbose_p(false),
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),
179     probe_downstream(0),
180     probe_pin (this, & generic_loader::handle_probe_pin)
181     {
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);
198     }
199   ~generic_loader() throw() { }
200     
201 };
202
203 void
204 generic_loader::configure (const string &config)
205 {
206   // Call up to the base class first
207   configurable_component::configure (config);
208
209   // Now handle relevent configuration for us.
210   if (config.size () < 12)
211     return;
212   if (config.substr (0, 8) == "verbose=")
213     {
214       verbose_p = (config.substr (8) == "true");
215       return;
216     }
217 }
218
219 ostream& 
220 operator << (ostream& out, const generic_loader& it)
221 {
222   out << "loader-state "
223       << string2stream(it.load_file) << " "
224       << it.verbose_p;
225
226   return out;
227 }
228
229
230 istream& 
231 operator >> (istream& in, generic_loader& it)
232 {
233   string coding;
234   in >> coding;
235   if (coding == "loader-state")
236     {
237       in >> stream2string(it.load_file)
238          >> it.verbose_p;
239     }
240   else
241     {
242       in.setstate(ios::badbit);
243     }
244
245   return in;
246 }
247
248 // ----------------------------------------------------------------------------
249
250 class elf_loader: public generic_loader
251 {
252 public:
253   elf_loader ()
254     : generic_loader (),
255       symbol_table (0),
256       current_function (""),
257       check_function_pin (this, &elf_loader::check_function_pin_handler)
258     {
259       add_pin ("function?", &check_function_pin);
260       add_attribute ("current-function", & current_function);
261     }
262   ~elf_loader () throw () {}
263
264 private:
265   // static pointer to active instance (XXX: concurrency?)
266   static elf_loader* freeloader;
267
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);
271
272   // stream for current file  
273   ifstream* file;
274
275   void load_it (host_int_4)
276     {
277       if (this->load_accessor_insn == 0 || this->load_accessor_data == 0)
278         {
279           cerr << "loader: error - target accessors not configured!" << endl;
280           this->error_pin.drive (0);
281           return;
282         }
283
284       if (this->verbose_p)
285         {
286           cout << "loader: reading program " << this->load_file << endl;
287         }
288
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())
292         {
293           cerr << "loader: error opening " << load_file << ": "
294                << std_error_string() << endl;
295           return;
296         }
297
298       elf_loader::freeloader = this;
299       unsigned entry_point;
300       int little_endian_p;
301       unsigned eflags;
302
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;
309
310       if (success_p)
311         {
312           // Tell anyone who's listening things we learned about the elf file.
313           this->start_pc_pin.drive((host_int_4) entry_point);
314           if (little_endian_p)
315             this->endian_pin.drive(sidutil::endian_little);
316           else
317             this->endian_pin.drive(sidutil::endian_big);
318           this->eflags_pin.drive((host_int_4) eflags);
319
320           if (this->verbose_p)
321             cout << "loader: starting "
322                  << (little_endian_p ? "little-" : "big-") << "endian"
323                  << " program at pc=" 
324                  << make_numeric_attribute (entry_point, ios::hex | ios::showbase)
325                  << endl;
326         }
327       else
328         {
329           cerr << "loader: error loading " << load_file << endl;
330           this->error_pin.drive (0);
331         }
332
333       delete this->file;
334       this->file = 0;
335     }
336
337 protected:
338   callback_pin<elf_loader> check_function_pin;
339   void check_function_pin_handler (host_int_4 addr);
340
341   const struct Symbol *symbol_table;
342   string current_function;
343 };
344
345 // static variable
346 elf_loader* elf_loader::freeloader = 0;
347
348 // static function
349 int
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)
351 {
352   elf_loader& l = * elf_loader::freeloader;
353   string who = insn_space ? "instruction" : "data";
354
355   if (l.verbose_p)
356     {
357       if (host_addr == 0)
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)
364              << endl;
365     }
366
367   ifstream& f = * l.file;
368   bus* b;
369
370   if (insn_space)
371     b = l.load_accessor_insn;
372   else
373     b = l.load_accessor_data;
374   assert (b);
375
376   // go to proper offset in file
377   f.seekg(file_offset);
378
379   // fetch lots of characters
380   for (int n = 0; n < bytes; n++)
381     {
382       char c;
383       f.get(c);
384       if (!f.good())
385         {
386           cerr << "loader: error reading byte " << file_offset+n
387                << " from file " << l.load_file << endl;
388           return -1; // oops
389         }
390
391       if (host_addr) // read into host buffer
392         {
393           // cerr << "H:" << (void*)host_addr << ":" << hex << (int)c << dec << endl;
394           *host_addr++ = c;
395         }
396       else // read into target memory
397         {
398           host_int_8 a = dest_addr++;
399           little_int_1 data = c;
400           host_int_4 addr = a;
401
402           bus::status s = b->write(addr, data);
403
404           if (s != bus::ok) // abort on error
405             {
406               cerr << "loader: write to " << who << " accessor failed at address "
407                    << make_numeric_attribute (addr, ios::hex | ios::showbase)
408                    << ", status "
409                    << (int) s << endl;
410               return -1;
411             }
412           // else
413           //  cerr << "T:" << addr << ":" << data << endl;
414         }
415     }
416   return bytes;
417 }
418
419 void
420 elf_loader::check_function_pin_handler (host_int_4 addr)
421 {
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.
425   if (symbol_table)
426     {
427       unsigned closest = 0;
428       host_int_8 min_difference = ~(host_int_8)0;
429       unsigned ix;
430       for (ix = 0; symbol_table[ix].name; ++ix)
431         {
432           // Don't consider unnamed symbols.
433           if (! symbol_table[ix].name[0])
434             continue;
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)
438             break;
439           if (addr > sym_addr && addr < (sym_addr + sym_size))
440             break;
441           if (addr - sym_addr < min_difference)
442             {
443               min_difference = addr - sym_addr;
444               closest = ix;
445             }
446         }
447       if (symbol_table[ix].name)
448         {
449           current_function = symbol_table[ix].name;
450           return;
451         }
452       if (closest != 0)
453         {
454           current_function = symbol_table[closest].name;
455           return;
456         }
457     }
458   current_function = "";
459 }
460
461 // ----------------------------------------------------------------------------
462
463 static
464 vector<string>
465 compLoaderListTypes()
466 {
467   vector<string> types;
468   types.push_back("sw-load-elf");
469   return types;
470 }
471
472 static
473 component*
474 compLoaderCreate(const string& typeName)
475 {
476   if (typeName == "sw-load-elf")
477     return new elf_loader();
478   else
479     return 0;
480 }
481
482 static
483 void
484 compLoaderDelete(component* c)
485 {
486   delete dynamic_cast<elf_loader*>(c);
487 }
488
489 // static object
490 DLLEXPORT extern const component_library loader_component_library;
491
492 const component_library loader_component_library =
493 {
494   COMPONENT_LIBRARY_MAGIC,
495   & compLoaderListTypes, 
496   & compLoaderCreate,
497   & compLoaderDelete
498 };