OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [gold/] [plugin.cc] - Blame information for rev 53

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 khays
// plugin.cc -- plugin manager for gold      -*- C++ -*-
2
 
3
// Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
4
// Written by Cary Coutant <ccoutant@google.com>.
5
 
6
// This file is part of gold.
7
 
8
// This program is free software; you can redistribute it and/or modify
9
// it under the terms of the GNU General Public License as published by
10
// the Free Software Foundation; either version 3 of the License, or
11
// (at your option) any later version.
12
 
13
// This program is distributed in the hope that it will be useful,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
// GNU General Public License for more details.
17
 
18
// You should have received a copy of the GNU General Public License
19
// along with this program; if not, write to the Free Software
20
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21
// MA 02110-1301, USA.
22
 
23
#include "gold.h"
24
 
25
#include <cstdio>
26
#include <cstdarg>
27
#include <cstring>
28
#include <string>
29
#include <vector>
30
 
31
#ifdef ENABLE_PLUGINS
32
#include <dlfcn.h>
33
#endif
34
 
35
#include "parameters.h"
36
#include "errors.h"
37
#include "fileread.h"
38
#include "layout.h"
39
#include "options.h"
40
#include "plugin.h"
41
#include "target.h"
42
#include "readsyms.h"
43
#include "symtab.h"
44
#include "elfcpp.h"
45
 
