1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #include "lldb/lldb-python.h" |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | #include "lldb/Core/Broadcaster.h" |
17 | #include "lldb/Core/Debugger.h" |
18 | #include "lldb/Core/Event.h" |
19 | #include "lldb/Core/Module.h" |
20 | #include "lldb/Core/ModuleSpec.h" |
21 | #include "lldb/Core/State.h" |
22 | #include "lldb/Core/Timer.h" |
23 | #include "lldb/Host/Host.h" |
24 | #include "lldb/Interpreter/CommandInterpreter.h" |
25 | #include "lldb/Interpreter/OptionGroupPlatform.h" |
26 | #include "lldb/Symbol/ObjectFile.h" |
27 | #include "lldb/Target/Platform.h" |
28 | #include "lldb/Target/Process.h" |
29 | #include "lldb/Target/TargetList.h" |
30 | |
31 | #include "llvm/ADT/SmallString.h" |
32 | |
33 | using namespace lldb; |
34 | using namespace lldb_private; |
35 | |
36 | ConstString & |
37 | TargetList::GetStaticBroadcasterClass () |
38 | { |
39 | static ConstString class_name ("lldb.targetList"); |
40 | return class_name; |
41 | } |
42 | |
43 | |
44 | |
45 | |
46 | TargetList::TargetList(Debugger &debugger) : |
47 | Broadcaster(&debugger, TargetList::GetStaticBroadcasterClass().AsCString()), |
48 | m_target_list(), |
49 | m_target_list_mutex (Mutex::eMutexTypeRecursive), |
50 | m_selected_target_idx (0) |
51 | { |
52 | CheckInWithManager(); |
53 | } |
54 | |
55 | |
56 | |
57 | |
58 | TargetList::~TargetList() |
59 | { |
60 | Mutex::Locker locker(m_target_list_mutex); |
61 | m_target_list.clear(); |
62 | } |
63 | |
64 | Error |
65 | TargetList::CreateTarget (Debugger &debugger, |
66 | const char *user_exe_path, |
67 | const char *triple_cstr, |
68 | bool get_dependent_files, |
69 | const OptionGroupPlatform *platform_options, |
70 | TargetSP &target_sp) |
71 | { |
72 | Error error; |
73 | PlatformSP platform_sp; |
74 | |
75 | |
76 | |
77 | |
78 | const ArchSpec arch(triple_cstr); |
79 | if (triple_cstr && triple_cstr[0]) |
80 | { |
81 | if (!arch.IsValid()) |
82 | { |
83 | error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr); |
84 | return error; |
85 | } |
86 | } |
87 | |
88 | ArchSpec platform_arch(arch); |
89 | |
90 | bool prefer_platform_arch = false; |
91 | |
92 | CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); |
93 | if (platform_options && platform_options->PlatformWasSpecified ()) |
94 | { |
95 | const bool select_platform = true; |
96 | platform_sp = platform_options->CreatePlatformWithOptions (interpreter, |
97 | arch, |
98 | select_platform, |
99 | error, |
100 | platform_arch); |
101 | if (!platform_sp) |
102 | return error; |
103 | } |
104 | |
105 | if (user_exe_path && user_exe_path[0]) |
106 | { |
107 | ModuleSpecList module_specs; |
108 | ModuleSpec module_spec; |
109 | module_spec.GetFileSpec().SetFile(user_exe_path, true); |
110 | |
111 | |
112 | |
113 | Host::ResolveExecutableInBundle (module_spec.GetFileSpec()); |
114 | |
115 | lldb::offset_t file_offset = 0; |
116 | lldb::offset_t file_size = 0; |
117 | const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs); |
118 | if (num_specs > 0) |
119 | { |
120 | ModuleSpec matching_module_spec; |
121 | |
122 | if (num_specs == 1) |
123 | { |
124 | if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) |
125 | { |
126 | if (platform_arch.IsValid()) |
127 | { |
128 | if (platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture())) |
129 | { |
130 | |
131 | |
132 | if (!platform_arch.TripleOSWasSpecified() || !platform_arch.TripleVendorWasSpecified()) |
133 | { |
134 | prefer_platform_arch = true; |
135 | platform_arch = matching_module_spec.GetArchitecture(); |
136 | } |
137 | } |
138 | else |
139 | { |
140 | error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'", |
141 | platform_arch.GetTriple().str().c_str(), |
142 | matching_module_spec.GetArchitecture().GetTriple().str().c_str(), |
143 | module_spec.GetFileSpec().GetPath().c_str()); |
144 | return error; |
145 | } |
146 | } |
147 | else |
148 | { |
149 | |
150 | prefer_platform_arch = true; |
151 | platform_arch = matching_module_spec.GetArchitecture(); |
152 | } |
153 | } |
154 | } |
155 | else |
156 | { |
157 | if (arch.IsValid()) |
158 | { |
159 | module_spec.GetArchitecture() = arch; |
160 | if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec)) |
161 | { |
162 | prefer_platform_arch = true; |
163 | platform_arch = matching_module_spec.GetArchitecture(); |
164 | } |
165 | } |
166 | else |
167 | { |
168 | |
169 | |
170 | |
171 | typedef std::vector<PlatformSP> PlatformList; |
172 | PlatformList platforms; |
173 | PlatformSP host_platform_sp = Platform::GetHostPlatform(); |
174 | for (size_t i=0; i<num_specs; ++i) |
175 | { |
176 | ModuleSpec module_spec; |
177 | if (module_specs.GetModuleSpecAtIndex(i, module_spec)) |
178 | { |
179 | |
180 | |
181 | if (platform_sp) |
182 | { |
183 | if (platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL__null)) |
184 | { |
185 | platforms.push_back(platform_sp); |
186 | continue; |
187 | } |
188 | } |
189 | |
190 | |
191 | if (host_platform_sp && (!platform_sp || host_platform_sp->GetName() != platform_sp->GetName())) |
192 | { |
193 | if (host_platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL__null)) |
194 | { |
195 | platforms.push_back(host_platform_sp); |
196 | continue; |
197 | } |
198 | } |
199 | |
200 | |
201 | platforms.push_back(Platform::GetPlatformForArchitecture(module_spec.GetArchitecture(), nullptr)); |
202 | } |
203 | } |
204 | |
205 | Platform *platform_ptr = NULL__null; |
206 | for (const auto &the_platform_sp : platforms) |
207 | { |
208 | if (platform_ptr) |
209 | { |
210 | if (platform_ptr->GetName() != the_platform_sp->GetName()) |
211 | { |
212 | platform_ptr = NULL__null; |
213 | break; |
214 | } |
215 | } |
216 | else |
217 | { |
218 | platform_ptr = the_platform_sp.get(); |
219 | } |
220 | } |
221 | |
222 | if (platform_ptr) |
223 | { |
224 | |
225 | platform_sp = platforms.front(); |
226 | } |
227 | else |
228 | { |
229 | |
230 | StreamString error_strm; |
231 | std::set<Platform *> platform_set; |
232 | error_strm.Printf ("more than one platform supports this executable ("); |
233 | for (const auto &the_platform_sp : platforms) |
234 | { |
235 | if (platform_set.find(the_platform_sp.get()) == platform_set.end()) |
236 | { |
237 | if (!platform_set.empty()) |
238 | error_strm.PutCString(", "); |
239 | error_strm.PutCString(the_platform_sp->GetName().GetCString()); |
240 | platform_set.insert(the_platform_sp.get()); |
241 | } |
242 | } |
243 | error_strm.Printf("), use the --platform option to specify a platform"); |
244 | error.SetErrorString(error_strm.GetString().c_str()); |
245 | return error; |
246 | } |
247 | } |
248 | } |
249 | } |
250 | } |
251 | |
252 | if (!platform_sp) |
253 | { |
254 | |
255 | |
256 | platform_sp = debugger.GetPlatformList().GetSelectedPlatform (); |
257 | |
258 | if (!prefer_platform_arch && arch.IsValid()) |
259 | { |
260 | if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) |
261 | { |
262 | platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); |
263 | if (platform_sp) |
264 | debugger.GetPlatformList().SetSelectedPlatform(platform_sp); |
265 | } |
266 | } |
267 | else if (platform_arch.IsValid()) |
268 | { |
269 | |
270 | |
271 | ArchSpec fixed_platform_arch; |
272 | if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, &fixed_platform_arch)) |
273 | { |
274 | platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch); |
275 | if (platform_sp) |
276 | debugger.GetPlatformList().SetSelectedPlatform(platform_sp); |
277 | } |
278 | } |
279 | } |
280 | |
281 | if (!platform_arch.IsValid()) |
282 | platform_arch = arch; |
283 | |
284 | error = TargetList::CreateTarget (debugger, |
285 | user_exe_path, |
286 | platform_arch, |
287 | get_dependent_files, |
288 | platform_sp, |
289 | target_sp); |
290 | return error; |
291 | } |
292 | |
293 | Error |
294 | TargetList::CreateTarget (Debugger &debugger, |
295 | const char *user_exe_path, |
296 | const ArchSpec& specified_arch, |
297 | bool get_dependent_files, |
298 | PlatformSP &platform_sp, |
299 | TargetSP &target_sp) |
300 | { |
301 | Timer scoped_timer (__PRETTY_FUNCTION__, |
302 | "TargetList::CreateTarget (file = '%s', arch = '%s')", |
303 | user_exe_path, |
304 | specified_arch.GetArchitectureName()); |
305 | Error error; |
306 | |
307 | ArchSpec arch(specified_arch); |
308 | |
309 | if (arch.IsValid()) |
| |
310 | { |
311 | if (!platform_sp || !platform_sp->IsCompatibleArchitecture(arch, false, NULL__null)) |
312 | platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); |
313 | } |
314 | |
315 | if (!platform_sp) |
| |
316 | platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); |
317 | |
318 | if (!arch.IsValid()) |
| |
319 | arch = specified_arch; |
320 | |
321 | FileSpec file (user_exe_path, false); |
322 | if (!file.Exists() && user_exe_path && user_exe_path[0] == '~') |
| 4 | | Assuming pointer value is null | |
|
323 | { |
324 | |
325 | |
326 | llvm::SmallString<64> unglobbed_path(user_exe_path); |
327 | FileSpec::ResolveUsername(unglobbed_path); |
328 | |
329 | if (unglobbed_path.empty()) |
330 | file = FileSpec(user_exe_path, false); |
331 | else |
332 | file = FileSpec(unglobbed_path.c_str(), false); |
333 | } |
334 | |
335 | bool user_exe_path_is_bundle = false; |
336 | char resolved_bundle_exe_path[PATH_MAX4096]; |
337 | resolved_bundle_exe_path[0] = '\0'; |
338 | if (file) |
| |
339 | { |
340 | if (file.GetFileType() == FileSpec::eFileTypeDirectory) |
| |
341 | user_exe_path_is_bundle = true; |
342 | |
343 | if (file.IsRelativeToCurrentWorkingDirectory()) |
| |
344 | { |
345 | |
346 | if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') || |
| 8 | | Array access (from variable 'user_exe_path') results in a null pointer dereference |
|
347 | (user_exe_path[0] == '.' && user_exe_path[1] == '.' && user_exe_path[2] == '/'))) |
348 | { |
349 | char cwd[PATH_MAX4096]; |
350 | if (getcwd (cwd, sizeof(cwd))) |
351 | { |
352 | std::string cwd_user_exe_path (cwd); |
353 | cwd_user_exe_path += '/'; |
354 | cwd_user_exe_path += user_exe_path; |
355 | FileSpec cwd_file (cwd_user_exe_path.c_str(), false); |
356 | if (cwd_file.Exists()) |
357 | file = cwd_file; |
358 | } |
359 | } |
360 | } |
361 | |
362 | ModuleSP exe_module_sp; |
363 | if (platform_sp) |
364 | { |
365 | FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); |
366 | error = platform_sp->ResolveExecutable (file, |
367 | arch, |
368 | exe_module_sp, |
369 | executable_search_paths.GetSize() ? &executable_search_paths : NULL__null); |
370 | } |
371 | |
372 | if (error.Success() && exe_module_sp) |
373 | { |
374 | if (exe_module_sp->GetObjectFile() == NULL__null) |
375 | { |
376 | if (arch.IsValid()) |
377 | { |
378 | error.SetErrorStringWithFormat("\"%s\" doesn't contain architecture %s", |
379 | file.GetPath().c_str(), |
380 | arch.GetArchitectureName()); |
381 | } |
382 | else |
383 | { |
384 | error.SetErrorStringWithFormat("unsupported file type \"%s\"", |
385 | file.GetPath().c_str()); |
386 | } |
387 | return error; |
388 | } |
389 | target_sp.reset(new Target(debugger, arch, platform_sp)); |
390 | target_sp->SetExecutableModule (exe_module_sp, get_dependent_files); |
391 | if (user_exe_path_is_bundle) |
392 | exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, sizeof(resolved_bundle_exe_path)); |
393 | } |
394 | } |
395 | else |
396 | { |
397 | |
398 | |
399 | target_sp.reset(new Target(debugger, arch, platform_sp)); |
400 | } |
401 | |
402 | if (target_sp) |
403 | { |
404 | |
405 | |
406 | |
407 | if (user_exe_path) |
408 | { |
409 | |
410 | if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) |
411 | { |
412 | target_sp->SetArg0 (resolved_bundle_exe_path); |
413 | } |
414 | else |
415 | { |
416 | |
417 | target_sp->SetArg0 (file.GetPath().c_str()); |
418 | } |
419 | } |
420 | if (file.GetDirectory()) |
421 | { |
422 | FileSpec file_dir; |
423 | file_dir.GetDirectory() = file.GetDirectory(); |
424 | target_sp->GetExecutableSearchPaths ().Append (file_dir); |
425 | } |
426 | Mutex::Locker locker(m_target_list_mutex); |
427 | m_selected_target_idx = m_target_list.size(); |
428 | m_target_list.push_back(target_sp); |
429 | |
430 | |
431 | } |
432 | |
433 | return error; |
434 | } |
435 | |
436 | bool |
437 | TargetList::DeleteTarget (TargetSP &target_sp) |
438 | { |
439 | Mutex::Locker locker(m_target_list_mutex); |
440 | collection::iterator pos, end = m_target_list.end(); |
441 | |
442 | for (pos = m_target_list.begin(); pos != end; ++pos) |
443 | { |
444 | if (pos->get() == target_sp.get()) |
445 | { |
446 | m_target_list.erase(pos); |
447 | return true; |
448 | } |
449 | } |
450 | return false; |
451 | } |
452 | |
453 | |
454 | TargetSP |
455 | TargetList::FindTargetWithExecutableAndArchitecture |
456 | ( |
457 | const FileSpec &exe_file_spec, |
458 | const ArchSpec *exe_arch_ptr |
459 | ) const |
460 | { |
461 | Mutex::Locker locker (m_target_list_mutex); |
462 | TargetSP target_sp; |
463 | bool full_match = (bool)exe_file_spec.GetDirectory(); |
464 | |
465 | collection::const_iterator pos, end = m_target_list.end(); |
466 | for (pos = m_target_list.begin(); pos != end; ++pos) |
467 | { |
468 | Module *exe_module = (*pos)->GetExecutableModulePointer(); |
469 | |
470 | if (exe_module) |
471 | { |
472 | if (FileSpec::Equal (exe_file_spec, exe_module->GetFileSpec(), full_match)) |
473 | { |
474 | if (exe_arch_ptr) |
475 | { |
476 | if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture())) |
477 | continue; |
478 | } |
479 | target_sp = *pos; |
480 | break; |
481 | } |
482 | } |
483 | } |
484 | return target_sp; |
485 | } |
486 | |
487 | TargetSP |
488 | TargetList::FindTargetWithProcessID (lldb::pid_t pid) const |
489 | { |
490 | Mutex::Locker locker(m_target_list_mutex); |
491 | TargetSP target_sp; |
492 | collection::const_iterator pos, end = m_target_list.end(); |
493 | for (pos = m_target_list.begin(); pos != end; ++pos) |
494 | { |
495 | Process* process = (*pos)->GetProcessSP().get(); |
496 | if (process && process->GetID() == pid) |
497 | { |
498 | target_sp = *pos; |
499 | break; |
500 | } |
501 | } |
502 | return target_sp; |
503 | } |
504 | |
505 | |
506 | TargetSP |
507 | TargetList::FindTargetWithProcess (Process *process) const |
508 | { |
509 | TargetSP target_sp; |
510 | if (process) |
511 | { |
512 | Mutex::Locker locker(m_target_list_mutex); |
513 | collection::const_iterator pos, end = m_target_list.end(); |
514 | for (pos = m_target_list.begin(); pos != end; ++pos) |
515 | { |
516 | if (process == (*pos)->GetProcessSP().get()) |
517 | { |
518 | target_sp = *pos; |
519 | break; |
520 | } |
521 | } |
522 | } |
523 | return target_sp; |
524 | } |
525 | |
526 | TargetSP |
527 | TargetList::GetTargetSP (Target *target) const |
528 | { |
529 | TargetSP target_sp; |
530 | if (target) |
531 | { |
532 | Mutex::Locker locker(m_target_list_mutex); |
533 | collection::const_iterator pos, end = m_target_list.end(); |
534 | for (pos = m_target_list.begin(); pos != end; ++pos) |
535 | { |
536 | if (target == (*pos).get()) |
537 | { |
538 | target_sp = *pos; |
539 | break; |
540 | } |
541 | } |
542 | } |
543 | return target_sp; |
544 | } |
545 | |
546 | uint32_t |
547 | TargetList::SendAsyncInterrupt (lldb::pid_t pid) |
548 | { |
549 | uint32_t num_async_interrupts_sent = 0; |
550 | |
551 | if (pid != LLDB_INVALID_PROCESS_ID0) |
552 | { |
553 | TargetSP target_sp(FindTargetWithProcessID (pid)); |
554 | if (target_sp.get()) |
555 | { |
556 | Process* process = target_sp->GetProcessSP().get(); |
557 | if (process) |
558 | { |
559 | process->SendAsyncInterrupt(); |
560 | ++num_async_interrupts_sent; |
561 | } |
562 | } |
563 | } |
564 | else |
565 | { |
566 | |
567 | |
568 | BroadcastEvent (Process::eBroadcastBitInterrupt, NULL__null); |
569 | } |
570 | |
571 | return num_async_interrupts_sent; |
572 | } |
573 | |
574 | uint32_t |
575 | TargetList::SignalIfRunning (lldb::pid_t pid, int signo) |
576 | { |
577 | uint32_t num_signals_sent = 0; |
578 | Process *process = NULL__null; |
579 | if (pid == LLDB_INVALID_PROCESS_ID0) |
580 | { |
581 | |
582 | Mutex::Locker locker(m_target_list_mutex); |
583 | collection::iterator pos, end = m_target_list.end(); |
584 | for (pos = m_target_list.begin(); pos != end; ++pos) |
585 | { |
586 | process = (*pos)->GetProcessSP().get(); |
587 | if (process) |
588 | { |
589 | if (process->IsAlive()) |
590 | { |
591 | ++num_signals_sent; |
592 | process->Signal (signo); |
593 | } |
594 | } |
595 | } |
596 | } |
597 | else |
598 | { |
599 | |
600 | TargetSP target_sp(FindTargetWithProcessID (pid)); |
601 | if (target_sp.get()) |
602 | { |
603 | process = target_sp->GetProcessSP().get(); |
604 | if (process) |
605 | { |
606 | if (process->IsAlive()) |
607 | { |
608 | ++num_signals_sent; |
609 | process->Signal (signo); |
610 | } |
611 | } |
612 | } |
613 | } |
614 | return num_signals_sent; |
615 | } |
616 | |
617 | int |
618 | TargetList::GetNumTargets () const |
619 | { |
620 | Mutex::Locker locker (m_target_list_mutex); |
621 | return m_target_list.size(); |
622 | } |
623 | |
624 | lldb::TargetSP |
625 | TargetList::GetTargetAtIndex (uint32_t idx) const |
626 | { |
627 | TargetSP target_sp; |
628 | Mutex::Locker locker (m_target_list_mutex); |
629 | if (idx < m_target_list.size()) |
630 | target_sp = m_target_list[idx]; |
631 | return target_sp; |
632 | } |
633 | |
634 | uint32_t |
635 | TargetList::GetIndexOfTarget (lldb::TargetSP target_sp) const |
636 | { |
637 | Mutex::Locker locker (m_target_list_mutex); |
638 | size_t num_targets = m_target_list.size(); |
639 | for (size_t idx = 0; idx < num_targets; idx++) |
640 | { |
641 | if (target_sp == m_target_list[idx]) |
642 | return idx; |
643 | } |
644 | return UINT32_MAX(4294967295U); |
645 | } |
646 | |
647 | uint32_t |
648 | TargetList::SetSelectedTarget (Target* target) |
649 | { |
650 | Mutex::Locker locker (m_target_list_mutex); |
651 | collection::const_iterator pos, |
652 | begin = m_target_list.begin(), |
653 | end = m_target_list.end(); |
654 | for (pos = begin; pos != end; ++pos) |
655 | { |
656 | if (pos->get() == target) |
657 | { |
658 | m_selected_target_idx = std::distance (begin, pos); |
659 | return m_selected_target_idx; |
660 | } |
661 | } |
662 | m_selected_target_idx = 0; |
663 | return m_selected_target_idx; |
664 | } |
665 | |
666 | lldb::TargetSP |
667 | TargetList::GetSelectedTarget () |
668 | { |
669 | Mutex::Locker locker (m_target_list_mutex); |
670 | if (m_selected_target_idx >= m_target_list.size()) |
671 | m_selected_target_idx = 0; |
672 | return GetTargetAtIndex (m_selected_target_idx); |
673 | } |