* dynobj.h (Dynobj::do_dynobj): New function.
* incremental-dump.cc (dump_incremental_inputs): Print as_needed flag and soname for shared objects. * incremental.cc (Incremental_inputs::report_object): Make either Incremental_object_entry or Incremental_dynobj_entry; add soname to string table. (Incremental_inputs::report_input_section): Add assertion. (Output_section_incremental_inputs::set_final_data_size): Adjust type of input file entry for shared libraries; adjust size of shared library info entry. (Output_section_incremental_inputs::write_input_files): Write as_needed flag for shared libraries. (Output_section_incremental_inputs::write_info_blocks): Adjust type of input file entry for shared libraries; write soname. (Sized_incr_dynobj::Sized_incr_dynobj): Read as_needed flag and soname from incremental info. * incremental.h (enum Incremental_input_flags): Add INCREMENTAL_INPUT_AS_NEEDED. (Incremental_input_entry::Incremental_input_entry): Initialize new data member. (Incremental_input_entry::set_as_needed): New function. (Incremental_input_entry::as_needed): New function. (Incremental_input_entry::do_dynobj_entry): New function. (Incremental_input_entry::as_needed_): New data member. (Incremental_object_entry::Incremental_object_entry): Don't check for shared library. (Incremental_object_entry::do_type): Likewise. (class Incremental_dynobj_entry): New class. (Incremental_input_entry_reader::as_needed): New function. (Incremental_input_entry_reader::get_soname): New function. (Incremental_input_entry_reader::get_global_symbol_count): Rewrite. (Incremental_input_entry_reader::get_output_symbol_index): Adjust size of shared library info entry. * layout.cc (Layout::finish_dynamic_section): Don't test for incremental link when adding DT_NEEDED entries. * object.h (Object::Object): Initialize new data member. (Object::dynobj): New function. (Object::set_as_needed): New function. (Object::as_needed): New function. (Object::do_dynobj): New function. (Object::as_needed_): New data member.
This commit is contained in:
parent
6fa2a40bf4
commit
0f1c85a622
@ -1,3 +1,47 @@
|
||||
2011-05-24 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* dynobj.h (Dynobj::do_dynobj): New function.
|
||||
* incremental-dump.cc (dump_incremental_inputs): Print as_needed
|
||||
flag and soname for shared objects.
|
||||
* incremental.cc (Incremental_inputs::report_object): Make
|
||||
either Incremental_object_entry or Incremental_dynobj_entry; add
|
||||
soname to string table.
|
||||
(Incremental_inputs::report_input_section): Add assertion.
|
||||
(Output_section_incremental_inputs::set_final_data_size): Adjust
|
||||
type of input file entry for shared libraries; adjust size of
|
||||
shared library info entry.
|
||||
(Output_section_incremental_inputs::write_input_files): Write
|
||||
as_needed flag for shared libraries.
|
||||
(Output_section_incremental_inputs::write_info_blocks): Adjust type
|
||||
of input file entry for shared libraries; write soname.
|
||||
(Sized_incr_dynobj::Sized_incr_dynobj): Read as_needed flag and
|
||||
soname from incremental info.
|
||||
* incremental.h (enum Incremental_input_flags): Add
|
||||
INCREMENTAL_INPUT_AS_NEEDED.
|
||||
(Incremental_input_entry::Incremental_input_entry): Initialize new
|
||||
data member.
|
||||
(Incremental_input_entry::set_as_needed): New function.
|
||||
(Incremental_input_entry::as_needed): New function.
|
||||
(Incremental_input_entry::do_dynobj_entry): New function.
|
||||
(Incremental_input_entry::as_needed_): New data member.
|
||||
(Incremental_object_entry::Incremental_object_entry): Don't check
|
||||
for shared library.
|
||||
(Incremental_object_entry::do_type): Likewise.
|
||||
(class Incremental_dynobj_entry): New class.
|
||||
(Incremental_input_entry_reader::as_needed): New function.
|
||||
(Incremental_input_entry_reader::get_soname): New function.
|
||||
(Incremental_input_entry_reader::get_global_symbol_count): Rewrite.
|
||||
(Incremental_input_entry_reader::get_output_symbol_index): Adjust
|
||||
size of shared library info entry.
|
||||
* layout.cc (Layout::finish_dynamic_section): Don't test for
|
||||
incremental link when adding DT_NEEDED entries.
|
||||
* object.h (Object::Object): Initialize new data member.
|
||||
(Object::dynobj): New function.
|
||||
(Object::set_as_needed): New function.
|
||||
(Object::as_needed): New function.
|
||||
(Object::do_dynobj): New function.
|
||||
(Object::as_needed_): New data member.
|
||||
|
||||
2011-05-24 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* incremental-dump.cc (dump_incremental_inputs): Print dynamic reloc
|
||||
|
@ -96,6 +96,11 @@ class Dynobj : public Object
|
||||
unsigned char** pphash, unsigned int* phashlen);
|
||||
|
||||
protected:
|
||||
// Return a pointer to this object.
|
||||
virtual Dynobj*
|
||||
do_dynobj()
|
||||
{ return this; }
|
||||
|
||||
// Set the DT_SONAME string.
|
||||
void
|
||||
set_soname_string(const char* s)
|
||||
|
@ -162,6 +162,10 @@ dump_incremental_inputs(const char* argv0, const char* filename,
|
||||
break;
|
||||
case INCREMENTAL_INPUT_SHARED_LIBRARY:
|
||||
printf("Shared library\n");
|
||||
printf(" As needed: %s\n",
|
||||
input_file.as_needed() ? "true" : "false");
|
||||
printf(" soname: %s\n",
|
||||
input_file.get_soname());
|
||||
printf(" Symbol count: %d\n",
|
||||
input_file.get_global_symbol_count());
|
||||
break;
|
||||
|
@ -975,28 +975,48 @@ Incremental_inputs::report_object(Object* obj, unsigned int arg_serial,
|
||||
arg_serial = 0;
|
||||
|
||||
this->strtab_->add(obj->name().c_str(), false, &filename_key);
|
||||
Incremental_object_entry* obj_entry =
|
||||
new Incremental_object_entry(filename_key, obj, arg_serial, mtime);
|
||||
if (obj->is_in_system_directory())
|
||||
obj_entry->set_is_in_system_directory();
|
||||
this->inputs_.push_back(obj_entry);
|
||||
|
||||
if (arch != NULL)
|
||||
Incremental_input_entry* input_entry;
|
||||
|
||||
this->current_object_ = obj;
|
||||
|
||||
if (!obj->is_dynamic())
|
||||
{
|
||||
Incremental_archive_entry* arch_entry = arch->incremental_info();
|
||||
gold_assert(arch_entry != NULL);
|
||||
arch_entry->add_object(obj_entry);
|
||||
this->current_object_entry_ =
|
||||
new Incremental_object_entry(filename_key, obj, arg_serial, mtime);
|
||||
input_entry = this->current_object_entry_;
|
||||
if (arch != NULL)
|
||||
{
|
||||
Incremental_archive_entry* arch_entry = arch->incremental_info();
|
||||
gold_assert(arch_entry != NULL);
|
||||
arch_entry->add_object(this->current_object_entry_);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current_object_entry_ = NULL;
|
||||
Stringpool::Key soname_key;
|
||||
Dynobj* dynobj = obj->dynobj();
|
||||
gold_assert(dynobj != NULL);
|
||||
this->strtab_->add(dynobj->soname(), false, &soname_key);
|
||||
input_entry = new Incremental_dynobj_entry(filename_key, soname_key, obj,
|
||||
arg_serial, mtime);
|
||||
}
|
||||
|
||||
if (obj->is_in_system_directory())
|
||||
input_entry->set_is_in_system_directory();
|
||||
|
||||
if (obj->as_needed())
|
||||
input_entry->set_as_needed();
|
||||
|
||||
this->inputs_.push_back(input_entry);
|
||||
|
||||
if (script_info != NULL)
|
||||
{
|
||||
Incremental_script_entry* script_entry = script_info->incremental_info();
|
||||
gold_assert(script_entry != NULL);
|
||||
script_entry->add_object(obj_entry);
|
||||
script_entry->add_object(input_entry);
|
||||
}
|
||||
|
||||
this->current_object_ = obj;
|
||||
this->current_object_entry_ = obj_entry;
|
||||
}
|
||||
|
||||
// Record the input object file OBJ. If ARCH is not NULL, attach
|
||||
@ -1013,6 +1033,7 @@ Incremental_inputs::report_input_section(Object* obj, unsigned int shndx,
|
||||
this->strtab_->add(name, true, &key);
|
||||
|
||||
gold_assert(obj == this->current_object_);
|
||||
gold_assert(this->current_object_entry_ != NULL);
|
||||
this->current_object_entry_->add_input_section(shndx, key, sh_size);
|
||||
}
|
||||
|
||||
@ -1155,11 +1176,11 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
|
||||
break;
|
||||
case INCREMENTAL_INPUT_SHARED_LIBRARY:
|
||||
{
|
||||
Incremental_object_entry* entry = (*p)->object_entry();
|
||||
Incremental_dynobj_entry* entry = (*p)->dynobj_entry();
|
||||
gold_assert(entry != NULL);
|
||||
(*p)->set_info_offset(info_offset);
|
||||
// Global symbol count.
|
||||
info_offset += 4;
|
||||
// Global symbol count, soname index.
|
||||
info_offset += 8;
|
||||
// Each global symbol.
|
||||
const Object::Symbols* syms = entry->object()->get_global_symbols();
|
||||
gold_assert(syms != NULL);
|
||||
@ -1321,6 +1342,8 @@ Output_section_incremental_inputs<size, big_endian>::write_input_files(
|
||||
unsigned int flags = (*p)->type();
|
||||
if ((*p)->is_in_system_directory())
|
||||
flags |= INCREMENTAL_INPUT_IN_SYSTEM_DIR;
|
||||
if ((*p)->as_needed())
|
||||
flags |= INCREMENTAL_INPUT_AS_NEEDED;
|
||||
Swap32::writeval(pov, filename_offset);
|
||||
Swap32::writeval(pov + 4, (*p)->get_info_offset());
|
||||
Swap64::writeval(pov + 8, mtime.seconds);
|
||||
@ -1483,11 +1506,17 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
|
||||
{
|
||||
gold_assert(static_cast<unsigned int>(pov - oview)
|
||||
== (*p)->get_info_offset());
|
||||
Incremental_object_entry* entry = (*p)->object_entry();
|
||||
Incremental_dynobj_entry* entry = (*p)->dynobj_entry();
|
||||
gold_assert(entry != NULL);
|
||||
const Object* obj = entry->object();
|
||||
const Object::Symbols* syms = obj->get_global_symbols();
|
||||
|
||||
// Write the soname string table index.
|
||||
section_offset_type soname_offset =
|
||||
strtab->get_offset_from_key(entry->get_soname_key());
|
||||
Swap32::writeval(pov, soname_offset);
|
||||
pov += 4;
|
||||
|
||||
// Skip the global symbol count for now.
|
||||
unsigned char* orig_pov = pov;
|
||||
pov += 4;
|
||||
@ -2347,6 +2376,9 @@ Sized_incr_dynobj<size, big_endian>::Sized_incr_dynobj(
|
||||
{
|
||||
if (this->input_reader_.is_in_system_directory())
|
||||
this->set_is_in_system_directory();
|
||||
if (this->input_reader_.as_needed())
|
||||
this->set_as_needed();
|
||||
this->set_soname_string(this->input_reader_.get_soname());
|
||||
this->set_shnum(0);
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ class Input_argument;
|
||||
class Incremental_inputs_checker;
|
||||
class Incremental_script_entry;
|
||||
class Incremental_object_entry;
|
||||
class Incremental_dynobj_entry;
|
||||
class Incremental_archive_entry;
|
||||
class Incremental_inputs;
|
||||
class Incremental_binary;
|
||||
@ -63,7 +64,8 @@ enum Incremental_input_type
|
||||
|
||||
enum Incremental_input_flags
|
||||
{
|
||||
INCREMENTAL_INPUT_IN_SYSTEM_DIR = 0x0800
|
||||
INCREMENTAL_INPUT_IN_SYSTEM_DIR = 0x8000,
|
||||
INCREMENTAL_INPUT_AS_NEEDED = 0x4000
|
||||
};
|
||||
|
||||
// Create an Incremental_binary object for FILE. Returns NULL is this is not
|
||||
@ -80,7 +82,8 @@ class Incremental_input_entry
|
||||
Incremental_input_entry(Stringpool::Key filename_key, unsigned int arg_serial,
|
||||
Timespec mtime)
|
||||
: filename_key_(filename_key), file_index_(0), offset_(0), info_offset_(0),
|
||||
arg_serial_(arg_serial), mtime_(mtime), is_in_system_directory_(false)
|
||||
arg_serial_(arg_serial), mtime_(mtime), is_in_system_directory_(false),
|
||||
as_needed_(false)
|
||||
{ }
|
||||
|
||||
virtual
|
||||
@ -145,6 +148,16 @@ class Incremental_input_entry
|
||||
is_in_system_directory() const
|
||||
{ return this->is_in_system_directory_; }
|
||||
|
||||
// Record that the file was linked with --as-needed.
|
||||
void
|
||||
set_as_needed()
|
||||
{ this->as_needed_ = true; }
|
||||
|
||||
// Return TRUE if the file was linked with --as-needed.
|
||||
bool
|
||||
as_needed() const
|
||||
{ return this->as_needed_; }
|
||||
|
||||
// Return a pointer to the derived Incremental_script_entry object.
|
||||
// Return NULL for input entries that are not script files.
|
||||
Incremental_script_entry*
|
||||
@ -157,6 +170,12 @@ class Incremental_input_entry
|
||||
object_entry()
|
||||
{ return this->do_object_entry(); }
|
||||
|
||||
// Return a pointer to the derived Incremental_dynobj_entry object.
|
||||
// Return NULL for input entries that are not shared object files.
|
||||
Incremental_dynobj_entry*
|
||||
dynobj_entry()
|
||||
{ return this->do_dynobj_entry(); }
|
||||
|
||||
// Return a pointer to the derived Incremental_archive_entry object.
|
||||
// Return NULL for input entries that are not archive files.
|
||||
Incremental_archive_entry*
|
||||
@ -180,6 +199,12 @@ class Incremental_input_entry
|
||||
do_object_entry()
|
||||
{ return NULL; }
|
||||
|
||||
// Return a pointer to the derived Incremental_dynobj_entry object.
|
||||
// Return NULL for input entries that are not shared object files.
|
||||
virtual Incremental_dynobj_entry*
|
||||
do_dynobj_entry()
|
||||
{ return NULL; }
|
||||
|
||||
// Return a pointer to the derived Incremental_archive_entry object.
|
||||
// Return NULL for input entries that are not archive files.
|
||||
virtual Incremental_archive_entry*
|
||||
@ -207,6 +232,9 @@ class Incremental_input_entry
|
||||
|
||||
// TRUE if the file was found in a system directory.
|
||||
bool is_in_system_directory_;
|
||||
|
||||
// TRUE if the file was linked with --as-needed.
|
||||
bool as_needed_;
|
||||
};
|
||||
|
||||
// Information about a script input that will persist during the whole linker
|
||||
@ -298,10 +326,7 @@ class Incremental_object_entry : public Incremental_input_entry
|
||||
unsigned int arg_serial, Timespec mtime)
|
||||
: Incremental_input_entry(filename_key, arg_serial, mtime), obj_(obj),
|
||||
is_member_(false), sections_()
|
||||
{
|
||||
if (!obj_->is_dynamic())
|
||||
this->sections_.reserve(obj->shnum());
|
||||
}
|
||||
{ this->sections_.reserve(obj->shnum()); }
|
||||
|
||||
// Get the object.
|
||||
Object*
|
||||
@ -349,9 +374,7 @@ class Incremental_object_entry : public Incremental_input_entry
|
||||
{
|
||||
return (this->is_member_
|
||||
? INCREMENTAL_INPUT_ARCHIVE_MEMBER
|
||||
: (this->obj_->is_dynamic()
|
||||
? INCREMENTAL_INPUT_SHARED_LIBRARY
|
||||
: INCREMENTAL_INPUT_OBJECT));
|
||||
: INCREMENTAL_INPUT_OBJECT);
|
||||
}
|
||||
|
||||
// Return a pointer to the derived Incremental_object_entry object.
|
||||
@ -379,6 +402,46 @@ class Incremental_object_entry : public Incremental_input_entry
|
||||
std::vector<Input_section> sections_;
|
||||
};
|
||||
|
||||
// Class for recording shared library input files.
|
||||
|
||||
class Incremental_dynobj_entry : public Incremental_input_entry
|
||||
{
|
||||
public:
|
||||
Incremental_dynobj_entry(Stringpool::Key filename_key,
|
||||
Stringpool::Key soname_key, Object* obj,
|
||||
unsigned int arg_serial, Timespec mtime)
|
||||
: Incremental_input_entry(filename_key, arg_serial, mtime),
|
||||
soname_key_(soname_key), obj_(obj)
|
||||
{ }
|
||||
|
||||
// Get the object.
|
||||
Object*
|
||||
object() const
|
||||
{ return this->obj_; }
|
||||
|
||||
// Get the stringpool key for the soname.
|
||||
Stringpool::Key
|
||||
get_soname_key() const
|
||||
{ return this->soname_key_; }
|
||||
|
||||
protected:
|
||||
virtual Incremental_input_type
|
||||
do_type() const
|
||||
{ return INCREMENTAL_INPUT_SHARED_LIBRARY; }
|
||||
|
||||
// Return a pointer to the derived Incremental_dynobj_entry object.
|
||||
virtual Incremental_dynobj_entry*
|
||||
do_dynobj_entry()
|
||||
{ return this; }
|
||||
|
||||
private:
|
||||
// Key of the soname string in the section stringtable.
|
||||
Stringpool::Key soname_key_;
|
||||
|
||||
// The object file itself.
|
||||
Object* obj_;
|
||||
};
|
||||
|
||||
// Class for recording archive library input files.
|
||||
|
||||
class Incremental_archive_entry : public Incremental_input_entry
|
||||
@ -718,6 +781,11 @@ class Incremental_inputs_reader
|
||||
is_in_system_directory() const
|
||||
{ return (this->flags_ & INCREMENTAL_INPUT_IN_SYSTEM_DIR) != 0; }
|
||||
|
||||
// Return TRUE if the file was linked with --as-needed.
|
||||
bool
|
||||
as_needed() const
|
||||
{ return (this->flags_ & INCREMENTAL_INPUT_AS_NEEDED) != 0; }
|
||||
|
||||
// Return the input section count -- for objects only.
|
||||
unsigned int
|
||||
get_input_section_count() const
|
||||
@ -727,6 +795,16 @@ class Incremental_inputs_reader
|
||||
return Swap32::readval(this->inputs_->p_ + this->info_offset_);
|
||||
}
|
||||
|
||||
// Return the soname -- for shared libraries only.
|
||||
const char*
|
||||
get_soname() const
|
||||
{
|
||||
gold_assert(this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY);
|
||||
unsigned int offset = Swap32::readval(this->inputs_->p_
|
||||
+ this->info_offset_);
|
||||
return this->inputs_->get_string(offset);
|
||||
}
|
||||
|
||||
// Return the offset of the supplemental info for symbol SYMNDX --
|
||||
// for objects only.
|
||||
unsigned int
|
||||
@ -745,16 +823,10 @@ class Incremental_inputs_reader
|
||||
unsigned int
|
||||
get_global_symbol_count() const
|
||||
{
|
||||
switch (this->type())
|
||||
{
|
||||
case INCREMENTAL_INPUT_OBJECT:
|
||||
case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
|
||||
return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4);
|
||||
case INCREMENTAL_INPUT_SHARED_LIBRARY:
|
||||
return Swap32::readval(this->inputs_->p_ + this->info_offset_);
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
|
||||
|| this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER
|
||||
|| this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY);
|
||||
return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4);
|
||||
}
|
||||
|
||||
// Return the offset of the first local symbol -- for objects only.
|
||||
@ -899,7 +971,7 @@ class Incremental_inputs_reader
|
||||
{
|
||||
gold_assert(this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY);
|
||||
const unsigned char* p = (this->inputs_->p_
|
||||
+ this->info_offset_ + 4
|
||||
+ this->info_offset_ + 8
|
||||
+ n * 4);
|
||||
unsigned int output_symndx = Swap32::readval(p);
|
||||
*is_def = (output_symndx & (1U << 31)) != 0;
|
||||
|
@ -3986,9 +3986,7 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
|
||||
p != input_objects->dynobj_end();
|
||||
++p)
|
||||
{
|
||||
if (!(*p)->is_needed()
|
||||
&& !(*p)->is_incremental()
|
||||
&& (*p)->input_file()->options().as_needed())
|
||||
if (!(*p)->is_needed() && (*p)->as_needed())
|
||||
{
|
||||
// This dynamic object was linked with --as-needed, but it
|
||||
// is not needed.
|
||||
|
@ -332,12 +332,13 @@ class Object
|
||||
: name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
|
||||
is_dynamic_(is_dynamic), is_needed_(false), uses_split_stack_(false),
|
||||
has_no_split_stack_(false), no_export_(false),
|
||||
is_in_system_directory_(false), xindex_(NULL)
|
||||
is_in_system_directory_(false), as_needed_(false), xindex_(NULL)
|
||||
{
|
||||
if (input_file != NULL)
|
||||
{
|
||||
input_file->file().add_object();
|
||||
this->is_in_system_directory_ = input_file->is_in_system_directory();
|
||||
this->as_needed_ = input_file->options().as_needed();
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,6 +387,12 @@ class Object
|
||||
has_no_split_stack() const
|
||||
{ return this->has_no_split_stack_; }
|
||||
|
||||
// Returns NULL for Objects that are not dynamic objects. This method
|
||||
// is overridden in the Dynobj class.
|
||||
Dynobj*
|
||||
dynobj()
|
||||
{ return this->do_dynobj(); }
|
||||
|
||||
// Returns NULL for Objects that are not plugin objects. This method
|
||||
// is overridden in the Pluginobj class.
|
||||
Pluginobj*
|
||||
@ -688,6 +695,16 @@ class Object
|
||||
is_in_system_directory() const
|
||||
{ return this->is_in_system_directory_; }
|
||||
|
||||
// Set flag that this object was linked with --as-needed.
|
||||
void
|
||||
set_as_needed()
|
||||
{ this->as_needed_ = true; }
|
||||
|
||||
// Return whether this object was linked with --as-needed.
|
||||
bool
|
||||
as_needed() const
|
||||
{ return this->as_needed_; }
|
||||
|
||||
// Return whether we found this object by searching a directory.
|
||||
bool
|
||||
searched_for() const
|
||||
@ -719,6 +736,12 @@ class Object
|
||||
{ return this->do_get_incremental_reloc_count(symndx); }
|
||||
|
||||
protected:
|
||||
// Returns NULL for Objects that are not dynamic objects. This method
|
||||
// is overridden in the Dynobj class.
|
||||
virtual Dynobj*
|
||||
do_dynobj()
|
||||
{ return NULL; }
|
||||
|
||||
// Returns NULL for Objects that are not plugin objects. This method
|
||||
// is overridden in the Pluginobj class.
|
||||
virtual Pluginobj*
|
||||
@ -911,6 +934,8 @@ class Object
|
||||
bool no_export_ : 1;
|
||||
// True if the object was found in a system directory.
|
||||
bool is_in_system_directory_ : 1;
|
||||
// True if the object was linked with --as-needed.
|
||||
bool as_needed_ : 1;
|
||||
// Many sections for objects with more than SHN_LORESERVE sections.
|
||||
Xindex* xindex_;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user