gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gold / target-select.cc
index ac311fba379dd7c68abca41007799a7198abf0b8..f47d79c6c19f4ac93c80efbbec3afac28f76891f 100644 (file)
@@ -1,6 +1,6 @@
 // target-select.cc -- select a target for an object file
 
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright (C) 2006-2020 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
 
 #include "gold.h"
 
+#include <cstdio>
 #include <cstring>
 
 #include "elfcpp.h"
+#include "options.h"
+#include "parameters.h"
 #include "target-select.h"
 
 namespace
@@ -39,44 +42,65 @@ gold::Target_selector* target_selectors;
 namespace gold
 {
 
+// Class Set_target_once.
+
+void
+Set_target_once::do_run_once(void*)
+{
+  this->target_selector_->set_target();
+}
+
 // Construct a Target_selector, which means adding it to the linked
 // list.  This runs at global constructor time, so we want it to be
 // fast.
 
-Target_selector::Target_selector(int amachine, int size, bool is_big_end,
-                                const char* bfdname)
-  : machine_(amachine), size_(size), is_big_endian_(is_big_end),
-    bfd_name_(bfdname), instantiated_target_(NULL), lock_(NULL),
-    initialize_lock_(&this->lock_)
-    
+Target_selector::Target_selector(int machine, int size, bool is_big_endian,
+                                const char* bfd_name, const char* emulation)
+  : machine_(machine), size_(size), is_big_endian_(is_big_endian),
+    bfd_name_(bfd_name), emulation_(emulation), instantiated_target_(NULL),
+    set_target_once_(this)
 {
   this->next_ = target_selectors;
   target_selectors = this;
 }
 
-// Instantiate the target and return it.  Use a lock to avoid
-// instantiating two instances of the same target.
+// Instantiate the target and return it.  Use SET_TARGET_ONCE_ to
+// avoid instantiating two instances of the same target.
 
 Target*
 Target_selector::instantiate_target()
 {
-  // We assume that the pointer will either be written entirely or not
-  // at all.
-  if (this->instantiated_target_ == NULL)
-    {
-      this->initialize_lock_.initialize();
-      Hold_optional_lock hl(this->lock_);
-      if (this->instantiated_target_ == NULL)
-       this->instantiated_target_ = this->do_instantiate_target();
-    }
+  this->set_target_once_.run_once(NULL);
   return this->instantiated_target_;
 }
 
+// Instantiate the target.  This is called at most once.
+
+void
+Target_selector::set_target()
+{
+  gold_assert(this->instantiated_target_ == NULL);
+  this->instantiated_target_ = this->do_instantiate_target();
+}
+
+// If we instantiated TARGET, return the corresponding BFD name.
+
+const char*
+Target_selector::do_target_bfd_name(const Target* target)
+{
+  if (!this->is_our_target(target))
+    return NULL;
+  const char* my_bfd_name = this->bfd_name();
+  gold_assert(my_bfd_name != NULL);
+  return my_bfd_name;
+}
+
 // Find the target for an ELF file.
 
 Target*
-select_target(int machine, int size, bool is_big_endian, int osabi,
-             int abiversion)
+select_target(Input_file* input_file, off_t offset,
+             int machine, int size, bool is_big_endian,
+             int osabi, int abiversion)
 {
   for (Target_selector* p = target_selectors; p != NULL; p = p->next())
     {
@@ -85,7 +109,8 @@ select_target(int machine, int size, bool is_big_endian, int osabi,
          && p->get_size() == size
          && (p->is_big_endian() ? is_big_endian : !is_big_endian))
        {
-         Target* ret = p->recognize(machine, osabi, abiversion);
+         Target* ret = p->recognize(input_file, offset,
+                                    machine, osabi, abiversion);
          if (ret != NULL)
            return ret;
        }
@@ -97,14 +122,33 @@ select_target(int machine, int size, bool is_big_endian, int osabi,
 // --oformat option.
 
 Target*
-select_target_by_name(const char* name)
+select_target_by_bfd_name(const char* name)
 {
   for (Target_selector* p = target_selectors; p != NULL; p = p->next())
     {
       const char* pname = p->bfd_name();
       if (pname == NULL || strcmp(pname, name) == 0)
        {
-         Target* ret = p->recognize_by_name(name);
+         Target* ret = p->recognize_by_bfd_name(name);
+         if (ret != NULL)
+           return ret;
+       }
+    }
+  return NULL;
+}
+
+// Find a target using a GNU linker emulation.  This is used to
+// support the -m option.
+
+Target*
+select_target_by_emulation(const char* name)
+{
+  for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+    {
+      const char* pname = p->emulation();
+      if (pname == NULL || strcmp(pname, name) == 0)
+       {
+         Target* ret = p->recognize_by_emulation(name);
          if (ret != NULL)
            return ret;
        }
@@ -118,7 +162,58 @@ void
 supported_target_names(std::vector<const char*>* names)
 {
   for (Target_selector* p = target_selectors; p != NULL; p = p->next())
-    p->supported_names(names);
+    p->supported_bfd_names(names);
+}
+
+// Push all the supported emulations onto a vector.
+
+void
+supported_emulation_names(std::vector<const char*>* names)
+{
+  for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+    p->supported_emulations(names);
+}
+
+// Implement the --print-output-format option.
+
+void
+print_output_format()
+{
+  if (!parameters->target_valid())
+    {
+      // This case arises when --print-output-format is used with no
+      // input files.  We need to come up with the right string to
+      // print based on the other options.  If the user specified the
+      // format using a --oformat option, use that.  That saves each
+      // target from having to remember the name that was used to
+      // select it.  In other cases, we will just have to ask the
+      // target.
+      if (parameters->options().user_set_oformat())
+       {
+         const char* bfd_name = parameters->options().oformat();
+         Target* target = select_target_by_bfd_name(bfd_name);
+         if (target != NULL)
+           printf("%s\n", bfd_name);
+         else
+           gold_error(_("unrecognized output format %s"), bfd_name);
+         return;
+       }
+
+      parameters_force_valid_target();
+    }
+
+  const Target* target = &parameters->target();
+  for (Target_selector* p = target_selectors; p != NULL; p = p->next())
+    {
+      const char* bfd_name = p->target_bfd_name(target);
+      if (bfd_name != NULL)
+       {
+         printf("%s\n", bfd_name);
+         return;
+       }
+    }
+
+  gold_unreachable();
 }
 
 } // End namespace gold.
This page took 0.025195 seconds and 4 git commands to generate.