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