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