1254721Semaste//===-- TargetList.cpp ------------------------------------------*- C++ -*-===// 2254721Semaste// 3254721Semaste// The LLVM Compiler Infrastructure 4254721Semaste// 5254721Semaste// This file is distributed under the University of Illinois Open Source 6254721Semaste// License. See LICENSE.TXT for details. 7254721Semaste// 8254721Semaste//===----------------------------------------------------------------------===// 9254721Semaste 10254721Semaste#include "lldb/lldb-python.h" 11254721Semaste 12254721Semaste// C Includes 13254721Semaste// C++ Includes 14254721Semaste// Other libraries and framework includes 15254721Semaste// Project includes 16254721Semaste#include "lldb/Core/Broadcaster.h" 17254721Semaste#include "lldb/Core/Debugger.h" 18254721Semaste#include "lldb/Core/Event.h" 19254721Semaste#include "lldb/Core/Module.h" 20254721Semaste#include "lldb/Core/ModuleSpec.h" 21254721Semaste#include "lldb/Core/State.h" 22254721Semaste#include "lldb/Core/Timer.h" 23254721Semaste#include "lldb/Host/Host.h" 24254721Semaste#include "lldb/Interpreter/CommandInterpreter.h" 25254721Semaste#include "lldb/Interpreter/OptionGroupPlatform.h" 26254721Semaste#include "lldb/Symbol/ObjectFile.h" 27254721Semaste#include "lldb/Target/Platform.h" 28254721Semaste#include "lldb/Target/Process.h" 29254721Semaste#include "lldb/Target/TargetList.h" 30254721Semaste 31254721Semasteusing namespace lldb; 32254721Semasteusing namespace lldb_private; 33254721Semaste 34254721SemasteConstString & 35254721SemasteTargetList::GetStaticBroadcasterClass () 36254721Semaste{ 37254721Semaste static ConstString class_name ("lldb.targetList"); 38254721Semaste return class_name; 39254721Semaste} 40254721Semaste 41254721Semaste//---------------------------------------------------------------------- 42254721Semaste// TargetList constructor 43254721Semaste//---------------------------------------------------------------------- 44254721SemasteTargetList::TargetList(Debugger &debugger) : 45254721Semaste Broadcaster(&debugger, TargetList::GetStaticBroadcasterClass().AsCString()), 46254721Semaste m_target_list(), 47254721Semaste m_target_list_mutex (Mutex::eMutexTypeRecursive), 48254721Semaste m_selected_target_idx (0) 49254721Semaste{ 50254721Semaste CheckInWithManager(); 51254721Semaste} 52254721Semaste 53254721Semaste//---------------------------------------------------------------------- 54254721Semaste// Destructor 55254721Semaste//---------------------------------------------------------------------- 56254721SemasteTargetList::~TargetList() 57254721Semaste{ 58254721Semaste Mutex::Locker locker(m_target_list_mutex); 59254721Semaste m_target_list.clear(); 60254721Semaste} 61254721Semaste 62254721SemasteError 63254721SemasteTargetList::CreateTarget (Debugger &debugger, 64254721Semaste const char *user_exe_path, 65254721Semaste const char *triple_cstr, 66254721Semaste bool get_dependent_files, 67254721Semaste const OptionGroupPlatform *platform_options, 68254721Semaste TargetSP &target_sp) 69254721Semaste{ 70254721Semaste Error error; 71254721Semaste PlatformSP platform_sp; 72254721Semaste 73254721Semaste // This is purposely left empty unless it is specified by triple_cstr. 74254721Semaste // If not initialized via triple_cstr, then the currently selected platform 75254721Semaste // will set the architecture correctly. 76254721Semaste const ArchSpec arch(triple_cstr); 77254721Semaste if (triple_cstr && triple_cstr[0]) 78254721Semaste { 79254721Semaste if (!arch.IsValid()) 80254721Semaste { 81254721Semaste error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr); 82254721Semaste return error; 83254721Semaste } 84254721Semaste } 85254721Semaste 86254721Semaste ArchSpec platform_arch(arch); 87254721Semaste 88254721Semaste 89254721Semaste if (user_exe_path && user_exe_path[0]) 90254721Semaste { 91254721Semaste ModuleSpecList module_specs; 92254721Semaste ModuleSpec module_spec; 93254721Semaste module_spec.GetFileSpec().SetFile(user_exe_path, true); 94254721Semaste lldb::offset_t file_offset = 0; 95254721Semaste lldb::offset_t file_size = 0; 96254721Semaste const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs); 97254721Semaste if (num_specs > 0) 98254721Semaste { 99254721Semaste ModuleSpec matching_module_spec; 100254721Semaste 101254721Semaste if (num_specs == 1) 102254721Semaste { 103254721Semaste if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) 104254721Semaste { 105254721Semaste if (platform_arch.IsValid()) 106254721Semaste { 107254721Semaste if (!platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture())) 108254721Semaste { 109254721Semaste error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'", 110254721Semaste platform_arch.GetTriple().str().c_str(), 111254721Semaste matching_module_spec.GetArchitecture().GetTriple().str().c_str(), 112254721Semaste module_spec.GetFileSpec().GetPath().c_str()); 113254721Semaste return error; 114254721Semaste } 115254721Semaste } 116254721Semaste else 117254721Semaste { 118254721Semaste // Only one arch and none was specified 119254721Semaste platform_arch = matching_module_spec.GetArchitecture(); 120254721Semaste } 121254721Semaste } 122254721Semaste } 123254721Semaste else 124254721Semaste { 125254721Semaste if (arch.IsValid()) 126254721Semaste { 127254721Semaste module_spec.GetArchitecture() = arch; 128254721Semaste if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec)) 129254721Semaste { 130254721Semaste platform_arch = matching_module_spec.GetArchitecture(); 131254721Semaste } 132254721Semaste } 133254721Semaste // Don't just select the first architecture, we want to let the platform select 134254721Semaste // the best architecture first when there are multiple archs. 135254721Semaste// else 136254721Semaste// { 137254721Semaste// // No arch specified, select the first arch 138254721Semaste// if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) 139254721Semaste// { 140254721Semaste// platform_arch = matching_module_spec.GetArchitecture(); 141254721Semaste// } 142254721Semaste// } 143254721Semaste } 144254721Semaste } 145254721Semaste } 146254721Semaste 147254721Semaste CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); 148254721Semaste if (platform_options) 149254721Semaste { 150254721Semaste if (platform_options->PlatformWasSpecified ()) 151254721Semaste { 152254721Semaste const bool select_platform = true; 153254721Semaste platform_sp = platform_options->CreatePlatformWithOptions (interpreter, 154254721Semaste arch, 155254721Semaste select_platform, 156254721Semaste error, 157254721Semaste platform_arch); 158254721Semaste if (!platform_sp) 159254721Semaste return error; 160254721Semaste } 161254721Semaste } 162254721Semaste 163254721Semaste if (!platform_sp) 164254721Semaste { 165254721Semaste // Get the current platform and make sure it is compatible with the 166254721Semaste // current architecture if we have a valid architecture. 167254721Semaste platform_sp = debugger.GetPlatformList().GetSelectedPlatform (); 168254721Semaste 169254721Semaste if (arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) 170254721Semaste { 171254721Semaste platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); 172254721Semaste } 173254721Semaste } 174254721Semaste 175254721Semaste if (!platform_arch.IsValid()) 176254721Semaste platform_arch = arch; 177254721Semaste 178254721Semaste error = TargetList::CreateTarget (debugger, 179254721Semaste user_exe_path, 180254721Semaste platform_arch, 181254721Semaste get_dependent_files, 182254721Semaste platform_sp, 183254721Semaste target_sp); 184254721Semaste return error; 185254721Semaste} 186254721Semaste 187254721SemasteError 188254721SemasteTargetList::CreateTarget (Debugger &debugger, 189254721Semaste const char *user_exe_path, 190254721Semaste const ArchSpec& specified_arch, 191254721Semaste bool get_dependent_files, 192254721Semaste PlatformSP &platform_sp, 193254721Semaste TargetSP &target_sp) 194254721Semaste{ 195254721Semaste Timer scoped_timer (__PRETTY_FUNCTION__, 196254721Semaste "TargetList::CreateTarget (file = '%s', arch = '%s')", 197254721Semaste user_exe_path, 198254721Semaste specified_arch.GetArchitectureName()); 199254721Semaste Error error; 200254721Semaste 201254721Semaste ArchSpec arch(specified_arch); 202254721Semaste 203254721Semaste if (platform_sp) 204254721Semaste { 205254721Semaste if (arch.IsValid()) 206254721Semaste { 207254721Semaste if (!platform_sp->IsCompatibleArchitecture(arch, false, NULL)) 208254721Semaste platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); 209254721Semaste } 210254721Semaste } 211254721Semaste else if (arch.IsValid()) 212254721Semaste { 213254721Semaste platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); 214254721Semaste } 215254721Semaste 216254721Semaste if (!platform_sp) 217254721Semaste platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); 218254721Semaste 219254721Semaste if (!arch.IsValid()) 220254721Semaste arch = specified_arch; 221254721Semaste 222254721Semaste FileSpec file (user_exe_path, false); 223254721Semaste if (!file.Exists() && user_exe_path && user_exe_path[0] == '~') 224254721Semaste { 225254721Semaste // we want to expand the tilde but we don't want to resolve any symbolic links 226254721Semaste // so we can't use the FileSpec constructor's resolve flag 227254721Semaste char unglobbed_path[PATH_MAX]; 228254721Semaste unglobbed_path[0] = '\0'; 229254721Semaste 230254721Semaste size_t return_count = FileSpec::ResolveUsername(user_exe_path, unglobbed_path, sizeof(unglobbed_path)); 231254721Semaste 232254721Semaste if (return_count == 0 || return_count >= sizeof(unglobbed_path)) 233254721Semaste ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", user_exe_path); 234254721Semaste 235254721Semaste file = FileSpec(unglobbed_path, false); 236254721Semaste } 237254721Semaste 238254721Semaste bool user_exe_path_is_bundle = false; 239254721Semaste char resolved_bundle_exe_path[PATH_MAX]; 240254721Semaste resolved_bundle_exe_path[0] = '\0'; 241254721Semaste if (file) 242254721Semaste { 243254721Semaste if (file.GetFileType() == FileSpec::eFileTypeDirectory) 244254721Semaste user_exe_path_is_bundle = true; 245254721Semaste 246254721Semaste if (file.IsRelativeToCurrentWorkingDirectory()) 247254721Semaste { 248254721Semaste // Ignore paths that start with "./" and "../" 249254721Semaste if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') || 250254721Semaste (user_exe_path[0] == '.' && user_exe_path[1] == '.' && user_exe_path[2] == '/'))) 251254721Semaste { 252254721Semaste char cwd[PATH_MAX]; 253254721Semaste if (getcwd (cwd, sizeof(cwd))) 254254721Semaste { 255254721Semaste std::string cwd_user_exe_path (cwd); 256254721Semaste cwd_user_exe_path += '/'; 257254721Semaste cwd_user_exe_path += user_exe_path; 258254721Semaste FileSpec cwd_file (cwd_user_exe_path.c_str(), false); 259254721Semaste if (cwd_file.Exists()) 260254721Semaste file = cwd_file; 261254721Semaste } 262254721Semaste } 263254721Semaste } 264254721Semaste 265254721Semaste ModuleSP exe_module_sp; 266254721Semaste if (platform_sp) 267254721Semaste { 268254721Semaste FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); 269254721Semaste error = platform_sp->ResolveExecutable (file, 270254721Semaste arch, 271254721Semaste exe_module_sp, 272254721Semaste executable_search_paths.GetSize() ? &executable_search_paths : NULL); 273254721Semaste } 274254721Semaste 275254721Semaste if (error.Success() && exe_module_sp) 276254721Semaste { 277254721Semaste if (exe_module_sp->GetObjectFile() == NULL) 278254721Semaste { 279254721Semaste if (arch.IsValid()) 280254721Semaste { 281254721Semaste error.SetErrorStringWithFormat("\"%s\" doesn't contain architecture %s", 282254721Semaste file.GetPath().c_str(), 283254721Semaste arch.GetArchitectureName()); 284254721Semaste } 285254721Semaste else 286254721Semaste { 287254721Semaste error.SetErrorStringWithFormat("unsupported file type \"%s\"", 288254721Semaste file.GetPath().c_str()); 289254721Semaste } 290254721Semaste return error; 291254721Semaste } 292254721Semaste target_sp.reset(new Target(debugger, arch, platform_sp)); 293254721Semaste target_sp->SetExecutableModule (exe_module_sp, get_dependent_files); 294254721Semaste if (user_exe_path_is_bundle) 295254721Semaste exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, sizeof(resolved_bundle_exe_path)); 296254721Semaste } 297254721Semaste } 298254721Semaste else 299254721Semaste { 300254721Semaste // No file was specified, just create an empty target with any arch 301254721Semaste // if a valid arch was specified 302254721Semaste target_sp.reset(new Target(debugger, arch, platform_sp)); 303254721Semaste } 304254721Semaste 305254721Semaste if (target_sp) 306254721Semaste { 307254721Semaste // Set argv0 with what the user typed, unless the user specified a 308254721Semaste // directory. If the user specified a directory, then it is probably a 309254721Semaste // bundle that was resolved and we need to use the resolved bundle path 310254721Semaste if (user_exe_path) 311254721Semaste { 312254721Semaste // Use exactly what the user typed as the first argument when we exec or posix_spawn 313254721Semaste if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) 314254721Semaste { 315254721Semaste target_sp->SetArg0 (resolved_bundle_exe_path); 316254721Semaste } 317254721Semaste else 318254721Semaste { 319254721Semaste // Use resolved path 320254721Semaste target_sp->SetArg0 (file.GetPath().c_str()); 321254721Semaste } 322254721Semaste } 323254721Semaste if (file.GetDirectory()) 324254721Semaste { 325254721Semaste FileSpec file_dir; 326254721Semaste file_dir.GetDirectory() = file.GetDirectory(); 327254721Semaste target_sp->GetExecutableSearchPaths ().Append (file_dir); 328254721Semaste } 329254721Semaste Mutex::Locker locker(m_target_list_mutex); 330254721Semaste m_selected_target_idx = m_target_list.size(); 331254721Semaste m_target_list.push_back(target_sp); 332254721Semaste 333254721Semaste 334254721Semaste } 335254721Semaste 336254721Semaste return error; 337254721Semaste} 338254721Semaste 339254721Semastebool 340254721SemasteTargetList::DeleteTarget (TargetSP &target_sp) 341254721Semaste{ 342254721Semaste Mutex::Locker locker(m_target_list_mutex); 343254721Semaste collection::iterator pos, end = m_target_list.end(); 344254721Semaste 345254721Semaste for (pos = m_target_list.begin(); pos != end; ++pos) 346254721Semaste { 347254721Semaste if (pos->get() == target_sp.get()) 348254721Semaste { 349254721Semaste m_target_list.erase(pos); 350254721Semaste return true; 351254721Semaste } 352254721Semaste } 353254721Semaste return false; 354254721Semaste} 355254721Semaste 356254721Semaste 357254721SemasteTargetSP 358254721SemasteTargetList::FindTargetWithExecutableAndArchitecture 359254721Semaste( 360254721Semaste const FileSpec &exe_file_spec, 361254721Semaste const ArchSpec *exe_arch_ptr 362254721Semaste) const 363254721Semaste{ 364254721Semaste Mutex::Locker locker (m_target_list_mutex); 365254721Semaste TargetSP target_sp; 366263363Semaste bool full_match = (bool)exe_file_spec.GetDirectory(); 367254721Semaste 368254721Semaste collection::const_iterator pos, end = m_target_list.end(); 369254721Semaste for (pos = m_target_list.begin(); pos != end; ++pos) 370254721Semaste { 371254721Semaste Module *exe_module = (*pos)->GetExecutableModulePointer(); 372254721Semaste 373254721Semaste if (exe_module) 374254721Semaste { 375254721Semaste if (FileSpec::Equal (exe_file_spec, exe_module->GetFileSpec(), full_match)) 376254721Semaste { 377254721Semaste if (exe_arch_ptr) 378254721Semaste { 379254721Semaste if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture())) 380254721Semaste continue; 381254721Semaste } 382254721Semaste target_sp = *pos; 383254721Semaste break; 384254721Semaste } 385254721Semaste } 386254721Semaste } 387254721Semaste return target_sp; 388254721Semaste} 389254721Semaste 390254721SemasteTargetSP 391254721SemasteTargetList::FindTargetWithProcessID (lldb::pid_t pid) const 392254721Semaste{ 393254721Semaste Mutex::Locker locker(m_target_list_mutex); 394254721Semaste TargetSP target_sp; 395254721Semaste collection::const_iterator pos, end = m_target_list.end(); 396254721Semaste for (pos = m_target_list.begin(); pos != end; ++pos) 397254721Semaste { 398254721Semaste Process* process = (*pos)->GetProcessSP().get(); 399254721Semaste if (process && process->GetID() == pid) 400254721Semaste { 401254721Semaste target_sp = *pos; 402254721Semaste break; 403254721Semaste } 404254721Semaste } 405254721Semaste return target_sp; 406254721Semaste} 407254721Semaste 408254721Semaste 409254721SemasteTargetSP 410254721SemasteTargetList::FindTargetWithProcess (Process *process) const 411254721Semaste{ 412254721Semaste TargetSP target_sp; 413254721Semaste if (process) 414254721Semaste { 415254721Semaste Mutex::Locker locker(m_target_list_mutex); 416254721Semaste collection::const_iterator pos, end = m_target_list.end(); 417254721Semaste for (pos = m_target_list.begin(); pos != end; ++pos) 418254721Semaste { 419254721Semaste if (process == (*pos)->GetProcessSP().get()) 420254721Semaste { 421254721Semaste target_sp = *pos; 422254721Semaste break; 423254721Semaste } 424254721Semaste } 425254721Semaste } 426254721Semaste return target_sp; 427254721Semaste} 428254721Semaste 429254721SemasteTargetSP 430254721SemasteTargetList::GetTargetSP (Target *target) const 431254721Semaste{ 432254721Semaste TargetSP target_sp; 433254721Semaste if (target) 434254721Semaste { 435254721Semaste Mutex::Locker locker(m_target_list_mutex); 436254721Semaste collection::const_iterator pos, end = m_target_list.end(); 437254721Semaste for (pos = m_target_list.begin(); pos != end; ++pos) 438254721Semaste { 439254721Semaste if (target == (*pos).get()) 440254721Semaste { 441254721Semaste target_sp = *pos; 442254721Semaste break; 443254721Semaste } 444254721Semaste } 445254721Semaste } 446254721Semaste return target_sp; 447254721Semaste} 448254721Semaste 449254721Semasteuint32_t 450254721SemasteTargetList::SendAsyncInterrupt (lldb::pid_t pid) 451254721Semaste{ 452254721Semaste uint32_t num_async_interrupts_sent = 0; 453254721Semaste 454254721Semaste if (pid != LLDB_INVALID_PROCESS_ID) 455254721Semaste { 456254721Semaste TargetSP target_sp(FindTargetWithProcessID (pid)); 457254721Semaste if (target_sp.get()) 458254721Semaste { 459254721Semaste Process* process = target_sp->GetProcessSP().get(); 460254721Semaste if (process) 461254721Semaste { 462254721Semaste process->SendAsyncInterrupt(); 463254721Semaste ++num_async_interrupts_sent; 464254721Semaste } 465254721Semaste } 466254721Semaste } 467254721Semaste else 468254721Semaste { 469254721Semaste // We don't have a valid pid to broadcast to, so broadcast to the target 470254721Semaste // list's async broadcaster... 471254721Semaste BroadcastEvent (Process::eBroadcastBitInterrupt, NULL); 472254721Semaste } 473254721Semaste 474254721Semaste return num_async_interrupts_sent; 475254721Semaste} 476254721Semaste 477254721Semasteuint32_t 478254721SemasteTargetList::SignalIfRunning (lldb::pid_t pid, int signo) 479254721Semaste{ 480254721Semaste uint32_t num_signals_sent = 0; 481254721Semaste Process *process = NULL; 482254721Semaste if (pid == LLDB_INVALID_PROCESS_ID) 483254721Semaste { 484254721Semaste // Signal all processes with signal 485254721Semaste Mutex::Locker locker(m_target_list_mutex); 486254721Semaste collection::iterator pos, end = m_target_list.end(); 487254721Semaste for (pos = m_target_list.begin(); pos != end; ++pos) 488254721Semaste { 489254721Semaste process = (*pos)->GetProcessSP().get(); 490254721Semaste if (process) 491254721Semaste { 492254721Semaste if (process->IsAlive()) 493254721Semaste { 494254721Semaste ++num_signals_sent; 495254721Semaste process->Signal (signo); 496254721Semaste } 497254721Semaste } 498254721Semaste } 499254721Semaste } 500254721Semaste else 501254721Semaste { 502254721Semaste // Signal a specific process with signal 503254721Semaste TargetSP target_sp(FindTargetWithProcessID (pid)); 504254721Semaste if (target_sp.get()) 505254721Semaste { 506254721Semaste process = target_sp->GetProcessSP().get(); 507254721Semaste if (process) 508254721Semaste { 509254721Semaste if (process->IsAlive()) 510254721Semaste { 511254721Semaste ++num_signals_sent; 512254721Semaste process->Signal (signo); 513254721Semaste } 514254721Semaste } 515254721Semaste } 516254721Semaste } 517254721Semaste return num_signals_sent; 518254721Semaste} 519254721Semaste 520254721Semasteint 521254721SemasteTargetList::GetNumTargets () const 522254721Semaste{ 523254721Semaste Mutex::Locker locker (m_target_list_mutex); 524254721Semaste return m_target_list.size(); 525254721Semaste} 526254721Semaste 527254721Semastelldb::TargetSP 528254721SemasteTargetList::GetTargetAtIndex (uint32_t idx) const 529254721Semaste{ 530254721Semaste TargetSP target_sp; 531254721Semaste Mutex::Locker locker (m_target_list_mutex); 532254721Semaste if (idx < m_target_list.size()) 533254721Semaste target_sp = m_target_list[idx]; 534254721Semaste return target_sp; 535254721Semaste} 536254721Semaste 537254721Semasteuint32_t 538254721SemasteTargetList::GetIndexOfTarget (lldb::TargetSP target_sp) const 539254721Semaste{ 540254721Semaste Mutex::Locker locker (m_target_list_mutex); 541254721Semaste size_t num_targets = m_target_list.size(); 542254721Semaste for (size_t idx = 0; idx < num_targets; idx++) 543254721Semaste { 544254721Semaste if (target_sp == m_target_list[idx]) 545254721Semaste return idx; 546254721Semaste } 547254721Semaste return UINT32_MAX; 548254721Semaste} 549254721Semaste 550254721Semasteuint32_t 551254721SemasteTargetList::SetSelectedTarget (Target* target) 552254721Semaste{ 553254721Semaste Mutex::Locker locker (m_target_list_mutex); 554254721Semaste collection::const_iterator pos, 555254721Semaste begin = m_target_list.begin(), 556254721Semaste end = m_target_list.end(); 557254721Semaste for (pos = begin; pos != end; ++pos) 558254721Semaste { 559254721Semaste if (pos->get() == target) 560254721Semaste { 561254721Semaste m_selected_target_idx = std::distance (begin, pos); 562254721Semaste return m_selected_target_idx; 563254721Semaste } 564254721Semaste } 565254721Semaste m_selected_target_idx = 0; 566254721Semaste return m_selected_target_idx; 567254721Semaste} 568254721Semaste 569254721Semastelldb::TargetSP 570254721SemasteTargetList::GetSelectedTarget () 571254721Semaste{ 572254721Semaste Mutex::Locker locker (m_target_list_mutex); 573254721Semaste if (m_selected_target_idx >= m_target_list.size()) 574254721Semaste m_selected_target_idx = 0; 575254721Semaste return GetTargetAtIndex (m_selected_target_idx); 576254721Semaste} 577