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/State.h"
18 #include "lldb/Core/Timer.h"
19 #include "lldb/Host/Host.h"
20 #include "lldb/Interpreter/CommandInterpreter.h"
21 #include "lldb/Interpreter/OptionGroupPlatform.h"
22 #include "lldb/Target/Platform.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/TargetList.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 ConstString &
30 TargetList::GetStaticBroadcasterClass ()
31 {
32     static ConstString class_name ("lldb.targetList");
33     return class_name;
34 }
35 
36 //----------------------------------------------------------------------
37 // TargetList constructor
38 //----------------------------------------------------------------------
39 TargetList::TargetList(Debugger &debugger) :
40     Broadcaster(&debugger, "TargetList"),
41     m_target_list(),
42     m_target_list_mutex (Mutex::eMutexTypeRecursive),
43     m_selected_target_idx (0)
44 {
45     CheckInWithManager();
46 }
47 
48 //----------------------------------------------------------------------
49 // Destructor
50 //----------------------------------------------------------------------
51 TargetList::~TargetList()
52 {
53     Mutex::Locker locker(m_target_list_mutex);
54     m_target_list.clear();
55 }
56 
57 Error
58 TargetList::CreateTarget (Debugger &debugger,
59                           const FileSpec& file,
60                           const char *triple_cstr,
61                           bool get_dependent_files,
62                           const OptionGroupPlatform *platform_options,
63                           TargetSP &target_sp)
64 {
65     Error error;
66     PlatformSP platform_sp;
67 
68     // This is purposely left empty unless it is specified by triple_cstr.
69     // If not initialized via triple_cstr, then the currently selected platform
70     // will set the architecture correctly.
71     ArchSpec arch;
72 
73     if (triple_cstr)
74     {
75         arch.SetTriple(triple_cstr, platform_sp.get());
76         if (!arch.IsValid())
77         {
78             error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr);
79             return error;
80         }
81     }
82 
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             if (!platform_sp)
94                 return error;
95         }
96     }
97 
98     if (!platform_sp)
99     {
100         // Get the current platform and make sure it is compatible with the
101         // current architecture if we have a valid architecture.
102         platform_sp = debugger.GetPlatformList().GetSelectedPlatform ();
103 
104         if (arch.IsValid() && !platform_sp->IsCompatibleWithArchitecture(arch))
105         {
106             platform_sp = Platform::GetPlatformForArchitecture(arch);
107         }
108     }
109 
110     error = TargetList::CreateTarget (debugger,
111                                       file,
112                                       arch,
113                                       get_dependent_files,
114                                       platform_sp,
115                                       target_sp);
116 
117     if (target_sp)
118     {
119         if (file.GetDirectory())
120         {
121             FileSpec file_dir;
122             file_dir.GetDirectory() = file.GetDirectory();
123             target_sp->GetExecutableSearchPaths ().Append (file_dir);
124         }
125     }
126     return error;
127 }
128 
129 Error
130 TargetList::CreateTarget
131 (
132     Debugger &debugger,
133     const FileSpec& file,
134     const ArchSpec& arch,
135     bool get_dependent_files,
136     PlatformSP &platform_sp,
137     TargetSP &target_sp
138 )
139 {
140     Timer scoped_timer (__PRETTY_FUNCTION__,
141                         "TargetList::CreateTarget (file = '%s/%s', arch = '%s')",
142                         file.GetDirectory().AsCString(),
143                         file.GetFilename().AsCString(),
144                         arch.GetArchitectureName());
145     Error error;
146 
147 
148     if (file)
149     {
150         ModuleSP exe_module_sp;
151         FileSpec resolved_file(file);
152 
153         if (platform_sp)
154         {
155             FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
156             error = platform_sp->ResolveExecutable (file, arch,
157                                                     exe_module_sp,
158                                                     executable_search_paths.GetSize() ? &executable_search_paths : NULL);
159 
160             if (exe_module_sp)
161             {
162                 const ArchSpec &arch = exe_module_sp->GetArchitecture();
163                 if (arch.IsValid() && !platform_sp->IsCompatibleWithArchitecture(arch))
164                     platform_sp = Platform::GetPlatformForArchitecture(arch);
165             }
166         }
167 
168         if (error.Success() && exe_module_sp)
169         {
170             if (exe_module_sp->GetObjectFile() == NULL)
171             {
172                 if (arch.IsValid())
173                 {
174                     error.SetErrorStringWithFormat("\"%s%s%s\" doesn't contain architecture %s",
175                                                    file.GetDirectory().AsCString(),
176                                                    file.GetDirectory() ? "/" : "",
177                                                    file.GetFilename().AsCString(),
178                                                    arch.GetArchitectureName());
179                 }
180                 else
181                 {
182                     error.SetErrorStringWithFormat("unsupported file type \"%s%s%s\"",
183                                                    file.GetDirectory().AsCString(),
184                                                    file.GetDirectory() ? "/" : "",
185                                                    file.GetFilename().AsCString());
186                 }
187                 return error;
188             }
189             target_sp.reset(new Target(debugger, arch, platform_sp));
190             target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
191         }
192     }
193     else
194     {
195         // No file was specified, just create an empty target with any arch
196         // if a valid arch was specified
197         target_sp.reset(new Target(debugger, arch, platform_sp));
198     }
199 
200     if (target_sp)
201     {
202         target_sp->UpdateInstanceName();
203 
204         Mutex::Locker locker(m_target_list_mutex);
205         m_selected_target_idx = m_target_list.size();
206         m_target_list.push_back(target_sp);
207     }
208 
209     return error;
210 }
211 
212 bool
213 TargetList::DeleteTarget (TargetSP &target_sp)
214 {
215     Mutex::Locker locker(m_target_list_mutex);
216     collection::iterator pos, end = m_target_list.end();
217 
218     for (pos = m_target_list.begin(); pos != end; ++pos)
219     {
220         if (pos->get() == target_sp.get())
221         {
222             m_target_list.erase(pos);
223             return true;
224         }
225     }
226     return false;
227 }
228 
229 
230 TargetSP
231 TargetList::FindTargetWithExecutableAndArchitecture
232 (
233     const FileSpec &exe_file_spec,
234     const ArchSpec *exe_arch_ptr
235 ) const
236 {
237     Mutex::Locker locker (m_target_list_mutex);
238     TargetSP target_sp;
239     bool full_match = exe_file_spec.GetDirectory();
240 
241     collection::const_iterator pos, end = m_target_list.end();
242     for (pos = m_target_list.begin(); pos != end; ++pos)
243     {
244         Module *exe_module = (*pos)->GetExecutableModulePointer();
245 
246         if (exe_module)
247         {
248             if (FileSpec::Equal (exe_file_spec, exe_module->GetFileSpec(), full_match))
249             {
250                 if (exe_arch_ptr)
251                 {
252                     if (*exe_arch_ptr != exe_module->GetArchitecture())
253                         continue;
254                 }
255                 target_sp = *pos;
256                 break;
257             }
258         }
259     }
260     return target_sp;
261 }
262 
263 TargetSP
264 TargetList::FindTargetWithProcessID (lldb::pid_t pid) const
265 {
266     Mutex::Locker locker(m_target_list_mutex);
267     TargetSP target_sp;
268     collection::const_iterator pos, end = m_target_list.end();
269     for (pos = m_target_list.begin(); pos != end; ++pos)
270     {
271         Process* process = (*pos)->GetProcessSP().get();
272         if (process && process->GetID() == pid)
273         {
274             target_sp = *pos;
275             break;
276         }
277     }
278     return target_sp;
279 }
280 
281 
282 TargetSP
283 TargetList::FindTargetWithProcess (Process *process) const
284 {
285     TargetSP target_sp;
286     if (process)
287     {
288         Mutex::Locker locker(m_target_list_mutex);
289         collection::const_iterator pos, end = m_target_list.end();
290         for (pos = m_target_list.begin(); pos != end; ++pos)
291         {
292             if (process == (*pos)->GetProcessSP().get())
293             {
294                 target_sp = *pos;
295                 break;
296             }
297         }
298     }
299     return target_sp;
300 }
301 
302 TargetSP
303 TargetList::GetTargetSP (Target *target) const
304 {
305     TargetSP target_sp;
306     if (target)
307     {
308         Mutex::Locker locker(m_target_list_mutex);
309         collection::const_iterator pos, end = m_target_list.end();
310         for (pos = m_target_list.begin(); pos != end; ++pos)
311         {
312             if (target == (*pos).get())
313             {
314                 target_sp = *pos;
315                 break;
316             }
317         }
318     }
319     return target_sp;
320 }
321 
322 uint32_t
323 TargetList::SendAsyncInterrupt (lldb::pid_t pid)
324 {
325     uint32_t num_async_interrupts_sent = 0;
326 
327     if (pid != LLDB_INVALID_PROCESS_ID)
328     {
329         TargetSP target_sp(FindTargetWithProcessID (pid));
330         if (target_sp.get())
331         {
332             Process* process = target_sp->GetProcessSP().get();
333             if (process)
334             {
335                 process->BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
336                 ++num_async_interrupts_sent;
337             }
338         }
339     }
340     else
341     {
342         // We don't have a valid pid to broadcast to, so broadcast to the target
343         // list's async broadcaster...
344         BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
345     }
346 
347     return num_async_interrupts_sent;
348 }
349 
350 uint32_t
351 TargetList::SignalIfRunning (lldb::pid_t pid, int signo)
352 {
353     uint32_t num_signals_sent = 0;
354     Process *process = NULL;
355     if (pid == LLDB_INVALID_PROCESS_ID)
356     {
357         // Signal all processes with signal
358         Mutex::Locker locker(m_target_list_mutex);
359         collection::iterator pos, end = m_target_list.end();
360         for (pos = m_target_list.begin(); pos != end; ++pos)
361         {
362             process = (*pos)->GetProcessSP().get();
363             if (process)
364             {
365                 if (process->IsAlive())
366                 {
367                     ++num_signals_sent;
368                     process->Signal (signo);
369                 }
370             }
371         }
372     }
373     else
374     {
375         // Signal a specific process with signal
376         TargetSP target_sp(FindTargetWithProcessID (pid));
377         if (target_sp.get())
378         {
379             process = target_sp->GetProcessSP().get();
380             if (process)
381             {
382                 if (process->IsAlive())
383                 {
384                     ++num_signals_sent;
385                     process->Signal (signo);
386                 }
387             }
388         }
389     }
390     return num_signals_sent;
391 }
392 
393 int
394 TargetList::GetNumTargets () const
395 {
396     Mutex::Locker locker (m_target_list_mutex);
397     return m_target_list.size();
398 }
399 
400 lldb::TargetSP
401 TargetList::GetTargetAtIndex (uint32_t idx) const
402 {
403     TargetSP target_sp;
404     Mutex::Locker locker (m_target_list_mutex);
405     if (idx < m_target_list.size())
406         target_sp = m_target_list[idx];
407     return target_sp;
408 }
409 
410 uint32_t
411 TargetList::SetSelectedTarget (Target* target)
412 {
413     Mutex::Locker locker (m_target_list_mutex);
414     collection::const_iterator pos,
415         begin = m_target_list.begin(),
416         end = m_target_list.end();
417     for (pos = begin; pos != end; ++pos)
418     {
419         if (pos->get() == target)
420         {
421             m_selected_target_idx = std::distance (begin, pos);
422             return m_selected_target_idx;
423         }
424     }
425     m_selected_target_idx = 0;
426     return m_selected_target_idx;
427 }
428 
429 lldb::TargetSP
430 TargetList::GetSelectedTarget ()
431 {
432     Mutex::Locker locker (m_target_list_mutex);
433     if (m_selected_target_idx >= m_target_list.size())
434         m_selected_target_idx = 0;
435     return GetTargetAtIndex (m_selected_target_idx);
436 }
437