46
namespace gold
47
{
48
 
49
#ifdef ENABLE_PLUGINS
50
 
51
// The linker's exported interfaces.
52
 
53
extern "C"
54
{
55
 
56
static enum ld_plugin_status
57
register_claim_file(ld_plugin_claim_file_handler handler);
58
 
59
static enum ld_plugin_status
60
register_all_symbols_read(ld_plugin_all_symbols_read_handler handler);
61
 
62
static enum ld_plugin_status
63
register_cleanup(ld_plugin_cleanup_handler handler);
64
 
65
static enum ld_plugin_status
66
add_symbols(void *handle, int nsyms, const struct ld_plugin_symbol *syms);
67
 
68
static enum ld_plugin_status
69
get_input_file(const void *handle, struct ld_plugin_input_file *file);
70
 
71
static enum ld_plugin_status
72
get_view(const void *handle, const void **viewp);
73
 
74
static enum ld_plugin_status
75
release_input_file(const void *handle);
76
 
77
static enum ld_plugin_status
78
get_symbols(const void *handle, int nsyms, struct ld_plugin_symbol *syms);
79
 
80
static enum ld_plugin_status
81
add_input_file(const char *pathname);
82
 
83
static enum ld_plugin_status
84
add_input_library(const char *pathname);
85
 
86
static enum ld_plugin_status
87
set_extra_library_path(const char *path);
88
 
89
static enum ld_plugin_status
90
message(int level, const char *format, ...);
91
 
92
};
93
 
94
#endif // ENABLE_PLUGINS
95
 
96
static Pluginobj* make_sized_plugin_object(Input_file* input_file,
97
                                           off_t offset, off_t filesize);
98
 
99
// Plugin methods.
100
 
101
// Load one plugin library.
102
 
103
void
104
Plugin::load()
105
{
106
#ifdef ENABLE_PLUGINS
107
  // Load the plugin library.
108
  // FIXME: Look for the library in standard locations.
109
  this->handle_ = dlopen(this->filename_.c_str(), RTLD_NOW);
110
  if (this->handle_ == NULL)
111
    {
112
      gold_error(_("%s: could not load plugin library: %s"),
113
                 this->filename_.c_str(), dlerror());
114
      return;
115
    }
116
 
117
  // Find the plugin's onload entry point.
118
  void* ptr = dlsym(this->handle_, "onload");
119
  if (ptr == NULL)
120
    {
121
      gold_error(_("%s: could not find onload entry point"),
122
                 this->filename_.c_str());
123
      return;
124
    }
125
  ld_plugin_onload onload;
126
  gold_assert(sizeof(onload) == sizeof(ptr));
127
  memcpy(&onload, &ptr, sizeof(ptr));
128
 
129
  // Get the linker's version number.
130
  const char* ver = get_version_string();
131
  int major = 0;
132
  int minor = 0;
133
  sscanf(ver, "%d.%d", &major, &minor);
134
 
135
  // Allocate and populate a transfer vector.
136
  const int tv_fixed_size = 17;
137
  int tv_size = this->args_.size() + tv_fixed_size;
138
  ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
139
 
140
  // Put LDPT_MESSAGE at the front of the list so the plugin can use it
141
  // while processing subsequent entries.
142
  int i = 0;
143
  tv[i].tv_tag = LDPT_MESSAGE;
144
  tv[i].tv_u.tv_message = message;
145
 
146
  ++i;
147
  tv[i].tv_tag = LDPT_API_VERSION;
148
  tv[i].tv_u.tv_val = LD_PLUGIN_API_VERSION;
149
 
150
  ++i;
151
  tv[i].tv_tag = LDPT_GOLD_VERSION;
152
  tv[i].tv_u.tv_val = major * 100 + minor;
153
 
154
  ++i;
155
  tv[i].tv_tag = LDPT_LINKER_OUTPUT;
156
  if (parameters->options().relocatable())
157
    tv[i].tv_u.tv_val = LDPO_REL;
158
  else if (parameters->options().shared())
159
    tv[i].tv_u.tv_val = LDPO_DYN;
160
  else
161
    tv[i].tv_u.tv_val = LDPO_EXEC;
162
 
163
  ++i;
164
  tv[i].tv_tag = LDPT_OUTPUT_NAME;
165
  tv[i].tv_u.tv_string = parameters->options().output();
166
 
167
  for (unsigned int j = 0; j < this->args_.size(); ++j)
168
    {
169
      ++i;
170
      tv[i].tv_tag = LDPT_OPTION;
171
      tv[i].tv_u.tv_string = this->args_[j].c_str();
172
    }
173
 
174
  ++i;
175
  tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
176
  tv[i].tv_u.tv_register_claim_file = register_claim_file;
177
 
178
  ++i;
179
  tv[i].tv_tag = LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK;
180
  tv[i].tv_u.tv_register_all_symbols_read = register_all_symbols_read;
181
 
182
  ++i;
183
  tv[i].tv_tag = LDPT_REGISTER_CLEANUP_HOOK;
184
  tv[i].tv_u.tv_register_cleanup = register_cleanup;
185
 
186
  ++i;
187
  tv[i].tv_tag = LDPT_ADD_SYMBOLS;
188
  tv[i].tv_u.tv_add_symbols = add_symbols;
189
 
190
  ++i;
191
  tv[i].tv_tag = LDPT_GET_INPUT_FILE;
192
  tv[i].tv_u.tv_get_input_file = get_input_file;
193
 
194
  ++i;
195
  tv[i].tv_tag = LDPT_GET_VIEW;
196
  tv[i].tv_u.tv_get_view = get_view;
197
 
198
  ++i;
199
  tv[i].tv_tag = LDPT_RELEASE_INPUT_FILE;
200
  tv[i].tv_u.tv_release_input_file = release_input_file;
201
 
202
  ++i;
203
  tv[i].tv_tag = LDPT_GET_SYMBOLS;
204
  tv[i].tv_u.tv_get_symbols = get_symbols;
205
 
206
  ++i;
207
  tv[i].tv_tag = LDPT_ADD_INPUT_FILE;
208
  tv[i].tv_u.tv_add_input_file = add_input_file;
209
 
210
  ++i;
211
  tv[i].tv_tag = LDPT_ADD_INPUT_LIBRARY;
212
  tv[i].tv_u.tv_add_input_library = add_input_library;
213
 
214
  ++i;
215
  tv[i].tv_tag = LDPT_SET_EXTRA_LIBRARY_PATH;
216
  tv[i].tv_u.tv_set_extra_library_path = set_extra_library_path;
217
 
218
  ++i;
219
  tv[i].tv_tag = LDPT_NULL;
220
  tv[i].tv_u.tv_val = 0;
221
 
222
  gold_assert(i == tv_size - 1);
223
 
224
  // Call the onload entry point.
225
  (*onload)(tv);
226
 
227
  delete[] tv;
228
#endif // ENABLE_PLUGINS
229
}
230
 
231
// Call the plugin claim-file handler.
232
 
233
inline bool
234
Plugin::claim_file(struct ld_plugin_input_file* plugin_input_file)
235
{
236
  int claimed = 0;
237
 
238
  if (this->claim_file_handler_ != NULL)
239
    {
240
      (*this->claim_file_handler_)(plugin_input_file, &claimed);
241
      if (claimed)
242
        return true;
243
    }
244
  return false;
245
}
246
 
247
// Call the all-symbols-read handler.
248
 
249
inline void
250
Plugin::all_symbols_read()
251
{
252
  if (this->all_symbols_read_handler_ != NULL)
253
    (*this->all_symbols_read_handler_)();
254
}
255
 
256
// Call the cleanup handler.
257
 
258
inline void
259
Plugin::cleanup()
260
{
261
  if (this->cleanup_handler_ != NULL && !this->cleanup_done_)
262
    {
263
      // Set this flag before calling to prevent a recursive plunge
264
      // in the event that a plugin's cleanup handler issues a
265
      // fatal error.
266
      this->cleanup_done_ = true;
267
      (*this->cleanup_handler_)();
268
    }
269
}
270
 
271
// This task is used to rescan archives as needed.
272
 
273
class Plugin_rescan : public Task
274
{
275
 public:
276
  Plugin_rescan(Task_token* this_blocker, Task_token* next_blocker)
277
    : this_blocker_(this_blocker), next_blocker_(next_blocker)
278
  { }
279
 
280
  ~Plugin_rescan()
281
  {
282
    delete this->this_blocker_;
283
  }
284
 
285
  Task_token*
286
  is_runnable()
287
  {
288
    if (this->this_blocker_->is_blocked())
289
      return this->this_blocker_;
290
    return NULL;
291
  }
292
 
293
  void
294
  locks(Task_locker* tl)
295
  { tl->add(this, this->next_blocker_); }
296
 
297
  void
298
  run(Workqueue*)
299
  { parameters->options().plugins()->rescan(this); }
300
 
301
  std::string
302
  get_name() const
303
  { return "Plugin_rescan"; }
304
 
305
 private:
306
  Task_token* this_blocker_;
307
  Task_token* next_blocker_;
308
};
309
 
310
// Plugin_manager methods.
311
 
312
Plugin_manager::~Plugin_manager()
313
{
314
  for (Plugin_list::iterator p = this->plugins_.begin();
315
       p != this->plugins_.end();
316
       ++p)
317
    delete *p;
318
  this->plugins_.clear();
319
  for (Object_list::iterator obj = this->objects_.begin();
320
       obj != this->objects_.end();
321
       ++obj)
322
    delete *obj;
323
  this->objects_.clear();
324
}
325
 
326
// Load all plugin libraries.
327
 
328
void
329
Plugin_manager::load_plugins()
330
{
331
  for (this->current_ = this->plugins_.begin();
332
       this->current_ != this->plugins_.end();
333
       ++this->current_)
334
    (*this->current_)->load();
335
}
336
 
337
// Call the plugin claim-file handlers in turn to see if any claim the file.
338
 
339
Pluginobj*
340
Plugin_manager::claim_file(Input_file* input_file, off_t offset,
341
                           off_t filesize)
342
{
343
  if (this->in_replacement_phase_)
344
    return NULL;
345
 
346
  unsigned int handle = this->objects_.size();
347
  this->input_file_ = input_file;
348
  this->plugin_input_file_.name = input_file->filename().c_str();
349
  this->plugin_input_file_.fd = input_file->file().descriptor();
350
  this->plugin_input_file_.offset = offset;
351
  this->plugin_input_file_.filesize = filesize;
352
  this->plugin_input_file_.handle = reinterpret_cast<void*>(handle);
353
 
354
  for (this->current_ = this->plugins_.begin();
355
       this->current_ != this->plugins_.end();
356
       ++this->current_)
357
    {
358
      if ((*this->current_)->claim_file(&this->plugin_input_file_))
359
        {
360
          this->any_claimed_ = true;
361
 
362
          if (this->objects_.size() > handle)
363
            return this->objects_[handle];
364
 
365
          // If the plugin claimed the file but did not call the
366
          // add_symbols callback, we need to create the Pluginobj now.
367
          Pluginobj* obj = this->make_plugin_object(handle);
368
          return obj;
369
        }
370
    }
371
 
372
  return NULL;
373
}
374
 
375
// Save an archive.  This is used so that a plugin can add a file
376
// which refers to a symbol which was not previously referenced.  In
377
// that case we want to pretend that the symbol was referenced before,
378
// and pull in the archive object.
379
 
380
void
381
Plugin_manager::save_archive(Archive* archive)
382
{
383
  if (this->in_replacement_phase_ || !this->any_claimed_)
384
    delete archive;
385
  else
386
    this->rescannable_.push_back(Rescannable(archive));
387
}
388
 
389
// Save an Input_group.  This is like save_archive.
390
 
391
void
392
Plugin_manager::save_input_group(Input_group* input_group)
393
{
394
  if (this->in_replacement_phase_ || !this->any_claimed_)
395
    delete input_group;
396
  else
397
    this->rescannable_.push_back(Rescannable(input_group));
398
}
399
 
400
// Call the all-symbols-read handlers.
401
 
402
void
403
Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
404
                                 Input_objects* input_objects,
405
                                 Symbol_table* symtab, Layout* layout,
406
                                 Dirsearch* dirpath, Mapfile* mapfile,
407
                                 Task_token** last_blocker)
