TargetList.cpp revision 360784
1//===-- TargetList.cpp ------------------------------------------*- C++ -*-===//
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-exception
6//
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
32ConstString &TargetList::GetStaticBroadcasterClass() {
33  static ConstString class_name("lldb.targetList");
34  return class_name;
35}
36
37// TargetList constructor
38TargetList::TargetList(Debugger &debugger)
39    : Broadcaster(debugger.GetBroadcasterManager(),
40                  TargetList::GetStaticBroadcasterClass().AsCString()),
41      m_target_list(), m_target_list_mutex(), m_selected_target_idx(0) {
42  CheckInWithManager();
43}
44
45// Destructor
46TargetList::~TargetList() {
47  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
48  m_target_list.clear();
49}
50
51Status TargetList::CreateTarget(Debugger &debugger,
52                                llvm::StringRef user_exe_path,
53                                llvm::StringRef triple_str,
54                                LoadDependentFiles load_dependent_files,
55                                const OptionGroupPlatform *platform_options,
56                                TargetSP &target_sp) {
57  return CreateTargetInternal(debugger, user_exe_path, triple_str,
58                              load_dependent_files, platform_options, target_sp,
59                              false);
60}
61
62Status TargetList::CreateTarget(Debugger &debugger,
63                                llvm::StringRef user_exe_path,
64                                const ArchSpec &specified_arch,
65                                LoadDependentFiles load_dependent_files,
66                                PlatformSP &platform_sp, TargetSP &target_sp) {
67  return CreateTargetInternal(debugger, user_exe_path, specified_arch,
68                              load_dependent_files, platform_sp, target_sp,
69                              false);
70}
71
72Status TargetList::CreateTargetInternal(
73    Debugger &debugger, llvm::StringRef user_exe_path,
74    llvm::StringRef triple_str, LoadDependentFiles load_dependent_files,
75    const OptionGroupPlatform *platform_options, TargetSP &target_sp,
76    bool is_dummy_target) {
77  Status error;
78  PlatformSP platform_sp;
79
80  // This is purposely left empty unless it is specified by triple_cstr. If not
81  // initialized via triple_cstr, then the currently selected platform will set
82  // the architecture correctly.
83  const ArchSpec arch(triple_str);
84  if (!triple_str.empty()) {
85    if (!arch.IsValid()) {
86      error.SetErrorStringWithFormat("invalid triple '%s'",
87                                     triple_str.str().c_str());
88      return error;
89    }
90  }
91
92  ArchSpec platform_arch(arch);
93
94  bool prefer_platform_arch = false;
95
96  CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
97
98  // let's see if there is already an existing platform before we go creating
99  // another...
100  platform_sp = debugger.GetPlatformList().GetSelectedPlatform();
101
102  if (platform_options && platform_options->PlatformWasSpecified()) {
103    // Create a new platform if it doesn't match the selected platform
104    if (!platform_options->PlatformMatches(platform_sp)) {
105      const bool select_platform = true;
106      platform_sp = platform_options->CreatePlatformWithOptions(
107          interpreter, arch, select_platform, error, platform_arch);
108      if (!platform_sp)
109        return error;
110    }
111  }
112
113  if (!user_exe_path.empty()) {
114    ModuleSpecList module_specs;
115    ModuleSpec module_spec;
116    module_spec.GetFileSpec().SetFile(user_exe_path, FileSpec::Style::native);
117    FileSystem::Instance().Resolve(module_spec.GetFileSpec());
118
119    // Resolve the executable in case we are given a path to a application
120    // bundle like a .app bundle on MacOSX
121    Host::ResolveExecutableInBundle(module_spec.GetFileSpec());
122
123    lldb::offset_t file_offset = 0;
124    lldb::offset_t file_size = 0;
125    const size_t num_specs = ObjectFile::GetModuleSpecifications(
126        module_spec.GetFileSpec(), file_offset, file_size, module_specs);
127    if (num_specs > 0) {
128      ModuleSpec matching_module_spec;
129
130      if (num_specs == 1) {
131        if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) {
132          if (platform_arch.IsValid()) {
133            if (platform_arch.IsCompatibleMatch(
134                    matching_module_spec.GetArchitecture())) {
135              // If the OS or vendor weren't specified, then adopt the module's
136              // architecture so that the platform matching can be more
137              // accurate
138              if (!platform_arch.TripleOSWasSpecified() ||
139                  !platform_arch.TripleVendorWasSpecified()) {
140                prefer_platform_arch = true;
141                platform_arch = matching_module_spec.GetArchitecture();
142              }
143            } else {
144              StreamString platform_arch_strm;
145              StreamString module_arch_strm;
146
147              platform_arch.DumpTriple(platform_arch_strm.AsRawOstream());
148              matching_module_spec.GetArchitecture().DumpTriple(
149                  module_arch_strm.AsRawOstream());
150              error.SetErrorStringWithFormat(
151                  "the specified architecture '%s' is not compatible with '%s' "
152                  "in '%s'",
153                  platform_arch_strm.GetData(), module_arch_strm.GetData(),
154                  module_spec.GetFileSpec().GetPath().c_str());
155              return error;
156            }
157          } else {
158            // Only one arch and none was specified
159            prefer_platform_arch = true;
160            platform_arch = matching_module_spec.GetArchitecture();
161          }
162        }
163      } else {
164        if (arch.IsValid()) {
165          module_spec.GetArchitecture() = arch;
166          if (module_specs.FindMatchingModuleSpec(module_spec,
167                                                  matching_module_spec)) {
168            prefer_platform_arch = true;
169            platform_arch = matching_module_spec.GetArchitecture();
170          }
171        } else {
172          // No architecture specified, check if there is only one platform for
173          // all of the architectures.
174
175          typedef std::vector<PlatformSP> PlatformList;
176          PlatformList platforms;
177          PlatformSP host_platform_sp = Platform::GetHostPlatform();
178          for (size_t i = 0; i < num_specs; ++i) {
179            ModuleSpec module_spec;
180            if (module_specs.GetModuleSpecAtIndex(i, module_spec)) {
181              // See if there was a selected platform and check that first
182              // since the user may have specified it.
183              if (platform_sp) {
184                if (platform_sp->IsCompatibleArchitecture(
185                        module_spec.GetArchitecture(), false, nullptr)) {
186                  platforms.push_back(platform_sp);
187                  continue;
188                }
189              }
190
191              // Next check the host platform it if wasn't already checked
192              // above
193              if (host_platform_sp &&
194                  (!platform_sp ||
195                   host_platform_sp->GetName() != platform_sp->GetName())) {
196                if (host_platform_sp->IsCompatibleArchitecture(
197                        module_spec.GetArchitecture(), false, nullptr)) {
198                  platforms.push_back(host_platform_sp);
199                  continue;
200                }
201              }
202
203              // Just find a platform that matches the architecture in the
204              // executable file
205              PlatformSP fallback_platform_sp(
206                  Platform::GetPlatformForArchitecture(
207                      module_spec.GetArchitecture(), nullptr));
208              if (fallback_platform_sp) {
209                platforms.push_back(fallback_platform_sp);
210              }
211            }
212          }
213
214          Platform *platform_ptr = nullptr;
215          bool more_than_one_platforms = false;
216          for (const auto &the_platform_sp : platforms) {
217            if (platform_ptr) {
218              if (platform_ptr->GetName() != the_platform_sp->GetName()) {
219                more_than_one_platforms = true;
220                platform_ptr = nullptr;
221                break;
222              }
223            } else {
224              platform_ptr = the_platform_sp.get();
225            }
226          }
227
228          if (platform_ptr) {
229            // All platforms for all modules in the executable match, so we can
230            // select this platform
231            platform_sp = platforms.front();
232          } else if (!more_than_one_platforms) {
233            // No platforms claim to support this file
234            error.SetErrorString("No matching platforms found for this file, "
235                                 "specify one with the --platform option");
236            return error;
237          } else {
238            // More than one platform claims to support this file, so the
239            // --platform option must be specified
240            StreamString error_strm;
241            std::set<Platform *> platform_set;
242            error_strm.Printf(
243                "more than one platform supports this executable (");
244            for (const auto &the_platform_sp : platforms) {
245              if (platform_set.find(the_platform_sp.get()) ==
246                  platform_set.end()) {
247                if (!platform_set.empty())
248                  error_strm.PutCString(", ");
249                error_strm.PutCString(the_platform_sp->GetName().GetCString());
250                platform_set.insert(the_platform_sp.get());
251              }
252            }
253            error_strm.Printf(
254                "), use the --platform option to specify a platform");
255            error.SetErrorString(error_strm.GetString());
256            return error;
257          }
258        }
259      }
260    }
261  }
262
263  // If we have a valid architecture, make sure the current platform is
264  // compatible with that architecture
265  if (!prefer_platform_arch && arch.IsValid()) {
266    if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) {
267      platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
268      if (!is_dummy_target && platform_sp)
269        debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
270    }
271  } else if (platform_arch.IsValid()) {
272    // if "arch" isn't valid, yet "platform_arch" is, it means we have an
273    // executable file with a single architecture which should be used
274    ArchSpec fixed_platform_arch;
275    if (!platform_sp->IsCompatibleArchitecture(platform_arch, false,
276                                               &fixed_platform_arch)) {
277      platform_sp = Platform::GetPlatformForArchitecture(platform_arch,
278                                                         &fixed_platform_arch);
279      if (!is_dummy_target && platform_sp)
280        debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
281    }
282  }
283
284  if (!platform_arch.IsValid())
285    platform_arch = arch;
286
287  error = TargetList::CreateTargetInternal(
288      debugger, user_exe_path, platform_arch, load_dependent_files, platform_sp,
289      target_sp, is_dummy_target);
290  return error;
291}
292
293lldb::TargetSP TargetList::GetDummyTarget(lldb_private::Debugger &debugger) {
294  // FIXME: Maybe the dummy target should be per-Debugger
295  if (!m_dummy_target_sp || !m_dummy_target_sp->IsValid()) {
296    ArchSpec arch(Target::GetDefaultArchitecture());
297    if (!arch.IsValid())
298      arch = HostInfo::GetArchitecture();
299    Status err = CreateDummyTarget(
300        debugger, arch.GetTriple().getTriple().c_str(), m_dummy_target_sp);
301  }
302
303  return m_dummy_target_sp;
304}
305
306Status TargetList::CreateDummyTarget(Debugger &debugger,
307                                     llvm::StringRef specified_arch_name,
308                                     lldb::TargetSP &target_sp) {
309  PlatformSP host_platform_sp(Platform::GetHostPlatform());
310  return CreateTargetInternal(
311      debugger, (const char *)nullptr, specified_arch_name, eLoadDependentsNo,
312      (const OptionGroupPlatform *)nullptr, target_sp, true);
313}
314
315Status TargetList::CreateTargetInternal(Debugger &debugger,
316                                        llvm::StringRef user_exe_path,
317                                        const ArchSpec &specified_arch,
318                                        LoadDependentFiles load_dependent_files,
319                                        lldb::PlatformSP &platform_sp,
320                                        lldb::TargetSP &target_sp,
321                                        bool is_dummy_target) {
322  static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
323  Timer scoped_timer(
324      func_cat, "TargetList::CreateTarget (file = '%s', arch = '%s')",
325      user_exe_path.str().c_str(), specified_arch.GetArchitectureName());
326  Status error;
327
328  ArchSpec arch(specified_arch);
329
330  if (arch.IsValid()) {
331    if (!platform_sp ||
332        !platform_sp->IsCompatibleArchitecture(arch, false, nullptr))
333      platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
334  }
335
336  if (!platform_sp)
337    platform_sp = debugger.GetPlatformList().GetSelectedPlatform();
338
339  if (!arch.IsValid())
340    arch = specified_arch;
341
342  FileSpec file(user_exe_path);
343  if (!FileSystem::Instance().Exists(file) && user_exe_path.startswith("~")) {
344    // we want to expand the tilde but we don't want to resolve any symbolic
345    // links so we can't use the FileSpec constructor's resolve flag
346    llvm::SmallString<64> unglobbed_path;
347    StandardTildeExpressionResolver Resolver;
348    Resolver.ResolveFullPath(user_exe_path, unglobbed_path);
349
350    if (unglobbed_path.empty())
351      file = FileSpec(user_exe_path);
352    else
353      file = FileSpec(unglobbed_path.c_str());
354  }
355
356  bool user_exe_path_is_bundle = false;
357  char resolved_bundle_exe_path[PATH_MAX];
358  resolved_bundle_exe_path[0] = '\0';
359  if (file) {
360    if (FileSystem::Instance().IsDirectory(file))
361      user_exe_path_is_bundle = true;
362
363    if (file.IsRelative() && !user_exe_path.empty()) {
364      llvm::SmallString<64> cwd;
365      if (! llvm::sys::fs::current_path(cwd)) {
366        FileSpec cwd_file(cwd.c_str());
367        cwd_file.AppendPathComponent(file);
368        if (FileSystem::Instance().Exists(cwd_file))
369          file = cwd_file;
370      }
371    }
372
373    ModuleSP exe_module_sp;
374    if (platform_sp) {
375      FileSpecList executable_search_paths(
376          Target::GetDefaultExecutableSearchPaths());
377      ModuleSpec module_spec(file, arch);
378      error = platform_sp->ResolveExecutable(module_spec, exe_module_sp,
379                                             executable_search_paths.GetSize()
380                                                 ? &executable_search_paths
381                                                 : nullptr);
382    }
383
384    if (error.Success() && exe_module_sp) {
385      if (exe_module_sp->GetObjectFile() == nullptr) {
386        if (arch.IsValid()) {
387          error.SetErrorStringWithFormat(
388              "\"%s\" doesn't contain architecture %s", file.GetPath().c_str(),
389              arch.GetArchitectureName());
390        } else {
391          error.SetErrorStringWithFormat("unsupported file type \"%s\"",
392                                         file.GetPath().c_str());
393        }
394        return error;
395      }
396      target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
397      target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
398      if (user_exe_path_is_bundle)
399        exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
400                                             sizeof(resolved_bundle_exe_path));
401    }
402  } else {
403    // No file was specified, just create an empty target with any arch if a
404    // valid arch was specified
405    target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
406  }
407
408  if (target_sp) {
409    // Set argv0 with what the user typed, unless the user specified a
410    // directory. If the user specified a directory, then it is probably a
411    // bundle that was resolved and we need to use the resolved bundle path
412    if (!user_exe_path.empty()) {
413      // Use exactly what the user typed as the first argument when we exec or
414      // posix_spawn
415      if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) {
416        target_sp->SetArg0(resolved_bundle_exe_path);
417      } else {
418        // Use resolved path
419        target_sp->SetArg0(file.GetPath().c_str());
420      }
421    }
422    if (file.GetDirectory()) {
423      FileSpec file_dir;
424      file_dir.GetDirectory() = file.GetDirectory();
425      target_sp->AppendExecutableSearchPaths(file_dir);
426    }
427
428    // Don't put the dummy target in the target list, it's held separately.
429    if (!is_dummy_target) {
430      std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
431      m_selected_target_idx = m_target_list.size();
432      m_target_list.push_back(target_sp);
433      // Now prime this from the dummy target:
434      target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget());
435    } else {
436      m_dummy_target_sp = target_sp;
437    }
438  }
439
440  return error;
441}
442
443bool TargetList::DeleteTarget(TargetSP &target_sp) {
444  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
445  collection::iterator pos, end = m_target_list.end();
446
447  for (pos = m_target_list.begin(); pos != end; ++pos) {
448    if (pos->get() == target_sp.get()) {
449      m_target_list.erase(pos);
450      return true;
451    }
452  }
453  return false;
454}
455
456TargetSP TargetList::FindTargetWithExecutableAndArchitecture(
457    const FileSpec &exe_file_spec, const ArchSpec *exe_arch_ptr) const {
458  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
459  TargetSP target_sp;
460  collection::const_iterator pos, end = m_target_list.end();
461  for (pos = m_target_list.begin(); pos != end; ++pos) {
462    Module *exe_module = (*pos)->GetExecutableModulePointer();
463
464    if (exe_module) {
465      if (FileSpec::Match(exe_file_spec, exe_module->GetFileSpec())) {
466        if (exe_arch_ptr) {
467          if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture()))
468            continue;
469        }
470        target_sp = *pos;
471        break;
472      }
473    }
474  }
475  return target_sp;
476}
477
478TargetSP TargetList::FindTargetWithProcessID(lldb::pid_t pid) const {
479  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
480  TargetSP target_sp;
481  collection::const_iterator pos, end = m_target_list.end();
482  for (pos = m_target_list.begin(); pos != end; ++pos) {
483    Process *process = (*pos)->GetProcessSP().get();
484    if (process && process->GetID() == pid) {
485      target_sp = *pos;
486      break;
487    }
488  }
489  return target_sp;
490}
491
492TargetSP TargetList::FindTargetWithProcess(Process *process) const {
493  TargetSP target_sp;
494  if (process) {
495    std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
496    collection::const_iterator pos, end = m_target_list.end();
497    for (pos = m_target_list.begin(); pos != end; ++pos) {
498      if (process == (*pos)->GetProcessSP().get()) {
499        target_sp = *pos;
500        break;
501      }
502    }
503  }
504  return target_sp;
505}
506
507TargetSP TargetList::GetTargetSP(Target *target) const {
508  TargetSP target_sp;
509  if (target) {
510    std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
511    collection::const_iterator pos, end = m_target_list.end();
512    for (pos = m_target_list.begin(); pos != end; ++pos) {
513      if (target == (*pos).get()) {
514        target_sp = *pos;
515        break;
516      }
517    }
518  }
519  return target_sp;
520}
521
522uint32_t TargetList::SendAsyncInterrupt(lldb::pid_t pid) {
523  uint32_t num_async_interrupts_sent = 0;
524
525  if (pid != LLDB_INVALID_PROCESS_ID) {
526    TargetSP target_sp(FindTargetWithProcessID(pid));
527    if (target_sp) {
528      Process *process = target_sp->GetProcessSP().get();
529      if (process) {
530        process->SendAsyncInterrupt();
531        ++num_async_interrupts_sent;
532      }
533    }
534  } else {
535    // We don't have a valid pid to broadcast to, so broadcast to the target
536    // list's async broadcaster...
537    BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr);
538  }
539
540  return num_async_interrupts_sent;
541}
542
543uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) {
544  uint32_t num_signals_sent = 0;
545  Process *process = nullptr;
546  if (pid == LLDB_INVALID_PROCESS_ID) {
547    // Signal all processes with signal
548    std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
549    collection::iterator pos, end = m_target_list.end();
550    for (pos = m_target_list.begin(); pos != end; ++pos) {
551      process = (*pos)->GetProcessSP().get();
552      if (process) {
553        if (process->IsAlive()) {
554          ++num_signals_sent;
555          process->Signal(signo);
556        }
557      }
558    }
559  } else {
560    // Signal a specific process with signal
561    TargetSP target_sp(FindTargetWithProcessID(pid));
562    if (target_sp) {
563      process = target_sp->GetProcessSP().get();
564      if (process) {
565        if (process->IsAlive()) {
566          ++num_signals_sent;
567          process->Signal(signo);
568        }
569      }
570    }
571  }
572  return num_signals_sent;
573}
574
575int TargetList::GetNumTargets() const {
576  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
577  return m_target_list.size();
578}
579
580lldb::TargetSP TargetList::GetTargetAtIndex(uint32_t idx) const {
581  TargetSP target_sp;
582  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
583  if (idx < m_target_list.size())
584    target_sp = m_target_list[idx];
585  return target_sp;
586}
587
588uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const {
589  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
590  size_t num_targets = m_target_list.size();
591  for (size_t idx = 0; idx < num_targets; idx++) {
592    if (target_sp == m_target_list[idx])
593      return idx;
594  }
595  return UINT32_MAX;
596}
597
598uint32_t TargetList::SetSelectedTarget(Target *target) {
599  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
600  collection::const_iterator pos, begin = m_target_list.begin(),
601                                  end = m_target_list.end();
602  for (pos = begin; pos != end; ++pos) {
603    if (pos->get() == target) {
604      m_selected_target_idx = std::distance(begin, pos);
605      return m_selected_target_idx;
606    }
607  }
608  m_selected_target_idx = 0;
609  return m_selected_target_idx;
610}
611
612lldb::TargetSP TargetList::GetSelectedTarget() {
613  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
614  if (m_selected_target_idx >= m_target_list.size())
615    m_selected_target_idx = 0;
616  return GetTargetAtIndex(m_selected_target_idx);
617}
618