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         // Now sign the Debugger up to listen to target events for this target:
166         debugger.GetListener().StartListeningForEvents(target_sp.get(), Target::eBroadcastBitBreakpointChanged);
167     }
168 
169     return error;
170 }
171 
172 bool
173 TargetList::DeleteTarget (TargetSP &target_sp)
174 {
175     Mutex::Locker locker(m_target_list_mutex);
176     collection::iterator pos, end = m_target_list.end();
177 
178     for (pos = m_target_list.begin(); pos != end; ++pos)
179     {
180         if (pos->get() == target_sp.get())
181         {
182             m_target_list.erase(pos);
183             return true;
184         }
185     }
186     return false;
187 }
188 
189 
190 TargetSP
191 TargetList::FindTargetWithExecutableAndArchitecture
192 (
193     const FileSpec &exe_file_spec,
194     const ArchSpec *exe_arch_ptr
195 ) const
196 {
197     Mutex::Locker locker (m_target_list_mutex);
198     TargetSP target_sp;
199     bool full_match = exe_file_spec.GetDirectory();
200 
201     collection::const_iterator pos, end = m_target_list.end();
202     for (pos = m_target_list.begin(); pos != end; ++pos)
203     {
204         Module *exe_module = (*pos)->GetExecutableModulePointer();
205 
206         if (exe_module)
207         {
208             if (FileSpec::Equal (exe_file_spec, exe_module->GetFileSpec(), full_match))
209             {
210                 if (exe_arch_ptr)
211                 {
212                     if (*exe_arch_ptr != exe_module->GetArchitecture())
213                         continue;
214                 }
215                 target_sp = *pos;
216                 break;
217             }
218         }
219     }
220     return target_sp;
221 }
222 
223 TargetSP
224 TargetList::FindTargetWithProcessID (lldb::pid_t pid) const
225 {
226     Mutex::Locker locker(m_target_list_mutex);
227     TargetSP target_sp;
228     collection::const_iterator pos, end = m_target_list.end();
229     for (pos = m_target_list.begin(); pos != end; ++pos)
230     {
231         Process* process = (*pos)->GetProcessSP().get();
232         if (process && process->GetID() == pid)
233         {
234             target_sp = *pos;
235             break;
236         }
237     }
238     return target_sp;
239 }
240 
241 
242 TargetSP
243 TargetList::FindTargetWithProcess (Process *process) const
244 {
245     TargetSP target_sp;
246     if (process)
247     {
248         Mutex::Locker locker(m_target_list_mutex);
249         collection::const_iterator pos, end = m_target_list.end();
250         for (pos = m_target_list.begin(); pos != end; ++pos)
251         {
252             if (process == (*pos)->GetProcessSP().get())
253             {
254                 target_sp = *pos;
255                 break;
256             }
257         }
258     }
259     return target_sp;
260 }
261 
262 TargetSP
263 TargetList::GetTargetSP (Target *target) const
264 {
265     TargetSP target_sp;
266     if (target)
267     {
268         Mutex::Locker locker(m_target_list_mutex);
269         collection::const_iterator pos, end = m_target_list.end();
270         for (pos = m_target_list.begin(); pos != end; ++pos)
271         {
272             if (target == (*pos).get())
273             {
274                 target_sp = *pos;
275                 break;
276             }
277         }
278     }
279     return target_sp;
280 }
281 
282 uint32_t
283 TargetList::SendAsyncInterrupt (lldb::pid_t pid)
284 {
285     uint32_t num_async_interrupts_sent = 0;
286 
287     if (pid != LLDB_INVALID_PROCESS_ID)
288     {
289         TargetSP target_sp(FindTargetWithProcessID (pid));
290         if (target_sp.get())
291         {
292             Process* process = target_sp->GetProcessSP().get();
293             if (process)
294             {
295                 process->BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
296                 ++num_async_interrupts_sent;
297             }
298         }
299     }
300     else
301     {
302         // We don't have a valid pid to broadcast to, so broadcast to the target
303         // list's async broadcaster...
304         BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
305     }
306 
307     return num_async_interrupts_sent;
308 }
309 
310 uint32_t
311 TargetList::SignalIfRunning (lldb::pid_t pid, int signo)
312 {
313     uint32_t num_signals_sent = 0;
314     Process *process = NULL;
315     if (pid == LLDB_INVALID_PROCESS_ID)
316     {
317         // Signal all processes with signal
318         Mutex::Locker locker(m_target_list_mutex);
319         collection::iterator pos, end = m_target_list.end();
320         for (pos = m_target_list.begin(); pos != end; ++pos)
321         {
322             process = (*pos)->GetProcessSP().get();
323             if (process)
324             {
325                 if (process->IsAlive())
326                 {
327                     ++num_signals_sent;
328                     process->Signal (signo);
329                 }
330             }
331         }
332     }
333     else
334     {
335         // Signal a specific process with signal
336         TargetSP target_sp(FindTargetWithProcessID (pid));
337         if (target_sp.get())
338         {
339             process = target_sp->GetProcessSP().get();
340             if (process)
341             {
342                 if (process->IsAlive())
343                 {
344                     ++num_signals_sent;
345                     process->Signal (signo);
346                 }
347             }
348         }
349     }
350     return num_signals_sent;
351 }
352 
353 int
354 TargetList::GetNumTargets () const
355 {
356     Mutex::Locker locker (m_target_list_mutex);
357     return m_target_list.size();
358 }
359 
360 lldb::TargetSP
361 TargetList::GetTargetAtIndex (uint32_t idx) const
362 {
363     TargetSP target_sp;
364     Mutex::Locker locker (m_target_list_mutex);
365     if (idx < m_target_list.size())
366         target_sp = m_target_list[idx];
367     return target_sp;
368 }
369 
370 uint32_t
371 TargetList::SetSelectedTarget (Target* target)
372 {
373     Mutex::Locker locker (m_target_list_mutex);
374     collection::const_iterator pos,
375         begin = m_target_list.begin(),
376         end = m_target_list.end();
377     for (pos = begin; pos != end; ++pos)
378     {
379         if (pos->get() == target)
380         {
381             m_selected_target_idx = std::distance (begin, pos);
382             return m_selected_target_idx;
383         }
384     }
385     m_selected_target_idx = 0;
386     return m_selected_target_idx;
387 }
388 
389 lldb::TargetSP
390 TargetList::GetSelectedTarget ()
391 {
392     Mutex::Locker locker (m_target_list_mutex);
393     if (m_selected_target_idx >= m_target_list.size())
394         m_selected_target_idx = 0;
395     return GetTargetAtIndex (m_selected_target_idx);
396 }
397