408
{
409
  this->in_replacement_phase_ = true;
410
  this->workqueue_ = workqueue;
411
  this->task_ = task;
412
  this->input_objects_ = input_objects;
413
  this->symtab_ = symtab;
414
  this->layout_ = layout;
415
  this->dirpath_ = dirpath;
416
  this->mapfile_ = mapfile;
417
  this->this_blocker_ = NULL;
418
 
419
  for (this->current_ = this->plugins_.begin();
420
       this->current_ != this->plugins_.end();
421
       ++this->current_)
422
    (*this->current_)->all_symbols_read();
423
 
424
  if (this->any_added_)
425
    {
426
      Task_token* next_blocker = new Task_token(true);
427
      next_blocker->add_blocker();
428
      workqueue->queue(new Plugin_rescan(this->this_blocker_, next_blocker));
429
      this->this_blocker_ = next_blocker;
430
    }
431
 
432
  *last_blocker = this->this_blocker_;
433
}
434
 
435
// This is called when we see a new undefined symbol.  If we are in
436
// the replacement phase, this means that we may need to rescan some
437
// archives we have previously seen.
438
 
439
void
440
Plugin_manager::new_undefined_symbol(Symbol* sym)
441
{
442
  if (this->in_replacement_phase_)
443
    this->undefined_symbols_.push_back(sym);
444
}
445
 
446
// Rescan archives as needed.  This handles the case where a new
447
// object file added by a plugin has an undefined reference to some
448
// symbol defined in an archive.
449
 
450
void
451
Plugin_manager::rescan(Task* task)
452
{
453
  size_t rescan_pos = 0;
454
  size_t rescan_size = this->rescannable_.size();
455
  while (!this->undefined_symbols_.empty())
456
    {
457
      if (rescan_pos >= rescan_size)
458
        {
459
          this->undefined_symbols_.clear();
460
          return;
461
        }
462
 
463
      Undefined_symbol_list undefs;
464
      undefs.reserve(this->undefined_symbols_.size());
465
      this->undefined_symbols_.swap(undefs);
466
 
467
      size_t min_rescan_pos = rescan_size;
468
 
469
      for (Undefined_symbol_list::const_iterator p = undefs.begin();
470
           p != undefs.end();
471
           ++p)
472
        {
473
          if (!(*p)->is_undefined())
474
            continue;
475
 
476
          this->undefined_symbols_.push_back(*p);
477
 
478
          // Find the first rescan archive which defines this symbol,
479
          // starting at the current rescan position.  The rescan position
480
          // exists so that given -la -lb -lc we don't look for undefined
481
          // symbols in -lb back in -la, but instead get the definition
482
          // from -lc.  Don't bother to look past the current minimum
483
          // rescan position.
484
          for (size_t i = rescan_pos; i < min_rescan_pos; ++i)
485
            {
486
              if (this->rescannable_defines(i, *p))
487
                {
488
                  min_rescan_pos = i;
489
                  break;
490
                }
491
            }
492
        }
493
 
494
      if (min_rescan_pos >= rescan_size)
495
        {
496
          // We didn't find any rescannable archives which define any
497
          // undefined symbols.
498
          return;
499
        }
500
 
501
      const Rescannable& r(this->rescannable_[min_rescan_pos]);
502
      if (r.is_archive)
503
        {
504
          Task_lock_obj<Archive> tl(task, r.u.archive);
505
          r.u.archive->add_symbols(this->symtab_, this->layout_,
506
                                   this->input_objects_, this->mapfile_);
507
        }
508
      else
509
        {
510
          size_t next_saw_undefined = this->symtab_->saw_undefined();
511
          size_t saw_undefined;
512
          do
513
            {
514
              saw_undefined = next_saw_undefined;
515
 
516
              for (Input_group::const_iterator p = r.u.input_group->begin();
517
                   p != r.u.input_group->end();
518
                   ++p)
519
                {
520
                  Task_lock_obj<Archive> tl(task, *p);
521
 
522
                  (*p)->add_symbols(this->symtab_, this->layout_,
523
                                    this->input_objects_, this->mapfile_);
524
                }
525
 
526
              next_saw_undefined = this->symtab_->saw_undefined();
527
            }
528
          while (saw_undefined != next_saw_undefined);
529
        }
530
 
531
      for (size_t i = rescan_pos; i < min_rescan_pos + 1; ++i)
532
        {
533
          if (this->rescannable_[i].is_archive)
534
            delete this->rescannable_[i].u.archive;
535
          else
536
            delete this->rescannable_[i].u.input_group;
537
        }
538
 
539
      rescan_pos = min_rescan_pos + 1;
540
    }
541
}
542
 
543
// Return whether the rescannable at index I defines SYM.
544
 
