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-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 
29 using namespace lldb;
30 using namespace lldb_private;
31 
GetStaticBroadcasterClass()32 ConstString &TargetList::GetStaticBroadcasterClass() {
33   static ConstString class_name("lldb.targetList");
34   return class_name;
35 }
36 
37 // TargetList constructor
TargetList(Debugger & debugger)38 TargetList::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
~TargetList()46 TargetList::~TargetList() {
47   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
48   m_target_list.clear();
49 }
50 
CreateTarget(Debugger & debugger,llvm::StringRef user_exe_path,llvm::StringRef triple_str,LoadDependentFiles load_dependent_files,const OptionGroupPlatform * platform_options,TargetSP & target_sp)51 Status 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 
CreateTarget(Debugger & debugger,llvm::StringRef user_exe_path,const ArchSpec & specified_arch,LoadDependentFiles load_dependent_files,PlatformSP & platform_sp,TargetSP & target_sp)62 Status 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 
CreateTargetInternal(Debugger & debugger,llvm::StringRef user_exe_path,llvm::StringRef triple_str,LoadDependentFiles load_dependent_files,const OptionGroupPlatform * platform_options,TargetSP & target_sp,bool is_dummy_target)72 Status 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 
GetDummyTarget(lldb_private::Debugger & debugger)293 lldb::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 
CreateDummyTarget(Debugger & debugger,llvm::StringRef specified_arch_name,lldb::TargetSP & target_sp)306 Status 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 
CreateTargetInternal(Debugger & debugger,llvm::StringRef user_exe_path,const ArchSpec & specified_arch,LoadDependentFiles load_dependent_files,lldb::PlatformSP & platform_sp,lldb::TargetSP & target_sp,bool is_dummy_target)315 Status 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       if (target_sp->GetPreloadSymbols())
402         exe_module_sp->PreloadSymbols();
403     }
404   } else {
405     // No file was specified, just create an empty target with any arch if a
406     // valid arch was specified
407     target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
408   }
409 
410   if (target_sp) {
411     // Set argv0 with what the user typed, unless the user specified a
412     // directory. If the user specified a directory, then it is probably a
413     // bundle that was resolved and we need to use the resolved bundle path
414     if (!user_exe_path.empty()) {
415       // Use exactly what the user typed as the first argument when we exec or
416       // posix_spawn
417       if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) {
418         target_sp->SetArg0(resolved_bundle_exe_path);
419       } else {
420         // Use resolved path
421         target_sp->SetArg0(file.GetPath().c_str());
422       }
423     }
424     if (file.GetDirectory()) {
425       FileSpec file_dir;
426       file_dir.GetDirectory() = file.GetDirectory();
427       target_sp->AppendExecutableSearchPaths(file_dir);
428     }
429 
430     // Don't put the dummy target in the target list, it's held separately.
431     if (!is_dummy_target) {
432       std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
433       m_selected_target_idx = m_target_list.size();
434       m_target_list.push_back(target_sp);
435       // Now prime this from the dummy target:
436       target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget());
437     } else {
438       m_dummy_target_sp = target_sp;
439     }
440   }
441 
442   return error;
443 }
444 
DeleteTarget(TargetSP & target_sp)445 bool TargetList::DeleteTarget(TargetSP &target_sp) {
446   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
447   collection::iterator pos, end = m_target_list.end();
448 
449   for (pos = m_target_list.begin(); pos != end; ++pos) {
450     if (pos->get() == target_sp.get()) {
451       m_target_list.erase(pos);
452       return true;
453     }
454   }
455   return false;
456 }
457 
FindTargetWithExecutableAndArchitecture(const FileSpec & exe_file_spec,const ArchSpec * exe_arch_ptr) const458 TargetSP TargetList::FindTargetWithExecutableAndArchitecture(
459     const FileSpec &exe_file_spec, const ArchSpec *exe_arch_ptr) const {
460   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
461   TargetSP target_sp;
462   collection::const_iterator pos, end = m_target_list.end();
463   for (pos = m_target_list.begin(); pos != end; ++pos) {
464     Module *exe_module = (*pos)->GetExecutableModulePointer();
465 
466     if (exe_module) {
467       if (FileSpec::Match(exe_file_spec, exe_module->GetFileSpec())) {
468         if (exe_arch_ptr) {
469           if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture()))
470             continue;
471         }
472         target_sp = *pos;
473         break;
474       }
475     }
476   }
477   return target_sp;
478 }
479 
FindTargetWithProcessID(lldb::pid_t pid) const480 TargetSP TargetList::FindTargetWithProcessID(lldb::pid_t pid) const {
481   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
482   TargetSP target_sp;
483   collection::const_iterator pos, end = m_target_list.end();
484   for (pos = m_target_list.begin(); pos != end; ++pos) {
485     Process *process = (*pos)->GetProcessSP().get();
486     if (process && process->GetID() == pid) {
487       target_sp = *pos;
488       break;
489     }
490   }
491   return target_sp;
492 }
493 
FindTargetWithProcess(Process * process) const494 TargetSP TargetList::FindTargetWithProcess(Process *process) const {
495   TargetSP target_sp;
496   if (process) {
497     std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
498     collection::const_iterator pos, end = m_target_list.end();
499     for (pos = m_target_list.begin(); pos != end; ++pos) {
500       if (process == (*pos)->GetProcessSP().get()) {
501         target_sp = *pos;
502         break;
503       }
504     }
505   }
506   return target_sp;
507 }
508 
GetTargetSP(Target * target) const509 TargetSP TargetList::GetTargetSP(Target *target) const {
510   TargetSP target_sp;
511   if (target) {
512     std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
513     collection::const_iterator pos, end = m_target_list.end();
514     for (pos = m_target_list.begin(); pos != end; ++pos) {
515       if (target == (*pos).get()) {
516         target_sp = *pos;
517         break;
518       }
519     }
520   }
521   return target_sp;
522 }
523 
SendAsyncInterrupt(lldb::pid_t pid)524 uint32_t TargetList::SendAsyncInterrupt(lldb::pid_t pid) {
525   uint32_t num_async_interrupts_sent = 0;
526 
527   if (pid != LLDB_INVALID_PROCESS_ID) {
528     TargetSP target_sp(FindTargetWithProcessID(pid));
529     if (target_sp) {
530       Process *process = target_sp->GetProcessSP().get();
531       if (process) {
532         process->SendAsyncInterrupt();
533         ++num_async_interrupts_sent;
534       }
535     }
536   } else {
537     // We don't have a valid pid to broadcast to, so broadcast to the target
538     // list's async broadcaster...
539     BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr);
540   }
541 
542   return num_async_interrupts_sent;
543 }
544 
SignalIfRunning(lldb::pid_t pid,int signo)545 uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) {
546   uint32_t num_signals_sent = 0;
547   Process *process = nullptr;
548   if (pid == LLDB_INVALID_PROCESS_ID) {
549     // Signal all processes with signal
550     std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
551     collection::iterator pos, end = m_target_list.end();
552     for (pos = m_target_list.begin(); pos != end; ++pos) {
553       process = (*pos)->GetProcessSP().get();
554       if (process) {
555         if (process->IsAlive()) {
556           ++num_signals_sent;
557           process->Signal(signo);
558         }
559       }
560     }
561   } else {
562     // Signal a specific process with signal
563     TargetSP target_sp(FindTargetWithProcessID(pid));
564     if (target_sp) {
565       process = target_sp->GetProcessSP().get();
566       if (process) {
567         if (process->IsAlive()) {
568           ++num_signals_sent;
569           process->Signal(signo);
570         }
571       }
572     }
573   }
574   return num_signals_sent;
575 }
576 
GetNumTargets() const577 int TargetList::GetNumTargets() const {
578   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
579   return m_target_list.size();
580 }
581 
GetTargetAtIndex(uint32_t idx) const582 lldb::TargetSP TargetList::GetTargetAtIndex(uint32_t idx) const {
583   TargetSP target_sp;
584   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
585   if (idx < m_target_list.size())
586     target_sp = m_target_list[idx];
587   return target_sp;
588 }
589 
GetIndexOfTarget(lldb::TargetSP target_sp) const590 uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const {
591   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
592   size_t num_targets = m_target_list.size();
593   for (size_t idx = 0; idx < num_targets; idx++) {
594     if (target_sp == m_target_list[idx])
595       return idx;
596   }
597   return UINT32_MAX;
598 }
599 
SetSelectedTarget(Target * target)600 uint32_t TargetList::SetSelectedTarget(Target *target) {
601   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
602   collection::const_iterator pos, begin = m_target_list.begin(),
603                                   end = m_target_list.end();
604   for (pos = begin; pos != end; ++pos) {
605     if (pos->get() == target) {
606       m_selected_target_idx = std::distance(begin, pos);
607       return m_selected_target_idx;
608     }
609   }
610   m_selected_target_idx = 0;
611   return m_selected_target_idx;
612 }
613 
GetSelectedTarget()614 lldb::TargetSP TargetList::GetSelectedTarget() {
615   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
616   if (m_selected_target_idx >= m_target_list.size())
617     m_selected_target_idx = 0;
618   return GetTargetAtIndex(m_selected_target_idx);
619 }
620