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