545
bool
546
Plugin_manager::rescannable_defines(size_t i, Symbol* sym)
547
{
548
  const Rescannable& r(this->rescannable_[i]);
549
  if (r.is_archive)
550
    return r.u.archive->defines_symbol(sym);
551
  else
552
    {
553
      for (Input_group::const_iterator p = r.u.input_group->begin();
554
           p != r.u.input_group->end();
555
           ++p)
556
        {
557
          if ((*p)->defines_symbol(sym))
558
            return true;
559
        }
560
      return false;
561
    }
562
}
563
 
564
// Layout deferred objects.
565
 
566
void
567
Plugin_manager::layout_deferred_objects()
568
{
569
  Deferred_layout_list::iterator obj;
570
 
571
  for (obj = this->deferred_layout_objects_.begin();
572
       obj != this->deferred_layout_objects_.end();
573
       ++obj)
574
    {
575
      // Lock the object so we can read from it.  This is only called
576
      // single-threaded from queue_middle_tasks, so it is OK to lock.
577
      // Unfortunately we have no way to pass in a Task token.
578
      const Task* dummy_task = reinterpret_cast<const Task*>(-1);
579
      Task_lock_obj<Object> tl(dummy_task, *obj);
580
      (*obj)->layout_deferred_sections(this->layout_);
581
    }
582
}
583
 
584
// Call the cleanup handlers.
585
 
586
void
587
Plugin_manager::cleanup()
588
{
589
  for (this->current_ = this->plugins_.begin();
590
       this->current_ != this->plugins_.end();
591
       ++this->current_)
592
    (*this->current_)->cleanup();
593
}
594
 
595
// Make a new Pluginobj object.  This is called when the plugin calls
596
// the add_symbols API.
597
 
598
Pluginobj*
599
Plugin_manager::make_plugin_object(unsigned int handle)
600
{
601
  // Make sure we aren't asked to make an object for the same handle twice.
602
  if (this->objects_.size() != handle)
603
    return NULL;
604
 
605
  Pluginobj* obj = make_sized_plugin_object(this->input_file_,
606
                                            this->plugin_input_file_.offset,
607
                                            this->plugin_input_file_.filesize);
608
  this->objects_.push_back(obj);
609
  return obj;
610
}
611
 
612
// Get the input file information with an open (possibly re-opened)
613
// file descriptor.
614
 
615
ld_plugin_status
616
Plugin_manager::get_input_file(unsigned int handle,
617
                               struct ld_plugin_input_file* file)
618
{
619
  Pluginobj* obj = this->object(handle);
620
  if (obj == NULL)
621
    return LDPS_BAD_HANDLE;
622
 
623
  obj->lock(this->task_);
624
  file->name = obj->filename().c_str();
625
  file->fd = obj->descriptor();
626
  file->offset = obj->offset();
627
  file->filesize = obj->filesize();
628
  file->handle = reinterpret_cast<void*>(handle);
629
  return LDPS_OK;
630
}
631
 
632
// Release the input file.
633
 
634
ld_plugin_status
635
Plugin_manager::release_input_file(unsigned int handle)
636
{
637
  Pluginobj* obj = this->object(handle);
638
  if (obj == NULL)
639
    return LDPS_BAD_HANDLE;
640
 
641
  obj->unlock(this->task_);
642
  return LDPS_OK;
643
}
644
 
645
ld_plugin_status
646
Plugin_manager::get_view(unsigned int handle, const void **viewp)
647
{
648
  off_t offset;
649
  size_t filesize;
650
  Input_file *input_file;
651
  if (this->objects_.size() == handle)
652
    {
653
      // We are being called from the claim_file hook.
654
      const struct ld_plugin_input_file &f = this->plugin_input_file_;
655
      offset = f.offset;
656
      filesize = f.filesize;
657
      input_file = this->input_file_;
658
    }
659
  else
660
    {
661
      // An already claimed file.
662
      Pluginobj* obj = this->object(handle);
663
      if (obj == NULL)
664
        return LDPS_BAD_HANDLE;
665
      offset = obj->offset();
666
      filesize = obj->filesize();
667
      input_file = obj->input_file();
668
    }
669
  *viewp = (void*) input_file->file().get_view(offset, 0, filesize, false,
670
                                               false);
671
  return LDPS_OK;
672
}
673
 
674
// Add a new library path.
675
 
676
ld_plugin_status
677
Plugin_manager::set_extra_library_path(const char* path)
678
{
679
  this->extra_search_path_ = std::string(path);
680
  return LDPS_OK;
681
}
682
 
683
// Add a new input file.
684
 
685
ld_plugin_status
686
Plugin_manager::add_input_file(const char* pathname, bool is_lib)
687
{
688
  Input_file_argument file(pathname,
689
                           (is_lib
690
                            ? Input_file_argument::INPUT_FILE_TYPE_LIBRARY
691
                            : Input_file_argument::INPUT_FILE_TYPE_FILE),
692
                           (is_lib
693
                            ? this->extra_search_path_.c_str()
694
                            : ""),
695
                           false,
696
                           this->options_);
697
  Input_argument* input_argument = new Input_argument(file);
698
  Task_token* next_blocker = new Task_token(true);
699
  next_blocker->add_blocker();
700
  if (parameters->incremental())
701
    gold_error(_("input files added by plug-ins in --incremental mode not "
702
                 "supported yet"));
703
  this->workqueue_->queue_soon(new Read_symbols(this->input_objects_,
704
                                                this->symtab_,
705
                                                this->layout_,
706
                                                this->dirpath_,
707
                                                0,
708
                                                this->mapfile_,
709
                                                input_argument,
710
                                                NULL,
711
                                                NULL,
712
                                                this->this_blocker_,
713
                                                next_blocker));
714
  this->this_blocker_ = next_blocker;
715
  this->any_added_ = true;
716
  return LDPS_OK;
717
}
718
 
719
// Class Pluginobj.
720
 
721
Pluginobj::Pluginobj(const std::string& name, Input_file* input_file,
722
                     off_t offset, off_t filesize)
723
  : Object(name, input_file, false, offset),
724
    nsyms_(0), syms_(NULL), symbols_(), filesize_(filesize), comdat_map_()
725
{
726
}
727
 
728
// Return TRUE if a defined symbol might be reachable from outside the
729
// universe of claimed objects.
730
 
