brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.4 KiB · 2e03bc1 Raw
591 lines · cpp
1//===-- TargetList.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/TargetList.h"10#include "lldb/Core/Debugger.h"11#include "lldb/Core/Module.h"12#include "lldb/Core/ModuleSpec.h"13#include "lldb/Host/Host.h"14#include "lldb/Host/HostInfo.h"15#include "lldb/Interpreter/CommandInterpreter.h"16#include "lldb/Interpreter/OptionGroupPlatform.h"17#include "lldb/Symbol/ObjectFile.h"18#include "lldb/Target/Platform.h"19#include "lldb/Target/Process.h"20#include "lldb/Utility/Broadcaster.h"21#include "lldb/Utility/Event.h"22#include "lldb/Utility/State.h"23#include "lldb/Utility/TildeExpressionResolver.h"24#include "lldb/Utility/Timer.h"25 26#include "llvm/ADT/SmallString.h"27#include "llvm/Support/FileSystem.h"28 29using namespace lldb;30using namespace lldb_private;31 32llvm::StringRef TargetList::GetStaticBroadcasterClass() {33  static constexpr llvm::StringLiteral class_name("lldb.targetList");34  return class_name;35}36 37// TargetList constructor38TargetList::TargetList(Debugger &debugger)39    : Broadcaster(debugger.GetBroadcasterManager(),40                  TargetList::GetStaticBroadcasterClass().str()),41      m_target_list(), m_target_list_mutex(), m_selected_target_idx(0) {42  CheckInWithManager();43}44 45Status TargetList::CreateTarget(Debugger &debugger,46                                llvm::StringRef user_exe_path,47                                llvm::StringRef triple_str,48                                LoadDependentFiles load_dependent_files,49                                const OptionGroupPlatform *platform_options,50                                TargetSP &target_sp) {51  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);52  auto result = TargetList::CreateTargetInternal(53      debugger, user_exe_path, triple_str, load_dependent_files,54      platform_options, target_sp);55 56  if (target_sp && result.Success())57    AddTargetInternal(target_sp, /*do_select*/ true);58  return result;59}60 61Status TargetList::CreateTarget(Debugger &debugger,62                                llvm::StringRef user_exe_path,63                                const ArchSpec &specified_arch,64                                LoadDependentFiles load_dependent_files,65                                PlatformSP &platform_sp, TargetSP &target_sp) {66  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);67  auto result = TargetList::CreateTargetInternal(68      debugger, user_exe_path, specified_arch, load_dependent_files,69      platform_sp, target_sp);70 71  if (target_sp && result.Success())72    AddTargetInternal(target_sp, /*do_select*/ true);73  return result;74}75 76Status TargetList::CreateTargetInternal(77    Debugger &debugger, llvm::StringRef user_exe_path,78    llvm::StringRef triple_str, LoadDependentFiles load_dependent_files,79    const OptionGroupPlatform *platform_options, TargetSP &target_sp) {80  Status error;81 82  PlatformList &platform_list = debugger.GetPlatformList();83  // Let's start by looking at the selected platform.84  PlatformSP platform_sp = platform_list.GetSelectedPlatform();85 86  // This variable corresponds to the architecture specified by the triple87  // string. If that string was empty the currently selected platform will88  // determine the architecture.89  const ArchSpec arch(triple_str);90  if (!triple_str.empty() && !arch.IsValid()) {91    error = Status::FromErrorStringWithFormat("invalid triple '%s'",92                                              triple_str.str().c_str());93    return error;94  }95 96  ArchSpec platform_arch(arch);97 98  // Create a new platform if a platform was specified in the platform options99  // and doesn't match the selected platform.100  if (platform_options && platform_options->PlatformWasSpecified() &&101      !platform_options->PlatformMatches(platform_sp)) {102    const bool select_platform = true;103    platform_sp = platform_options->CreatePlatformWithOptions(104        debugger.GetCommandInterpreter(), arch, select_platform, error,105        platform_arch);106    if (!platform_sp)107      return error;108  }109 110  bool prefer_platform_arch = false;111  auto update_platform_arch = [&](const ArchSpec &module_arch) {112    // If the OS or vendor weren't specified, then adopt the module's113    // architecture so that the platform matching can be more accurate.114    if (!platform_arch.TripleOSWasSpecified() ||115        !platform_arch.TripleVendorWasSpecified()) {116      prefer_platform_arch = true;117      platform_arch = module_arch;118    }119  };120 121  if (!user_exe_path.empty()) {122    ModuleSpec module_spec(FileSpec(user_exe_path, FileSpec::Style::native));123    FileSystem::Instance().Resolve(module_spec.GetFileSpec());124 125    // Try to resolve the exe based on PATH and/or platform-specific suffixes,126    // but only if using the host platform.127    if (platform_sp->IsHost() &&128        !FileSystem::Instance().Exists(module_spec.GetFileSpec()))129      FileSystem::Instance().ResolveExecutableLocation(130          module_spec.GetFileSpec());131 132    // Resolve the executable in case we are given a path to a application133    // bundle like a .app bundle on MacOSX.134    Host::ResolveExecutableInBundle(module_spec.GetFileSpec());135 136    lldb::offset_t file_offset = 0;137    lldb::offset_t file_size = 0;138    ModuleSpecList module_specs;139    const size_t num_specs = ObjectFile::GetModuleSpecifications(140        module_spec.GetFileSpec(), file_offset, file_size, module_specs);141 142    if (num_specs > 0) {143      ModuleSpec matching_module_spec;144 145      if (num_specs == 1) {146        if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) {147          if (platform_arch.IsValid()) {148            if (platform_arch.IsCompatibleMatch(149                    matching_module_spec.GetArchitecture())) {150              // If the OS or vendor weren't specified, then adopt the module's151              // architecture so that the platform matching can be more152              // accurate.153              update_platform_arch(matching_module_spec.GetArchitecture());154            } else {155              StreamString platform_arch_strm;156              StreamString module_arch_strm;157 158              platform_arch.DumpTriple(platform_arch_strm.AsRawOstream());159              matching_module_spec.GetArchitecture().DumpTriple(160                  module_arch_strm.AsRawOstream());161              error = Status::FromErrorStringWithFormat(162                  "the specified architecture '%s' is not compatible with '%s' "163                  "in '%s'",164                  platform_arch_strm.GetData(), module_arch_strm.GetData(),165                  module_spec.GetFileSpec().GetPath().c_str());166              return error;167            }168          } else {169            // Only one arch and none was specified.170            prefer_platform_arch = true;171            platform_arch = matching_module_spec.GetArchitecture();172          }173        }174      } else if (arch.IsValid()) {175        // Fat binary. A (valid) architecture was specified.176        module_spec.GetArchitecture() = arch;177        if (module_specs.FindMatchingModuleSpec(module_spec,178                                                matching_module_spec))179            update_platform_arch(matching_module_spec.GetArchitecture());180      } else {181        // Fat binary. No architecture specified, check if there is182        // only one platform for all of the architectures.183        std::vector<PlatformSP> candidates;184        std::vector<ArchSpec> archs;185        for (const ModuleSpec &spec : module_specs.ModuleSpecs())186          archs.push_back(spec.GetArchitecture());187        if (PlatformSP platform_for_archs_sp =188                platform_list.GetOrCreate(archs, {}, candidates)) {189          platform_sp = platform_for_archs_sp;190        } else if (candidates.empty()) {191          error = Status::FromErrorString(192              "no matching platforms found for this file");193          return error;194        } else {195          // More than one platform claims to support this file.196          StreamString error_strm;197          std::set<llvm::StringRef> platform_set;198          error_strm.Printf(199              "more than one platform supports this executable (");200          for (const auto &candidate : candidates) {201            llvm::StringRef platform_name = candidate->GetName();202            if (platform_set.count(platform_name))203              continue;204            if (!platform_set.empty())205              error_strm.PutCString(", ");206            error_strm.PutCString(platform_name);207            platform_set.insert(platform_name);208          }209          error_strm.Printf("), specify an architecture to disambiguate");210          error = Status(error_strm.GetString().str());211          return error;212        }213      }214    }215  }216 217  // If we have a valid architecture, make sure the current platform is218  // compatible with that architecture.219  if (!prefer_platform_arch && arch.IsValid()) {220    if (!platform_sp->IsCompatibleArchitecture(221            arch, {}, ArchSpec::CompatibleMatch, nullptr)) {222      platform_sp = platform_list.GetOrCreate(arch, {}, &platform_arch);223      if (platform_sp)224        platform_list.SetSelectedPlatform(platform_sp);225    }226  } else if (platform_arch.IsValid()) {227    // If "arch" isn't valid, yet "platform_arch" is, it means we have an228    // executable file with a single architecture which should be used.229    ArchSpec fixed_platform_arch;230    if (!platform_sp->IsCompatibleArchitecture(231            platform_arch, {}, ArchSpec::CompatibleMatch, nullptr)) {232      platform_sp =233          platform_list.GetOrCreate(platform_arch, {}, &fixed_platform_arch);234      if (platform_sp)235        platform_list.SetSelectedPlatform(platform_sp);236    }237  }238 239  if (!platform_arch.IsValid())240    platform_arch = arch;241 242  return TargetList::CreateTargetInternal(debugger, user_exe_path,243                                          platform_arch, load_dependent_files,244                                          platform_sp, target_sp);245}246 247Status TargetList::CreateTargetInternal(Debugger &debugger,248                                        llvm::StringRef user_exe_path,249                                        const ArchSpec &specified_arch,250                                        LoadDependentFiles load_dependent_files,251                                        lldb::PlatformSP &platform_sp,252                                        lldb::TargetSP &target_sp) {253  LLDB_SCOPED_TIMERF("TargetList::CreateTarget (file = '%s', arch = '%s')",254                     user_exe_path.str().c_str(),255                     specified_arch.GetArchitectureName());256  Status error;257  const bool is_dummy_target = false;258 259  ArchSpec arch(specified_arch);260 261  if (arch.IsValid()) {262    if (!platform_sp || !platform_sp->IsCompatibleArchitecture(263                            arch, {}, ArchSpec::CompatibleMatch, nullptr))264      platform_sp =265          debugger.GetPlatformList().GetOrCreate(specified_arch, {}, &arch);266  }267 268  if (!platform_sp)269    platform_sp = debugger.GetPlatformList().GetSelectedPlatform();270 271  if (!arch.IsValid())272    arch = specified_arch;273 274  FileSpec file(user_exe_path);275  if (!FileSystem::Instance().Exists(file) && user_exe_path.starts_with("~")) {276    // we want to expand the tilde but we don't want to resolve any symbolic277    // links so we can't use the FileSpec constructor's resolve flag278    llvm::SmallString<64> unglobbed_path;279    StandardTildeExpressionResolver Resolver;280    Resolver.ResolveFullPath(user_exe_path, unglobbed_path);281 282    if (unglobbed_path.empty())283      file = FileSpec(user_exe_path);284    else285      file = FileSpec(unglobbed_path.c_str());286  }287 288  bool user_exe_path_is_bundle = false;289  char resolved_bundle_exe_path[PATH_MAX];290  resolved_bundle_exe_path[0] = '\0';291  if (file) {292    if (FileSystem::Instance().IsDirectory(file))293      user_exe_path_is_bundle = true;294 295    if (file.IsRelative() && !user_exe_path.empty()) {296      llvm::SmallString<64> cwd;297      if (! llvm::sys::fs::current_path(cwd)) {298        FileSpec cwd_file(cwd.c_str());299        cwd_file.AppendPathComponent(file);300        if (FileSystem::Instance().Exists(cwd_file))301          file = cwd_file;302      }303    }304 305    ModuleSP exe_module_sp;306    if (platform_sp) {307      ModuleSpec module_spec(file, arch);308      module_spec.SetTarget(target_sp);309      error = platform_sp->ResolveExecutable(module_spec, exe_module_sp);310    }311 312    if (error.Success() && exe_module_sp) {313      if (exe_module_sp->GetObjectFile() == nullptr) {314        if (arch.IsValid()) {315          error = Status::FromErrorStringWithFormat(316              "\"%s\" doesn't contain architecture %s", file.GetPath().c_str(),317              arch.GetArchitectureName());318        } else {319          error = Status::FromErrorStringWithFormat(320              "unsupported file type \"%s\"", file.GetPath().c_str());321        }322        return error;323      }324      target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));325      debugger.GetTargetList().RegisterInProcessTarget(target_sp);326      target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);327      if (user_exe_path_is_bundle)328        exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,329                                             sizeof(resolved_bundle_exe_path));330      if (target_sp->GetPreloadSymbols())331        exe_module_sp->PreloadSymbols();332    }333  } else {334    // No file was specified, just create an empty target with any arch if a335    // valid arch was specified336    target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));337    debugger.GetTargetList().RegisterInProcessTarget(target_sp);338  }339 340  if (!target_sp)341    return error;342 343  // Set argv0 with what the user typed, unless the user specified a344  // directory. If the user specified a directory, then it is probably a345  // bundle that was resolved and we need to use the resolved bundle path346  if (!user_exe_path.empty()) {347    // Use exactly what the user typed as the first argument when we exec or348    // posix_spawn349    if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) {350      target_sp->SetArg0(resolved_bundle_exe_path);351    } else {352      // Use resolved path353      target_sp->SetArg0(file.GetPath().c_str());354    }355  }356  if (file.GetDirectory()) {357    FileSpec file_dir;358    file_dir.SetDirectory(file.GetDirectory());359    target_sp->AppendExecutableSearchPaths(file_dir);360  }361 362  // Now prime this from the dummy target:363  target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget());364 365  return error;366}367 368bool TargetList::DeleteTarget(TargetSP &target_sp) {369  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);370  auto it = llvm::find(m_target_list, target_sp);371  if (it == m_target_list.end())372    return false;373 374  m_target_list.erase(it);375  return true;376}377 378TargetSP TargetList::FindTargetWithExecutableAndArchitecture(379    const FileSpec &exe_file_spec, const ArchSpec *exe_arch_ptr) const {380  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);381  auto it = llvm::find_if(382      m_target_list, [&exe_file_spec, exe_arch_ptr](const TargetSP &item) {383        Module *exe_module = item->GetExecutableModulePointer();384        if (!exe_module ||385            !FileSpec::Match(exe_file_spec, exe_module->GetFileSpec()))386          return false;387 388        return !exe_arch_ptr ||389               exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture());390      });391 392  if (it != m_target_list.end())393    return *it;394 395  return TargetSP();396}397 398TargetSP TargetList::FindTargetWithProcessID(lldb::pid_t pid) const {399  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);400  auto it = llvm::find_if(m_target_list, [pid](const TargetSP &item) {401    auto *process_ptr = item->GetProcessSP().get();402    return process_ptr && (process_ptr->GetID() == pid);403  });404 405  if (it != m_target_list.end())406    return *it;407 408  return TargetSP();409}410 411TargetSP TargetList::FindTargetWithProcess(Process *process) const {412  TargetSP target_sp;413  if (!process)414    return target_sp;415 416  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);417  auto it = llvm::find_if(m_target_list, [process](const TargetSP &item) {418    return item->GetProcessSP().get() == process;419  });420 421  if (it != m_target_list.end())422    target_sp = *it;423 424  return target_sp;425}426 427TargetSP TargetList::FindTargetByGloballyUniqueID(lldb::user_id_t id) const {428  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);429  auto it = llvm::find_if(m_target_list, [id](const TargetSP &item) {430    return item->GetGloballyUniqueID() == id;431  });432 433  if (it != m_target_list.end())434    return *it;435 436  return TargetSP();437}438 439TargetSP TargetList::GetTargetSP(Target *target) const {440  TargetSP target_sp;441  if (!target)442    return target_sp;443 444  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);445  auto it = llvm::find_if(m_target_list, [target](const TargetSP &item) {446    return item.get() == target;447  });448  if (it != m_target_list.end())449    target_sp = *it;450 451  return target_sp;452}453 454uint32_t TargetList::SendAsyncInterrupt(lldb::pid_t pid) {455  uint32_t num_async_interrupts_sent = 0;456 457  if (pid != LLDB_INVALID_PROCESS_ID) {458    TargetSP target_sp(FindTargetWithProcessID(pid));459    if (target_sp) {460      Process *process = target_sp->GetProcessSP().get();461      if (process) {462        process->SendAsyncInterrupt();463        ++num_async_interrupts_sent;464      }465    }466  } else {467    // We don't have a valid pid to broadcast to, so broadcast to the target468    // list's async broadcaster...469    BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr);470  }471 472  return num_async_interrupts_sent;473}474 475uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) {476  uint32_t num_signals_sent = 0;477  Process *process = nullptr;478  if (pid == LLDB_INVALID_PROCESS_ID) {479    // Signal all processes with signal480    std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);481    for (const auto &target_sp : m_target_list) {482      process = target_sp->GetProcessSP().get();483      if (process && process->IsAlive()) {484        ++num_signals_sent;485        process->Signal(signo);486      }487    }488  } else {489    // Signal a specific process with signal490    TargetSP target_sp(FindTargetWithProcessID(pid));491    if (target_sp) {492      process = target_sp->GetProcessSP().get();493      if (process && process->IsAlive()) {494        ++num_signals_sent;495        process->Signal(signo);496      }497    }498  }499  return num_signals_sent;500}501 502size_t TargetList::GetNumTargets() const {503  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);504  return m_target_list.size();505}506 507lldb::TargetSP TargetList::GetTargetAtIndex(uint32_t idx) const {508  TargetSP target_sp;509  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);510  if (idx < m_target_list.size())511    target_sp = m_target_list[idx];512  return target_sp;513}514 515uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const {516  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);517  auto it = llvm::find(m_target_list, target_sp);518  if (it != m_target_list.end())519    return std::distance(m_target_list.begin(), it);520  return UINT32_MAX;521}522 523void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {524  lldbassert(!llvm::is_contained(m_target_list, target_sp) &&525             "target already exists it the list");526  UnregisterInProcessTarget(target_sp);527  m_target_list.push_back(std::move(target_sp));528  if (do_select)529    SetSelectedTargetInternal(m_target_list.size() - 1);530}531 532void TargetList::SetSelectedTargetInternal(uint32_t index) {533  lldbassert(!m_target_list.empty());534  m_selected_target_idx = index < m_target_list.size() ? index : 0;535}536 537void TargetList::SetSelectedTarget(uint32_t index) {538  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);539  SetSelectedTargetInternal(index);540}541 542void TargetList::SetSelectedTarget(const TargetSP &target_sp) {543  // Don't allow an invalid target shared pointer or a target that has been544  // destroyed to become the selected target.545  if (target_sp && target_sp->IsValid()) {546    std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);547    auto it = llvm::find(m_target_list, target_sp);548    SetSelectedTargetInternal(std::distance(m_target_list.begin(), it));549  }550}551 552lldb::TargetSP TargetList::GetSelectedTarget() {553  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);554  if (m_selected_target_idx >= m_target_list.size())555    m_selected_target_idx = 0;556  return GetTargetAtIndex(m_selected_target_idx);557}558 559bool TargetList::AnyTargetContainsModule(Module &module) {560  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);561  for (const auto &target_sp : m_target_list) {562    if (target_sp->GetImages().FindModule(&module))563      return true;564  }565  for (const auto &target_sp: m_in_process_target_list) {566    if (target_sp->GetImages().FindModule(&module))567      return true;568  }569  return false;570}571 572  void TargetList::RegisterInProcessTarget(TargetSP target_sp) {573    std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);574    [[maybe_unused]] bool was_added;575    std::tie(std::ignore, was_added) =576        m_in_process_target_list.insert(target_sp);577    assert(was_added && "Target pointer was left in the in-process map");578  }579  580  void TargetList::UnregisterInProcessTarget(TargetSP target_sp) {581    std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);582    [[maybe_unused]] bool was_present =583        m_in_process_target_list.erase(target_sp);584    assert(was_present && "Target pointer being removed was not registered");585  }586  587  bool TargetList::IsTargetInProcess(TargetSP target_sp) {588    std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);589    return m_in_process_target_list.count(target_sp) == 1; 590  }591