Skip to content

Commit f40711b

Browse files
committed
[lldb/Target] Add ability to set a label to targets
This patch add the ability for the user to set a label for a target. This can be very useful when debugging targets with the same executables in the same session. Labels can be set either at the target creation in the command interpreter or at any time using the SBAPI. Target labels show up in the `target list` output, following the target index, and they also allow the user to switch targets using them. rdar://105016191 Differential Revision: https://reviews.llvm.org/D151859 Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent b1b8ed9 commit f40711b

File tree

8 files changed

+144
-12
lines changed

8 files changed

+144
-12
lines changed

lldb/include/lldb/API/SBTarget.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ class LLDB_API SBTarget {
328328

329329
const char *GetABIName();
330330

331+
const char *GetLabel() const;
332+
333+
SBError SetLabel(const char *label);
334+
331335
/// Architecture data byte width accessor
332336
///
333337
/// \return

lldb/include/lldb/Target/Target.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,17 @@ class Target : public std::enable_shared_from_this<Target>,
633633

634634
bool IsDummyTarget() const { return m_is_dummy_target; }
635635

636+
const std::string &GetLabel() const { return m_label; }
637+
638+
/// Set a label for a target.
639+
///
640+
/// The label cannot be used by another target or be only integral.
641+
///
642+
/// \return
643+
/// The label for this target or an error if the label didn't match the
644+
/// requirements.
645+
llvm::Error SetLabel(llvm::StringRef label);
646+
636647
/// Find a binary on the system and return its Module,
637648
/// or return an existing Module that is already in the Target.
638649
///
@@ -1643,6 +1654,7 @@ class Target : public std::enable_shared_from_this<Target>,
16431654
/// detect that code is running on the private state thread.
16441655
std::recursive_mutex m_private_mutex;
16451656
Arch m_arch;
1657+
std::string m_label;
16461658
ModuleList m_images; ///< The list of images for this process (shared
16471659
/// libraries and anything dynamically loaded).
16481660
SectionLoadHistory m_section_load_history;

lldb/include/lldb/Target/TargetList.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class TargetList : public Broadcaster {
115115
/// in \a target_sp which can then be properly released.
116116
bool DeleteTarget(lldb::TargetSP &target_sp);
117117

118-
int GetNumTargets() const;
118+
size_t GetNumTargets() const;
119119

120120
lldb::TargetSP GetTargetAtIndex(uint32_t index) const;
121121

lldb/source/API/SBTarget.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,26 @@ const char *SBTarget::GetABIName() {
16371637
return nullptr;
16381638
}
16391639

1640+
const char *SBTarget::GetLabel() const {
1641+
LLDB_INSTRUMENT_VA(this);
1642+
1643+
TargetSP target_sp(GetSP());
1644+
if (!target_sp)
1645+
return nullptr;
1646+
1647+
return ConstString(target_sp->GetLabel().data()).AsCString();
1648+
}
1649+
1650+
SBError SBTarget::SetLabel(const char *label) {
1651+
LLDB_INSTRUMENT_VA(this, label);
1652+
1653+
TargetSP target_sp(GetSP());
1654+
if (!target_sp)
1655+
return Status("Couldn't get internal target object.");
1656+
1657+
return Status(target_sp->SetLabel(label));
1658+
}
1659+
16401660
uint32_t SBTarget::GetDataByteSize() {
16411661
LLDB_INSTRUMENT_VA(this);
16421662

lldb/source/Commands/CommandObjectTarget.cpp

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,14 @@ static void DumpTargetInfo(uint32_t target_idx, Target *target,
8282
if (!exe_valid)
8383
::strcpy(exe_path, "<none>");
8484

85-
strm.Printf("%starget #%u: %s", prefix_cstr ? prefix_cstr : "", target_idx,
86-
exe_path);
85+
std::string formatted_label = "";
86+
const std::string &label = target->GetLabel();
87+
if (!label.empty()) {
88+
formatted_label = " (" + label + ")";
89+
}
90+
91+
strm.Printf("%starget #%u%s: %s", prefix_cstr ? prefix_cstr : "", target_idx,
92+
formatted_label.data(), exe_path);
8793

8894
uint32_t properties = 0;
8995
if (target_arch.IsValid()) {
@@ -209,6 +215,8 @@ class CommandObjectTargetCreate : public CommandObjectParsed {
209215
m_platform_options(true), // Include the --platform option.
210216
m_core_file(LLDB_OPT_SET_1, false, "core", 'c', 0, eArgTypeFilename,
211217
"Fullpath to a core file to use for this target."),
218+
m_label(LLDB_OPT_SET_1, false, "label", 'l', 0, eArgTypeName,
219+
"Optional name for this target.", nullptr),
212220
m_symbol_file(LLDB_OPT_SET_1, false, "symfile", 's', 0,
213221
eArgTypeFilename,
214222
"Fullpath to a stand alone debug "
@@ -234,6 +242,7 @@ class CommandObjectTargetCreate : public CommandObjectParsed {
234242
m_option_group.Append(&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
235243
m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);
236244
m_option_group.Append(&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
245+
m_option_group.Append(&m_label, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
237246
m_option_group.Append(&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
238247
m_option_group.Append(&m_remote_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
239248
m_option_group.Append(&m_add_dependents, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
@@ -302,6 +311,14 @@ class CommandObjectTargetCreate : public CommandObjectParsed {
302311
return false;
303312
}
304313

314+
const llvm::StringRef label =
315+
m_label.GetOptionValue().GetCurrentValueAsRef();
316+
if (!label.empty()) {
317+
if (auto E = target_sp->SetLabel(label))
318+
result.SetError(std::move(E));
319+
return false;
320+
}
321+
305322
auto on_error = llvm::make_scope_exit(
306323
[&target_list = debugger.GetTargetList(), &target_sp]() {
307324
target_list.DeleteTarget(target_sp);
@@ -454,6 +471,7 @@ class CommandObjectTargetCreate : public CommandObjectParsed {
454471
OptionGroupArchitecture m_arch_option;
455472
OptionGroupPlatform m_platform_options;
456473
OptionGroupFile m_core_file;
474+
OptionGroupString m_label;
457475
OptionGroupFile m_symbol_file;
458476
OptionGroupFile m_remote_file;
459477
OptionGroupDependents m_add_dependents;
@@ -502,11 +520,11 @@ class CommandObjectTargetSelect : public CommandObjectParsed {
502520
protected:
503521
bool DoExecute(Args &args, CommandReturnObject &result) override {
504522
if (args.GetArgumentCount() == 1) {
505-
const char *target_idx_arg = args.GetArgumentAtIndex(0);
506-
uint32_t target_idx;
507-
if (llvm::to_integer(target_idx_arg, target_idx)) {
508-
TargetList &target_list = GetDebugger().GetTargetList();
509-
const uint32_t num_targets = target_list.GetNumTargets();
523+
const char *target_identifier = args.GetArgumentAtIndex(0);
524+
uint32_t target_idx = LLDB_INVALID_INDEX32;
525+
TargetList &target_list = GetDebugger().GetTargetList();
526+
const uint32_t num_targets = target_list.GetNumTargets();
527+
if (llvm::to_integer(target_identifier, target_idx)) {
510528
if (target_idx < num_targets) {
511529
target_list.SetSelectedTarget(target_idx);
512530
Stream &strm = result.GetOutputStream();
@@ -525,8 +543,26 @@ class CommandObjectTargetSelect : public CommandObjectParsed {
525543
}
526544
}
527545
} else {
528-
result.AppendErrorWithFormat("invalid index string value '%s'\n",
529-
target_idx_arg);
546+
for (size_t i = 0; i < num_targets; i++) {
547+
if (TargetSP target_sp = target_list.GetTargetAtIndex(i)) {
548+
const std::string &label = target_sp->GetLabel();
549+
if (!label.empty() && label == target_identifier) {
550+
target_idx = i;
551+
break;
552+
}
553+
}
554+
}
555+
556+
if (target_idx != LLDB_INVALID_INDEX32) {
557+
target_list.SetSelectedTarget(target_idx);
558+
Stream &strm = result.GetOutputStream();
559+
bool show_stopped_process_status = false;
560+
DumpTargetList(target_list, show_stopped_process_status, strm);
561+
result.SetStatus(eReturnStatusSuccessFinishResult);
562+
} else {
563+
result.AppendErrorWithFormat("invalid index string value '%s'\n",
564+
target_identifier);
565+
}
530566
}
531567
} else {
532568
result.AppendError(
@@ -575,7 +611,7 @@ class CommandObjectTargetDelete : public CommandObjectParsed {
575611
TargetSP target_sp;
576612

577613
if (m_all_option.GetOptionValue()) {
578-
for (int i = 0; i < target_list.GetNumTargets(); ++i)
614+
for (size_t i = 0; i < target_list.GetNumTargets(); ++i)
579615
delete_target_list.push_back(target_list.GetTargetAtIndex(i));
580616
} else if (argc > 0) {
581617
const uint32_t num_targets = target_list.GetNumTargets();

lldb/source/Target/Target.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@
6969

7070
#include <memory>
7171
#include <mutex>
72+
#include <optional>
73+
#include <sstream>
7274

7375
#ifdef LLDB_ENABLE_SWIFT
7476
#include "Plugins/TypeSystem/Swift/SwiftASTContext.h"
@@ -2930,6 +2932,26 @@ void Target::SetDefaultArchitecture(const ArchSpec &arch) {
29302932
Target::GetGlobalProperties().SetDefaultArchitecture(arch);
29312933
}
29322934

2935+
llvm::Error Target::SetLabel(llvm::StringRef label) {
2936+
size_t n = LLDB_INVALID_INDEX32;
2937+
if (llvm::to_integer(label, n))
2938+
return llvm::make_error<llvm::StringError>(
2939+
"Cannot use integer as target label.", llvm::inconvertibleErrorCode());
2940+
TargetList &targets = GetDebugger().GetTargetList();
2941+
for (size_t i = 0; i < targets.GetNumTargets(); i++) {
2942+
TargetSP target_sp = targets.GetTargetAtIndex(i);
2943+
if (target_sp && target_sp->GetLabel() == label) {
2944+
return llvm::make_error<llvm::StringError>(
2945+
llvm::formatv("Cannot use label '{0}' since it's set in target #{1}.",
2946+
label, i),
2947+
llvm::inconvertibleErrorCode());
2948+
}
2949+
}
2950+
2951+
m_label = label.str();
2952+
return llvm::Error::success();
2953+
}
2954+
29332955
Target *Target::GetTargetFromContexts(const ExecutionContext *exe_ctx_ptr,
29342956
const SymbolContext *sc_ptr) {
29352957
// The target can either exist in the "process" of ExecutionContext, or in

lldb/source/Target/TargetList.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) {
491491
return num_signals_sent;
492492
}
493493

494-
int TargetList::GetNumTargets() const {
494+
size_t TargetList::GetNumTargets() const {
495495
std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
496496
return m_target_list.size();
497497
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# RUN: %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -s %s 2>&1 | FileCheck %s
2+
3+
target create -l "ls" /bin/ls
4+
target list
5+
# CHECK: * target #0 (ls): /bin/ls
6+
7+
script lldb.target.SetLabel("")
8+
target list
9+
# CHECK: * target #0: /bin/ls
10+
11+
target create -l "cat" /bin/cat
12+
target list
13+
# CHECK: target #0: /bin/ls
14+
# CHECK-NEXT: * target #1 (cat): /bin/cat
15+
16+
target create -l "cat" /bin/cat
17+
# CHECK: Cannot use label 'cat' since it's set in target #1.
18+
19+
target create -l 42 /bin/cat
20+
# CHECK: error: Cannot use integer as target label.
21+
22+
target select 0
23+
# CHECK: * target #0: /bin/ls
24+
# CHECK-NEXT: target #1 (cat): /bin/cat
25+
26+
target select cat
27+
# CHECK: target #0: /bin/ls
28+
# CHECK-NEXT: * target #1 (cat): /bin/cat
29+
30+
script lldb.target.GetLabel()
31+
# CHECK: 'cat'
32+
33+
script lldb.debugger.GetTargetAtIndex(0).SetLabel('Not cat')
34+
# CHECK: success
35+
36+
target list
37+
# CHECK: target #0 (Not cat): /bin/ls
38+
# CHECK-NEXT: * target #1 (cat): /bin/cat

0 commit comments

Comments
 (0)