731
static inline bool
732
is_visible_from_outside(Symbol* lsym)
733
{
734
  if (lsym->in_real_elf())
735
    return true;
736
  if (parameters->options().relocatable())
737
    return true;
738
  if (parameters->options().is_undefined(lsym->name()))
739
    return true;
740
  if (parameters->options().export_dynamic() || parameters->options().shared())
741
    return lsym->is_externally_visible();
742
  return false;
743
}
744
 
745
// Get symbol resolution info.
746
 
747
ld_plugin_status
748
Pluginobj::get_symbol_resolution_info(int nsyms, ld_plugin_symbol* syms) const
749
{
750
  if (nsyms > this->nsyms_)
751
    return LDPS_NO_SYMS;
752
 
753
  if (static_cast<size_t>(nsyms) > this->symbols_.size())
754
    {
755
      // We never decided to include this object. We mark all symbols as
756
      // preempted.
757
      gold_assert(this->symbols_.size() == 0);
758
      for (int i = 0; i < nsyms; i++)
759
        syms[i].resolution = LDPR_PREEMPTED_REG;
760
      return LDPS_OK;
761
    }
762
 
763
  for (int i = 0; i < nsyms; i++)
764
    {
765
      ld_plugin_symbol* isym = &syms[i];
766
      Symbol* lsym = this->symbols_[i];
767
      ld_plugin_symbol_resolution res = LDPR_UNKNOWN;
768
 
769
      if (lsym->is_undefined())
770
        // The symbol remains undefined.
771
        res = LDPR_UNDEF;
772
      else if (isym->def == LDPK_UNDEF
773
               || isym->def == LDPK_WEAKUNDEF
774
               || isym->def == LDPK_COMMON)
775
        {
776
          // The original symbol was undefined or common.
777
          if (lsym->source() != Symbol::FROM_OBJECT)
778
            res = LDPR_RESOLVED_EXEC;
779
          else if (lsym->object()->pluginobj() == this)
780
            res = (is_visible_from_outside(lsym)
781
                   ? LDPR_PREVAILING_DEF
782
                   : LDPR_PREVAILING_DEF_IRONLY);
783
          else if (lsym->object()->pluginobj() != NULL)
784
            res = LDPR_RESOLVED_IR;
785
          else if (lsym->object()->is_dynamic())
786
            res = LDPR_RESOLVED_DYN;
787
          else
788
            res = LDPR_RESOLVED_EXEC;
789
        }
790
      else
791
        {
792
          // The original symbol was a definition.
793
          if (lsym->source() != Symbol::FROM_OBJECT)
794
            res = LDPR_PREEMPTED_REG;
795
          else if (lsym->object() == static_cast<const Object*>(this))
796
            res = (is_visible_from_outside(lsym)
797
                   ? LDPR_PREVAILING_DEF
798
                   : LDPR_PREVAILING_DEF_IRONLY);
799
          else
800
            res = (lsym->object()->pluginobj() != NULL
801
                   ? LDPR_PREEMPTED_IR
802
                   : LDPR_PREEMPTED_REG);
803
        }
804
      isym->resolution = res;
805
    }
806
  return LDPS_OK;
807
}
808
 
809
// Return TRUE if the comdat group with key COMDAT_KEY from this object
810
// should be kept.
811
 
812
bool
813
Pluginobj::include_comdat_group(std::string comdat_key, Layout* layout)
814
{
815
  std::pair<Comdat_map::iterator, bool> ins =
816
    this->comdat_map_.insert(std::make_pair(comdat_key, false));
817
 
818
  // If this is the first time we've seen this comdat key, ask the
819
  // layout object whether it should be included.
820
  if (ins.second)
821
    ins.first->second = layout->find_or_add_kept_section(comdat_key,
822
                                                         NULL, 0, true,
823
                                                         true, NULL);
824
 
825
  return ins.first->second;
826
}
827
 
828
// Class Sized_pluginobj.
829
 
830
template<int size, bool big_endian>
831
Sized_pluginobj<size, big_endian>::Sized_pluginobj(
832
    const std::string& name,
833
    Input_file* input_file,
834
    off_t offset,
835
    off_t filesize)
836
  : Pluginobj(name, input_file, offset, filesize)
837
{
838
}
839
 
840
// Read the symbols.  Not used for plugin objects.
841
 
842
template<int size, bool big_endian>
843
void
844
Sized_pluginobj<size, big_endian>::do_read_symbols(Read_symbols_data*)
845
{
846
  gold_unreachable();
847
}
848
 
849
// Lay out the input sections.  Not used for plugin objects.
850
 
851
template<int size, bool big_endian>
852
void
853
Sized_pluginobj<size, big_endian>::do_layout(Symbol_table*, Layout*,
854
                                             Read_symbols_data*)
855
{
856
  gold_unreachable();
857
}
858
 
859
// Add the symbols to the symbol table.
860
 
861
template<int size, bool big_endian>
862
void
863
Sized_pluginobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
864
                                                  Read_symbols_data*,
865
                                                  Layout* layout)
