Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Target/TargetList.cpp
39587 views
1
//===-- TargetList.cpp ----------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "lldb/Target/TargetList.h"
10
#include "lldb/Core/Debugger.h"
11
#include "lldb/Core/Module.h"
12
#include "lldb/Core/ModuleSpec.h"
13
#include "lldb/Host/Host.h"
14
#include "lldb/Host/HostInfo.h"
15
#include "lldb/Interpreter/CommandInterpreter.h"
16
#include "lldb/Interpreter/OptionGroupPlatform.h"
17
#include "lldb/Symbol/ObjectFile.h"
18
#include "lldb/Target/Platform.h"
19
#include "lldb/Target/Process.h"
20
#include "lldb/Utility/Broadcaster.h"
21
#include "lldb/Utility/Event.h"
22
#include "lldb/Utility/State.h"
23
#include "lldb/Utility/TildeExpressionResolver.h"
24
#include "lldb/Utility/Timer.h"
25
26
#include "llvm/ADT/SmallString.h"
27
#include "llvm/Support/FileSystem.h"
28
29
using namespace lldb;
30
using namespace lldb_private;
31
32
llvm::StringRef TargetList::GetStaticBroadcasterClass() {
33
static constexpr llvm::StringLiteral class_name("lldb.targetList");
34
return class_name;
35
}
36
37
// TargetList constructor
38
TargetList::TargetList(Debugger &debugger)
39
: Broadcaster(debugger.GetBroadcasterManager(),
40
TargetList::GetStaticBroadcasterClass().str()),
41
m_target_list(), m_target_list_mutex(), m_selected_target_idx(0) {
42
CheckInWithManager();
43
}
44
45
Status TargetList::CreateTarget(Debugger &debugger,
46
llvm::StringRef user_exe_path,
47
llvm::StringRef triple_str,
48
LoadDependentFiles load_dependent_files,
49
const OptionGroupPlatform *platform_options,
50
TargetSP &target_sp) {
51
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
52
auto result = TargetList::CreateTargetInternal(
53
debugger, user_exe_path, triple_str, load_dependent_files,
54
platform_options, target_sp);
55
56
if (target_sp && result.Success())
57
AddTargetInternal(target_sp, /*do_select*/ true);
58
return result;
59
}
60
61
Status TargetList::CreateTarget(Debugger &debugger,
62
llvm::StringRef user_exe_path,
63
const ArchSpec &specified_arch,
64
LoadDependentFiles load_dependent_files,
65
PlatformSP &platform_sp, TargetSP &target_sp) {
66
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
67
auto result = TargetList::CreateTargetInternal(
68
debugger, user_exe_path, specified_arch, load_dependent_files,
69
platform_sp, target_sp);
70
71
if (target_sp && result.Success())
72
AddTargetInternal(target_sp, /*do_select*/ true);
73
return result;
74
}
75
76
Status TargetList::CreateTargetInternal(
77
Debugger &debugger, llvm::StringRef user_exe_path,
78
llvm::StringRef triple_str, LoadDependentFiles load_dependent_files,
79
const OptionGroupPlatform *platform_options, TargetSP &target_sp) {
80
Status error;
81
82
PlatformList &platform_list = debugger.GetPlatformList();
83
// Let's start by looking at the selected platform.
84
PlatformSP platform_sp = platform_list.GetSelectedPlatform();
85
86
// This variable corresponds to the architecture specified by the triple
87
// string. If that string was empty the currently selected platform will
88
// determine the architecture.
89
const ArchSpec arch(triple_str);
90
if (!triple_str.empty() && !arch.IsValid()) {
91
error.SetErrorStringWithFormat("invalid triple '%s'",
92
triple_str.str().c_str());
93
return error;
94
}
95
96
ArchSpec platform_arch(arch);
97
98
// Create a new platform if a platform was specified in the platform options
99
// and doesn't match the selected platform.
100
if (platform_options && platform_options->PlatformWasSpecified() &&
101
!platform_options->PlatformMatches(platform_sp)) {
102
const bool select_platform = true;
103
platform_sp = platform_options->CreatePlatformWithOptions(
104
debugger.GetCommandInterpreter(), arch, select_platform, error,
105
platform_arch);
106
if (!platform_sp)
107
return error;
108
}
109
110
bool prefer_platform_arch = false;
111
auto update_platform_arch = [&](const ArchSpec &module_arch) {
112
// If the OS or vendor weren't specified, then adopt the module's
113
// architecture so that the platform matching can be more accurate.
114
if (!platform_arch.TripleOSWasSpecified() ||
115
!platform_arch.TripleVendorWasSpecified()) {
116
prefer_platform_arch = true;
117
platform_arch = module_arch;
118
}
119
};
120
121
if (!user_exe_path.empty()) {
122
ModuleSpec module_spec(FileSpec(user_exe_path, FileSpec::Style::native));
123
FileSystem::Instance().Resolve(module_spec.GetFileSpec());
124
125
// Try to resolve the exe based on PATH and/or platform-specific suffixes,
126
// but only if using the host platform.
127
if (platform_sp->IsHost() &&
128
!FileSystem::Instance().Exists(module_spec.GetFileSpec()))
129
FileSystem::Instance().ResolveExecutableLocation(
130
module_spec.GetFileSpec());
131
132
// Resolve the executable in case we are given a path to a application
133
// bundle like a .app bundle on MacOSX.
134
Host::ResolveExecutableInBundle(module_spec.GetFileSpec());
135
136
lldb::offset_t file_offset = 0;
137
lldb::offset_t file_size = 0;
138
ModuleSpecList module_specs;
139
const size_t num_specs = ObjectFile::GetModuleSpecifications(
140
module_spec.GetFileSpec(), file_offset, file_size, module_specs);
141
142
if (num_specs > 0) {
143
ModuleSpec matching_module_spec;
144
145
if (num_specs == 1) {
146
if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) {
147
if (platform_arch.IsValid()) {
148
if (platform_arch.IsCompatibleMatch(
149
matching_module_spec.GetArchitecture())) {
150
// If the OS or vendor weren't specified, then adopt the module's
151
// architecture so that the platform matching can be more
152
// accurate.
153
update_platform_arch(matching_module_spec.GetArchitecture());
154
} else {
155
StreamString platform_arch_strm;
156
StreamString module_arch_strm;
157
158
platform_arch.DumpTriple(platform_arch_strm.AsRawOstream());
159
matching_module_spec.GetArchitecture().DumpTriple(
160
module_arch_strm.AsRawOstream());
161
error.SetErrorStringWithFormat(
162
"the specified architecture '%s' is not compatible with '%s' "
163
"in '%s'",
164
platform_arch_strm.GetData(), module_arch_strm.GetData(),
165
module_spec.GetFileSpec().GetPath().c_str());
166
return error;
167
}
168
} else {
169
// Only one arch and none was specified.
170
prefer_platform_arch = true;
171
platform_arch = matching_module_spec.GetArchitecture();
172
}
173
}
174
} else if (arch.IsValid()) {
175
// Fat binary. A (valid) architecture was specified.
176
module_spec.GetArchitecture() = arch;
177
if (module_specs.FindMatchingModuleSpec(module_spec,
178
matching_module_spec))
179
update_platform_arch(matching_module_spec.GetArchitecture());
180
} else {
181
// Fat binary. No architecture specified, check if there is
182
// only one platform for all of the architectures.
183
std::vector<PlatformSP> candidates;
184
std::vector<ArchSpec> archs;
185
for (const ModuleSpec &spec : module_specs.ModuleSpecs())
186
archs.push_back(spec.GetArchitecture());
187
if (PlatformSP platform_for_archs_sp =
188
platform_list.GetOrCreate(archs, {}, candidates)) {
189
platform_sp = platform_for_archs_sp;
190
} else if (candidates.empty()) {
191
error.SetErrorString("no matching platforms found for this file");
192
return error;
193
} else {
194
// More than one platform claims to support this file.
195
StreamString error_strm;
196
std::set<llvm::StringRef> platform_set;
197
error_strm.Printf(
198
"more than one platform supports this executable (");
199
for (const auto &candidate : candidates) {
200
llvm::StringRef platform_name = candidate->GetName();
201
if (platform_set.count(platform_name))
202
continue;
203
if (!platform_set.empty())
204
error_strm.PutCString(", ");
205
error_strm.PutCString(platform_name);
206
platform_set.insert(platform_name);
207
}
208
error_strm.Printf("), specify an architecture to disambiguate");
209
error.SetErrorString(error_strm.GetString());
210
return error;
211
}
212
}
213
}
214
}
215
216
// If we have a valid architecture, make sure the current platform is
217
// compatible with that architecture.
218
if (!prefer_platform_arch && arch.IsValid()) {
219
if (!platform_sp->IsCompatibleArchitecture(
220
arch, {}, ArchSpec::CompatibleMatch, nullptr)) {
221
platform_sp = platform_list.GetOrCreate(arch, {}, &platform_arch);
222
if (platform_sp)
223
platform_list.SetSelectedPlatform(platform_sp);
224
}
225
} else if (platform_arch.IsValid()) {
226
// If "arch" isn't valid, yet "platform_arch" is, it means we have an
227
// executable file with a single architecture which should be used.
228
ArchSpec fixed_platform_arch;
229
if (!platform_sp->IsCompatibleArchitecture(
230
platform_arch, {}, ArchSpec::CompatibleMatch, nullptr)) {
231
platform_sp =
232
platform_list.GetOrCreate(platform_arch, {}, &fixed_platform_arch);
233
if (platform_sp)
234
platform_list.SetSelectedPlatform(platform_sp);
235
}
236
}
237
238
if (!platform_arch.IsValid())
239
platform_arch = arch;
240
241
return TargetList::CreateTargetInternal(debugger, user_exe_path,
242
platform_arch, load_dependent_files,
243
platform_sp, target_sp);
244
}
245
246
Status TargetList::CreateTargetInternal(Debugger &debugger,
247
llvm::StringRef user_exe_path,
248
const ArchSpec &specified_arch,
249
LoadDependentFiles load_dependent_files,
250
lldb::PlatformSP &platform_sp,
251
lldb::TargetSP &target_sp) {
252
LLDB_SCOPED_TIMERF("TargetList::CreateTarget (file = '%s', arch = '%s')",
253
user_exe_path.str().c_str(),
254
specified_arch.GetArchitectureName());
255
Status error;
256
const bool is_dummy_target = false;
257
258
ArchSpec arch(specified_arch);
259
260
if (arch.IsValid()) {
261
if (!platform_sp || !platform_sp->IsCompatibleArchitecture(
262
arch, {}, ArchSpec::CompatibleMatch, nullptr))
263
platform_sp =
264
debugger.GetPlatformList().GetOrCreate(specified_arch, {}, &arch);
265
}
266
267
if (!platform_sp)
268
platform_sp = debugger.GetPlatformList().GetSelectedPlatform();
269
270
if (!arch.IsValid())
271
arch = specified_arch;
272
273
FileSpec file(user_exe_path);
274
if (!FileSystem::Instance().Exists(file) && user_exe_path.starts_with("~")) {
275
// we want to expand the tilde but we don't want to resolve any symbolic
276
// links so we can't use the FileSpec constructor's resolve flag
277
llvm::SmallString<64> unglobbed_path;
278
StandardTildeExpressionResolver Resolver;
279
Resolver.ResolveFullPath(user_exe_path, unglobbed_path);
280
281
if (unglobbed_path.empty())
282
file = FileSpec(user_exe_path);
283
else
284
file = FileSpec(unglobbed_path.c_str());
285
}
286
287
bool user_exe_path_is_bundle = false;
288
char resolved_bundle_exe_path[PATH_MAX];
289
resolved_bundle_exe_path[0] = '\0';
290
if (file) {
291
if (FileSystem::Instance().IsDirectory(file))
292
user_exe_path_is_bundle = true;
293
294
if (file.IsRelative() && !user_exe_path.empty()) {
295
llvm::SmallString<64> cwd;
296
if (! llvm::sys::fs::current_path(cwd)) {
297
FileSpec cwd_file(cwd.c_str());
298
cwd_file.AppendPathComponent(file);
299
if (FileSystem::Instance().Exists(cwd_file))
300
file = cwd_file;
301
}
302
}
303
304
ModuleSP exe_module_sp;
305
if (platform_sp) {
306
FileSpecList executable_search_paths(
307
Target::GetDefaultExecutableSearchPaths());
308
ModuleSpec module_spec(file, arch);
309
error = platform_sp->ResolveExecutable(module_spec, exe_module_sp,
310
executable_search_paths.GetSize()
311
? &executable_search_paths
312
: nullptr);
313
}
314
315
if (error.Success() && exe_module_sp) {
316
if (exe_module_sp->GetObjectFile() == nullptr) {
317
if (arch.IsValid()) {
318
error.SetErrorStringWithFormat(
319
"\"%s\" doesn't contain architecture %s", file.GetPath().c_str(),
320
arch.GetArchitectureName());
321
} else {
322
error.SetErrorStringWithFormat("unsupported file type \"%s\"",
323
file.GetPath().c_str());
324
}
325
return error;
326
}
327
target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
328
debugger.GetTargetList().RegisterInProcessTarget(target_sp);
329
target_sp->SetExecutableModule(exe_module_sp, load_dependent_files);
330
if (user_exe_path_is_bundle)
331
exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path,
332
sizeof(resolved_bundle_exe_path));
333
if (target_sp->GetPreloadSymbols())
334
exe_module_sp->PreloadSymbols();
335
}
336
} else {
337
// No file was specified, just create an empty target with any arch if a
338
// valid arch was specified
339
target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
340
debugger.GetTargetList().RegisterInProcessTarget(target_sp);
341
}
342
343
if (!target_sp)
344
return error;
345
346
// Set argv0 with what the user typed, unless the user specified a
347
// directory. If the user specified a directory, then it is probably a
348
// bundle that was resolved and we need to use the resolved bundle path
349
if (!user_exe_path.empty()) {
350
// Use exactly what the user typed as the first argument when we exec or
351
// posix_spawn
352
if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) {
353
target_sp->SetArg0(resolved_bundle_exe_path);
354
} else {
355
// Use resolved path
356
target_sp->SetArg0(file.GetPath().c_str());
357
}
358
}
359
if (file.GetDirectory()) {
360
FileSpec file_dir;
361
file_dir.SetDirectory(file.GetDirectory());
362
target_sp->AppendExecutableSearchPaths(file_dir);
363
}
364
365
// Now prime this from the dummy target:
366
target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget());
367
368
return error;
369
}
370
371
bool TargetList::DeleteTarget(TargetSP &target_sp) {
372
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
373
auto it = llvm::find(m_target_list, target_sp);
374
if (it == m_target_list.end())
375
return false;
376
377
m_target_list.erase(it);
378
return true;
379
}
380
381
TargetSP TargetList::FindTargetWithExecutableAndArchitecture(
382
const FileSpec &exe_file_spec, const ArchSpec *exe_arch_ptr) const {
383
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
384
auto it = std::find_if(m_target_list.begin(), m_target_list.end(),
385
[&exe_file_spec, exe_arch_ptr](const TargetSP &item) {
386
Module *exe_module = item->GetExecutableModulePointer();
387
if (!exe_module ||
388
!FileSpec::Match(exe_file_spec, exe_module->GetFileSpec()))
389
return false;
390
391
return !exe_arch_ptr ||
392
exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture());
393
});
394
395
if (it != m_target_list.end())
396
return *it;
397
398
return TargetSP();
399
}
400
401
TargetSP TargetList::FindTargetWithProcessID(lldb::pid_t pid) const {
402
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
403
auto it = std::find_if(m_target_list.begin(), m_target_list.end(),
404
[pid](const TargetSP &item) {
405
auto *process_ptr = item->GetProcessSP().get();
406
return process_ptr && (process_ptr->GetID() == pid);
407
});
408
409
if (it != m_target_list.end())
410
return *it;
411
412
return TargetSP();
413
}
414
415
TargetSP TargetList::FindTargetWithProcess(Process *process) const {
416
TargetSP target_sp;
417
if (!process)
418
return target_sp;
419
420
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
421
auto it = std::find_if(m_target_list.begin(), m_target_list.end(),
422
[process](const TargetSP &item) {
423
return item->GetProcessSP().get() == process;
424
});
425
426
if (it != m_target_list.end())
427
target_sp = *it;
428
429
return target_sp;
430
}
431
432
TargetSP TargetList::GetTargetSP(Target *target) const {
433
TargetSP target_sp;
434
if (!target)
435
return target_sp;
436
437
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
438
auto it = std::find_if(m_target_list.begin(), m_target_list.end(),
439
[target](const TargetSP &item) { return item.get() == target; });
440
if (it != m_target_list.end())
441
target_sp = *it;
442
443
return target_sp;
444
}
445
446
uint32_t TargetList::SendAsyncInterrupt(lldb::pid_t pid) {
447
uint32_t num_async_interrupts_sent = 0;
448
449
if (pid != LLDB_INVALID_PROCESS_ID) {
450
TargetSP target_sp(FindTargetWithProcessID(pid));
451
if (target_sp) {
452
Process *process = target_sp->GetProcessSP().get();
453
if (process) {
454
process->SendAsyncInterrupt();
455
++num_async_interrupts_sent;
456
}
457
}
458
} else {
459
// We don't have a valid pid to broadcast to, so broadcast to the target
460
// list's async broadcaster...
461
BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr);
462
}
463
464
return num_async_interrupts_sent;
465
}
466
467
uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) {
468
uint32_t num_signals_sent = 0;
469
Process *process = nullptr;
470
if (pid == LLDB_INVALID_PROCESS_ID) {
471
// Signal all processes with signal
472
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
473
for (const auto &target_sp : m_target_list) {
474
process = target_sp->GetProcessSP().get();
475
if (process && process->IsAlive()) {
476
++num_signals_sent;
477
process->Signal(signo);
478
}
479
}
480
} else {
481
// Signal a specific process with signal
482
TargetSP target_sp(FindTargetWithProcessID(pid));
483
if (target_sp) {
484
process = target_sp->GetProcessSP().get();
485
if (process && process->IsAlive()) {
486
++num_signals_sent;
487
process->Signal(signo);
488
}
489
}
490
}
491
return num_signals_sent;
492
}
493
494
size_t TargetList::GetNumTargets() const {
495
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
496
return m_target_list.size();
497
}
498
499
lldb::TargetSP TargetList::GetTargetAtIndex(uint32_t idx) const {
500
TargetSP target_sp;
501
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
502
if (idx < m_target_list.size())
503
target_sp = m_target_list[idx];
504
return target_sp;
505
}
506
507
uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const {
508
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
509
auto it = llvm::find(m_target_list, target_sp);
510
if (it != m_target_list.end())
511
return std::distance(m_target_list.begin(), it);
512
return UINT32_MAX;
513
}
514
515
void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
516
lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
517
"target already exists it the list");
518
UnregisterInProcessTarget(target_sp);
519
m_target_list.push_back(std::move(target_sp));
520
if (do_select)
521
SetSelectedTargetInternal(m_target_list.size() - 1);
522
}
523
524
void TargetList::SetSelectedTargetInternal(uint32_t index) {
525
lldbassert(!m_target_list.empty());
526
m_selected_target_idx = index < m_target_list.size() ? index : 0;
527
}
528
529
void TargetList::SetSelectedTarget(uint32_t index) {
530
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
531
SetSelectedTargetInternal(index);
532
}
533
534
void TargetList::SetSelectedTarget(const TargetSP &target_sp) {
535
// Don't allow an invalid target shared pointer or a target that has been
536
// destroyed to become the selected target.
537
if (target_sp && target_sp->IsValid()) {
538
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
539
auto it = llvm::find(m_target_list, target_sp);
540
SetSelectedTargetInternal(std::distance(m_target_list.begin(), it));
541
}
542
}
543
544
lldb::TargetSP TargetList::GetSelectedTarget() {
545
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
546
if (m_selected_target_idx >= m_target_list.size())
547
m_selected_target_idx = 0;
548
return GetTargetAtIndex(m_selected_target_idx);
549
}
550
551
bool TargetList::AnyTargetContainsModule(Module &module) {
552
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
553
for (const auto &target_sp : m_target_list) {
554
if (target_sp->GetImages().FindModule(&module))
555
return true;
556
}
557
for (const auto &target_sp: m_in_process_target_list) {
558
if (target_sp->GetImages().FindModule(&module))
559
return true;
560
}
561
return false;
562
}
563
564
void TargetList::RegisterInProcessTarget(TargetSP target_sp) {
565
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
566
[[maybe_unused]] bool was_added;
567
std::tie(std::ignore, was_added) =
568
m_in_process_target_list.insert(target_sp);
569
assert(was_added && "Target pointer was left in the in-process map");
570
}
571
572
void TargetList::UnregisterInProcessTarget(TargetSP target_sp) {
573
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
574
[[maybe_unused]] bool was_present =
575
m_in_process_target_list.erase(target_sp);
576
assert(was_present && "Target pointer being removed was not registered");
577
}
578
579
bool TargetList::IsTargetInProcess(TargetSP target_sp) {
580
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
581
return m_in_process_target_list.count(target_sp) == 1;
582
}
583
584