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