866
{
867
  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
868
  unsigned char symbuf[sym_size];
869
  elfcpp::Sym<size, big_endian> sym(symbuf);
870
  elfcpp::Sym_write<size, big_endian> osym(symbuf);
871
 
872
  typedef typename elfcpp::Elf_types<size>::Elf_WXword Elf_size_type;
873
 
874
  this->symbols_.resize(this->nsyms_);
875
 
876
  for (int i = 0; i < this->nsyms_; ++i)
877
    {
878
      const struct ld_plugin_symbol* isym = &this->syms_[i];
879
      const char* name = isym->name;
880
      const char* ver = isym->version;
881
      elfcpp::Elf_Half shndx;
882
      elfcpp::STB bind;
883
      elfcpp::STV vis;
884
 
885
      if (name != NULL && name[0] == '\0')
886
        name = NULL;
887
      if (ver != NULL && ver[0] == '\0')
888
        ver = NULL;
889
 
890
      switch (isym->def)
891
        {
892
        case LDPK_WEAKDEF:
893
        case LDPK_WEAKUNDEF:
894
          bind = elfcpp::STB_WEAK;
895
          break;
896
        case LDPK_DEF:
897
        case LDPK_UNDEF:
898
        case LDPK_COMMON:
899
        default:
900
          bind = elfcpp::STB_GLOBAL;
901
          break;
902
        }
903
 
904
      switch (isym->def)
905
        {
906
        case LDPK_DEF:
907
        case LDPK_WEAKDEF:
908
          shndx = elfcpp::SHN_ABS;
909
          break;
910
        case LDPK_COMMON:
911
          shndx = elfcpp::SHN_COMMON;
912
          break;
913
        case LDPK_UNDEF:
914
        case LDPK_WEAKUNDEF:
915
        default:
916
          shndx = elfcpp::SHN_UNDEF;
917
          break;
918
        }
919
 
920
      switch (isym->visibility)
921
        {
922
        case LDPV_PROTECTED:
923
          vis = elfcpp::STV_PROTECTED;
924
          break;
925
        case LDPV_INTERNAL:
926
          vis = elfcpp::STV_INTERNAL;
927
          break;
928
        case LDPV_HIDDEN:
929
          vis = elfcpp::STV_HIDDEN;
930
          break;
931
        case LDPV_DEFAULT:
932
        default:
933
          vis = elfcpp::STV_DEFAULT;
934
          break;
935
        }
936
 
937
      if (isym->comdat_key != NULL
938
          && isym->comdat_key[0] != '\0'
939
          && !this->include_comdat_group(isym->comdat_key, layout))
940
        shndx = elfcpp::SHN_UNDEF;
941
 
942
      osym.put_st_name(0);
943
      osym.put_st_value(0);
944
      osym.put_st_size(static_cast<Elf_size_type>(isym->size));
945
      osym.put_st_info(bind, elfcpp::STT_NOTYPE);
946
      osym.put_st_other(vis, 0);
947
      osym.put_st_shndx(shndx);
948
 
949
      this->symbols_[i] =
950
        symtab->add_from_pluginobj<size, big_endian>(this, name, ver, &sym);
951
    }
952
}
953
 
954
template<int size, bool big_endian>
955
Archive::Should_include
956
Sized_pluginobj<size, big_endian>::do_should_include_member(
957
    Symbol_table* symtab,
958
    Layout* layout,
959
    Read_symbols_data*,
960
    std::string* why)
961
{
962
  char* tmpbuf = NULL;
963
  size_t tmpbuflen = 0;
964
 
965
  for (int i = 0; i < this->nsyms_; ++i)
966
    {
967
      const struct ld_plugin_symbol& sym = this->syms_[i];
968
      const char* name = sym.name;
969
      Symbol* symbol;
970
      Archive::Should_include t = Archive::should_include_member(symtab,
971
                                                                 layout,
972
                                                                 name,
973
                                                                 &symbol, why,
974
                                                                 &tmpbuf,
975
                                                                 &tmpbuflen);
976
      if (t == Archive::SHOULD_INCLUDE_YES)
977
        {
978
          if (tmpbuf != NULL)
979
            free(tmpbuf);
980
          return t;
981
        }
982
    }
983
  if (tmpbuf != NULL)
984
    free(tmpbuf);
985
  return Archive::SHOULD_INCLUDE_UNKNOWN;
986
}
987
 
988
// Iterate over global symbols, calling a visitor class V for each.
989
 
990
template<int size, bool big_endian>
991
void
992
Sized_pluginobj<size, big_endian>::do_for_all_global_symbols(
993
    Read_symbols_data*,
994
    Library_base::Symbol_visitor_base* v)
995
{
996
  for (int i = 0; i < this->nsyms_; ++i)
997
    {
998
      const struct ld_plugin_symbol& sym = this->syms_[i];
999
      if (sym.def != LDPK_UNDEF)
1000
        v->visit(sym.name);
1001
    }
1002
}
1003
 
1004
// Iterate over local symbols, calling a visitor class V for each GOT offset
1005
// associated with a local symbol.
1006
template<int size, bool big_endian>
1007
void
1008
Sized_pluginobj<size, big_endian>::do_for_all_local_got_entries(
1009
    Got_offset_list::Visitor*) const
1010
{
1011
  gold_unreachable();
1012
}
1013
 
1014
// Get the size of a section.  Not used for plugin objects.
1015
 
1016
template<int size, bool big_endian>
1017
uint64_t
1018
Sized_pluginobj<size, big_endian>::do_section_size(unsigned int)
1019
{
1020
  gold_unreachable();
1021
  return 0;
1022
}
1023
 
1024
// Get the name of a section.  Not used for plugin objects.
1025
 
1026
template<int size, bool big_endian>
1027
std::string
1028
Sized_pluginobj<size, big_endian>::do_section_name(unsigned int)
1029
{
1030
  gold_unreachable();
1031
  return std::string();
1032
}
1033
 
1034
// Return a view of the contents of a section.  Not used for plugin objects.
1035
 
1036
template<int size, bool big_endian>
1037
Object::Location
1038
Sized_pluginobj<size, big_endian>::do_section_contents(unsigned int)
1039
{
1040
  Location loc(0, 0);
1041
 
1042
  gold_unreachable();
1043
  return loc;
1044
}
1045
 
1046
// Return section flags.  Not used for plugin objects.
1047
 
1048
template<int size, bool big_endian>
1049
uint64_t
1050
Sized_pluginobj<size, big_endian>::do_section_flags(unsigned int)
1051
{
1052
  gold_unreachable();
1053
  return 0;
1054
}
1055
 
1056
// Return section entsize.  Not used for plugin objects.
1057
 
1058
template<int size, bool big_endian>
1059
uint64_t
1060
Sized_pluginobj<size, big_endian>::do_section_entsize(unsigned int)
1061
{
1062
  gold_unreachable();
1063
  return 0;
1064
}
1065
 
1066
// Return section address.  Not used for plugin objects.
1067
 
1068
template<int size, bool big_endian>
1069
uint64_t
1070
Sized_pluginobj<size, big_endian>::do_section_address(unsigned int)
1071
{
1072
  gold_unreachable();
1073
  return 0;
1074
}
1075
 
1076
// Return section type.  Not used for plugin objects.
1077
 
