1 //===-- TargetList.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "lldb/Core/Broadcaster.h"
15 #include "lldb/Core/Debugger.h"
16 #include "lldb/Core/Event.h"
17 #include "lldb/Core/Module.h"
18 #include "lldb/Core/State.h"
19 #include "lldb/Core/Timer.h"
20 #include "lldb/Host/Host.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/OptionGroupPlatform.h"
23 #include "lldb/Target/Platform.h"
24 #include "lldb/Target/Process.h"
25 #include "lldb/Target/TargetList.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 ConstString &
31 TargetList::GetStaticBroadcasterClass ()
32 {
33     static ConstString class_name ("lldb.targetList");
34     return class_name;
35 }
36 
37 //----------------------------------------------------------------------
38 // TargetList constructor
39 //----------------------------------------------------------------------
40 TargetList::TargetList(Debugger &debugger) :
41     Broadcaster(&debugger, TargetList::GetStaticBroadcasterClass().AsCString()),
42     m_target_list(),
43     m_target_list_mutex (Mutex::eMutexTypeRecursive),
44     m_selected_target_idx (0)
45 {
46     CheckInWithManager();
47 }
48 
49 //----------------------------------------------------------------------
50 // Destructor
51 //----------------------------------------------------------------------
52 TargetList::~TargetList()
53 {
54     Mutex::Locker locker(m_target_list_mutex);
55     m_target_list.clear();
56 }
57 
58 Error
59 TargetList::CreateTarget (Debugger &debugger,
60                           const char *user_exe_path,
61                           const char *triple_cstr,
62                           bool get_dependent_files,
63                           const OptionGroupPlatform *platform_options,
64                           TargetSP &target_sp)
65 {
66     Error error;
67     PlatformSP platform_sp;
68 
69     // This is purposely left empty unless it is specified by triple_cstr.
70     // If not initialized via triple_cstr, then the currently selected platform
71     // will set the architecture correctly.
72     const ArchSpec arch(triple_cstr);
73     if (triple_cstr && triple_cstr[0])
74     {
75         if (!arch.IsValid())
76         {
77             error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr);
78             return error;
79         }
80     }
81 
82     ArchSpec platform_arch(arch);
83     CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
84     if (platform_options)
85     {
86         if (platform_options->PlatformWasSpecified ())
87         {
88             const bool select_platform = true;
89             platform_sp = platform_options->CreatePlatformWithOptions (interpreter,
90                                                                        arch,
91                                                                        select_platform,
92                                                                        error,
93                                                                        platform_arch);
94             if (!platform_sp)
95                 return error;
96         }
97     }
98 
99     if (!platform_sp)
100     {
101         // Get the current platform and make sure it is compatible with the
102         // current architecture if we have a valid architecture.
103         platform_sp = debugger.GetPlatformList().GetSelectedPlatform ();
104 
105         if (arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, &platform_arch))
106         {
107             platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
108         }
109     }
110 
111     if (!platform_arch.IsValid())
112         platform_arch = arch;
113 
114     error = TargetList::CreateTarget (debugger,
115                                       user_exe_path,
116                                       platform_arch,
117                                       get_dependent_files,
118                                       platform_sp,
119                                       target_sp);
120     return error;
121 }
122 
123 Error
124 TargetList::CreateTarget (Debugger &debugger,
125                           const char *user_exe_path,
126                           const ArchSpec& specified_arch,
127                           bool get_dependent_files,
128                           PlatformSP &platform_sp,
129                           TargetSP &target_sp)
130 {
131     Timer scoped_timer (__PRETTY_FUNCTION__,
132                         "TargetList::CreateTarget (file = '%s', arch = '%s')",
133                         user_exe_path,
134                         specified_arch.GetArchitectureName());
135     Error error;
136 
137     ArchSpec arch(specified_arch);
138 
139     if (platform_sp)
140     {
141         if (arch.IsValid())
142         {
143             if (!platform_sp->IsCompatibleArchitecture(arch))
144                 platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
145         }
146     }
147     else if (arch.IsValid())
148     {
149         platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
150     }
151 
152     if (!platform_sp)
153         platform_sp = debugger.GetPlatformList().GetSelectedPlatform();
154 
155     if (!arch.IsValid())
156         arch = specified_arch;
157 
158     FileSpec file (user_exe_path, false);
159     bool user_exe_path_is_bundle = false;
160     char resolved_bundle_exe_path[PATH_MAX];
161     resolved_bundle_exe_path[0] = '\0';
162     if (file)
163     {
164         if (file.GetFileType() == FileSpec::eFileTypeDirectory)
165             user_exe_path_is_bundle = true;
166 
167         if (file.IsRelativeToCurrentWorkingDirectory())
168         {
169             // Ignore paths that start with "./" and "../"
170             if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') ||
171                   (user_exe_path[0] == '.' && user_exe_path[1] == '.' && user_exe_path[2] == '/')))
172             {
173                 char cwd[PATH_MAX];
174                 if (getcwd (cwd, sizeof(cwd)))
175                 {
176                     std::string cwd_user_exe_path (cwd);
177                     cwd_user_exe_path += '/';
178                     cwd_user_exe_path += user_exe_path;
179                     file.SetFile(cwd_user_exe_path.c_str(), false);
180                 }
181             }
182         }
183 
184         ModuleSP exe_module_sp;
185         if (platform_sp)
186         {
187             FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
188             error = platform_sp->ResolveExecutable (file,
189                                                     arch,
190                                                     exe_module_sp,
191                                                     executable_search_paths.GetSize() ? &executable_search_paths : NULL);
192         }
193 
194         if (error.Success() && exe_module_sp)
195         {
196             if (exe_module_sp->GetObjectFile() == NULL)
197             {
198                 if (arch.IsValid())
199                 {
200                     error.SetErrorStringWithFormat("\"%s%s%s\" doesn't contain architecture %s",
201                                                    file.GetDirectory().AsCString(),
202                                                    file.GetDirectory() ? "/" : "",
203                                                    file.GetFilename().AsCString(),
204                                                    arch.GetArchitectureName());
205                 }
206                 else
207                 {
208                     error.SetErrorStringWithFormat("unsupported file type \"%s%s%s\"",
209                                                    file.GetDirectory().AsCString(),
210                                                    file.GetDirectory() ? "/" : "",
211                                                    file.GetFilename().AsCString());
212                 }
213                 return error;
214             }
215             target_sp.reset(new Target(debugger, arch, platform_sp));
216             target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
217             if (user_exe_path_is_bundle)
218                 exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, sizeof(resolved_bundle_exe_path));
219         }
220     }
221     else
222     {
223         // No file was specified, just create an empty target with any arch
224         // if a valid arch was specified
225         target_sp.reset(new Target(debugger, arch, platform_sp));
226     }
227 
228     if (target_sp)
229     {
230         // Set argv0 with what the user typed, unless the user specified a
231         // directory. If the user specified a directory, then it is probably a
232         // bundle that was resolved and we need to use the resolved bundle path
233         if (user_exe_path)
234         {
235             // Use exactly what the user typed as the first argument when we exec or posix_spawn
236             if (user_exe_path_is_bundle && resolved_bundle_exe_path[0])
237             {
238                 target_sp->SetArg0 (resolved_bundle_exe_path);
239             }
240             else
241             {
242                 // Just use what the user typed
243                 target_sp->SetArg0 (user_exe_path);
244             }
245         }
246         if (file.GetDirectory())
247         {
248             FileSpec file_dir;
249             file_dir.GetDirectory() = file.GetDirectory();
250             target_sp->GetExecutableSearchPaths ().Append (file_dir);
251         }
252         Mutex::Locker locker(m_target_list_mutex);
253         m_selected_target_idx = m_target_list.size();
254         m_target_list.push_back(target_sp);
255 
256 
257     }
258 
259     return error;
260 }
261 
262 bool
263 TargetList::DeleteTarget (TargetSP &target_sp)
264 {
265     Mutex::Locker locker(m_target_list_mutex);
266     collection::iterator pos, end = m_target_list.end();
267 
268     for (pos = m_target_list.begin(); pos != end; ++pos)
269     {
270         if (pos->get() == target_sp.get())
271         {
272             m_target_list.erase(pos);
273             return true;
274         }
275     }
276     return false;
277 }
278 
279 
280 TargetSP
281 TargetList::FindTargetWithExecutableAndArchitecture
282 (
283     const FileSpec &exe_file_spec,
284     const ArchSpec *exe_arch_ptr
285 ) const
286 {
287     Mutex::Locker locker (m_target_list_mutex);
288     TargetSP target_sp;
289     bool full_match = exe_file_spec.GetDirectory();
290 
291     collection::const_iterator pos, end = m_target_list.end();
292     for (pos = m_target_list.begin(); pos != end; ++pos)
293     {
294         Module *exe_module = (*pos)->GetExecutableModulePointer();
295 
296         if (exe_module)
297         {
298             if (FileSpec::Equal (exe_file_spec, exe_module->GetFileSpec(), full_match))
299             {
300                 if (exe_arch_ptr)
301                 {
302                     if (*exe_arch_ptr != exe_module->GetArchitecture())
303                         continue;
304                 }
305                 target_sp = *pos;
306                 break;
307             }
308         }
309     }
310     return target_sp;
311 }
312 
313 TargetSP
314 TargetList::FindTargetWithProcessID (lldb::pid_t pid) const
315 {
316     Mutex::Locker locker(m_target_list_mutex);
317     TargetSP target_sp;
318     collection::const_iterator pos, end = m_target_list.end();
319     for (pos = m_target_list.begin(); pos != end; ++pos)
320     {
321         Process* process = (*pos)->GetProcessSP().get();
322         if (process && process->GetID() == pid)
323         {
324             target_sp = *pos;
325             break;
326         }
327     }
328     return target_sp;
329 }
330 
331 
332 TargetSP
333 TargetList::FindTargetWithProcess (Process *process) const
334 {
335     TargetSP target_sp;
336     if (process)
337     {
338         Mutex::Locker locker(m_target_list_mutex);
339         collection::const_iterator pos, end = m_target_list.end();
340         for (pos = m_target_list.begin(); pos != end; ++pos)
341         {
342             if (process == (*pos)->GetProcessSP().get())
343             {
344                 target_sp = *pos;
345                 break;
346             }
347         }
348     }
349     return target_sp;
350 }
351 
352 TargetSP
353 TargetList::GetTargetSP (Target *target) const
354 {
355     TargetSP target_sp;
356     if (target)
357     {
358         Mutex::Locker locker(m_target_list_mutex);
359         collection::const_iterator pos, end = m_target_list.end();
360         for (pos = m_target_list.begin(); pos != end; ++pos)
361         {
362             if (target == (*pos).get())
363             {
364                 target_sp = *pos;
365                 break;
366             }
367         }
368     }
369     return target_sp;
370 }
371 
372 uint32_t
373 TargetList::SendAsyncInterrupt (lldb::pid_t pid)
374 {
375     uint32_t num_async_interrupts_sent = 0;
376 
377     if (pid != LLDB_INVALID_PROCESS_ID)
378     {
379         TargetSP target_sp(FindTargetWithProcessID (pid));
380         if (target_sp.get())
381         {
382             Process* process = target_sp->GetProcessSP().get();
383             if (process)
384             {
385                 process->SendAsyncInterrupt();
386                 ++num_async_interrupts_sent;
387             }
388         }
389     }
390     else
391     {
392         // We don't have a valid pid to broadcast to, so broadcast to the target
393         // list's async broadcaster...
394         BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
395     }
396 
397     return num_async_interrupts_sent;
398 }
399 
400 uint32_t
401 TargetList::SignalIfRunning (lldb::pid_t pid, int signo)
402 {
403     uint32_t num_signals_sent = 0;
404     Process *process = NULL;
405     if (pid == LLDB_INVALID_PROCESS_ID)
406     {
407         // Signal all processes with signal
408         Mutex::Locker locker(m_target_list_mutex);
409         collection::iterator pos, end = m_target_list.end();
410         for (pos = m_target_list.begin(); pos != end; ++pos)
411         {
412             process = (*pos)->GetProcessSP().get();
413             if (process)
414             {
415                 if (process->IsAlive())
416                 {
417                     ++num_signals_sent;
418                     process->Signal (signo);
419                 }
420             }
421         }
422     }
423     else
424     {
425         // Signal a specific process with signal
426         TargetSP target_sp(FindTargetWithProcessID (pid));
427         if (target_sp.get())
428         {
429             process = target_sp->GetProcessSP().get();
430             if (process)
431             {
432                 if (process->IsAlive())
433                 {
434                     ++num_signals_sent;
435                     process->Signal (signo);
436                 }
437             }
438         }
439     }
440     return num_signals_sent;
441 }
442 
443 int
444 TargetList::GetNumTargets () const
445 {
446     Mutex::Locker locker (m_target_list_mutex);
447     return m_target_list.size();
448 }
449 
450 lldb::TargetSP
451 TargetList::GetTargetAtIndex (uint32_t idx) const
452 {
453     TargetSP target_sp;
454     Mutex::Locker locker (m_target_list_mutex);
455     if (idx < m_target_list.size())
456         target_sp = m_target_list[idx];
457     return target_sp;
458 }
459 
460 uint32_t
461 TargetList::GetIndexOfTarget (lldb::TargetSP target_sp) const
462 {
463     Mutex::Locker locker (m_target_list_mutex);
464     size_t num_targets = m_target_list.size();
465     for (size_t idx = 0; idx < num_targets; idx++)
466     {
467         if (target_sp == m_target_list[idx])
468             return idx;
469     }
470     return UINT32_MAX;
471 }
472 
473 uint32_t
474 TargetList::SetSelectedTarget (Target* target)
475 {
476     Mutex::Locker locker (m_target_list_mutex);
477     collection::const_iterator pos,
478         begin = m_target_list.begin(),
479         end = m_target_list.end();
480     for (pos = begin; pos != end; ++pos)
481     {
482         if (pos->get() == target)
483         {
484             m_selected_target_idx = std::distance (begin, pos);
485             return m_selected_target_idx;
486         }
487     }
488     m_selected_target_idx = 0;
489     return m_selected_target_idx;
490 }
491 
492 lldb::TargetSP
493 TargetList::GetSelectedTarget ()
494 {
495     Mutex::Locker locker (m_target_list_mutex);
496     if (m_selected_target_idx >= m_target_list.size())
497         m_selected_target_idx = 0;
498     return GetTargetAtIndex (m_selected_target_idx);
499 }
500