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 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
|
// plugin.h -- plugin manager for gold -*- C++ -*-
// Copyright (C) 2008-2018 Free Software Foundation, Inc.
// Written by Cary Coutant <ccoutant@google.com>.
// This file is part of gold.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
#ifndef GOLD_PLUGIN_H
#define GOLD_PLUGIN_H
#include <list>
#include <string>
#include "object.h"
#include "plugin-api.h"
#include "workqueue.h"
namespace gold
{
class General_options;
class Input_file;
class Input_objects;
class Archive;
class Input_group;
class Symbol;
class Symbol_table;
class Layout;
class Dirsearch;
class Mapfile;
class Task;
class Task_token;
class Pluginobj;
class Plugin_rescan;
class Plugin_recorder;
// This class represents a single plugin library.
class Plugin
{
public:
Plugin(const char* filename)
: handle_(NULL),
filename_(filename),
args_(),
claim_file_handler_(NULL),
all_symbols_read_handler_(NULL),
cleanup_handler_(NULL),
new_input_handler_(NULL),
cleanup_done_(false)
{ }
~Plugin()
{ }
// Load the library and call its entry point.
void
load();
// Call the claim-file handler.
bool
claim_file(struct ld_plugin_input_file* plugin_input_file);
// Call the all-symbols-read handler.
void
all_symbols_read();
// Call the new_input handler.
void
new_input(struct ld_plugin_input_file* plugin_input_file);
// Call the cleanup handler.
void
cleanup();
// Register a claim-file handler.
void
set_claim_file_handler(ld_plugin_claim_file_handler handler)
{ this->claim_file_handler_ = handler; }
// Register an all-symbols-read handler.
void
set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
{ this->all_symbols_read_handler_ = handler; }
// Register a claim-file handler.
void
set_cleanup_handler(ld_plugin_cleanup_handler handler)
{ this->cleanup_handler_ = handler; }
// Register a new_input handler.
void
set_new_input_handler(ld_plugin_new_input_handler handler)
{ this->new_input_handler_ = handler; }
// Add an argument
void
add_option(const char* arg)
{
this->args_.push_back(arg);
}
const std::string&
filename() const
{ return this->filename_; }
private:
Plugin(const Plugin&);
Plugin& operator=(const Plugin&);
// The shared library handle returned by dlopen.
void* handle_;
// The argument string given to --plugin.
std::string filename_;
// The list of argument string given to --plugin-opt.
std::vector<std::string> args_;
// The plugin's event handlers.
ld_plugin_claim_file_handler claim_file_handler_;
ld_plugin_all_symbols_read_handler all_symbols_read_handler_;
ld_plugin_cleanup_handler cleanup_handler_;
ld_plugin_new_input_handler new_input_handler_;
// TRUE if the cleanup handlers have been called.
bool cleanup_done_;
};
// A manager class for plugins.
class Plugin_manager
{
public:
Plugin_manager(const General_options& options)
: plugins_(), objects_(), deferred_layout_objects_(), input_file_(NULL),
plugin_input_file_(), rescannable_(), undefined_symbols_(),
any_claimed_(false), in_replacement_phase_(false), any_added_(false),
in_claim_file_handler_(false),
options_(options), workqueue_(NULL), task_(NULL), input_objects_(NULL),
symtab_(NULL), layout_(NULL), dirpath_(NULL), mapfile_(NULL),
this_blocker_(NULL), extra_search_path_(), lock_(NULL),
initialize_lock_(&lock_), defsym_defines_set_(),
recorder_(NULL)
{ this->current_ = plugins_.end(); }
~Plugin_manager();
// Returns true if the symbol name is used in the LHS of a defsym.
bool
is_defsym_def(const char* sym_name) const
{
return defsym_defines_set_.find(sym_name) != defsym_defines_set_.end();
}
// Add a plugin library.
void
add_plugin(const char* filename)
{ this->plugins_.push_back(new Plugin(filename)); }
// Add an argument to the current plugin.
void
add_plugin_option(const char* opt)
{
Plugin* last = this->plugins_.back();
last->add_option(opt);
}
// Load all plugin libraries.
void
load_plugins(Layout* layout);
// Call the plugin claim-file handlers in turn to see if any claim the file.
Pluginobj*
claim_file(Input_file* input_file, off_t offset, off_t filesize,
Object* elf_object);
// Get the object associated with the handle and check if it is an elf object.
// If it is not a Pluginobj, it is an elf object.
Object*
get_elf_object(const void* handle);
// True if the claim_file handler of the plugins is being called.
bool
in_claim_file_handler()
{ return in_claim_file_handler_; }
// Let the plugin manager save an archive for later rescanning.
// This takes ownership of the Archive pointer.
void
save_archive(Archive*);
// Let the plugin manager save an input group for later rescanning.
// This takes ownership of the Input_group pointer.
void
save_input_group(Input_group*);
// Call the all-symbols-read handlers.
void
all_symbols_read(Workqueue* workqueue, Task* task,
Input_objects* input_objects, Symbol_table* symtab,
Dirsearch* dirpath, Mapfile* mapfile,
Task_token** last_blocker);
// Tell the plugin manager that we've a new undefined symbol which
// may require rescanning.
void
new_undefined_symbol(Symbol*);
// Run deferred layout.
void
layout_deferred_objects();
// Call the cleanup handlers.
void
cleanup();
// Register a claim-file handler.
void
set_claim_file_handler(ld_plugin_claim_file_handler handler)
{
gold_assert(this->current_ != plugins_.end());
(*this->current_)->set_claim_file_handler(handler);
}
// Register an all-symbols-read handler.
void
set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
{
gold_assert(this->current_ != plugins_.end());
(*this->current_)->set_all_symbols_read_handler(handler);
}
// Register a new_input handler.
void
set_new_input_handler(ld_plugin_new_input_handler handler)
{
gold_assert(this->current_ != plugins_.end());
(*this->current_)->set_new_input_handler(handler);
}
// Register a claim-file handler.
void
set_cleanup_handler(ld_plugin_cleanup_handler handler)
{
gold_assert(this->current_ != plugins_.end());
(*this->current_)->set_cleanup_handler(handler);
}
// Make a new Pluginobj object. This is called when the plugin calls
// the add_symbols API.
Pluginobj*
make_plugin_object(unsigned int handle);
// Return the object associated with the given HANDLE.
Object*
object(unsigned int handle) const
{
if (handle >= this->objects_.size())
return NULL;
return this->objects_[handle];
}
// Return TRUE if any input files have been claimed by a plugin
// and we are still in the initial input phase.
bool
should_defer_layout() const
{ return this->any_claimed_ && !this->in_replacement_phase_; }
// Add a regular object to the deferred layout list. These are
// objects whose layout has been deferred until after the
// replacement files have arrived.
void
add_deferred_layout_object(Relobj* obj)
{ this->deferred_layout_objects_.push_back(obj); }
// Get input file information with an open (possibly re-opened)
// file descriptor.
ld_plugin_status
get_input_file(unsigned int handle, struct ld_plugin_input_file* file);
ld_plugin_status
get_view(unsigned int handle, const void **viewp);
// Release an input file.
ld_plugin_status
release_input_file(unsigned int handle);
// Add a new input file.
ld_plugin_status
add_input_file(const char* pathname, bool is_lib);
// Set the extra library path.
ld_plugin_status
set_extra_library_path(const char* path);
// Return TRUE if we are in the replacement phase.
bool
in_replacement_phase() const
{ return this->in_replacement_phase_; }
Input_objects*
input_objects() const
{ return this->input_objects_; }
Symbol_table*
symtab()
{ return this->symtab_; }
Layout*
layout()
{ return this->layout_; }
Plugin_recorder*
recorder() const
{ return this->recorder_; }
private:
Plugin_manager(const Plugin_manager&);
Plugin_manager& operator=(const Plugin_manager&);
// Plugin_rescan is a Task which calls the private rescan method.
friend class Plugin_rescan;
// An archive or input group which may have to be rescanned if a
// plugin adds a new file.
struct Rescannable
{
bool is_archive;
union
{
Archive* archive;
Input_group* input_group;
} u;
Rescannable(Archive* archive)
: is_archive(true)
{ this->u.archive = archive; }
Rescannable(Input_group* input_group)
: is_archive(false)
{ this->u.input_group = input_group; }
};
typedef std::list<Plugin*> Plugin_list;
typedef std::vector<Object*> Object_list;
typedef std::vector<Relobj*> Deferred_layout_list;
typedef std::vector<Rescannable> Rescannable_list;
typedef std::vector<Symbol*> Undefined_symbol_list;
// Rescan archives for undefined symbols.
void
rescan(Task*);
// See whether the rescannable at index I defines SYM.
bool
rescannable_defines(size_t i, Symbol* sym);
// The list of plugin libraries.
Plugin_list plugins_;
// A pointer to the current plugin. Used while loading plugins.
Plugin_list::iterator current_;
// The list of plugin objects. The index of an item in this list
// serves as the "handle" that we pass to the plugins.
Object_list objects_;
// The list of regular objects whose layout has been deferred.
Deferred_layout_list deferred_layout_objects_;
// The file currently up for claim by the plugins.
Input_file* input_file_;
struct ld_plugin_input_file plugin_input_file_;
// A list of archives and input groups being saved for possible
// later rescanning.
Rescannable_list rescannable_;
// A list of undefined symbols found in added files.
Undefined_symbol_list undefined_symbols_;
// Whether any input files have been claimed by a plugin.
bool any_claimed_;
// Set to true after the all symbols read event; indicates that we
// are processing replacement files whose symbols should replace the
// placeholder symbols from the Pluginobj objects.
bool in_replacement_phase_;
// Whether any input files or libraries were added by a plugin.
bool any_added_;
// Set to true when the claim_file handler of a plugin is called.
bool in_claim_file_handler_;
const General_options& options_;
Workqueue* workqueue_;
Task* task_;
Input_objects* input_objects_;
Symbol_table* symtab_;
Layout* layout_;
Dirsearch* dirpath_;
Mapfile* mapfile_;
Task_token* this_blocker_;
// An extra directory to search for the libraries passed by
// add_input_library.
std::string extra_search_path_;
Lock* lock_;
Initialize_lock initialize_lock_;
// Keep track of all symbols defined by defsym.
typedef Unordered_set<std::string> Defsym_defines_set;
Defsym_defines_set defsym_defines_set_;
// Class to record plugin actions.
Plugin_recorder* recorder_;
};
// An object file claimed by a plugin. This is an abstract base class.
// The implementation is the template class Sized_pluginobj.
class Pluginobj : public Object
{
public:
typedef std::vector<Symbol*> Symbols;
Pluginobj(const std::string& name, Input_file* input_file, off_t offset,
off_t filesize);
// Fill in the symbol resolution status for the given plugin symbols.
ld_plugin_status
get_symbol_resolution_info(Symbol_table* symtab,
int nsyms,
ld_plugin_symbol* syms,
int version) const;
// Store the incoming symbols from the plugin for later processing.
void
store_incoming_symbols(int nsyms, const struct ld_plugin_symbol* syms)
{
this->nsyms_ = nsyms;
this->syms_ = syms;
}
// Return TRUE if the comdat group with key COMDAT_KEY from this object
// should be kept.
bool
include_comdat_group(std::string comdat_key, Layout* layout);
// Return the filename.
const std::string&
filename() const
{ return this->input_file()->filename(); }
// Return the file descriptor.
int
descriptor()
{ return this->input_file()->file().descriptor(); }
// Return the size of the file or archive member.
off_t
filesize()
{ return this->filesize_; }
// Return the word size of the object file.
int
elfsize() const
{ gold_unreachable(); }
// Return TRUE if this is a big-endian object file.
bool
is_big_endian() const
{ gold_unreachable(); }
protected:
// Return TRUE if this is an object claimed by a plugin.
virtual Pluginobj*
do_pluginobj()
{ return this; }
// The number of symbols provided by the plugin.
int nsyms_;
// The symbols provided by the plugin.
const struct ld_plugin_symbol* syms_;
// The entries in the symbol table for the external symbols.
Symbols symbols_;
private:
// Size of the file (or archive member).
off_t filesize_;
// Map a comdat key symbol to a boolean indicating whether the comdat
// group in this object with that key should be kept.
typedef Unordered_map<std::string, bool> Comdat_map;
Comdat_map comdat_map_;
};
// A plugin object, size-specific version.
template<int size, bool big_endian>
class Sized_pluginobj : public Pluginobj
{
public:
Sized_pluginobj(const std::string& name, Input_file* input_file,
off_t offset, off_t filesize);
// Read the symbols.
void
do_read_symbols(Read_symbols_data*);
// Lay out the input sections.
void
do_layout(Symbol_table*, Layout*, Read_symbols_data*);
// Add the symbols to the symbol table.
void
do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*);
Archive::Should_include
do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*,
std::string* why);
// Iterate over global symbols, calling a visitor class V for each.
void
do_for_all_global_symbols(Read_symbols_data* sd,
Library_base::Symbol_visitor_base* v);
// Iterate over local symbols, calling a visitor class V for each GOT offset
// associated with a local symbol.
void
do_for_all_local_got_entries(Got_offset_list::Visitor* v) const;
// Get the size of a section.
uint64_t
do_section_size(unsigned int shndx);
// Get the name of a section.
std::string
do_section_name(unsigned int shndx) const;
// Return a view of the contents of a section.
const unsigned char*
do_section_contents(unsigned int shndx, section_size_type* plen,
bool cache);
// Return section flags.
uint64_t
do_section_flags(unsigned int shndx);
// Return section entsize.
uint64_t
do_section_entsize(unsigned int shndx);
// Return section address.
uint64_t
do_section_address(unsigned int shndx);
// Return section type.
unsigned int
do_section_type(unsigned int shndx);
// Return the section link field.
unsigned int
do_section_link(unsigned int shndx);
// Return the section link field.
unsigned int
do_section_info(unsigned int shndx);
// Return the section alignment.
uint64_t
do_section_addralign(unsigned int shndx);
// Return the Xindex structure to use.
Xindex*
do_initialize_xindex();
// Get symbol counts.
void
do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const;
// Get global symbols.
const Symbols*
do_get_global_symbols() const;
// Add placeholder symbols from a claimed file.
ld_plugin_status
add_symbols_from_plugin(int nsyms, const ld_plugin_symbol* syms);
protected:
private:
};
// This Task handles handles the "all symbols read" event hook.
// The plugin may add additional input files at this time, which must
// be queued for reading.
class Plugin_hook : public Task
{
public:
Plugin_hook(const General_options& options, Input_objects* input_objects,
Symbol_table* symtab, Layout* /*layout*/, Dirsearch* dirpath,
Mapfile* mapfile, Task_token* this_blocker,
Task_token* next_blocker)
: options_(options), input_objects_(input_objects), symtab_(symtab),
dirpath_(dirpath), mapfile_(mapfile),
this_blocker_(this_blocker), next_blocker_(next_blocker)
{ }
~Plugin_hook();
// The standard Task methods.
Task_token*
is_runnable();
void
locks(Task_locker*);
void
run(Workqueue*);
std::string
get_name() const
{ return "Plugin_hook"; }
private:
const General_options& options_;
Input_objects* input_objects_;
Symbol_table* symtab_;
Dirsearch* dirpath_;
Mapfile* mapfile_;
Task_token* this_blocker_;
Task_token* next_blocker_;
};
} // End namespace gold.
#endif // !defined(GOLD_PLUGIN_H)
|