1078
template<int size, bool big_endian>
1079
unsigned int
1080
Sized_pluginobj<size, big_endian>::do_section_type(unsigned int)
1081
{
1082
  gold_unreachable();
1083
  return 0;
1084
}
1085
 
1086
// Return the section link field.  Not used for plugin objects.
1087
 
1088
template<int size, bool big_endian>
1089
unsigned int
1090
Sized_pluginobj<size, big_endian>::do_section_link(unsigned int)
1091
{
1092
  gold_unreachable();
1093
  return 0;
1094
}
1095
 
1096
// Return the section link field.  Not used for plugin objects.
1097
 
1098
template<int size, bool big_endian>
1099
unsigned int
1100
Sized_pluginobj<size, big_endian>::do_section_info(unsigned int)
1101
{
1102
  gold_unreachable();
1103
  return 0;
1104
}
1105
 
1106
// Return the section alignment.  Not used for plugin objects.
1107
 
1108
template<int size, bool big_endian>
1109
uint64_t
1110
Sized_pluginobj<size, big_endian>::do_section_addralign(unsigned int)
1111
{
1112
  gold_unreachable();
1113
  return 0;
1114
}
1115
 
1116
// Return the Xindex structure to use.  Not used for plugin objects.
1117
 
1118
template<int size, bool big_endian>
1119
Xindex*
1120
Sized_pluginobj<size, big_endian>::do_initialize_xindex()
1121
{
1122
  gold_unreachable();
1123
  return NULL;
1124
}
1125
 
1126
// Get symbol counts.  Not used for plugin objects.
1127
 
1128
template<int size, bool big_endian>
1129
void
1130
Sized_pluginobj<size, big_endian>::do_get_global_symbol_counts(const Symbol_table*,
1131
                                                   size_t*, size_t*) const
1132
{
1133
  gold_unreachable();
1134
}
1135
 
1136
// Get symbols.  Not used for plugin objects.
1137
 
1138
template<int size, bool big_endian>
1139
const Object::Symbols*
1140
Sized_pluginobj<size, big_endian>::do_get_global_symbols() const
1141
{
1142
  gold_unreachable();
1143
}
1144
 
1145
// Class Plugin_finish.  This task runs after all replacement files have
1146
// been added.  For now, it's a placeholder for a possible plugin API
1147
// to allow the plugin to release most of its resources.  The cleanup
1148
// handlers must be called later, because they can remove the temporary
1149
// object files that are needed until the end of the link.
1150
 
1151
class Plugin_finish : public Task
1152
{
1153
 public:
1154
  Plugin_finish(Task_token* this_blocker, Task_token* next_blocker)
1155
    : this_blocker_(this_blocker), next_blocker_(next_blocker)
1156
  { }
1157
 
1158
  ~Plugin_finish()
1159
  {
1160
    if (this->this_blocker_ != NULL)
1161
      delete this->this_blocker_;
1162
  }
1163
 
1164
  Task_token*
1165
  is_runnable()
1166
  {
1167
    if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
1168
      return this->this_blocker_;
1169
    return NULL;
1170
  }
1171
 
1172
  void
1173
  locks(Task_locker* tl)
1174
  { tl->add(this, this->next_blocker_); }
1175
 
1176
  void
1177
  run(Workqueue*)
1178
  {
1179
    // We could call early cleanup handlers here.
1180
  }
1181
 
1182
  std::string
1183
  get_name() const
1184
  { return "Plugin_finish"; }
1185
 
1186
 private:
1187
  Task_token* this_blocker_;
1188
  Task_token* next_blocker_;
1189
};
1190
 
1191
// Class Plugin_hook.
1192
 
1193
Plugin_hook::~Plugin_hook()
1194
{
1195
}
1196
 
1197
// Return whether a Plugin_hook task is runnable.
1198
 
1199
Task_token*
1200
Plugin_hook::is_runnable()
1201
{
1202
  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
1203
    return this->this_blocker_;
1204
  return NULL;
1205
}
1206
 
1207
// Return a Task_locker for a Plugin_hook task.  We don't need any
1208
// locks here.
1209
 
1210
void
1211
Plugin_hook::locks(Task_locker*)
1212
{
1213
}
1214
 
1215
// Run the "all symbols read" plugin hook.
1216
 
1217
void
1218
Plugin_hook::run(Workqueue* workqueue)
1219
{
1220
  gold_assert(this->options_.has_plugins());
1221
  Symbol* start_sym = this->symtab_->lookup(parameters->entry());
1222
  if (start_sym != NULL)
1223
    start_sym->set_in_real_elf();
1224
 
1225
  this->options_.plugins()->all_symbols_read(workqueue,
1226
                                             this,
1227
                                             this->input_objects_,
1228
                                             this->symtab_,
1229
                                             this->layout_,
1230
                                             this->dirpath_,
1231
                                             this->mapfile_,
1232
                                             &this->this_blocker_);
1233
  workqueue->queue_soon(new Plugin_finish(this->this_blocker_,
1234
                                          this->next_blocker_));
1235
}
1236
 
1237
// The C interface routines called by the plugins.
1238
 
1239
#ifdef ENABLE_PLUGINS
1240
 
1241
// Register a claim-file handler.
1242
 
1243
static enum ld_plugin_status
1244
register_claim_file(ld_plugin_claim_file_handler handler)
1245
{
1246
  gold_assert(parameters->options().has_plugins());
1247
  parameters->options().plugins()->set_claim_file_handler(handler);
1248
  return LDPS_OK;
1249
}
1250
 
1251
// Register an all-symbols-read handler.
1252
 
1253
static enum ld_plugin_status
1254
register_all_symbols_read(ld_plugin_all_symbols_read_handler handler)
1255
{
1256
  gold_assert(parameters->options().has_plugins());
1257
  parameters->options().plugins()->set_all_symbols_read_handler(handler);
1258
  return LDPS_OK;
1259
}
1260
 
1261
// Register a cleanup handler.
1262
 
1263
static enum ld_plugin_status
1264
register_cleanup(ld_plugin_cleanup_handler handler)
1265
{
1266
  gold_assert(parameters->options().has_plugins());
1267
  parameters->options().plugins()->set_cleanup_handler(handler);
1268
  return LDPS_OK;
1269
}
1270
 
1271
// Add symbols from a plugin-claimed input file.
1272
 
