xref: /openbsd-src/gnu/llvm/lldb/source/Target/TargetList.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- TargetList.cpp ----------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Target/TargetList.h"
10061da546Spatrick #include "lldb/Core/Debugger.h"
11061da546Spatrick #include "lldb/Core/Module.h"
12061da546Spatrick #include "lldb/Core/ModuleSpec.h"
13061da546Spatrick #include "lldb/Host/Host.h"
14061da546Spatrick #include "lldb/Host/HostInfo.h"
15061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
16061da546Spatrick #include "lldb/Interpreter/OptionGroupPlatform.h"
17061da546Spatrick #include "lldb/Symbol/ObjectFile.h"
18061da546Spatrick #include "lldb/Target/Platform.h"
19061da546Spatrick #include "lldb/Target/Process.h"
20061da546Spatrick #include "lldb/Utility/Broadcaster.h"
21061da546Spatrick #include "lldb/Utility/Event.h"
22061da546Spatrick #include "lldb/Utility/State.h"
23061da546Spatrick #include "lldb/Utility/TildeExpressionResolver.h"
24061da546Spatrick #include "lldb/Utility/Timer.h"
25061da546Spatrick 
26061da546Spatrick #include "llvm/ADT/SmallString.h"
27061da546Spatrick #include "llvm/Support/FileSystem.h"
28061da546Spatrick 
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick 
GetStaticBroadcasterClass()32061da546Spatrick ConstString &TargetList::GetStaticBroadcasterClass() {
33061da546Spatrick   static ConstString class_name("lldb.targetList");
34061da546Spatrick   return class_name;
35061da546Spatrick }
36061da546Spatrick 
37061da546Spatrick // TargetList constructor
TargetList(Debugger & debugger)38061da546Spatrick TargetList::TargetList(Debugger &debugger)
39061da546Spatrick     : Broadcaster(debugger.GetBroadcasterManager(),
40061da546Spatrick                   TargetList::GetStaticBroadcasterClass().AsCString()),
41061da546Spatrick       m_target_list(), m_target_list_mutex(), m_selected_target_idx(0) {
42061da546Spatrick   CheckInWithManager();
43061da546Spatrick }
44061da546Spatrick 
CreateTarget(Debugger & debugger,llvm::StringRef user_exe_path,llvm::StringRef triple_str,LoadDependentFiles load_dependent_files,const OptionGroupPlatform * platform_options,TargetSP & target_sp)45061da546Spatrick Status TargetList::CreateTarget(Debugger &debugger,
46061da546Spatrick                                 llvm::StringRef user_exe_path,
47061da546Spatrick                                 llvm::StringRef triple_str,
48061da546Spatrick                                 LoadDependentFiles load_dependent_files,
49061da546Spatrick                                 const OptionGroupPlatform *platform_options,
50061da546Spatrick                                 TargetSP &target_sp) {
51be691f3bSpatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
52be691f3bSpatrick   auto result = TargetList::CreateTargetInternal(
53be691f3bSpatrick       debugger, user_exe_path, triple_str, load_dependent_files,
54be691f3bSpatrick       platform_options, target_sp);
55be691f3bSpatrick 
56be691f3bSpatrick   if (target_sp && result.Success())
57be691f3bSpatrick     AddTargetInternal(target_sp, /*do_select*/ true);
58be691f3bSpatrick   return result;
59061da546Spatrick }
60061da546Spatrick 
CreateTarget(Debugger & debugger,llvm::StringRef user_exe_path,const ArchSpec & specified_arch,LoadDependentFiles load_dependent_files,PlatformSP & platform_sp,TargetSP & target_sp)61061da546Spatrick Status TargetList::CreateTarget(Debugger &debugger,
62061da546Spatrick                                 llvm::StringRef user_exe_path,
63061da546Spatrick                                 const ArchSpec &specified_arch,
64061da546Spatrick                                 LoadDependentFiles load_dependent_files,
65061da546Spatrick                                 PlatformSP &platform_sp, TargetSP &target_sp) {
66be691f3bSpatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
67be691f3bSpatrick   auto result = TargetList::CreateTargetInternal(
68be691f3bSpatrick       debugger, user_exe_path, specified_arch, load_dependent_files,
69be691f3bSpatrick       platform_sp, target_sp);
70be691f3bSpatrick 
71be691f3bSpatrick   if (target_sp && result.Success())
72be691f3bSpatrick     AddTargetInternal(target_sp, /*do_select*/ true);
73be691f3bSpatrick   return result;
74061da546Spatrick }
75061da546Spatrick 
CreateTargetInternal(Debugger & debugger,llvm::StringRef user_exe_path,llvm::StringRef triple_str,LoadDependentFiles load_dependent_files,const OptionGroupPlatform * platform_options,TargetSP & target_sp)76061da546Spatrick Status TargetList::CreateTargetInternal(
77061da546Spatrick     Debugger &debugger, llvm::StringRef user_exe_path,
78061da546Spatrick     llvm::StringRef triple_str, LoadDependentFiles load_dependent_files,
79be691f3bSpatrick     const OptionGroupPlatform *platform_options, TargetSP &target_sp) {
80061da546Spatrick   Status error;
81061da546Spatrick 
82*f6aab3d8Srobert   PlatformList &platform_list = debugger.GetPlatformList();
83be691f3bSpatrick   // Let's start by looking at the selected platform.
84*f6aab3d8Srobert   PlatformSP platform_sp = platform_list.GetSelectedPlatform();
85be691f3bSpatrick 
86be691f3bSpatrick   // This variable corresponds to the architecture specified by the triple
87be691f3bSpatrick   // string. If that string was empty the currently selected platform will
88be691f3bSpatrick   // determine the architecture.
89061da546Spatrick   const ArchSpec arch(triple_str);
90be691f3bSpatrick   if (!triple_str.empty() && !arch.IsValid()) {
91061da546Spatrick     error.SetErrorStringWithFormat("invalid triple '%s'",
92061da546Spatrick                                    triple_str.str().c_str());
93061da546Spatrick     return error;
94061da546Spatrick   }
95061da546Spatrick 
96061da546Spatrick   ArchSpec platform_arch(arch);
97061da546Spatrick 
98be691f3bSpatrick   // Create a new platform if a platform was specified in the platform options
99be691f3bSpatrick   // and doesn't match the selected platform.
100be691f3bSpatrick   if (platform_options && platform_options->PlatformWasSpecified() &&
101be691f3bSpatrick       !platform_options->PlatformMatches(platform_sp)) {
102061da546Spatrick     const bool select_platform = true;
103061da546Spatrick     platform_sp = platform_options->CreatePlatformWithOptions(
104be691f3bSpatrick         debugger.GetCommandInterpreter(), arch, select_platform, error,
105be691f3bSpatrick         platform_arch);
106061da546Spatrick     if (!platform_sp)
107061da546Spatrick       return error;
108061da546Spatrick   }
109be691f3bSpatrick 
110be691f3bSpatrick   bool prefer_platform_arch = false;
111be691f3bSpatrick   auto update_platform_arch = [&](const ArchSpec &module_arch) {
112be691f3bSpatrick     // If the OS or vendor weren't specified, then adopt the module's
113be691f3bSpatrick     // architecture so that the platform matching can be more accurate.
114be691f3bSpatrick     if (!platform_arch.TripleOSWasSpecified() ||
115be691f3bSpatrick         !platform_arch.TripleVendorWasSpecified()) {
116be691f3bSpatrick       prefer_platform_arch = true;
117be691f3bSpatrick       platform_arch = module_arch;
118061da546Spatrick     }
119be691f3bSpatrick   };
120061da546Spatrick 
121061da546Spatrick   if (!user_exe_path.empty()) {
122be691f3bSpatrick     ModuleSpec module_spec(FileSpec(user_exe_path, FileSpec::Style::native));
123061da546Spatrick     FileSystem::Instance().Resolve(module_spec.GetFileSpec());
124*f6aab3d8Srobert 
125*f6aab3d8Srobert     // Try to resolve the exe based on PATH and/or platform-specific suffixes,
126*f6aab3d8Srobert     // but only if using the host platform.
127*f6aab3d8Srobert     if (platform_sp->IsHost() &&
128*f6aab3d8Srobert         !FileSystem::Instance().Exists(module_spec.GetFileSpec()))
129*f6aab3d8Srobert       FileSystem::Instance().ResolveExecutableLocation(
130*f6aab3d8Srobert           module_spec.GetFileSpec());
131*f6aab3d8Srobert 
132061da546Spatrick     // Resolve the executable in case we are given a path to a application
133be691f3bSpatrick     // bundle like a .app bundle on MacOSX.
134061da546Spatrick     Host::ResolveExecutableInBundle(module_spec.GetFileSpec());
135061da546Spatrick 
136061da546Spatrick     lldb::offset_t file_offset = 0;
137061da546Spatrick     lldb::offset_t file_size = 0;
138be691f3bSpatrick     ModuleSpecList module_specs;
139061da546Spatrick     const size_t num_specs = ObjectFile::GetModuleSpecifications(
140061da546Spatrick         module_spec.GetFileSpec(), file_offset, file_size, module_specs);
141be691f3bSpatrick 
142061da546Spatrick     if (num_specs > 0) {
143061da546Spatrick       ModuleSpec matching_module_spec;
144061da546Spatrick 
145061da546Spatrick       if (num_specs == 1) {
146061da546Spatrick         if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) {
147061da546Spatrick           if (platform_arch.IsValid()) {
148061da546Spatrick             if (platform_arch.IsCompatibleMatch(
149061da546Spatrick                     matching_module_spec.GetArchitecture())) {
150061da546Spatrick               // If the OS or vendor weren't specified, then adopt the module's
151061da546Spatrick               // architecture so that the platform matching can be more
152be691f3bSpatrick               // accurate.
153be691f3bSpatrick               update_platform_arch(matching_module_spec.GetArchitecture());
154061da546Spatrick             } else {
155061da546Spatrick               StreamString platform_arch_strm;
156061da546Spatrick               StreamString module_arch_strm;
157061da546Spatrick 
158061da546Spatrick               platform_arch.DumpTriple(platform_arch_strm.AsRawOstream());
159061da546Spatrick               matching_module_spec.GetArchitecture().DumpTriple(
160061da546Spatrick                   module_arch_strm.AsRawOstream());
161061da546Spatrick               error.SetErrorStringWithFormat(
162061da546Spatrick                   "the specified architecture '%s' is not compatible with '%s' "
163061da546Spatrick                   "in '%s'",
164061da546Spatrick                   platform_arch_strm.GetData(), module_arch_strm.GetData(),
165061da546Spatrick                   module_spec.GetFileSpec().GetPath().c_str());
166061da546Spatrick               return error;
167061da546Spatrick             }
168061da546Spatrick           } else {
169be691f3bSpatrick             // Only one arch and none was specified.
170061da546Spatrick             prefer_platform_arch = true;
171061da546Spatrick             platform_arch = matching_module_spec.GetArchitecture();
172061da546Spatrick           }
173061da546Spatrick         }
174be691f3bSpatrick       } else if (arch.IsValid()) {
175be691f3bSpatrick         // Fat binary. A (valid) architecture was specified.
176061da546Spatrick         module_spec.GetArchitecture() = arch;
177061da546Spatrick         if (module_specs.FindMatchingModuleSpec(module_spec,
178be691f3bSpatrick                                                 matching_module_spec))
179be691f3bSpatrick             update_platform_arch(matching_module_spec.GetArchitecture());
180061da546Spatrick       } else {
181be691f3bSpatrick         // Fat binary. No architecture specified, check if there is
182be691f3bSpatrick         // only one platform for all of the architectures.
183*f6aab3d8Srobert         std::vector<PlatformSP> candidates;
184*f6aab3d8Srobert         std::vector<ArchSpec> archs;
185*f6aab3d8Srobert         for (const ModuleSpec &spec : module_specs.ModuleSpecs())
186*f6aab3d8Srobert           archs.push_back(spec.GetArchitecture());
187*f6aab3d8Srobert         if (PlatformSP platform_for_archs_sp =
188*f6aab3d8Srobert                 platform_list.GetOrCreate(archs, {}, candidates)) {
189*f6aab3d8Srobert           platform_sp = platform_for_archs_sp;
190*f6aab3d8Srobert         } else if (candidates.empty()) {
191be691f3bSpatrick           error.SetErrorString("no matching platforms found for this file");
192061da546Spatrick           return error;
193061da546Spatrick         } else {
194be691f3bSpatrick           // More than one platform claims to support this file.
195061da546Spatrick           StreamString error_strm;
196*f6aab3d8Srobert           std::set<llvm::StringRef> platform_set;
197061da546Spatrick           error_strm.Printf(
198061da546Spatrick               "more than one platform supports this executable (");
199*f6aab3d8Srobert           for (const auto &candidate : candidates) {
200*f6aab3d8Srobert             llvm::StringRef platform_name = candidate->GetName();
201*f6aab3d8Srobert             if (platform_set.count(platform_name))
202*f6aab3d8Srobert               continue;
203061da546Spatrick             if (!platform_set.empty())
204061da546Spatrick               error_strm.PutCString(", ");
205*f6aab3d8Srobert             error_strm.PutCString(platform_name);
206*f6aab3d8Srobert             platform_set.insert(platform_name);
207061da546Spatrick           }
208be691f3bSpatrick           error_strm.Printf("), specify an architecture to disambiguate");
209061da546Spatrick           error.SetErrorString(error_strm.GetString());
210061da546Spatrick           return error;
211061da546Spatrick         }
212061da546Spatrick       }
213061da546Spatrick     }
214061da546Spatrick   }
215061da546Spatrick 
216061da546Spatrick   // If we have a valid architecture, make sure the current platform is
217be691f3bSpatrick   // compatible with that architecture.
218061da546Spatrick   if (!prefer_platform_arch && arch.IsValid()) {
219*f6aab3d8Srobert     if (!platform_sp->IsCompatibleArchitecture(
220*f6aab3d8Srobert             arch, {}, ArchSpec::CompatibleMatch, nullptr)) {
221*f6aab3d8Srobert       platform_sp = platform_list.GetOrCreate(arch, {}, &platform_arch);
222be691f3bSpatrick       if (platform_sp)
223*f6aab3d8Srobert         platform_list.SetSelectedPlatform(platform_sp);
224061da546Spatrick     }
225061da546Spatrick   } else if (platform_arch.IsValid()) {
226be691f3bSpatrick     // If "arch" isn't valid, yet "platform_arch" is, it means we have an
227be691f3bSpatrick     // executable file with a single architecture which should be used.
228061da546Spatrick     ArchSpec fixed_platform_arch;
229*f6aab3d8Srobert     if (!platform_sp->IsCompatibleArchitecture(
230*f6aab3d8Srobert             platform_arch, {}, ArchSpec::CompatibleMatch, nullptr)) {
231*f6aab3d8Srobert       platform_sp =
232*f6aab3d8Srobert           platform_list.GetOrCreate(platform_arch, {}, &fixed_platform_arch);
233be691f3bSpatrick       if (platform_sp)
234*f6aab3d8Srobert         platform_list.SetSelectedPlatform(platform_sp);
235061da546Spatrick     }
236061da546Spatrick   }
237061da546Spatrick 
238061da546Spatrick   if (!platform_arch.IsValid())
239061da546Spatrick     platform_arch = arch;
240061da546Spatrick 
241be691f3bSpatrick   return TargetList::CreateTargetInternal(debugger, user_exe_path,
242be691f3bSpatrick                                           platform_arch, load_dependent_files,
243be691f3bSpatrick                                           platform_sp, target_sp);
244061da546Spatrick }
245061da546Spatrick 
CreateTargetInternal(Debugger & debugger,llvm::StringRef user_exe_path,const ArchSpec & specified_arch,LoadDependentFiles load_dependent_files,lldb::PlatformSP & platform_sp,lldb::TargetSP & target_sp)246061da546Spatrick Status TargetList::CreateTargetInternal(Debugger &debugger,
247061da546Spatrick                                         llvm::StringRef user_exe_path,
248061da546Spatrick                                         const ArchSpec &specified_arch,
249061da546Spatrick                                         LoadDependentFiles load_dependent_files,
250061da546Spatrick                                         lldb::PlatformSP &platform_sp,
251be691f3bSpatrick                                         lldb::TargetSP &target_sp) {
252be691f3bSpatrick   LLDB_SCOPED_TIMERF("TargetList::CreateTarget (file = '%s', arch = '%s')",
253be691f3bSpatrick                      user_exe_path.str().c_str(),
254be691f3bSpatrick                      specified_arch.GetArchitectureName());
255061da546Spatrick   Status error;
256be691f3bSpatrick   const bool is_dummy_target = false;
257061da546Spatrick 
258061da546Spatrick   ArchSpec arch(specified_arch);
259061da546Spatrick 
260061da546Spatrick   if (arch.IsValid()) {
261*f6aab3d8Srobert     if (!platform_sp || !platform_sp->IsCompatibleArchitecture(
262*f6aab3d8Srobert                             arch, {}, ArchSpec::CompatibleMatch, nullptr))
263*f6aab3d8Srobert       platform_sp =
264*f6aab3d8Srobert           debugger.GetPlatformList().GetOrCreate(specified_arch, {}, &arch);
265061da546Spatrick   }
266061da546Spatrick 
267061da546Spatrick   if (!platform_sp)
268061da546Spatrick     platform_sp = debugger.GetPlatformList().GetSelectedPlatform();
269061da546Spatrick 
270061da546Spatrick   if (!arch.IsValid())
271061da546Spatrick     arch = specified_arch;
272061da546Spatrick 
273061da546Spatrick   FileSpec file(user_exe_path);
274061da546Spatrick   if (!FileSystem::Instance().Exists(file) && user_exe_path.startswith("~")) {
275061da546Spatrick     // we want to expand the tilde but we don't want to resolve any symbolic
276061da546Spatrick     // links so we can't use the FileSpec constructor's resolve flag
277061da546Spatrick     llvm::SmallString<64> unglobbed_path;
278061da546Spatrick     StandardTildeExpressionResolver Resolver;
279061da546Spatrick     Resolver.ResolveFullPath(user_exe_path, unglobbed_path);
280061da546Spatrick 
281061da546Spatrick     if (unglobbed_path.empty())
282061da546Spatrick       file = FileSpec(user_exe_path);
283061da546Spatrick     else
284061da546Spatrick       file = FileSpec(unglobbed_path.c_str());
285061da546Spatrick   }
286061da546Spatrick 
287061da546Spatrick   bool user_exe_path_is_bundle = false;
288061da546Spatrick   char resolved_bundle_exe_path[PATH_MAX];
289061da546Spatrick   resolved_bundle_exe_path[0] = '\0';
290061da546Spatrick   if (file) {
291061da546Spatrick     if (FileSystem::Instance().IsDirectory(file))
292061da546Spatrick       user_exe_path_is_bundle = true;
293061da546Spatrick 
294061da546Spatrick     if (file.IsRelative() && !user_exe_path.empty()) {
295061da546Spatrick       llvm::SmallString<64> cwd;
296061da546Spatrick       if (! llvm::sys::fs::current_path(cwd)) {
297061da546Spatrick         FileSpec cwd_file(cwd.c_str());
298061da546Spatrick         cwd_file.AppendPathComponent(file);
299061da546Spatrick         if (FileSystem::Instance().Exists(cwd_file))
300061da546Spatrick           file = cwd_file;
301061da546Spatrick       }
302061da546Spatrick     }
303061da546Spatrick 
304061da546Spatrick     ModuleSP exe_module_sp;
305061da546Spatrick     if (platform_sp) {
306061da546Spatrick       FileSpecList executable_search_paths(
307061da546Spatrick           Target::GetDefaultExecutableSearchPaths());
308061da546Spatrick       ModuleSpec module_spec(file, arch);
309061da546Spatrick       error = platform_sp->ResolveExecutable(module_spec, exe_module_sp,
310061da546Spatrick                                              executable_search_paths.GetSize()
311061da546Spatrick                                                  ? &executable_search_paths
312061da546Spatrick                                                  : nullptr);
313061da546Spatrick     }
314061da546Spatrick 
315061da546Spatrick     if (error.Success() && exe_module_sp) {
316061da546Spatrick       if (exe_module_sp->GetObjectFile() == nullptr) {
317061da546Spatrick         if (arch.IsValid()) {
318061da546Spatrick           error.SetErrorStringWithFormat(
319061da546Spatrick               "\"%s\" doesn't contain architecture %s", file.GetPath().c_str(),
320061da546Spatrick               arch.GetArchitectureName());
321061da546Spatrick         } else {
322061da546Spatrick           error.SetErrorStringWithFormat("unsupported file type \"%s\"",
323061da546Spatrick                                          file.GetPath().c_str());
324061da546Spatrick         }
325061da546Spatrick         return error;
326061da546Spatrick       }
327061da546Spatrick       target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
328061da546Spatrick       target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
329061da546Spatrick       if (user_exe_path_is_bundle)
330061da546Spatrick         exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
331061da546Spatrick                                              sizeof(resolved_bundle_exe_path));
332dda28197Spatrick       if (target_sp->GetPreloadSymbols())
333dda28197Spatrick         exe_module_sp->PreloadSymbols();
334061da546Spatrick     }
335061da546Spatrick   } else {
336061da546Spatrick     // No file was specified, just create an empty target with any arch if a
337061da546Spatrick     // valid arch was specified
338061da546Spatrick     target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
339061da546Spatrick   }
340061da546Spatrick 
341be691f3bSpatrick   if (!target_sp)
342be691f3bSpatrick     return error;
343be691f3bSpatrick 
344061da546Spatrick   // Set argv0 with what the user typed, unless the user specified a
345061da546Spatrick   // directory. If the user specified a directory, then it is probably a
346061da546Spatrick   // bundle that was resolved and we need to use the resolved bundle path
347061da546Spatrick   if (!user_exe_path.empty()) {
348061da546Spatrick     // Use exactly what the user typed as the first argument when we exec or
349061da546Spatrick     // posix_spawn
350061da546Spatrick     if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) {
351061da546Spatrick       target_sp->SetArg0(resolved_bundle_exe_path);
352061da546Spatrick     } else {
353061da546Spatrick       // Use resolved path
354061da546Spatrick       target_sp->SetArg0(file.GetPath().c_str());
355061da546Spatrick     }
356061da546Spatrick   }
357061da546Spatrick   if (file.GetDirectory()) {
358061da546Spatrick     FileSpec file_dir;
359*f6aab3d8Srobert     file_dir.SetDirectory(file.GetDirectory());
360061da546Spatrick     target_sp->AppendExecutableSearchPaths(file_dir);
361061da546Spatrick   }
362061da546Spatrick 
363061da546Spatrick   // Now prime this from the dummy target:
364061da546Spatrick   target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget());
365061da546Spatrick 
366061da546Spatrick   return error;
367061da546Spatrick }
368061da546Spatrick 
DeleteTarget(TargetSP & target_sp)369061da546Spatrick bool TargetList::DeleteTarget(TargetSP &target_sp) {
370061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
371be691f3bSpatrick   auto it = std::find(m_target_list.begin(), m_target_list.end(), target_sp);
372be691f3bSpatrick   if (it == m_target_list.end())
373061da546Spatrick     return false;
374be691f3bSpatrick 
375be691f3bSpatrick   m_target_list.erase(it);
376be691f3bSpatrick   return true;
377061da546Spatrick }
378061da546Spatrick 
FindTargetWithExecutableAndArchitecture(const FileSpec & exe_file_spec,const ArchSpec * exe_arch_ptr) const379061da546Spatrick TargetSP TargetList::FindTargetWithExecutableAndArchitecture(
380061da546Spatrick     const FileSpec &exe_file_spec, const ArchSpec *exe_arch_ptr) const {
381061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
382be691f3bSpatrick   auto it = std::find_if(m_target_list.begin(), m_target_list.end(),
383be691f3bSpatrick       [&exe_file_spec, exe_arch_ptr](const TargetSP &item) {
384be691f3bSpatrick         Module *exe_module = item->GetExecutableModulePointer();
385be691f3bSpatrick         if (!exe_module ||
386be691f3bSpatrick             !FileSpec::Match(exe_file_spec, exe_module->GetFileSpec()))
387be691f3bSpatrick           return false;
388061da546Spatrick 
389be691f3bSpatrick         return !exe_arch_ptr ||
390be691f3bSpatrick                exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture());
391be691f3bSpatrick       });
392be691f3bSpatrick 
393be691f3bSpatrick   if (it != m_target_list.end())
394be691f3bSpatrick     return *it;
395be691f3bSpatrick 
396be691f3bSpatrick   return TargetSP();
397061da546Spatrick }
398061da546Spatrick 
FindTargetWithProcessID(lldb::pid_t pid) const399061da546Spatrick TargetSP TargetList::FindTargetWithProcessID(lldb::pid_t pid) const {
400061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
401be691f3bSpatrick   auto it = std::find_if(m_target_list.begin(), m_target_list.end(),
402be691f3bSpatrick       [pid](const TargetSP &item) {
403be691f3bSpatrick         auto *process_ptr = item->GetProcessSP().get();
404be691f3bSpatrick         return process_ptr && (process_ptr->GetID() == pid);
405be691f3bSpatrick       });
406be691f3bSpatrick 
407be691f3bSpatrick   if (it != m_target_list.end())
408be691f3bSpatrick     return *it;
409be691f3bSpatrick 
410be691f3bSpatrick   return TargetSP();
411061da546Spatrick }
412061da546Spatrick 
FindTargetWithProcess(Process * process) const413061da546Spatrick TargetSP TargetList::FindTargetWithProcess(Process *process) const {
414061da546Spatrick   TargetSP target_sp;
415be691f3bSpatrick   if (!process)
416be691f3bSpatrick     return target_sp;
417be691f3bSpatrick 
418061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
419be691f3bSpatrick   auto it = std::find_if(m_target_list.begin(), m_target_list.end(),
420be691f3bSpatrick       [process](const TargetSP &item) {
421be691f3bSpatrick         return item->GetProcessSP().get() == process;
422be691f3bSpatrick       });
423be691f3bSpatrick 
424be691f3bSpatrick   if (it != m_target_list.end())
425be691f3bSpatrick     target_sp = *it;
426be691f3bSpatrick 
427061da546Spatrick   return target_sp;
428061da546Spatrick }
429061da546Spatrick 
GetTargetSP(Target * target) const430061da546Spatrick TargetSP TargetList::GetTargetSP(Target *target) const {
431061da546Spatrick   TargetSP target_sp;
432be691f3bSpatrick   if (!target)
433be691f3bSpatrick     return target_sp;
434be691f3bSpatrick 
435061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
436be691f3bSpatrick   auto it = std::find_if(m_target_list.begin(), m_target_list.end(),
437be691f3bSpatrick       [target](const TargetSP &item) { return item.get() == target; });
438be691f3bSpatrick   if (it != m_target_list.end())
439be691f3bSpatrick     target_sp = *it;
440be691f3bSpatrick 
441061da546Spatrick   return target_sp;
442061da546Spatrick }
443061da546Spatrick 
SendAsyncInterrupt(lldb::pid_t pid)444061da546Spatrick uint32_t TargetList::SendAsyncInterrupt(lldb::pid_t pid) {
445061da546Spatrick   uint32_t num_async_interrupts_sent = 0;
446061da546Spatrick 
447061da546Spatrick   if (pid != LLDB_INVALID_PROCESS_ID) {
448061da546Spatrick     TargetSP target_sp(FindTargetWithProcessID(pid));
449061da546Spatrick     if (target_sp) {
450061da546Spatrick       Process *process = target_sp->GetProcessSP().get();
451061da546Spatrick       if (process) {
452061da546Spatrick         process->SendAsyncInterrupt();
453061da546Spatrick         ++num_async_interrupts_sent;
454061da546Spatrick       }
455061da546Spatrick     }
456061da546Spatrick   } else {
457061da546Spatrick     // We don't have a valid pid to broadcast to, so broadcast to the target
458061da546Spatrick     // list's async broadcaster...
459061da546Spatrick     BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr);
460061da546Spatrick   }
461061da546Spatrick 
462061da546Spatrick   return num_async_interrupts_sent;
463061da546Spatrick }
464061da546Spatrick 
SignalIfRunning(lldb::pid_t pid,int signo)465061da546Spatrick uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) {
466061da546Spatrick   uint32_t num_signals_sent = 0;
467061da546Spatrick   Process *process = nullptr;
468061da546Spatrick   if (pid == LLDB_INVALID_PROCESS_ID) {
469061da546Spatrick     // Signal all processes with signal
470061da546Spatrick     std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
471be691f3bSpatrick     for (const auto &target_sp : m_target_list) {
472be691f3bSpatrick       process = target_sp->GetProcessSP().get();
473be691f3bSpatrick       if (process && process->IsAlive()) {
474061da546Spatrick         ++num_signals_sent;
475061da546Spatrick         process->Signal(signo);
476061da546Spatrick       }
477061da546Spatrick     }
478061da546Spatrick   } else {
479061da546Spatrick     // Signal a specific process with signal
480061da546Spatrick     TargetSP target_sp(FindTargetWithProcessID(pid));
481061da546Spatrick     if (target_sp) {
482061da546Spatrick       process = target_sp->GetProcessSP().get();
483be691f3bSpatrick       if (process && process->IsAlive()) {
484061da546Spatrick         ++num_signals_sent;
485061da546Spatrick         process->Signal(signo);
486061da546Spatrick       }
487061da546Spatrick     }
488061da546Spatrick   }
489061da546Spatrick   return num_signals_sent;
490061da546Spatrick }
491061da546Spatrick 
GetNumTargets() const492061da546Spatrick int TargetList::GetNumTargets() const {
493061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
494061da546Spatrick   return m_target_list.size();
495061da546Spatrick }
496061da546Spatrick 
GetTargetAtIndex(uint32_t idx) const497061da546Spatrick lldb::TargetSP TargetList::GetTargetAtIndex(uint32_t idx) const {
498061da546Spatrick   TargetSP target_sp;
499061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
500061da546Spatrick   if (idx < m_target_list.size())
501061da546Spatrick     target_sp = m_target_list[idx];
502061da546Spatrick   return target_sp;
503061da546Spatrick }
504061da546Spatrick 
GetIndexOfTarget(lldb::TargetSP target_sp) const505061da546Spatrick uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const {
506061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
507be691f3bSpatrick   auto it = std::find(m_target_list.begin(), m_target_list.end(), target_sp);
508be691f3bSpatrick   if (it != m_target_list.end())
509be691f3bSpatrick     return std::distance(m_target_list.begin(), it);
510061da546Spatrick   return UINT32_MAX;
511061da546Spatrick }
512061da546Spatrick 
AddTargetInternal(TargetSP target_sp,bool do_select)513be691f3bSpatrick void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
514*f6aab3d8Srobert   lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
515be691f3bSpatrick              "target already exists it the list");
516be691f3bSpatrick   m_target_list.push_back(std::move(target_sp));
517be691f3bSpatrick   if (do_select)
518be691f3bSpatrick     SetSelectedTargetInternal(m_target_list.size() - 1);
519be691f3bSpatrick }
520be691f3bSpatrick 
SetSelectedTargetInternal(uint32_t index)521be691f3bSpatrick void TargetList::SetSelectedTargetInternal(uint32_t index) {
522be691f3bSpatrick   lldbassert(!m_target_list.empty());
523be691f3bSpatrick   m_selected_target_idx = index < m_target_list.size() ? index : 0;
524be691f3bSpatrick }
525be691f3bSpatrick 
SetSelectedTarget(uint32_t index)526be691f3bSpatrick void TargetList::SetSelectedTarget(uint32_t index) {
527061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
528be691f3bSpatrick   SetSelectedTargetInternal(index);
529061da546Spatrick }
530be691f3bSpatrick 
SetSelectedTarget(const TargetSP & target_sp)531be691f3bSpatrick void TargetList::SetSelectedTarget(const TargetSP &target_sp) {
532be691f3bSpatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
533be691f3bSpatrick   auto it = std::find(m_target_list.begin(), m_target_list.end(), target_sp);
534be691f3bSpatrick   SetSelectedTargetInternal(std::distance(m_target_list.begin(), it));
535061da546Spatrick }
536061da546Spatrick 
GetSelectedTarget()537061da546Spatrick lldb::TargetSP TargetList::GetSelectedTarget() {
538061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
539061da546Spatrick   if (m_selected_target_idx >= m_target_list.size())
540061da546Spatrick     m_selected_target_idx = 0;
541061da546Spatrick   return GetTargetAtIndex(m_selected_target_idx);
542061da546Spatrick }
543