1273
static enum ld_plugin_status
1274
add_symbols(void* handle, int nsyms, const ld_plugin_symbol* syms)
1275
{
1276
  gold_assert(parameters->options().has_plugins());
1277
  Pluginobj* obj = parameters->options().plugins()->make_plugin_object(
1278
      static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
1279
  if (obj == NULL)
1280
    return LDPS_ERR;
1281
  obj->store_incoming_symbols(nsyms, syms);
1282
  return LDPS_OK;
1283
}
1284
 
1285
// Get the input file information with an open (possibly re-opened)
1286
// file descriptor.
1287
 
1288
static enum ld_plugin_status
1289
get_input_file(const void* handle, struct ld_plugin_input_file* file)
1290
{
1291
  gold_assert(parameters->options().has_plugins());
1292
  unsigned int obj_index =
1293
      static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
1294
  return parameters->options().plugins()->get_input_file(obj_index, file);
1295
}
1296
 
1297
// Release the input file.
1298
 
1299
static enum ld_plugin_status
1300
release_input_file(const void* handle)
1301
{
1302
  gold_assert(parameters->options().has_plugins());
1303
  unsigned int obj_index =
1304
      static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
1305
  return parameters->options().plugins()->release_input_file(obj_index);
1306
}
1307
 
1308
static enum ld_plugin_status
1309
get_view(const void *handle, const void **viewp)
1310
{
1311
  gold_assert(parameters->options().has_plugins());
1312
  unsigned int obj_index =
1313
      static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
1314
  return parameters->options().plugins()->get_view(obj_index, viewp);
1315
}
1316
 
1317
// Get the symbol resolution info for a plugin-claimed input file.
1318
 
1319
static enum ld_plugin_status
1320
get_symbols(const void* handle, int nsyms, ld_plugin_symbol* syms)
1321
{
1322
  gold_assert(parameters->options().has_plugins());
1323
  Pluginobj* obj = parameters->options().plugins()->object(
1324
      static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle)));
1325
  if (obj == NULL)
1326
    return LDPS_ERR;
1327
  return obj->get_symbol_resolution_info(nsyms, syms);
1328
}
1329
 
1330
// Add a new (real) input file generated by a plugin.
1331
 
1332
static enum ld_plugin_status
1333
add_input_file(const char* pathname)
1334
{
1335
  gold_assert(parameters->options().has_plugins());
1336
  return parameters->options().plugins()->add_input_file(pathname, false);
1337
}
1338
 
1339
// Add a new (real) library required by a plugin.
1340
 
1341
static enum ld_plugin_status
1342
add_input_library(const char* pathname)
1343
{
1344
  gold_assert(parameters->options().has_plugins());
1345
  return parameters->options().plugins()->add_input_file(pathname, true);
1346
}
1347
 
1348
// Set the extra library path to be used by libraries added via
1349
// add_input_library
1350
 
1351
static enum ld_plugin_status
1352
set_extra_library_path(const char* path)
1353
{
1354
  gold_assert(parameters->options().has_plugins());
1355
  return parameters->options().plugins()->set_extra_library_path(path);
1356
}
1357
 
1358
// Issue a diagnostic message from a plugin.
1359
 
1360
static enum ld_plugin_status
1361
message(int level, const char* format, ...)
1362
{
1363
  va_list args;
1364
  va_start(args, format);
1365
 
1366
  switch (level)
1367
    {
1368
    case LDPL_INFO:
1369
      parameters->errors()->info(format, args);
1370
      break;
1371
    case LDPL_WARNING:
1372
      parameters->errors()->warning(format, args);
1373
      break;
1374
    case LDPL_ERROR:
1375
    default:
1376
      parameters->errors()->error(format, args);
1377
      break;
1378
    case LDPL_FATAL:
1379
      parameters->errors()->fatal(format, args);
1380
      break;
1381
    }
1382
 
1383
  va_end(args);
1384
  return LDPS_OK;
1385
}
1386
 
1387
#endif // ENABLE_PLUGINS
1388
 
1389
// Allocate a Pluginobj object of the appropriate size and endianness.
1390
 
1391
static Pluginobj*
1392
make_sized_plugin_object(Input_file* input_file, off_t offset, off_t filesize)
1393
{
1394
  Pluginobj* obj = NULL;
1395
 
1396
  parameters_force_valid_target();
1397
  const Target& target(parameters->target());
1398
 
1399
  if (target.get_size() == 32)
1400
    {
1401
      if (target.is_big_endian())
1402
#ifdef HAVE_TARGET_32_BIG
1403
        obj = new Sized_pluginobj<32, true>(input_file->filename(),
1404
                                            input_file, offset, filesize);
1405
#else
1406
        gold_error(_("%s: not configured to support "
1407
                     "32-bit big-endian object"),
1408
                   input_file->filename().c_str());
1409
#endif
1410
      else
1411
#ifdef HAVE_TARGET_32_LITTLE
1412
        obj = new Sized_pluginobj<32, false>(input_file->filename(),
1413
                                             input_file, offset, filesize);
1414
#else
1415
        gold_error(_("%s: not configured to support "
1416
                     "32-bit little-endian object"),
1417
                   input_file->filename().c_str());
1418
#endif
1419
    }
1420
  else if (target.get_size() == 64)
1421
    {
1422
      if (target.is_big_endian())
1423
#ifdef HAVE_TARGET_64_BIG
1424
        obj = new Sized_pluginobj<64, true>(input_file->filename(),
1425
                                            input_file, offset, filesize);
1426
#else
1427
        gold_error(_("%s: not configured to support "
1428
                     "64-bit big-endian object"),
1429
                   input_file->filename().c_str());
1430
#endif
1431
      else
1432
#ifdef HAVE_TARGET_64_LITTLE
1433
        obj = new Sized_pluginobj<64, false>(input_file->filename(),
1434
                                             input_file, offset, filesize);
1435
#else
1436
        gold_error(_("%s: not configured to support "
1437
                     "64-bit little-endian object"),
1438
                   input_file->filename().c_str());
1439
#endif
1440
    }
1441
 
1442
  gold_assert(obj != NULL);
1443
  return obj;
1444
}
1445
 
1446
} // End namespace gold.

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.